diff --git a/.gitignore b/.gitignore index deea3bfd..58aeefb8 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ *.app *.spv *.elf +*.elf.unstripped # Logs *.log diff --git a/bin/data/entities/model.json b/bin/data/entities/model.json index 19b4f82a..9ede9011 100644 --- a/bin/data/entities/model.json +++ b/bin/data/entities/model.json @@ -78,7 +78,7 @@ "stream": { "tag": "worldspawn", "player": "info_player_spawn", - "enabled": "auto", + "enabled": true, // "auto", "radius": 32, "every": 4 } diff --git a/bin/exe/default/renderer b/bin/exe/default/renderer index 53395cff..91caa7c1 100644 --- a/bin/exe/default/renderer +++ b/bin/exe/default/renderer @@ -1 +1 @@ -vulkan \ No newline at end of file +opengl \ No newline at end of file diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index aa4dd376..7d6e9983 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -158,7 +158,10 @@ namespace uf { } bounds; */ uf::stl::vector buffers; - uf::stl::vector buffer_paths; // crunge, but it's better this way + + // crunge, but it's better this way + uf::stl::vector buffer_paths; + uf::stl::vector buffer_descriptors; protected: void _destroy( uf::Mesh::Input& input ); void _bind( bool interleaved = uf::Mesh::defaultInterleaved ); @@ -300,32 +303,42 @@ namespace uf { template void convert() { + // if mesh data is interleaved, skip conversion if ( this->isInterleaved() ) { UF_MSG_DEBUG("Downcasting/upcasting requested yet mesh is interleaved, ignoring..."); return; } + auto fromEnum = uf::renderer::typeToEnum(); - auto toEnum = uf::renderer::typeToEnum(); + auto toEnum = uf::renderer::typeToEnum(); if ( toEnum == fromEnum ) return; for ( auto& attribute : this->vertex.attributes ) { + if ( attribute.descriptor.type == toEnum ) continue; if ( attribute.descriptor.type != fromEnum ) continue; - float scale = (float) sizeof(To) / (float) sizeof(From); - - size_t elements = this->vertex.count * attribute.descriptor.components; - size_t bytes = elements * sizeof(To); - + size_t elementCount = this->vertex.count * attribute.descriptor.components; auto& srcBuffer = this->buffers[attribute.buffer]; - if ( srcBuffer.empty() ) continue; - uf::stl::vector dstBuffer( srcBuffer.size() * scale ); + uf::stl::vector dstBuffer( elementCount * sizeof(To) ); - attribute.pointer = (uint8_t*) dstBuffer.data(); - attribute.length *= scale; + const From* srcPtr = (const From*) (srcBuffer.data()); + To* dstPtr = (To*) (dstBuffer.data()); + + if ( toEnum == uf::renderer::enums::Type::USHORT ) + for ( size_t i = 0; i < elementCount; ++i ) dstPtr[i] = uf::quant::quantize_f32u16(srcPtr[i]); + else if ( fromEnum == uf::renderer::enums::Type::USHORT ) + for ( size_t i = 0; i < elementCount; ++i) dstPtr[i] = uf::quant::dequantize_u16f32(srcPtr[i]); + else + for ( size_t i = 0; i < elementCount; ++i ) dstPtr[i] = (To) srcPtr[i]; + + srcBuffer.swap( dstBuffer ); + + attribute.pointer = (uint8_t*) ( srcBuffer.data() ); attribute.descriptor.type = toEnum; - attribute.descriptor.size *= scale; + attribute.descriptor.size = sizeof(To) * attribute.descriptor.components; + attribute.length = sizeof(To) * elementCount; if ( toEnum == uf::renderer::enums::Type::FLOAT ) { switch ( attribute.descriptor.components ) { @@ -334,14 +347,16 @@ namespace uf { case 3: attribute.descriptor.format = uf::renderer::enums::Format::R32G32B32_SFLOAT; break; case 4: attribute.descriptor.format = uf::renderer::enums::Format::R32G32B32A32_SFLOAT; break; } - } else if ( toEnum == uf::renderer::enums::Type::FLOAT16 ) { + } + else if ( toEnum == uf::renderer::enums::Type::FLOAT16 ) { switch ( attribute.descriptor.components ) { case 1: attribute.descriptor.format = uf::renderer::enums::Format::R16_SFLOAT; break; case 2: attribute.descriptor.format = uf::renderer::enums::Format::R16G16_SFLOAT; break; case 3: attribute.descriptor.format = uf::renderer::enums::Format::R16G16B16_SFLOAT; break; case 4: attribute.descriptor.format = uf::renderer::enums::Format::R16G16B16A16_SFLOAT; break; } - } else if ( toEnum == uf::renderer::enums::Type::USHORT ) { + } + else if ( toEnum == uf::renderer::enums::Type::USHORT ) { switch ( attribute.descriptor.components ) { case 1: attribute.descriptor.format = uf::renderer::enums::Format::R16_UINT; break; case 2: attribute.descriptor.format = uf::renderer::enums::Format::R16G16_UINT; break; @@ -349,20 +364,6 @@ namespace uf { case 4: attribute.descriptor.format = uf::renderer::enums::Format::R16G16B16A16_UINT; break; } } - - - From* srcPtr = (From*) (srcBuffer.data()); - To* dstPtr = (To*) (dstBuffer.data()); - - if ( toEnum == uf::renderer::enums::Type::USHORT ) { - for ( size_t i = 0; i < elements; ++i ) dstPtr[i] = uf::quant::quantize_f32u16(srcPtr[i]); - } else if ( fromEnum == uf::renderer::enums::Type::USHORT ) { - for ( size_t i = 0; i < elements; ++i ) dstPtr[i] = uf::quant::dequantize_u16f32(srcPtr[i]); - } else { - for ( size_t i = 0; i < elements; ++i ) dstPtr[i] = srcPtr[i]; - } - - srcBuffer.swap( dstBuffer ); } } }; @@ -421,10 +422,10 @@ namespace ext { } namespace std { - template <> - struct hash { - size_t operator()(const ext::RENDERER::GraphicDescriptor& descriptor) const { return descriptor.hash(); } - }; + template <> + struct hash { + size_t operator()(const ext::RENDERER::GraphicDescriptor& descriptor) const { return descriptor.hash(); } + }; } #undef UF_RENDERER diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index e9cb9490..e5bf2d80 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -231,6 +231,7 @@ namespace { attribute.offset = value["offset"].as(attribute.offset);\ attribute.stride = value["stride"].as(attribute.stride);\ attribute.length = value["length"].as(attribute.length);\ + mesh.buffer_descriptors.emplace_back(attribute.descriptor);\ });\ } @@ -240,6 +241,8 @@ namespace { DESERIALIZE_MESH(indirect); mesh.buffers.reserve( json["buffers"].size() ); + mesh.buffer_paths.reserve( json["buffers"].size() ); + mesh.buffer_descriptors.reserve( json["buffers"].size() ); ext::json::forEach( json["buffers"], [&]( ext::json::Value& value ){ const uf::stl::string filename = value.as(); const uf::stl::string directory = uf::io::directory( graph.name ); @@ -298,7 +301,6 @@ namespace { { #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 != "" ) { @@ -314,8 +316,9 @@ namespace { else if ( conversion == "float" ) mesh.convert(); } #endif - mesh.updateDescriptor(); } + + mesh.updateDescriptor(); return mesh; } diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 81b63793..7927ed19 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -25,7 +25,7 @@ #if UF_USE_OPENGL #define UF_GRAPH_SPARSE_READ_MESH 1 #else - #define UF_GRAPH_SPARSE_READ_MESH 0 + #define UF_GRAPH_SPARSE_READ_MESH 1 #endif #endif @@ -44,6 +44,40 @@ namespace { return hash; } + void bindTextures( uf::renderer::Graphic& graphic ) { + graphic.material.textures.clear(); + + auto& scene = uf::scene::getCurrentScene(); + auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent(); + + // for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( storage.samplers.map[s] ); + // for ( auto pair : storage.samplers.map ) graphic.material.samplers.emplace_back( pair.second ); + // for ( auto& key : storage.samplers.keys ) graphic.material.samplers.emplace_back( storage.samplers.map[key] ); + + // for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( storage.texture2Ds.map[i] ); + // for ( auto pair : storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second ); + + for ( auto& key : storage.texture2Ds.keys ) graphic.material.textures.emplace_back().aliasTexture( storage.texture2Ds.map[key] ); + + // bind scene's voxel texture + #if UF_USE_VULKAN + if ( uf::renderer::settings::pipelines::vxgi ) { + auto& scene = uf::scene::getCurrentScene(); + auto& sceneTextures = scene.getComponent(); + for ( auto& t : sceneTextures.voxels.drawId ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.instanceId ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.normalX ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.normalY ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radianceR ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radianceG ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radianceB ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radianceA ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.count ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.output ) graphic.material.textures.emplace_back().aliasTexture(t); + } + #endif + } + // lazy load animations if requested void loadAnimation( const uf::stl::string& name ) { auto& scene = uf::scene::getCurrentScene(); @@ -344,34 +378,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M #endif */ - { - // for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( storage.samplers.map[s] ); - // for ( auto pair : storage.samplers.map ) graphic.material.samplers.emplace_back( pair.second ); - // for ( auto& key : storage.samplers.keys ) graphic.material.samplers.emplace_back( storage.samplers.map[key] ); - - // for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( storage.texture2Ds.map[i] ); - // for ( auto pair : storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second ); - - for ( auto& key : storage.texture2Ds.keys ) graphic.material.textures.emplace_back().aliasTexture( storage.texture2Ds.map[key] ); - - // bind scene's voxel texture - #if UF_USE_VULKAN - if ( uf::renderer::settings::pipelines::vxgi ) { - auto& scene = uf::scene::getCurrentScene(); - auto& sceneTextures = scene.getComponent(); - for ( auto& t : sceneTextures.voxels.drawId ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.instanceId ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.normalX ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.normalY ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.radianceR ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.radianceG ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.radianceB ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.radianceA ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.count ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.output ) graphic.material.textures.emplace_back().aliasTexture(t); - } - #endif - } + ::bindTextures( graphic ); uf::stl::string root = uf::io::directory( graph.name ); size_t texture2Ds = 0; @@ -2166,21 +2173,18 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { mesh.index.count += drawCommand.indices; } - // load mesh data - for ( auto& attribute : mesh.index.attributes ) { - if ( ranges.count(attribute.buffer) <= 0 ) { - mesh.buffers[attribute.buffer].clear(); - } else { - mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer], ranges[attribute.buffer] ); + #define STREAM_MESH_DATA( N ) \ + for ( auto& attribute : mesh.N.attributes ) {\ + if ( ranges.count(attribute.buffer) <= 0 ) { \ + mesh.buffers[attribute.buffer].clear();\ + } else {\ + attribute.descriptor = mesh.buffer_descriptors[attribute.buffer];\ + mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer], ranges[attribute.buffer] );\ + }\ } - } - for ( auto& attribute : mesh.vertex.attributes ) { - if ( ranges.count(attribute.buffer) <= 0 ) { - mesh.buffers[attribute.buffer].clear(); - } else { - mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer], ranges[attribute.buffer] ); - } - } + + STREAM_MESH_DATA( index ); + STREAM_MESH_DATA( vertex ); // keep the vertex data intact #else // disable remaining draw commands @@ -2197,13 +2201,15 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { } } - // load mesh data - for ( auto& attribute : mesh.index.attributes ) { - mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] ); - } - for ( auto& attribute : mesh.vertex.attributes ) { - mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] ); - } + #define STREAM_MESH_DATA( N ) \ + for ( auto& attribute : mesh.N.attributes ) {\ + if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue;\ + attribute.descriptor = mesh.buffer_descriptors[attribute.buffer];\ + mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );\ + } + + STREAM_MESH_DATA( index ); + STREAM_MESH_DATA( vertex ); #endif if ( graph.settings.stream.textures ) { @@ -2239,13 +2245,11 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { } // iterate through our ref counts - // to-do: figure out why this doesn't work for OpenGL (texture ID handles might be wrong, might be better to store the old texture ID handle to use it and then update to that handle) for ( auto& [ key, count ] : textureReferences ) { auto& texture = storage.texture2Ds[key]; auto& image = storage.images[key]; bool visible = count > 0; - // load texture if ( visible && (!texture.generated() || texture.aliased) ) { // load image if ( image.getPixels().empty() ) image.open(image.getFilename(), false); @@ -2264,7 +2268,13 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { // avoids manipulating the aliased texture if ( texture.aliased ) { - texture = {}; + texture.aliased = false; + #if UF_USE_OPENGL + texture.image = 0; + #else + texture.image = {}; + texture.view = {}; + #endif } texture.sampler.descriptor.filter.min = filter; @@ -2275,7 +2285,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { #if UF_ENV_DREAMCAST image.clear(); #endif - } else if ( !visible && texture.generated() ) { + } else if ( !visible && (texture.generated() && !texture.aliased) ) { // unload image image.clear(); // defer destruction of texture @@ -2286,20 +2296,39 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { } } } else { // this shouldn't be reached - // load mesh data - for ( auto& attribute : mesh.index.attributes ) { - if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue; - mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] ); - } - for ( auto& attribute : mesh.vertex.attributes ) { - if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue; - mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] ); + #define LOAD_MESH_DATA( N ) \ + for ( auto& attribute : mesh.N.attributes ) {\ + if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue;\ + mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );\ + } + + LOAD_MESH_DATA( index ); + LOAD_MESH_DATA( vertex ); + } + + { + #if UF_ENV_DREAMCAST && GL_QUANTIZED_SHORT + mesh.convert(); + #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(); - // may or may not be necessary (OpenGL might need a re-record, Vulkan seems fine for the main deferred pass but VXGI doesn't ever get to update since null textures get used sometimes) - uf::renderer::states::rebuild = true; + + // uf::renderer::states::rebuild = true; // update graphic if ( /*(graph.metadata["renderer"]["separate"].as()) &&*/ graph.metadata["renderer"]["render"].as() ) { @@ -2310,11 +2339,13 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { if ( rebuild ) { // uf::renderer::states::rebuild = true; } + ::bindTextures( graphic ); } else { uf::graph::initializeGraphics( graph, entity, mesh ); } } // bind mesh to physics state + // to-do: figure out why the mesh just suddenly breaks when re-streamed in dreamcast (could just be the version of reactphysics) { auto phyziks = tag["physics"]; if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];