From 22fb850709f562881dc94e3d264111a892bbf599 Mon Sep 17 00:00:00 2001 From: ecker Date: Sat, 6 Jun 2026 15:36:36 -0500 Subject: [PATCH] more engine cleanup and fixes (removed the footgun of texture2Ds/instanceAddresses, parse VMT values into material information, re-parent nodes for BSP loader, hopefully final VFS integration fixes) --- bin/data/config.json | 2 +- bin/data/scenes/vbsp/base_sourceengine.json | 2 +- bin/data/shaders/common/functions.h | 42 ++-- bin/data/shaders/common/structs.h | 2 +- bin/data/shaders/display/deferred/comp/comp.h | 2 +- bin/data/shaders/display/vxgi/comp.glsl | 2 +- bin/data/shaders/graph/baking/frag.h | 2 +- bin/data/shaders/graph/base/frag.glsl | 2 +- bin/data/shaders/graph/depth/frag.glsl | 2 +- bin/data/shaders/graph/voxelize/frag.glsl | 2 +- bin/data/shaders/raytrace/shader.ray-gen.glsl | 2 +- engine/inc/uf/engine/graph/graph.h | 9 +- engine/inc/uf/engine/graph/pod.inl | 11 +- engine/inc/uf/utils/io/vfs.h | 2 + engine/inc/uf/utils/mesh/mesh.h | 2 + engine/src/engine/ext/baking/behavior.cpp | 2 +- engine/src/engine/ext/raytrace/behavior.cpp | 2 +- engine/src/engine/ext/scene/behavior.cpp | 2 +- engine/src/engine/graph/convert.cpp | 7 +- engine/src/engine/graph/decode.cpp | 9 +- engine/src/engine/graph/encode.cpp | 5 +- engine/src/engine/graph/graph.cpp | 182 +++++++++--------- engine/src/ext/gltf/gltf.cpp | 10 +- engine/src/ext/valve/bsp.cpp | 119 ++++++++---- engine/src/ext/valve/mdl.cpp | 10 +- engine/src/ext/vulkan/graphic.cpp | 10 +- .../src/ext/vulkan/rendermodes/deferred.cpp | 2 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 2 +- engine/src/utils/image/image.cpp | 29 ++- engine/src/utils/io/file.cpp | 10 +- engine/src/utils/io/vfs.cpp | 22 +++ engine/src/utils/mesh/mesh.cpp | 74 +++---- 32 files changed, 345 insertions(+), 238 deletions(-) diff --git a/bin/data/config.json b/bin/data/config.json index edefcd60..34d97ab1 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -4,7 +4,7 @@ "start": "StartMenu", "matrix": { "reverseInfinite": true }, "lights": { "enabled": true, - "lightmaps": true, + "lightmaps": false, "max": 32, "shadows": { "enabled": true, diff --git a/bin/data/scenes/vbsp/base_sourceengine.json b/bin/data/scenes/vbsp/base_sourceengine.json index 71adb375..eea42986 100644 --- a/bin/data/scenes/vbsp/base_sourceengine.json +++ b/bin/data/scenes/vbsp/base_sourceengine.json @@ -20,7 +20,7 @@ // regexp matches // "/^worldspawn_/": { "physics": { "type": "mesh", "static": true } }, "/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, - "/^prop_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + // "/^prop_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, "/^prop_static/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ }, "/^prop_dynamic/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ }, "/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } }, diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index 4c7a78a6..95fe7c8d 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -355,38 +355,38 @@ uvec4 uvec2_16x4( uvec2 i ) { } #if BUFFER_REFERENCE -void populateSurface( InstanceAddresses instanceAddresses, uvec3 indices ) { +void populateSurface( InstanceAddresses addresses, uvec3 indices ) { Triangle triangle; Vertex points[3]; - if ( false && isValidAddress(instanceAddresses.vertex) ) { - // Vertices vertices = Vertices(nonuniformEXT(instanceAddresses.vertex)); + if ( false && isValidAddress(addresses.vertex) ) { + // Vertices vertices = Vertices(nonuniformEXT(addresses.vertex)); // #pragma unroll 3 // for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_] = vertices.v[/*triangle.*/indices[_]]; } else { - if ( isValidAddress(instanceAddresses.position) ) { - VPos buf = VPos(nonuniformEXT(instanceAddresses.position)); + if ( isValidAddress(addresses.position) ) { + VPos buf = VPos(nonuniformEXT(addresses.position)); #pragma unroll 3 for ( uint _ = 0; _ < 3; ++_ ) points[_].position = vec3( buf.v[indices[_]*3+0], buf.v[indices[_]*3+1], buf.v[indices[_]*3+2] ); //for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].position[_] = buf.v[/*triangle.*/indices[_]*3+_]; } - if ( isValidAddress(instanceAddresses.uv) ) { - VUv buf = VUv(nonuniformEXT(instanceAddresses.uv)); + if ( isValidAddress(addresses.uv) ) { + VUv buf = VUv(nonuniformEXT(addresses.uv)); #pragma unroll 3 for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].uv/*[_]*/ = buf.v[/*triangle.*/indices[_]]; } - if ( isValidAddress(instanceAddresses.st) ) { - VSt buf = VSt(nonuniformEXT(instanceAddresses.st)); + if ( isValidAddress(addresses.st) ) { + VSt buf = VSt(nonuniformEXT(addresses.st)); #pragma unroll 3 for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].st/*[_]*/ = buf.v[/*triangle.*/indices[_]]; } - if ( isValidAddress(instanceAddresses.normal) ) { - VNormal buf = VNormal(nonuniformEXT(instanceAddresses.normal)); + if ( isValidAddress(addresses.normal) ) { + VNormal buf = VNormal(nonuniformEXT(addresses.normal)); #pragma unroll 3 for ( uint _ = 0; _ < 3; ++_ ) points[_].normal = vec3( buf.v[indices[_]*3+0], buf.v[indices[_]*3+1], buf.v[indices[_]*3+2] ); // for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].normal[_] = buf.v[/*triangle.*/indices[_]*3+_]; } - if ( isValidAddress(instanceAddresses.tangent) ) { - VTangent buf = VTangent(nonuniformEXT(instanceAddresses.tangent)); + if ( isValidAddress(addresses.tangent) ) { + VTangent buf = VTangent(nonuniformEXT(addresses.tangent)); #pragma unroll 3 for ( uint _ = 0; _ < 3; ++_ ) points[_].tangent = vec3( buf.v[indices[_]*3+0], buf.v[indices[_]*3+1], buf.v[indices[_]*3+2] ); // for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].tangent[_] = buf.v[/*triangle.*/indices[_]*3+_]; @@ -475,23 +475,23 @@ void populateSurface( uint instanceID, uint primitiveID ) { surface.instance = instances[instanceID]; surface.object = objects[surface.instance.objectID]; - const InstanceAddresses instanceAddresses = instanceAddresses[instanceID]; - if ( !isValidAddress(instanceAddresses.index) ) return; - const DrawCommand drawCommand = Indirects(nonuniformEXT(instanceAddresses.indirect)).dc[instanceAddresses.drawID]; + const InstanceAddresses addresses = addresses[instanceID]; + if ( !isValidAddress(addresses.index) ) return; + const DrawCommand drawCommand = Indirects(nonuniformEXT(addresses.indirect)).dc[addresses.drawID]; const uint triangleID = primitiveID + (drawCommand.indexID / 3); - //uvec3 indices = Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID]; + //uvec3 indices = Indices(nonuniformEXT(addresses.index)).i[triangleID]; uvec3 indices = uvec3( - Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID*3+0], - Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID*3+1], - Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID*3+2] + Indices(nonuniformEXT(addresses.index)).i[triangleID*3+0], + Indices(nonuniformEXT(addresses.index)).i[triangleID*3+1], + Indices(nonuniformEXT(addresses.index)).i[triangleID*3+2] ); #pragma unroll 3 for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/indices[_] += drawCommand.vertexID; - populateSurface( instanceAddresses, indices ); + populateSurface( addresses, indices ); } void populateSurface( RayTracePayload payload ) { surface.fragment = vec4(0); diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index c66d8c42..30ce6b9a 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -67,7 +67,7 @@ struct Material { int indexMetallicRoughness; int padding1; - int padding2; + int modeCull; int modeAlpha; }; diff --git a/bin/data/shaders/display/deferred/comp/comp.h b/bin/data/shaders/display/deferred/comp/comp.h index 4c78f656..e7fdf4a9 100644 --- a/bin/data/shaders/display/deferred/comp/comp.h +++ b/bin/data/shaders/display/deferred/comp/comp.h @@ -78,7 +78,7 @@ layout (std140, binding = 13, set = 0) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 14, set = 0) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 15, set = 0) readonly buffer Objects { Object objects[]; diff --git a/bin/data/shaders/display/vxgi/comp.glsl b/bin/data/shaders/display/vxgi/comp.glsl index a8adf52f..0fa4ee09 100644 --- a/bin/data/shaders/display/vxgi/comp.glsl +++ b/bin/data/shaders/display/vxgi/comp.glsl @@ -34,7 +34,7 @@ layout (std140, binding = 2) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 3) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 4) readonly buffer Objects { Object objects[]; diff --git a/bin/data/shaders/graph/baking/frag.h b/bin/data/shaders/graph/baking/frag.h index 829c0b7b..eacd5eae 100644 --- a/bin/data/shaders/graph/baking/frag.h +++ b/bin/data/shaders/graph/baking/frag.h @@ -45,7 +45,7 @@ layout (std140, binding = 11) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 12) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 13) readonly buffer Materials { Material materials[]; diff --git a/bin/data/shaders/graph/base/frag.glsl b/bin/data/shaders/graph/base/frag.glsl index a106158f..4f84325f 100644 --- a/bin/data/shaders/graph/base/frag.glsl +++ b/bin/data/shaders/graph/base/frag.glsl @@ -35,7 +35,7 @@ layout (std140, binding = 8) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 9) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 10) readonly buffer Materials { Material materials[]; diff --git a/bin/data/shaders/graph/depth/frag.glsl b/bin/data/shaders/graph/depth/frag.glsl index e6116b13..4e669ebf 100644 --- a/bin/data/shaders/graph/depth/frag.glsl +++ b/bin/data/shaders/graph/depth/frag.glsl @@ -17,7 +17,7 @@ layout (std140, binding = 8) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 9) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 10) readonly buffer Materials { Material materials[]; diff --git a/bin/data/shaders/graph/voxelize/frag.glsl b/bin/data/shaders/graph/voxelize/frag.glsl index 01d20c7f..859c4fd3 100644 --- a/bin/data/shaders/graph/voxelize/frag.glsl +++ b/bin/data/shaders/graph/voxelize/frag.glsl @@ -24,7 +24,7 @@ layout (std140, binding = 8) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 9) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 10) readonly buffer Materials { diff --git a/bin/data/shaders/raytrace/shader.ray-gen.glsl b/bin/data/shaders/raytrace/shader.ray-gen.glsl index e0b0f076..afb2acef 100644 --- a/bin/data/shaders/raytrace/shader.ray-gen.glsl +++ b/bin/data/shaders/raytrace/shader.ray-gen.glsl @@ -48,7 +48,7 @@ layout (std140, binding = 4) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 5) readonly buffer InstanceAddresseses { - InstanceAddresses instanceAddresses[]; + InstanceAddresses addresses[]; }; layout (std140, binding = 6) readonly buffer Objects { Object objects[]; diff --git a/engine/inc/uf/engine/graph/graph.h b/engine/inc/uf/engine/graph/graph.h index cd668168..237d925e 100644 --- a/engine/inc/uf/engine/graph/graph.h +++ b/engine/inc/uf/engine/graph/graph.h @@ -87,11 +87,11 @@ namespace pod { }; uf::stl::KeyMap> groupedInstances; - uf::stl::KeyMap> instanceAddresses; + uf::stl::KeyMap> addresses; uf::stl::KeyMap> primitives; uf::stl::KeyMap meshes; - uf::stl::KeyMap images; + uf::stl::KeyMap images; uf::stl::KeyMap materials; uf::stl::KeyMap textures; uf::stl::KeyMap samplers; @@ -103,7 +103,6 @@ namespace pod { uf::stl::KeyMap atlases; uf::stl::KeyMap objects; uf::stl::KeyMap> joints; - uf::stl::KeyMap texture2Ds; uf::stl::KeyMap entities; uf::stl::vector shadow2Ds; @@ -113,7 +112,7 @@ namespace pod { uf::renderer::Buffer camera; uf::renderer::Buffer drawCommands; uf::renderer::Buffer instance; - uf::renderer::Buffer instanceAddresses; + uf::renderer::Buffer addresses; uf::renderer::Buffer lodMetadata; uf::renderer::Buffer joint; uf::renderer::Buffer object; @@ -155,7 +154,7 @@ namespace uf { const pod::Graph::Storage& UF_API getStorage( const uf::Object& ); // void UF_API process( uf::Object& entity ); - void UF_API initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::Mesh& mesh, uf::stl::vector& ); + void UF_API initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::Mesh& mesh, uf::stl::vector& ); void UF_API process( pod::Graph& graph ); void UF_API process( pod::Graph& graph, int32_t, uf::Object& parent ); void UF_API reload( pod::Graph& ); diff --git a/engine/inc/uf/engine/graph/pod.inl b/engine/inc/uf/engine/graph/pod.inl index 520590d8..3fe075ce 100644 --- a/engine/inc/uf/engine/graph/pod.inl +++ b/engine/inc/uf/engine/graph/pod.inl @@ -4,8 +4,8 @@ namespace pod { pod::Vector4f colorEmissive = { 0, 0, 0, 0 }; float factorMetallic = 0.0f; - float factorRoughness = 0.0f; - float factorOcclusion = 0.0f; + float factorRoughness = 1.0f; + float factorOcclusion = 1.0f; float factorAlphaCutoff = 1.0f; int32_t indexAlbedo = -1; @@ -15,7 +15,7 @@ namespace pod { int32_t indexMetallicRoughness = -1; int32_t padding1 = -1; - int32_t padding2 = -1; + int32_t modeCull = -1; int32_t modeAlpha = -1; }; @@ -92,4 +92,9 @@ namespace pod { pod::Transform<> transform; uf::Serializer metadata; }; + + struct UF_API ImageTexture { + uf::Image data; + uf::renderer::Texture2D handle; + }; } \ No newline at end of file diff --git a/engine/inc/uf/utils/io/vfs.h b/engine/inc/uf/utils/io/vfs.h index 1896c106..b72f7f55 100644 --- a/engine/inc/uf/utils/io/vfs.h +++ b/engine/inc/uf/utils/io/vfs.h @@ -21,6 +21,7 @@ namespace pod { std::function mtime; std::function&)> read; std::function write; + std::function mkdir; std::function&)> readRange; std::function&, uf::stl::vector&)> readRanges; @@ -42,6 +43,7 @@ namespace uf { size_t UF_API write( const uf::stl::string& path, const void* data, size_t len ); size_t UF_API write( const uf::stl::string& path, uf::stl::vector& buffer ); + bool UF_API mkdir( const uf::stl::string& path ); bool UF_API readRange( const uf::stl::string& path, size_t start, size_t len, uf::stl::vector& buffer ); bool UF_API readRanges( const uf::stl::string& path, const uf::stl::vector& ranges, uf::stl::vector& buffer ); diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index 127e31cd..f9cfd24b 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -143,6 +143,7 @@ namespace pod { pod::DrawCommand drawCommand; pod::Instance instance; pod::LODMetadata lod; + pod::Instance::Addresses addresses; }; } @@ -261,6 +262,7 @@ namespace uf { uf::Mesh& copy( const uf::Mesh& ); uf::Mesh copy() const; + uf::Mesh alias() const; uf::Mesh expand(); void updateDescriptor(); diff --git a/engine/src/engine/ext/baking/behavior.cpp b/engine/src/engine/ext/baking/behavior.cpp index bf5f55d1..2014cc89 100644 --- a/engine/src/engine/ext/baking/behavior.cpp +++ b/engine/src/engine/ext/baking/behavior.cpp @@ -86,7 +86,7 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { uf::stl::vector textures2D; uf::stl::vector texturesCube; // bind scene textures - for ( auto& key : storage.texture2Ds.keys ) textures2D.emplace_back().aliasTexture( storage.texture2Ds.map[key] ); + for ( auto& key : storage.images.keys ) textures2D.emplace_back().aliasTexture( storage.images.map[key].handle ); // bind shadow maps for ( auto& texture : storage.shadow2Ds ) textures2D.emplace_back().aliasTexture(texture); for ( auto& texture : storage.shadowCubes ) texturesCube.emplace_back().aliasTexture(texture); diff --git a/engine/src/engine/ext/raytrace/behavior.cpp b/engine/src/engine/ext/raytrace/behavior.cpp index 13773ef8..cc7802e3 100644 --- a/engine/src/engine/ext/raytrace/behavior.cpp +++ b/engine/src/engine/ext/raytrace/behavior.cpp @@ -211,7 +211,7 @@ void ext::RayTraceSceneBehavior::tick( uf::Object& self ) { size_t maxCascades = uf::config["engine"]["scenes"]["vxgi"]["cascades"].as(16); shader.aliasBuffer( storage.buffers.instance ); - shader.aliasBuffer( storage.buffers.instanceAddresses ); + shader.aliasBuffer( storage.buffers.addresses ); shader.aliasBuffer( storage.buffers.object ); shader.aliasBuffer( storage.buffers.material ); shader.aliasBuffer( storage.buffers.texture ); diff --git a/engine/src/engine/ext/scene/behavior.cpp b/engine/src/engine/ext/scene/behavior.cpp index 70638fe9..36905bef 100644 --- a/engine/src/engine/ext/scene/behavior.cpp +++ b/engine/src/engine/ext/scene/behavior.cpp @@ -1139,7 +1139,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic texturesCube.reserve( metadata.max.texturesCube ); // bind scene textures - for ( auto& key : storage.texture2Ds.keys ) textures2D.emplace_back().aliasTexture( storage.texture2Ds.map[key] ); + for ( auto& key : storage.images.keys ) textures2D.emplace_back().aliasTexture( storage.images.map[key].handle ); size_t indexSkybox = 0; size_t indexNoise = 0; diff --git a/engine/src/engine/graph/convert.cpp b/engine/src/engine/graph/convert.cpp index dfbb6afe..5b957b06 100644 --- a/engine/src/engine/graph/convert.cpp +++ b/engine/src/engine/graph/convert.cpp @@ -49,12 +49,12 @@ namespace { size_t materialID = graph.materials.size(); for ( auto& t : textures ) { size_t textureID = graph.textures.size(); - size_t texture2DID = graph.texture2Ds.size(); + size_t texture2DID = graph.images.size(); uf::stl::string subName = keyName + "[" + std::to_string(sub++) + "]"; auto& material = storage.materials[graph.materials.emplace_back(subName)]; auto& texture = storage.textures[graph.textures.emplace_back(subName)]; - auto& texture2D = storage.texture2Ds[graph.texture2Ds.emplace_back(subName)]; + auto& texture2D = storage.images[graph.images.emplace_back(subName)].handle; material.indexAlbedo = textureID; material.colorBase = {1, 1, 1, 1}; @@ -66,7 +66,6 @@ namespace { node.mesh = meshID; auto& primitives = storage.primitives[graph.primitives.emplace_back(keyName)]; auto& mesh = (storage.meshes[graph.meshes.emplace_back(keyName)] = object.getComponent()); - auto& instanceAddresses = storage.instanceAddresses[keyName]; pod::Vector3f boundsMin = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; pod::Vector3f boundsMax = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; @@ -128,7 +127,7 @@ namespace { primitive.lod.levels[0].vertices = drawCommand.vertices; } - uf::graph::initializeGraphics( graph, object, mesh, instanceAddresses ); + uf::graph::initializeGraphics( graph, object, mesh, primitives ); } } diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index 3c23e806..d9a41e4c 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -338,6 +338,7 @@ namespace { .skin = json["skin"].as(-1), .entity = NULL, .transform = uf::transform::decode( json["transform"], pod::Transform<>{} ), + .metadata = json["metadata"], }; node.children.reserve( json["children"].size() ); @@ -447,7 +448,6 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const auto name = key + value["name"].as(); // UF_MSG_DEBUG("{}", name); storage.primitives[name] = decodePrimitives( value, graph ); - storage.instanceAddresses[name] = {}; graph.primitives.emplace_back(name); }); @@ -478,7 +478,9 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const ext::json::forEach( serializer["images"], [&]( ext::json::Value& value ){ auto name = key + value["name"].as(); // UF_MSG_DEBUG("{}", name); - storage.images[name] = decodeImage( value, graph ); + storage.images[name] = { + .data = decodeImage( value, graph ), + }; graph.images.emplace_back(name); }); UF_DEBUG_TIMER_MULTITRACE("Read images"); @@ -509,9 +511,6 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const // UF_MSG_DEBUG("{}", name); storage.textures[name] = decodeTexture( value, graph ); graph.textures.emplace_back(name); - - // pre-allocate - storage.texture2Ds[name]; }); UF_DEBUG_TIMER_MULTITRACE("Read texture information"); #if UF_ENV_DREAMCAST diff --git a/engine/src/engine/graph/encode.cpp b/engine/src/engine/graph/encode.cpp index 070a3216..57b39ec6 100644 --- a/engine/src/engine/graph/encode.cpp +++ b/engine/src/engine/graph/encode.cpp @@ -225,6 +225,7 @@ namespace { for ( auto& child : node.children ) json["children"].emplace_back(child); json["transform"] = uf::transform::encode( node.transform, false, settings ); + json["metadata"] = node.metadata; return json; } } @@ -331,7 +332,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& if ( !settings.combined ) { for ( size_t i = 0; i < graph.images.size(); ++i ) { auto& name = graph.images[i]; - auto& image = /*graph.storage*/storage.images.map.at(name); + auto& image = /*graph.storage*/storage.images.map.at(name).data; uf::stl::string f = "image."+std::to_string(i)+".png"; image.save(directory + "/" + f); @@ -350,7 +351,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } } else { for ( auto& name : graph.images ) { - auto& image = /*graph.storage*/storage.images.map.at(name); + auto& image = /*graph.storage*/storage.images.map.at(name).data; auto json = encode(image, settings, graph); json["name"] = name; serializer["images"].emplace_back( json ); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 96b5f38c..f6c7e83d 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -69,7 +69,7 @@ namespace { auto& storage = uf::graph::getStorage( graph ); - for ( auto& key : storage.texture2Ds.keys ) graphic.material.textures.emplace_back().aliasTexture( storage.texture2Ds.map[key] ); + for ( auto& key : storage.images.keys ) graphic.material.textures.emplace_back().aliasTexture( storage.images.map[key].handle ); // bind scene's voxel texture #if 0 && UF_USE_VULKAN @@ -395,7 +395,7 @@ namespace { ::resetBuffers( shader ); shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands ); shader.aliasBuffer( "instance", storage.buffers.instance ); - shader.aliasBuffer( "instanceAddresses", storage.buffers.instanceAddresses ); + shader.aliasBuffer( "addresses", storage.buffers.addresses ); shader.aliasBuffer( "material", storage.buffers.material ); shader.aliasBuffer( "texture", storage.buffers.texture ); shader.aliasBuffer( "light", storage.buffers.light ); @@ -413,7 +413,7 @@ namespace { ::resetBuffers( shader ); shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands ); shader.aliasBuffer( "instance", storage.buffers.instance ); - shader.aliasBuffer( "instanceAddresses", storage.buffers.instanceAddresses ); + shader.aliasBuffer( "addresses", storage.buffers.addresses ); shader.aliasBuffer( "material", storage.buffers.material ); shader.aliasBuffer( "texture", storage.buffers.texture ); shader.aliasBuffer( "light", storage.buffers.light ); @@ -445,7 +445,7 @@ namespace { ::resetBuffers( shader ); shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands ); shader.aliasBuffer( "instance", storage.buffers.instance ); - shader.aliasBuffer( "instanceAddresses", storage.buffers.instanceAddresses ); + shader.aliasBuffer( "addresses", storage.buffers.addresses ); shader.aliasBuffer( "material", storage.buffers.material ); shader.aliasBuffer( "texture", storage.buffers.texture ); shader.aliasBuffer( "light", storage.buffers.light ); @@ -474,7 +474,7 @@ namespace { ::resetBuffers( shader ); shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands ); shader.aliasBuffer( "instance", storage.buffers.instance ); - shader.aliasBuffer( "instanceAddresses", storage.buffers.instanceAddresses ); + shader.aliasBuffer( "addresses", storage.buffers.addresses ); shader.aliasBuffer( "material", storage.buffers.material ); shader.aliasBuffer( "texture", storage.buffers.texture ); shader.aliasBuffer( "light", storage.buffers.light ); @@ -483,38 +483,37 @@ namespace { #endif } - void bindInstanceAddresses( pod::Graph& graph, uf::renderer::Graphic& graphic, uf::Mesh& mesh, uf::stl::vector& addresses ) { + void bindAddresses( pod::Graph& graph, uf::renderer::Graphic& graphic, uf::Mesh& mesh, uf::stl::vector& primitives ) { #if UF_USE_VULKAN if ( !uf::renderer::settings::invariant::deviceAddressing || !mesh.indirect.count ) return; - addresses.resize( mesh.indirect.count ); - pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer( mesh.indirect ).data(); + pod::Instance::Addresses addresses; + if ( mesh.vertex.count ) { + for ( auto& attribute : graphic.descriptor.inputs.vertex.attributes ) { + if ( attribute.buffer < 0 ) continue; + if ( attribute.descriptor.name == "position" ) addresses.position = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "uv" ) addresses.uv = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "color" ) addresses.color = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "st" ) addresses.st = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "normal" ) addresses.normal = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "tangent" ) addresses.tangent = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "joints" ) addresses.joints = graphic.buffers.at(attribute.buffer).getAddress(); + else if ( attribute.descriptor.name == "weights" ) addresses.weights = graphic.buffers.at(attribute.buffer).getAddress(); + } + } + if ( mesh.index.count ) { + addresses.index = graphic.buffers.at(graphic.descriptor.inputs.index.attributes.front().buffer).getAddress(); + } + + if ( mesh.indirect.count ) { + addresses.indirect = graphic.buffers.at(graphic.descriptor.inputs.indirect.attributes.front().buffer).getAddress(); + } + for ( size_t drawID = 0; drawID < mesh.indirect.count; ++drawID ) { - auto& drawCommand = drawCommands[drawID]; - auto instanceID = drawCommand.instanceID; - - auto& instanceAddresses = addresses[drawID]; // THIS IS WRONG (to-do: actually use instanceIDs) - if ( mesh.vertex.count ) { - for ( auto& attribute : graphic.descriptor.inputs.vertex.attributes ) { - if ( attribute.buffer < 0 ) continue; - if ( attribute.descriptor.name == "position" ) instanceAddresses.position = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "uv" ) instanceAddresses.uv = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "color" ) instanceAddresses.color = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "st" ) instanceAddresses.st = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "normal" ) instanceAddresses.normal = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "tangent" ) instanceAddresses.tangent = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "joints" ) instanceAddresses.joints = graphic.buffers.at(attribute.buffer).getAddress(); - else if ( attribute.descriptor.name == "weights" ) instanceAddresses.weights = graphic.buffers.at(attribute.buffer).getAddress(); - } - } - if ( mesh.index.count ) { - instanceAddresses.index = graphic.buffers.at(graphic.descriptor.inputs.index.attributes.front().buffer).getAddress(); - } - - if ( mesh.indirect.count ) { - instanceAddresses.indirect = graphic.buffers.at(graphic.descriptor.inputs.indirect.attributes.front().buffer).getAddress(); - instanceAddresses.drawID = drawID; - } + // copy address + primitives[drawID].addresses = addresses; + // bind draw ID (necessary for deferred pass where we store , to fetch the drawID, to fetch the triangleID) (or something) + primitives[drawID].addresses.drawID = drawID; } #endif } @@ -696,7 +695,7 @@ const pod::Graph::Storage& uf::graph::getStorage( const pod::Graph& graph ) { return uf::graph::getStorage( g ); } -void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::Mesh& mesh, uf::stl::vector& addresses ) { +void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::Mesh& mesh, uf::stl::vector& primitives ) { auto& scene = uf::scene::getCurrentScene(); auto& sceneTextures = scene.getComponent(); auto& sceneMetadataJson = scene.getComponent(); @@ -731,6 +730,20 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M } else UF_MSG_WARNING("Invalid Face enum string specified: {}", mode); } + + // query materials if culling needs to be disabled + for ( auto& primitive : primitives ) { + auto materialID = primitive.instance.materialID; + if ( 0 < materialID && materialID <= graph.materials.size() ) { + auto& materialName = graph.materials[materialID]; + auto& material = storage.materials[materialName]; + if ( material.modeCull == 0 ) { + tag["renderer"]["cull mode"] = "none"; + break; + } + } + } + if ( tag["renderer"]["cull mode"].is() ) { const auto mode = uf::string::lowercase( tag["renderer"]["cull mode"].as() ); if ( mode == "back" ) graphic.descriptor.cullMode = uf::renderer::enums::CullMode::BACK; @@ -740,10 +753,11 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M else UF_MSG_WARNING("Invalid CullMode enum string specified: {}", mode); } + ::bindTextures( graph, graphic ); ::bindShaders( graph, entity, mesh ); ::bindBuffers( graph, graphic, mesh ); - ::bindInstanceAddresses( graph, graphic, mesh, addresses ); + ::bindAddresses( graph, graphic, mesh, primitives ); graphic.process = true; } @@ -869,7 +883,7 @@ void uf::graph::process( pod::Graph& graph ) { auto imageID = graph.images.size(); auto& texture = storage.textures[graph.textures.emplace_back(f)]; - auto& image = storage.images[graph.images.emplace_back(f)]; + auto& image = storage.images[graph.images.emplace_back(f)].data; if ( !graph.settings.stream.textures ) { image.open( f, false ); } @@ -894,9 +908,6 @@ void uf::graph::process( pod::Graph& graph ) { } } - // setup textures - storage.texture2Ds.reserve( storage.images.map.size() ); - // figure out what texture is what exactly UF_DEBUG_TIMER_MULTITRACE("Determining format of textures"); for ( auto& key : graph.materials ) { @@ -911,8 +922,8 @@ void uf::graph::process( pod::Graph& graph ) { UF_DEBUG_TIMER_MULTITRACE("Processing images..."); for ( auto& key : graph.images ) { - auto& image = storage.images[key]; - auto& texture = storage.texture2Ds[key]; + auto& image = storage.images[key].data; + auto& texture = storage.images[key].handle; if ( !texture.generated() ) { // set as null if ( graph.settings.stream.textures ) { @@ -1177,7 +1188,6 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) if ( graphMetadataJson["baking"]["enabled"].as(false) && !tag["bake"].as(true) ) ignore = true; if ( tag["ignore"].as() ) ignore = true; } - bool isLight = graph.lights.count(node.name) > 0; if ( ignore ) return; @@ -1188,6 +1198,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) uf::Object& entity = *pointer; node.entity = &entity; + auto nameID = ::fmt::format( "{}_{}", node.name, index ); bool setName = entity.getName() == "Entity"; auto& metadata = entity.getComponent(); auto& metadataJson = entity.getComponent(); @@ -1220,8 +1231,11 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) // create as light { - if ( isLight ) { - auto& l = graph.lights[node.name]; + // attempt to resolve a light name + auto lightName = node.name; + if ( graph.lights.count( nameID ) > 0 ) lightName = nameID; + if ( graph.lights.count( lightName ) > 0 ) { + auto& l = graph.lights[lightName]; #if UF_USE_OPENGL metadata.system.ignoreGraph = true; @@ -1319,10 +1333,9 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) }; } - auto primitiveName = graph.primitives[node.mesh]; auto& mesh = storage.meshes.map[graph.meshes[node.mesh]]; + auto primitiveName = graph.primitives[node.mesh]; auto& primitives = storage.primitives.map[primitiveName]; - auto& grouped = storage.groupedInstances[primitiveName]; node.object = ::allocateObjectID( storage ); auto objectKeyName = std::to_string( node.object ); @@ -1335,6 +1348,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) pod::Instance::Bounds bounds = {}; + auto& grouped = storage.groupedInstances[primitiveName]; for ( auto drawID = 0; drawID < primitives.size(); ++drawID ) { pod::Instance newInstance = primitives[drawID].instance; newInstance.objectID = node.object; @@ -1349,14 +1363,13 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) bool isFirstInstance = ( grouped.size() == primitives.size() ); #if !UF_GRAPH_EXTENDED if ( graphMetadataJson["renderer"]["render"].as() && isFirstInstance ) { - uf::graph::initializeGraphics( graph, entity, mesh, addresses ); + uf::graph::initializeGraphics( graph, entity, mesh, primitives ); } #endif #if 0 auto& mesh = storage.meshes.map[graph.meshes[node.mesh]]; auto& primitives = storage.primitives.map[graph.primitives[node.mesh]]; - auto& instanceAddresses = storage.instanceAddresses.map[graph.primitives[node.mesh]]; pod::Instance::Bounds bounds = {}; size_t baseInstanceID = ::allocateInstanceID( storage, graph.primitives[node.mesh] ); @@ -1449,7 +1462,7 @@ void uf::graph::initialize( pod::Graph::Storage& storage, size_t initialElements // to-do: check if opengl really needs these if ( !storage.buffers.drawCommands.buffer ) storage.buffers.drawCommands.initialize( (const void*) nullptr, sizeof(pod::DrawCommand) * initialElements, uf::renderer::enums::Buffer::STORAGE ); if ( !storage.buffers.instance.buffer ) storage.buffers.instance.initialize( (const void*) nullptr, sizeof(pod::Instance) * initialElements, uf::renderer::enums::Buffer::STORAGE ); - if ( !storage.buffers.instanceAddresses.buffer ) storage.buffers.instanceAddresses.initialize( (const void*) nullptr, sizeof(pod::Instance::Addresses) * initialElements, uf::renderer::enums::Buffer::STORAGE ); + if ( !storage.buffers.addresses.buffer ) storage.buffers.addresses.initialize( (const void*) nullptr, sizeof(pod::Instance::Addresses) * initialElements, uf::renderer::enums::Buffer::STORAGE ); if ( !storage.buffers.lodMetadata.buffer ) storage.buffers.lodMetadata.initialize( (const void*) nullptr, sizeof(pod::LODMetadata) * initialElements, uf::renderer::enums::Buffer::STORAGE ); if ( !storage.buffers.joint.buffer ) storage.buffers.joint.initialize( (const void*) nullptr, sizeof(pod::Matrix4f) * initialElements, uf::renderer::enums::Buffer::STORAGE ); if ( !storage.buffers.object.buffer ) storage.buffers.object.initialize( (const void*) nullptr, sizeof(pod::Instance::Object) * initialElements, uf::renderer::enums::Buffer::STORAGE ); @@ -1515,7 +1528,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) { bool rebuild = false; STATIC_THREAD_LOCAL(uf::stl::vector, instances); - STATIC_THREAD_LOCAL(uf::stl::vector, instanceAddresses); + STATIC_THREAD_LOCAL(uf::stl::vector, addresses); STATIC_THREAD_LOCAL(uf::stl::vector, lodMetadata); STATIC_THREAD_LOCAL(uf::stl::vector, joints); STATIC_THREAD_LOCAL(uf::stl::vector, objects); @@ -1549,44 +1562,40 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) { if ( storage.stale ) { for ( auto& key : storage.primitives.keys ) { - auto& submeshes = storage.primitives.map[key]; + auto& primitives = storage.primitives.map[key]; auto& grouped = storage.groupedInstances.map[key]; - auto& submeshAddresses = storage.instanceAddresses.map[key]; auto& mesh = storage.meshes.map[key]; - pod::DrawCommand* meshIndirectCmds = nullptr; + pod::DrawCommand* commands = nullptr; - if (mesh.indirect.count > 0) { + if ( mesh.indirect.count > 0 ) { auto& attr = mesh.indirect.attributes.front(); - meshIndirectCmds = (pod::DrawCommand*) mesh.buffers[attr.buffer].data(); + commands = (pod::DrawCommand*) mesh.buffers[attr.buffer].data(); } - size_t nodesCount = submeshes.empty() ? 0 : grouped.size() / submeshes.size(); - - for ( size_t drawID = 0; drawID < submeshes.size(); ++drawID ) { - auto& primitive = submeshes[drawID]; + size_t count = primitives.empty() ? 0 : grouped.size() / primitives.size(); + for ( size_t drawID = 0; drawID < primitives.size(); ++drawID ) { + auto& primitive = primitives[drawID]; primitive.drawCommand.instanceID = instances.size(); - primitive.drawCommand.instances = nodesCount; + primitive.drawCommand.instances = count; - if (meshIndirectCmds) { - meshIndirectCmds[drawID].instanceID = primitive.drawCommand.instanceID; - meshIndirectCmds[drawID].instances = primitive.drawCommand.instances; + if ( commands ) { + commands[drawID].instanceID = primitive.drawCommand.instanceID; + commands[drawID].instances = primitive.drawCommand.instances; } drawCommands.emplace_back( primitive.drawCommand ); lodMetadata.emplace_back( primitive.lod ); - bool hasAddresses = (drawID < submeshAddresses.size()); - - for (size_t i = 0; i < nodesCount; ++i) { - size_t strideIndex = (i * submeshes.size()) + drawID; + for ( size_t i = 0; i < count; ++i ) { + size_t strideIndex = (i * primitives.size()) + drawID; instances.emplace_back( grouped[strideIndex] ); - instanceAddresses.emplace_back( hasAddresses ? submeshAddresses[drawID] : pod::Instance::Addresses{} ); + addresses.emplace_back( primitive.addresses ); } } - if (meshIndirectCmds && !grouped.empty()) { + if ( commands && !grouped.empty() ) { auto hostKeyName = std::to_string(grouped.front().objectID); if (storage.entities.map.count(hostKeyName) > 0) { auto* hostEntity = storage.entities.map[hostKeyName]; @@ -1602,7 +1611,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) { for ( auto& key : storage.materials.keys ) materials.emplace_back( storage.materials.map[key] ); rebuild = storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) ) || rebuild; - rebuild = storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild; + rebuild = storage.buffers.addresses.update( (const void*) addresses.data(), addresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild; rebuild = storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) ) || rebuild; rebuild = storage.buffers.lodMetadata.update( (const void*) lodMetadata.data(), lodMetadata.size() * sizeof(pod::LODMetadata) ) || rebuild; rebuild = storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ) || rebuild; @@ -1627,7 +1636,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) { shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands ); shader.aliasBuffer( "instance", storage.buffers.instance ); - shader.aliasBuffer( "instanceAddresses", storage.buffers.instanceAddresses ); + shader.aliasBuffer( "addresses", storage.buffers.addresses ); shader.aliasBuffer( "material", storage.buffers.material ); shader.aliasBuffer( "texture", storage.buffers.texture ); shader.aliasBuffer( "light", storage.buffers.light ); @@ -1644,7 +1653,7 @@ void uf::graph::aggregate() { } void uf::graph::aggregate( uf::Object& object, pod::Graph::Storage& storage ) { STATIC_THREAD_LOCAL(uf::stl::vector, instances); - STATIC_THREAD_LOCAL(uf::stl::vector, instanceAddresses); + STATIC_THREAD_LOCAL(uf::stl::vector, addresses); STATIC_THREAD_LOCAL(uf::stl::vector, lodMetadata); STATIC_THREAD_LOCAL(uf::stl::vector, joints); STATIC_THREAD_LOCAL(uf::stl::vector, objects); @@ -1703,14 +1712,14 @@ void uf::graph::aggregate( uf::Object& object, pod::Graph::Storage& storage ) { } } - for ( auto& key : storage.instanceAddresses.keys ) { - instanceAddresses.insert( instanceAddresses.end(), storage.instanceAddresses.map[key].begin(), storage.instanceAddresses.map[key].end() ); + for ( auto& key : storage.addresses.keys ) { + addresses.insert( addresses.end(), storage.addresses.map[key].begin(), storage.addresses.map[key].end() ); } } bool rebuild = false; rebuild = storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) ) || rebuild; - rebuild = storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild; + rebuild = storage.buffers.addresses.update( (const void*) addresses.data(), addresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild; rebuild = storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) ) || rebuild; rebuild = storage.buffers.lodMetadata.update( (const void*) lodMetadata.data(), lodMetadata.size() * sizeof(pod::LODMetadata) ) || rebuild; rebuild = storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ) || rebuild; @@ -1800,16 +1809,17 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) { #endif // cleanup graphic handles - for ( auto pair : storage.texture2Ds.map ) pair.second.destroy(); + for ( auto pair : storage.images.map ) { + pair.second.data.clear(); + pair.second.handle.destroy(); + } for ( auto& t : storage.shadow2Ds ) t.destroy(); for ( auto& t : storage.shadowCubes ) t.destroy(); for ( auto pair : storage.atlases.map ) pair.second.clear(); - for ( auto pair : storage.images.map ) pair.second.clear(); for ( auto pair : storage.meshes.map ) pair.second.destroy(); // cleanup storage cache - storage.instanceAddresses.clear(); storage.primitives.clear(); storage.meshes.clear(); storage.images.clear(); @@ -1820,7 +1830,6 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) { storage.animations.clear(); storage.atlases.clear(); storage.joints.clear(); - storage.texture2Ds.clear(); storage.entities.clear(); storage.shadow2Ds.clear(); storage.shadowCubes.clear(); @@ -1831,7 +1840,7 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) { storage.buffers.drawCommands.destroy(true); storage.buffers.lodMetadata.destroy(true); storage.buffers.instance.destroy(true); - storage.buffers.instanceAddresses.destroy(true); + storage.buffers.addresses.destroy(true); storage.buffers.joint.destroy(true); storage.buffers.object.destroy(true); storage.buffers.material.destroy(true); @@ -1880,7 +1889,6 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { auto model = uf::transform::model( transform ); auto& mesh = storage.meshes.map[graph.meshes[node.mesh]]; auto& primitives = storage.primitives.map[graph.primitives[node.mesh]]; - auto& instanceAddresses = storage.instanceAddresses.map[graph.primitives[node.mesh]]; float radius = graph.settings.stream.radius; float radiusSquared = radius * radius; @@ -2133,8 +2141,8 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { // iterate through our ref counts for ( auto& [ key, count ] : textureReferences ) { - auto& texture = storage.texture2Ds[key]; - auto& image = storage.images[key]; + auto& image = storage.images[key].data; + auto& texture = storage.images[key].handle; bool visible = count > 0; if ( visible && (!texture.generated() || texture.aliased) ) { @@ -2240,11 +2248,11 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { if ( rebuild ) { ::bindBuffers( graph, graphic, mesh ); - ::bindInstanceAddresses( graph, graphic, mesh, instanceAddresses ); + ::bindAddresses( graph, graphic, mesh, primitives ); uf::renderer::states::rebuild = true; } } else { - uf::graph::initializeGraphics( graph, entity, mesh, instanceAddresses ); + uf::graph::initializeGraphics( graph, entity, mesh, primitives ); } } // bind mesh to physics state @@ -2306,10 +2314,10 @@ void uf::graph::update( pod::Graph& graph, float delta ) { auto& graphic = entity.getComponent(); auto& mesh = storage.meshes.map[graph.meshes[node.mesh]]; - auto& instanceAddresses = storage.instanceAddresses.map[graph.primitives[node.mesh]]; + auto& primitives = storage.primitives.map[graph.primitives[node.mesh]]; ::bindBuffers( graph, graphic, mesh ); - ::bindInstanceAddresses( graph, graphic, mesh, instanceAddresses ); + ::bindAddresses( graph, graphic, mesh, primitives ); } storage.shouldRebind = false; } diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index 278c4e1c..bae4b277 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -156,7 +156,7 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const for ( auto& i : model.images ) { auto imageID = graph.images.size(); auto keyName = graph.images.emplace_back(key + i.name); - auto& image = storage.images[keyName]; + auto& image = storage.images[keyName].data; if ( graph.metadata["debug"]["print"]["images"].as() ) { UF_MSG_DEBUG("Image: {}", i.name ); } @@ -290,7 +290,6 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const auto& primitives = storage.primitives[keyName]; auto& mesh = storage.meshes[keyName]; - storage.instanceAddresses[keyName] = {}; struct { uf::meshgrid::Grid grid; @@ -472,14 +471,13 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const auto atlasImageIndex = graph.images.size(); auto atlasTextureIndex = graph.textures.size(); - for ( auto& keyName : graph.images ) atlas.addImage( storage.images[keyName] ); + for ( auto& keyName : graph.images ) atlas.addImage( storage.images[keyName].data ); atlas.generate(); for ( auto& keyName : graph.images ) { auto& texture = storage.textures[keyName]; - storage.texture2Ds[keyName]; if ( texture.index < 0 ) continue; - auto& image = storage.images[keyName]; + auto& image = storage.images[keyName].data; const auto& hash = image.getHash(); auto min = atlas.mapUv( {0, 0}, hash ); @@ -491,7 +489,7 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const { graph.images.emplace_back(atlasName); - auto& image = storage.images[atlasName]; + auto& image = storage.images[atlasName].data; image = atlas.getAtlas(); graph.textures.emplace_back(atlasName); diff --git a/engine/src/ext/valve/bsp.cpp b/engine/src/ext/valve/bsp.cpp index 4bd8cb18..84ae83bf 100644 --- a/engine/src/ext/valve/bsp.cpp +++ b/engine/src/ext/valve/bsp.cpp @@ -342,8 +342,8 @@ namespace impl { v.uv.y = uf::vector::dot( vertex, info.textureVecs[1] ) / (float) data.height; } - v.st.x = (uf::vector::dot( vertex, info.lightmapVecs[0] ) - face.lightmapTextureMins.x) / (face.lightmapTextureSize.x + 1.0f); - v.st.y = (uf::vector::dot( vertex, info.lightmapVecs[1] ) - face.lightmapTextureMins.y) / (face.lightmapTextureSize.y + 1.0f); + v.st.x = (uf::vector::dot( vertex, info.lightmapVecs[0] ) + 0.5f - face.lightmapTextureMins.x) / (face.lightmapTextureSize.x + 1.0f); + v.st.y = (uf::vector::dot( vertex, info.lightmapVecs[1] ) + 0.5f - face.lightmapTextureMins.y) / (face.lightmapTextureSize.y + 1.0f); v.st = uf::atlas::mapUv( context.lightmapAtlas, v.st, impl::faceHash( faceID ) ); @@ -386,15 +386,17 @@ namespace impl { int32_t spawnID = -1; uf::stl::vector spawns; + uf::stl::unordered_map targets; for ( auto nodeID : graph.root.children ) { auto& node = graph.nodes[nodeID]; - auto classname = node.metadata["classname"].as(""); + auto& metadata = node.metadata["valve"]; + auto classname = metadata["classname"].as(""); //UF_MSG_INFO("Entity found: {}", classname); node.name = classname; // parse origin - auto origin = node.metadata["origin"].as(""); + auto origin = metadata["origin"].as(""); if ( origin != "" ) { auto position = impl::str2vec( origin ); node.transform.position = impl::convertPos( position, scale ); @@ -402,7 +404,7 @@ namespace impl { // parse angles // to-do: fix oddities - auto angles = node.metadata["angles"].as(""); + auto angles = metadata["angles"].as(""); if ( angles != "" ) { auto pyr = impl::str2vec( angles ) * DEG_2_RAD; pyr.x = -pyr.x; @@ -411,7 +413,7 @@ namespace impl { } // parse model - auto model = node.metadata["model"].as(); + auto model = metadata["model"].as(); if ( classname == "worldspawn" ) { node.mesh = context.modelToMesh[0]; // implicitly bind to model 0 } else if ( model.starts_with("*") ) { @@ -420,26 +422,26 @@ namespace impl { node.mesh = context.modelToMesh[modelID]; } } else if ( model.length() > 4 && model.ends_with(".mdl") ) { - auto it = std::find(graph.meshes.begin(), graph.meshes.end(), model); - if ( it == graph.meshes.end() ) { - if ( ext::valve::loadMdl(graph, model) ) { - node.mesh = (int32_t)(graph.meshes.size() - 1); - } - } else { - node.mesh = (int32_t)std::distance(graph.meshes.begin(), it); - } - } + auto it = std::find(graph.meshes.begin(), graph.meshes.end(), model); + if ( it == graph.meshes.end() ) { + if ( ext::valve::loadMdl(graph, model) ) { + node.mesh = (int32_t)(graph.meshes.size() - 1); + } + } else { + node.mesh = (int32_t)std::distance(graph.meshes.begin(), it); + } + } // parse lighting info if ( classname.starts_with("light") ) { - auto lightKeyName = ::fmt::format( "{}_{}", classname, lights++ ); + auto lightKeyName = ::fmt::format( "{}_{}", classname, nodeID ); auto& light = graph.lights[lightKeyName]; light.color = { 1.0f, 1.0f, 1.0f }; - light.intensity = 1.0f; + light.intensity = 200.0f; light.range = 0.0f; // read color and intensity - auto _light = node.metadata["_light"].as(""); + auto _light = metadata["_light"].as(""); if ( _light != "" ) { // to-do: do not use stringstream std::istringstream stream(_light); @@ -449,10 +451,9 @@ namespace impl { light.color /= 255.0f; if (!(stream >> light.intensity)) light.intensity = 200.0f; - light.intensity /= 10.0f; } - // to-do: read range + light.intensity *= 0.2f; // scale down } // parse player spawn info @@ -462,9 +463,32 @@ namespace impl { spawns.emplace_back(nodeID); } + auto targetname = metadata["targetname"].as(""); + if ( targetname != "" ) { + targets[targetname] = nodeID; + } + // to-do: add additional parsing } + uf::stl::vector newChildren; + for ( auto nodeID : graph.root.children ) { + auto& node = graph.nodes[nodeID]; + auto& metadata = node.metadata["valve"]; + + auto parentname = metadata["parentname"].as(""); + if ( parentname != "" && targets.count(parentname) > 0 ) { + auto parentID = targets[parentname]; + auto& parentNode = graph.nodes[parentID]; + parentNode.children.emplace_back(nodeID); + + node.transform = uf::transform::relative( parentNode.transform, node.transform ); + } else { + newChildren.emplace_back(nodeID); + } + } + graph.root.children = newChildren; + // no valid spawn UF_ASSERT( !(spawnID == -1 && spawns.empty()) ); // to-do: make the engine implicitly spawn the player at origin // pick a random candidate if none was found @@ -537,12 +561,11 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co size_t imageID = graph.images.size(); auto imgKeyName = graph.images.emplace_back(matName); - auto& image = storage.images[imgKeyName]; + auto& image = storage.images[imgKeyName].data; size_t textureID = graph.textures.size(); auto texKeyName = graph.textures.emplace_back(matName); storage.textures[texKeyName].index = imageID; - storage.texture2Ds[texKeyName]; size_t materialID = graph.materials.size(); context.texdataToMaterial[texDataID] = materialID; @@ -551,6 +574,9 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co auto& material = storage.materials[matKeyName]; material.indexAlbedo = textureID; material.colorBase = {1.0f, 1.0f, 1.0f, 1.0f}; + material.factorMetallic = 0.0f; + material.factorRoughness = 1.0f; + material.factorOcclusion = 1.0f; //UF_MSG_INFO("Material found: {}", matName); } @@ -559,13 +585,18 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co auto atlasImageID = graph.images.size(); auto atlasTextureID = graph.textures.size(); + for ( size_t i = 3; i < context.lighting.size(); i += 4 ) { + int8_t exp = (int8_t)context.lighting[i]; + context.lighting[i] = (uint8_t)(exp + 128); + } for ( auto faceID = 0; faceID < context.faces.size(); ++faceID ) { const auto& face = context.faces[faceID]; if ( face.lightofs == -1 || context.lighting.empty() ) continue; size_t width = face.lightmapTextureSize.x + 1; size_t height = face.lightmapTextureSize.y + 1; - + + uf::Image image; image.loadFromBuffer( (uint8_t*)(context.lighting.data() + face.lightofs), { width, height }, 8, 4 ); @@ -580,9 +611,8 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co auto& imageKey = graph.images.emplace_back("lightmap_atlas"); auto& textureKey = graph.textures.emplace_back("lightmap_atlas"); - storage.images[imageKey] = uf::atlas::get( context.lightmapAtlas ); + storage.images[imageKey].data = uf::atlas::get( context.lightmapAtlas ); storage.textures[textureKey].index = atlasImageID; - storage.texture2Ds[textureKey]; } // read models @@ -605,7 +635,10 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co // read brush auto& meshlet = meshlets[materialID]; meshlet.primitive.instance.materialID = materialID; - meshlet.primitive.instance.lightmapID = atlasTextureID; + + if ( 0 <= face.lightofs ) { + meshlet.primitive.instance.lightmapID = atlasTextureID; + } if ( face.dispinfo != -1 ) { impl::buildDisplacement( context, meshlet, faceID ); @@ -644,7 +677,6 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co auto& mesh = storage.meshes[meshName]; auto& primitives = storage.primitives[meshName]; - storage.instanceAddresses[meshName] = {}; mesh.compile( meshlets, primitives ); } @@ -667,7 +699,8 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co // create node auto nodeID = graph.nodes.size(); auto& node = graph.nodes.emplace_back(); - for ( const auto& [k, v] : dict ) node.metadata[k] = v; // store as metadata for later parsing + auto& metadata = node.metadata["valve"]; + for ( const auto& [k, v] : dict ) metadata[k] = v; // store as metadata for later parsing // add node as child graph.root.children.emplace_back( nodeID ); @@ -722,11 +755,12 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co if ( type < dict.size() ) { auto nodeID = graph.nodes.size(); auto& node = graph.nodes.emplace_back(); + auto& metadata = node.metadata["valve"]; - node.metadata["classname"] = "prop_static"; - node.metadata["model"] = dict[type]; - node.metadata["origin"] = ::fmt::format("{} {} {}", origin.x, origin.y, origin.z); - node.metadata["angles"] = ::fmt::format("{} {} {}", angles.x, angles.y, angles.z); + metadata["classname"] = "prop_static"; + metadata["model"] = dict[type]; + metadata["origin"] = ::fmt::format("{} {} {}", origin.x, origin.y, origin.z); + metadata["angles"] = ::fmt::format("{} {} {}", angles.x, angles.y, angles.z); graph.root.children.emplace_back( nodeID ); } @@ -743,9 +777,28 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co uf::Serializer vmt; auto vmtPath = ::fmt::format("materials/{}.vmt", matName); auto vtfPath = ::fmt::format("materials/{}.vtf", matName); - auto& image = storage.images[matName]; + auto& image = storage.images[matName].data; + auto& material = storage.materials[matName]; if ( !ext::valve::loadVmt( vmt, vmtPath ) ) goto PEETAH; + + material.factorMetallic = vmt["$metalness"].as(0.0f); + material.factorRoughness = vmt["$roughness"].as(1.0f); + + if ( vmt["$envmap"].as() != "" ) material.factorRoughness = 0.3f; + if ( vmt["$phong"].as("0") == "1" ) material.factorRoughness = std::min(material.factorRoughness, 0.5f); + + if ( vmt["$translucent"].as("0") == "1" ) { + material.modeAlpha = 1; // BLEND + } else if ( vmt["$alphatest"].as("0") == "1" ) { + material.modeAlpha = 2; // MASK + material.factorAlphaCutoff = vmt["$alphatestreference"].as(0.5f); + } + if ( vmt["$nocull"].as("0") == "1" ) material.modeCull = 0; + + // VMTs usually define emissive masks in the albedo's alpha channel or a separate mask + // set it to a white glow for now until I can patch the shader + if ( vmt["$selfillum"].as("0") == "1" ) material.colorEmissive = { 1.0f, 1.0f, 1.0f, 1.0f }; if ( !vmt["$basetexture"].is() ) goto PEETAH; vtfPath = ::fmt::format("materials/{}.vtf", vmt["$basetexture"].as()); diff --git a/engine/src/ext/valve/mdl.cpp b/engine/src/ext/valve/mdl.cpp index ed0be4ca..b4250e5d 100644 --- a/engine/src/ext/valve/mdl.cpp +++ b/engine/src/ext/valve/mdl.cpp @@ -288,19 +288,22 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) { // does not exist, register size_t imageID = graph.images.size(); auto imgKeyName = graph.images.emplace_back(matName); - auto& image = storage.images[imgKeyName]; + auto& image = storage.images[imgKeyName].data; size_t textureID = graph.textures.size(); auto texKeyName = graph.textures.emplace_back(matName); storage.textures[texKeyName].index = imageID; - storage.texture2Ds[texKeyName]; materialID = graph.materials.size(); auto matKeyName = graph.materials.emplace_back(matName); auto& material = storage.materials[matKeyName]; material.indexAlbedo = textureID; material.colorBase = {1.0f, 1.0f, 1.0f, 1.0f}; - } + material.factorMetallic = 0.0f; + material.factorRoughness = 1.0f; + material.factorOcclusion = 1.0f; + } + meshlet.primitive.instance.materialID = materialID; } } @@ -313,7 +316,6 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) { auto& mesh = storage.meshes[meshName]; auto& primitives = storage.primitives[meshName]; - storage.instanceAddresses[meshName] = {}; mesh.compile( meshlets, primitives ); } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 6e2faefd..b1b3f0ab 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -1198,9 +1198,8 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { #define PARSE_INPUT_INITIALIZE(NAME, USAGE){\ for ( size_t i = 0; i < descriptor.inputs.NAME.attributes.size(); ++i ) {\ auto& attribute = descriptor.inputs.NAME.attributes[i];\ - auto& buffer = mesh.buffers[attribute.buffer];\ - if ( !buffer.empty() ) {\ - attribute.buffer = initializeBuffer( (const void*) buffer.data(), buffer.size(), USAGE | baseUsage );\ + if ( attribute.pointer && attribute.length > 0 ) {\ + attribute.buffer = initializeBuffer( (const void*) attribute.pointer, attribute.length, USAGE | baseUsage );\ this->metadata.buffers[#NAME"["+attribute.descriptor.name+"]"] = attribute.buffer;\ } else attribute.buffer = -1;\ }\ @@ -1239,9 +1238,8 @@ bool ext::vulkan::Graphic::updateMesh( uf::Mesh& mesh ) { #define PARSE_INPUT_UPDATE(NAME, USAGE){\ for ( size_t i = 0; i < descriptor.inputs.NAME.attributes.size(); ++i ) {\ auto& attribute = descriptor.inputs.NAME.attributes[i];\ - auto& buffer = mesh.buffers[attribute.buffer];\ - if ( !buffer.empty() ) {\ - rebuild = updateBuffer( (const void*) buffer.data(), buffer.size(), this->metadata.buffers[#NAME"["+attribute.descriptor.name+"]"] ) || rebuild;\ + if ( attribute.pointer && attribute.length > 0 ) {\ + rebuild = updateBuffer( (const void*) attribute.pointer, attribute.length, this->metadata.buffers[#NAME"["+attribute.descriptor.name+"]"] ) || rebuild;\ } else attribute.buffer = -1;\ }\ } diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index cc396d54..b5d32b5d 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -553,7 +553,7 @@ void ext::vulkan::DeferredRenderMode::build( bool resized ) { // shader.aliasBuffer( storage.buffers.joint ); shader.aliasBuffer( storage.buffers.drawCommands ); shader.aliasBuffer( storage.buffers.instance ); - shader.aliasBuffer( storage.buffers.instanceAddresses ); + shader.aliasBuffer( storage.buffers.addresses ); shader.aliasBuffer( storage.buffers.object ); shader.aliasBuffer( storage.buffers.material ); shader.aliasBuffer( storage.buffers.texture ); diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 484dfe10..7127eab8 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -229,7 +229,7 @@ void ext::vulkan::RenderTargetRenderMode::build( bool resized ) { // shader.aliasBuffer( storage.buffers.joint ); shader.aliasBuffer( storage.buffers.drawCommands ); shader.aliasBuffer( storage.buffers.instance ); - shader.aliasBuffer( storage.buffers.instanceAddresses ); + shader.aliasBuffer( storage.buffers.addresses ); shader.aliasBuffer( storage.buffers.object ); shader.aliasBuffer( storage.buffers.material ); shader.aliasBuffer( storage.buffers.texture ); diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index 378249a9..7140b12a 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include // std::fstream #include // std::fstream #include // libpng @@ -13,6 +14,14 @@ #include #include +namespace { + void stbi_buffer_write_func(void *context, void *data, int size) { + auto* buffer = static_cast*>(context); + auto* bytes = static_cast(data); + buffer->insert(buffer->end(), bytes, bytes + size); + } +} + namespace impl { pod::Image scaleNearest( const pod::Image& image, const pod::Vector2ui& size ) { pod::Image out = image; @@ -203,12 +212,20 @@ bool uf::image::save( const pod::Image& image, const uf::stl::string& filename, auto* pixels = &image.pixels[0]; uf::stl::string extension = uf::io::extension(filename); stbi_flip_vertically_on_write(flip); - if ( extension == "png" ) { - stbi_write_png(filename.c_str(), w, h, image.channels, &pixels[0], w * image.channels); - } else if ( extension == "jpg" || extension == "jpeg" ) { - stbi_write_jpg(filename.c_str(), w, h, image.channels, &pixels[0], w * image.channels); - } - return true; + + uf::stl::vector buffer; + + if ( extension == "png" ) { + stbi_write_png_to_func(stbi_buffer_write_func, &buffer, w, h, image.channels, pixels, w * image.channels); + } else if ( extension == "jpg" || extension == "jpeg" ) { + stbi_write_jpg_to_func(stbi_buffer_write_func, &buffer, w, h, image.channels, pixels, 90); // 90 is quality + } else { + UF_MSG_ERROR("Unsupported image save format: {}", extension); + return false; + } + + if ( buffer.empty() ) return false; + return uf::vfs::write( filename, buffer.data(), buffer.size() ) > 0; } void uf::image::save( const pod::Image& image, std::ostream& stream ) { diff --git a/engine/src/utils/io/file.cpp b/engine/src/utils/io/file.cpp index 049c781c..3208cd8a 100644 --- a/engine/src/utils/io/file.cpp +++ b/engine/src/utils/io/file.cpp @@ -216,14 +216,8 @@ bool uf::io::exists( const uf::stl::string& filename ) { size_t uf::io::mtime( const uf::stl::string& filename ) { return uf::vfs::mtime( uf::io::resolveURI(filename) ); } -bool uf::io::mkdir( const uf::stl::string& _filename ) { -#if UF_ENV_DREAMCAST || UF_ENV_LINUX - return false; -#else - uf::stl::string filename = uf::io::normalize(_filename); - int status = ::mkdir(filename.c_str()); - return status != -1; -#endif +bool uf::io::mkdir( const uf::stl::string& filename ) { + return uf::vfs::mkdir( uf::io::resolveURI(filename) ); } uf::stl::string uf::io::assetType( const uf::stl::string& _filename ) { diff --git a/engine/src/utils/io/vfs.cpp b/engine/src/utils/io/vfs.cpp index 74d1c8da..11a21ac9 100644 --- a/engine/src/utils/io/vfs.cpp +++ b/engine/src/utils/io/vfs.cpp @@ -61,6 +61,15 @@ pod::Mount uf::vfs::createDiskMount( const uf::stl::string& uri, int priority) { output.close(); return size; }, + .mkdir = [path](const uf::stl::string& file) -> bool { + uf::stl::string fullPath = path + file; + #if UF_ENV_DREAMCAST || UF_ENV_LINUX + return false; + #else + int status = ::mkdir(fullPath.c_str()); + return status != -1; + #endif + }, .readRange = [path](const uf::stl::string& file, size_t start, size_t len, uf::stl::vector& buffer) -> bool { uf::stl::string fullPath = path + file; std::ifstream is(fullPath, std::ios::binary); @@ -166,6 +175,19 @@ bool uf::vfs::exists( const uf::stl::string& path ) { return false; } +bool uf::vfs::mkdir( const uf::stl::string& path ) { + uf::stl::string prefix, relative; + uf::io::splitUri(path, prefix, relative); + + for ( const auto& mount : mounts ) { + if ( prefix.empty() && mount.priority < 0 ) continue; + if ( prefix.empty() || mount.prefix == prefix ) { + if ( mount.mkdir(relative) ) return true; + } + } + return false; +} + size_t uf::vfs::size( const uf::stl::string& path ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); diff --git a/engine/src/utils/mesh/mesh.cpp b/engine/src/utils/mesh/mesh.cpp index 6425f642..34420925 100644 --- a/engine/src/utils/mesh/mesh.cpp +++ b/engine/src/utils/mesh/mesh.cpp @@ -130,6 +130,12 @@ uf::Mesh& uf::Mesh::copy( const uf::Mesh& src ) { return *this; } +uf::Mesh uf::Mesh::alias() const { + uf::Mesh alias = *this; + for ( auto& buf : alias.buffers ) buf.clear(); + alias.updateDescriptor(); + return alias; +} void uf::Mesh::updateDescriptor() { _updateDescriptor(vertex); _updateDescriptor(index); @@ -150,7 +156,7 @@ void uf::Mesh::insert( const uf::Mesh& mesh ) { insertVertices(mesh); insertIndices(mesh); - insertInstances(mesh); +// insertInstances(mesh); insertIndirects(mesh); updateDescriptor(); @@ -282,25 +288,25 @@ const uf::Mesh::buffer_t& uf::Mesh::getBuffer( const uf::Mesh::Input& input, con uf::Mesh::View uf::Mesh::makeView( const uf::stl::vector& wanted, size_t lod ) const { uf::Mesh::View view; - view.vertex = vertex; - view.index = index; + view.vertex = vertex; + view.index = index; - if ( wanted.size() ) { - for ( auto& attr : vertex.attributes ) { - if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue; - view.attributes[uf::string::fnv1a(attr.descriptor.name)] = { attr }; - } - } else { - for ( auto& attr : vertex.attributes ) { - view.attributes[uf::string::fnv1a(attr.descriptor.name)] = { attr }; - } - } + if ( wanted.size() ) { + for ( auto& attr : vertex.attributes ) { + if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue; + view.attributes[uf::string::fnv1a(attr.descriptor.name)] = { attr }; + } + } else { + for ( auto& attr : vertex.attributes ) { + view.attributes[uf::string::fnv1a(attr.descriptor.name)] = { attr }; + } + } - if ( !index.attributes.empty() ) { - view.attributes["index"_hash] = { index.attributes[lod] }; - } + if ( !index.attributes.empty() ) { + view.attributes["index"_hash] = { index.attributes[lod] }; + } - return view; + return view; } uf::Mesh::View uf::Mesh::makeView( size_t i, const uf::stl::vector& wanted, size_t lod ) const { uf::Mesh::View view; @@ -398,9 +404,11 @@ void uf::Mesh::_bind() { void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) { input.size = 0; for ( auto& attribute : input.attributes ) { - auto& buffer = buffers[attribute.buffer]; - attribute.length = buffer.size(); - attribute.pointer = buffer.data() + attribute.offset; + if ( attribute.buffer >= 0 && attribute.buffer < buffers.size() && !buffers[attribute.buffer].empty() ) { + auto& buffer = buffers[attribute.buffer]; + attribute.length = buffer.size(); + attribute.pointer = buffer.data() + attribute.offset; + } if ( &input == &index || &input == &indirect ) input.size = attribute.descriptor.size; else input.size += attribute.descriptor.size; @@ -510,24 +518,24 @@ void uf::Mesh::_insertV( uf::Mesh::Input& input, const void* data ) { } void uf::Mesh::_insertVs( uf::Mesh::Input& input, const void* data, size_t size ) { size_t count = input.count; - input.count += size; + input.count += size; - _resizeVs( input, input.count ); + _resizeVs( input, input.count ); - const uint8_t* pointer = static_cast(data); - for ( auto& attribute : input.attributes ) { - uint8_t* dstBase = buffers[attribute.buffer].data() + (count * attribute.descriptor.size); + const uint8_t* pointer = static_cast(data); + for ( auto& attribute : input.attributes ) { + uint8_t* dstBase = buffers[attribute.buffer].data() + (count * attribute.descriptor.size); - size_t srcOffset = attribute.descriptor.offset; - size_t attrSize = attribute.descriptor.size; + size_t srcOffset = attribute.descriptor.offset; + size_t attrSize = attribute.descriptor.size; - for ( size_t i = 0; i < size; ++i ) { - const uint8_t* srcAddr = pointer + (i * input.size) + srcOffset; - uint8_t* dstAddr = dstBase + (i * attrSize); + for ( size_t i = 0; i < size; ++i ) { + const uint8_t* srcAddr = pointer + (i * input.size) + srcOffset; + uint8_t* dstAddr = dstBase + (i * attrSize); - memcpy( dstAddr, srcAddr, attrSize ); - } - } + memcpy( dstAddr, srcAddr, attrSize ); + } + } } // Indices void uf::Mesh::_bindI( uf::Mesh::Input& input, size_t size, ext::RENDERER::enums::Type::type_t type, size_t count ) {