From 4e439599bcffa783393564343db6744e76948bd4 Mon Sep 17 00:00:00 2001 From: Daniele Bartolini Date: Thu, 2 Jan 2025 02:08:06 +0100 Subject: [PATCH] resource: extract Mesh from mesh_resource.* Part-of: #207 --- src/resource/mesh.cpp | 259 +++++++++++++++++ src/resource/mesh.h | 75 +++++ src/resource/mesh_resource.cpp | 450 ++++++++---------------------- src/resource/mesh_resource.h | 68 ++--- src/resource/physics_resource.cpp | 16 +- src/resource/unit_compiler.cpp | 14 +- tools/resource/mesh_resource.vala | 11 +- 7 files changed, 487 insertions(+), 406 deletions(-) create mode 100644 src/resource/mesh.cpp create mode 100644 src/resource/mesh.h diff --git a/src/resource/mesh.cpp b/src/resource/mesh.cpp new file mode 100644 index 000000000..f2c5fa80d --- /dev/null +++ b/src/resource/mesh.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2012-2024 Daniele Bartolini et al. + * SPDX-License-Identifier: MIT + */ + +#include "config.h" +#include "core/containers/array.inl" +#include "core/containers/vector.inl" +#include "core/filesystem/filesystem.h" +#include "core/json/json_object.inl" +#include "core/json/sjson.h" +#include "core/math/aabb.inl" +#include "core/math/constants.h" +#include "core/math/matrix4x4.inl" +#include "core/math/vector2.inl" +#include "core/math/vector3.inl" +#include "core/memory/temp_allocator.inl" +#include "core/strings/dynamic_string.inl" +#include "resource/compile_options.inl" +#include "resource/mesh.h" +#include "resource/mesh_resource.h" +#include +#include +#include // bgfx::write, bgfx::read + +namespace crown +{ +namespace mesh +{ + /// Writer interface. + struct BgfxWriter : public bx::WriterI + { + BinaryWriter *_bw; + + /// + explicit BgfxWriter(BinaryWriter &bw) + : _bw(&bw) + { + } + + /// + virtual ~BgfxWriter() + { + } + + /// + virtual int32_t write(const void *_data, int32_t _size, bx::Error *_err) + { + CE_UNUSED(_err); + _bw->write(_data, _size); + return _size; // FIXME: return the actual number of bytes written + } + }; + + static void reset(Geometry &g) + { + array::clear(g._positions); + array::clear(g._normals); + array::clear(g._uvs); + array::clear(g._tangents); + array::clear(g._binormals); + + array::clear(g._position_indices); + array::clear(g._normal_indices); + array::clear(g._uv_indices); + array::clear(g._tangent_indices); + array::clear(g._binormal_indices); + + array::clear(g._vertex_buffer); + array::clear(g._index_buffer); + } + + bool has_normals(Geometry &g) + { + return array::size(g._normals) != 0; + } + + bool has_uvs(Geometry &g) + { + return array::size(g._uvs) != 0; + } + + static u32 vertex_stride(Geometry &g) + { + u32 stride = 0; + stride += 3 * sizeof(f32); + stride += (has_normals(g) ? 3 * sizeof(f32) : 0); + stride += (has_uvs(g) ? 2 * sizeof(f32) : 0); + return stride; + } + + static bgfx::VertexLayout vertex_layout(Geometry &g) + { + bgfx::VertexLayout layout; + memset((void *)&layout, 0, sizeof(layout)); + + layout.begin(); + layout.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float); + + if (has_normals(g)) { + layout.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float, true); + } + if (has_uvs(g)) { + layout.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float); + } + + layout.end(); + return layout; + } + + static void generate_vertex_and_index_buffers(Geometry &g) + { + array::resize(g._index_buffer, array::size(g._position_indices)); + + u16 index = 0; + for (u32 i = 0; i < array::size(g._position_indices); ++i) { + g._index_buffer[i] = index++; + + const u16 p_idx = g._position_indices[i] * 3; + Vector3 xyz; + xyz.x = g._positions[p_idx + 0]; + xyz.y = g._positions[p_idx + 1]; + xyz.z = g._positions[p_idx + 2]; + array::push(g._vertex_buffer, (char *)&xyz, sizeof(xyz)); + + if (has_normals(g)) { + const u16 n_idx = g._normal_indices[i] * 3; + Vector3 n; + n.x = g._normals[n_idx + 0]; + n.y = g._normals[n_idx + 1]; + n.z = g._normals[n_idx + 2]; + array::push(g._vertex_buffer, (char *)&n, sizeof(n)); + } + if (has_uvs(g)) { + const u16 t_idx = g._uv_indices[i] * 2; + Vector2 uv; + uv.x = g._uvs[t_idx + 0]; + uv.y = g._uvs[t_idx + 1]; + array::push(g._vertex_buffer, (char *)&uv, sizeof(uv)); + } + } + } + + static void geometry_names(Vector &names, const Mesh &m, const DynamicString &geometry) + { + auto cur = hash_map::begin(m._nodes); + auto end = hash_map::end(m._nodes); + for (; cur != end; ++cur) { + HASH_MAP_SKIP_HOLE(m._nodes, cur); + + if (cur->second._geometry == geometry) + vector::push_back(names, cur->first); + } + } + + static OBB obb(Geometry &g) + { + AABB aabb; + OBB obb; + aabb::reset(aabb); + memset(&obb, 0, sizeof(obb)); + + aabb::from_points(aabb + , array::size(g._positions) / 3 + , sizeof(g._positions[0]) * 3 + , array::begin(g._positions) + ); + + obb.tm = from_quaternion_translation(QUATERNION_IDENTITY, aabb::center(aabb)); + obb.half_extents = (aabb.max - aabb.min) * 0.5f; + return obb; + } + + s32 write(Mesh &m, CompileOptions &opts) + { + opts.write(RESOURCE_HEADER(RESOURCE_VERSION_MESH)); + opts.write(hash_map::size(m._geometries)); + + auto cur = hash_map::begin(m._geometries); + auto end = hash_map::end(m._geometries); + for (; cur != end; ++cur) { + HASH_MAP_SKIP_HOLE(m._geometries, cur); + + Vector geo_names(default_allocator()); + geometry_names(geo_names, m, cur->first); + u32 num_geo_names = vector::size(geo_names); + + opts.write(num_geo_names); + for (u32 i = 0; i < num_geo_names; ++i) + opts.write(geo_names[i].to_string_id()._id); + + Geometry *geo = (Geometry *)&cur->second; + mesh::generate_vertex_and_index_buffers(*geo); + + bgfx::VertexLayout layout = mesh::vertex_layout(*geo); + u32 stride = mesh::vertex_stride(*geo); + OBB bbox = mesh::obb(*geo); + + BgfxWriter writer(opts._binary_writer); + bgfx::write(&writer, layout); + opts.write(bbox); + + opts.write(array::size(geo->_vertex_buffer) / stride); + opts.write(stride); + opts.write(array::size(geo->_index_buffer)); + + opts.write(geo->_vertex_buffer); + opts.write(array::begin(geo->_index_buffer), array::size(geo->_index_buffer) * sizeof(u16)); + } + + return 0; + } + + s32 parse(Mesh &m, CompileOptions &opts, const char *path) + { + if (str_has_suffix(path, ".mesh")) { + Buffer buf = opts.read(path); + return mesh::parse(m, buf, opts); + } else { + TempAllocator512 ta; + DynamicString str(ta); + str = path; + str += ".mesh"; + Buffer buf = opts.read(str.c_str()); + return mesh::parse(m, buf, opts); + } + } +} + +Node::Node(Allocator &a) + : _local_pose(MATRIX4X4_IDENTITY) + , _geometry(a) +{ +} + +Geometry::Geometry(Allocator &a) + : _positions(a) + , _normals(a) + , _uvs(a) + , _tangents(a) + , _binormals(a) + , _position_indices(a) + , _normal_indices(a) + , _uv_indices(a) + , _tangent_indices(a) + , _binormal_indices(a) + , _vertex_buffer(a) + , _index_buffer(a) +{ + mesh::reset(*this); +} + +Mesh::Mesh(Allocator &a) + : _geometries(a) + , _nodes(a) +{ +} + +} // namespace crown diff --git a/src/resource/mesh.h b/src/resource/mesh.h new file mode 100644 index 000000000..f6c6bcd6a --- /dev/null +++ b/src/resource/mesh.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012-2024 Daniele Bartolini et al. + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include "core/filesystem/types.h" +#include "core/math/types.h" +#include "core/memory/types.h" +#include "core/strings/dynamic_string.h" +#include "resource/types.h" + +namespace crown +{ +struct Node +{ + ALLOCATOR_AWARE; + + Matrix4x4 _local_pose; + DynamicString _geometry; + + /// + explicit Node(Allocator &a); +}; + +struct Geometry +{ + ALLOCATOR_AWARE; + + Array _positions; + Array _normals; + Array _uvs; + Array _tangents; + Array _binormals; + + Array _position_indices; + Array _normal_indices; + Array _uv_indices; + Array _tangent_indices; + Array _binormal_indices; + + Array _vertex_buffer; + Array _index_buffer; + + /// + explicit Geometry(Allocator &a); +}; + +struct Mesh +{ + HashMap _geometries; + HashMap _nodes; + + /// + explicit Mesh(Allocator &a); +}; + +namespace mesh +{ + /// + bool has_normals(Geometry &g); + + /// + bool has_uvs(Geometry &g); + + /// + s32 parse(Mesh &m, CompileOptions &opts, const char *path); + + /// + s32 write(Mesh &m, CompileOptions &opts); + +} // namespace mesh + +} // namespace crown diff --git a/src/resource/mesh_resource.cpp b/src/resource/mesh_resource.cpp index 039cb5fa0..d06b1fc49 100644 --- a/src/resource/mesh_resource.cpp +++ b/src/resource/mesh_resource.cpp @@ -20,9 +20,9 @@ #include "core/strings/string_id.inl" #include "device/log.h" #include "resource/compile_options.inl" +#include "resource/mesh.h" #include "resource/mesh_resource.h" #include "resource/resource_manager.h" -#include #include #include // bgfx::write, bgfx::read @@ -52,31 +52,6 @@ struct BgfxReader : public bx::ReaderI } }; -/// Writer interface. -struct BgfxWriter : public bx::WriterI -{ - BinaryWriter *_bw; - - /// - explicit BgfxWriter(BinaryWriter &bw) - : _bw(&bw) - { - } - - /// - virtual ~BgfxWriter() - { - } - - /// - virtual int32_t write(const void *_data, int32_t _size, bx::Error *_err) - { - CE_UNUSED(_err); - _bw->write(_data, _size); - return _size; // FIXME: return the actual number of bytes written - } -}; - MeshResource::MeshResource(Allocator &a) : nodes(a) , geometries(a) @@ -208,7 +183,7 @@ namespace mesh_resource_internal } // namespace mesh_resource_internal #if CROWN_CAN_COMPILE -namespace mesh_resource_internal +namespace mesh { static void parse_float_array(Array &output, const char *json) { @@ -232,369 +207,162 @@ namespace mesh_resource_internal output[i] = (u16)sjson::parse_int(indices[i]); } - namespace mesh - { - s32 parse_nodes(Mesh &m, const char *sjson, CompileOptions &opts); - - s32 parse_node(Node &n, const char *sjson, Mesh *mesh, CompileOptions &opts) - { - TempAllocator4096 ta; - JsonObject obj(ta); - sjson::parse(obj, sjson); - - n._local_pose = sjson::parse_matrix4x4(obj["matrix_local"]); - - if (json_object::has(obj, "children")) { - s32 err = mesh::parse_nodes(*mesh, obj["children"], opts); - DATA_COMPILER_ENSURE(err == 0, opts); - } - - if (json_object::has(obj, "geometry")) - sjson::parse_string(n._geometry, obj["geometry"]); - - return 0; - } - - void reset(Geometry &g) - { - array::clear(g._positions); - array::clear(g._normals); - array::clear(g._uvs); - array::clear(g._tangents); - array::clear(g._binormals); - - array::clear(g._position_indices); - array::clear(g._normal_indices); - array::clear(g._uv_indices); - array::clear(g._tangent_indices); - array::clear(g._binormal_indices); - - array::clear(g._vertex_buffer); - array::clear(g._index_buffer); - } + s32 parse_nodes(Mesh &m, const char *sjson, CompileOptions &opts); - bool has_normals(Geometry &g) - { - return array::size(g._normals) != 0; - } + s32 parse_node(Node &n, const char *sjson, Mesh *mesh, CompileOptions &opts) + { + TempAllocator4096 ta; + JsonObject obj(ta); + sjson::parse(obj, sjson); - bool has_uvs(Geometry &g) - { - return array::size(g._uvs) != 0; - } + n._local_pose = sjson::parse_matrix4x4(obj["matrix_local"]); - u32 vertex_stride(Geometry &g) - { - u32 stride = 0; - stride += 3 * sizeof(f32); - stride += (has_normals(g) ? 3 * sizeof(f32) : 0); - stride += (has_uvs(g) ? 2 * sizeof(f32) : 0); - return stride; + if (json_object::has(obj, "children")) { + s32 err = mesh::parse_nodes(*mesh, obj["children"], opts); + DATA_COMPILER_ENSURE(err == 0, opts); } - bgfx::VertexLayout vertex_layout(Geometry &g) - { - bgfx::VertexLayout layout; - memset((void *)&layout, 0, sizeof(layout)); - - layout.begin(); - layout.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float); - - if (has_normals(g)) { - layout.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float, true); - } - if (has_uvs(g)) { - layout.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float); - } + if (json_object::has(obj, "geometry")) + sjson::parse_string(n._geometry, obj["geometry"]); - layout.end(); - return layout; - } + return 0; + } - void generate_vertex_and_index_buffers(Geometry &g) - { - array::resize(g._index_buffer, array::size(g._position_indices)); - - u16 index = 0; - for (u32 i = 0; i < array::size(g._position_indices); ++i) { - g._index_buffer[i] = index++; - - const u16 p_idx = g._position_indices[i] * 3; - Vector3 xyz; - xyz.x = g._positions[p_idx + 0]; - xyz.y = g._positions[p_idx + 1]; - xyz.z = g._positions[p_idx + 2]; - array::push(g._vertex_buffer, (char *)&xyz, sizeof(xyz)); - - if (has_normals(g)) { - const u16 n_idx = g._normal_indices[i] * 3; - Vector3 n; - n.x = g._normals[n_idx + 0]; - n.y = g._normals[n_idx + 1]; - n.z = g._normals[n_idx + 2]; - array::push(g._vertex_buffer, (char *)&n, sizeof(n)); - } - if (has_uvs(g)) { - const u16 t_idx = g._uv_indices[i] * 2; - Vector2 uv; - uv.x = g._uvs[t_idx + 0]; - uv.y = g._uvs[t_idx + 1]; - array::push(g._vertex_buffer, (char *)&uv, sizeof(uv)); - } - } - } + s32 parse_indices(Geometry &g, const char *json) + { + TempAllocator4096 ta; + JsonObject obj(ta); + sjson::parse(obj, json); - OBB obb(Geometry &g) - { - AABB aabb; - OBB obb; - aabb::reset(aabb); - memset(&obb, 0, sizeof(obb)); + JsonArray data_json(ta); + sjson::parse_array(data_json, obj["data"]); - aabb::from_points(aabb - , array::size(g._positions) / 3 - , sizeof(g._positions[0]) * 3 - , array::begin(g._positions) - ); + parse_index_array(g._position_indices, data_json[0]); - obb.tm = from_quaternion_translation(QUATERNION_IDENTITY, aabb::center(aabb)); - obb.half_extents = (aabb.max - aabb.min) * 0.5f; - return obb; + if (has_normals(g)) { + parse_index_array(g._normal_indices, data_json[1]); } - - s32 parse_indices(Geometry &g, const char *json) - { - TempAllocator4096 ta; - JsonObject obj(ta); - sjson::parse(obj, json); - - JsonArray data_json(ta); - sjson::parse_array(data_json, obj["data"]); - - parse_index_array(g._position_indices, data_json[0]); - - if (has_normals(g)) { - parse_index_array(g._normal_indices, data_json[1]); - } - if (has_uvs(g)) { - parse_index_array(g._uv_indices, data_json[2]); - } - - return 0; + if (has_uvs(g)) { + parse_index_array(g._uv_indices, data_json[2]); } - s32 parse_geometry(Geometry &g, const char *sjson) - { - TempAllocator4096 ta; - JsonObject obj(ta); - sjson::parse(obj, sjson); + return 0; + } - parse_float_array(g._positions, obj["position"]); + s32 parse_geometry(Geometry &g, const char *sjson) + { + TempAllocator4096 ta; + JsonObject obj(ta); + sjson::parse(obj, sjson); - if (json_object::has(obj, "normal")) { - parse_float_array(g._normals, obj["normal"]); - } - if (json_object::has(obj, "texcoord")) { - parse_float_array(g._uvs, obj["texcoord"]); - } + parse_float_array(g._positions, obj["position"]); - return parse_indices(g, obj["indices"]); + if (json_object::has(obj, "normal")) { + parse_float_array(g._normals, obj["normal"]); } - - s32 parse_geometries(Mesh &m, const char *sjson, CompileOptions &opts) - { - TempAllocator4096 ta; - JsonObject geometries(ta); - sjson::parse(geometries, sjson); - - auto cur = json_object::begin(geometries); - auto end = json_object::end(geometries); - for (; cur != end; ++cur) { - JSON_OBJECT_SKIP_HOLE(geometries, cur); - - Geometry geo(default_allocator()); - s32 err = mesh::parse_geometry(geo, cur->second); - DATA_COMPILER_ENSURE(err == 0, opts); - - DynamicString geometry_name(ta); - geometry_name = cur->first; - DATA_COMPILER_ASSERT(!hash_map::has(m._geometries, geometry_name) - , opts - , "Geometry redefined: '%s'" - , geometry_name.c_str() - ); - hash_map::set(m._geometries, geometry_name, geo); - } - - return 0; + if (json_object::has(obj, "texcoord")) { + parse_float_array(g._uvs, obj["texcoord"]); } - s32 parse_nodes(Mesh &m, const char *sjson, CompileOptions &opts) - { - TempAllocator4096 ta; - JsonObject nodes(ta); - sjson::parse(nodes, sjson); - - auto cur = json_object::begin(nodes); - auto end = json_object::end(nodes); - for (; cur != end; ++cur) { - JSON_OBJECT_SKIP_HOLE(nodes, cur); - - Node node(default_allocator()); - s32 err = mesh::parse_node(node, cur->second, &m, opts); - DATA_COMPILER_ENSURE(err == 0, opts); - - DynamicString node_name(ta); - node_name = cur->first; - DATA_COMPILER_ASSERT(!hash_map::has(m._nodes, node_name) - , opts - , "Node redefined: '%s'" - , node_name.c_str() - ); - - // For backwards compatibility: originally .mesh resources - // enforced (implicitly) a 1:1 relationship between nodes - // and geometries. - if (node._geometry == "") - node._geometry = node_name; - - DATA_COMPILER_ASSERT(hash_map::has(m._geometries, node._geometry) - , opts - , "Node '%s' references unexisting geometry '%s'" - , node_name.c_str() - , node._geometry.c_str() - ); - hash_map::set(m._nodes, node_name, node); - } + return parse_indices(g, obj["indices"]); + } - return 0; - } + s32 parse_geometries(Mesh &m, const char *sjson, CompileOptions &opts) + { + TempAllocator4096 ta; + JsonObject geometries(ta); + sjson::parse(geometries, sjson); - s32 parse(Mesh &m, Buffer &buf, CompileOptions &opts) - { - TempAllocator4096 ta; - JsonObject nodes(ta); - JsonObject obj(ta); - sjson::parse(obj, buf); + auto cur = json_object::begin(geometries); + auto end = json_object::end(geometries); + for (; cur != end; ++cur) { + JSON_OBJECT_SKIP_HOLE(geometries, cur); - s32 err = mesh::parse_geometries(m, obj["geometries"], opts); + Geometry geo(default_allocator()); + s32 err = mesh::parse_geometry(geo, cur->second); DATA_COMPILER_ENSURE(err == 0, opts); - return mesh::parse_nodes(m, obj["nodes"], opts); - } - - s32 parse(Mesh &m, CompileOptions &opts) - { - return mesh::parse(m, opts, opts._source_path.c_str()); - } - - void geometry_names(Vector &names, const Mesh &m, const DynamicString &geometry) - { - auto cur = hash_map::begin(m._nodes); - auto end = hash_map::end(m._nodes); - for (; cur != end; ++cur) { - HASH_MAP_SKIP_HOLE(m._nodes, cur); - - if (cur->second._geometry == geometry) - vector::push_back(names, cur->first); - } + DynamicString geometry_name(ta); + geometry_name = cur->first; + DATA_COMPILER_ASSERT(!hash_map::has(m._geometries, geometry_name) + , opts + , "Geometry redefined: '%s'" + , geometry_name.c_str() + ); + hash_map::set(m._geometries, geometry_name, geo); } - s32 write(Mesh &m, CompileOptions &opts) - { - opts.write(RESOURCE_HEADER(RESOURCE_VERSION_MESH)); - opts.write(hash_map::size(m._geometries)); - - auto cur = hash_map::begin(m._geometries); - auto end = hash_map::end(m._geometries); - for (; cur != end; ++cur) { - HASH_MAP_SKIP_HOLE(m._geometries, cur); - - Vector geo_names(default_allocator()); - geometry_names(geo_names, m, cur->first); - u32 num_geo_names = vector::size(geo_names); - - opts.write(num_geo_names); - for (u32 i = 0; i < num_geo_names; ++i) - opts.write(geo_names[i].to_string_id()._id); - - Geometry *geo = (Geometry *)&cur->second; - mesh::generate_vertex_and_index_buffers(*geo); - - bgfx::VertexLayout layout = mesh::vertex_layout(*geo); - u32 stride = mesh::vertex_stride(*geo); - OBB bbox = mesh::obb(*geo); - - BgfxWriter writer(opts._binary_writer); - bgfx::write(&writer, layout); - opts.write(bbox); - - opts.write(array::size(geo->_vertex_buffer) / stride); - opts.write(stride); - opts.write(array::size(geo->_index_buffer)); + return 0; + } - opts.write(geo->_vertex_buffer); - opts.write(array::begin(geo->_index_buffer), array::size(geo->_index_buffer) * sizeof(u16)); - } + s32 parse_nodes(Mesh &m, const char *sjson, CompileOptions &opts) + { + TempAllocator4096 ta; + JsonObject nodes(ta); + sjson::parse(nodes, sjson); - return 0; - } + auto cur = json_object::begin(nodes); + auto end = json_object::end(nodes); + for (; cur != end; ++cur) { + JSON_OBJECT_SKIP_HOLE(nodes, cur); - } // namespace mesh + Node node(default_allocator()); + s32 err = mesh::parse_node(node, cur->second, &m, opts); + DATA_COMPILER_ENSURE(err == 0, opts); - namespace mesh - { - s32 parse(Mesh &m, CompileOptions &opts, const char *path) - { - Buffer buf = opts.read(path); + DynamicString node_name(ta); + node_name = cur->first; + DATA_COMPILER_ASSERT(!hash_map::has(m._nodes, node_name) + , opts + , "Node redefined: '%s'" + , node_name.c_str() + ); - if (str_has_suffix(path, ".mesh")) - return mesh::parse(m, buf, opts); + // For backwards compatibility: originally .mesh resources + // enforced (implicitly) a 1:1 relationship between nodes + // and geometries. + if (node._geometry == "") + node._geometry = node_name; - DATA_COMPILER_ASSERT(false + DATA_COMPILER_ASSERT(hash_map::has(m._geometries, node._geometry) , opts - , "Unknown mesh '%s'" - , path + , "Node '%s' references unexisting geometry '%s'" + , node_name.c_str() + , node._geometry.c_str() ); + hash_map::set(m._nodes, node_name, node); } - } // namespace mesh - - Node::Node(Allocator &a) - : _local_pose(MATRIX4X4_IDENTITY) - , _geometry(a) - { + return 0; } - Geometry::Geometry(Allocator &a) - : _positions(a) - , _normals(a) - , _uvs(a) - , _tangents(a) - , _binormals(a) - , _position_indices(a) - , _normal_indices(a) - , _uv_indices(a) - , _tangent_indices(a) - , _binormal_indices(a) - , _vertex_buffer(a) - , _index_buffer(a) + s32 parse(Mesh &m, Buffer &buf, CompileOptions &opts) { - mesh::reset(*this); + TempAllocator4096 ta; + JsonObject nodes(ta); + JsonObject obj(ta); + sjson::parse(obj, buf); + + s32 err = mesh::parse_geometries(m, obj["geometries"], opts); + DATA_COMPILER_ENSURE(err == 0, opts); + + return mesh::parse_nodes(m, obj["nodes"], opts); } - Mesh::Mesh(Allocator &a) - : _geometries(a) - , _nodes(a) + s32 parse(Mesh &m, CompileOptions &opts) { + return mesh::parse(m, opts, opts._source_path.c_str()); } +} + +namespace mesh_resource_internal +{ s32 compile(CompileOptions &opts) { Mesh mesh(default_allocator()); s32 err = mesh::parse(mesh, opts); DATA_COMPILER_ENSURE(err == 0, opts); - return mesh::write(mesh, opts); } diff --git a/src/resource/mesh_resource.h b/src/resource/mesh_resource.h index 298385162..6a664c023 100644 --- a/src/resource/mesh_resource.h +++ b/src/resource/mesh_resource.h @@ -5,12 +5,13 @@ #pragma once +#include "core/containers/types.h" #include "core/filesystem/types.h" #include "core/math/types.h" #include "core/memory/types.h" #include "core/strings/dynamic_string.h" #include "core/strings/string_id.h" -#include "resource/types.h" +#include "resource/mesh.h" #include "resource/types.h" #include @@ -57,62 +58,27 @@ struct MeshResource const MeshGeometry *geometry(StringId32 name) const; }; -namespace mesh_resource_internal +namespace mesh { - struct Node - { - ALLOCATOR_AWARE; - - Matrix4x4 _local_pose; - DynamicString _geometry; - - /// - explicit Node(Allocator &a); - }; - - struct Geometry - { - ALLOCATOR_AWARE; - - Array _positions; - Array _normals; - Array _uvs; - Array _tangents; - Array _binormals; - - Array _position_indices; - Array _normal_indices; - Array _uv_indices; - Array _tangent_indices; - Array _binormal_indices; - - Array _vertex_buffer; - Array _index_buffer; - - /// - explicit Geometry(Allocator &a); - }; - - struct Mesh - { - HashMap _geometries; - HashMap _nodes; - - /// - explicit Mesh(Allocator &a); - }; - - namespace mesh - { - /// - s32 parse(Mesh &m, CompileOptions &opts, const char *path); - - } // namespace mesh + /// + s32 parse(Mesh &m, Buffer &buf, CompileOptions &opts); +} +namespace mesh_resource_internal +{ + /// s32 compile(CompileOptions &opts); + + /// void *load(File &file, Allocator &a); + + /// void online(StringId64 /*id*/, ResourceManager & /*rm*/); + + /// void offline(StringId64 /*id*/, ResourceManager & /*rm*/); + + /// void unload(Allocator &a, void *res); } // namespace mesh_resource_internal diff --git a/src/resource/physics_resource.cpp b/src/resource/physics_resource.cpp index e3f52a93f..48cca1a96 100644 --- a/src/resource/physics_resource.cpp +++ b/src/resource/physics_resource.cpp @@ -20,6 +20,7 @@ #include "core/strings/string.inl" #include "core/strings/string_id.inl" #include "resource/compile_options.inl" +#include "resource/mesh.h" #include "resource/mesh_resource.h" #include "resource/physics_resource.h" #include "world/types.h" @@ -193,23 +194,20 @@ namespace physics_resource_internal sjson::parse_string(name, obj["name"]); // Parse mesh resource. - if (opts.resource_exists("mesh", scene.c_str())) - scene += ".mesh"; - - mesh_resource_internal::Mesh mesh(default_allocator()); - s32 err = mesh_resource_internal::mesh::parse(mesh, opts, scene.c_str()); + Mesh mesh(default_allocator()); + s32 err = mesh::parse(mesh, opts, scene.c_str()); DATA_COMPILER_ENSURE(err == 0, opts); - mesh_resource_internal::Node deffault_node(default_allocator()); - mesh_resource_internal::Node &node = hash_map::get(mesh._nodes, name, deffault_node); + Node deffault_node(default_allocator()); + Node &node = hash_map::get(mesh._nodes, name, deffault_node); DATA_COMPILER_ASSERT(&node != &deffault_node , opts , "Node '%s' does not exist" , name.c_str() ); - mesh_resource_internal::Geometry deffault_geometry(default_allocator()); - mesh_resource_internal::Geometry &geometry = hash_map::get(mesh._geometries, node._geometry, deffault_geometry); + Geometry deffault_geometry(default_allocator()); + Geometry &geometry = hash_map::get(mesh._geometries, node._geometry, deffault_geometry); DATA_COMPILER_ASSERT(&geometry != &deffault_geometry , opts , "Geometry '%s' does not exist" diff --git a/src/resource/unit_compiler.cpp b/src/resource/unit_compiler.cpp index a25cf8861..a6edacdf5 100644 --- a/src/resource/unit_compiler.cpp +++ b/src/resource/unit_compiler.cpp @@ -18,6 +18,7 @@ #include "core/strings/string_id.inl" #include "resource/compile_options.inl" #include "resource/physics_resource.h" +#include "resource/resource_id.inl" #include "resource/unit_compiler.h" #include "resource/unit_resource.h" #include "world/types.h" @@ -130,10 +131,17 @@ static s32 compile_mesh_renderer(Buffer &output, const char *json, CompileOption DynamicString mesh_resource(ta); sjson::parse_string(mesh_resource, obj["mesh_resource"]); - DATA_COMPILER_ASSERT_RESOURCE_EXISTS("mesh" - , mesh_resource.c_str() + + DATA_COMPILER_ENSURE(opts.resource_exists("mesh", mesh_resource.c_str()) + || opts.file_exists(mesh_resource.c_str()) , opts ); + + const char *mesh_resource_type = resource_type(mesh_resource.c_str()); + if (mesh_resource_type != NULL) { + u32 name_len = resource_name_length(mesh_resource_type, mesh_resource.c_str()); + array::resize(mesh_resource._data, name_len); + } opts.add_requirement("mesh", mesh_resource.c_str()); DynamicString material(ta); @@ -145,7 +153,7 @@ static s32 compile_mesh_renderer(Buffer &output, const char *json, CompileOption opts.add_requirement("material", material.c_str()); MeshRendererDesc mrd; - mrd.mesh_resource = sjson::parse_resource_name(obj["mesh_resource"]); + mrd.mesh_resource = StringId64(mesh_resource.c_str()); mrd.material_resource = sjson::parse_resource_name(obj["material"]); mrd.geometry_name = sjson::parse_string_id (obj["geometry_name"]); mrd.visible = sjson::parse_bool (obj["visible"]); diff --git a/tools/resource/mesh_resource.vala b/tools/resource/mesh_resource.vala index 13cd1acf7..035f9a189 100644 --- a/tools/resource/mesh_resource.vala +++ b/tools/resource/mesh_resource.vala @@ -41,7 +41,7 @@ public class MeshResource unit.set_component_property_string(component_id, "data.geometry_name", node_name); unit.set_component_property_string(component_id, "data.material", material_name); - unit.set_component_property_string(component_id, "data.mesh_resource", resource_name); + unit.set_component_property_string(component_id, "data.mesh_resource", resource_name + ".mesh"); unit.set_component_property_bool (component_id, "data.visible", true); } @@ -172,7 +172,14 @@ public class MeshResource new_unit_id = Guid.new_guid(); db.create(new_unit_id, OBJECT_TYPE_UNIT); } - create_components(db, unit_id, new_unit_id, material_name, resource_name, entry.key, (Hashtable)entry.value); + create_components(db + , unit_id + , new_unit_id + , material_name + , resource_name + , entry.key + , (Hashtable)entry.value + ); } db.save(project.absolute_path(resource_name) + ".unit", unit_id);