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)

This commit is contained in:
ecker 2025-08-11 21:14:30 -05:00
parent cf9a4c9a9d
commit a9b5a03f94
7 changed files with 186 additions and 198 deletions

View File

@ -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

View File

@ -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": {

View File

@ -1,7 +1,7 @@
{
"engine": {
"scenes": {
"start": "SourceEngine",
"start": "StartMenu",
"matrix": { "reverseInfinite": true },
"meshes": { "interleaved": false },
"lights": { "enabled": true,

View File

@ -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();
}
}

View File

@ -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<T> vertices = meshlet.vertices;
uf::stl::vector<U> indices = meshlet.indices;
uf::shapes::clip<T,U>( 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<T,U>( 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<T,U>( 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;

View File

@ -66,6 +66,11 @@ namespace {
sampler.descriptor.addressMode.v = (uf::renderer::enums::AddressMode::type_t) json["v"].as<size_t>();
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;
}

View File

@ -226,6 +226,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent<pod::Graph::Storage>();
auto& graphic = entity.getComponent<uf::renderer::Graphic>();
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<bool>()) ) {
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<pod::DrawCommand>();
#if UF_ENV_DREAMCAST
mesh.bind<uf::graph::mesh::Base, uint32_t>();
#else
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
#endif
/*
{
#if UF_ENV_DREAMCAST
mesh.bind<uf::graph::mesh::Base_u16q, uint32_t>();
// mesh.convert<float, uint16_t>();
#else
auto conversion = graph.metadata["decode"]["conversion"].as<uf::stl::string>();
if ( conversion != "" ) {
if ( conversion == "uint16_t" ) mesh.bind<uf::graph::mesh::Skinned_16f, uint32_t>();
#if UF_USE_FLOAT16
else if ( conversion == "float16" ) mesh.bind<uf::graph::mesh::Skinned_16f, uint32_t>();
#endif
#if UF_USE_BFLOAT16
else if ( conversion == "bfloat16" ) mesh.bind<uf::graph::mesh::Skinned_16f, uint32_t>();
#endif
else mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
} else mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
#endif
}
*/
uf::stl::vector<pod::DrawCommand> 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<bool>() ) 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<uf::stl::string> attributesKept = ext::json::vector<uf::stl::string>(graph.metadata["decode"]["attributes"]);
if ( !mesh.isInterleaved() ) {
uf::stl::vector<size_t> 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<float, uint16_t>();
UF_MSG_DEBUG("Quantizing mesh to GL_QUANTIZED_SHORT");
#else
auto conversion = graph.metadata["decode"]["conversion"].as<uf::stl::string>();
if ( conversion != "" ) {
#if UF_USE_FLOAT16
if ( conversion == "float16" ) mesh.convert<float, float16>();
else if ( conversion == "float" ) mesh.convert<float16, float>();
#endif
#if UF_USE_BFLOAT16
if ( conversion == "bfloat16" ) mesh.convert<float, bfloat16>();
else if ( conversion == "float" ) mesh.convert<bfloat16, float>();
#endif
if ( conversion == "uint16_t" ) mesh.convert<float, uint16_t>();
else if ( conversion == "float" ) mesh.convert<uint16_t, float>();
}
#endif
}
mesh.updateDescriptor();
{
auto& graphic = graph.root.entity->getComponent<uf::renderer::Graphic>();
uf::graph::initializeGraphics( graph, *graph.root.entity, mesh );
}
}
storage.instanceAddresses.keys = storage.instances.keys;
UF_DEBUG_TIMER_MULTITRACE_END("Processed graph.");
}
@ -1521,6 +1399,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
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<bool>()) && graph.metadata["renderer"]["render"].as<bool>() ) {
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<uf::stl::string>();
if ( type == "mesh" ) {
auto& collider = entity.getComponent<pod::PhysicsState>();
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<uf::Object>(), mesh, !phyziks["static"].as<bool>(true) );
} else {
if ( type != "mesh" ) {
auto min = uf::matrix::multiply<float>( model, bounds.min, 1.0f );
auto max = uf::matrix::multiply<float>( 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<pod::Graph::Storage>();
auto& entity = node.entity->as<uf::Object>();
auto& metadata = entity.getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = entity.getComponent<uf::Serializer>();
auto& transform = entity.getComponent<pod::Transform<>>();
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<bool>()) && graph.metadata["renderer"]["render"].as<bool>() ) {
#endif
if ( graph.metadata["renderer"]["render"].as<bool>() ) {
bool exists = entity.hasComponent<uf::renderer::Graphic>();
if ( exists ) {
auto& graphic = entity.getComponent<uf::renderer::Graphic>();
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<uf::stl::string>();
if ( type == "mesh" ) {
bool exists = entity.hasComponent<pod::PhysicsState>();
if ( exists ) {
uf::physics::terminate( entity );
// entity.deleteComponent<pod::PhysicsState>();
}
auto& collider = entity.getComponent<pod::PhysicsState>();
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<bool>(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<bool>()) ) {
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<pod::DrawCommand>();
#if UF_ENV_DREAMCAST
mesh.bind<uf::graph::mesh::Base, uint32_t>();
#else
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
#endif
uf::stl::vector<pod::DrawCommand> 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<bool>() ) 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<uf::stl::string> attributesKept = ext::json::vector<uf::stl::string>(graph.metadata["decode"]["attributes"]);
if ( !mesh.isInterleaved() ) {
uf::stl::vector<size_t> 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<float, uint16_t>();
UF_MSG_DEBUG("Quantizing mesh to GL_QUANTIZED_SHORT");
#else
auto conversion = graph.metadata["decode"]["conversion"].as<uf::stl::string>();
if ( conversion != "" ) {
#if UF_USE_FLOAT16
if ( conversion == "float16" ) mesh.convert<float, float16>();
else if ( conversion == "float" ) mesh.convert<float16, float>();
#endif
#if UF_USE_BFLOAT16
if ( conversion == "bfloat16" ) mesh.convert<float, bfloat16>();
else if ( conversion == "float" ) mesh.convert<bfloat16, float>();
#endif
if ( conversion == "uint16_t" ) mesh.convert<float, uint16_t>();
else if ( conversion == "float" ) mesh.convert<uint16_t, float>();
}
#endif
}
mesh.updateDescriptor();
{
auto& graphic = graph.root.entity->getComponent<uf::renderer::Graphic>();
uf::graph::initializeGraphics( graph, *graph.root.entity, mesh );
}
}
#endif
}
void uf::graph::reload() {
::newGraphAdded = true;
}