From a9b5a03f94dcb7f76e5af0f0165ad0fb0c404100 Mon Sep 17 00:00:00 2001 From: ecker Date: Mon, 11 Aug 2025 21:14:30 -0500 Subject: [PATCH] shuffled code around for when I figure out how I want to stream a partitioned mesh (even though this defeats the purpose of re-implementing the chunk/region system because I do not want to go about splitting each region into its own model-entity-graph-whatever) --- Makefile | 2 +- bin/data/scenes/sourceengine/ss2_medsci1.json | 4 +- bin/dreamcast/data/config.json | 2 +- engine/inc/uf/engine/graph/graph.h | 2 + engine/inc/uf/utils/mesh/grid.h | 57 ---- engine/src/engine/graph/decode.cpp | 5 + engine/src/engine/graph/graph.cpp | 312 ++++++++++-------- 7 files changed, 186 insertions(+), 198 deletions(-) diff --git a/Makefile b/Makefile index e377120c..9a89185e 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ FLAGS += -DUF_DEV_ENV ifneq (,$(findstring win64,$(ARCH))) ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS))) REQ_DEPS += meshoptimizer toml xatlas curl ffx:fsr cpptrace vall_e # ncurses openvr draco discord bullet ultralight-ux - FLAGS += -march=native -flto # -g + FLAGS += -march=native # -flto # -g endif REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit reactphysics simd ctti gltf imgui fmt freetype openal ogg wav FLAGS += -DUF_ENV_WINDOWS -DUF_ENV_WIN64 -DWIN32_LEAN_AND_MEAN diff --git a/bin/data/scenes/sourceengine/ss2_medsci1.json b/bin/data/scenes/sourceengine/ss2_medsci1.json index 978b8e10..ad352bf7 100644 --- a/bin/data/scenes/sourceengine/ss2_medsci1.json +++ b/bin/data/scenes/sourceengine/ss2_medsci1.json @@ -3,8 +3,10 @@ "assets": [ // { "filename": "./models/ss2_medsci1.glb" } // { "filename": "./models/ss2_medsci1/graph.json" } - // { "filename": "./models/ss2_medsci1_smallish/graph.json" } + // { "filename": "./models/ss2_medsci1_small.glb" } { "filename": "./models/ss2_medsci1_small/graph.json" } + // { "filename": "./models/ss2_medsci1_smallish.glb" } + // { "filename": "./models/ss2_medsci1_smallish/graph.json" } ], "metadata": { "graph": { diff --git a/bin/dreamcast/data/config.json b/bin/dreamcast/data/config.json index 0d7a72f8..dba9288d 100644 --- a/bin/dreamcast/data/config.json +++ b/bin/dreamcast/data/config.json @@ -1,7 +1,7 @@ { "engine": { "scenes": { - "start": "SourceEngine", + "start": "StartMenu", "matrix": { "reverseInfinite": true }, "meshes": { "interleaved": false }, "lights": { "enabled": true, diff --git a/engine/inc/uf/engine/graph/graph.h b/engine/inc/uf/engine/graph/graph.h index dd45c5f2..358de2cc 100644 --- a/engine/inc/uf/engine/graph/graph.h +++ b/engine/inc/uf/engine/graph/graph.h @@ -152,6 +152,8 @@ namespace uf { uf::stl::string UF_API print( const pod::Graph& graph ); uf::Serializer UF_API stats( const pod::Graph& graph ); + void UF_API reload( pod::Graph& graph ); + void UF_API reload( pod::Graph& graph, pod::Node& node ); void UF_API reload(); } } diff --git a/engine/inc/uf/utils/mesh/grid.h b/engine/inc/uf/utils/mesh/grid.h index 5ad38399..3332f584 100644 --- a/engine/inc/uf/utils/mesh/grid.h +++ b/engine/inc/uf/utils/mesh/grid.h @@ -83,55 +83,6 @@ namespace uf { uf::meshgrid::calculate( grid, eps ); - // it's better to naively clip the mesh multiple times rather than calculate the triangles needed to clip - /* - if ( clip ) { - for ( auto& pair : grid.nodes ) { - ++atlasID; - for ( auto& meshlet : meshlets ) { - auto& node = pair.second; - - uf::stl::vector vertices = meshlet.vertices; - uf::stl::vector indices = meshlet.indices; - - uf::shapes::clip( vertices, indices, node.extents.min, node.extents.max ); - - if ( vertices.empty() || indices.empty() ) continue; - - size_t primitiveID = partitioned.size(); - auto& slice = partitioned.emplace_back(); - - slice.vertices = std::move( vertices ); - slice.indices = std::move( indices ); - - for ( auto& vertex : slice.vertices ) { - vertex.id.x = primitiveID; - vertex.id.y = meshlet.primitive.instance.meshID; - } - - slice.primitive.instance = meshlet.primitive.instance; - slice.primitive.instance.materialID = meshlet.primitive.instance.materialID; - slice.primitive.instance.primitiveID = primitiveID; - slice.primitive.instance.meshID = meshlet.primitive.instance.meshID; - slice.primitive.instance.objectID = 0; - slice.primitive.instance.auxID = atlasID; - slice.primitive.instance.bounds.min = node.extents.min; - slice.primitive.instance.bounds.max = node.extents.max; - - slice.primitive.drawCommand.indices = slice.indices.size(); - slice.primitive.drawCommand.instances = 1; - slice.primitive.drawCommand.indexID = 0; - slice.primitive.drawCommand.vertexID = 0; - slice.primitive.drawCommand.instanceID = 0; - slice.primitive.drawCommand.auxID = atlasID; // meshlet.primitive.instance.meshID; - slice.primitive.drawCommand.vertices = slice.vertices.size(); - } - } - - return partitioned; - } - */ - for ( auto& meshlet : meshlets ) uf::meshgrid::partition( grid, meshlet.vertices, meshlet.indices, meshlet.primitive ); if ( cleanup ) uf::meshgrid::cleanup( grid ); @@ -155,14 +106,6 @@ namespace uf { vertex.id.y = meshlet.primitive.instance.meshID; } - /* - if ( clip ) { - node.effectiveExtents.min = node.extents.min; - node.effectiveExtents.max = node.extents.max; - uf::shapes::clip( slice.vertices, slice.indices, node.extents.min, node.extents.max ); - } - */ - slice.primitive.instance = meshlet.primitive.instance; slice.primitive.instance.materialID = meshlet.primitive.instance.materialID; slice.primitive.instance.primitiveID = primitiveID; diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index 8a02cf62..d9192a27 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -65,6 +65,11 @@ namespace { sampler.descriptor.addressMode.u = (uf::renderer::enums::AddressMode::type_t) json["u"].as(); sampler.descriptor.addressMode.v = (uf::renderer::enums::AddressMode::type_t) json["v"].as(); sampler.descriptor.addressMode.w = sampler.descriptor.addressMode.v; + + #if UF_ENV_DREAMCAST + sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST; + sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; + #endif return sampler; } diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 72993b2e..20cd65a4 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -226,6 +226,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M auto& sceneMetadataJson = scene.getComponent(); auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent(); + auto& graphic = entity.getComponent(); graphic.initialize(); graphic.initializeMesh( mesh ); @@ -1217,132 +1218,9 @@ void uf::graph::process( pod::Graph& graph ) { } UF_DEBUG_TIMER_MULTITRACE("Updating master graph"); + uf::graph::reload( graph ); uf::graph::reload(); - - // setup combined mesh if requested - if ( !(graph.metadata["renderer"]["separate"].as()) ) { - UF_DEBUG_TIMER_MULTITRACE("Processing root graphic"); - - graph.root.mesh = graph.meshes.size(); - auto keyName = graph.name + "/" + graph.root.name; - auto& mesh = storage.meshes[graph.meshes.emplace_back(keyName)]; - - mesh.bindIndirect(); - #if UF_ENV_DREAMCAST - mesh.bind(); - #else - mesh.bind(); - #endif - /* - { - #if UF_ENV_DREAMCAST - mesh.bind(); - // mesh.convert(); - #else - auto conversion = graph.metadata["decode"]["conversion"].as(); - if ( conversion != "" ) { - if ( conversion == "uint16_t" ) mesh.bind(); - #if UF_USE_FLOAT16 - else if ( conversion == "float16" ) mesh.bind(); - #endif - #if UF_USE_BFLOAT16 - else if ( conversion == "bfloat16" ) mesh.bind(); - #endif - else mesh.bind(); - } else mesh.bind(); - #endif - } - */ - - uf::stl::vector drawCommands; - - size_t counts = 0; - for ( auto& name : graph.meshes ) { - if ( name == keyName ) continue; - auto tag = ext::json::find( name, graph.metadata["tags"] ); - if ( ext::json::isObject( tag ) ) { - if ( tag["ignore"].as() ) continue; - } - - auto& m = storage.meshes.map[name]; - m.updateDescriptor(); - - mesh.insertVertices( m ); - mesh.insertIndices( m ); - mesh.insertInstances( m ); - - // mesh.insertIndirects( m ); - pod::DrawCommand* drawCommand = (pod::DrawCommand*) m.getBuffer( m.indirect ).data(); - for ( size_t i = 0; i < m.indirect.count; ++i ) drawCommands.emplace_back( drawCommand[i] ); - } - - // fix up draw command for combined mesh - { - size_t totalIndices = 0; - size_t totalVertices = 0; - for ( auto& drawCommand : drawCommands ) { - drawCommand.indexID = totalIndices; - drawCommand.vertexID = totalVertices; - - totalIndices += drawCommand.indices; - totalVertices += drawCommand.vertices; - } - - mesh.insertIndirects( drawCommands ); - } - - #if UF_ENV_DREAMCAST - { - uf::stl::vector attributesKept = ext::json::vector(graph.metadata["decode"]["attributes"]); - if ( !mesh.isInterleaved() ) { - uf::stl::vector remove; remove.reserve(mesh.vertex.attributes.size()); - - for ( size_t i = 0; i < mesh.vertex.attributes.size(); ++i ) { - auto& attribute = mesh.vertex.attributes[i]; - if ( std::find( attributesKept.begin(), attributesKept.end(), attribute.descriptor.name ) != attributesKept.end() ) continue; - remove.insert(remove.begin(), i); - UF_MSG_DEBUG("Removing mesh attribute: {}", attribute.descriptor.name); - } - for ( auto& i : remove ) { - mesh.buffers[mesh.vertex.attributes[i].buffer].clear(); - mesh.buffers[mesh.vertex.attributes[i].buffer].shrink_to_fit(); - mesh.vertex.attributes.erase(mesh.vertex.attributes.begin() + i); - } - } else { - UF_MSG_DEBUG("Attribute removal requested yet mesh is interleaved, ignoring..."); - } - } - #endif - { - #if UF_ENV_DREAMCAST && GL_QUANTIZED_SHORT - mesh.convert(); - UF_MSG_DEBUG("Quantizing mesh to GL_QUANTIZED_SHORT"); - #else - auto conversion = graph.metadata["decode"]["conversion"].as(); - if ( conversion != "" ) { - #if UF_USE_FLOAT16 - if ( conversion == "float16" ) mesh.convert(); - else if ( conversion == "float" ) mesh.convert(); - #endif - #if UF_USE_BFLOAT16 - if ( conversion == "bfloat16" ) mesh.convert(); - else if ( conversion == "float" ) mesh.convert(); - #endif - if ( conversion == "uint16_t" ) mesh.convert(); - else if ( conversion == "float" ) mesh.convert(); - } - #endif - } - - mesh.updateDescriptor(); - - { - auto& graphic = graph.root.entity->getComponent(); - uf::graph::initializeGraphics( graph, *graph.root.entity, mesh ); - } - } - storage.instanceAddresses.keys = storage.instances.keys; UF_DEBUG_TIMER_MULTITRACE_END("Processed graph."); } @@ -1520,7 +1398,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) size_t objectID = storage.entities.keys.size(); auto objectKeyName = std::to_string(objectID); storage.entities[objectKeyName] = &entity; - + + // if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { auto model = uf::transform::model( transform ); auto& mesh = storage.meshes.map[graph.meshes[node.mesh]]; @@ -1553,9 +1432,6 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) drawCommand.instanceID = instanceID; } } - if ( (graph.metadata["renderer"]["separate"].as()) && graph.metadata["renderer"]["render"].as() ) { - uf::graph::initializeGraphics( graph, entity, mesh ); - } { auto phyziks = tag["physics"]; @@ -1565,16 +1441,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) if ( ext::json::isObject( phyziks ) ) { uf::stl::string type = phyziks["type"].as(); - if ( type == "mesh" ) { - auto& collider = entity.getComponent(); - collider.stats.mass = phyziks["mass"].as(collider.stats.mass); - collider.stats.friction = phyziks["friction"].as(collider.stats.friction); - collider.stats.restitution = phyziks["restitution"].as(collider.stats.restitution); - collider.stats.inertia = uf::vector::decode( phyziks["inertia"], collider.stats.inertia ); - collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity ); - - uf::physics::impl::create( entity.as(), mesh, !phyziks["static"].as(true) ); - } else { + if ( type != "mesh" ) { auto min = uf::matrix::multiply( model, bounds.min, 1.0f ); auto max = uf::matrix::multiply( model, bounds.max, 1.0f ); @@ -1587,6 +1454,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) } } } + for ( auto index : node.children ) uf::graph::process( graph, index, entity ); } void uf::graph::cleanup( pod::Graph& graph ) { @@ -1988,6 +1856,174 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) { uf::renderer::states::rebuild = true; } +void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { + if ( !(0 <= node.mesh && node.mesh < graph.meshes.size()) ) return; + + auto& scene = uf::scene::getCurrentScene(); + auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent(); + + auto& entity = node.entity->as(); + + auto& metadata = entity.getComponent(); + auto& metadataJson = entity.getComponent(); + auto& transform = entity.getComponent>(); + + ext::json::Value tag = ext::json::find( node.name, graph.metadata["tags"] ); + + if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { + auto model = uf::transform::model( transform ); + auto& mesh = storage.meshes.map[graph.meshes[node.mesh]]; + + #if 0 + if ( (graph.metadata["renderer"]["separate"].as()) && graph.metadata["renderer"]["render"].as() ) { + #endif + if ( graph.metadata["renderer"]["render"].as() ) { + bool exists = entity.hasComponent(); + if ( exists ) { + auto& graphic = entity.getComponent(); + graphic.updateMesh( mesh ); + } else { + uf::graph::initializeGraphics( graph, entity, mesh ); + } + } + { + auto phyziks = tag["physics"]; + if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"]; + else metadataJson["physics"] = phyziks; + + if ( ext::json::isObject( phyziks ) ) { + uf::stl::string type = phyziks["type"].as(); + if ( type == "mesh" ) { + bool exists = entity.hasComponent(); + if ( exists ) { + uf::physics::terminate( entity ); + // entity.deleteComponent(); + } + auto& collider = entity.getComponent(); + + collider.stats.mass = phyziks["mass"].as(collider.stats.mass); + collider.stats.friction = phyziks["friction"].as(collider.stats.friction); + collider.stats.restitution = phyziks["restitution"].as(collider.stats.restitution); + collider.stats.inertia = uf::vector::decode( phyziks["inertia"], collider.stats.inertia ); + collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity ); + + uf::physics::impl::create( entity, mesh, !phyziks["static"].as(true) ); + } + } + } + } +} +void uf::graph::reload( pod::Graph& graph ) { + // update graphics + for ( auto& node : graph.nodes ) uf::graph::reload( graph, node ); + + // setup combined mesh if requested + // disabled for now +#if 0 + if ( !(graph.metadata["renderer"]["separate"].as()) ) { + UF_DEBUG_TIMER_MULTITRACE("Processing root graphic"); + + graph.root.mesh = graph.meshes.size(); + auto keyName = graph.name + "/" + graph.root.name; + auto& mesh = storage.meshes[graph.meshes.emplace_back(keyName)]; + + mesh.bindIndirect(); + #if UF_ENV_DREAMCAST + mesh.bind(); + #else + mesh.bind(); + #endif + + uf::stl::vector drawCommands; + + size_t counts = 0; + for ( auto& name : graph.meshes ) { + if ( name == keyName ) continue; + auto tag = ext::json::find( name, graph.metadata["tags"] ); + if ( ext::json::isObject( tag ) ) { + if ( tag["ignore"].as() ) continue; + } + + auto& m = storage.meshes.map[name]; + m.updateDescriptor(); + + mesh.insertVertices( m ); + mesh.insertIndices( m ); + mesh.insertInstances( m ); + + // mesh.insertIndirects( m ); + pod::DrawCommand* drawCommand = (pod::DrawCommand*) m.getBuffer( m.indirect ).data(); + for ( size_t i = 0; i < m.indirect.count; ++i ) drawCommands.emplace_back( drawCommand[i] ); + } + + // fix up draw command for combined mesh + { + size_t totalIndices = 0; + size_t totalVertices = 0; + for ( auto& drawCommand : drawCommands ) { + drawCommand.indexID = totalIndices; + drawCommand.vertexID = totalVertices; + + totalIndices += drawCommand.indices; + totalVertices += drawCommand.vertices; + } + + mesh.insertIndirects( drawCommands ); + } + + #if UF_ENV_DREAMCAST + { + uf::stl::vector attributesKept = ext::json::vector(graph.metadata["decode"]["attributes"]); + if ( !mesh.isInterleaved() ) { + uf::stl::vector remove; remove.reserve(mesh.vertex.attributes.size()); + + for ( size_t i = 0; i < mesh.vertex.attributes.size(); ++i ) { + auto& attribute = mesh.vertex.attributes[i]; + if ( std::find( attributesKept.begin(), attributesKept.end(), attribute.descriptor.name ) != attributesKept.end() ) continue; + remove.insert(remove.begin(), i); + UF_MSG_DEBUG("Removing mesh attribute: {}", attribute.descriptor.name); + } + for ( auto& i : remove ) { + mesh.buffers[mesh.vertex.attributes[i].buffer].clear(); + mesh.buffers[mesh.vertex.attributes[i].buffer].shrink_to_fit(); + mesh.vertex.attributes.erase(mesh.vertex.attributes.begin() + i); + } + } else { + UF_MSG_DEBUG("Attribute removal requested yet mesh is interleaved, ignoring..."); + } + } + #endif + + { + #if UF_ENV_DREAMCAST && GL_QUANTIZED_SHORT + mesh.convert(); + UF_MSG_DEBUG("Quantizing mesh to GL_QUANTIZED_SHORT"); + #else + auto conversion = graph.metadata["decode"]["conversion"].as(); + if ( conversion != "" ) { + #if UF_USE_FLOAT16 + if ( conversion == "float16" ) mesh.convert(); + else if ( conversion == "float" ) mesh.convert(); + #endif + #if UF_USE_BFLOAT16 + if ( conversion == "bfloat16" ) mesh.convert(); + else if ( conversion == "float" ) mesh.convert(); + #endif + if ( conversion == "uint16_t" ) mesh.convert(); + else if ( conversion == "float" ) mesh.convert(); + } + #endif + } + + mesh.updateDescriptor(); + + { + auto& graphic = graph.root.entity->getComponent(); + uf::graph::initializeGraphics( graph, *graph.root.entity, mesh ); + } + } +#endif +} void uf::graph::reload() { ::newGraphAdded = true; } \ No newline at end of file