From a9f5a5636699551c6ec77dd7afd44a9e272be29a Mon Sep 17 00:00:00 2001 From: mrq Date: Sun, 5 Jun 2022 22:42:00 -0500 Subject: [PATCH] Commit for 2022.06.05 22-42-59.7z --- Makefile | 8 +- bin/data/config.json | 10 +- bin/data/entities/model.json | 5 +- bin/data/scenes/mcdonalds/mcdonalds.json | 3 +- bin/data/scenes/ss2/medsci.json | 8 +- bin/data/scenes/ss2/test.json | 25 ++ bin/dreamcast/config.json | 2 +- engine/inc/uf/engine/graph/mesh.inl | 2 + engine/inc/uf/ext/meshopt/meshopt.h | 2 +- engine/inc/uf/utils/mesh/grid.h | 12 +- engine/src/engine/asset/asset.cpp | 2 + engine/src/engine/graph/convert.cpp | 100 ++++++-- engine/src/engine/graph/decode.cpp | 38 ++- engine/src/engine/graph/encode.cpp | 124 +++++----- engine/src/engine/graph/graph.cpp | 2 + engine/src/ext/gltf/gltf.cpp | 114 ++++----- engine/src/ext/gltf/processPrimitives2.inl | 8 +- engine/src/ext/meshopt/meshopt.cpp | 266 ++++++++++++--------- engine/src/ext/opengl/commands.cpp | 10 + engine/src/ext/opengl/graphic.cpp | 65 ++--- engine/src/ext/xatlas/xatlas.cpp | 3 +- ext/gui/behavior.cpp | 36 ++- 22 files changed, 481 insertions(+), 364 deletions(-) create mode 100644 bin/data/scenes/ss2/test.json diff --git a/Makefile b/Makefile index b589f605..a211a012 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ ifneq (,$(findstring simd,$(REQ_DEPS))) endif endif ifneq (,$(findstring meshoptimizer,$(REQ_DEPS))) - FLAGS += -DUF_USE_MESHOPTIMIZER + FLAGS += -DUF_USE_MESHOPT DEPS += -lmeshoptimizer endif ifneq (,$(findstring draco,$(REQ_DEPS))) @@ -315,7 +315,9 @@ clean: @-rm ./bin/dreamcast/build/* @-rm ./bin/dreamcast/romdisk.* @-rm ./bin/dreamcast/$(TARGET_NAME).* - # @-find ./bin/data/ -name "*.gz" -type f -delete + +clean-zips: + @-find ./bin/data/ -name "*.gz" -type f -delete run: $(KOS_EMU) ./bin/dreamcast/$(TARGET_NAME).cdi @@ -328,6 +330,8 @@ clean: @-rm -f $(OBJS_DLL) @-rm -f $(OBJS_EXT_DLL) @-rm -f $(OBJS) + +clean-zips: @-find ./bin/data/ -name "*.gz" -type f -delete run: diff --git a/bin/data/config.json b/bin/data/config.json index 62a54b59..75ecefeb 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -6,7 +6,7 @@ "matrix": { "reverseInfinite": true }, "lights": { "enabled": true, "useLightmaps": false, - "max": 16 + "max": 32 }, "shadows": { "enabled": true, @@ -24,17 +24,17 @@ }, "vxgi": { "limiter": 1, - "size": 86, + "size": 128, "dispatch": 8, "cascades": 4, - "cascadePower": 4, + "cascadePower": 3, "granularity": 8, "voxelizeScale": 1, "occlusionFalloff": 2, "shadows": 0, "extents": { - "min": [ -4, -4, -4 ], - "max": [ 4, 4, 4 ] + "min": [ -8, -1, -8 ], + "max": [ 8, 4, 8 ] } }, "bloom": { diff --git a/bin/data/entities/model.json b/bin/data/entities/model.json index 9cef6284..85f1d09a 100644 --- a/bin/data/entities/model.json +++ b/bin/data/entities/model.json @@ -24,14 +24,15 @@ "precision": 4, "combined": false, "encode buffers": true, - "unwrap": true, + "unwrap": false, + "optimize": "tagged", "quit": true, "mesh": { // "print": true } }, "baking": { - "enabled": false, + "enabled": true, "resolution": 8192, "shadows": 1024, "layers": 1, diff --git a/bin/data/scenes/mcdonalds/mcdonalds.json b/bin/data/scenes/mcdonalds/mcdonalds.json index d6a758c3..be74ffd0 100644 --- a/bin/data/scenes/mcdonalds/mcdonalds.json +++ b/bin/data/scenes/mcdonalds/mcdonalds.json @@ -22,7 +22,8 @@ "tags": { "/^worldspawn/": { "physics": { "type": "mesh", "static": true }, - "grid": { "size": [4,1,4], "epsilon": 1.0, "cleanup": true, "print": true } + "grid": { "size": [4,1,4], "epsilon": 1.0, "cleanup": true, "print": true }, + "optimize mesh": { "simplify": 0 } }, "info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true }, diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index 0f613a80..dcf9b6e2 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -2,15 +2,16 @@ "import": "/model.json", "assets": [ // { "filename": "./craeture.json", "delay": 1 }, + { "filename": "./test.json", "delay": 1 }, // { "filename": "./models/tiny_msci.glb" } - // { "filename": "./models/tiny_msci/graph.json" } + { "filename": "./models/tiny_msci/graph.json" } // { "filename": "./models/micro_sci.glb" } // { "filename": "./models/micro_sci/graph.json" } // { "filename": "./models/msci.glb" } - { "filename": "./models/msci/graph.json" } + // { "filename": "./models/msci/graph.json" } // { "filename": "./models/medsci.glb" } // { "filename": "./models/medsci/graph.json" } @@ -25,7 +26,8 @@ "tags": { "/^worldspawn/": { "physics": { "type": "mesh", "static": true }, - "grid": { "size": [5,1,5], "epsilon": 1.0, "cleanup": true, "print": true } + "grid": { "size": [5,1,5], "epsilon": 1.0, "cleanup": true, "print": true }, + "optimize mesh": { "simplify": 0 } }, "info_player_spawn": { "action": "attach", diff --git a/bin/data/scenes/ss2/test.json b/bin/data/scenes/ss2/test.json new file mode 100644 index 00000000..c4fc9edc --- /dev/null +++ b/bin/data/scenes/ss2/test.json @@ -0,0 +1,25 @@ +{ + "name": "Gui: Text Test", + "type": "Gui", + "ignore": false, + "transform": { + "position": [18.3785, 2.41477, 0.859857], + "rotation": { + "axis": [ 0, 0, 1 ], + "angle": 3.141 + }, + "scale": [ 1, 1, 1 ] + }, + "metadata": { + "uv": [ 0, 0, 1, 1 ], + "location": "", + "scaling": "relative", + "world": true, + "cull mode": "none", + "text settings": { + "scale": 8, + "font": "Coolvetica.ttf", + "string": "Grimgram" + } + } +} \ No newline at end of file diff --git a/bin/dreamcast/config.json b/bin/dreamcast/config.json index c3bc3aae..3e42ef10 100644 --- a/bin/dreamcast/config.json +++ b/bin/dreamcast/config.json @@ -1,7 +1,7 @@ { "engine": { "scenes": { - "start": "SS2", + "start": "McDonalds", "meshes": { "interleaved": false }, "matrix": { "reverseInfinite": false }, "lights": { "enabled": false, diff --git a/engine/inc/uf/engine/graph/mesh.inl b/engine/inc/uf/engine/graph/mesh.inl index 2b582332..20748617 100644 --- a/engine/inc/uf/engine/graph/mesh.inl +++ b/engine/inc/uf/engine/graph/mesh.inl @@ -7,6 +7,7 @@ namespace uf { pod::ColorRgba color{ (uint8_t) ~0, (uint8_t) ~0, (uint8_t) ~0, (uint8_t) ~0 }; pod::Vector2f st{}; pod::Vector3f normal{}; + pod::Vector id{}; static UF_API uf::stl::vector descriptor; }; @@ -19,6 +20,7 @@ namespace uf { pod::Vector3f tangent{}; pod::Vector joints{}; pod::Vector4f weights{}; + pod::Vector id{}; static UF_API uf::stl::vector descriptor; }; diff --git a/engine/inc/uf/ext/meshopt/meshopt.h b/engine/inc/uf/ext/meshopt/meshopt.h index a8b6f098..e82810eb 100644 --- a/engine/inc/uf/ext/meshopt/meshopt.h +++ b/engine/inc/uf/ext/meshopt/meshopt.h @@ -6,6 +6,6 @@ namespace ext { namespace meshopt { - void UF_API optimize( uf::Mesh&, size_t = SIZE_MAX ); + bool UF_API optimize( uf::Mesh&, float simplify = 1.0f, size_t = SIZE_MAX ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/mesh/grid.h b/engine/inc/uf/utils/mesh/grid.h index 99c64c56..5c84470c 100644 --- a/engine/inc/uf/utils/mesh/grid.h +++ b/engine/inc/uf/utils/mesh/grid.h @@ -87,16 +87,22 @@ namespace uf { if ( mlet.indices.empty() ) continue; auto& meshlet = meshlets[mlet.primitive.instance.primitiveID]; + size_t primitiveID = partitioned.size(); auto& slice = partitioned.emplace_back(); slice.vertices.reserve( mlet.indices.size() ); slice.indices.reserve( mlet.indices.size() ); for ( auto idx : mlet.indices ) { - slice.vertices.emplace_back( meshlet.vertices[idx] ); - slice.indices.emplace_back( slice.indices.size() ); + auto& vertex = slice.vertices.emplace_back( meshlet.vertices[idx] ); + auto& index = slice.indices.emplace_back( slice.indices.size() ); + + 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 = partitioned.size() - 1; + 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.effectiveExtents.min; diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index 8ff6d539..120f765e 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -359,8 +359,10 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { #endif asset = uf::graph::load( filename, metadata[payload.filename] ); uf::graph::process( asset ); + #if !UF_ENV_DREAMCAST if ( asset.metadata["debug"]["print stats"].as() ) UF_MSG_INFO(uf::graph::stats( asset ).dump(1,'\t')); if ( asset.metadata["debug"]["print tree"].as() ) UF_MSG_INFO(uf::graph::print( asset )); + #endif if ( !asset.metadata["debug"]["no cleanup"].as() ) uf::graph::cleanup( asset ); } break; default: { diff --git a/engine/src/engine/graph/convert.cpp b/engine/src/engine/graph/convert.cpp index 359c7324..517d7f8b 100644 --- a/engine/src/engine/graph/convert.cpp +++ b/engine/src/engine/graph/convert.cpp @@ -121,47 +121,111 @@ pod::Graph& UF_API uf::graph::convert( uf::Object& object, bool process ) { for ( auto index : graph.root.children ) uf::graph::process( graph, index, *graph.root.entity ); } + // remap textures->images IDs + for ( auto& name : graph.textures ) { + auto& texture = uf::graph::storage.textures[name]; + auto& keys = uf::graph::storage.images.keys; + auto& indices = uf::graph::storage.images.indices; + + if ( !(0 <= texture.index && texture.index < graph.images.size()) ) continue; + + auto& needle = graph.images[texture.index]; + #if 1 + texture.index = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + texture.index = i; + break; + } + #else + auto it = std::find( keys.begin(), keys.end(), needle ); + UF_ASSERT( it != keys.end() ); + texture.index = it - keys.begin(); + #endif + } // remap materials->texture IDs for ( auto& name : graph.materials ) { auto& material = uf::graph::storage.materials[name]; auto& keys = uf::graph::storage.textures.keys; + auto& indices = uf::graph::storage.textures.indices; int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness }; for ( auto* pointer : IDs ) { auto& ID = *pointer; - if ( !(0 <= ID && ID < graph.materials.size()) ) continue; - auto it = std::find( keys.begin(), keys.end(), graph.textures[ID] ); + if ( !(0 <= ID && ID < graph.textures.size()) ) continue; + auto& needle = graph.textures[ID]; + #if 1 + ID = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + ID = i; + break; + } + #else + if ( !(0 <= ID && ID < graph.textures.size()) ) continue; + auto it = std::find( keys.begin(), keys.end(), needle ); UF_ASSERT( it != keys.end() ); ID = it - keys.begin(); + #endif } } - // remap textures->images IDs -/* - for ( auto& name : graph.textures ) { - auto& texture = uf::graph::storage.textures[name]; - auto& keys = uf::graph::storage.images.keys; - - if ( !(0 <= texture.index && texture.index < graph.textures.size()) ) continue; - auto it = std::find( keys.begin(), keys.end(), graph.images[texture.index] ); - UF_ASSERT( it != keys.end() ); - texture.index = it - keys.begin(); - } -*/ // remap instance variables for ( auto& name : graph.instances ) { auto& instance = uf::graph::storage.instances[name]; if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) { auto& keys = /*graph.storage*/uf::graph::storage.materials.keys; - auto it = std::find( keys.begin(), keys.end(), graph.materials[instance.materialID] ); + auto& indices = /*graph.storage*/uf::graph::storage.materials.indices; + + if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue; + + auto& needle = graph.materials[instance.materialID]; + #if 1 + instance.materialID = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + instance.materialID = i; + break; + } + #else + auto it = std::find( keys.begin(), keys.end(), needle ); UF_ASSERT( it != keys.end() ); instance.materialID = it - keys.begin(); + #endif } + if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) { + auto& keys = /*graph.storage*/uf::graph::storage.textures.keys; + auto& indices = /*graph.storage*/uf::graph::storage.textures.indices; + + if ( !(0 <= instance.lightmapID && instance.lightmapID < graph.textures.size()) ) continue; + + auto& needle = graph.textures[instance.lightmapID]; + #if 1 + instance.lightmapID = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + instance.lightmapID = i; + break; + } + #else + auto it = std::find( keys.begin(), keys.end(), needle ); + UF_ASSERT( it != keys.end() ); + instance.lightmapID = it - keys.begin(); + #endif + } + #if 0 + // i genuinely dont remember what this is used for + if ( 0 <= instance.imageID && instance.imageID < graph.images.size() ) { auto& keys = /*graph.storage*/uf::graph::storage.images.keys; auto it = std::find( keys.begin(), keys.end(), graph.images[instance.imageID] ); UF_ASSERT( it != keys.end() ); instance.imageID = it - keys.begin(); } + #endif // remap a skinID as an actual jointID if ( 0 <= instance.jointID && instance.jointID < graph.skins.size() ) { auto& name = graph.skins[instance.jointID]; @@ -172,12 +236,6 @@ pod::Graph& UF_API uf::graph::convert( uf::Object& object, bool process ) { instance.jointID += joints.size(); } } - if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) { - auto& keys = /*graph.storage*/uf::graph::storage.textures.keys; - auto it = std::find( keys.begin(), keys.end(), graph.textures[instance.lightmapID] ); - UF_ASSERT( it != keys.end() ); - instance.lightmapID = it - keys.begin(); - } } uf::graph::reload(); diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index c868bd75..07ed3a0a 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -225,16 +225,36 @@ namespace { }); // remove extraneous buffers - #if UF_USE_OPENGL - /* - for ( auto& attribute : mesh.vertex.attributes ) { - if ( attribute.descriptor.name == "position" ) continue; - if ( attribute.descriptor.name == "color" ) continue; - if ( attribute.descriptor.name == "uv" ) continue; - if ( attribute.descriptor.name == "st" ) continue; + if ( !mesh.isInterleaved() ) { + uf::stl::vector remove; remove.reserve(mesh.vertex.attributes.size()); + + for ( size_t i = 0; i < mesh.vertex.attributes.size(); ++i ) { + auto& attribute = mesh.vertex.attributes[i]; + if ( attribute.descriptor.name == "position" ) continue; + if ( attribute.descriptor.name == "color" ) continue; + if ( attribute.descriptor.name == "uv" ) continue; + if ( attribute.descriptor.name == "st" ) continue; + + if ( graph.metadata["flags"]["SKINNED"].as() ) { + if ( attribute.descriptor.name == "tangent" ) continue; + if ( attribute.descriptor.name == "joints" ) continue; + if ( attribute.descriptor.name == "weights" ) continue; + } + #if !UF_USE_OPENGL + if ( attribute.descriptor.name == "normal" ) continue; + #endif + + remove.insert(remove.begin(), i); + } + for ( auto& i : remove ) { + // UF_MSG_DEBUG("Removing " << mesh.vertex.attributes[i].descriptor.name); + 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 not interleaved, ignoring..."); } - */ - #endif mesh.updateDescriptor(); diff --git a/engine/src/engine/graph/encode.cpp b/engine/src/engine/graph/encode.cpp index 394c85f7..d6459fb9 100644 --- a/engine/src/engine/graph/encode.cpp +++ b/engine/src/engine/graph/encode.cpp @@ -9,12 +9,7 @@ #include #include -#if UF_ENV_DREAMCAST - #define UF_GRAPH_LOAD_MULTITHREAD 0 -#else - #define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM -#endif - +#if !UF_ENV_DREAMCAST namespace { struct EncodingSettings : public ext::json::EncodingSettings { bool combined = false; @@ -23,7 +18,7 @@ namespace { uf::stl::string filename = ""; }; - uf::Serializer encode( const uf::Image& image, const EncodingSettings& settings ) { + uf::Serializer encode( const uf::Image& image, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["size"] = uf::vector::encode( image.getDimensions() ); json["bpp"] = image.getBpp() / image.getChannels(); @@ -31,7 +26,7 @@ namespace { json["data"] = uf::base64::encode( image.getPixels() ); return json; } - uf::Serializer encode( const pod::Texture& texture, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Texture& texture, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["index"] = texture.index; json["sampler"] = texture.sampler; @@ -40,7 +35,7 @@ namespace { json["lerp"] = uf::vector::encode( texture.lerp, settings ); return json; } - uf::Serializer encode( const uf::renderer::Sampler& sampler, const EncodingSettings& settings ) { + uf::Serializer encode( const uf::renderer::Sampler& sampler, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["min"] = sampler.descriptor.filter.min; json["mag"] = sampler.descriptor.filter.mag; @@ -48,7 +43,7 @@ namespace { json["v"] = sampler.descriptor.addressMode.v; return json; } - uf::Serializer encode( const pod::Material& material, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Material& material, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["base"] = uf::vector::encode( material.colorBase, settings ); json["emissive"] = uf::vector::encode( material.colorEmissive, settings ); @@ -64,14 +59,14 @@ namespace { json["modeAlpha"] = material.modeAlpha; return json; } - uf::Serializer encode( const pod::Light& light, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Light& light, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["color"] = uf::vector::encode( light.color, settings ); json["intensity"] = light.intensity; json["range"] = light.range; return json; } - uf::Serializer encode( const pod::Animation& animation, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Animation& animation, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["name"] = animation.name; json["start"] = animation.start; @@ -99,7 +94,7 @@ namespace { } return json; } - uf::Serializer encode( const pod::Skin& skin, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Skin& skin, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["name"] = skin.name; @@ -111,7 +106,7 @@ namespace { json["inverseBindMatrices"].emplace_back( uf::matrix::encode(inverseBindMatrix, settings) ); return json; } - uf::Serializer encode( const pod::Instance& instance, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Instance& instance, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["model"] = uf::matrix::encode( instance.model, settings ); json["color"] = uf::vector::encode( instance.color, settings ); @@ -126,7 +121,7 @@ namespace { return json; } - uf::Serializer encode( const pod::DrawCommand& drawCommand, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::DrawCommand& drawCommand, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["indices"] = drawCommand.indices; json["instances"] = drawCommand.instances; @@ -138,34 +133,48 @@ namespace { json["vertices"] = drawCommand.vertices; return json; } - uf::Serializer encode( const pod::Primitive& primitive, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Primitive& primitive, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; - json["drawCommand"] = encode( primitive.drawCommand, settings ); - json["instance"] = encode( primitive.instance, settings ); + json["drawCommand"] = encode( primitive.drawCommand, settings, graph ); + json["instance"] = encode( primitive.instance, settings, graph ); return json; } - uf::Serializer encode( const uf::Mesh& mesh, const EncodingSettings& settings ) { + uf::Serializer encode( const uf::Mesh& mesh, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; + #if 0 + uf::Mesh mesh = mesh; + // remove extraneous buffers + if ( !mesh.isInterleaved() ) { + uf::stl::vector remove; remove.reserve(mesh.vertex.attributes.size()); - /* - struct Attribute { - ext::RENDERER::AttributeDescriptor descriptor; - int32_t buffer = -1; - size_t offset = 0; + for ( size_t i = 0; i < mesh.vertex.attributes.size(); ++i ) { + auto& attribute = mesh.vertex.attributes[i]; + if ( attribute.descriptor.name == "position" ) continue; + if ( attribute.descriptor.name == "color" ) continue; + if ( attribute.descriptor.name == "uv" ) continue; + if ( attribute.descriptor.name == "st" ) continue; - size_t stride = 0; - size_t length = 0; - void* pointer = NULL; - }; - struct Input { - uf::stl::vector attributes; - size_t count = 0; // how many elements is the input using - size_t first = 0; // base index to start from - size_t size = 0; // size of one element in the input's buffer - size_t offset = 0; // bytes to offset from within the associated buffer - int32_t interleaved = -1; // index to interleaved buffer if in bounds - } vertex, index, instance, indirect; - */ + if ( graph.metadata["flags"]["SKINNED"].as() ) { + if ( attribute.descriptor.name == "tangent" ) continue; + if ( attribute.descriptor.name == "joints" ) continue; + if ( attribute.descriptor.name == "weights" ) continue; + } + #if !UF_USE_OPENGL + if ( attribute.descriptor.name == "normal" ) continue; + #endif + + remove.insert(remove.begin(), i); + } + for ( auto& i : remove ) { + // UF_MSG_DEBUG("Removing " << mesh.vertex.attributes[i].descriptor.name); + 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 not interleaved, ignoring..."); + } + #endif #define SERIALIZE_MESH(N) {\ auto& input = json["inputs"][#N];\ @@ -203,7 +212,7 @@ namespace { } return json; } - uf::Serializer encode( const pod::Node& node, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::Node& node, const EncodingSettings& settings, const pod::Graph& graph ) { uf::Serializer json; json["name"] = node.name; json["index"] = node.index; @@ -239,7 +248,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& }; if ( settings.encoding == "auto" ) settings.encoding = ext::json::PREFERRED_ENCODING; - if ( settings.compression == "auto" ) settings.compression = ext::json::PREFERRED_COMPRESSION; + if ( settings.compression == "auto" ) settings.compression = ext::json::PREFERRED_COMPRESSION; if ( !settings.combined ) uf::io::mkdir(directory); #if UF_USE_XATLAS @@ -258,7 +267,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& for ( size_t i = 0; i < graph.instances.size(); ++i ) { auto& name = graph.instances[i]; auto& instance = /*graph.storage*/uf::graph::storage.instances.map.at(name); - uf::Serializer json = encode( instance, settings ); + uf::Serializer json = encode( instance, settings, graph ); json["name"] = name; serializer["instances"].emplace_back( json ); } @@ -272,7 +281,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& json["name"] = name; // ext::json::reserve( json["primitives"], primitives.size() ); for ( auto& primitive : primitives ) { - json["primitives"].emplace_back( encode( primitive, settings ) ); + json["primitives"].emplace_back( encode( primitive, settings, graph ) ); } } }); @@ -285,7 +294,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& json["name"] = name; // ext::json::reserve( json["drawCommands"], drawCommands.size() ); for ( auto& drawCommand : drawCommands ) { - json["drawCommands"].emplace_back( encode( drawCommand, settings ) ); + json["drawCommands"].emplace_back( encode( drawCommand, settings, graph ) ); } } }); @@ -299,14 +308,14 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& auto& mesh = /*graph.storage*/uf::graph::storage.meshes.map.at(name); if ( !s.encodeBuffers ) { s.filename = directory+"/mesh."+std::to_string(i)+".json"; - encode(mesh, s).writeToFile(s.filename); + encode(mesh, s, graph).writeToFile(s.filename); uf::Serializer json; json["name"] = name; json["filename"] = uf::io::filename(s.filename); serializer["meshes"].emplace_back( json ); } else { s.filename = directory+"/mesh."+std::to_string(i); - auto json = encode(mesh, s); + auto json = encode(mesh, s, graph); json["name"] = name; serializer["meshes"].emplace_back(json); } @@ -314,7 +323,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } else { for ( auto& name : graph.meshes ) { auto& mesh = /*graph.storage*/uf::graph::storage.meshes.map.at(name); - auto json = encode(mesh, settings); + auto json = encode(mesh, settings, graph); json["name"] = name; serializer["meshes"].emplace_back(json); } @@ -330,7 +339,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& image.save(directory + "/atlas.png"); serializer["atlas"] = "atlas.png"; } else { - serializer["atlas"] = encode(image, settings); + serializer["atlas"] = encode(image, settings, graph); } } }); @@ -352,7 +361,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*/uf::graph::storage.images.map.at(name); - auto json = encode(image, settings); + auto json = encode(image, settings, graph); json["name"] = name; serializer["images"].emplace_back( json ); } @@ -363,7 +372,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& ext::json::reserve( serializer["textures"], graph.textures.size() ); for ( auto& name : graph.textures ) { auto& texture = /*graph.storage*/uf::graph::storage.textures.map.at(name); - auto json = encode(texture, settings); + auto json = encode(texture, settings, graph); json["name"] = name; serializer["textures"].emplace_back(json); } @@ -373,7 +382,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& ext::json::reserve( serializer["samplers"], graph.samplers.size() ); for ( auto& name : graph.samplers ) { auto& sampler = /*graph.storage*/uf::graph::storage.samplers.map.at(name); - auto json = encode(sampler, settings); + auto json = encode(sampler, settings, graph); json["name"] = name; serializer["samplers"].emplace_back(json); } @@ -383,7 +392,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& ext::json::reserve( serializer["materials"], graph.materials.size() ); for ( auto& name : graph.materials ) { auto& material = /*graph.storage*/uf::graph::storage.materials.map.at(name); - auto json = encode(material, settings); + auto json = encode(material, settings, graph); json["name"] = name; serializer["materials"].emplace_back(json); } @@ -394,7 +403,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& for ( auto pair : graph.lights ) { auto& name = pair.first; auto& light = pair.second; - auto json = encode(light, settings); + auto json = encode(light, settings, graph); json["name"] = name; serializer["lights"].emplace_back(json); } @@ -407,13 +416,13 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& auto& name = graph.animations[i]; uf::stl::string f = "animation."+std::to_string(i)+".json"; auto& animation = /*graph.storage*/uf::graph::storage.animations.map.at(name); - encode(animation, settings).writeToFile(directory+"/"+f); + encode(animation, settings, graph).writeToFile(directory+"/"+f); serializer["animations"].emplace_back(f); } } else { for ( auto& name : graph.animations ) { auto& animation = /*graph.storage*/uf::graph::storage.animations.map.at(name); - serializer["animations"][name] = encode(animation, settings); + serializer["animations"][name] = encode(animation, settings, graph); } } }); @@ -422,14 +431,14 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& ext::json::reserve( serializer["skins"], graph.skins.size() ); for ( auto& name : graph.skins ) { auto& skin = /*graph.storage*/uf::graph::storage.skins.map.at(name); - serializer["skins"].emplace_back( encode(skin, settings) ); + serializer["skins"].emplace_back( encode(skin, settings, graph) ); } }); jobs.emplace_back([&]{ // store node information ext::json::reserve( serializer["nodes"], graph.nodes.size() ); - for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, settings) ); - serializer["root"] = encode(graph.root, settings); + for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, settings, graph) ); + serializer["root"] = encode(graph.root, settings, graph); }); #if UF_GRAPH_LOAD_MULTITHREAD if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); @@ -551,4 +560,5 @@ uf::Serializer uf::graph::stats( const pod::Graph& graph ) { */ #endif return json; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 50afad07..eb730ea8 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -22,6 +22,7 @@ UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Base, UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R8G8B8A8_UNORM, color) UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, st) UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R16G16_UINT, id) ); UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned, UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, position) @@ -32,6 +33,7 @@ UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned, UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, tangent) UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16B16A16_UINT, joints) UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32A32_SFLOAT, weights) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16_UINT, id) ); pod::Matrix4f uf::graph::local( pod::Graph& graph, int32_t index ) { diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index ffcd19c0..2ea3fdce 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -19,6 +19,10 @@ #include #include + +#if UF_USE_MESHOPT + #include +#endif #if UF_USE_XATLAS #include #endif @@ -282,7 +286,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print); meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup); } - if ( graph.metadata["flags"]["SKINNED"].as() ) { #define UF_GRAPH_MESH_FORMAT uf::graph::mesh::Skinned, uint32_t @@ -298,75 +301,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize #undef UF_GRAPH_PROCESS_PRIMITIVES_FULL #undef UF_GRAPH_MESH_FORMAT } - - #if 0 - if ( m.name == "worldspawn_20" ) { - uf::stl::vector<::Primitive<>> objs; - - #include "processPrimitives2.inl" - - graph.primitives.emplace_back(keyName); - graph.drawCommands.emplace_back(keyName); - - auto& drawCommands = /*graph.storage*/uf::graph::storage.drawCommands[keyName]; - auto& primitives = /*graph.storage*/uf::graph::storage.primitives[keyName]; - auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName]; - - mesh.bindIndirect(); - mesh.bind(); - - size_t indexID = 0; - size_t vertexID = 0; - for ( auto& obj : objs ) { - drawCommands.emplace_back(pod::DrawCommand{ - .indices = obj.indices.size(), - .instances = 1, - .indexID = indexID, - .vertexID = vertexID, - .instanceID = 0, - - - .vertices = obj.vertices.size(), - }); - - primitives.emplace_back( obj.primitive ); - - indexID += obj.indices.size(); - vertexID += obj.vertices.size(); - - mesh.insertVertices(obj.vertices); - mesh.insertIndices(obj.indices); - } - - mesh.insertIndirects(drawCommands); - mesh.updateDescriptor(); - } else { - graph.primitives.emplace_back(keyName); - graph.drawCommands.emplace_back(keyName); - - auto& drawCommands = /*graph.storage*/uf::graph::storage.drawCommands[keyName]; - auto& primitives = /*graph.storage*/uf::graph::storage.primitives[keyName]; - auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName]; - - mesh.bindIndirect(); - - if ( graph.metadata["flags"]["SKINNED"].as() ) { - mesh.bind(); - uf::stl::vector vertices; - uf::stl::vector indices; - #define UF_GRAPH_PROCESS_PRIMITIVES_FULL 1 - #include "processPrimitives.inl" - #undef UF_GRAPH_PROCESS_PRIMITIVES_FULL - } else { - mesh.bind(); - uf::stl::vector vertices; - uf::stl::vector indices; - #include "processPrimitives.inl" - } - mesh.insertIndirects(drawCommands); - mesh.updateDescriptor(); - } - #endif } } // load skins @@ -530,14 +464,50 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize texture.index = atlasImageIndex; } } - // generate STs #if UF_USE_XATLAS - if ( graph.metadata["exporter"]["unwrap"].as() ) { + // generate STs + if ( graph.metadata["exporter"]["unwrap"].as(true) ) { UF_MSG_DEBUG( "Generating ST's..." ); size_t atlases = ext::xatlas::unwrap( graph ); UF_MSG_DEBUG( "Generated ST's for " << atlases << " lightmaps" ); } #endif +#if UF_USE_MESHOPT + // cleanup if blender's exporter is poopy + if ( graph.metadata["exporter"]["optimize"].as(true) || graph.metadata["exporter"]["optimize"].as("") == "tagged" ) { + UF_MSG_DEBUG( "Optimizing meshes..." ); + for ( auto& keyName : graph.meshes ) { + size_t level = SIZE_MAX; + float simplify = 1.0f; + + if ( graph.metadata["exporter"]["optimize"].as("") == "tagged" ) { + bool should = false; + + ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) { + if ( ext::json::isNull( value["optimize mesh"] ) ) return; + if ( uf::string::isRegex( key ) ) { + if ( !uf::string::matched( keyName, key ) ) return; + } else if ( keyName != key ) return; + should = true; + if ( ext::json::isObject( value["optimize mesh"] ) ) { + level = value["optimize mesh"]["level"].as(level); + simplify = value["optimize mesh"]["simplify"].as(simplify); + } + }); + + if ( !should ) continue; + } + + auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName]; + UF_MSG_DEBUG("Optimizing mesh at level " << level << ": " << keyName); + if ( !ext::meshopt::optimize( mesh, simplify, level ) ) { + UF_MSG_ERROR("Mesh optimization failed: " << keyName ); + } + } + + UF_MSG_DEBUG( "Optimized mesh" ); + } +#endif if ( graph.metadata["exporter"]["enabled"].as() ) { graph.name = uf::graph::save( graph, filename ); diff --git a/engine/src/ext/gltf/processPrimitives2.inl b/engine/src/ext/gltf/processPrimitives2.inl index 0d1acd7b..aedc4935 100644 --- a/engine/src/ext/gltf/processPrimitives2.inl +++ b/engine/src/ext/gltf/processPrimitives2.inl @@ -1,6 +1,7 @@ uf::stl::vector> meshlets; for ( auto& p : m.primitives ) { + size_t primitiveID = meshlets.size(); auto& meshlet = meshlets.emplace_back(); struct Attribute { @@ -123,6 +124,9 @@ for ( auto& p : m.primitives ) { vertex.tangent.x = -vertex.tangent.x; #endif } + + vertex.id.x = primitiveID; + vertex.id.y = meshID; } if ( p.indices > -1 ) { @@ -155,10 +159,8 @@ for ( auto& p : m.primitives ) { #undef COPY_INDICES } - - meshlet.primitive.instance.materialID = p.material; - meshlet.primitive.instance.primitiveID = meshlets.size() - 1; + meshlet.primitive.instance.primitiveID = primitiveID; meshlet.primitive.instance.meshID = meshID; meshlet.primitive.instance.objectID = 0; diff --git a/engine/src/ext/meshopt/meshopt.cpp b/engine/src/ext/meshopt/meshopt.cpp index 4c069725..36f3dca8 100644 --- a/engine/src/ext/meshopt/meshopt.cpp +++ b/engine/src/ext/meshopt/meshopt.cpp @@ -1,126 +1,164 @@ #include -#if UF_USE_MESHOPTIMIZER - #include -#endif +#if UF_USE_MESHOPT +#include -void ext::meshopt::optimize( uf::Mesh& mesh, size_t o ) { -#if 0 +bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o ) { + if ( mesh.isInterleaved() ) { + UF_MSG_ERROR("optimization of interleaved meshes is currently not supported"); + return false; + } mesh.updateDescriptor(); - void* vertices = NULL; - void* indices = NULL; - size_t verticesCount = mesh.attributes.vertex.length; - size_t indicesCount = mesh.attributes.index.length; + struct Remap { + uf::Mesh::Attribute attribute; + uf::stl::vector buffer; + }; - if ( !indicesCount ) mesh.generateIndices(); - if ( o == 0 ) { - if ( !indicesCount ) { - mesh.resizeIndices(verticesCount); - switch ( mesh.attributes.index.size ) { - case sizeof(uint32_t): - for ( size_t i = 0; i < verticesCount; ++i ) ((uint32_t*) mesh.attributes.index.pointer)[i] = i; - break; - case sizeof(uint16_t): - for ( size_t i = 0; i < verticesCount; ++i ) ((uint16_t*) mesh.attributes.index.pointer)[i] = i; - break; - case sizeof(uint8_t): - for ( size_t i = 0; i < verticesCount; ++i ) ((uint8_t*) mesh.attributes.index.pointer)[i] = i; - break; + uf::stl::vector attributes; + uf::stl::vector streams; + for ( auto& attribute : mesh.vertex.attributes ) { + auto& p = attributes.emplace_back(); + p.attribute = attribute; + + auto& stream = streams.emplace_back(); + stream.data = p.attribute.pointer; + stream.size = p.attribute.descriptor.size; + stream.stride = p.attribute.stride; + } + + size_t indicesCount = mesh.vertex.count; + uf::stl::vector remap(indicesCount); + + size_t verticesCount = meshopt_generateVertexRemapMulti( &remap[0], NULL, indicesCount, indicesCount, &streams[0], streams.size() ); + + // generate new indices, as they're going to be specific to a region of vertices due to drawcommand shittery + uf::stl::vector indices(indicesCount); + meshopt_remapIndexBuffer(&indices[0], NULL, indicesCount, &remap[0]); + + // + for ( auto& p : attributes ) { + auto& buffer = p.buffer; + buffer.resize(verticesCount * p.attribute.descriptor.size); + + meshopt_remapVertexBuffer(&buffer[0], p.attribute.pointer, indicesCount, p.attribute.descriptor.size, &remap[0]); + } + // + meshopt_optimizeVertexCache(&indices[0], &indices[0], indicesCount, verticesCount); + // + meshopt_optimizeVertexFetchRemap(&remap[0], &indices[0], indicesCount, verticesCount); + // + for ( auto& p : attributes ) { + auto& buffer = p.buffer; + p.attribute.pointer = &buffer[0]; + + meshopt_remapVertexBuffer(p.attribute.pointer, p.attribute.pointer, verticesCount, p.attribute.descriptor.size, &remap[0]); + } + // almost always causes ID discontinuities + if ( 0.0f < simplify && simplify < 1.0f ) { + uf::stl::vector indicesSimplified(indicesCount); + + uf::Mesh::Attribute positionAttribute; + for ( auto& p : attributes ) if ( p.attribute.descriptor.name == "position" ) positionAttribute = p.attribute; + + size_t targetIndices = indicesCount * simplify; + float targetError = 1e-2f / simplify; + + float realError = 0.0f; + // size_t realIndices = meshopt_simplify(&indicesSimplified[0], &indices[0], indicesCount, (float*) positionAttribute.pointer, verticesCount, positionAttribute.stride, targetError, realError); + size_t realIndices = meshopt_simplifySloppy(&indicesSimplified[0], &indices[0], indicesCount, (float*) positionAttribute.pointer, verticesCount, positionAttribute.stride, targetIndices); + + UF_MSG_DEBUG("[Simplified] indices: " << indicesCount << " -> " << realIndices << " | error: " << targetError << " -> " << realError); + + indicesCount = realIndices; + indices.swap( indicesSimplified ); + } + // done + if ( mesh.indirect.count ) { + bool discontinuityDetected = false; + size_t lastID = 0; + struct Remap { + pod::DrawCommand* drawCommand; + struct { + size_t start = SIZE_MAX; + size_t end = 0; + } index, vertex; + }; + + pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data(); + uf::stl::vector remappedDrawCommands( mesh.indirect.count ); + + uf::Mesh::Attribute idAttribute; + for ( auto& p : attributes ) if ( p.attribute.descriptor.name == "id" ) idAttribute = p.attribute; + for ( size_t index = 0; index < indicesCount; ++index ) { + size_t vertex = indices[index]; + pod::Vector& id = *(pod::Vector*) ( static_cast(idAttribute.pointer) + idAttribute.stride * vertex ); + + auto& d = remappedDrawCommands[id.x]; + d.drawCommand = &drawCommands[id.x]; + d.vertex.start = std::min( d.vertex.start, vertex ); + d.vertex.end = std::max( d.vertex.end, vertex ); + + d.index.start = std::min( d.index.start, index ); + d.index.end = std::max( d.index.end, index ); + + if ( lastID == id.x ) { + + } else if ( lastID + 1 == id.x ) { + lastID = id.x; + } else { + UF_MSG_DEBUG("Discontinuity detected: " << index << " | " << vertex << " | " << lastID << " | " << id.x); + discontinuityDetected = true; + lastID = id.x; } } - return; + + if ( discontinuityDetected ) { + UF_MSG_ERROR("Discontinuity detected, bailing..."); + return false; + } + + for ( auto& d : remappedDrawCommands ) { + d.drawCommand->indices = d.index.end - d.index.start + 1; + d.drawCommand->indexID = d.index.start; + d.drawCommand->vertexID = d.vertex.start; + d.drawCommand->vertices = d.vertex.end - d.vertex.start + 1; + } + + for ( size_t index = 0; index < indicesCount; ++index ) { + auto& vertex = indices[index]; + pod::Vector& id = *(pod::Vector*) ( static_cast(idAttribute.pointer) + idAttribute.stride * vertex ); + + auto& d = remappedDrawCommands[id.x]; + vertex -= d.vertex.start; + } } + + mesh.index.count = indicesCount; + mesh.vertex.count = verticesCount; + + // vertices + for ( size_t i = 0; i < attributes.size(); ++i ) { + auto& attribute = mesh.vertex.attributes[i]; + auto& remapped = attributes[i]; + + mesh.buffers[attribute.buffer].swap( remapped.buffer ); + attribute.pointer = mesh.buffers[attribute.buffer].data(); + } + + // indices { - vertices = malloc(verticesCount * mesh.attributes.vertex.size); - memcpy( vertices, mesh.attributes.vertex.pointer, verticesCount ); - } - if ( indicesCount > 0 ) { - indices = malloc(indicesCount); - memcpy( indices, mesh.attributes.index.pointer, indicesCount ); + mesh.resizeIndices( mesh.index.count ); + uint8_t* pointer = (uint8_t*) mesh.getBuffer(mesh.index).data(); + for ( auto index = 0; index < indicesCount; ++index ) { + switch ( mesh.index.size ) { + case 1: (( uint8_t*) pointer)[index] = indices[index]; break; + case 2: ((uint16_t*) pointer)[index] = indices[index]; break; + case 4: ((uint32_t*) pointer)[index] = indices[index]; break; + } + } } - uf::stl::vector remap(verticesCount); - verticesCount = meshopt_generateVertexRemap(&remap[0], (uint32_t*) indices, indicesCount ? indicesCount : verticesCount, (float*) vertices, verticesCount, mesh.attributes.vertex.size); - - mesh.resizeIndices(indicesCount); - mesh.resizeVertices(verticesCount); - - meshopt_remapIndexBuffer((uint32_t*) mesh.attributes.index.pointer, (uint32_t*) indices, indicesCount, &remap[0]); - meshopt_remapVertexBuffer(mesh.attributes.vertex.pointer, (float*) vertices, verticesCount, mesh.attributes.vertex.size, &remap[0]); - - if ( vertices ) free(vertices); - if ( indices ) free(indices); -#endif -#if 0 - auto vertices = std::move( this->vertices ); - size_t valueCount = vertices.size(); - - uf::stl::vector remap(valueCount); - size_t verticesCount = meshopt_generateVertexRemap(&remap[0], NULL, valueCount, &vertices[0], valueCount, sizeof(T)); - - this->indices.resize(valueCount); - meshopt_remapIndexBuffer(&this->indices[0], NULL, valueCount, &remap[0]); - //meshopt_remapIndexBuffer(&this->indices[0], (const U*) NULL, indices, &remap[0]); - this->vertices.resize(verticesCount); - meshopt_remapVertexBuffer(&this->vertices[0], &vertices[0], valueCount, sizeof(T), &remap[0]); - - size_t verticesCount = this->vertices.size(); - size_t indicesCount = this->indices.size(); - if ( indicesCount == 0 ) indicesCount = verticesCount; - - auto vertices = std::move( this->vertices ); - auto indices = std::move( this->indices ); - - uf::stl::vector remap(indicesCount); - verticesCount = meshopt_generateVertexRemap(&remap[0], &indices[0], indicesCount, &vertices[0], verticesCount, sizeof(T)); - - this->indices.resize(indicesCount); - this->vertices.resize(verticesCount); - - meshopt_remapIndexBuffer(&this->indices[0], &indices[0], indicesCount, &remap[0]); - meshopt_remapVertexBuffer(&this->vertices[0], &vertices[0], verticesCount, sizeof(T), &remap[0]); -#endif -#if 0 - // optimize for cache - if ( o >= 2 ) { - meshopt_optimizeVertexCache(mesh.attributes.index.pointer, mesh.attributes.index.pointer, mesh.attributes.index.length, mesh.attributes.vertex.length); - } - // optimize for overdraw - if ( o >= 3 ) { - const float kOverdrawThreshold = 3.f; - meshopt_optimizeOverdraw(mesh.attributes.index.pointer, mesh.attributes.index.pointer, mesh.attributes.index.length, (float*) mesh.attributes.vertex.pointer.position, mesh.attributes.vertex.length, sizeof(T), kOverdrawThreshold); - } - // optimize for fetch - if ( o >= 4 ) { - meshopt_optimizeVertexFetch(mesh.attributes.vertex.pointer, mesh.attributes.index.pointer, mesh.attributes.index.length, mesh.attributes.vertex.pointer, mesh.attributes.vertex.length, mesh.attributes.vertex.size); - } -#endif + mesh.updateDescriptor(); + return true; } - - -/* -auto vertices = std::move( this->vertices ); -U indices = vertices.size(); - -uf::stl::vector remap(indices); -size_t verticesCount = meshopt_generateVertexRemap(&remap[0], NULL, indices, &vertices[0], indices, sizeof(T)); - -this->indices.resize(indices); -//meshopt_remapIndexBuffer(&this->indices[0], NULL, indices, &remap[0]); -meshopt_remapIndexBuffer(&this->indices[0], (const U*) NULL, indices, &remap[0]); -this->vertices.resize(verticesCount); -meshopt_remapVertexBuffer(&this->vertices[0], &vertices[0], indices, sizeof(T), &remap[0]); -// optimize for cache -if ( o >= 1 ) { - meshopt_optimizeVertexCache(&this->indices[0], &this->indices[0], this->indices.size(), this->vertices.size()); -} -// optimize for overdraw -if ( o >= 2 ) { - const float kOverdrawThreshold = 3.f; - meshopt_optimizeOverdraw(&this->indices[0], &this->indices[0], this->indices.size(), (float*) &this->vertices[0].position, this->vertices.size(), sizeof(T), kOverdrawThreshold); -} -// optimize for fetch -if ( o >= 3 ) { - meshopt_optimizeVertexFetch(&this->vertices[0], &this->indices[0], this->indices.size(), &this->vertices[0], this->vertices.size(), sizeof(T)); -} -*/ \ No newline at end of file +#endif \ No newline at end of file diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index 9886411d..137253cc 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -232,11 +232,21 @@ namespace { void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::InfoDraw& drawInfo ) { pod::Matrix4f modelView = uf::matrix::identity(), projection = uf::matrix::identity(); + if ( drawInfo.matrices.model && drawInfo.matrices.view ) modelView = uf::matrix::multiply( *drawInfo.matrices.view, *drawInfo.matrices.model ); else if ( drawInfo.matrices.model ) modelView = *drawInfo.matrices.model; else if ( drawInfo.matrices.view ) modelView = *drawInfo.matrices.view; + if ( drawInfo.matrices.projection ) projection = *drawInfo.matrices.projection; +#if 0 + { + if ( drawInfo.matrices.model ) UF_MSG_DEBUG( "model: " << drawInfo.matrices.model << " " << uf::matrix::toString( *drawInfo.matrices.model ) ); + if ( drawInfo.matrices.view ) UF_MSG_DEBUG( "view: " << drawInfo.matrices.view << " " << uf::matrix::toString( *drawInfo.matrices.view ) ); + if ( drawInfo.matrices.projection ) UF_MSG_DEBUG( "projection: " << drawInfo.matrices.projection << " " << uf::matrix::toString( *drawInfo.matrices.projection ) ); + } +#endif + if ( drawInfo.attributes.indirect.pointer && drawInfo.attributes.indirect.length == sizeof(pod::DrawCommand) ) { pod::DrawCommand& drawCommand = *(pod::DrawCommand*) drawInfo.attributes.indirect.pointer; if ( ext::opengl::settings::experimental::culling && drawInfo.attributes.instance.pointer && drawInfo.attributes.instance.length == sizeof(pod::Instance) ) { diff --git a/engine/src/ext/opengl/graphic.cpp b/engine/src/ext/opengl/graphic.cpp index 6cc01af8..3cebe44f 100644 --- a/engine/src/ext/opengl/graphic.cpp +++ b/engine/src/ext/opengl/graphic.cpp @@ -357,8 +357,10 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe } auto uniformBufferIt = uniformBuffers.begin(); - auto uniformBuffer = (*uniformBufferIt++).buffer; + auto uniformBuffer = (*uniformBufferIt).buffer; + auto uniformBufferSize = (*uniformBufferIt).range; pod::Camera::Viewports* viewports = (pod::Camera::Viewports*) device->getBuffer( uniformBuffer ); + pod::Uniform* viewports2 = (pod::Uniform*) device->getBuffer( uniformBuffer ); CommandBuffer::InfoDraw drawCommandInfoBase = {}; drawCommandInfoBase.type = ext::opengl::enums::Command::DRAW; @@ -373,10 +375,14 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe } drawCommandInfoBase.attributes.index = descriptor.inputs.index.attributes.front(); - drawCommandInfoBase.matrices.view = &viewports->matrices[0].view; - drawCommandInfoBase.matrices.projection = &viewports->matrices[0].projection; + if ( uniformBufferSize == sizeof(pod::Camera::Viewports) ) { + drawCommandInfoBase.matrices.view = &viewports->matrices[0].view; + drawCommandInfoBase.matrices.projection = &viewports->matrices[0].projection; + } else if ( uniformBufferSize == sizeof(pod::Uniform) ) { + drawCommandInfoBase.matrices.model = &viewports2->modelView; + drawCommandInfoBase.matrices.projection = &viewports2->projection; + } -#if 1 if ( descriptor.inputs.indirect.count ) { auto& indirectAttribute = descriptor.inputs.indirect.attributes.front(); @@ -406,22 +412,6 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe auto& infos = pool[textureID]; CommandBuffer::InfoDraw& drawCommandInfo = infos.emplace_back( drawCommandInfoBase ); - /* - drawCommandInfo.type = ext::opengl::enums::Command::DRAW; - drawCommandInfo.descriptor = descriptor; - drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front(); - for ( uf::Mesh::Attribute attribute : descriptor.inputs.vertex.attributes ) { - if ( attribute.descriptor.name == "position" ) drawCommandInfo.attributes.position = attribute; - else if ( attribute.descriptor.name == "uv" ) drawCommandInfo.attributes.uv = attribute; - else if ( attribute.descriptor.name == "st" ) drawCommandInfo.attributes.st = attribute; - else if ( attribute.descriptor.name == "normal" ) drawCommandInfo.attributes.normal = attribute; - else if ( attribute.descriptor.name == "color" ) drawCommandInfo.attributes.color = attribute; - } - - drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front(); - drawCommandInfo.matrices.view = &viewports->matrices[0].view; - drawCommandInfo.matrices.projection = &viewports->matrices[0].projection; - */ drawCommandInfo.descriptor.inputs.index.first = drawCommand.indexID; drawCommandInfo.descriptor.inputs.index.count = drawCommand.indices; @@ -447,41 +437,18 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe auto texture2DID = textures[instance.lightmapID].index; drawCommandInfo.textures.secondary = this->material.textures.at(texture2DID).descriptor; } - // if ( !optimize ) commandBuffer.record(drawCommandInfo); } - // if ( optimize ) for ( auto pair : pool ) for ( auto& info : pair.second ) commandBuffer.record(info); - } else { + } else { /* - auto uniformBufferIt = uniformBuffers.begin(); - auto uniformBuffer = (*uniformBufferIt++).buffer; - auto uniformOffset = (size_t) 0; - - - CommandBuffer::InfoDraw drawCommandInfo = {}; - drawCommandInfo.type = ext::opengl::enums::Command::DRAW; - drawCommandInfo.descriptor = descriptor; - drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front(); - for ( auto& attribute : descriptor.inputs.vertex.attributes ) { - if ( attribute.descriptor.name == "position" ) drawCommandInfo.attributes.position = attribute; - else if ( attribute.descriptor.name == "uv" ) drawCommandInfo.attributes.uv = attribute; - else if ( attribute.descriptor.name == "st" ) drawCommandInfo.attributes.st = attribute; - else if ( attribute.descriptor.name == "normal" ) drawCommandInfo.attributes.normal = attribute; - else if ( attribute.descriptor.name == "color" ) drawCommandInfo.attributes.color = attribute; - } - - drawCommandInfo.textures.primary = this->material.textures.front().descriptor; - - if ( !uniformBuffers.empty() ) { - pod::Uniform* uniforms = (pod::Uniform*) device->getBuffer( uniformBuffer ); - drawCommandInfo.matrices.model = NULL; - drawCommandInfo.matrices.view = &uniforms->modelView; - drawCommandInfo.matrices.projection = &uniforms->projection; - } + UF_MSG_DEBUG( viewports << " " << uniformBuffers.size() ); + if ( drawCommandInfoBase.matrices.model ) UF_MSG_DEBUG( "model: " << drawCommandInfoBase.matrices.model << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.model ) ); + if ( drawCommandInfoBase.matrices.view ) UF_MSG_DEBUG( "view: " << drawCommandInfoBase.matrices.view << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.view ) ); + if ( drawCommandInfoBase.matrices.projection ) UF_MSG_DEBUG( "projection: " << drawCommandInfoBase.matrices.projection << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.projection ) ); */ + commandBuffer.record(drawCommandInfoBase); } -#endif } void ext::opengl::Graphic::destroy() { for ( auto& pair : pipelines ) pair.second.destroy(); diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index 538223b6..349b933d 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -322,7 +322,8 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { } // indices if ( mesh.index.count ) { - uint8_t* pointer = (uint8_t*) mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer].data(); + // uint8_t* pointer = (uint8_t*) mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer].data(); + uint8_t* pointer = (uint8_t*) mesh.getBuffer(mesh.index).data(); for ( auto index = 0; index < xmesh.indexCount; ++index ) { switch ( mesh.index.size ) { case 1: (( uint8_t*) pointer)[index] = xmesh.indexArray[index]; break; diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index bddd7c0c..dcbad543 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -40,6 +40,7 @@ namespace { uf::stl::unordered_map> cache; } glyphs; #endif + uf::stl::string defaultRenderMode = "Gui"; uf::Serializer defaultSettings; @@ -342,18 +343,16 @@ void ext::Gui::load( const uf::Image& image ) { if ( ext::json::isNull(metadataJson["projection"]) ) metadataJson["projection"] = false; if ( ext::json::isNull(metadataJson["flip uv"]) ) metadataJson["flip uv"] = true; if ( ext::json::isNull(metadataJson["front face"]) ) metadataJson["front face"] = "ccw"; - #if UF_USE_OPENGL - metadataJson["cull mode"] = "back"; - // metadataJson["depth test"]["test"] = false; - // metadataJson["depth test"]["write"] = true; - // if ( metadataJson["flip uv"].is() ) metadataJson["flip uv"] = !metadataJson["flip uv"].as(); - #endif } else { if ( ext::json::isNull(metadataJson["projection"]) ) metadataJson["projection"] = true; if ( ext::json::isNull(metadataJson["flip uv"]) ) metadataJson["flip uv"] = false; if ( ext::json::isNull(metadataJson["front face"]) ) metadataJson["front face"] = "cw"; } - metadataJson["cull mode"] = "none"; + + if ( metadataJson["world"].as() ) { + + } + graphic.descriptor.parse( metadataJson ); if ( uf::matrix::reverseInfiniteProjection ) { } else { @@ -752,9 +751,10 @@ void ext::GuiBehavior::tick( uf::Object& self ) { bool isGlyph = this->hasComponent(); #if UF_USE_OPENGL - auto model = uf::matrix::identity(); + auto model = transform.model; auto& shader = graphic.material.getShader("vertex"); pod::Uniform uniform; + if ( metadata.mode == 1 ) { uniform.modelView = transform.model; uniform.projection = uf::matrix::identity(); @@ -764,7 +764,6 @@ void ext::GuiBehavior::tick( uf::Object& self ) { auto& camera = controller.getComponent(); uniform.modelView = camera.getView() * uf::transform::model( transform ); uniform.projection = camera.getProjection(); - model = uniform.modelView; } else if ( metadata.mode == 3 ) { pod::Transform<> flatten = uf::transform::flatten( transform ); uniform.modelView = @@ -773,19 +772,8 @@ void ext::GuiBehavior::tick( uf::Object& self ) { uf::quaternion::matrix( flatten.orientation ) * flatten.model; uniform.projection = camera.getProjection(); - model = uniform.modelView; } else { pod::Transform<> flatten = uf::transform::flatten( transform ); - model = - uf::matrix::translate( uf::matrix::identity(), flatten.position ) * - uf::matrix::scale( uf::matrix::identity(), flatten.scale ) * - uf::quaternion::matrix( flatten.orientation ) * - flatten.model; - - flatten.position.y = -flatten.position.y; - if ( isGlyph ) flatten.scale.y = -flatten.scale.y; - - flatten.position.z = 1; uniform.modelView = uf::matrix::translate( uf::matrix::identity(), flatten.position ) * uf::matrix::scale( uf::matrix::identity(), flatten.scale ) * @@ -793,7 +781,15 @@ void ext::GuiBehavior::tick( uf::Object& self ) { flatten.model; uniform.projection = uf::matrix::identity(); } + shader.updateUniform( "UBO", (const void*) &uniform, sizeof(uniform) ); + pod::Uniform* uniformBuffer = (pod::Uniform*) shader.device->getBuffer(shader.getUniformBuffer("UBO").descriptor.buffer); + #if 0 + UF_MSG_DEBUG( "buffer: " << uniformBuffer ); + UF_MSG_DEBUG( "modelView: " << &uniformBuffer->modelView << " " << uf::matrix::toString( uniformBuffer->modelView ) ); + UF_MSG_DEBUG( "projection: " << &uniformBuffer->projection << " " << uf::matrix::toString( uniformBuffer->projection ) ); + #endif + /* auto model = uf::matrix::identity(); auto uniformBuffer = graphic.getUniform();