Browse Source

resource: many nodes can refer to the same geometry

Part-of: #207
Daniele Bartolini 1 năm trước cách đây
mục cha
commit
529f385357

+ 1 - 0
docs/changelog.rst

@@ -22,6 +22,7 @@ Changelog
 **Runtime**
 
 * Lua API: 3D Gui will now place objects on the new XY plane (on the "floor") by default.
+* Data Compiler: .mesh resource can now have shared geometries between nodes.
 
 0.53.0 --- 30 Nov 2024
 ----------------------

+ 50 - 12
src/resource/mesh_resource.cpp

@@ -78,16 +78,16 @@ struct BgfxWriter : public bx::WriterI
 };
 
 MeshResource::MeshResource(Allocator &a)
-	: geometry_names(a)
+	: nodes(a)
 	, geometries(a)
 {
 }
 
 const MeshGeometry *MeshResource::geometry(StringId32 name) const
 {
-	for (u32 i = 0; i < array::size(geometry_names); ++i) {
-		if (geometry_names[i] == name)
-			return geometries[i];
+	for (u32 i = 0; i < array::size(nodes); ++i) {
+		if (nodes[i].name == name)
+			return geometries[nodes[i].geometry_index];
 	}
 
 	CE_FATAL("Mesh name not found");
@@ -108,12 +108,17 @@ namespace mesh_resource_internal
 		br.read(num_geoms);
 
 		MeshResource *mr = CE_NEW(a, MeshResource)(a);
-		array::resize(mr->geometry_names, num_geoms);
-		array::resize(mr->geometries, num_geoms);
 
 		for (u32 i = 0; i < num_geoms; ++i) {
-			StringId32 name;
-			br.read(name);
+			u32 num_names;
+			br.read(num_names);
+
+			for (u32 j = 0; j < num_names; ++j) {
+				StringId32 name;
+				br.read(name);
+
+				array::push_back(mr->nodes, { name, i });
+			}
 
 			bgfx::VertexLayout layout;
 			BgfxReader reader(br);
@@ -150,8 +155,7 @@ namespace mesh_resource_internal
 			br.read(mg->vertices.data, vsize);
 			br.read(mg->indices.data, isize);
 
-			mr->geometry_names[i] = name;
-			mr->geometries[i] = mg;
+			array::push_back(mr->geometries, mg);
 		}
 
 		return mr;
@@ -245,6 +249,9 @@ namespace mesh_resource_internal
 				DATA_COMPILER_ENSURE(err == 0, opts);
 			}
 
+			if (json_object::has(obj, "geometry"))
+				sjson::parse_string(n._geometry, obj["geometry"]);
+
 			return 0;
 		}
 
@@ -445,6 +452,18 @@ namespace mesh_resource_internal
 					, 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);
 			}
 
@@ -469,6 +488,18 @@ namespace mesh_resource_internal
 			return mesh::parse(m, opts, opts._source_path.c_str());
 		}
 
+		void geometry_names(Vector<DynamicString> &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);
+			}
+		}
+
 		s32 write(Mesh &m, CompileOptions &opts)
 		{
 			opts.write(RESOURCE_HEADER(RESOURCE_VERSION_MESH));
@@ -479,11 +510,17 @@ namespace mesh_resource_internal
 			for (; cur != end; ++cur) {
 				HASH_MAP_SKIP_HOLE(m._geometries, cur);
 
+				Vector<DynamicString> 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);
 
-				opts.write(cur->first.to_string_id()._id);
-
 				bgfx::VertexLayout layout = mesh::vertex_layout(*geo);
 				u32 stride = mesh::vertex_stride(*geo);
 				OBB bbox = mesh::obb(*geo);
@@ -525,6 +562,7 @@ namespace mesh_resource_internal
 
 	Node::Node(Allocator &a)
 		: _local_pose(MATRIX4X4_IDENTITY)
+		, _geometry(a)
 	{
 	}
 

+ 8 - 1
src/resource/mesh_resource.h

@@ -39,9 +39,15 @@ struct MeshGeometry
 	IndexData indices;
 };
 
+struct MeshNode
+{
+	StringId32 name;
+	u32 geometry_index;
+};
+
 struct MeshResource
 {
-	Array<StringId32> geometry_names;
+	Array<MeshNode> nodes;
 	Array<MeshGeometry *> geometries;
 
 	///
@@ -58,6 +64,7 @@ namespace mesh_resource_internal
 		ALLOCATOR_AWARE;
 
 		Matrix4x4 _local_pose;
+		DynamicString _geometry;
 
 		///
 		explicit Node(Allocator &a);

+ 8 - 8
src/resource/physics_resource.cpp

@@ -200,14 +200,6 @@ namespace physics_resource_internal
 			s32 err = mesh_resource_internal::mesh::parse(mesh, opts, scene.c_str());
 			DATA_COMPILER_ENSURE(err == 0, opts);
 
-			mesh_resource_internal::Geometry deffault_geometry(default_allocator());
-			mesh_resource_internal::Geometry &geometry = hash_map::get(mesh._geometries, name, deffault_geometry);
-			DATA_COMPILER_ASSERT(&geometry != &deffault_geometry
-				, opts
-				, "Geometry '%s' does not exist"
-				, name.c_str()
-				);
-
 			mesh_resource_internal::Node deffault_node(default_allocator());
 			mesh_resource_internal::Node &node = hash_map::get(mesh._nodes, name, deffault_node);
 			DATA_COMPILER_ASSERT(&node != &deffault_node
@@ -216,6 +208,14 @@ namespace physics_resource_internal
 				, 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);
+			DATA_COMPILER_ASSERT(&geometry != &deffault_geometry
+				, opts
+				, "Geometry '%s' does not exist"
+				, node._geometry.c_str()
+				);
+
 			for (u32 i = 0; i < array::size(geometry._positions); i += 3) {
 				Vector3 p;
 				p.x = geometry._positions[i + 0];

+ 1 - 1
src/resource/types.h

@@ -80,7 +80,7 @@ struct Platform
 #define RESOURCE_VERSION_UNIT             RESOURCE_VERSION(10)
 #define RESOURCE_VERSION_LEVEL            (RESOURCE_VERSION_UNIT + 4) //!< Level embeds UnitResource
 #define RESOURCE_VERSION_MATERIAL         RESOURCE_VERSION(5)
-#define RESOURCE_VERSION_MESH             RESOURCE_VERSION(5)
+#define RESOURCE_VERSION_MESH             RESOURCE_VERSION(6)
 #define RESOURCE_VERSION_PACKAGE          RESOURCE_VERSION(7)
 #define RESOURCE_VERSION_PHYSICS_CONFIG   RESOURCE_VERSION(2)
 #define RESOURCE_VERSION_SCRIPT           RESOURCE_VERSION(4)