diff --git a/bin/data/config.json b/bin/data/config.json index b0a88ab8..d70c3ad2 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -37,7 +37,7 @@ "ext": { "vulkan": { "validation": { - "enabled": false, + "enabled": true, "filters": [ "MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps) "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) @@ -66,7 +66,7 @@ "deferred alias output to swapchain": true, "vsync": true, "hdr": false, - "vxgi": true, + "vxgi": false, "deferred sampling": false }, "formats": { diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index 5bbd5494..bcf01aea 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -36,12 +36,24 @@ bool validCubemapIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < CUBEMAPS; } #if DEFERRED || COMPUTE +bool validTextureIndex( uint id ) { + return 0 <= id && id < MAX_TEXTURES; +} bool validTextureIndex( uint start, int offset ) { return 0 <= offset && start + offset < MAX_TEXTURES; } uint textureIndex( uint start, int offset ) { return start + offset; } +vec4 sampleTexture( uint id ) { + const Texture t = textures[id]; + return texture( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, surface.uv ) ); +} +vec4 sampleTexture( uint id, float mip ) { + const Texture t = textures[id]; + return textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, surface.uv ), mip ); +} +#if 0 vec4 sampleTexture( uint start, uint slot, int offset, int atlas ) { Texture a; const bool useAtlas = 0 <= atlas && validTextureIndex( start, atlas ); @@ -61,6 +73,7 @@ vec4 sampleTexture( uint start, uint slot, int offset, int atlas, float mip ) { return textureLod( samplerTextures[nonuniformEXT(i)], uv, mip ); } #endif +#endif vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { const vec3 t0 = (boundsMin - ray.origin) / ray.direction; const vec3 t1 = (boundsMax - ray.origin) / ray.direction; diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index d98c9bff..3d6a61d1 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -56,6 +56,9 @@ struct Mode { }; struct Light { + mat4 view; + mat4 projection; + vec3 position; float radius; @@ -66,9 +69,6 @@ struct Light { int typeMap; int indexMap; float depthBias; - - mat4 view; - mat4 projection; }; struct Material { @@ -100,11 +100,16 @@ struct Texture { vec4 lerp; }; -struct DrawCall { - int materialIndex; - int textureIndex; - uint textureSlot; - uint padding; +struct DrawCommand { + uint indices; // triangle count + uint instances; // instance count + uint indexID; // starting triangle position + int vertexID; // starting vertex position + + uint instanceID; // starting instance position + uint materialID; // material used for draw + uint objectID; // + uint vertices; // }; struct SurfaceMaterial { diff --git a/bin/data/shaders/display/renderTarget.h b/bin/data/shaders/display/renderTarget.h index 10755885..ab1aca5f 100644 --- a/bin/data/shaders/display/renderTarget.h +++ b/bin/data/shaders/display/renderTarget.h @@ -9,7 +9,7 @@ #if DEFERRED_SAMPLING layout (binding = 3) uniform sampler2D samplerUvs; #else - layout (binding = 3) uniform sampler2D samplerAlbedo; + layout (binding = 4) uniform sampler2D samplerAlbedo; #endif #else layout (binding = 1) uniform usampler2DMS samplerId; @@ -17,7 +17,7 @@ #if DEFERRED_SAMPLING layout (binding = 3) uniform sampler2DMS samplerUvs; #else - layout (binding = 3) uniform sampler2DMS samplerAlbedo; + layout (binding = 4) uniform sampler2DMS samplerAlbedo; #endif #endif diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h index 1519f52a..1d42669f 100644 --- a/bin/data/shaders/display/subpass.h +++ b/bin/data/shaders/display/subpass.h @@ -43,7 +43,7 @@ layout (binding = 4) uniform UBO { uint lights; uint materials; uint textures; - uint drawCalls; + uint drawCommands; vec3 ambient; float gamma; @@ -63,8 +63,8 @@ layout (std140, binding = 6) readonly buffer Materials { layout (std140, binding = 7) readonly buffer Textures { Texture textures[]; }; -layout (std140, binding = 8) readonly buffer DrawCalls { - DrawCall drawCalls[]; +layout (std140, binding = 8) readonly buffer DrawCommands { + DrawCommand drawCommands[]; }; layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; @@ -168,8 +168,8 @@ void populateSurface() { return; } const uint drawId = ID.x - 1; - const DrawCall drawCall = drawCalls[drawId]; - surface.material.id = ID.y + drawCall.materialIndex - 1; + const DrawCommand drawCommand = drawCommands[drawId]; + surface.material.id = ID.y + drawCommand.materialID - 1; const Material material = materials[surface.material.id]; surface.material.albedo = material.colorBase; surface.fragment = material.colorEmissive; @@ -180,8 +180,10 @@ void populateSurface() { surface.uv = resolve(samplerUv, ubo.msaa).xy; #endif const float mip = mipLevel(inUv.xy); - if ( validTextureIndex( drawCall.textureIndex, material.indexAlbedo ) ) { - surface.material.albedo = sampleTexture( drawCall.textureIndex, drawCall.textureSlot, material.indexAlbedo, material.indexAtlas, mip ); +// if ( validTextureIndex( drawCommand.textureIndex, material.indexAlbedo ) ) { +// surface.material.albedo = sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexAlbedo, material.indexAtlas, mip ); + if ( validTextureIndex( material.indexAlbedo ) ) { + surface.material.albedo = sampleTexture( material.indexAlbedo, mip ); } // OPAQUE if ( material.modeAlpha == 0 ) { @@ -194,8 +196,10 @@ void populateSurface() { } // Emissive textures - if ( validTextureIndex( drawCall.textureIndex, material.indexEmissive ) ) { - surface.fragment += sampleTexture( drawCall.textureIndex, drawCall.textureSlot, material.indexEmissive, material.indexAtlas, mip ); +// if ( validTextureIndex( drawCommand.textureIndex, material.indexEmissive ) ) { +// surface.fragment += sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexEmissive, material.indexAtlas, mip ); + if ( validTextureIndex( material.indexEmissive ) ) { + surface.fragment += sampleTexture( material.indexEmissive, mip ); } #else #if !MULTISAMPLING diff --git a/bin/data/shaders/display/vxgi.comp.h b/bin/data/shaders/display/vxgi.comp.h index 5a74f2b2..656960c1 100644 --- a/bin/data/shaders/display/vxgi.comp.h +++ b/bin/data/shaders/display/vxgi.comp.h @@ -26,7 +26,7 @@ layout (binding = 4) uniform UBO { uint lights; uint materials; uint textures; - uint drawCalls; + uint drawCommands; vec3 ambient; float gamma; @@ -46,8 +46,8 @@ layout (std140, binding = 6) readonly buffer Materials { layout (std140, binding = 7) readonly buffer Textures { Texture textures[]; }; -layout (std140, binding = 8) readonly buffer DrawCalls { - DrawCall drawCalls[]; +layout (std140, binding = 8) readonly buffer DrawCommands { + DrawCommand drawCommands[]; }; layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; @@ -81,16 +81,18 @@ void main() { continue; } const uint drawId = ID.x - 1; - const DrawCall drawCall = drawCalls[drawId]; - surface.material.id = ID.y + drawCall.materialIndex - 1; + const DrawCommand drawCommand = drawCommands[drawId]; + surface.material.id = ID.y + drawCommand.materialID - 1; const Material material = materials[surface.material.id]; surface.material.albedo = material.colorBase; surface.fragment = material.colorEmissive; #if DEFERRED_SAMPLING surface.uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) ).xy; - if ( validTextureIndex( drawCall.textureIndex, material.indexAlbedo ) ) { - surface.material.albedo = sampleTexture( drawCall.textureIndex, drawCall.textureSlot, material.indexAlbedo, material.indexAtlas ); + // if ( validTextureIndex( drawCommand.textureIndex, material.indexAlbedo ) ) { + // surface.material.albedo = sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexAlbedo, material.indexAtlas ); + if ( validTextureIndex( material.indexAlbedo ) ) { + surface.material.albedo = sampleTexture( material.indexAlbedo ); } // OPAQUE @@ -104,8 +106,10 @@ void main() { } // Emissive textures - if ( validTextureIndex( drawCall.textureIndex, material.indexEmissive ) ) { - surface.fragment += sampleTexture( drawCall.textureIndex, drawCall.textureSlot, material.indexEmissive, material.indexAtlas ); + // if ( validTextureIndex( drawCommand.textureIndex, material.indexEmissive ) ) { + // surface.fragment += sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexEmissive, material.indexAtlas ); + if ( validTextureIndex( material.indexEmissive ) ) { + surface.fragment += sampleTexture( material.indexEmissive ); } #else surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); diff --git a/bin/data/shaders/gltf/base.frag.h b/bin/data/shaders/gltf/base.frag.h index 34dc2e34..6f215cc1 100644 --- a/bin/data/shaders/gltf/base.frag.h +++ b/bin/data/shaders/gltf/base.frag.h @@ -57,7 +57,7 @@ void main() { if ( useAtlas ) textureAtlas = textures[material.indexAtlas]; if ( !validTextureIndex( material.indexAlbedo ) ) discard; { Texture t = textures[material.indexAlbedo]; - A = textureLod( samplerTextures[nonuniformEXT((useAtlas) ? textureAtlas.index : t.index)], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { A.a = 1; @@ -88,7 +88,7 @@ void main() { // sample normal if ( validTextureIndex( material.indexNormal ) ) { Texture t = textures[material.indexNormal]; - N = inTBN * normalize( textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ).xyz * 2.0 - vec3(1.0)); + N = inTBN * normalize( textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ).xyz * 2.0 - vec3(1.0)); } #if 0 // sample metallic/roughness diff --git a/client/main.cpp b/client/main.cpp index b5e50c0b..4d305d72 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -46,7 +46,7 @@ namespace { } } } - +#include int main(int argc, char** argv){ for ( size_t i = 0; i < argc; ++i ) { char* c_str = argv[i]; @@ -58,6 +58,46 @@ int main(int argc, char** argv){ signal(SIGABRT, ::handlers::abrt); signal(SIGSEGV, ::handlers::segv); + { + uf::Mesh mesh; + mesh.bind(); + mesh.insertVertices({ + { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, + { {-1.0f, -1.0f}, {0.0f, 0.0f}, }, + { {1.0f, -1.0f}, {1.0f, 0.0f}, }, + { {1.0f, 1.0f}, {1.0f, 1.0f}, } + }); + mesh.insertIndices({ + 0, 1, 2, 2, 3, 0 + }); + /* + mesh.bind(); + mesh.insertVertices({ + {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}, + {{8.0f, 9.0f, 10.0f}, {11.0f, 12.0f}, {13.0f, 14.0f, 15.0f}}, + {{16.0f, 17.0f, 18.0f}, {19.0f, 20.0f}, {21.0f, 22.0f, 23.0f}}, + }); + mesh.insertIndices({ + 0, 1, 2 + }); + */ + + mesh.print(); + /* + auto& buffer = mesh.buffers[0 <= mesh.vertex.interleaved && mesh.vertex.interleaved < mesh.buffers.size() ? mesh.vertex.interleaved :]; + uint8_t* pointer = (uint8_t*) buffer.data(); + while ( pointer < (uint8_t*) buffer.data() + buffer.size() ) { + for ( auto& attribute : mesh.vertex.attributes ) { + float* vector = pointer + attrribute.descriptor.offset; + for ( auto i = 0; i < attribute.descriptor.components; ++i ) { + UF_MSG_DEBUG( attribute.descriptor.name << ": " << vector[i] ); + } + pointer += attribute.descriptor.size; + } + } + */ + } + client::initialize(); ext::initialize(); diff --git a/engine/inc/uf/engine/graph/graph.h b/engine/inc/uf/engine/graph/graph.h index a869c30f..61fe6902 100644 --- a/engine/inc/uf/engine/graph/graph.h +++ b/engine/inc/uf/engine/graph/graph.h @@ -4,82 +4,48 @@ #include #include #include -#include #include -#include - -#include "mesh.h" -#include "pod.h" +#include #include -#define UF_GRAPH_EXPERIMENTAL 1 +#define UF_GRAPH_VARYING_MESH 1 +#define UF_GRAPH_INDIRECT_DRAW 1 + +#include "pod.inl" +#include "mesh.inl" +#include "scene.inl" + namespace pod { - struct UF_API Texture { - struct Storage { - /*alignas(4)*/ int32_t index = -1; - /*alignas(4)*/ int32_t sampler = -1; - /*alignas(4)*/ int32_t remap = -1; - /*alignas(4)*/ float blend = 0; - - /*alignas(16)*/ pod::Vector4f lerp = {0, 0, 1, 1}; - } storage; - uf::stl::string name = ""; - uf::renderer::Texture2D texture; - bool bind = false; - }; - struct UF_API Node { - uf::stl::string name = ""; - - int32_t index = -1; - int32_t skin = -1; - int32_t parent = -1; - int32_t mesh = -1; - - pod::Transform<> transform; - uf::stl::vector children; - - uf::Object* entity = NULL; - struct { - int32_t material = -1; - int32_t texture = -1; - int32_t joint = -1; - } buffers; - }; struct UF_API Graph { - #if UF_GRAPH_EXPERIMENTAL - typedef pod::VaryingMesh Mesh; - #else - typedef uf::graph::skinned_mesh_t Mesh; - #endif - - // Node* node = NULL; - pod::Node root; - uf::stl::vector nodes; - - uf::Object* entity = NULL; - - struct { - int32_t instance = -1; - } buffers; - uf::stl::string name = ""; - uf::graph::load_mode_t mode; uf::Serializer metadata; - uf::Atlas atlas; - uf::stl::vector images; - uf::stl::vector samplers; - uf::stl::vector textures; - uf::stl::vector materials; - uf::stl::vector lights; - uf::stl::vector drawCalls; + pod::Node root; + uf::stl::vector nodes; // node's position corresponds to its drawCommand and instance + // Render information + uf::stl::vector> drawCommands; // draws to dispatch, one per primitive, gets copied per rendermode + + uf::stl::vector instances; // instance data to use, gets copied per rendermode + + uf::stl::vector meshes; // collection of primitives (stored as meshes, by material) + + uf::stl::vector images; // references global pool of images + uf::stl::vector materials; // references global pool of materials + uf::stl::vector textures; // references global pool of textures + + uf::stl::vector texture2Ds; // references global pool of texture2Ds + uf::stl::vector samplers; // references global pool of samplers + + // Lighting information + uf::stl::unordered_map lights; + + // Animations uf::stl::vector skins; - uf::stl::vector meshes; uf::stl::unordered_map animations; - + // Animation queue std::queue sequence; struct { struct { @@ -92,22 +58,29 @@ namespace pod { } override; } animations; } settings; + + // Local storage, used for save/load + struct Storage { + uf::stl::fifo_map atlases; + uf::stl::fifo_map images; + uf::stl::fifo_map meshes; + uf::stl::fifo_map materials; + uf::stl::fifo_map textures; + + uf::stl::fifo_map texture2Ds; + uf::stl::fifo_map samplers; + }; }; } namespace uf { namespace graph { - /* - namespace { - extern UF_API uf::stl::vector storage; - extern UF_API uf::stl::vector indices; - } materials; - namespace { - extern UF_API uf::stl::vector storage; - extern UF_API uf::stl::vector indices; - } textures; - */ + extern UF_API pod::Graph::Storage storage; + } +} +namespace uf { + namespace graph { pod::Node* UF_API find( pod::Graph& graph, int32_t index ); pod::Node* UF_API find( pod::Graph& graph, const uf::stl::string& name ); @@ -128,7 +101,7 @@ namespace uf { void UF_API destroy( pod::Graph& ); - pod::Graph UF_API load( const uf::stl::string&, uf::graph::load_mode_t = 0, const uf::Serializer& = ext::json::null() ); + pod::Graph UF_API load( const uf::stl::string&, const uf::Serializer& = ext::json::null() ); void UF_API save( const pod::Graph&, const uf::stl::string& ); uf::stl::string UF_API print( const pod::Graph& graph ); diff --git a/engine/inc/uf/engine/graph/mesh.h b/engine/inc/uf/engine/graph/mesh.h deleted file mode 100644 index 999dfac5..00000000 --- a/engine/inc/uf/engine/graph/mesh.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -namespace uf { - namespace graph { - enum LoadMode { - ATLAS = 0x1 << 1, - INVERT = 0x1 << 2, - TRANSFORM = 0x1 << 3, - SKINNED = 0x1 << 4, - }; - typedef uint16_t load_mode_t; - typedef uint16_t id_t; - - namespace mesh { - struct Base { - /*alignas(16)*/ pod::Vector3f position; - /*alignas(8)*/ pod::Vector2f uv; - /*alignas(8)*/ pod::Vector2f st; - /*alignas(4)*/ pod::Vector id; - - static UF_API uf::stl::vector descriptor; - }; - struct ID { - /*alignas(16)*/ pod::Vector3f position; - /*alignas(8)*/ pod::Vector2f uv; - /*alignas(8)*/ pod::Vector2f st; - /*alignas(16)*/ pod::Vector3f normal; - /*alignas(16)*/ pod::Vector3f tangent; - /*alignas(4)*/ pod::Vector id; - - static UF_API uf::stl::vector descriptor; - }; - struct Skinned { - /*alignas(16)*/ pod::Vector3f position; - /*alignas(8)*/ pod::Vector2f uv; - /*alignas(8)*/ pod::Vector2f st; - /*alignas(16)*/ pod::Vector3f normal; - /*alignas(16)*/ pod::Vector3f tangent; - /*alignas(4)*/ pod::Vector id; - /*alignas(8)*/ pod::Vector joints; - /*alignas(16)*/ pod::Vector4f weights; - - static UF_API uf::stl::vector descriptor; - }; - } - typedef uf::Mesh base_mesh_t; - typedef uf::Mesh id_mesh_t; - typedef uf::Mesh skinned_mesh_t; - } -} \ No newline at end of file diff --git a/engine/inc/uf/engine/graph/mesh.inl b/engine/inc/uf/engine/graph/mesh.inl new file mode 100644 index 00000000..33ea0d9c --- /dev/null +++ b/engine/inc/uf/engine/graph/mesh.inl @@ -0,0 +1,40 @@ +namespace uf { + namespace graph { + namespace mesh { + typedef uint16_t id_t; + + struct Base { + pod::Vector3f position; + pod::Vector2f uv; + pod::Vector2f st; + + static UF_API uf::stl::vector descriptor; + }; + struct ID { + pod::Vector3f position; + pod::Vector2f uv; + pod::Vector2f st; + pod::Vector3f normal; + pod::Vector3f tangent; + + static UF_API uf::stl::vector descriptor; + }; + struct Skinned { + pod::Vector3f position; + pod::Vector2f uv; + pod::Vector2f st; + pod::Vector3f normal; + pod::Vector3f tangent; + pod::Vector joints; + pod::Vector4f weights; + + static UF_API uf::stl::vector descriptor; + }; + } + /* + typedef uf::Mesh base_mesh_t; + typedef uf::Mesh id_mesh_t; + typedef uf::Mesh skinned_mesh_t; + */ + } +} \ No newline at end of file diff --git a/engine/inc/uf/engine/graph/pod.h b/engine/inc/uf/engine/graph/pod.h deleted file mode 100644 index 96bd25a6..00000000 --- a/engine/inc/uf/engine/graph/pod.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace pod { - struct UF_API SceneTextures { - uf::renderer::Texture3D noise; - uf::renderer::TextureCube skybox; - struct { - uf::stl::vector id; - uf::stl::vector uv; - uf::stl::vector normal; - uf::stl::vector radiance; - uf::stl::vector depth; - } voxels; - }; - - struct UF_API DrawCall { - struct Storage { - /*alignas(4)*/ int32_t materialIndex = -1; - /*alignas(4)*/ int32_t textureIndex = -1; - /*alignas(4)*/ uint32_t textureSlot = 0; - /*alignas(4)*/ uint32_t padding = 0; - } storage; - uf::stl::string name = ""; - size_t verticesIndex = 0; - size_t vertices = 0; - size_t indicesIndex = 0; - size_t indices = 0; - }; - struct UF_API Light { - struct UF_API Storage { - /*alignas(16)*/ pod::Vector4f position; - /*alignas(16)*/ pod::Vector4f color; - - /*alignas(4)*/ int32_t type = 0; - /*alignas(4)*/ int32_t typeMap = 0; - /*alignas(4)*/ int32_t indexMap = -1; - /*alignas(4)*/ float depthBias = 0; - - /*alignas(16)*/ pod::Matrix4f view; - /*alignas(16)*/ pod::Matrix4f projection; - }; - uf::stl::string name = ""; - pod::Vector3f color = { 1, 1, 1 }; - float intensity = 1.0f; - float range = 0.0f; - }; - struct UF_API Material { - struct Storage { - /*alignas(16)*/ pod::Vector4f colorBase = { 0, 0, 0, 0 }; - /*alignas(16)*/ pod::Vector4f colorEmissive = { 0, 0, 0, 0 }; - - /*alignas(4)*/ float factorMetallic = 0.0f; - /*alignas(4)*/ float factorRoughness = 0.0f; - /*alignas(4)*/ float factorOcclusion = 0.0f; - /*alignas(4)*/ float factorAlphaCutoff = 1.0f; - - /*alignas(4)*/ int32_t indexAlbedo = -1; - /*alignas(4)*/ int32_t indexNormal = -1; - /*alignas(4)*/ int32_t indexEmissive = -1; - /*alignas(4)*/ int32_t indexOcclusion = -1; - - /*alignas(4)*/ int32_t indexMetallicRoughness = -1; - /*alignas(4)*/ int32_t indexAtlas = -1; - /*alignas(4)*/ int32_t indexLightmap = -1; - /*alignas(4)*/ int32_t modeAlpha = -1; - } storage; - uf::stl::string name = ""; - uf::stl::string alphaMode = ""; - }; - struct UF_API Skin { - uf::stl::string name = ""; - uf::stl::vector joints; - uf::stl::vector inverseBindMatrices; - }; - struct UF_API Animation { - struct Sampler { - uf::stl::string interpolator; - uf::stl::vector inputs; - uf::stl::vector outputs; - }; - struct Channel { - uf::stl::string path; - int32_t node; - uint32_t sampler; - }; - - uf::stl::string name = ""; - uf::stl::vector samplers; - uf::stl::vector channels; - float start = std::numeric_limits::max(); - float end = std::numeric_limits::min(); - float cur = 0; - }; -} \ No newline at end of file diff --git a/engine/inc/uf/engine/graph/pod.inl b/engine/inc/uf/engine/graph/pod.inl new file mode 100644 index 00000000..be76a83a --- /dev/null +++ b/engine/inc/uf/engine/graph/pod.inl @@ -0,0 +1,121 @@ +namespace pod { + struct UF_API DrawCommand { + uint32_t indices = 0; // triangle count + uint32_t instances = 0; // instance count + uint32_t indexID = 0; // starting triangle position + int32_t vertexID = 0; // starting vertex position + + uint32_t instanceID = 0; // starting instance position + uint32_t materialID = 0; + uint32_t objectID = 0; + uint32_t vertices = 0; + }; + + struct UF_API Instance { + pod::Matrix4f model; + pod::Vector4f color = {1,1,1,1}; + + alignas(4) uint32_t materialID = 0; + alignas(4) uint32_t padding1 = 0; + alignas(4) uint32_t padding2 = 0; + alignas(4) uint32_t padding3 = 0; + + struct { + pod::Vector3f min = {}; + alignas(4) float padding1 = 0; + pod::Vector3f max = {}; + alignas(4) float padding2 = 0; + } bounds; + }; + + struct UF_API Material { + pod::Vector4f colorBase = { 0, 0, 0, 0 }; + pod::Vector4f colorEmissive = { 0, 0, 0, 0 }; + + float factorMetallic = 0.0f; + float factorRoughness = 0.0f; + float factorOcclusion = 0.0f; + float factorAlphaCutoff = 1.0f; + + int32_t indexAlbedo = -1; + int32_t indexNormal = -1; + int32_t indexEmissive = -1; + int32_t indexOcclusion = -1; + + int32_t indexMetallicRoughness = -1; + int32_t indexAtlas = -1; + int32_t indexLightmap = -1; + int32_t modeAlpha = -1; + }; + + struct UF_API Texture { + int32_t index = -1; + int32_t sampler = -1; + int32_t remap = -1; + float blend = 0; + + pod::Vector4f lerp = {0, 0, 1, 1}; + }; + + struct UF_API Light { + pod::Matrix4f view; + pod::Matrix4f projection; + + pod::Vector3f position; + alignas(4) float range = 0.0f; + pod::Vector3f color; + alignas(4) float intensity = 0.0f; + + int32_t type = 0; + int32_t typeMap = 0; + int32_t indexMap = -1; + float depthBias = 0; + }; + // + struct UF_API Mesh { + uf::stl::vector drawCommands; + uf::Mesh mesh; + }; + // + struct UF_API Skin { + uf::stl::string name = ""; + + uf::stl::vector joints; + uf::stl::vector inverseBindMatrices; + }; + + struct UF_API Animation { + struct Sampler { + uf::stl::string interpolator; + uf::stl::vector inputs; + uf::stl::vector outputs; + }; + + struct Channel { + uf::stl::string path; + int32_t node; + uint32_t sampler; + }; + + uf::stl::string name = ""; + + uf::stl::vector samplers; + uf::stl::vector channels; + float start = std::numeric_limits::max(); + float end = std::numeric_limits::min(); + float cur = 0; + }; + // + struct UF_API Node { + uf::stl::string name = ""; + + int32_t index = -1; + int32_t parent = -1; + int32_t mesh = -1; + int32_t skin = -1; + uf::stl::vector children; + + uf::Object* entity = NULL; + pod::Transform<> transform; + }; +} \ No newline at end of file diff --git a/engine/inc/uf/engine/graph/scene.inl b/engine/inc/uf/engine/graph/scene.inl new file mode 100644 index 00000000..444646e2 --- /dev/null +++ b/engine/inc/uf/engine/graph/scene.inl @@ -0,0 +1,15 @@ +// Doesn't have a home + +namespace pod { + struct UF_API SceneTextures { + uf::renderer::Texture3D noise; + uf::renderer::TextureCube skybox; + struct { + uf::stl::vector id; + uf::stl::vector uv; + uf::stl::vector normal; + uf::stl::vector radiance; + uf::stl::vector depth; + } voxels; + }; +} \ No newline at end of file diff --git a/engine/inc/uf/ext/bullet/bullet.h b/engine/inc/uf/ext/bullet/bullet.h index 88b40c7d..f61ba891 100644 --- a/engine/inc/uf/ext/bullet/bullet.h +++ b/engine/inc/uf/ext/bullet/bullet.h @@ -57,7 +57,7 @@ namespace ext { #endif // collider for mesh (static or dynamic) - pod::Bullet& create( uf::Object&, const pod::Mesh&, bool ); + pod::Bullet& create( uf::Object&, const uf::Mesh&, bool ); // collider for boundingbox pod::Bullet& UF_API create( uf::Object&, const pod::Vector3f&, float ); // collider for capsule diff --git a/engine/inc/uf/ext/gltf/gltf.h b/engine/inc/uf/ext/gltf/gltf.h index a5254714..bb7d7301 100644 --- a/engine/inc/uf/ext/gltf/gltf.h +++ b/engine/inc/uf/ext/gltf/gltf.h @@ -1,12 +1,11 @@ #pragma once -#include #include #include namespace ext { namespace gltf { - pod::Graph UF_API load( const uf::stl::string&, uf::graph::load_mode_t = 0, const uf::Serializer& = {} ); + pod::Graph UF_API load( const uf::stl::string&, const uf::Serializer& = {} ); void UF_API save( const uf::stl::string&, const pod::Graph& ); } } \ No newline at end of file diff --git a/engine/inc/uf/ext/json/jsoncpp.h b/engine/inc/uf/ext/json/jsoncpp.h deleted file mode 100644 index 62252bd8..00000000 --- a/engine/inc/uf/ext/json/jsoncpp.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -#include - -namespace ext { - namespace json { - class UF_API Value; - typedef Json::Value base_value; - typedef Value Document; - - class UF_API Value : public base_value { - public: - Value( Json::ValueType type = Json::objectValue ) : base_value(type) {} - Value& operator=( const Value& ); - - template Value& operator[]( Args... args ); - template const Value& operator[]( Args... args ) const; - template Value& operator=( Args... args ); - - template - Value& emplace_back( const T& ); - }; - - inline bool isTable( const Value& v ) { return v.isArray() || v.isObject(); } - inline bool isObject( const Value& v ) { return v.isObject(); } - inline bool isArray( const Value& v ) { return v.isArray(); } - inline bool isNull( const Value& v ) { return v.isNull(); } - - inline Value array() { return Value(Json::arrayValue); } - inline Value object() { return Value(Json::objectValue); } - inline Value null() { return Value(Json::nullValue); } - - inline uf::stl::vector keys( const Value& v ) { return v.getMemberNames(); } - } -} - -template ext::json::Value& ext::json::Value::operator[]( Args... args ) { - return (ext::json::Value&) ext::json::base_value::operator[](args...); -} -template const ext::json::Value& ext::json::Value::operator[]( Args... args ) const { - return (const ext::json::Value&) ext::json::base_value::operator[](args...); -} -template ext::json::Value& ext::json::Value::operator=( Args... args ) { - ext::json::base_value::operator=(args...); - return *this; -} - -template -ext::json::Value& ext::json::Value::emplace_back( const T& v ) { - ext::json::base_value::append( v ); - return *this; -} \ No newline at end of file diff --git a/engine/inc/uf/ext/json/lua.h b/engine/inc/uf/ext/json/lua.h deleted file mode 100644 index 5117317a..00000000 --- a/engine/inc/uf/ext/json/lua.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include - -#include - -namespace ext { - namespace json { - class UF_API Value; - typedef sol::table base_value; - typedef Value Document; - - class UF_API Value : public base_value { - public: - Value& operator=( const Value& ); - - template Value& operator[]( Args... args ); - template const Value& operator[]( Args... args ) const; - template Value& operator=( Args... args ); - }; - - inline bool isTable( sol::object v ) { return v.is(); } - inline bool isObject( sol::object v ) { return v.is(); } - inline bool isArray( sol::object v ) { return v.is(); } - inline bool isNull( sol::object v ) { return v == sol::lua_nil; } - - template inline bool isTable( T v ); - template inline bool isObject( T v ); - template inline bool isArray( T v ); - template inline bool isNull( T v ); - } -} - -template ext::json::Value& ext::json::Value::operator[]( Args... args ) { - return (ext::json::Value&) ext::json::base_value::operator[](args...); -} -template const ext::json::Value& ext::json::Value::operator[]( Args... args ) const { - return (const ext::json::Value&) ext::json::base_value::operator[](args...); -} -template ext::json::Value& ext::json::Value::operator=( Args... args ) { - ext::json::base_value::operator=(args...); - return *this; -} - - -template -inline bool ext::json::isTable( T v ) { return v.get_type() == sol::type::table; } - -template -inline bool ext::json::isObject( T v ) { return v.get_type() == sol::type::table; } - -template -inline bool ext::json::isArray( T v ) { return v.get_type() == sol::type::table; } - -template -inline bool ext::json::isNull( T v ) { return v.get_type() == sol::type::nil; } \ No newline at end of file diff --git a/engine/inc/uf/ext/json/rapidjson.h b/engine/inc/uf/ext/json/rapidjson.h deleted file mode 100644 index 7d4f4264..00000000 --- a/engine/inc/uf/ext/json/rapidjson.h +++ /dev/null @@ -1,147 +0,0 @@ -#pragma once - -#include - -#include - -namespace ext { - namespace json { - class UF_API Value; - typedef rapidjson::Value base_value; - struct UF_API Document; - // typedef rapidjson::Document Document - class UF_API Value : public base_value { - public: - Value& operator=( const Value& ); - - template Value& operator[]( Args... args ); - template const Value& operator[]( Args... args ) const; - - inline size_t size() const { return Size(); } - - inline decltype(auto) begin() { return Begin(); } - inline decltype(auto) end() { return End(); } - - template inline T get() const = delete; - template inline Value& operator=( T v ) = delete; - }; - - inline bool isTable( const Value& v ) { return v.IsArray() || v.IsObject(); } - inline bool isObject( const Value& v ) { return v.IsObject(); } - inline bool isArray( const Value& v ) { return v.IsArray(); } - inline bool isNull( const Value& v ) { return v.IsNull(); } - - inline decltype(auto) array() { - return ext::json::base_value(rapidjson::kArrayType).Move(); - } - inline decltype(auto) object() { - return ext::json::base_value(rapidjson::kObjectType).Move(); - } - inline Value null() { return Value(); } - - uf::stl::vector UF_API keys( const Value& v ); - static rapidjson::Document::AllocatorType allocator; - - struct Document : public rapidjson::Document { - public: - Document() : rapidjson::Document(&ext::json::allocator) {} - - template Value& operator[]( Args... args ); - template const Value& operator[]( Args... args ) const; - }; - } -} - -template ext::json::Value& ext::json::Value::operator[]( Args... args ) { - const uf::stl::string k(args...); - auto key = rapidjson::StringRef(k.c_str()); - auto it = ext::json::base_value::FindMember(key); - if ( it != ext::json::base_value::MemberEnd() ) - return (ext::json::Value&) it->value; - - // member doesn't exist, make empty object - ext::json::base_value::AddMember(key, ext::json::object(), ext::json::allocator); - return this->operator[](args...); -} -template const ext::json::Value& ext::json::Value::operator[]( Args... args ) const { - const uf::stl::string k(args...); - auto key = rapidjson::StringRef(k.c_str()); - auto it = ext::json::base_value::FindMember(key); - if ( it != ext::json::base_value::MemberEnd() ) - return (const ext::json::Value&) it->value; - - return ext::json::base_value(); -} -template<> inline ext::json::Value& ext::json::Value::operator=( uf::stl::string v ) { - ext::json::base_value::SetString( v.c_str(), ext::json::allocator ); - return *this; -} -template<> inline ext::json::Value& ext::json::Value::operator=( bool v ) { - ext::json::base_value::SetBool(v); - return *this; -} -template<> inline ext::json::Value& ext::json::Value::operator=( int v ) { - ext::json::base_value::SetInt(v); - return *this; -} -template<> inline ext::json::Value& ext::json::Value::operator=( size_t v ) { - ext::json::base_value::SetUint64(v); - return *this; -} -template<> inline ext::json::Value& ext::json::Value::operator=( float v ) { - ext::json::base_value::SetFloat(v); - return *this; -} -template<> inline ext::json::Value& ext::json::Value::operator=( double v ) { - ext::json::base_value::SetDouble(v); - return *this; -} - -template ext::json::Value& ext::json::Document::operator[]( Args... args ) { - const uf::stl::string k(args...); - auto key = rapidjson::StringRef(k.c_str()); - auto it = rapidjson::Document::FindMember(key); - if ( it != rapidjson::Document::MemberEnd() ) - return (ext::json::Value&) it->value; - - // member doesn't exist, make empty object - rapidjson::Document::AddMember(key, ext::json::object(), ext::json::allocator); - return this->operator[](args...); -} -template const ext::json::Value& ext::json::Document::operator[]( Args... args ) const { - const uf::stl::string k(args...); - auto key = rapidjson::StringRef(k.c_str()); - auto it = rapidjson::Document::FindMember(key); - if ( it != rapidjson::Document::MemberEnd() ) - return (const ext::json::Value&) it->value; - - return ext::json::base_value(); -} - -template<> inline bool ext::json::Value::is() const { return IsBool(); } -template<> inline bool ext::json::Value::is() const { return IsInt64(); } -template<> inline bool ext::json::Value::is() const { return IsUint64(); } -template<> inline bool ext::json::Value::is() const { return IsDouble(); } -template<> inline bool ext::json::Value::is() const { return IsDouble(); } -template<> inline bool ext::json::Value::is() const { return IsString(); } - -template<> inline bool ext::json::Value::get() const { return GetBool(); } -template<> inline int ext::json::Value::get() const { return GetInt(); } -template<> inline size_t ext::json::Value::get() const { return GetUint64(); } -template<> inline float ext::json::Value::get() const { return GetDouble(); } -template<> inline double ext::json::Value::get() const { return GetDouble(); } -template<> inline uf::stl::string ext::json::Value::get() const { return GetString(); } - -template inline T ext::json::Value::as() const { - if ( !is() ) return T(); - return get(); -} -template<> inline bool ext::json::Value::as() const { - if ( is() ) return get(); - if ( IsNull() ) return false; - if ( IsNumber() ) return get() != 0; - if ( IsString() ) return get() != ""; - if ( IsObject() ) return !ext::json::keys( *this ).empty(); - if ( IsArray() ) return size() > 0; - return false; -} \ No newline at end of file diff --git a/engine/inc/uf/ext/meshopt/meshopt.h b/engine/inc/uf/ext/meshopt/meshopt.h index ca5f2eb2..39557c27 100644 --- a/engine/inc/uf/ext/meshopt/meshopt.h +++ b/engine/inc/uf/ext/meshopt/meshopt.h @@ -5,6 +5,6 @@ namespace ext { namespace meshopt { - void UF_API optimize( pod::Mesh&, size_t = SIZE_MAX ); + void UF_API optimize( uf::Mesh&, size_t = SIZE_MAX ); } } \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/graphic.h b/engine/inc/uf/ext/opengl/graphic.h index 478796a6..8f561186 100644 --- a/engine/inc/uf/ext/opengl/graphic.h +++ b/engine/inc/uf/ext/opengl/graphic.h @@ -80,10 +80,10 @@ namespace ext { void initialize( const uf::stl::string& = "" ); void destroy(); - template - void initializeMesh( uf::Mesh& mesh, size_t = SIZE_MAX ); - - void initializeAttributes( const pod::Mesh::Attributes& mesh ); + // template + // void initializeMesh( uf::Mesh& mesh, size_t = SIZE_MAX ); + // void initializeAttributes( const uf::Mesh::Attributes& mesh ); + void initializeMesh( uf::Mesh& mesh ); bool hasPipeline( const GraphicDescriptor& descriptor ) const; void initializePipeline(); diff --git a/engine/inc/uf/ext/opengl/graphic.inl b/engine/inc/uf/ext/opengl/graphic.inl index c56607bc..5878ca56 100644 --- a/engine/inc/uf/ext/opengl/graphic.inl +++ b/engine/inc/uf/ext/opengl/graphic.inl @@ -1,6 +1,8 @@ +#if 0 template void ext::opengl::Graphic::initializeMesh( uf::Mesh& mesh, size_t o ) { if ( mesh.indices.empty() ) mesh.initialize( o ); mesh.updateDescriptor(); initializeAttributes( mesh.attributes ); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index 46ad999a..e4084301 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -8,7 +8,7 @@ namespace ext { struct Device; struct UF_API Buffer { - VkDevice device; + ext::vulkan::Device* device = NULL; VkBuffer buffer = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE; VkDescriptorBufferInfo descriptor = { @@ -40,7 +40,9 @@ namespace ext { // RAII ~Buffer(); - void initialize( VkDevice device ); + void initialize( ext::vulkan::Device& device ); + void initialize( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool = VK_DEFAULT_STAGE_BUFFERS ); + void update( const void*, VkDeviceSize, bool = VK_DEFAULT_STAGE_BUFFERS ) const; void destroy(); void aliasBuffer( const Buffer& ); diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index 3d99e577..0ca87ccc 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -10,6 +10,7 @@ namespace ext { namespace vulkan { struct Graphic; + struct UF_API Pipeline { bool aliased = false; @@ -39,6 +40,7 @@ namespace ext { uf::stl::vector getShaders( uf::stl::vector& ); uf::stl::vector getShaders( const uf::stl::vector& ) const; }; + struct UF_API Material { bool aliased = false; Device* device; @@ -64,6 +66,7 @@ namespace ext { bool validate(); }; + struct UF_API Graphic : public Buffers { GraphicDescriptor descriptor; @@ -76,14 +79,28 @@ namespace ext { uf::stl::unordered_map buffers; } metadata; + struct Layout { + uf::stl::vector uniform; + uf::stl::vector storage; + + uf::stl::vector image; + uf::stl::vector image2D; + uf::stl::vector imageCube; + uf::stl::vector image3D; + + uf::stl::vector sampler; + uf::stl::vector input; + } layout; + ~Graphic(); void initialize( const uf::stl::string& = "" ); void destroy(); - template - void initializeMesh( uf::Mesh& mesh, size_t = SIZE_MAX ); - - void initializeAttributes( const pod::Mesh::Attributes& mesh ); + // template + // void initializeMesh( uf::Mesh& mesh ); + // void initializeAttributes( const uf::Mesh::Attributes& mesh ); + + void initializeMesh( uf::Mesh& mesh, bool buffer = true ); bool hasPipeline( const GraphicDescriptor& descriptor ) const; void initializePipeline(); @@ -99,13 +116,6 @@ namespace ext { void record( VkCommandBuffer commandBuffer, size_t pass = 0, size_t draw = 0 ) const; void record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0 ) const; - - bool hasStorage( const uf::stl::string& name ) const; - Buffer& getStorageBuffer( const uf::stl::string& name ); - const Buffer& getStorageBuffer( const uf::stl::string& name ) const; - - uf::Serializer getStorageJson( const uf::stl::string& name, bool cache = true ); - ext::vulkan::userdata_t getStorageUserdata( const uf::stl::string& name, const ext::json::Value& payload ); }; } } diff --git a/engine/inc/uf/ext/vulkan/graphic.inl b/engine/inc/uf/ext/vulkan/graphic.inl index feed3d69..6d4b4a81 100644 --- a/engine/inc/uf/ext/vulkan/graphic.inl +++ b/engine/inc/uf/ext/vulkan/graphic.inl @@ -1,6 +1,8 @@ +#if 0 template void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, size_t o ) { if ( mesh.indices.empty() ) mesh.initialize( o ); mesh.updateDescriptor(); initializeAttributes( mesh.attributes ); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/shader.h b/engine/inc/uf/ext/vulkan/shader.h index b84d8b68..4c4a8a36 100644 --- a/engine/inc/uf/ext/vulkan/shader.h +++ b/engine/inc/uf/ext/vulkan/shader.h @@ -38,6 +38,14 @@ namespace ext { uf::stl::string type = ""; struct Definition { + struct InOut { + uf::stl::string name = ""; + uint32_t index = 0; + uint32_t binding = 0; + uint32_t size = 0; + // int32_t buffer = -1; + ext::vulkan::enums::Image::viewType_t type{}; + }; struct Texture { uf::stl::string name = ""; uint32_t index = 0; @@ -50,12 +58,14 @@ namespace ext { uint32_t index = 0; uint32_t binding = 0; uint32_t size = 0; + // int32_t buffer = -1; }; struct Storage { uf::stl::string name = ""; uint32_t index = 0; uint32_t binding = 0; uint32_t size = 0; + // int32_t buffer = -1; }; struct PushConstant { uf::stl::string name = ""; @@ -75,6 +85,8 @@ namespace ext { } value; }; uf::stl::unordered_map textures; + uf::stl::unordered_map inputs; + uf::stl::unordered_map outputs; uf::stl::unordered_map uniforms; uf::stl::unordered_map storage; uf::stl::unordered_map pushConstants; @@ -106,16 +118,25 @@ namespace ext { inline bool updateUniform( const uf::stl::string& name, const ext::vulkan::userdata_t& userdata ) const { return updateUniform(name, (const void*) userdata, userdata.size() ); } - + bool hasStorage( const uf::stl::string& name ) const; + Buffer& getStorageBuffer( const uf::stl::string& name ); const Buffer& getStorageBuffer( const uf::stl::string& name ) const; + + bool updateStorage( const uf::stl::string& name, const void*, size_t ) const; + inline bool updateStorage( const uf::stl::string& name, const ext::vulkan::userdata_t& userdata ) const { + return updateStorage(name, (const void*) userdata, userdata.size() ); + } + /* uf::Serializer getUniformJson( const uf::stl::string& name, bool cache = true ); bool updateUniform( const uf::stl::string& name, const ext::json::Value& payload ); ext::vulkan::userdata_t getUniformUserdata( const uf::stl::string& name, const ext::json::Value& payload ); + uf::Serializer getStorageJson( const uf::stl::string& name, bool cache = true ); ext::vulkan::userdata_t getStorageUserdata( const uf::stl::string& name, const ext::json::Value& payload ); + */ }; } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/collision/mesh.h b/engine/inc/uf/utils/math/collision/mesh.h index 8f7dff1f..5f036cd8 100644 --- a/engine/inc/uf/utils/math/collision/mesh.h +++ b/engine/inc/uf/utils/math/collision/mesh.h @@ -15,6 +15,7 @@ namespace uf { void setPositions( const uf::stl::vector& ); + #if 0 template void setPositions( const uf::Mesh& mesh ) { this->m_positions.clear(); @@ -25,6 +26,7 @@ namespace uf { for ( auto& vertex : mesh.vertices ) this->m_positions.push_back( vertex.position ); } } + #endif virtual uf::stl::string type() const; virtual pod::Vector3* expand() const; diff --git a/engine/inc/uf/utils/memory/fifo_map.h b/engine/inc/uf/utils/memory/fifo_map.h new file mode 100644 index 00000000..f5f870ff --- /dev/null +++ b/engine/inc/uf/utils/memory/fifo_map.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "./allocator.h" + +#include + +namespace uf { + namespace stl { + template< + class Key, + class T, + class Compare = nlohmann::fifo_map_compare, + #if UF_MEMORYPOOL_USE_STL_ALLOCATOR + class Allocator = std::allocator> + #else + class Allocator = uf::Allocator> + #endif + > + using fifo_map = nlohmann::fifo_map; + } +} \ 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 9d17883f..cfeba1ba 100644 --- a/engine/inc/uf/utils/mesh/grid.h +++ b/engine/inc/uf/utils/mesh/grid.h @@ -1,3 +1,4 @@ +#if 0 #pragma once #include @@ -36,7 +37,6 @@ namespace uf { void insert( uint32_t, uint32_t, uint32_t, const pod::Vector3f&, const pod::Vector3f&, const pod::Vector3f& ); public: ~MeshGrid(); - template void initialize( const uf::Mesh& mesh, size_t = 1 ); @@ -56,4 +56,5 @@ namespace uf { }; }; -#include "grid.inl" \ No newline at end of file +#include "grid.inl" +#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index 74b9bfd4..03edcd96 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -21,40 +21,159 @@ namespace ext { #else typedef uint32_t index_t; #endif - - struct /*UF_API*/ VertexDescriptor { - ext::RENDERER::enums::Format::type_t format = ext::RENDERER::enums::Format::UNDEFINED; // VK_FORMAT_R32G32B32_SFLOAT - size_t offset = 0; // offsetof(Vertex, position) - size_t size = 0; // sizeof(Vertex::position::type_t) - size_t components = 0; // Vertex::position::size - ext::RENDERER::enums::Type::type_t type = 0; // ext::RENDERER::typeToEnum() + struct UF_API AttributeDescriptor { + // essential for vertex input + size_t offset = 0; + size_t size = 0; + ext::RENDERER::enums::Format::type_t format = ext::RENDERER::enums::Format::UNDEFINED; + // not as essential uf::stl::string name = ""; - - bool operator==( const VertexDescriptor& right ) const { return format == right.format && offset == right.offset && size == right.size && components == right.components && type == right.type && name == right.name; } - bool operator!=( const VertexDescriptor& right ) const { return !(*this == right); }; + ext::RENDERER::enums::Type::type_t type = 0; + size_t components = 0; + // somewhat essential + size_t length = 0; + void* pointer = NULL; + + bool operator==( const AttributeDescriptor& right ) const { return + offset == right.offset && + size == right.size && + format == right.format && + name == right.name && + type == right.type && + components == right.components; + } + bool operator!=( const AttributeDescriptor& right ) const { return !(*this == right); }; }; } } -namespace pod { +namespace uf { struct UF_API Mesh { public: - struct Attributes { - struct { - size_t size = 0; - size_t length = 0; - void* pointer = NULL; - } vertex, index; + static bool defaultInterleaved; + typedef uf::stl::vector buffer_t; + struct Attribute { + ext::RENDERER::AttributeDescriptor descriptor; + int32_t buffer = -1; + size_t offset = 0; + }; + 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 stride = 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 - typedef uf::stl::vector descriptors_t; - descriptors_t descriptor; - } attributes; + struct Settings { + bool interleaved = false; + } settings; + } vertex, index, instance, indirect; + uf::stl::vector buffers; + protected: + void _destroy( uf::Mesh::Input& input ); + void _bind( bool interleaved = uf::Mesh::defaultInterleaved ); + void _updateDescriptor( uf::Mesh::Input& input ); + bool _hasV( const uf::Mesh::Input& input, const uf::stl::vector& descriptors ) const; + bool _hasV( const uf::Mesh::Input& input, const uf::Mesh::Input& src ) const; + void _bindV( uf::Mesh::Input& input, const uf::stl::vector& descriptors ); + void _resizeVs( uf::Mesh::Input& input, size_t count ); + void _reserveVs( uf::Mesh::Input& input, size_t count ); + void _insertV( uf::Mesh::Input& input, const void* data ); + void _insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ); + void _insertVs( uf::Mesh::Input& input, const void* data, size_t size ); + + template inline bool _hasV( const uf::Mesh::Input& input ) const { return _hasV( input, T::descriptors ); } + template inline void _bindV( uf::Mesh::Input& input ) { return _bindV( input, T::descriptor ); } + template inline void _insertV( uf::Mesh::Input& input, const T& vertex ) { return _insertV( input, (const void*) &vertex ); } + template inline void _insertVs( uf::Mesh::Input& input, const uf::stl::vector& vs ) { return _insertVs( input, (const void*) vs.data(), vs.size() ); } + + void _bindI( uf::Mesh::Input& input, size_t size, ext::RENDERER::enums::Type::type_t type, size_t count = 1 ); + void _reserveIs( uf::Mesh::Input& input, size_t count, size_t i = 0 ); + void _resizeIs( uf::Mesh::Input& input, size_t count, size_t i = 0 ); + void _insertI( uf::Mesh::Input& input, const void* data, size_t i ); + void _insertI( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ); + void _insertIs( uf::Mesh::Input& input, const void* data, size_t size, size_t i ); + + template inline void _bindI( uf::Mesh::Input& input, size_t indices = 1 ) { return _bindI( input, sizeof(U), ext::RENDERER::typeToEnum(), indices ); } + template inline void _insertI( uf::Mesh::Input& input, U index, size_t i = 0 ) { return _insertI( input, (const void*) &index, i ); } + template inline void _insertIs( uf::Mesh::Input& input, const uf::stl::vector& is, size_t i = 0 ) { return _insertIs( input, (const void*) is.data(), is.size(), i ); } + public: + void initialize(); + void destroy(); + + uf::Mesh interleave() const; + void updateDescriptor(); + void insert( const uf::Mesh& ); + void generateIndices(); - virtual ~Mesh(); - virtual void updateDescriptor(); - virtual void resizeVertices( size_t ); - virtual void resizeIndices( size_t ); + void generateIndirect(); + + bool isInterleaved( size_t ) const; + + void print() const; + + inline bool hasVertex( const uf::stl::vector& descriptors ) const { return _hasV( vertex, descriptors ); } + inline bool hasVertex( const uf::Mesh& mesh ) const { return _hasV( vertex, mesh.vertex ); } + inline void bindVertex( const uf::stl::vector& descriptors ) { return _bindV( vertex, descriptors ); } + inline void resizeVertices( size_t count ) { return _resizeVs( vertex, count ); } + inline void reserveVertices( size_t count ) { return _reserveVs( vertex, count ); } + inline void insertVertex( const void* data ) { return _insertV( vertex, data ); } + inline void insertVertices( const void* data, size_t size ) { return _insertVs( vertex, data, size ); } + inline void insertVertices( const uf::Mesh& mesh ) { return _insertV( vertex, mesh, mesh.vertex ); } + inline void updateVertexDescriptor() { return _updateDescriptor( vertex ); } + + template inline bool hasVertex() const { return _hasV( vertex, T::descriptors ); } + template inline void bindVertex() { return _bindV( vertex, T::descriptor ); } + template inline void insertVertex( const T& v ) { return _insertV( vertex, (const void*) &v ); } + template inline void insertVertices( const uf::stl::vector& vertices ) { return _insertVs( vertex, (const void*) vertices.data(), vertices.size() ); } + + inline void bindIndex( size_t size, ext::RENDERER::enums::Type::type_t type, size_t count = 1 ) { return _bindI( index, size, type, count ); } + inline void reserveIndices( size_t count, size_t i = 0 ) { return _reserveIs( index, count, i ); } + inline void resizeIndices( size_t count, size_t i = 0 ) { return _resizeIs( index, count, i ); } + inline void insertIndex( const void* data, size_t i = 0 ) { return _insertI( index, data, i ); } + inline void insertIndices( const void* data, size_t size, size_t i = 0 ) { return _insertIs( index, data, size, i ); } + inline void insertIndices( const uf::Mesh& mesh ) { return _insertI( index, mesh, mesh.index ); } + inline void updateIndexDescriptor() { return _updateDescriptor( index ); } + + template inline void bindIndex( size_t count = 1 ) { return _bindI( index, sizeof(U), ext::RENDERER::typeToEnum(), count ); } + template inline void insertIndex( U I, size_t i = 0 ) { return _insertI( index, (const void*) &I, i ); } + template inline void insertIndices( const uf::stl::vector& indices, size_t i = 0 ) { return _insertIs( index, (const void*) indices.data(), indices.size(), i ); } + + inline bool hasInstance( const uf::stl::vector& descriptors ) const { return _hasV( instance, descriptors ); } + inline bool hasInstance( const uf::Mesh& mesh ) const { return _hasV( instance, mesh.instance ); } + inline void bindInstance( const uf::stl::vector& descriptors ) { return _bindV( instance, descriptors ); } + inline void resizeInstances( size_t count ) { return _resizeVs( instance, count ); } + inline void reserveInstances( size_t count ) { return _reserveVs( instance, count ); } + inline void insertInstance( const void* data ) { return _insertV( instance, data ); } + inline void insertInstances( const void* data, size_t size ) { return _insertVs( instance, data, size ); } + inline void insertInstances( const uf::Mesh& mesh ) { return _insertV( instance, mesh, mesh.instance ); } + inline void updateInstanceDescriptor() { return _updateDescriptor( instance ); } + + template inline bool hasInstance() const { return _hasV( instance, T::descriptors ); } + template inline void bindInstance() { return _bindV( instance, T::descriptor ); } + template inline void insertInstance( const T& v ) { return _insertV( instance, (const void*) &v ); } + template inline void insertInstances( const uf::stl::vector& instances ) { return _insertVs( instance, (const void*) instances.data(), instances.size() ); } + + inline void bindIndirect( size_t size, ext::RENDERER::enums::Type::type_t type, size_t count = 1 ) { return _bindI( indirect, size, type, count ); } + inline void reserveIndirects( size_t count, size_t i = 0 ) { return _reserveIs( indirect, count, i ); } + inline void resizeIndirects( size_t count, size_t i = 0 ) { return _resizeIs( indirect, count, i ); } + inline void insertIndirect( const void* data, size_t i = 0 ) { return _insertI( indirect, data, i ); } + inline void insertIndirects( const void* data, size_t size, size_t i = 0 ) { return _insertIs( indirect, data, size, i ); } + inline void insertIndirects( const uf::Mesh& mesh ) { return _insertI( indirect, mesh, mesh.indirect ); } + inline void updateIndirectDescriptor() { return _updateDescriptor( indirect ); } + + template inline void bindIndirect( size_t i = 1 ) { return _bindI( indirect, sizeof(U), ext::RENDERER::typeToEnum(), i ); } + template inline void insertIndirect( U v, size_t i = 0 ) { return _insertI( indirect, (const void*) &v, i ); } + template inline void insertIndirects( const uf::stl::vector& indirects, size_t i = 0 ) { return _insertIs( indirect, (const void*) indirects.data(), indirects.size(), i ); } + + template + void bind( bool interleave = uf::Mesh::defaultInterleaved, size_t indices = 1 ) { + bindVertex(); + bindIndex( indices ); + _bind( interleave ); + } }; } @@ -73,13 +192,10 @@ namespace ext { uint32_t renderTarget = 0; uint32_t subpass = 0; - pod::Mesh::Attributes attributes; - size_t indices = 0; - struct { - size_t vertex = 0; - size_t index = 0; - } offsets; + uf::Mesh::Input vertex, index, instance, indirect; + size_t bufferOffset = 0; + } inputs; ext::RENDERER::enums::PrimitiveTopology::type_t topology = ext::RENDERER::enums::PrimitiveTopology::TRIANGLE_LIST; ext::RENDERER::enums::PolygonMode::type_t fill = ext::RENDERER::enums::PolygonMode::FILL; @@ -98,7 +214,9 @@ namespace ext { float clamp = 0; } bias; } depth; + bool invalidated = false; + hash_t hash() const; void parse( ext::json::Value& ); bool operator==( const GraphicDescriptor& right ) const { return this->hash() == right.hash(); } @@ -109,16 +227,16 @@ namespace ext { #undef UF_RENDERER #define UF_VERTEX_DESCRIPTION( TYPE, FORMAT, ATTRIBUTE ) {\ - uf::renderer::enums::Format::FORMAT,\ - offsetof(TYPE, ATTRIBUTE),\ - sizeof(decltype(TYPE::ATTRIBUTE)::type_t),\ - decltype(TYPE::ATTRIBUTE)::size,\ - ext::RENDERER::typeToEnum(),\ - #ATTRIBUTE\ + .offset = offsetof(TYPE, ATTRIBUTE),\ + .size = sizeof(decltype(TYPE::ATTRIBUTE)),\ + .format = uf::renderer::enums::Format::FORMAT,\ + .name = #ATTRIBUTE,\ + .type = ext::RENDERER::typeToEnum(),\ + .components = decltype(TYPE::ATTRIBUTE)::size,\ }, #define UF_VERTEX_DESCRIPTOR( TYPE, ... )\ - uf::stl::vector TYPE::descriptor = { __VA_ARGS__ }; + uf::stl::vector TYPE::descriptor = { __VA_ARGS__ }; #if UF_USE_VULKAN @@ -131,31 +249,6 @@ namespace ext { } #endif -namespace uf { - template - class /*UF_API*/ Mesh : public pod::Mesh { - public: - typedef T vertex_t; - typedef U index_t; - typedef vertex_t vertices_t; - typedef index_t indices_t; - uf::stl::vector vertices; - uf::stl::vector indices; - - void initialize( size_t = SIZE_MAX ); - void destroy(); - - void expand( bool = true ); - uf::Mesh simplify( float = 0.2f ); - void optimize( size_t = SIZE_MAX ); - void insert( const uf::Mesh& mesh ); - - virtual void updateDescriptor(); - virtual void resizeVertices( size_t ); - virtual void resizeIndices( size_t ); - }; -} - namespace pod { struct /*UF_API*/ Vertex_3F2F3F4F { /*alignas(16)*/ pod::Vector3f position; @@ -163,7 +256,7 @@ namespace pod { /*alignas(16)*/ pod::Vector3f normal; /*alignas(16)*/ pod::Vector4f color; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_3F2F3F32B { /*alignas(16)*/ pod::Vector3f position; @@ -171,14 +264,14 @@ namespace pod { /*alignas(16)*/ pod::Vector3f normal; /*alignas(16)*/ pod::Vector4t color; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_3F3F3F { /*alignas(16)*/ pod::Vector3f position; /*alignas(16)*/ pod::Vector3f uv; /*alignas(16)*/ pod::Vector3f normal; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_3F2F3F1UI { /*alignas(16)*/ pod::Vector3f position; @@ -186,83 +279,34 @@ namespace pod { /*alignas(16)*/ pod::Vector3f normal; /*alignas(4)*/ pod::Vector1ui id; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_3F2F3F { /*alignas(16)*/ pod::Vector3f position; /*alignas(8)*/ pod::Vector2f uv; /*alignas(16)*/ pod::Vector3f normal; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_3F2F { /*alignas(16)*/ pod::Vector3f position; /*alignas(8)*/ pod::Vector2f uv; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_2F2F { /*alignas(8)*/ pod::Vector2f position; /*alignas(8)*/ pod::Vector2f uv; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; struct /*UF_API*/ Vertex_3F { /*alignas(16)*/ pod::Vector3f position; - static UF_API uf::stl::vector descriptor; + static UF_API uf::stl::vector descriptor; }; } -#if 0 -namespace uf { - typedef BaseMesh ColoredMesh; - typedef BaseMesh Mesh; - typedef BaseMesh LineMesh; - template - struct MeshDescriptor { - struct { - /*alignas(16)*/ pod::Matrix4f model; - /*alignas(16)*/ pod::Matrix4f view[N]; - /*alignas(16)*/ pod::Matrix4f projection[N]; - } matrices; - /*alignas(16)*/ pod::Vector4f color = { 1, 1, 1, 0 }; - }; -} -#endif - -#include -namespace pod { - struct UF_API VaryingMesh : public pod::Mesh { - pod::PointeredUserdata userdata; - - pod::Mesh& get(); - const pod::Mesh& get() const; - void destroy(); - - virtual void updateDescriptor(); - virtual void resizeVertices( size_t ); - virtual void resizeIndices( size_t ); - - template - bool is() const; - - template - uf::Mesh& get(); - - template - const uf::Mesh& get() const; - - template - void set( const uf::Mesh& = {} ); - - template - void insert( const pod::VaryingMesh& mesh ); - - template - void insert( const uf::Mesh& mesh ); - }; -} #include #include "mesh.inl" \ No newline at end of file diff --git a/engine/inc/uf/utils/mesh/mesh.inl b/engine/inc/uf/utils/mesh/mesh.inl index df79b185..ae9335a2 100644 --- a/engine/inc/uf/utils/mesh/mesh.inl +++ b/engine/inc/uf/utils/mesh/mesh.inl @@ -1,3 +1,4 @@ +#if 0 template void uf::Mesh::initialize( size_t o ) { this->optimize(o); @@ -44,12 +45,13 @@ void uf::Mesh::expand( bool check ) { template void uf::Mesh::updateDescriptor() { attributes.vertex.size = sizeof(vertex_t); - attributes.index.size = sizeof(indices_t); - attributes.vertex.pointer = &this->vertices[0]; - attributes.index.pointer = &this->indices[0]; attributes.vertex.length = this->vertices.size(); + attributes.vertex.pointer = &this->vertices[0]; + attributes.vertex.descriptor = vertex_t::descriptor; + + attributes.index.size = sizeof(indices_t); attributes.index.length = this->indices.size(); - attributes.descriptor = vertex_t::descriptor; + attributes.index.pointer = &this->indices[0]; } template void uf::Mesh::destroy() { @@ -105,26 +107,26 @@ bool pod::VaryingMesh::is() const { #if 0 return uf::pointeredUserdata::is>(); #else - if ( attributes.descriptor.size() != T::descriptor.size() || + if ( attributes.vertex.descriptor.size() != T::descriptor.size() || // vertex types are the same size attributes.vertex.size != sizeof(T) || // index types are the same size attributes.index.size != sizeof(U) ) return false; - for ( size_t i = 0; i < attributes.descriptor.size(); ++i ) { - if ( attributes.descriptor[i].offset != attributes.descriptor[i].offset || attributes.descriptor[i].size != attributes.descriptor[i].size || attributes.descriptor[i].components != attributes.descriptor[i].components ) return false; + for ( size_t i = 0; i < attributes.vertex.descriptor.size(); ++i ) { + if ( attributes.vertex.descriptor[i].offset != attributes.vertex.descriptor[i].offset || attributes.vertex.descriptor[i].size != attributes.vertex.descriptor[i].size || attributes.vertex.descriptor[i].components != attributes.vertex.descriptor[i].components ) return false; } return true; #if 0 return // descriptors are the same size - attributes.descriptor.size() == T::descriptor.size() && + attributes.vertex.descriptor.size() == T::descriptor.size() && // vertex types are the same size attributes.vertex.size == sizeof(T) && // index types are the same size attributes.index.size == sizeof(U) && // attributes are the same - std::equal( attributes.descriptor.begin(), attributes.descriptor.end(), T::descriptor.begin() ); + std::equal( attributes.vertex.descriptor.begin(), attributes.vertex.descriptor.end(), T::descriptor.begin() ); #endif #endif } @@ -157,4 +159,5 @@ template void pod::VaryingMesh::insert( const uf::Mesh& mesh ) { get().insert( mesh ); updateDescriptor(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index 920f8721..7b8f11e2 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -139,6 +139,7 @@ uf::stl::string uf::Asset::load( const uf::stl::string& uri, const uf::stl::stri UF_MSG_ERROR("Failed to load `" << filename << "`: Hash mismatch; expected " << hash << ", got " << actual); return ""; } + #define UF_ASSET_REGISTER(type)\ auto& container = this->getContainer();\ if ( !ext::json::isNull( map[extension][uri]["index"] ) ) return filename;\ @@ -172,29 +173,17 @@ uf::stl::string uf::Asset::load( const uf::stl::string& uri, const uf::stl::stri auto& metadata = this->getComponent(); #if UF_USE_OPENGL_FIXED_FUNCTION - // force disable use of a texture atlas, for now metadata[uri]["flags"]["ATLAS"] = false; metadata[uri]["flags"]["SEPARATE"] = true; - // metadata[uri]["flags"]["NORMALS"] = true; - #else - // metadata[uri]["flags"]["ATLAS"] = true; + #elif UF_GRAPH_INDIRECT_DRAW + metadata[uri]["flags"]["ATLAS"] = false; + metadata[uri]["flags"]["SEPARATE"] = false; #endif - uf::graph::load_mode_t LOAD_FLAGS = 0; - #define LOAD_FLAG(name)\ - if ( metadata[uri]["flags"][#name].as() )\ - LOAD_FLAGS |= uf::graph::LoadMode::name; - - LOAD_FLAG(ATLAS) // = 0x1 << 1, - LOAD_FLAG(INVERT) // = 0x1 << 2, - LOAD_FLAG(TRANSFORM) // = 0x1 << 3, - LOAD_FLAG(SKINNED) // = 0x1 << 4, - - asset = uf::graph::load( filename, LOAD_FLAGS, metadata[uri] ); + asset = uf::graph::load( filename, metadata[uri] ); uf::graph::process( asset ); 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 )); if ( !asset.metadata["debug"]["no cleanup"].as() ) uf::graph::cleanup( asset ); - //uf::graph::process( asset ); } else { UF_MSG_ERROR("Failed to parse `" + filename + "`: Unimplemented extension: " + extension + " or category: " + category ); } diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 551aec73..34056040 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #if UF_ENV_DREAMCAST @@ -13,6 +14,30 @@ #define UF_GRAPH_LOAD_MULTITHREAD 1 #endif +pod::Graph::Storage uf::graph::storage; + +UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Base, + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, st) +); +UF_VERTEX_DESCRIPTOR(uf::graph::mesh::ID, + UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32_SFLOAT, st) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, tangent) +); +UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned, + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32_SFLOAT, st) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, tangent) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16B16A16_SINT, joints) + UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32A32_SFLOAT, weights) +); + namespace { void initializeShaders( pod::Graph& graph, uf::Object& entity ) { auto& graphic = entity.getComponent(); @@ -154,12 +179,12 @@ namespace { } } { - for ( auto& texture : graph.textures ) { - if ( !texture.bind ) continue; - graphic.material.textures.emplace_back().aliasTexture(texture.texture); + for ( auto& t : graph.textures ) { + auto& texture2D = uf::graph::storage.texture2Ds[t]; + graphic.material.textures.emplace_back().aliasTexture(uf::graph::storage.texture2Ds[t]); } - for ( auto& sampler : graph.samplers ) { - graphic.material.samplers.emplace_back( sampler ); + for ( auto& s : graph.samplers ) { + graphic.material.samplers.emplace_back( uf::graph::storage.samplers[s] ); } // bind scene's voxel texture if ( uf::renderer::settings::experimental::vxgi ) { @@ -208,6 +233,67 @@ void uf::graph::process( uf::Object& entity ) { for ( auto index : graph.root.children ) process( graph, index, entity ); } void uf::graph::process( pod::Graph& graph ) { + // + if ( !graph.root.entity ) graph.root.entity = new uf::Object; + + // process lightmap + + // add atlas + + // setup textures + + // process nodes + for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity ); + + // setup meshes + if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { + initializeGraphics( graph, *graph.root.entity ); + } + + // setup collision +#if 0 + graph.root.entity->process([&]( uf::Entity* entity ) { + auto& metadata = entity->getComponent(); + size_t index = metadata["system"]["graph"]["index"].as(); + auto& node = graph.nodes[nodeName]; + auto& nodeName = node.name; + + uf::Mesh* mesh = NULL; + if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { + mesh = &uf::graphs::storage[graph.meshes[node.mesh]]; + } + + if ( !ext::json::isNull( graph.metadata["tags"][nodeName] ) ) { + auto& info = graph.metadata["tags"][nodeName]; + if ( ext::json::isObject( info["collision"] ) ) { + uf::stl::string type = info["collision"]["type"].as(); + float mass = info["collision"]["mass"].as(); + bool dynamic = !info["collision"]["static"].as(); + bool recenter = info["collision"]["recenter"].as(); + pod::Vector3f corner = (max - min) * 0.5f; + pod::Vector3f center = (max + min) * 0.5f; + #if UF_USE_BULLET + if ( type == "mesh" && mesh ) { + auto& collider = ext::bullet::create( entity->as(), mesh, dynamic ); + if ( recenter ) collider.transform.position = center; + } else if ( type == "bounding box" ) { + auto& collider = ext::bullet::create( entity->as(), corner, mass ); + collider.shared = true; + if ( recenter ) collider.transform.position = center - transform.position; + } else if ( type == "capsule" ) { + float radius = info["collision"]["radius"].as(); + float height = info["collision"]["height"].as(); + auto& collider = ext::bullet::create( entity->as(), radius, height, mass ); + collider.shared = true; + if ( recenter ) collider.transform.position = center - transform.position; + } + #endif + } + } + }); +#endif + +#if 0 //UF_MSG_DEBUG( "Processing graph..." ); // for OpenGL (immediate mode), implicitly load a lightmap so I don't have to keep commenting it out for the Vulkan version #if UF_USE_OPENGL @@ -251,17 +337,6 @@ void uf::graph::process( pod::Graph& graph ) { } // invalidate our ST's if we're in OpenGL } -#if 0 || UF_USE_OPENGL - if ( !lightmapped ) { - - #if UF_GRAPH_EXPERIMENTAL - - #else - for ( auto& mesh : graph.meshes ) for ( auto& v : mesh.vertices ) v.st = pod::Vector2f{0,0}; - #endif - - } -#endif // using an atlas texture will not bind other textures if ( graph.metadata["flags"]["ATLAS"].as() && graph.atlas.generated() ) { @@ -392,18 +467,18 @@ void uf::graph::process( pod::Graph& graph ) { //UF_MSG_DEBUG( "Post-processing nodes..." ); graph.root.entity->process([&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; + if ( !entity->hasComponent() ) return; //UF_MSG_DEBUG( "Post-processing node...: " << uf::string::toString( entity->as() ) ); auto& metadata = entity->getComponent(); uf::stl::string nodeName = metadata["system"]["graph"]["name"].as( entity->getName() ); auto& transform = entity->getComponent>(); - #if UF_GRAPH_EXPERIMENTAL - auto& mesh = entity->getComponent().get(); + #if UF_GRAPH_VARYING_MESH + auto& mesh = entity->getComponent().get(); mesh.updateDescriptor(); #else - auto& mesh = entity->getComponent(); + auto& mesh = entity->getComponent(); #endif pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; @@ -411,7 +486,7 @@ void uf::graph::process( pod::Graph& graph ) { auto model = uf::transform::model( transform ); - #if UF_GRAPH_EXPERIMENTAL + #if UF_GRAPH_VARYING_MESH size_t indices = mesh.attributes.index.length; size_t indexStride = mesh.attributes.index.size; uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer; @@ -420,10 +495,10 @@ void uf::graph::process( pod::Graph& graph ) { size_t vertexStride = mesh.attributes.vertex.size; uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; - uf::renderer::VertexDescriptor vertexAttributePosition; - uf::renderer::VertexDescriptor vertexAttributeNormal; + uf::renderer::AttributeDescriptor vertexAttributePosition; + uf::renderer::AttributeDescriptor vertexAttributeNormal; - for ( auto& attribute : mesh.attributes.descriptor ) { + for ( auto& attribute : mesh.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; } @@ -467,7 +542,7 @@ void uf::graph::process( pod::Graph& graph ) { if ( graph.metadata["flags"]["NORMALS"].as() ) { // bool invert = false; bool INVERTED = graph.metadata["flags"]["INVERT"].as(); - #if UF_GRAPH_EXPERIMENTAL + #if UF_GRAPH_VARYING_MESH if ( mesh.attributes.index.pointer ) { uint32_t indexes[3] = {}; pod::Vector3f positions[3] = {}; @@ -552,7 +627,7 @@ void uf::graph::process( pod::Graph& graph ) { auto& graphic = entity->getComponent(); graphic.initialize(); #if 1 - #if UF_GRAPH_EXPERIMENTAL + #if UF_GRAPH_VARYING_MESH graphic.initializeAttributes( mesh.attributes ); #else graphic.initializeMesh( mesh ); @@ -589,7 +664,7 @@ void uf::graph::process( pod::Graph& graph ) { if ( graphic.buffers[i].usage & uf::renderer::enums::Buffer::INDEX ) indexBuffer = i; } if ( indexBuffer >= 0 && !indices.empty() && indices.size() % 3 == 0 ) { - graphic.updateBuffer( + shader.updateBuffer( (const void*) indices.data(), indices.size() * mesh.attributes.index.size, indexBuffer @@ -599,8 +674,8 @@ void uf::graph::process( pod::Graph& graph ) { #endif #endif } - if ( entity->hasComponent() ) { - auto& mesh = entity->getComponent(); + if ( entity->hasComponent() ) { + auto& mesh = entity->getComponent(); auto& meshAttributes = entity->getComponent(); meshAttributes = mesh; } @@ -639,6 +714,7 @@ void uf::graph::process( pod::Graph& graph ) { graph.metadata["extents"]["min"] = uf::vector::encode( extentMin * graph.metadata["extents"]["scale"].as(1.0f) ); graph.metadata["extents"]["max"] = uf::vector::encode( extentMax * graph.metadata["extents"]["scale"].as(1.0f) ); //UF_MSG_DEBUG( "Processed graph" ); +#endif } void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) { auto& node = graph.nodes[index]; @@ -647,7 +723,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) // for dreamcast, ignore lights if we're baked #if UF_USE_OPENGL if ( graph.metadata["lightmapped"].as() ) { - for ( auto& l : graph.lights ) if ( l.name == node.name ) return; + if ( graph.lights.count(node.name) > 0 ) return; } #endif //UF_MSG_DEBUG( "Loading " << node.name ); @@ -662,6 +738,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) auto& metadata = entity.getComponent(); auto& metadataJson = entity.getComponent(); metadataJson["system"]["graph"]["name"] = node.name; + metadataJson["system"]["graph"]["index"] = index; // on systems where frametime is very, very important, we can set all static nodes to not tick // tie to tag if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) { @@ -692,8 +769,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) } // create as light { - for ( auto& l : graph.lights ) { - if ( l.name != node.name ) continue; + if ( graph.lights.count(node.name) > 0 ) { + auto& l = graph.lights[node.name]; #if UF_ENV_DREAMCAST metadata.system.ignoreGraph = graph.metadata["debug"]["static"].as(); #endif @@ -719,14 +796,14 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) if ( key == "transform" ) return; metadataLight[key] = value; }); - if ( graph.metadata["lightmapped"].as() && !(metadataLight["shadows"].as() || metadataLight["dynamic"].as()) ) continue; - auto& metadataJson = entity.getComponent(); - entity.load("/light.json"); - // copy - ext::json::forEach( metadataLight, [&]( const uf::stl::string& key, ext::json::Value& value ) { - metadataJson["light"][key] = value; - }); - break; + if ( !(graph.metadata["lightmapped"].as() && !(metadataLight["shadows"].as() || metadataLight["dynamic"].as())) ) { + auto& metadataJson = entity.getComponent(); + entity.load("/light.json"); + // copy + ext::json::forEach( metadataLight, [&]( const uf::stl::string& key, ext::json::Value& value ) { + metadataJson["light"][key] = value; + }); + } } } @@ -765,25 +842,32 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) } } } + if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { + auto& nodeMesh = graph.meshes[node.mesh]; + auto& mesh = entity.getComponent(); + + } + +#if 0 // copy mesh if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { auto& nodeMesh = graph.meshes[node.mesh]; - auto& mesh = entity.getComponent(); + auto& mesh = entity.getComponent(); // preprocess mesh - #if UF_GRAPH_EXPERIMENTAL + #if UF_GRAPH_VARYING_MESH { size_t vertices = nodeMesh.attributes.vertex.length; size_t vertexStride = nodeMesh.attributes.vertex.size; uint8_t* vertexPointer = (uint8_t*) nodeMesh.attributes.vertex.pointer; - uf::renderer::VertexDescriptor vertexAttributeId; + uf::renderer::AttributeDescriptor vertexAttributeId; - for ( auto& attribute : nodeMesh.attributes.descriptor ) if ( attribute.name == "id" ) vertexAttributeId = attribute; + for ( auto& attribute : nodeMesh.attributes.vertex.descriptor ) if ( attribute.name == "id" ) vertexAttributeId = attribute; UF_ASSERT( vertexAttributeId.name != "" ); for ( size_t currentIndex = 0; currentIndex < vertices; ++currentIndex ) { uint8_t* vertexSrc = vertexPointer + (currentIndex * vertexStride); - pod::Vector& id = *((pod::Vector*) (vertexSrc + vertexAttributeId.offset)); + pod::Vector& id = *((pod::Vector*) (vertexSrc + vertexAttributeId.offset)); id.x = node.index; } } @@ -798,8 +882,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) #endif if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { - auto& mesh = graph.root.entity->getComponent(); - #if UF_GRAPH_EXPERIMENTAL + auto& mesh = graph.root.entity->getComponent(); + #if UF_GRAPH_VARYING_MESH if ( nodeMesh.is() ) mesh.insert( nodeMesh ); else if ( nodeMesh.is() ) mesh.insert( nodeMesh ); else if ( nodeMesh.is() ) mesh.insert( nodeMesh ); @@ -843,15 +927,16 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) ); } } +#endif //UF_MSG_DEBUG( "Loaded " << node.name ); for ( auto index : node.children ) uf::graph::process( graph, index, entity ); } void uf::graph::cleanup( pod::Graph& graph ) { - for ( auto& m : graph.meshes ) m.destroy(); +// for ( auto& m : graph.meshes ) m.destroy(); - graph.images.clear(); - graph.meshes.clear(); - graph.atlas.clear(); +// graph.images.clear(); +// graph.meshes.clear(); +// graph.atlas.clear(); } void uf::graph::override( pod::Graph& graph ) { graph.settings.animations.override.a = 0; @@ -892,6 +977,7 @@ void uf::graph::override( pod::Graph& graph ) { void uf::graph::initialize( pod::Graph& graph ) { graph.root.entity->initialize(); graph.root.entity->process([&]( uf::Entity* entity ) { + #if 0 //UF_MSG_DEBUG( "Initializing... " << uf::string::toString( entity->as() ) ); if ( !entity->hasComponent() ) { if ( entity->getUid() == 0 ) entity->initialize(); @@ -902,6 +988,7 @@ void uf::graph::initialize( pod::Graph& graph ) { uf::instantiator::bind( "GraphBehavior", *entity ); uf::instantiator::unbind( "RenderBehavior", *entity ); + #endif if ( entity->getUid() == 0 ) entity->initialize(); //UF_MSG_DEBUG( "Initialized " << uf::string::toString( entity->as() ) ); }); @@ -983,6 +1070,7 @@ UPDATE: for ( auto& node : graph.nodes ) uf::graph::update( graph, node ); } void uf::graph::update( pod::Graph& graph, pod::Node& node ) { +#if 0 if ( node.skin >= 0 ) { pod::Matrix4f nodeMatrix = uf::graph::matrix( graph, node.index ); pod::Matrix4f inverseTransform = uf::matrix::inverse( nodeMatrix ); @@ -1001,104 +1089,109 @@ void uf::graph::update( pod::Graph& graph, pod::Node& node ) { auto& graphic = node.entity->getComponent(); if ( node.buffers.joint < graphic.buffers.size() ) { auto& buffer = graphic.buffers.at(node.buffers.joint); - graphic.updateBuffer( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f), buffer ); + shader.updateBuffer( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f), buffer ); } } } +#endif } void uf::graph::destroy( pod::Graph& graph ) { +#if 0 for ( auto& t : graph.textures ) { t.texture.destroy(); } for ( auto& m : graph.meshes ) { m.destroy(); } +#endif } namespace { - uf::Image decodeImage( ext::json::Value& json, const pod::Graph& graph ) { - uf::Image image; + uf::stl::string decodeImage( ext::json::Value& json, const pod::Graph& graph ) { + if ( json.is() ) { + const uf::stl::string directory = uf::io::directory( graph.name ); + const uf::stl::string filename = uf::io::filename( json.as() ); + const uf::stl::string name = directory + "/" + filename; + + uf::Image& image = uf::graph::storage.images[name]; + image.open(name, false); + return name; + } + auto name = json["name"].as(); + + uf::Image& image = uf::graph::storage.images[name]; auto size = uf::vector::decode( json["size"], pod::Vector2ui{} ); size_t bpp = json["bpp"].as(); size_t channels = json["channels"].as(); auto pixels = uf::base64::decode( json["data"].as() ); image.loadFromBuffer( &pixels[0], size, bpp, channels, true ); - return image; - } - uf::Image& decode( ext::json::Value& json, uf::Image& image, const pod::Graph& graph ) { - return image = decodeImage( json, graph ); + + return name; } - pod::Texture decodeTexture( ext::json::Value& json, const pod::Graph& graph ) { - pod::Texture texture; - texture.name = json["name"].as(); - texture.storage.index = json["index"].is() ? json["index"].as() : -1; - texture.storage.sampler = json["sampler"].is() ? json["sampler"].as() : -1; - texture.storage.remap = json["remap"].is() ? json["remap"].as() : -1; - texture.storage.blend = json["blend"].is() ? json["blend"].as() : -1; - texture.storage.lerp = uf::vector::decode( json["lerp"], pod::Vector4f{} ); - return texture; - } - pod::Texture& decode( ext::json::Value& json, pod::Texture& texture, const pod::Graph& graph ) { - return texture = decodeTexture( json, graph ); + uf::stl::string decodeTexture( ext::json::Value& json, const pod::Graph& graph ) { + auto name = json["name"].as(); + + pod::Texture& texture = uf::graph::storage.textures[name]; + texture.index = json["index"].as(texture.index); + texture.sampler = json["sampler"].as(texture.sampler); + texture.remap = json["remap"].as(texture.remap); + texture.blend = json["blend"].as(texture.blend); + texture.lerp = uf::vector::decode( json["lerp"], pod::Vector4f{} ); + + return name; } - uf::renderer::Sampler decodeSampler( ext::json::Value& json, const pod::Graph& graph ) { - uf::renderer::Sampler sampler; + uf::stl::string decodeSampler( ext::json::Value& json, const pod::Graph& graph ) { + auto name = json["name"].as(); + + uf::renderer::Sampler& sampler = uf::graph::storage.samplers[name]; sampler.descriptor.filter.min = (uf::renderer::enums::Filter::type_t) json["min"].as(); sampler.descriptor.filter.mag = (uf::renderer::enums::Filter::type_t) json["mag"].as(); sampler.descriptor.addressMode.u = (uf::renderer::enums::AddressMode::type_t) json["u"].as(); sampler.descriptor.addressMode.v = (uf::renderer::enums::AddressMode::type_t) json["v"].as(); sampler.descriptor.addressMode.w = sampler.descriptor.addressMode.v; - return sampler; - } - uf::renderer::Sampler& decode( ext::json::Value& json, uf::renderer::Sampler& sampler, const pod::Graph& graph ) { - return sampler = decodeSampler( json, graph ); + + return name; } - pod::Material decodeMaterial( ext::json::Value& json, const pod::Graph& graph ) { - pod::Material material; - material.name = json["name"].as(); - material.alphaMode = json["alphaMode"].as(); - material.storage.colorBase = uf::vector::decode( json["base"], pod::Vector4f{} ); - material.storage.colorEmissive = uf::vector::decode( json["emissive"], pod::Vector4f{} ); - material.storage.factorMetallic = json["fMetallic"].as(); - material.storage.factorRoughness = json["fRoughness"].as(); - material.storage.factorOcclusion = json["fOcclusion"].as(); - material.storage.factorAlphaCutoff = json["fAlphaCutoff"].as(); - material.storage.indexAlbedo = json["iAlbedo"].is() ? json["iAlbedo"].as() : -1; - material.storage.indexNormal = json["iNormal"].is() ? json["iNormal"].as() : -1; - material.storage.indexEmissive = json["iEmissive"].is() ? json["iEmissive"].as() : -1; - material.storage.indexOcclusion = json["iOcclusion"].is() ? json["iOcclusion"].as() : -1; - material.storage.indexMetallicRoughness = json["iMetallicRoughness"].is() ? json["iMetallicRoughness"].as() : -1; - material.storage.modeAlpha = json["modeAlpha"].as(); - return material; - } - pod::Material& decode( ext::json::Value& json, pod::Material& material, const pod::Graph& graph ) { - return material = decodeMaterial( json, graph ); + uf::stl::string decodeMaterial( ext::json::Value& json, const pod::Graph& graph ) { + auto name = json["name"].as(); + + pod::Material& material = uf::graph::storage.materials[name]; + material.colorBase = uf::vector::decode( json["base"], material.colorBase ); + material.colorEmissive = uf::vector::decode( json["emissive"], material.colorEmissive ); + material.factorMetallic = json["fMetallic"].as(material.factorMetallic); + material.factorRoughness = json["fRoughness"].as(material.factorRoughness); + material.factorOcclusion = json["fOcclusion"].as(material.factorOcclusion); + material.factorAlphaCutoff = json["fAlphaCutoff"].as(material.factorAlphaCutoff); + material.indexAlbedo = json["iAlbedo"].as(material.indexAlbedo); + material.indexNormal = json["iNormal"].as(material.indexNormal); + material.indexEmissive = json["iEmissive"].as(material.indexEmissive); + material.indexOcclusion = json["iOcclusion"].as(material.indexOcclusion); + material.indexMetallicRoughness = json["iMetallicRoughness"].as(material.indexMetallicRoughness); + material.modeAlpha = json["modeAlpha"].as(material.modeAlpha); + + return name; } pod::Light decodeLight( ext::json::Value& json, const pod::Graph& graph ) { pod::Light light; - light.name = json["name"].as(); - light.color = uf::vector::decode( json["color"], pod::Vector3f{} ); - light.intensity = json["intensity"].as(); - light.range = json["range"].as(); + light.color = uf::vector::decode( json["color"], light.color ); + light.intensity = json["intensity"].as(light.intensity); + light.range = json["range"].as(light.range); return light; } - pod::Light& decode( ext::json::Value& json, pod::Light& light, const pod::Graph& graph ) { - return light = decodeLight( json, graph ); - } pod::Animation decodeAnimation( ext::json::Value& json, const pod::Graph& graph ) { pod::Animation animation; - animation.name = json["name"].as(); - animation.start = json["start"].as(); - animation.end = json["end"].as(); + animation.name = json["name"].as(animation.name); + animation.start = json["start"].as(animation.start); + animation.end = json["end"].as(animation.end); ext::json::forEach( json["samplers"], [&]( ext::json::Value& value ){ auto& sampler = animation.samplers.emplace_back(); - sampler.interpolator = value["interpolator"].as(); + sampler.interpolator = value["interpolator"].as(sampler.interpolator); sampler.inputs.reserve( value["inputs"].size() ); ext::json::forEach( value["inputs"], [&]( ext::json::Value& input ){ @@ -1113,19 +1206,16 @@ namespace { ext::json::forEach( json["channels"], [&]( ext::json::Value& value ){ auto& channel = animation.channels.emplace_back(); - channel.path = value["path"].as(); - channel.node = value["node"].as(); - channel.sampler = value["sampler"].as(); + channel.path = value["path"].as(channel.path); + channel.node = value["node"].as(channel.node); + channel.sampler = value["sampler"].as(channel.sampler); }); return animation; } - pod::Animation& decode( ext::json::Value& json, pod::Animation& animation, const pod::Graph& graph ) { - return animation = decodeAnimation( json, graph ); - } pod::Skin decodeSkin( ext::json::Value& json, const pod::Graph& graph ) { pod::Skin skin; - skin.name = json["name"].as(); + skin.name = json["name"].as(skin.name); skin.joints.reserve( json["joints"].size() ); ext::json::forEach( json["joints"], [&]( ext::json::Value& value ){ @@ -1139,300 +1229,116 @@ namespace { return skin; } - pod::Skin& decode( ext::json::Value& json, pod::Skin& skin, const pod::Graph& graph ) { - return skin = decodeSkin( json, graph ); - } - pod::Graph::Mesh decodeMesh( ext::json::Value& json, const pod::Graph& graph ) { - pod::Graph::Mesh mesh; - ext::json::forEach( json["attributes"], [&]( ext::json::Value& value ){ - auto& attribute = mesh.attributes.descriptor.emplace_back(); - attribute.format = (uf::renderer::enums::Format::type_t) value["format"].as(); - attribute.offset = value["offset"].as(); - attribute.size = value["size"].as(); - attribute.components = value["components"].as(); - attribute.type = (uf::renderer::enums::Type::type_t) value["type"].as(); - attribute.name = value["name"].as(); + uf::stl::vector decodeDrawCommand( ext::json::Value& json, const pod::Graph& graph ) { + uf::stl::vector drawCommands; + drawCommands.reserve( json.size() ); + ext::json::forEach( json, [&]( ext::json::Value& value ){ + auto& drawCommand = drawCommands.emplace_back(); + drawCommand.indices = value["indices"].as(drawCommand.indices); + drawCommand.instances = value["instances"].as(drawCommand.instances); + drawCommand.indexID = value["indexID"].as(drawCommand.indexID); + drawCommand.vertexID = value["vertexID"].as(drawCommand.vertexID); + + drawCommand.instanceID = value["instanceID"].as(drawCommand.instanceID); + drawCommand.materialID = value["materialID"].as(drawCommand.materialID); + drawCommand.objectID = value["objectID"].as(drawCommand.objectID); + drawCommand.vertices = value["vertices"].as(drawCommand.vertices); }); - #if UF_GRAPH_EXPERIMENTAL - size_t vertices = (mesh.attributes.vertex.length = json["metadata"]["vertices"]["count"].as()); - size_t vertexStride = (mesh.attributes.vertex.size = json["metadata"]["vertices"]["size"].as()); - - size_t indices = (mesh.attributes.index.length = json["metadata"]["indices"]["count"].as()); - size_t indexStride = (mesh.attributes.index.size = json["metadata"]["indices"]["size"].as()); - - if ( mesh.is() ) { - mesh.set(); - } - else if ( mesh.is() ) { - mesh.set(); - } - else if ( mesh.is() ) { - mesh.set(); - } else { - UF_EXCEPTION("unknown mesh type"); - } - mesh.resizeVertices( vertices ); - mesh.resizeIndices( indices ); - mesh.updateDescriptor(); - - uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; - uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer; - - // vertices are encoded as a raw buffer, referenced as a filename - if ( json["vertices"].is() ) { - const uf::stl::string filename = json["vertices"].as(); - const uf::stl::string directory = uf::io::directory( graph.name ); - const auto buffer = uf::io::readAsBuffer( directory + "/" + filename ); - UF_ASSERT( buffer.size() % vertexStride == 0 ); - memcpy( vertexPointer, buffer.data(), buffer.size() ); - // vertices are encoded as a JSON array - } else if ( ext::json::isArray( json["vertices"] ) ) { - // UF_EXCEPTION("todo: not implemented yet"); - } else { - if ( mesh.is() ) { - auto& m = mesh.get(); - ext::json::forEach( json["vertices"], [&]( size_t currentIndex, ext::json::Value& value ){ - uint_fast8_t attr = 0; - m.vertices[currentIndex] = uf::graph::mesh::Base{ - .position = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .uv = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .st = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .id = uf::vector::decode( value[attr++], pod::Vector{} ), - }; - }); - } - else if ( mesh.is() ) { - auto& m = mesh.get(); - ext::json::forEach( json["vertices"], [&]( size_t currentIndex, ext::json::Value& value ){ - uint_fast8_t attr = 0; - m.vertices[currentIndex] = uf::graph::mesh::ID{ - .position = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .uv = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .st = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .normal = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .tangent = uf::vector::decode( value[attr++], pod::Vector4f{} ), - .id = uf::vector::decode( value[attr++], pod::Vector{} ), - }; - }); - } - else if ( mesh.is() ) { - auto& m = mesh.get(); - ext::json::forEach( json["vertices"], [&]( size_t currentIndex, ext::json::Value& value ){ - uint_fast8_t attr = 0; - m.vertices[currentIndex] = uf::graph::mesh::Skinned{ - .position = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .uv = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .st = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .normal = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .tangent = uf::vector::decode( value[attr++], pod::Vector4f{} ), - .id = uf::vector::decode( value[attr++], pod::Vector{} ), - .joints = uf::vector::decode( value[attr++], pod::Vector{} ), - .weights = uf::vector::decode( value[attr++], pod::Vector4f{} ), - }; - }); - } else { - ext::json::forEach( json["vertices"], [&]( size_t currentIndex, ext::json::Value& value ){ - uint_fast8_t attr = 0; - uint8_t* vertexSrc = vertexPointer + (currentIndex * vertexStride); - for ( auto& attribute : mesh.attributes.descriptor ) { - //vertexSrc + attribute.offset; - if ( attribute.name == "id" || attribute.name == "joints" ) - switch ( attribute.components ) { - case 1: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - case 2: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - case 3: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - case 4: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - } - else - switch ( attribute.components ) { - case 1: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - case 2: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - case 3: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - case 4: *((pod::Vector*) (vertexSrc + attribute.offset)) = uf::vector::decode( value[attr++], pod::Vector{} ); break; - } - } - }); - UF_EXCEPTION("unknown mesh type"); - } - } - - // indices are encoded as a raw buffer, referenced as a filename - if ( json["indices"].is() ) { - const uf::stl::string filename = json["indices"].as(); - const uf::stl::string directory = uf::io::directory( graph.name ); - const auto buffer = uf::io::readAsBuffer( directory + "/" + filename ); - UF_ASSERT( buffer.size() % indexStride == 0 ); - memcpy( indexPointer, buffer.data(), buffer.size() ); - // indices are encoded as a JSON array - } else if ( ext::json::isArray( json["indices"] ) ) { - ext::json::forEach( json["indices"], [&]( size_t currentIndex, ext::json::Value& value ){ - size_t index = value.as(); - uint8_t* indexSrc = indexPointer + (currentIndex * indexStride); - switch ( indexStride ) { - case sizeof( uint8_t): *(( uint8_t*) indexSrc) = index; break; - case sizeof(uint16_t): *((uint16_t*) indexSrc) = index; break; - case sizeof(uint32_t): *((uint32_t*) indexSrc) = index; break; - } - }); - } else { - UF_MSG_ERROR("invalid indices information encountered while decoding mesh: " << graph.name ); - } - - #if UF_ENV_DREAMCAST - // for Dreamcast, convert mesh to a smaller type - pod::Graph::Mesh converted; - converted.set(); - converted.resizeVertices( vertices ); - converted.resizeIndices( indices ); - - memcpy( converted.attributes.index.pointer, mesh.attributes.index.pointer, mesh.attributes.index.size * mesh.attributes.index.length ); - - uf::renderer::VertexDescriptor vertexAttributePosition; - uf::renderer::VertexDescriptor vertexAttributeUv; - uf::renderer::VertexDescriptor vertexAttributeSt; - uf::renderer::VertexDescriptor vertexAttributeId; - - for ( auto& attribute : mesh.attributes.descriptor ) { - if ( attribute.name == "position" ) vertexAttributePosition = attribute; - else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; - else if ( attribute.name == "st" ) vertexAttributeSt = attribute; - else if ( attribute.name == "id" ) vertexAttributeId = attribute; - } - - auto& base = converted.get(); - for ( size_t currentIndex = 0; currentIndex < vertices; ++currentIndex ) { - uint8_t* vertexSrc = vertexPointer + (currentIndex * vertexStride); - - const pod::Vector3f& position = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); - const pod::Vector2f& uv = *((pod::Vector2f*) (vertexSrc + vertexAttributeUv.offset)); - const pod::Vector2f& st = *((pod::Vector2f*) (vertexSrc + vertexAttributeSt.offset)); - const pod::Vector& id = *((pod::Vector*) (vertexSrc + vertexAttributeId.offset)); - - base.vertices[currentIndex] = { - .position = position, - .uv = uv, - .st = st, - .id = id, - }; - } - - - mesh.destroy(); - return converted; - #endif - #else - // ensures vertex size remains the same between mesh encoding and mesh decoding - // example: engine has differing alignment requirements compared to when the mesh was originally encoded - if ( ext::json::isObject( json["metadata"]["vertices"] ) ) { - size_t expectedValue = sizeof(pod::Graph::Mesh::vertex_t); - size_t actualValue = json["metadata"]["vertices"]["size"].as(expectedValue); - if ( expectedValue != actualValue ) UF_EXCEPTION("mismatched vertex size encountered while decoding mesh; expected " << expectedValue << ", got " << actualValue << ": " << graph.name); - - #if 0 - expectedValue = alignof(pod::Graph::Mesh::vertex_t); - actualValue = json["metadata"]["vertices"]["alignment"].as(expectedValue); - if ( expectedValue != actualValue ) UF_EXCEPTION("mismatched vertex alignment encountered while decoding mesh; expected " << expectedValue << ", got " << actualValue << ": " << graph.name); - #endif - } - // ensures index size remains the same between mesh encoding and mesh decoding - // example: engine used uint32_t for indices when the mesh was encoded, and the engine changes to using uint16_t when decoding the mesh - if ( ext::json::isObject( json["metadata"]["indices"] ) ) { - size_t expectedValue = sizeof(pod::Graph::Mesh::index_t); - size_t actualValue = json["metadata"]["indices"]["size"].as(expectedValue); - if ( expectedValue != actualValue ) UF_EXCEPTION("mismatched index size encountered while decoding mesh; expected " << expectedValue << ", got " << actualValue << ": " << graph.name); - - #if 0 - expectedValue = alignof(pod::Graph::Mesh::index_t); - actualValue = json["metadata"]["indices"]["alignment"].as(expectedValue); - if ( expectedValue != actualValue ) UF_EXCEPTION("mismatched index alignment encountered while decoding mesh; expected " << expectedValue << ", got " << actualValue << ": " << graph.name); - #endif - } - - // vertices are encoded as a raw buffer, referenced as a filename - if ( json["vertices"].is() ) { - const uf::stl::string filename = json["vertices"].as(); - const uf::stl::string directory = uf::io::directory( graph.name ); - const auto buffer = uf::io::readAsBuffer( directory + "/" + filename ); - if ( ext::json::isObject( json["metadata"]["vertices"] ) ) { - size_t actualValue = buffer.size() / sizeof(pod::Graph::Mesh::vertex_t); - size_t expectedValue = json["metadata"]["vertices"]["count"].as( actualValue ); - if ( expectedValue != actualValue ) UF_EXCEPTION("mismatched vertex count encountered while decoding mesh; expected " << expectedValue << ", got " << actualValue << ": " << directory << "/" << filename); - } else if ( buffer.size() % sizeof(pod::Graph::Mesh::vertex_t) != 0 ) { - UF_EXCEPTION("mismatched vertex size encountered while decoding mesh: " << directory << "/" << filename); - } - mesh.vertices.resize( buffer.size() / sizeof(pod::Graph::Mesh::vertex_t) ); - memcpy( mesh.vertices.data(), buffer.data(), buffer.size() ); - // vertices are encoded as a JSON array - } else if ( ext::json::isArray( json["vertices"] ) ) { - mesh.vertices.reserve( json["vertices"].size() ); - ext::json::forEach( json["vertices"], [&]( ext::json::Value& value ){ - uint_fast8_t attr = 0; - mesh.vertices.emplace_back(pod::Graph::Mesh::vertex_t{ - .position = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .uv = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .st = uf::vector::decode( value[attr++], pod::Vector2f{} ), - .normal = uf::vector::decode( value[attr++], pod::Vector3f{} ), - .tangent = uf::vector::decode( value[attr++], pod::Vector4f{} ), - .id = uf::vector::decode( value[attr++], pod::Vector{} ), - .joints = uf::vector::decode( value[attr++], pod::Vector{} ), - .weights = uf::vector::decode( value[attr++], pod::Vector4f{} ), - }); - }); - } else { - UF_MSG_ERROR("invalid vertices information encountered while decoding mesh: " << graph.name ); - } - // indices are encoded as a raw buffer, referenced as a filename - if ( json["indices"].is() ) { - const uf::stl::string filename = json["indices"].as(); - const uf::stl::string directory = uf::io::directory( graph.name ); - const auto buffer = uf::io::readAsBuffer( directory + "/" + filename ); - if ( ext::json::isObject( json["metadata"]["indices"] ) ) { - size_t actualValue = buffer.size() / sizeof(pod::Graph::Mesh::index_t); - size_t expectedValue = json["metadata"]["indices"]["count"].as( actualValue ); - if ( expectedValue != actualValue ) UF_EXCEPTION("mismatched index count encountered while decoding mesh; expected " << expectedValue << ", got " << actualValue << ": " << directory << "/" << filename); - } else if ( buffer.size() % sizeof(pod::Graph::Mesh::index_t) != 0 ) { - UF_EXCEPTION("mismatched index size encountered while decoding mesh: " << directory << "/" << filename); - } - mesh.indices.resize( buffer.size() / sizeof(pod::Graph::Mesh::index_t) ); - memcpy( mesh.indices.data(), buffer.data(), buffer.size() ); - // indices are encoded as a JSON array - } else if ( ext::json::isArray( json["indices"] ) ) { - mesh.indices.reserve( json["indices"].size() ); - ext::json::forEach( json["indices"], [&]( ext::json::Value& value ){ - mesh.indices.emplace_back( value.as() ); - }); - } else { - UF_MSG_ERROR("invalid indices information encountered while decoding mesh: " << graph.name ); - } - #endif - return mesh; + return drawCommands; } - pod::Graph::Mesh& decode( ext::json::Value& json, pod::Graph::Mesh& mesh, const pod::Graph& graph ) { - return mesh = decodeMesh( json, graph ); + + pod::Instance decodeInstance( ext::json::Value& json, const pod::Graph& graph ) { + pod::Instance instance; + + return instance; + } + + uf::stl::string decodeMesh( ext::json::Value& json, const pod::Graph& graph ) { + auto name = json["name"].as(); + auto& pair = uf::graph::storage.meshes[name]; + pair.drawCommands = decodeDrawCommand( json["drawCommands"], graph ); + + auto& mesh = pair.mesh; + mesh.vertex.attributes.reserve( json["inputs"]["vertex"]["attributes"].size() ); + ext::json::forEach( json["inputs"]["vertex"]["attributes"], [&]( ext::json::Value& value ){ + auto& attribute = mesh.vertex.attributes.emplace_back(); + + attribute.descriptor.offset = value["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["components"].as(attribute.descriptor.components); + attribute.buffer = value["buffer"].as(attribute.buffer); + }); + mesh.index.attributes.reserve( json["inputs"]["index"]["attributes"].size() ); + ext::json::forEach( json["inputs"]["index"]["attributes"], [&]( ext::json::Value& value ){ + auto& attribute = mesh.index.attributes.emplace_back(); + + attribute.descriptor.offset = value["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["components"].as(attribute.descriptor.components); + attribute.buffer = value["buffer"].as(attribute.buffer); + }); + mesh.instance.attributes.reserve( json["inputs"]["instance"]["attributes"].size() ); + ext::json::forEach( json["inputs"]["instance"]["attributes"], [&]( ext::json::Value& value ){ + auto& attribute = mesh.instance.attributes.emplace_back(); + + attribute.descriptor.offset = value["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["components"].as(attribute.descriptor.components); + attribute.buffer = value["buffer"].as(attribute.buffer); + }); + mesh.indirect.attributes.reserve( json["inputs"]["indirect"]["attributes"].size() ); + ext::json::forEach( json["inputs"]["indirect"]["attributes"], [&]( ext::json::Value& value ){ + auto& attribute = mesh.indirect.attributes.emplace_back(); + + attribute.descriptor.offset = value["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["components"].as(attribute.descriptor.components); + attribute.buffer = value["buffer"].as(attribute.buffer); + }); + + mesh.buffers.reserve( json["buffers"].size() ); + ext::json::forEach( json["buffers"], [&]( ext::json::Value& value ){ + const uf::stl::string filename = value.as(); + const uf::stl::string directory = uf::io::directory( graph.name ); + mesh.buffers.emplace_back(uf::io::readAsBuffer( directory + "/" + filename )); + }); + + return name; } pod::Node decodeNode( ext::json::Value& json, const pod::Graph& graph ) { pod::Node node = pod::Node{ .name = json["name"].as(), .index = json["index"].as(), - .skin = json["skin"].as(-1), .parent = json["parent"].as(-1), .mesh = json["mesh"].as(-1), + .skin = json["skin"].as(-1), + .entity = NULL, .transform = uf::transform::decode( json["transform"], pod::Transform<>{} ), }; + node.children.reserve( json["children"].size() ); ext::json::forEach( json["children"], [&]( ext::json::Value& value ){ node.children.emplace_back( value.as() ); }); return node; } - pod::Node& decode( ext::json::Value& json, pod::Node& node, const pod::Graph& graph ) { - return node = decodeNode( json, graph ); - } } -pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mode_t mode, const uf::Serializer& metadata ) { +pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serializer& metadata ) { #if UF_ENV_DREAMCAST #define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__) #define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__) @@ -1443,7 +1349,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod #define UF_DEBUG_TIMER_MULTITRACE_END(...) #endif const uf::stl::string extension = uf::io::extension( filename ); - if ( extension == "glb" || extension == "gltf" ) return ext::gltf::load( filename, mode, metadata ); + if ( extension == "glb" || extension == "gltf" ) return ext::gltf::load( filename, metadata ); const uf::stl::string directory = uf::io::directory( filename ) + "/"; pod::Graph graph; uf::Serializer serializer; @@ -1451,29 +1357,43 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod serializer.readFromFile( filename ); // load metadata graph.name = filename; //serializer["name"].as(); - graph.mode = mode; // serializer["mode"].as(); graph.metadata = metadata; // serializer["metadata"]; -#if UF_GRAPH_LOAD_MULTITHREAD pod::Thread::container_t jobs; + jobs.emplace_back([&]{ + // load draw command information + UF_DEBUG_TIMER_MULTITRACE("Reading draw commands..."); + graph.drawCommands.reserve( serializer["drawCommands"].size() ); + ext::json::forEach( serializer["drawCommands"], [&]( ext::json::Value& value ){ + graph.drawCommands.emplace_back(decodeDrawCommand( value, graph )); + }); + }); + jobs.emplace_back([&]{ + // load draw command information + UF_DEBUG_TIMER_MULTITRACE("Reading instances..."); + graph.instances.reserve( serializer["instances"].size() ); + ext::json::forEach( serializer["instances"], [&]( ext::json::Value& value ){ + graph.instances.emplace_back(decodeInstance( value, graph )); + }); + }); jobs.emplace_back([&]{ // load mesh information - UF_DEBUG_TIMER_MULTITRACE("Reading meshes..."); + UF_DEBUG_TIMER_MULTITRACE("Reading meshes..."); graph.meshes.reserve( serializer["meshes"].size() ); ext::json::forEach( serializer["meshes"], [&]( ext::json::Value& value ){ - auto& mesh = graph.meshes.emplace_back(); if ( value.is() ) { UF_DEBUG_TIMER_MULTITRACE(directory + "/" + value.as()); uf::Serializer json; json.readFromFile( directory + "/" + value.as() ); - decode( json, mesh, graph ); + graph.meshes.emplace_back(decodeMesh( json, graph )); } else { - decode( value, mesh, graph ); + graph.meshes.emplace_back(decodeMesh( value, graph )); } }); }); - jobs.emplace_back([&]{ + #if 0 #if !UF_ENV_DREAMCAST + jobs.emplace_back([&]{ if ( !ext::json::isNull( serializer["atlas"] ) ) { UF_DEBUG_TIMER_MULTITRACE("Reading atlas..."); auto& image = graph.atlas.getAtlas(); @@ -1486,28 +1406,23 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod decode( value, image, graph ); } } + }); #endif + #endif + jobs.emplace_back([&]{ // load texture information UF_DEBUG_TIMER_MULTITRACE("Reading texture information..."); graph.textures.reserve( serializer["textures"].size() ); ext::json::forEach( serializer["textures"], [&]( ext::json::Value& value ){ - decode( value, graph.textures.emplace_back(), graph ); + graph.textures.emplace_back(decodeTexture( value, graph )); }); + }); + jobs.emplace_back([&]{ // load images UF_DEBUG_TIMER_MULTITRACE("Reading images..."); graph.images.reserve( serializer["images"].size() ); ext::json::forEach( serializer["images"], [&]( ext::json::Value& value ){ - auto& texture = graph.textures[ graph.images.size() ]; - auto& image = graph.images.emplace_back(); - if ( value.is() ) { - uf::stl::string filename = directory + "/" + value.as(); - UF_DEBUG_TIMER_MULTITRACE("Reading image " << filename); - image.open(filename, false); - } else { - decode( value, image, graph ); - } - texture.texture.loadFromImage( image ); - image.clear(); + graph.images.emplace_back(decodeImage( value, graph )); }); }); jobs.emplace_back([&]{ @@ -1515,7 +1430,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod UF_DEBUG_TIMER_MULTITRACE("Reading sampler information..."); graph.samplers.reserve( serializer["samplers"].size() ); ext::json::forEach( serializer["samplers"], [&]( ext::json::Value& value ){ - decode( value, graph.samplers.emplace_back(), graph ); + graph.samplers.emplace_back(decodeSampler( value, graph )); }); }); jobs.emplace_back([&]{ @@ -1523,7 +1438,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod UF_DEBUG_TIMER_MULTITRACE("Reading material information..."); graph.materials.reserve( serializer["materials"].size() ); ext::json::forEach( serializer["materials"], [&]( ext::json::Value& value ){ - decode( value, graph.materials.emplace_back(), graph ); + graph.materials.emplace_back(decodeMaterial( value, graph )); }); }); jobs.emplace_back([&]{ @@ -1531,7 +1446,8 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod UF_DEBUG_TIMER_MULTITRACE("Reading lighting information..."); graph.lights.reserve( serializer["lighting"].size() ); ext::json::forEach( serializer["lighting"], [&]( ext::json::Value& value ){ - decode( value, graph.lights.emplace_back(), graph ); + auto name = value["name"].as(); + graph.lights[name] = decodeLight( value, graph ); }); }); jobs.emplace_back([&]{ @@ -1543,10 +1459,10 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod uf::Serializer json; json.readFromFile( directory + "/" + value.as() ); uf::stl::string key = json["name"].as(); - decode( json, graph.animations[key], graph ); + graph.animations[key] = decodeAnimation( json, graph ); } else { uf::stl::string key = value["name"].as(); - decode( value, graph.animations[key], graph ); + graph.animations[key] = decodeAnimation( value, graph ); } }); }); @@ -1555,7 +1471,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod UF_DEBUG_TIMER_MULTITRACE("Reading skinning information..."); graph.skins.reserve( serializer["skins"].size() ); ext::json::forEach( serializer["skins"], [&]( ext::json::Value& value ){ - decode( value, graph.skins.emplace_back(), graph ); + graph.skins.emplace_back(decodeSkin( value, graph )); }); }); jobs.emplace_back([&]{ @@ -1563,117 +1479,16 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, uf::graph::load_mod UF_DEBUG_TIMER_MULTITRACE("Reading nodes..."); graph.nodes.reserve( serializer["nodes"].size() ); ext::json::forEach( serializer["nodes"], [&]( ext::json::Value& value ){ - decode( value, graph.nodes.emplace_back(), graph ); + graph.nodes.emplace_back(decodeNode( value, graph )); }); - decode( serializer["root"], graph.root, graph ); + graph.root = decodeNode( serializer["root"], graph ); }); +#if UF_GRAPH_LOAD_MULTITHREAD if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); #else - // load mesh information - UF_DEBUG_TIMER_MULTITRACE("Reading meshes..."); - graph.meshes.reserve( serializer["meshes"].size() ); - ext::json::forEach( serializer["meshes"], [&]( ext::json::Value& value ){ - auto& mesh = graph.meshes.emplace_back(); - if ( value.is() ) { - UF_DEBUG_TIMER_MULTITRACE(directory + "/" + value.as()); - uf::Serializer json; - json.readFromFile( directory + "/" + value.as() ); - decode( json, mesh, graph ); - - } else { - decode( value, mesh, graph ); - } - }); - // load images - #if !UF_ENV_DREAMCAST - if ( !ext::json::isNull( serializer["atlas"] ) ) { - UF_DEBUG_TIMER_MULTITRACE("Reading atlas..."); - auto& image = graph.atlas.getAtlas(); - auto& value = serializer["atlas"]; - if ( value.is() ) { - uf::stl::string filename = directory + "/" + value.as(); - UF_DEBUG_TIMER_MULTITRACE("Reading atlas " << filename); - image.open(filename, false); - } else { - decode( value, image, graph ); - } - } - #endif - // load texture information - UF_DEBUG_TIMER_MULTITRACE("Reading texture information..."); - graph.textures.reserve( serializer["textures"].size() ); - ext::json::forEach( serializer["textures"], [&]( ext::json::Value& value ){ - decode( value, graph.textures.emplace_back(), graph ); - }); - UF_DEBUG_TIMER_MULTITRACE("Reading images..."); - graph.images.reserve( serializer["images"].size() ); - ext::json::forEach( serializer["images"], [&]( ext::json::Value& value ){ - auto& texture = graph.textures[ graph.images.size() ]; - auto& image = graph.images.emplace_back(); - if ( value.is() ) { - uf::stl::string filename = directory + "/" + value.as(); - UF_DEBUG_TIMER_MULTITRACE("Reading image " << filename); - image.open(filename, false); - } else { - decode( value, image, graph ); - } - texture.texture.loadFromImage( image ); - image.clear(); - }); - // load sampler information - UF_DEBUG_TIMER_MULTITRACE("Reading sampler information..."); - graph.samplers.reserve( serializer["samplers"].size() ); - ext::json::forEach( serializer["samplers"], [&]( ext::json::Value& value ){ - decode( value, graph.samplers.emplace_back(), graph ); - }); - // load material information - UF_DEBUG_TIMER_MULTITRACE("Reading material information..."); - graph.materials.reserve( serializer["materials"].size() ); - ext::json::forEach( serializer["materials"], [&]( ext::json::Value& value ){ - decode( value, graph.materials.emplace_back(), graph ); - }); - // load light information - UF_DEBUG_TIMER_MULTITRACE("Reading lighting information..."); - graph.lights.reserve( serializer["lighting"].size() ); - ext::json::forEach( serializer["lighting"], [&]( ext::json::Value& value ){ - decode( value, graph.lights.emplace_back(), graph ); - }); - // load animation information - UF_DEBUG_TIMER_MULTITRACE("Reading animation information..."); - graph.animations.reserve( serializer["animations"].size() ); - ext::json::forEach( serializer["animations"], [&]( ext::json::Value& value ){ - if ( value.is() ) { - uf::Serializer json; - json.readFromFile( directory + "/" + value.as() ); - uf::stl::string key = json["name"].as(); - decode( json, graph.animations[key], graph ); - } else { - uf::stl::string key = value["name"].as(); - decode( value, graph.animations[key], graph ); - } - }); - // load skin information - UF_DEBUG_TIMER_MULTITRACE("Reading skinning information..."); - graph.skins.reserve( serializer["skins"].size() ); - ext::json::forEach( serializer["skins"], [&]( ext::json::Value& value ){ - decode( value, graph.skins.emplace_back(), graph ); - }); - // load node information - UF_DEBUG_TIMER_MULTITRACE("Reading nodes..."); - graph.nodes.reserve( serializer["nodes"].size() ); - ext::json::forEach( serializer["nodes"], [&]( ext::json::Value& value ){ - decode( value, graph.nodes.emplace_back(), graph ); - }); - decode( serializer["root"], graph.root, graph ); -#endif -#if 0 - // generate atlas - if ( graph.metadata["flags"]["ATLAS"].as() ) { - UF_DEBUG_TIMER_MULTITRACE("Generating atlas..."); - graph.atlas.generate( graph.images ); - graph.atlas.clear(false); - } + for ( auto& job : jobs ) job(); #endif + // re-reference all transform parents for ( auto& node : graph.nodes ) { if ( 0 <= node.parent && node.parent < graph.nodes.size() && node.index != node.parent ) { @@ -1702,13 +1517,12 @@ namespace { } uf::Serializer encode( const pod::Texture& texture, const EncodingSettings& settings ) { uf::Serializer json; - json["name"] = texture.name; - json["index"] = texture.storage.index; - json["sampler"] = texture.storage.sampler; - json["remap"] = texture.storage.remap; - json["blend"] = texture.storage.blend; - json["lerp"] = uf::vector::encode( texture.storage.lerp, settings ); - return json; // return ext::json::reencode( json, settings ); + json["index"] = texture.index; + json["sampler"] = texture.sampler; + json["remap"] = texture.remap; + json["blend"] = texture.blend; + json["lerp"] = uf::vector::encode( texture.lerp, settings ); + return json; } uf::Serializer encode( const uf::renderer::Sampler& sampler, const EncodingSettings& settings ) { uf::Serializer json; @@ -1720,29 +1534,26 @@ namespace { } uf::Serializer encode( const pod::Material& material, const EncodingSettings& settings ) { uf::Serializer json; - json["name"] = material.name; - json["alphaMode"] = material.alphaMode; - json["base"] = uf::vector::encode( material.storage.colorBase, settings ); - json["emissive"] = uf::vector::encode( material.storage.colorEmissive, settings ); - json["fMetallic"] = material.storage.factorMetallic; - json["fRoughness"] = material.storage.factorRoughness; - json["fOcclusion"] = material.storage.factorOcclusion; - json["fAlphaCutoff"] = material.storage.factorAlphaCutoff; - if ( material.storage.indexAlbedo >= 0 ) json["iAlbedo"] = material.storage.indexAlbedo; - if ( material.storage.indexNormal >= 0 ) json["iNormal"] = material.storage.indexNormal; - if ( material.storage.indexEmissive >= 0 ) json["iEmissive"] = material.storage.indexEmissive; - if ( material.storage.indexOcclusion >= 0 ) json["iOcclusion"] = material.storage.indexOcclusion; - if ( material.storage.indexMetallicRoughness >= 0 ) json["iMetallicRoughness"] = material.storage.indexMetallicRoughness; - json["modeAlpha"] = material.storage.modeAlpha; - return json; // return ext::json::reencode( json, settings ); + json["base"] = uf::vector::encode( material.colorBase, settings ); + json["emissive"] = uf::vector::encode( material.colorEmissive, settings ); + json["fMetallic"] = material.factorMetallic; + json["fRoughness"] = material.factorRoughness; + json["fOcclusion"] = material.factorOcclusion; + json["fAlphaCutoff"] = material.factorAlphaCutoff; + if ( material.indexAlbedo >= 0 ) json["iAlbedo"] = material.indexAlbedo; + if ( material.indexNormal >= 0 ) json["iNormal"] = material.indexNormal; + if ( material.indexEmissive >= 0 ) json["iEmissive"] = material.indexEmissive; + if ( material.indexOcclusion >= 0 ) json["iOcclusion"] = material.indexOcclusion; + if ( material.indexMetallicRoughness >= 0 ) json["iMetallicRoughness"] = material.indexMetallicRoughness; + json["modeAlpha"] = material.modeAlpha; + return json; } uf::Serializer encode( const pod::Light& light, const EncodingSettings& settings ) { uf::Serializer json; - json["name"] = light.name; json["color"] = uf::vector::encode( light.color, settings ); json["intensity"] = light.intensity; json["range"] = light.range; - return json; // return ext::json::reencode( json, settings ); + return json; } uf::Serializer encode( const pod::Animation& animation, const EncodingSettings& settings ) { uf::Serializer json; @@ -1770,7 +1581,7 @@ namespace { json["node"] = channel.node; json["sampler"] = channel.sampler; } - return json; // return ext::json::reencode( json, settings ); + return json; } uf::Serializer encode( const pod::Skin& skin, const EncodingSettings& settings ) { uf::Serializer json; @@ -1782,12 +1593,111 @@ namespace { ext::json::reserve( json["inverseBindMatrices"], skin.inverseBindMatrices.size() ); for ( auto& inverseBindMatrix : skin.inverseBindMatrices ) json["inverseBindMatrices"].emplace_back( uf::matrix::encode(inverseBindMatrix, settings) ); - return json; // return ext::json::reencode( json, settings ); - } - uf::Serializer encode( const pod::Graph::Mesh& mesh, const EncodingSettings& settings ) { + return json; + } + uf::Serializer encode( const uf::stl::vector& drawCommands, const EncodingSettings& settings ) { uf::Serializer json; - ext::json::reserve( json["attributes"], mesh.attributes.descriptor.size() ); - for ( auto& attribute : mesh.attributes.descriptor ) { + ext::json::reserve( json, drawCommands.size() ); + + for ( auto& drawCommand : drawCommands ) { + auto& d = json.emplace_back(); + d["indices"] = drawCommand.indices; + d["instances"] = drawCommand.instances; + d["indexID"] = drawCommand.indexID; + d["vertexID"] = drawCommand.vertexID; + + d["instanceID"] = drawCommand.instanceID; + d["materialID"] = drawCommand.materialID; + d["objectID"] = drawCommand.objectID; + d["vertices"] = drawCommand.vertices; + } + + return json; + } + uf::Serializer encode( const pod::Instance& instance, const EncodingSettings& settings ) { + uf::Serializer json; + return json; + } + uf::Serializer encode( const pod::Mesh& pair, const EncodingSettings& settings ) { + uf::Serializer json; + json["drawCommands"] = encode( pair.drawCommands, settings ); + + + auto& mesh = pair.mesh; + json["inputs"]["vertex"]["count"] = mesh.vertex.count; + json["inputs"]["vertex"]["first"] = mesh.vertex.first; + json["inputs"]["vertex"]["stride"] = mesh.vertex.stride; + json["inputs"]["vertex"]["offset"] = mesh.vertex.offset; + ext::json::reserve( json["inputs"]["vertex"]["attributes"], mesh.vertex.attributes.size() ); + for ( auto& attribute : mesh.vertex.attributes ) { + auto& a = json["inputs"]["vertex"]["attributes"].emplace_back(); + a["descriptor"]["offset"] = attribute.descriptor.offset; + a["descriptor"]["size"] = attribute.descriptor.size; + a["descriptor"]["format"] = attribute.descriptor.format; + a["descriptor"]["name"] = attribute.descriptor.name; + a["descriptor"]["type"] = attribute.descriptor.type; + a["descriptor"]["components"] = attribute.descriptor.components; + a["buffer"] = attribute.buffer; + } + + json["inputs"]["index"]["count"] = mesh.index.count; + json["inputs"]["index"]["first"] = mesh.index.first; + json["inputs"]["index"]["stride"] = mesh.index.stride; + json["inputs"]["index"]["offset"] = mesh.index.offset; + ext::json::reserve( json["inputs"]["index"]["attributes"], mesh.index.attributes.size() ); + for ( auto& attribute : mesh.index.attributes ) { + auto& a = json["inputs"]["index"]["attributes"].emplace_back(); + a["descriptor"]["offset"] = attribute.descriptor.offset; + a["descriptor"]["size"] = attribute.descriptor.size; + a["descriptor"]["format"] = attribute.descriptor.format; + a["descriptor"]["name"] = attribute.descriptor.name; + a["descriptor"]["type"] = attribute.descriptor.type; + a["descriptor"]["components"] = attribute.descriptor.components; + a["buffer"] = attribute.buffer; + } + + json["inputs"]["instance"]["count"] = mesh.instance.count; + json["inputs"]["instance"]["first"] = mesh.instance.first; + json["inputs"]["instance"]["stride"] = mesh.instance.stride; + json["inputs"]["instance"]["offset"] = mesh.instance.offset; + ext::json::reserve( json["inputs"]["instance"]["attributes"], mesh.instance.attributes.size() ); + for ( auto& attribute : mesh.instance.attributes ) { + auto& a = json["inputs"]["instance"]["attributes"].emplace_back(); + a["descriptor"]["offset"] = attribute.descriptor.offset; + a["descriptor"]["size"] = attribute.descriptor.size; + a["descriptor"]["format"] = attribute.descriptor.format; + a["descriptor"]["name"] = attribute.descriptor.name; + a["descriptor"]["type"] = attribute.descriptor.type; + a["descriptor"]["components"] = attribute.descriptor.components; + a["buffer"] = attribute.buffer; + } + + json["inputs"]["indirect"]["count"] = mesh.indirect.count; + json["inputs"]["indirect"]["first"] = mesh.indirect.first; + json["inputs"]["indirect"]["stride"] = mesh.indirect.stride; + json["inputs"]["indirect"]["offset"] = mesh.indirect.offset; + ext::json::reserve( json["inputs"]["indirect"]["attributes"], mesh.indirect.attributes.size() ); + for ( auto& attribute : mesh.indirect.attributes ) { + auto& a = json["inputs"]["indirect"]["attributes"].emplace_back(); + a["descriptor"]["offset"] = attribute.descriptor.offset; + a["descriptor"]["size"] = attribute.descriptor.size; + a["descriptor"]["format"] = attribute.descriptor.format; + a["descriptor"]["name"] = attribute.descriptor.name; + a["descriptor"]["type"] = attribute.descriptor.type; + a["descriptor"]["components"] = attribute.descriptor.components; + a["buffer"] = attribute.buffer; + } + + ext::json::reserve( json["buffers"], mesh.buffers.size() ); + for ( auto i = 0; i < mesh.buffers.size(); ++i ) { + const uf::stl::string filename = settings.filename + ".buffer." + std::to_string(i) + "." + ( settings.compress ? "gz" : "bin" ); + uf::io::write( filename, mesh.buffers[i] ); + json["buffers"].emplace_back(uf::io::filename( filename )); + } + + #if 0 + ext::json::reserve( json["attributes"], mesh.attributes.vertex.descriptor.size() ); + for ( auto& attribute : mesh.attributes.vertex.descriptor ) { auto& a = json["attributes"].emplace_back(); a["name"] = attribute.name; a["size"] = attribute.size; @@ -1805,7 +1715,7 @@ namespace { json["metadata"]["indices"]["count"] = mesh.attributes.index.length; if ( !settings.encodeBuffers ){ - #if UF_GRAPH_EXPERIMENTAL + #if UF_GRAPH_VARYING_MESH size_t indices = mesh.attributes.index.length; size_t indexStride = mesh.attributes.index.size; uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer; @@ -1827,7 +1737,7 @@ namespace { json["indices"].emplace_back( index ); auto& v = json["vertices"].emplace_back(); - for ( auto& attribute : mesh.attributes.descriptor ) { + for ( auto& attribute : mesh.attributes.vertex.descriptor ) { uint8_t* vertexSrc = (vertexPointer + (index * vertexStride)) + attribute.offset; if ( attribute.name == "id" || attribute.name == "joints" ) switch ( attribute.components ) { @@ -1905,7 +1815,8 @@ namespace { json["indices"] = uf::io::filename( indicesFilename ); } } - return json; // return ext::json::reencode( json, settings ); + #endif + return json; } uf::Serializer encode( const pod::Node& node, const EncodingSettings& settings ) { uf::Serializer json; @@ -1947,52 +1858,84 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) serializer["wrapped"] = uf::vector::encode( size ); } -#if UF_GRAPH_LOAD_MULTITHREAD pod::Thread::container_t jobs; // store images jobs.emplace_back([&]{ + #if 0 if ( graph.atlas.generated() ) { auto& image = graph.atlas.getAtlas(); if ( !settings.combined ) { - // uf::stl::string f = "atlas" + ( settings.compress?".jpg":".png" ); - // serializer["atlas"] = f; image.save(directory + "/atlas.png"); serializer["atlas"] = "atlas.png"; } else { serializer["atlas"] = encode(image, settings); } } + #endif + }); + jobs.emplace_back([&]{ ext::json::reserve( serializer["images"], graph.images.size() ); if ( !settings.combined ) { for ( size_t i = 0; i < graph.images.size(); ++i ) { - // uf::stl::string f = "image."+std::to_string(i)+(settings.compress?".jpg":".png"); + auto& name = graph.images[i]; + auto& image = uf::graph::storage.images[name]; uf::stl::string f = "image."+std::to_string(i)+".png"; - graph.images[i].save(directory + "/" + f); - serializer["images"].emplace_back(f); + + image.save(directory + "/" + f); + uf::Serializer json; + json["name"] = name; + json["filename"] = f; + serializer["images"].emplace_back( json ); } } else { - for ( auto& image : graph.images ) serializer["images"].emplace_back( encode(image, settings) ); + for ( auto& name : graph.images ) { + auto& image = uf::graph::storage.images[name]; + auto json = encode(image, settings); + json["name"] = name; + serializer["images"].emplace_back( json ); + } } }); jobs.emplace_back([&]{ // store texture information ext::json::reserve( serializer["textures"], graph.textures.size() ); - for ( auto& texture : graph.textures ) serializer["textures"].emplace_back( encode(texture, settings) ); + for ( auto& name : graph.textures ) { + auto& texture = uf::graph::storage.textures[name]; + auto json = encode(texture, settings); + json["name"] = name; + serializer["textures"].emplace_back(json); + } }); jobs.emplace_back([&]{ // store sampler information ext::json::reserve( serializer["samplers"], graph.samplers.size() ); - for ( auto& sampler : graph.samplers ) serializer["samplers"].emplace_back( encode(sampler, settings) ); + for ( auto& name : graph.samplers ) { + auto& sampler = uf::graph::storage.samplers[name]; + auto json = encode(sampler, settings); + json["name"] = name; + serializer["samplers"].emplace_back(json); + } }); jobs.emplace_back([&]{ // store material information ext::json::reserve( serializer["materials"], graph.materials.size() ); - for ( auto& material : graph.materials ) serializer["materials"].emplace_back( encode(material, settings) ); + for ( auto& name : graph.materials ) { + auto& material = uf::graph::storage.materials[name]; + auto json = encode(material, settings); + json["name"] = name; + serializer["materials"].emplace_back(json); + } }); jobs.emplace_back([&]{ // store light information ext::json::reserve( serializer["lighting"], graph.lights.size() ); - for ( auto& light : graph.lights ) serializer["lighting"].emplace_back( encode(light, settings) ); + for ( auto pair : graph.lights ) { + auto& name = pair.first; + auto& light = pair.second; + auto json = encode(light, settings); + json["name"] = name; + serializer["lighting"].emplace_back(json); + } }); jobs.emplace_back([&]{ // store animation information @@ -2012,24 +1955,45 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) ext::json::reserve( serializer["skins"], graph.skins.size() ); for ( auto& skin : graph.skins ) serializer["skins"].emplace_back( encode(skin, settings) ); }); + jobs.emplace_back([&]{ + // store draw command information + ext::json::reserve( serializer["drawCommands"], graph.drawCommands.size() ); + for ( auto& drawCommand : graph.drawCommands ) serializer["drawCommands"].emplace_back( encode(drawCommand, settings) ); + }); + jobs.emplace_back([&]{ + // store instance information + ext::json::reserve( serializer["instances"], graph.instances.size() ); + for ( auto& instance : graph.instances ) serializer["instances"].emplace_back( encode(instance, settings) ); + }); jobs.emplace_back([&]{ // store mesh information ext::json::reserve( serializer["meshes"], graph.meshes.size() ); if ( !settings.combined ) { ::EncodingSettings s = settings; for ( size_t i = 0; i < graph.meshes.size(); ++i ) { + auto& name = graph.meshes[i]; + auto& mesh = uf::graph::storage.meshes[name]; if ( !s.encodeBuffers ) { s.filename = directory+"/mesh."+std::to_string(i)+".json"; - encode(graph.meshes[i], s).writeToFile(s.filename, settings); - serializer["meshes"].emplace_back( uf::io::filename(s.filename + (settings.compress ? ".gz" : "")) ); + encode(mesh, s).writeToFile(s.filename, settings); + uf::Serializer json; + json["name"] = name; + json["filename"] = uf::io::filename(s.filename + (settings.compress ? ".gz" : "")); + serializer["meshes"].emplace_back( json ); } else { s.filename = directory+"/mesh."+std::to_string(i); - auto json = encode(graph.meshes[i], s); + auto json = encode(mesh, s); + json["name"] = name; serializer["meshes"].emplace_back(json); } } } else { - for ( auto& mesh : graph.meshes ) serializer["meshes"].emplace_back( encode(mesh, settings) ); + for ( auto& name : graph.meshes ) { + auto& mesh = uf::graph::storage.meshes[name]; + auto json = encode(mesh, settings); + json["name"] = name; + serializer["meshes"].emplace_back(json); + } } }); jobs.emplace_back([&]{ @@ -2038,78 +2002,10 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, settings) ); serializer["root"] = encode(graph.root, settings); }); +#if UF_GRAPH_LOAD_MULTITHREAD if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); #else - if ( graph.atlas.generated() ) { - auto& image = graph.atlas.getAtlas(); - if ( !settings.combined ) { - // uf::stl::string f = "atlas" + ( settings.compress?".jpg":".png" ); - // serializer["atlas"] = f; - image.save(directory + "/atlas.png"); - serializer["atlas"] = "atlas.png"; - } else { - serializer["atlas"] = encode(image, settings); - } - } - ext::json::reserve( serializer["images"], graph.images.size() ); - if ( !settings.combined ) { - for ( size_t i = 0; i < graph.images.size(); ++i ) { - // uf::stl::string f = "image."+std::to_string(i)+(settings.compress?".jpg":".png"); - uf::stl::string f = "image."+std::to_string(i)+".png"; - graph.images[i].save(directory + "/" + f); - serializer["images"].emplace_back(f); - } - } else { - for ( auto& image : graph.images ) serializer["images"].emplace_back( encode(image, settings) ); - } - // store texture information - ext::json::reserve( serializer["textures"], graph.textures.size() ); - for ( auto& texture : graph.textures ) serializer["textures"].emplace_back( encode(texture, settings) ); - // store sampler information - ext::json::reserve( serializer["samplers"], graph.samplers.size() ); - for ( auto& sampler : graph.samplers ) serializer["samplers"].emplace_back( encode(sampler, settings) ); - // store material information - ext::json::reserve( serializer["materials"], graph.materials.size() ); - for ( auto& material : graph.materials ) serializer["materials"].emplace_back( encode(material, settings) ); - // store light information - ext::json::reserve( serializer["lighting"], graph.lights.size() ); - for ( auto& light : graph.lights ) serializer["lighting"].emplace_back( encode(light, settings) ); - // store animation information - ext::json::reserve( serializer["animations"], graph.animations.size() ); - if ( !settings.combined ) { - for ( auto pair : graph.animations ) { - uf::stl::string f = "animation."+pair.first+".json"; - encode(pair.second, settings).writeToFile(directory+"/animation."+pair.first+".json", settings); - serializer["animations"].emplace_back("animation."+pair.first+".json" + (settings.compress ? ".gz" : "")); - } - } else { - for ( auto pair : graph.animations ) serializer["animations"][pair.first] = encode(pair.second, settings); - } - // store skin information - ext::json::reserve( serializer["skins"], graph.skins.size() ); - for ( auto& skin : graph.skins ) serializer["skins"].emplace_back( encode(skin, settings) ); - // store mesh information - ext::json::reserve( serializer["meshes"], graph.meshes.size() ); - if ( !settings.combined ) { - ::EncodingSettings s = settings; - for ( size_t i = 0; i < graph.meshes.size(); ++i ) { - if ( !s.encodeBuffers ) { - s.filename = directory+"/mesh."+std::to_string(i)+".json"; - encode(graph.meshes[i], s).writeToFile(s.filename, settings); - serializer["meshes"].emplace_back( uf::io::filename(s.filename + (settings.compress ? ".gz" : "")) ); - } else { - s.filename = directory+"/mesh."+std::to_string(i); - auto json = encode(graph.meshes[i], s); - serializer["meshes"].emplace_back(json); - } - } - } else { - for ( auto& mesh : graph.meshes ) serializer["meshes"].emplace_back( encode(mesh, settings) ); - } - // 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& job : jobs ) return job(); #endif if ( !settings.combined ) target = directory + "/graph.json"; @@ -2118,6 +2014,7 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) uf::stl::string uf::graph::print( const pod::Graph& graph ) { uf::stl::stringstream ss; +#if 0 ss << "Graph Data:" "\n\tImages: " << graph.images.size() << "" "\n\tTextures: " << graph.textures.size() << "" @@ -2134,11 +2031,12 @@ uf::stl::string uf::graph::print( const pod::Graph& graph ) { for ( auto index : node.children ) print( graph.nodes[index], indent + 1 ); }; print( graph.root, 1 ); +#endif return ss.str(); } uf::Serializer uf::graph::stats( const pod::Graph& graph ) { ext::json::Value json; - +#if 0 size_t memoryTextures = sizeof(pod::Texture::Storage) * graph.textures.size(); size_t memoryMaterials = sizeof(pod::Material::Storage) * graph.materials.size(); size_t memoryLights = sizeof(pod::Light) * graph.lights.size(); @@ -2164,8 +2062,8 @@ uf::Serializer uf::graph::stats( const pod::Graph& graph ) { for ( auto& image : graph.images ) memoryImages += image.getPixels().size(); for ( auto& mesh : graph.meshes ) { - // memoryMeshes += sizeof(pod::Graph::Mesh::vertex_t) * mesh.vertices.size(); - // memoryMeshes += sizeof(pod::Graph::Mesh::index_t) * mesh.indices.size(); + // memoryMeshes += sizeof(uf::Mesh::vertex_t) * mesh.vertices.size(); + // memoryMeshes += sizeof(uf::Mesh::index_t) * mesh.indices.size(); memoryMeshes += mesh.attributes.vertex.size * mesh.attributes.vertex.length; memoryMeshes += mesh.attributes.index.size * mesh.attributes.index.length; } @@ -2211,5 +2109,6 @@ uf::Serializer uf::graph::stats( const pod::Graph& graph ) { "\n\tNodes: " << graph.nodes.size() << " | Bytes: " << memoryNodes << "" "\n\tTotal: " << (memoryTextures + memoryMaterials + memoryLights + memoryImages + memoryMeshes + memoryAnimations + memoryNodes + memoryStrings) << std::endl; */ +#endif return json; } \ No newline at end of file diff --git a/engine/src/engine/graph/mesh.cpp b/engine/src/engine/graph/mesh.cpp deleted file mode 100644 index b3187975..00000000 --- a/engine/src/engine/graph/mesh.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include - -UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Base, - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32B32_SFLOAT, position) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, uv) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, st) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R16G16_SINT, id) -); -UF_VERTEX_DESCRIPTOR(uf::graph::mesh::ID, - UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, position) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32_SFLOAT, uv) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32_SFLOAT, st) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, normal) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, tangent) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R16G16_SINT, id) -); -UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned, - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, position) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32_SFLOAT, uv) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32_SFLOAT, st) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, normal) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, tangent) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16_SINT, id) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16B16A16_SINT, joints) - UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32A32_SFLOAT, weights) -); \ No newline at end of file diff --git a/engine/src/engine/object/behaviors/graph.cpp b/engine/src/engine/object/behaviors/graph.cpp index 52466698..d3580cb8 100644 --- a/engine/src/engine/object/behaviors/graph.cpp +++ b/engine/src/engine/object/behaviors/graph.cpp @@ -66,6 +66,7 @@ void uf::GraphBehavior::initialize( uf::Object& self ) { } void uf::GraphBehavior::destroy( uf::Object& self ) {} void uf::GraphBehavior::tick( uf::Object& self ) { +#if 0 /* Update animations */ if ( this->hasComponent() ) { auto& graph = this->getComponent(); // if ( graph.metadata["flags"]["SKINNED"].as() ) uf::graph::update( graph ); @@ -101,7 +102,7 @@ void uf::GraphBehavior::tick( uf::Object& self ) { auto& node = graph.nodes[i]; instances[i] = uf::transform::model( node.entity ? node.entity->getComponent>() : node.transform ); } - graphic.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance ); + shader.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance ); shader.execute( graphic, mesh.attributes.vertex.pointer ); } else if ( graph.metadata["flags"]["SKINNED"].as() ) { shader.execute( graphic, mesh.attributes.vertex.pointer ); @@ -117,7 +118,7 @@ void uf::GraphBehavior::tick( uf::Object& self ) { auto& node = graph.nodes[i]; instances[i] = uf::transform::model( node.entity ? node.entity->getComponent>() : node.transform ); } - graphic.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance /*storageBuffer*/ ); + shader.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance /*storageBuffer*/ ); } else { struct UniformDescriptor { /*alignas(16)*/ pod::Matrix4f model; @@ -135,7 +136,7 @@ void uf::GraphBehavior::tick( uf::Object& self ) { .model = uf::transform::model( transform ), // .color = uf::vector::decode( metadata["color"], pod::Vector4f{1,1,1,1} ), }; - graphic.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); #endif } } @@ -148,12 +149,14 @@ void uf::GraphBehavior::tick( uf::Object& self ) { instances[i] = node.entity ? uf::transform::model( node.entity->getComponent>() ) : uf::transform::model( node.transform ); } auto& storageBuffer = *graphic.getStorageBuffer("Models"); - graphic.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance /*storageBuffer*/ ); + shader.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance /*storageBuffer*/ ); } #endif #endif +#endif } void uf::GraphBehavior::render( uf::Object& self ) { +#if 0 /* Update uniforms */ if ( !this->hasComponent() ) return; @@ -199,10 +202,11 @@ void uf::GraphBehavior::render( uf::Object& self ) { shader.updateUniform("Camera", uniform); #else pod::Camera::Viewports uniforms = camera.data().viewport; - graphic.updateBuffer( uniforms, shader.getUniformBuffer("Camera") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("Camera") ); #endif } #endif +#endif } void uf::GraphBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {} void uf::GraphBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) {} diff --git a/engine/src/engine/object/behaviors/render.cpp b/engine/src/engine/object/behaviors/render.cpp index 172cb7f7..69b56473 100644 --- a/engine/src/engine/object/behaviors/render.cpp +++ b/engine/src/engine/object/behaviors/render.cpp @@ -62,7 +62,7 @@ void uf::RenderBehavior::tick( uf::Object& self ) { .model = uf::transform::model( transform ), // .color = uf::vector::decode( metadata["color"], pod::Vector4f{ 1, 1, 1, 1 } ), }; - graphic.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); #endif #endif } @@ -115,7 +115,7 @@ void uf::RenderBehavior::render( uf::Object& self ) { shader.updateUniform("Camera", uniform); #else pod::Camera::Viewports uniforms = camera.data().viewport; - graphic.updateBuffer( uniforms, shader.getUniformBuffer("Camera") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("Camera") ); #endif #endif } diff --git a/engine/src/ext/bullet/bullet.cpp b/engine/src/ext/bullet/bullet.cpp index f14011dc..2029336d 100644 --- a/engine/src/ext/bullet/bullet.cpp +++ b/engine/src/ext/bullet/bullet.cpp @@ -10,28 +10,27 @@ class BulletDebugDrawer : public btIDebugDraw { protected: int m; - uf::Mesh mesh; + uf::Mesh mesh; public: virtual void drawLine( const btVector3& from, const btVector3& to, const btVector3& color ) { drawLine( from, to, color, color ); } virtual void drawLine( const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor ) { - auto& A = mesh.vertices.emplace_back(); - A.position = { from.getX(), from.getY(), from.getZ() }; - //{0.0f, 0.0f}, - //{0.0f, 0.0f, 0.0f}, - A.color = { fromColor.getX(), fromColor.getY(), fromColor.getZ(), 1.0f }; - auto& B = mesh.vertices.emplace_back(); - B.position = { to.getX(), to.getY(), to.getZ() }; - //{0.0f, 0.0f}, - //{0.0f, 0.0f, 0.0f}, - B.color = { toColor.getX(), toColor.getY(), toColor.getZ(), 1.0f }; + pod::Vertex_3F2F3F4F vertex; + + vertex.position = { from.getX(), from.getY(), from.getZ() }; + vertex.color = { fromColor.getX(), fromColor.getY(), fromColor.getZ(), 1.0f }; + mesh.insertVertex(vertex); + + vertex.position = { to.getX(), to.getY(), to.getZ() }; + vertex.color = { toColor.getX(), toColor.getY(), toColor.getZ(), 1.0f }; + mesh.insertVertex(vertex); } virtual void drawContactPoint(const btVector3&, const btVector3&, btScalar, int, const btVector3&) { } virtual void reportErrorWarning(const char* str ) { - uf::iostream << "[Bullet] " << str << "\n"; + UF_MSG_WARNING("[Bullet] " << str); } virtual void draw3dText(const btVector3& , const char* str ) { @@ -48,8 +47,8 @@ public: } int getDebugMode(void) const { return m; } - uf::Mesh& getMesh() { return mesh; } - const uf::Mesh& getMesh() const { return mesh; } + uf::Mesh& getMesh() { return mesh; } + const uf::Mesh& getMesh() const { return mesh; } }; bool ext::bullet::debugDrawEnabled = false; @@ -112,7 +111,7 @@ void ext::bullet::initialize() { ext::bullet::dynamicsWorld->setGravity(btVector3(0, -9.81, 0)); ext::bullet::debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe); - ext::bullet::dynamicsWorld->setDebugDrawer(&ext::bullet::debugDrawer); + ext::bullet::dynamicsWorld->setDebugDrawer(&ext::bullet::debugDrawer); #if !UF_ENV_DREAMCAST gContactAddedCallback = contactCallback; @@ -276,46 +275,38 @@ void ext::bullet::detach( pod::Bullet& collider ) { ext::bullet::dynamicsWorld->removeCollisionObject( collider.body ); } -pod::Bullet& ext::bullet::create( uf::Object& object, const pod::Mesh& mesh, bool dynamic ) { +pod::Bullet& ext::bullet::create( uf::Object& object, const uf::Mesh& mesh, bool dynamic ) { auto& transform = object.getComponent>(); auto& collider = ext::bullet::create( object ); auto model = uf::transform::model( collider.transform ); - size_t indices = mesh.attributes.index.length; - size_t indexStride = mesh.attributes.index.size; - uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer; - - size_t vertices = mesh.attributes.vertex.length; - size_t vertexStride = mesh.attributes.vertex.size; - uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; - - uf::renderer::VertexDescriptor vertexAttributePosition; - for ( auto& attribute : mesh.attributes.descriptor ) { - if ( attribute.name == "position" ) vertexAttributePosition = attribute; - } - if ( vertexAttributePosition.name == "" ) return collider; - btTriangleMesh* bMesh = new btTriangleMesh( true, false ); - bMesh->preallocateVertices( vertices ); - for ( size_t currentIndex = 0; currentIndex < vertices; ++currentIndex ) { - uint8_t* vertexSrc = vertexPointer + (currentIndex * vertexStride); - const pod::Vector3f& position = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); - bMesh->findOrAddVertex( btVector3( position.x, position.y, position.z ), false ); - } - if ( mesh.attributes.index.pointer ) { - bMesh->preallocateIndices( indices ); - for ( size_t currentIndex = 0; currentIndex < indices; ++currentIndex ) { - uint32_t index = 0; - uint8_t* indexSrc = indexPointer + (currentIndex * indexStride); - switch ( indexStride ) { - case sizeof( uint8_t): index = *(( uint8_t*) indexSrc); break; - case sizeof(uint16_t): index = *((uint16_t*) indexSrc); break; - case sizeof(uint32_t): index = *((uint32_t*) indexSrc); break; - } - bMesh->addIndex( index ); + for ( auto& attribute : mesh.vertex.attributes ) { + if ( attribute.descriptor.name != "position" ) continue; + + const pod::Vector3f* pointer = (const pod::Vector3f*) attribute.descriptor.pointer; + bMesh->preallocateVertices( mesh.vertex.count ); + for ( auto i = 0; i < mesh.vertex.count; ++i ) { + bMesh->findOrAddVertex( btVector3( pointer[i].x, pointer[i].y, pointer[i].z ), false ); + } + break; + } + if ( mesh.index.count ) { + bMesh->preallocateIndices( mesh.index.count ); + for ( auto& attribute : mesh.index.attributes ) { + size_t count = attribute.descriptor.length / attribute.descriptor.size; + const uint8_t* pointer = (const uint8_t*) attribute.descriptor.pointer; + for ( auto i = 0; i < count; ++i ) { + uint32_t index = 0; + switch ( attribute.descriptor.size ) { + case sizeof( uint8_t): index = (( uint8_t*) pointer)[i]; break; + case sizeof(uint16_t): index = ((uint16_t*) pointer)[i]; break; + case sizeof(uint32_t): index = ((uint32_t*) pointer)[i]; break; + } + bMesh->addIndex( index ); + } } - bMesh->getIndexedMeshArray()[0].m_numTriangles = indices / 3; } collider.shape = new btBvhTriangleMeshShape(bMesh, true); @@ -332,7 +323,6 @@ pod::Bullet& ext::bullet::create( uf::Object& object, const pod::Mesh& mesh, boo triangleInfoMap->m_maxEdgeAngleThreshold = SIMD_HALF_PI*0.25; if ( !false ) btGenerateInternalEdgeInfo( triangleMeshShape, triangleInfoMap ); collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); - return collider; } pod::Bullet& ext::bullet::create( uf::Object& object, const pod::Vector3f& corner, float mass ) { @@ -453,7 +443,10 @@ void UF_API ext::bullet::activateCollision( pod::Bullet& collider, bool enabled void UF_API ext::bullet::debugDraw( uf::Object& object ) { auto& mesh = ext::bullet::debugDrawer.getMesh(); - if ( mesh.vertices.empty() ) return; + mesh.bind(); + + if ( !mesh.vertex.count ) return; + bool create = !object.hasComponent(); auto& graphic = object.getComponent(); graphic.process = false; @@ -468,14 +461,14 @@ void UF_API ext::bullet::debugDraw( uf::Object& object ) { graphic.material.attachShader(uf::io::root + "/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); graphic.initialize(); - graphic.initializeMesh( mesh, 0 ); + graphic.initializeMesh( mesh ); graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST; graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE; graphic.descriptor.lineWidth = 8.0f; } else { graphic.process = true; - graphic.initializeMesh( mesh, 0 ); + graphic.initializeMesh( mesh ); graphic.getPipeline().update( graphic ); } } diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index dcd5c0df..4b0cacfc 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -75,7 +75,7 @@ namespace { } else { transform.position = { 0, 0, 0 }; } - if ( !(graph.mode & uf::graph::LoadMode::INVERT) ) { + if ( !(graph.metadata["flags"]["INVERT"].as()) ) { transform.position.x *= -1; } if ( node.rotation.size() == 4 ) { @@ -111,10 +111,10 @@ namespace { } } -pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mode_t mode, const uf::Serializer& metadata ) { +pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serializer& metadata ) { uf::stl::string extension = uf::io::extension( filename ); if ( extension != "glb" && extension != "gltf" ) { - return uf::graph::load( filename, mode, metadata ); + return uf::graph::load( filename, metadata ); } tinygltf::Model model; @@ -125,7 +125,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod pod::Graph graph; graph.name = filename; - graph.mode = mode; graph.metadata = metadata; if ( !warn.empty() ) UF_MSG_WARNING("glTF warning: " << warn); @@ -136,9 +135,9 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod // load samplers { - graph.samplers.reserve(model.samplers.size()); + uf::graph::storage.samplers.reserve(model.samplers.size()); for ( auto& s : model.samplers ) { - auto& sampler = graph.samplers.emplace_back(); + auto& sampler = uf::graph::storage.samplers[graph.samplers.emplace_back(s.name)]; sampler.descriptor.filter.min = getFilterMode( s.minFilter ); sampler.descriptor.filter.mag = getFilterMode( s.magFilter ); sampler.descriptor.addressMode.u = getWrapMode( s.wrapS ); @@ -149,84 +148,69 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod // load images { - graph.images.reserve(model.images.size()); + uf::graph::storage.images.reserve(model.images.size()); for ( auto& i : model.images ) { - size_t index = graph.images.size(); - auto& image = graph.images.emplace_back(); + auto& image = uf::graph::storage.images[graph.images.emplace_back(i.name)]; image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, true ); } } // generate atlas - if ( mode & uf::graph::LoadMode::ATLAS ) { - graph.atlas.generate( graph.images ); + if ( graph.metadata["flags"]["ATLAS"].as() ) { + // uf::graph::storage.atlases[filename].generate(); } // load textures { - graph.textures.reserve(model.textures.size()); + uf::graph::storage.textures.reserve(model.textures.size()); for ( auto& t : model.textures ) { - auto& texture = graph.textures.emplace_back(); - texture.name = t.name; - - texture.storage.index = t.source; - texture.storage.sampler = t.sampler; - if ( 0 <= t.source && graph.atlas.generated() ) { - size_t index = t.source; - const auto& hash = graph.images[index].getHash(); - auto atlasMin = graph.atlas.mapUv( {0, 0}, hash ); - auto atlasMax = graph.atlas.mapUv( {1, 1}, hash ); - - texture.storage.lerp = { - atlasMin.x, - atlasMin.y, - - atlasMax.x, - atlasMax.y, - }; + auto& texture = uf::graph::storage.textures[graph.textures.emplace_back(t.name)]; + texture.index = t.source; + texture.sampler = t.sampler; + if ( 0 <= t.source && uf::graph::storage.atlases[filename].generated() ) { + auto& image = graph.images[t.source]; + const auto& hash = uf::graph::storage.images[image].getHash(); + auto atlasMin = uf::graph::storage.atlases[filename].mapUv( {0, 0}, hash ); + auto atlasMax = uf::graph::storage.atlases[filename].mapUv( {1, 1}, hash ); + texture.lerp = { atlasMin.x, atlasMin.y, atlasMax.x, atlasMax.y, }; } } } - if ( graph.atlas.generated() ) { - graph.atlas.clear(false); + // clear source images + if ( uf::graph::storage.atlases[filename].generated() ) { + uf::graph::storage.atlases[filename].clear(false); } // load materials { - graph.materials.reserve(model.materials.size()); + uf::graph::storage.materials.reserve(model.materials.size()); for ( auto& m : model.materials ) { - auto& material = graph.materials.emplace_back(); - material.name = m.name; - material.storage.indexAlbedo = m.pbrMetallicRoughness.baseColorTexture.index; - material.storage.indexNormal = m.normalTexture.index; - material.storage.indexEmissive = m.emissiveTexture.index; - material.storage.indexOcclusion = m.occlusionTexture.index; - material.storage.indexMetallicRoughness = m.pbrMetallicRoughness.metallicRoughnessTexture.index; - material.storage.colorBase = { + auto& material = uf::graph::storage.materials[graph.materials.emplace_back(m.name)]; + material.indexAlbedo = m.pbrMetallicRoughness.baseColorTexture.index; + material.indexNormal = m.normalTexture.index; + material.indexEmissive = m.emissiveTexture.index; + material.indexOcclusion = m.occlusionTexture.index; + material.indexMetallicRoughness = m.pbrMetallicRoughness.metallicRoughnessTexture.index; + material.colorBase = { m.pbrMetallicRoughness.baseColorFactor[0], m.pbrMetallicRoughness.baseColorFactor[1], m.pbrMetallicRoughness.baseColorFactor[2], m.pbrMetallicRoughness.baseColorFactor[3], }; - material.storage.colorEmissive = { + material.colorEmissive = { m.emissiveFactor[0], m.emissiveFactor[1], m.emissiveFactor[2], 0 }; - material.storage.factorMetallic = m.pbrMetallicRoughness.metallicFactor; - material.storage.factorRoughness = m.pbrMetallicRoughness.roughnessFactor; - material.storage.factorOcclusion = m.occlusionTexture.strength; - material.storage.factorAlphaCutoff = m.alphaCutoff; + material.factorMetallic = m.pbrMetallicRoughness.metallicFactor; + material.factorRoughness = m.pbrMetallicRoughness.roughnessFactor; + material.factorOcclusion = m.occlusionTexture.strength; + material.factorAlphaCutoff = m.alphaCutoff; + + if ( m.alphaMode == "OPAQUE" ) material.modeAlpha = 0; + else if ( m.alphaMode == "BLEND" ) material.modeAlpha = 1; + else if ( m.alphaMode == "MASK" ) material.modeAlpha = 2; + else UF_MSG_WARNING("Unhandled alpha mode: " << m.alphaMode); - material.alphaMode = m.alphaMode; - if ( material.alphaMode == "OPAQUE" ) { - material.storage.modeAlpha = 0; - } else if ( material.alphaMode == "BLEND" ) { - material.storage.modeAlpha = 1; - } else if ( material.alphaMode == "MASK" ) { - material.storage.modeAlpha = 2; - } else { - UF_MSG_WARNING("Unhandled alpha mode: " << material.alphaMode) - } if ( m.doubleSided && graph.metadata["cull mode"].as() == "auto" ) { graph.metadata["cull mode"] = "none"; } @@ -236,54 +220,19 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod { graph.meshes.reserve(model.meshes.size()); for ( auto& m : model.meshes ) { - // auto& mesh = graph.meshes.emplace_back(); + auto& pair = uf::graph::storage.meshes[graph.meshes.emplace_back(m.name)]; + auto& mesh = pair.mesh; + mesh.bind(); - /* - struct { - uf::Mesh base; - uf::Mesh id; - uf::Mesh skinned; - } meshes; - */ - /* - // use skinned mesh - if ( mode & uf::graph::LoadMode::SKINNED ) { - mesh.set(); - // use ID'd mesh - } else { - mesh.set(); - } - */ - // we'll fill up the most feature complete mesh (skinned) and then convert down to what we need - // this is fine since we only really ever load gltf files once, and parse to an internal format for reuse - /* - uf::Mesh storageMesh; - // already here, just move it over - auto& MESH = graph.meshes.emplace_back(); - auto& mesh = ( mode & uf::graph::LoadMode::SKINNED ) ? MESH.get() : storageMesh; - */ - #if UF_GRAPH_EXPERIMENTAL - uf::Mesh mesh; - auto& varyingMesh = graph.meshes.emplace_back(); - #else - auto& mesh = graph.meshes.emplace_back(); - #endif - - pod::DrawCall drawCall; - drawCall.verticesIndex = mesh.vertices.size(); - drawCall.indicesIndex = mesh.indices.size(); - drawCall.vertices = 0; - drawCall.indices = 0; - for ( auto& primitive : m.primitives ) { - pod::DrawCall dc; - dc.verticesIndex = mesh.vertices.size(); - dc.indicesIndex = mesh.indices.size(); + for ( auto& p : m.primitives ) { + uf::stl::vector vertices; + uf::stl::vector indices; struct Attribute { uf::stl::string name = ""; size_t components = 1; - uf::stl::vector buffer; - uf::stl::vector indices; + uf::stl::vector floats; + uf::stl::vector ints; }; uf::stl::unordered_map attributes = { {"POSITION", {}}, @@ -297,14 +246,14 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod for ( auto& kv : attributes ) { auto& attribute = kv.second; attribute.name = kv.first; - auto it = primitive.attributes.find(attribute.name); - if ( it == primitive.attributes.end() ) continue; + auto it = p.attributes.find(attribute.name); + if ( it == p.attributes.end() ) continue; auto& accessor = model.accessors[it->second]; auto& view = model.bufferViews[accessor.bufferView]; if ( attribute.name == "POSITION" ) { - dc.vertices = accessor.count; + vertices.resize(accessor.count); pod::Vector3f minCorner = { accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] }; pod::Vector3f maxCorner = { accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] }; @@ -315,34 +264,30 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod auto* buffer = reinterpret_cast(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); attribute.components = accessor.ByteStride(view) / sizeof(uint16_t); size_t len = accessor.count * attribute.components; - attribute.indices.reserve( len ); - attribute.indices.insert( attribute.indices.end(), &buffer[0], &buffer[len] ); + attribute.ints.assign( &buffer[0], &buffer[len] ); } else { auto* buffer = reinterpret_cast(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); attribute.components = accessor.ByteStride(view) / sizeof(float); size_t len = accessor.count * attribute.components; - attribute.buffer.reserve( len ); - attribute.buffer.insert( attribute.buffer.end(), &buffer[0], &buffer[len] ); + attribute.floats.assign( &buffer[0], &buffer[len] ); } } - mesh.vertices.reserve( dc.vertices + dc.verticesIndex ); - for ( size_t i = 0; i < dc.vertices; ++i ) { + for ( size_t i = 0; i < vertices.size(); ++i ) { #define ITERATE_ATTRIBUTE( name, member )\ - if ( !attributes[name].indices.empty() ) { \ + if ( !attributes[name].ints.empty() ) { \ for ( size_t j = 0; j < attributes[name].components; ++j )\ - vertex.member[j] = attributes[name].indices[i * attributes[name].components + j];\ - } else if ( !attributes[name].buffer.empty() ) { \ + vertex.member[j] = attributes[name].ints[i * attributes[name].components + j];\ + } else if ( !attributes[name].floats.empty() ) { \ for ( size_t j = 0; j < attributes[name].components; ++j )\ - vertex.member[j] = attributes[name].buffer[i * attributes[name].components + j];\ + vertex.member[j] = attributes[name].floats[i * attributes[name].components + j];\ } - auto& vertex = mesh.vertices.emplace_back(); + auto& vertex = vertices[i]; ITERATE_ATTRIBUTE("POSITION", position); ITERATE_ATTRIBUTE("TEXCOORD_0", uv); ITERATE_ATTRIBUTE("NORMAL", normal); ITERATE_ATTRIBUTE("TANGENT", tangent); - vertex.id = { 0, primitive.material }; ITERATE_ATTRIBUTE("JOINTS_0", joints); ITERATE_ATTRIBUTE("WEIGHTS_0", weights); @@ -350,26 +295,27 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod // required due to reverse-Z projection matrix flipping the X axis as well // default is to proceed with this - if ( !(graph.mode & uf::graph::LoadMode::INVERT) ){ + if ( !(graph.metadata["flags"]["INVERT"].as()) ){ vertex.position.x *= -1; vertex.normal.x *= -1; vertex.tangent.x *= -1; } + + } - if ( primitive.indices > -1 ) { - auto& accessor = model.accessors[primitive.indices]; + if ( p.indices > -1 ) { + auto& accessor = model.accessors[p.indices]; auto& view = model.bufferViews[accessor.bufferView]; auto& buffer = model.buffers[view.buffer]; - dc.indices = static_cast(accessor.count); - mesh.indices.reserve( dc.indices + dc.indicesIndex ); - const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]); + indices.reserve( static_cast(accessor.count) ); #define COPY_INDICES()\ - for (size_t index = 0; index < dc.indices; index++)\ - mesh.indices.emplace_back(buf[index] + dc.verticesIndex); + for (size_t index = 0; index < indices.size(); index++)\ + indices.emplace_back(buf[index]); + const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]); switch (accessor.componentType) { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: { auto* buf = static_cast( pointer ); @@ -390,49 +336,22 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod #undef COPY_INDICES } - drawCall.vertices += dc.vertices; - drawCall.indices += dc.indices; + pair.drawCommands.emplace_back(pod::DrawCommand{ + .indices = indices.size(), + .instances = 1, + .indexID = mesh.index.count, + .vertexID = mesh.vertex.count, + + .instanceID = mesh.instance.count, + .materialID = p.material, + .objectID = 0, + .vertices = vertices.size(), + }); + + mesh.insertVertices(vertices); + mesh.insertIndices(indices); } mesh.updateDescriptor(); - - // convert to a more optimal format - #if UF_GRAPH_EXPERIMENTAL - bool override = graph.metadata["debug"]["override varying mesh"].as(); - // use skinned mesh - if ( override || (mode & uf::graph::LoadMode::SKINNED) ) { - auto& m = varyingMesh.get(); - m.indices = std::move( mesh.indices ); - m.vertices = std::move( mesh.vertices ); - #if 0 - // use barebone mesh - } else if ( UF_ENV_DREAMCAST ) { - auto& m = varyingMesh.get(); - m.indices = std::move( mesh.indices ); - m.vertices.reserve( mesh.vertices.size() ); - for ( auto& v : mesh.vertices ) m.vertices.emplace_back(uf::graph::mesh::Base{ - .position = v.position, - .uv = v.uv, - .st = v.st, - .normal = v.normal, - }); - #endif - // use ID'd mesh - } else { - auto& m = varyingMesh.get(); - m.indices = std::move( mesh.indices ); - m.vertices.reserve( mesh.vertices.size() ); - for ( auto& v : mesh.vertices ) m.vertices.emplace_back(uf::graph::mesh::ID{ - .position = v.position, - .uv = v.uv, - .st = v.st, - .normal = v.normal, - .tangent = v.tangent, - .id = v.id, - }); - } - varyingMesh.updateDescriptor(); - #else - #endif } } // load node information/meshes @@ -449,8 +368,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod // load lights { for ( auto& l : model.lights ) { - auto& light = graph.lights.emplace_back(); - light.name = l.name; + auto& light = graph.lights[l.name]; light.color = { l.color[0], l.color[1], l.color[2], }; light.intensity = l.intensity; light.range = l.range; @@ -542,19 +460,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, uf::graph::load_mod } } } - { - if ( graph.metadata["export"]["should"].as() ) uf::graph::save( graph, filename ); - /* - bool shouldExport = false; - if ( graph.metadata["debug"]["export"].is() ) shouldExport = graph.metadata["debug"]["export"].as(); - else if ( ext::json::isObject( graph.metadata["debug"]["export"] ) ) { - if ( graph.metadata["debug"]["export"]["should"].is() ) - shouldExport = graph.metadata["debug"]["export"]["should"].as(); - else - shouldExport = true; - } - if ( shouldExport ) uf::graph::save( graph, filename ); - */ - } + if ( graph.metadata["export"]["should"].as() ) uf::graph::save( graph, filename ); return graph; } \ No newline at end of file diff --git a/engine/src/ext/meshopt/meshopt.cpp b/engine/src/ext/meshopt/meshopt.cpp index a13d6e7d..44566bb2 100644 --- a/engine/src/ext/meshopt/meshopt.cpp +++ b/engine/src/ext/meshopt/meshopt.cpp @@ -3,7 +3,7 @@ #include #endif -void ext::meshopt::optimize( pod::Mesh& mesh, size_t o ) { +void ext::meshopt::optimize( uf::Mesh& mesh, size_t o ) { #if 0 mesh.updateDescriptor(); diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index b75c1bfd..160b8d82 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #define VERBOSE false #define VERBOSE_SUBMIT false @@ -397,14 +397,14 @@ void ext::opengl::CommandBuffer::draw( const ext::opengl::CommandBuffer::InfoDra size_t vertexStride = drawInfo.descriptor.attributes.vertex.size; size_t vertices = vertexBuffer.range / vertexStride; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeColor, vertexAttributeUv, vertexAttributeSt, vertexAttributeId; - for ( auto& attribute : drawInfo.descriptor.attributes.descriptor ) { + for ( auto& attribute : drawInfo.descriptor.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "color" ) vertexAttributeColor = attribute; @@ -701,14 +701,14 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: size_t vertexStride = drawInfo.descriptor.attributes.vertex.size; size_t vertices = vertexBuffer.range / vertexStride; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeColor, vertexAttributeUv, vertexAttributeSt, vertexAttributeId; - for ( auto& attribute : drawInfo.descriptor.attributes.descriptor ) { + for ( auto& attribute : drawInfo.descriptor.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "color" ) vertexAttributeColor = attribute; diff --git a/engine/src/ext/opengl/graphic.cpp b/engine/src/ext/opengl/graphic.cpp index fd7d899d..24ae8405 100644 --- a/engine/src/ext/opengl/graphic.cpp +++ b/engine/src/ext/opengl/graphic.cpp @@ -38,8 +38,8 @@ void ext::opengl::Pipeline::initialize( const Graphic& graphic, const GraphicDes { GL_ERROR_CHECK(glGenVertexArrays(1, &vertexArray)); GL_ERROR_CHECK(glBindVertexArray(vertexArray)); - for ( size_t i = 0; i < descriptor.attributes.descriptor.size(); ++i ) { - auto& attribute = descriptor.attributes.descriptor[i]; + for ( size_t i = 0; i < descriptor.attributes.vertex.descriptor.size(); ++i ) { + auto& attribute = descriptor.attributes.vertex.descriptor[i]; GL_ERROR_CHECK(glEnableVertexAttribArray(i)); GL_ERROR_CHECK(glVertexAttribPointer(0, attribute.components, attribute.type, false, descriptor.attributes.vertex.size, attribute.offset)); @@ -183,7 +183,7 @@ ext::opengl::Pipeline& ext::opengl::Graphic::initializePipeline( const GraphicDe return pipeline; } -void ext::opengl::Graphic::initializeAttributes( const pod::Mesh::Attributes& attributes ) { +void ext::opengl::Graphic::initializeAttributes( const uf::Mesh::Attributes& attributes ) { // already generated, check if we can just update if ( descriptor.indices > 0 ) { if ( descriptor.attributes.vertex.size == attributes.vertex.size && descriptor.attributes.index.size == attributes.index.size && descriptor.indices == attributes.index.length ) { @@ -266,14 +266,14 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe } if ( !vertexBuffer.buffer || !indexBuffer.buffer ) return; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeColor, vertexAttributeUv, vertexAttributeSt, vertexAttributeId; - for ( auto& attribute : descriptor.attributes.descriptor ) { + for ( auto& attribute : descriptor.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; // else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; // else if ( attribute.name == "color" ) vertexAttributeColor = attribute; @@ -524,9 +524,9 @@ ext::opengl::GraphicDescriptor::hash_t ext::opengl::GraphicDescriptor::hash() co serializer["offsets"]["vertex"] = offsets.vertex; serializer["offsets"]["index"] = offsets.index; - for ( uint8_t i = 0; i < attributes.descriptor.size(); ++i ) { - serializer["geometry"]["attributes"][i]["format"] = attributes.descriptor[i].format; - serializer["geometry"]["attributes"][i]["offset"] = attributes.descriptor[i].offset; + for ( uint8_t i = 0; i < attributes.vertex.descriptor.size(); ++i ) { + serializer["geometry"]["attributes"][i]["format"] = attributes.vertex.descriptor[i].format; + serializer["geometry"]["attributes"][i]["offset"] = attributes.vertex.descriptor[i].offset; } serializer["topology"] = topology; @@ -558,9 +558,9 @@ ext::opengl::GraphicDescriptor::hash_t ext::opengl::GraphicDescriptor::hash() co hash += std::hash{}(offsets.vertex); hash += std::hash{}(offsets.index); - for ( uint8_t i = 0; i < attributes.descriptor.size(); ++i ) { - hash += std::hash{}(attributes.descriptor[i].format); - hash += std::hash{}(attributes.descriptor[i].offset); + for ( uint8_t i = 0; i < attributes.vertex.descriptor.size(); ++i ) { + hash += std::hash{}(attributes.vertex.descriptor[i].format); + hash += std::hash{}(attributes.vertex.descriptor[i].offset); } hash += std::hash{}(topology); diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index 71846a9c..8cb78429 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -189,12 +189,12 @@ void UF_API ext::opengl::initialize() { size_t vertexStride = graphic.descriptor.attributes.vertex.size; size_t vertices = vertexBuffer.range / vertexStride; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeUv, vertexAttributeNormal, vertexAttributeId; - for ( auto& attribute : graphic.descriptor.attributes.descriptor ) { + for ( auto& attribute : graphic.descriptor.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; @@ -255,12 +255,12 @@ void UF_API ext::opengl::initialize() { size_t vertexStride = graphic.descriptor.attributes.vertex.size; size_t vertices = vertexBuffer.range / vertexStride; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeJoints, vertexAttributeWeights; - for ( auto& attribute : graphic.descriptor.attributes.descriptor ) { + for ( auto& attribute : graphic.descriptor.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "joints" ) vertexAttributeJoints = attribute; diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index 979e69fa..c9e391c0 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -99,8 +99,8 @@ void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) { ext::vulkan::Buffer::~Buffer() { // this->destroy(); } -void ext::vulkan::Buffer::initialize( VkDevice device ) { - this->device = device; +void ext::vulkan::Buffer::initialize( ext::vulkan::Device& device ) { + this->device = &device; } void ext::vulkan::Buffer::destroy() { if ( !device ) return; @@ -114,6 +114,50 @@ void ext::vulkan::Buffer::destroy() { buffer = nullptr; memory = nullptr; } +void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) { + if ( stage ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties + VK_CHECK_RESULT(device->createBuffer( + usage, + memoryProperties, + *this, + length + )); + if ( data ) update( data, length, stage ); +} +void ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool stage ) const { + if ( length > allocationInfo.size ) { + UF_MSG_DEBUG("LENGTH OF " << length << " EXCEEDS BUFFER SIZE " << allocationInfo.size ); + Buffer& b = *const_cast(this); + b.destroy(); + b.initialize( data, length, usage, memoryProperties, stage ); + return; + } + if ( !stage ) { + void* map = this->map(); + memcpy(map, data, length); + if ((this->memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) this->flush(); + this->unmap(); + return; + } + + Buffer staging; + device->createBuffer( + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + staging, + length, + data + ); + + // Copy to staging buffer + VkCommandBuffer copyCommand = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkBufferCopy region = {}; + region.size = length; + vkCmdCopyBuffer(copyCommand, staging.buffer, buffer, 1, ®ion); + + device->flushCommandBuffer(copyCommand, true); + staging.destroy(); +} // // Buffers @@ -133,93 +177,13 @@ void ext::vulkan::Buffers::destroy() { size_t ext::vulkan::Buffers::initializeBuffer( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) { size_t index = buffers.size(); - Buffer& buffer = buffers.emplace_back(); - - // Stage - if ( !stage ) { - VK_CHECK_RESULT(device->createBuffer( - usage, - memoryProperties, - buffer, - length - )); - this->updateBuffer( data, length, buffer, stage ); - return index; - } - - // implicitly set properties - usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - Buffer staging; - VkDeviceSize storageBufferSize = length; - device->createBuffer( - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - staging, - storageBufferSize, - data - ); - - device->createBuffer( - usage, - memoryProperties, - buffer, - storageBufferSize - ); - - // Copy to staging buffer - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - VkBufferCopy copyRegion = {}; - copyRegion.size = storageBufferSize; - vkCmdCopyBuffer(copyCmd, staging.buffer, buffer.buffer, 1, ©Region); - device->flushCommandBuffer(copyCmd, true); - staging.destroy(); - + auto& buffer = buffers.emplace_back(); + buffer.initialize( *device ); + buffer.initialize( data, length, usage, memoryProperties, stage ); return index; } void ext::vulkan::Buffers::updateBuffer( const void* data, VkDeviceSize length, const Buffer& buffer, bool stage ) const { -// assert(buffer.allocationInfo.size == length); - - if ( length > buffer.allocationInfo.size ) { - if ( !true ) { - VK_VALIDATION_MESSAGE("Mismatch buffer update: Requesting " << buffer.allocationInfo.size << ", got " << length << "; Userdata might've been corrupted, please try validating with shader.validate() before updating buffer"); - } else { - VK_VALIDATION_MESSAGE("Mismatch buffer update: Requesting " << buffer.allocationInfo.size << ", got " << length << ", resetting for safety"); - length = buffer.allocationInfo.size; - } -// assert(buffer.allocationInfo.size > length); - } - if ( !stage ) { - #if UF_TESTING - void* map = buffer.map(); - memcpy(map, data, length); - if ((buffer.memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) buffer.flush(); - buffer.unmap(); - #else - void* map = buffer.map(); - memcpy(map, data, length); - if ((buffer.memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) buffer.flush(); - buffer.unmap(); - #endif - return; - } - Buffer staging; - device->createBuffer( - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - staging, - length, - data - ); - - // Copy to staging buffer - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - VkBufferCopy copyRegion = {}; - copyRegion.size = length; - vkCmdCopyBuffer(copyCmd, staging.buffer, buffer.buffer, 1, ©Region); - - device->flushCommandBuffer(copyCmd, true); - staging.destroy(); + buffer.update( data, length, stage ); } #endif \ No newline at end of file diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index e6352461..6d61f336 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -394,7 +394,7 @@ VkResult ext::vulkan::Device::createBuffer( VkDeviceSize size, const void* data ) { - buffer.device = logicalDevice; + buffer.device = this; buffer.usage = usage; buffer.memoryProperties = memoryProperties; diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 3f1c6f34..1b126de9 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -42,8 +42,8 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes uf::stl::vector blendAttachmentStates; uf::stl::vector shaderDescriptors; - uf::stl::vector vertexAttributeDescriptions; - + uf::stl::vector inputBindingDescriptions; + uf::stl::vector attributeDescriptions; { for ( auto* shaderPointer : shaders ) { @@ -209,30 +209,46 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes 0 ); - // Binding description - uf::stl::vector vertexBindingDescriptions = { - ext::vulkan::initializers::vertexInputBindingDescription( - VERTEX_BUFFER_BIND_ID, - descriptor.attributes.vertex.size, - VK_VERTEX_INPUT_RATE_VERTEX - ) - }; - // Attribute descriptions - // Describes memory layout and shader positions - for ( auto& attribute : descriptor.attributes.descriptor ) { - vertexAttributeDescriptions.emplace_back(ext::vulkan::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - vertexAttributeDescriptions.size(), - attribute.format, - attribute.offset - )); + // Vertex binding description + size_t vertexBindID = 0; + size_t vertexLocationID = 0; + if ( !descriptor.inputs.vertex.attributes.empty() ) { + if ( 0 <= descriptor.inputs.vertex.interleaved ) { + inputBindingDescriptions.emplace_back(ext::vulkan::initializers::vertexInputBindingDescription( + vertexBindID, // descriptor.inputs.vertex.interleaved, + descriptor.inputs.vertex.stride, + VK_VERTEX_INPUT_RATE_VERTEX + )); + for ( auto& attribute : descriptor.inputs.vertex.attributes ) { + attributeDescriptions.emplace_back(ext::vulkan::initializers::vertexInputAttributeDescription( + vertexBindID, + vertexLocationID++, + attribute.descriptor.format, + attribute.descriptor.offset + )); + } + ++vertexBindID; + } else for ( auto& attribute : descriptor.inputs.vertex.attributes ) { + inputBindingDescriptions.emplace_back(ext::vulkan::initializers::vertexInputBindingDescription( + vertexBindID, // attribute.buffer, + attribute.descriptor.size, + VK_VERTEX_INPUT_RATE_VERTEX + )); + attributeDescriptions.emplace_back(ext::vulkan::initializers::vertexInputAttributeDescription( + vertexBindID, + vertexLocationID++, + attribute.descriptor.format, + 0 // attribute.descriptor.offset + )); + ++vertexBindID; + } } VkPipelineVertexInputStateCreateInfo vertexInputState = ext::vulkan::initializers::pipelineVertexInputStateCreateInfo(); - vertexInputState.vertexBindingDescriptionCount = vertexBindingDescriptions.size(); - vertexInputState.pVertexBindingDescriptions = vertexBindingDescriptions.data(); - vertexInputState.vertexAttributeDescriptionCount = vertexAttributeDescriptions.size(); - vertexInputState.pVertexAttributeDescriptions = vertexAttributeDescriptions.data(); + vertexInputState.vertexBindingDescriptionCount = inputBindingDescriptions.size(); + vertexInputState.pVertexBindingDescriptions = inputBindingDescriptions.data(); + vertexInputState.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputState.pVertexAttributeDescriptions = attributeDescriptions.data(); for ( auto* shader : shaders ) shaderDescriptors.emplace_back(shader->descriptor); @@ -257,11 +273,9 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes VK_CHECK_RESULT(vkCreateGraphicsPipelines( device, device.pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); } - -// graphic.process = true; return; + PIPELINE_INITIALIZATION_INVALID: -// graphic.process = false; VK_DEBUG_VALIDATION_MESSAGE("Pipeline initialization invalid, updating next tick..."); uf::thread::add( uf::thread::get("Main"), [&]() -> int { this->initialize( graphic, descriptor ); @@ -271,32 +285,47 @@ PIPELINE_INITIALIZATION_INVALID: void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const { auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; auto shaders = getShaders( graphic.material.shaders ); - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - - if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) { - bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; - } - size_t offset = 0; - for ( auto& pushConstant : shader.pushConstants ) { - // - // if ( ext::json::isObject( shader.metadata.json["definitions"]["pushConstants"]["PushConstant"] ) ) { - if ( shader.metadata.definitions.pushConstants.count("PushConstant") > 0 ) { - if ( shader.descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT ) { + for ( auto* shader : shaders ) { + if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + #if 0 + if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) { + if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT ) { struct PushConstant { uint32_t pass; uint32_t draw; } pushConstant = { pass, draw }; - vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, sizeof(pushConstant), &pushConstant ); + ( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, sizeof(pushConstant), &pushConstant ); + } + } else + #endif + if ( !shader->pushConstants.empty() ) { + auto& pushConstant = shader->pushConstants.front(); + size_t size = pushConstant.size(); + void* data = pushConstant.data().data; + if ( size && data ) { + vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, size, data ); + } + } + /* + size_t offset = 0; + for ( auto& pushConstant : shader->pushConstants ) { + if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) { + if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT ) { + struct PushConstant { + uint32_t pass; + uint32_t draw; + } pushConstant = { pass, draw }; + ( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, sizeof(pushConstant), &pushConstant ); } } else { size_t len = pushConstant.data().len; void* pointer = pushConstant.data().data; if ( len > 0 && pointer ) { - vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, len, pointer ); + vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, len, pointer ); } } } + */ } // Bind descriptor sets describing shader binding points vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); @@ -312,16 +341,12 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip if ( descriptorSet == VK_NULL_HANDLE ) return; this->descriptor = descriptor; - //descriptor = d; RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true); auto& renderTarget = renderMode.getRenderTarget(descriptor.renderTarget ); - uf::stl::vector descriptorSetLayoutBindings; + auto shaders = getShaders( graphic.material.shaders ); - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); - } + uf::stl::vector writeDescriptorSets; struct { uf::stl::vector uniform; @@ -337,6 +362,8 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip uf::stl::vector input; } infos; + uf::stl::vector types; + if ( descriptor.subpass < renderTarget.passes.size() ) { auto& subpass = renderTarget.passes[descriptor.subpass]; for ( auto& input : subpass.inputs ) { @@ -347,56 +374,35 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip } } - { - for ( auto& texture : graphic.material.textures ) { - infos.image.emplace_back(texture.descriptor); - switch ( texture.viewType ) { - case VK_IMAGE_VIEW_TYPE_2D: - infos.image2D.emplace_back(texture.descriptor); - break; - case VK_IMAGE_VIEW_TYPE_CUBE: - infos.imageCube.emplace_back(texture.descriptor); - break; - case VK_IMAGE_VIEW_TYPE_3D: - infos.image3D.emplace_back(texture.descriptor); - break; - default: - infos.imageUnknown.emplace_back(texture.descriptor); - break; - } + for ( auto& texture : graphic.material.textures ) { + infos.image.emplace_back(texture.descriptor); + switch ( texture.viewType ) { + case VK_IMAGE_VIEW_TYPE_2D: infos.image2D.emplace_back(texture.descriptor); break; + case VK_IMAGE_VIEW_TYPE_CUBE: infos.imageCube.emplace_back(texture.descriptor); break; + case VK_IMAGE_VIEW_TYPE_3D: infos.image3D.emplace_back(texture.descriptor); break; + default: infos.imageUnknown.emplace_back(texture.descriptor); break; } - for ( auto& sampler : graphic.material.samplers ) infos.sampler.emplace_back(sampler.descriptor.info); + } + for ( auto& sampler : graphic.material.samplers ) { + infos.sampler.emplace_back(sampler.descriptor.info); } size_t consumes = 0; -// uf::stl::vector types; - uf::stl::vector types; - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - - #define PARSE_BUFFER( buffers ) for ( auto& buffer : buffers ) {\ - if ( buffer.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {\ - infos.uniform.emplace_back(buffer.descriptor);\ - }\ - if ( buffer.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) {\ - infos.storage.emplace_back(buffer.descriptor);\ - }\ + for ( auto* shader : shaders ) { + for ( auto& buffer : shader->buffers ) { + if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); + if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); } - PARSE_BUFFER(shader.buffers) - PARSE_BUFFER(graphic.buffers) - // check if we can even consume that many infos - for ( auto& layout : shader.descriptorSetLayoutBindings ) { + for ( auto& layout : shader->descriptorSetLayoutBindings ) { switch ( layout.descriptorType ) { // consume an texture image info case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - consumes += layout.descriptorCount; - // uf::stl::string binding = std::to_string(layout.binding); - // uf::stl::string imageType = shader.metadata.json["definitions"]["textures"][binding]["type"].as(); - ext::vulkan::enums::Image::viewType_t imageType = shader.metadata.definitions.textures.at(layout.binding).type; + consumes += layout.descriptorCount; + ext::vulkan::enums::Image::viewType_t imageType = shader->metadata.definitions.textures.at(layout.binding).type; types.reserve(consumes); for ( size_t i = 0; i < layout.descriptorCount; ++i ) types.emplace_back(imageType); } break; @@ -421,7 +427,6 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.emplace_back(Texture2D::empty.descriptor); for ( size_t i = infos.image.size(); i < consumes; ++i ) { - // uf::stl::string type = i < types.size() ? types[i] : ""; ext::vulkan::enums::Image::viewType_t type = i < types.size() ? types[i] : ext::vulkan::enums::Image::viewType_t{}; if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) infos.image.emplace_back(Texture3D::empty.descriptor); else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) infos.image.emplace_back(TextureCube::empty.descriptor); @@ -441,33 +446,16 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip auto samplerInfo = infos.sampler.begin(); auto inputInfo = infos.input.begin(); - - uf::stl::vector writeDescriptorSets; - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - - // UF_MSG_DEBUG(shader.filename << ": "); - // UF_MSG_DEBUG("\tAVAILABLE UNIFORM BUFFERS: " << infos.uniform.size()); - // UF_MSG_DEBUG("\tAVAILABLE STORAGE BUFFERS: " << infos.storage.size()); - // UF_MSG_DEBUG("\tCONSUMING : " << shader.descriptorSetLayoutBindings.size()); - - for ( auto& layout : shader.descriptorSetLayoutBindings ) { - // VK_VALIDATION_MESSAGE(shader.filename << "\tType: " << layout.descriptorType << "\tConsuming: " << layout.descriptorCount); + for ( auto* shader : shaders ) { + for ( auto& layout : shader->descriptorSetLayoutBindings ) { switch ( layout.descriptorType ) { // consume an texture image info case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - // UF_MSG_DEBUG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " IMAGE"); - // if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ) UF_MSG_DEBUG("\t\tCOMBINED_IMAGE_SAMPLER"); - // if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ) UF_MSG_DEBUG("\t\tSAMPLED_IMAGE"); - // if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ) UF_MSG_DEBUG("\t\tSTORAGE_IMAGE"); - // if ( layout.descriptorCount == 1 ) UF_MSG_DEBUG(i.imageView << "\t" << (*imageInfo).imageLayout); - - #if 1 - ext::vulkan::enums::Image::viewType_t imageType = shader.metadata.definitions.textures.at(layout.binding).type; + ext::vulkan::enums::Image::viewType_t imageType = shader->metadata.definitions.textures.at(layout.binding).type; if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_2D ) { - UF_ASSERT_BREAK_MSG( image2DInfo != infos.image2D.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( image2DInfo != infos.image2D.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -477,7 +465,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip )); image2DInfo += layout.descriptorCount; } else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) { - UF_ASSERT_BREAK_MSG( imageCubeInfo != infos.imageCube.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( imageCubeInfo != infos.imageCube.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -487,7 +475,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip )); imageCubeInfo += layout.descriptorCount; } else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_3D ) { - UF_ASSERT_BREAK_MSG( image3DInfo != infos.image3D.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( image3DInfo != infos.image3D.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -497,7 +485,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip )); image3DInfo += layout.descriptorCount; } else { - UF_ASSERT_BREAK_MSG( imageUnknownInfo != infos.imageUnknown.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( imageUnknownInfo != infos.imageUnknown.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -507,21 +495,9 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip )); imageUnknownInfo += layout.descriptorCount; } - #else - UF_ASSERT_BREAK_MSG( imageInfo != infos.image.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) - writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( - descriptorSet, - layout.descriptorType, - layout.binding, - &(*imageInfo), - layout.descriptorCount - )); - imageInfo += layout.descriptorCount; - #endif } break; case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { - // UF_MSG_DEBUG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " INPUT_ATTACHMENT"); - UF_ASSERT_BREAK_MSG( inputInfo != infos.input.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( inputInfo != infos.input.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -532,8 +508,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip inputInfo += layout.descriptorCount; } break; case VK_DESCRIPTOR_TYPE_SAMPLER: { - // UF_MSG_DEBUG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " SAMPLER"); - UF_ASSERT_BREAK_MSG( samplerInfo != infos.sampler.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( samplerInfo != infos.sampler.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -544,8 +519,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip samplerInfo += layout.descriptorCount; } break; case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { - // UF_MSG_DEBUG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " UNIFORM_BUFFER"); - UF_ASSERT_BREAK_MSG( uniformBufferInfo != infos.uniform.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( uniformBufferInfo != infos.uniform.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -556,8 +530,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip uniformBufferInfo += layout.descriptorCount; } break; case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: { - // UF_MSG_DEBUG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " STORAGE_BUFFER"); - UF_ASSERT_BREAK_MSG( storageBufferInfo != infos.storage.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + UF_ASSERT_BREAK_MSG( storageBufferInfo != infos.storage.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -571,6 +544,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip } } + // validate writeDescriptorSets for ( auto& descriptor : writeDescriptorSets ) { for ( size_t i = 0; i < descriptor.descriptorCount; ++i ) { if ( descriptor.pBufferInfo ) { @@ -588,17 +562,10 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip if ( descriptor.pImageInfo[i].imageView == VK_NULL_HANDLE || descriptor.pImageInfo[i].imageLayout == VK_IMAGE_LAYOUT_UNDEFINED ) { VK_DEBUG_VALIDATION_MESSAGE("Null image view or layout is undefined, replacing with fallback texture..."); auto pointer = const_cast(&descriptor.pImageInfo[i]); - // uf::stl::string binding = std::to_string(descriptor.dstBinding); - // uf::stl::string imageType = ""; ext::vulkan::enums::Image::viewType_t imageType{}; - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - - if ( shader.metadata.definitions.textures.count(descriptor.dstBinding) == 0 ) continue; - imageType = shader.metadata.definitions.textures.at(descriptor.dstBinding).type; - // auto& info = shader.metadata.json["definitions"]["textures"][binding]; - // if ( ext::json::isNull(info) ) continue; - // imageType = info["type"].as(); + for ( auto* shader : shaders ) { + if ( shader->metadata.definitions.textures.count(descriptor.dstBinding) == 0 ) continue; + imageType = shader->metadata.definitions.textures.at(descriptor.dstBinding).type; break; } if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_3D ) { @@ -615,9 +582,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip pointer->imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; } } - if ( descriptor.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || - descriptor.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER - ) { + if ( descriptor.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ) { if ( !descriptor.pImageInfo[i].sampler ) { VK_DEBUG_VALIDATION_MESSAGE("Image descriptor type is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, yet lacks a sampler, adding default sampler..."); auto pointer = const_cast(&descriptor.pImageInfo[i]); @@ -629,7 +594,6 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip } renderMode.rebuild = true; -// graphic.process = true; vkUpdateDescriptorSets( *device, @@ -797,49 +761,55 @@ ext::vulkan::Pipeline& ext::vulkan::Graphic::initializePipeline( const GraphicDe return pipeline; } -void ext::vulkan::Graphic::initializeAttributes( const pod::Mesh::Attributes& attributes ) { - // already generated, check if we can just update - if ( descriptor.indices > 0 ) { - if ( descriptor.attributes.vertex.size == attributes.vertex.size && descriptor.attributes.index.size == attributes.index.size && descriptor.indices == attributes.index.length ) { - // too lazy to check if this equals, only matters in pipeline creation anyways - descriptor.attributes = attributes; +void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { + // generate indices if not found + if ( mesh.index.count == 0 ) mesh.generateIndices(); + // generate indirect data if not found + if ( mesh.indirect.count == 0 ) mesh.generateIndirect(); + // ensure our descriptors are proper + mesh.updateDescriptor(); - int32_t vertexBuffer = -1; - int32_t indexBuffer = -1; - for ( size_t i = 0; i < buffers.size(); ++i ) { - if ( buffers[i].usage & uf::renderer::enums::Buffer::VERTEX ) vertexBuffer = i; - if ( buffers[i].usage & uf::renderer::enums::Buffer::INDEX ) indexBuffer = i; - } + // copy descriptors + descriptor.inputs.vertex = mesh.vertex; + descriptor.inputs.index = mesh.index; + descriptor.inputs.instance = mesh.instance; + descriptor.inputs.indirect = mesh.indirect; - if ( vertexBuffer > 0 && indexBuffer > 0 ) { - updateBuffer( - (const void*) attributes.vertex.pointer, - attributes.vertex.size * attributes.vertex.length, - vertexBuffer - ); - updateBuffer( - (const void*) attributes.index.pointer, - attributes.index.size * attributes.index.length, - indexBuffer - ); - return; - } + // create buffer if not set and requested + if ( !initialized && buffer ) { + // ensures each buffer index reflects nicely + struct Queue { + void* data; + size_t size; + uf::renderer::enums::Buffer::type_t usage; + }; + uf::stl::vector queue; + descriptor.inputs.bufferOffset = buffers.empty() ? 0 : buffers.size() - 1; + + #define PARSE_ATTRIBUTE(i, usage) {\ + auto& buffer = mesh.buffers[i];\ + if ( queue.size() <= i ) queue.resize( i );\ + if ( !buffer.empty() ) queue.emplace_back(Queue{ (void*) buffer.data(), buffer.size(), usage });\ + } + #define PARSE_INPUT(name, usage){\ + if ( mesh.isInterleaved( mesh.name.interleaved ) ) PARSE_ATTRIBUTE(descriptor.inputs.name.interleaved, usage)\ + else for ( auto& attribute : descriptor.inputs.name.attributes ) PARSE_ATTRIBUTE(attribute.buffer, usage)\ + } + + PARSE_INPUT(vertex, uf::renderer::enums::Buffer::VERTEX) + PARSE_INPUT(index, uf::renderer::enums::Buffer::INDEX) + PARSE_INPUT(instance, uf::renderer::enums::Buffer::VERTEX) + PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT) + + // allocate buffers + for ( auto& q : queue ) { + initializeBuffer( q.data, q.size, q.usage ); } } - descriptor.attributes = attributes; - descriptor.indices = attributes.index.length; - - initializeBuffer( - (const void*) attributes.vertex.pointer, - attributes.vertex.size * attributes.vertex.length, - uf::renderer::enums::Buffer::VERTEX - ); - initializeBuffer( - (const void*) attributes.index.pointer, - attributes.index.size * attributes.index.length, - uf::renderer::enums::Buffer::INDEX - ); + if ( mesh.instance.count == 0 && mesh.instance.attributes.empty() ) { + descriptor.inputs.instance.count = 1; + } } bool ext::vulkan::Graphic::hasPipeline( const GraphicDescriptor& descriptor ) const { return pipelines.count( descriptor.hash() ) > 0; @@ -877,118 +847,150 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD return; } if ( !pipeline.metadata.process ) return; - - const Buffer* vertexBuffer = NULL; - const Buffer* indexBuffer = NULL; - for ( auto& buffer : buffers ) { - if ( buffer.usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ) vertexBuffer = &buffer; - if ( buffer.usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT ) indexBuffer = &buffer; - } - assert( vertexBuffer && indexBuffer ); - pipeline.record(*this, commandBuffer, pass, draw); - // Bind triangle vertex buffer (contains position and colors) - VkDeviceSize offsets[1] = { descriptor.offsets.vertex }; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer->buffer, offsets); - // Bind triangle index buffer - VkIndexType indicesType = VK_INDEX_TYPE_UINT32; - switch ( descriptor.attributes.index.size ) { - case 1: indicesType = VK_INDEX_TYPE_UINT8_EXT; break; - case 2: indicesType = VK_INDEX_TYPE_UINT16; break; - case 4: indicesType = VK_INDEX_TYPE_UINT32; break; - default: - UF_EXCEPTION("Vulkan error: invalid indices size of " << (int) descriptor.attributes.index.size); - break; + +/* + struct VertexInstance { + VkBuffer buffer; + VkDeviceSize offset; + }; + struct { + struct { + size_t min; + size_t max; + } binding; + uf::stl::vector buffer; + uf::stl::vector offset; + } vertexInstance; + + uf::stl::unordered_map vertexInstanceRemap; + for ( auto& attribute : descriptor.inputs.vertex.attributes ) { + vertexInstanceRemap[attribute.binding] = { + .buffer = buffers.at(attribute.buffer).buffer, + .offset = attribute.offset, + }; + vertexInstance.binding.min = MIN(vertexInstance.binding.min, attribute.binding); + vertexInstance.binding.max = MAX(vertexInstance.binding.max, attribute.binding); + } + for ( auto& attribute : descriptor.inputs.instance.attributes ) { + vertexInstanceRemap[attribute.binding] = { + .buffer = buffers.at(attribute.buffer).buffer, + .offset = attribute.offset, + }; + vertexInstance.binding.min = MIN(vertexInstance.binding.min, attribute.binding); + vertexInstance.binding.max = MAX(vertexInstance.binding.max, attribute.binding); + } + vertexInstance.buffer.resize( vertexInstanceRemap.size() ); + vertexInstance.offset.resize( vertexInstanceRemap.size() ); + for ( auto i = vertexInstance.binding.min; i <= vertexInstance.binding.max; ++i ) { + vertexInstance.buffer.emplace_back(vertexInstanceRemap[i].buffer); + vertexInstance.offset.emplace_back(vertexInstanceRemap[i].offset); + } +*/ + + struct { + uf::stl::vector buffer; + uf::stl::vector offset; + } vertexInstance; + + for ( auto& attribute : descriptor.inputs.vertex.attributes ) { + vertexInstance.buffer.emplace_back( buffers.at((0 <= descriptor.inputs.vertex.interleaved ? descriptor.inputs.vertex.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer ); + vertexInstance.offset.emplace_back( 0 <= descriptor.inputs.vertex.interleaved ? descriptor.inputs.vertex.offset : attribute.offset ); + } + for ( auto& attribute : descriptor.inputs.instance.attributes ) { + vertexInstance.buffer.emplace_back( buffers.at((0 <= descriptor.inputs.instance.interleaved ? descriptor.inputs.instance.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer ); + vertexInstance.offset.emplace_back( 0 <= descriptor.inputs.instance.interleaved ? descriptor.inputs.instance.offset : attribute.offset ); + } + + struct { + VkBuffer buffer = NULL; + VkDeviceSize offset = 0; + size_t binding = 0; + size_t index = 0; + } index, indirect; + + if ( descriptor.inputs.index.count && !descriptor.inputs.index.attributes.empty() ) { + auto& attribute = descriptor.inputs.index.attributes.front(); + index.buffer = buffers.at((0 <= descriptor.inputs.index.interleaved ? descriptor.inputs.index.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer; + index.offset = 0 <= descriptor.inputs.index.interleaved ? descriptor.inputs.index.offset : attribute.offset; + } + if ( descriptor.inputs.indirect.count && !descriptor.inputs.indirect.attributes.empty() ) { + auto& attribute = descriptor.inputs.indirect.attributes.front(); + indirect.buffer = buffers.at((0 <= descriptor.inputs.indirect.interleaved ? descriptor.inputs.indirect.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer; + indirect.offset = 0 <= descriptor.inputs.indirect.interleaved ? descriptor.inputs.indirect.offset : attribute.offset; + } + + for ( auto& buffer : buffers ) { + if ( !index.buffer && buffer.usage & uf::renderer::enums::Buffer::INDEX ) index.buffer = buffer.buffer; + if ( !indirect.buffer && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect.buffer = buffer.buffer; + } + + if ( !vertexInstance.buffer.empty() ) { + vkCmdBindVertexBuffers( commandBuffer, 0, vertexInstance.buffer.size(), vertexInstance.buffer.data(), vertexInstance.offset.data() ); + } + + if ( index.buffer ) { + VkIndexType indicesType = VK_INDEX_TYPE_UINT32; + switch ( descriptor.inputs.index.stride ) { + case 1: indicesType = VK_INDEX_TYPE_UINT8_EXT; break; + case 2: indicesType = VK_INDEX_TYPE_UINT16; break; + case 4: indicesType = VK_INDEX_TYPE_UINT32; break; + default: + UF_EXCEPTION("invalid indices size of " << (int) descriptor.inputs.index.stride); + break; + } + vkCmdBindIndexBuffer(commandBuffer, index.buffer, index.offset, indicesType); + } + if ( index.buffer && indirect.buffer ) { + vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, + descriptor.inputs.indirect.offset, // offset + descriptor.inputs.indirect.count, // drawCount + descriptor.inputs.indirect.stride // stride + ); + } else if ( index.buffer && !indirect.buffer ) { + vkCmdDrawIndexed(commandBuffer, + descriptor.inputs.index.count, // indexCount + descriptor.inputs.instance.count, // instanceCount + descriptor.inputs.index.first, // firstIndex + descriptor.inputs.vertex.first, // vertexOffset + descriptor.inputs.instance.first // firstInstance + ); + } else if ( !vertexInstance.buffer.empty() && indirect.buffer ) { + vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, + descriptor.inputs.indirect.offset, // offset + descriptor.inputs.indirect.count, // drawCount + descriptor.inputs.indirect.stride // stride + ); + } else/* if ( !vertexInstance.buffer.empty() && !indirect.buffer ) */{ + vkCmdDraw(commandBuffer, + descriptor.inputs.vertex.count, // vertexCount + descriptor.inputs.instance.count, // instanceCount + descriptor.inputs.vertex.first, // firstVertex + descriptor.inputs.instance.first // firstInstance + ); } - vkCmdBindIndexBuffer(commandBuffer, indexBuffer->buffer, descriptor.offsets.index, indicesType); - vkCmdDrawIndexed(commandBuffer, descriptor.indices, 1, 0, 0, 1); } void ext::vulkan::Graphic::destroy() { for ( auto& pair : pipelines ) pair.second.destroy(); pipelines.clear(); - material.destroy(); - ext::vulkan::Buffers::destroy(); - ext::vulkan::states::rebuild = true; } -bool ext::vulkan::Graphic::hasStorage( const uf::stl::string& name ) const { - for ( auto& shader : material.shaders ) if ( shader.hasStorage(name) ) return true; - return false; -} -ext::vulkan::Buffer& ext::vulkan::Graphic::getStorageBuffer( const uf::stl::string& name ) { - size_t storageIndex = -1; - for ( auto& shader : material.shaders ) { - if ( !shader.hasStorage(name) ) continue; - storageIndex = shader.metadata.definitions.storage[name].index; - break; - } - for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) ) continue; - if ( storageCounter++ != storageIndex ) continue; - return buffers[bufferIndex]; - } - UF_EXCEPTION("buffer not found: " << name); -} -const ext::vulkan::Buffer& ext::vulkan::Graphic::getStorageBuffer( const uf::stl::string& name ) const { - size_t storageIndex = -1; - for ( auto& shader : material.shaders ) { - if ( !shader.hasStorage(name) ) continue; - storageIndex = shader.metadata.definitions.storage.at(name).index; - break; - } - for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) ) continue; - if ( storageCounter++ != storageIndex ) continue; - return buffers[bufferIndex]; - } - UF_EXCEPTION("buffer not found: " << name); -} -// JSON shit -uf::Serializer ext::vulkan::Graphic::getStorageJson( const uf::stl::string& name, bool cache ) { - for ( auto& shader : material.shaders ) { - if ( !shader.hasStorage(name) ) continue; - return shader.getStorageJson(name, cache); - } - return ext::json::null(); -} -ext::vulkan::userdata_t ext::vulkan::Graphic::getStorageUserdata( const uf::stl::string& name, const ext::json::Value& payload ) { - for ( auto& shader : material.shaders ) { - if ( !shader.hasStorage(name) ) continue; - return shader.getStorageUserdata(name, payload); - } - return ext::vulkan::userdata_t(); -} - #include void ext::vulkan::GraphicDescriptor::parse( ext::json::Value& metadata ) { if ( metadata["front face"].is() ) { - if ( metadata["front face"].as() == "ccw" ) { - frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - } else if ( metadata["front face"].as() == "cw" ) { - frontFace = VK_FRONT_FACE_CLOCKWISE; - } + if ( metadata["front face"].as() == "ccw" ) frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + else if ( metadata["front face"].as() == "cw" ) frontFace = VK_FRONT_FACE_CLOCKWISE; } if ( metadata["cull mode"].is() ) { - if ( metadata["cull mode"].as() == "back" ) { - cullMode = VK_CULL_MODE_BACK_BIT; - } else if ( metadata["cull mode"].as() == "front" ) { - cullMode = VK_CULL_MODE_FRONT_BIT; - } else if ( metadata["cull mode"].as() == "none" ) { - cullMode = VK_CULL_MODE_NONE; - } else if ( metadata["cull mode"].as() == "both" ) { - cullMode = VK_CULL_MODE_FRONT_AND_BACK; - } - } - if ( metadata["indices"].is() ) { - indices = metadata["indices"].as(); - } - if ( ext::json::isObject( metadata["offsets"] ) ) { - offsets.vertex = metadata["offsets"]["vertex"].as(); - offsets.index = metadata["offsets"]["index"].as(); + if ( metadata["cull mode"].as() == "back" ) cullMode = VK_CULL_MODE_BACK_BIT; + else if ( metadata["cull mode"].as() == "front" ) cullMode = VK_CULL_MODE_FRONT_BIT; + else if ( metadata["cull mode"].as() == "none" ) cullMode = VK_CULL_MODE_NONE; + else if ( metadata["cull mode"].as() == "both" ) cullMode = VK_CULL_MODE_FRONT_AND_BACK; } + if ( ext::json::isObject(metadata["depth bias"]) ) { depth.bias.enable = VK_TRUE; depth.bias.constant = metadata["depth bias"]["constant"].as(); @@ -997,41 +999,6 @@ void ext::vulkan::GraphicDescriptor::parse( ext::json::Value& metadata ) { } } ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() const { -#if UF_GRAPHIC_DESCRIPTOR_USE_STRING - uf::Serializer serializer; - - serializer["subpass"] = subpass; - if ( settings::experimental::individualPipelines ) - serializer["renderMode"] = renderMode; - - serializer["renderTarget"] = renderTarget; - serializer["geometry"]["sizes"]["vertex"] = attributes.vertex.size; - serializer["geometry"]["sizes"]["indices"] = attributes.index.size; - serializer["indices"] = indices; - serializer["offsets"]["vertex"] = offsets.vertex; - serializer["offsets"]["index"] = offsets.index; - - for ( uint8_t i = 0; i < attributes.descriptor.size(); ++i ) { - serializer["geometry"]["attributes"][i]["format"] = attributes.descriptor[i].format; - serializer["geometry"]["attributes"][i]["offset"] = attributes.descriptor[i].offset; - } - - serializer["topology"] = topology; - serializer["cullMode"] = cullMode; - serializer["fill"] = fill; - serializer["lineWidth"] = lineWidth; - serializer["frontFace"] = frontFace; - serializer["depth"]["test"] = depth.test; - serializer["depth"]["write"] = depth.write; - serializer["depth"]["operation"] = depth.operation; - serializer["depth"]["bias"]["enable"] = depth.bias.enable; - serializer["depth"]["bias"]["constant"] = depth.bias.constant; - serializer["depth"]["bias"]["slope"] = depth.bias.slope; - serializer["depth"]["bias"]["clamp"] = depth.bias.clamp; - - return uf::string::sha256( serializer.serialize() ); -// return serializer.dump(); -#else size_t hash{}; hash += std::hash{}(subpass); @@ -1039,15 +1006,23 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co hash += std::hash{}(renderMode); hash += std::hash{}(renderTarget); - hash += std::hash{}(attributes.vertex.size); - hash += std::hash{}(attributes.index.size); - hash += std::hash{}(indices); - hash += std::hash{}(offsets.vertex); - hash += std::hash{}(offsets.index); - for ( uint8_t i = 0; i < attributes.descriptor.size(); ++i ) { - hash += std::hash{}(attributes.descriptor[i].format); - hash += std::hash{}(attributes.descriptor[i].offset); +/* + hash += std::hash{}(vertex.attributes.size); + hash += std::hash{}(vertex.attributes.length); + hash += std::hash{}(index.attributes.size); + hash += std::hash{}(index.attributes.length); + hash += std::hash{}(instance.attributes.size); + hash += std::hash{}(instance.attributes.length); +*/ + + for ( uint8_t i = 0; i < inputs.vertex.attributes.size(); ++i ) { + hash += std::hash{}(inputs.vertex.attributes[i].descriptor.format); + hash += std::hash{}(inputs.vertex.attributes[i].descriptor.offset); + } + for ( uint8_t i = 0; i < inputs.index.attributes.size(); ++i ) { + hash += std::hash{}(inputs.index.attributes[i].descriptor.format); + hash += std::hash{}(inputs.index.attributes[i].descriptor.offset); } hash += std::hash{}(topology); @@ -1064,7 +1039,6 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co hash += std::hash{}(depth.bias.clamp); return hash; -#endif } #endif \ No newline at end of file diff --git a/engine/src/ext/vulkan/rendermodes/compute.cpp b/engine/src/ext/vulkan/rendermodes/compute.cpp index 32551a8a..099b64f3 100644 --- a/engine/src/ext/vulkan/rendermodes/compute.cpp +++ b/engine/src/ext/vulkan/rendermodes/compute.cpp @@ -81,6 +81,18 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { } } { + uf::Mesh mesh; + mesh.bind(); + mesh.insertVertices({ + { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, + { {-1.0f, -1.0f}, {0.0f, 0.0f}, }, + { {1.0f, -1.0f}, {1.0f, 0.0f}, }, + { {1.0f, 1.0f}, {1.0f, 1.0f}, } + }); + mesh.insertIndices({ + 0, 1, 2, 2, 3, 0 + }); + /* uf::Mesh mesh; mesh.vertices = { { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, @@ -91,6 +103,7 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { mesh.indices = { 0, 1, 2, 2, 3, 0 }; + */ blitter.device = &device; blitter.material.device = &device; blitter.descriptor.subpass = 1; diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index ae15a219..bb5137a7 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -192,6 +192,18 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { renderTarget.initialize( device ); { + uf::Mesh mesh; + mesh.bind(); + mesh.insertVertices({ + { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, + { {-1.0f, -1.0f}, {0.0f, 0.0f}, }, + { {1.0f, -1.0f}, {1.0f, 0.0f}, }, + { {1.0f, 1.0f}, {1.0f, 1.0f}, } + }); + mesh.insertIndices({ + 0, 1, 2, 2, 3, 0 + }); + /* uf::Mesh mesh; mesh.vertices = { { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, @@ -202,6 +214,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { mesh.indices = { 0, 1, 2, 0, 2, 3 }; + */ blitter.descriptor.subpass = 1; blitter.descriptor.depth.test = false; blitter.descriptor.depth.write = false; @@ -305,33 +318,33 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { }); } - uf::stl::vector lights(maxLights); - uf::stl::vector materials(maxTextures2D); - uf::stl::vector textures(maxTextures2D); - uf::stl::vector drawCalls(maxTextures2D); + uf::stl::vector lights(maxLights); + uf::stl::vector materials(maxTextures2D); + uf::stl::vector textures(maxTextures2D); + uf::stl::vector drawCommands(maxTextures2D); for ( auto& material : materials ) material.colorBase = {0,0,0,0}; - metadata.lightBufferIndex = blitter.initializeBuffer( + metadata.lightBufferIndex = shader.initializeBuffer( (const void*) lights.data(), - lights.size() * sizeof(pod::Light::Storage), + lights.size() * sizeof(pod::Light), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); - metadata.materialBufferIndex = blitter.initializeBuffer( + metadata.materialBufferIndex = shader.initializeBuffer( (const void*) materials.data(), - materials.size() * sizeof(pod::Material::Storage), + materials.size() * sizeof(pod::Material), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); - metadata.textureBufferIndex = blitter.initializeBuffer( + metadata.textureBufferIndex = shader.initializeBuffer( (const void*) textures.data(), - textures.size() * sizeof(pod::Texture::Storage), + textures.size() * sizeof(pod::Texture), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); - metadata.drawCallBufferIndex = blitter.initializeBuffer( - (const void*) drawCalls.data(), - drawCalls.size() * sizeof(pod::DrawCall::Storage), + metadata.drawCallBufferIndex = shader.initializeBuffer( + (const void*) drawCommands.data(), + drawCommands.size() * sizeof(pod::DrawCommand), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); } diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 0be8406e..398b0135 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -303,16 +303,17 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { renderTarget.initialize( device ); if ( blitter.process ) { - uf::Mesh mesh; - mesh.vertices = { + uf::Mesh mesh; + mesh.bind(); + mesh.insertVertices({ { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, { {-1.0f, -1.0f}, {0.0f, 0.0f}, }, { {1.0f, -1.0f}, {1.0f, 0.0f}, }, { {1.0f, 1.0f}, {1.0f, 1.0f}, } - }; - mesh.indices = { + }); + mesh.insertIndices({ 0, 1, 2, 2, 3, 0 - }; + }); blitter.device = &device; blitter.material.device = &device; @@ -434,33 +435,33 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { } }); - uf::stl::vector lights(maxLights); - uf::stl::vector materials(maxTextures2D); - uf::stl::vector textures(maxTextures2D); - uf::stl::vector drawCalls(maxTextures2D); + uf::stl::vector lights(maxLights); + uf::stl::vector materials(maxTextures2D); + uf::stl::vector textures(maxTextures2D); + uf::stl::vector drawCalls(maxTextures2D); for ( auto& material : materials ) material.colorBase = {0,0,0,0}; - metadata.lightBufferIndex = blitter.initializeBuffer( + metadata.lightBufferIndex = shader.initializeBuffer( (const void*) lights.data(), - lights.size() * sizeof(pod::Light::Storage), + lights.size() * sizeof(pod::Light), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); - metadata.materialBufferIndex = blitter.initializeBuffer( + metadata.materialBufferIndex = shader.initializeBuffer( (const void*) materials.data(), - materials.size() * sizeof(pod::Material::Storage), + materials.size() * sizeof(pod::Material), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); - metadata.textureBufferIndex = blitter.initializeBuffer( + metadata.textureBufferIndex = shader.initializeBuffer( (const void*) textures.data(), - textures.size() * sizeof(pod::Texture::Storage), + textures.size() * sizeof(pod::Texture), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); - metadata.drawCallBufferIndex = blitter.initializeBuffer( + metadata.drawCallBufferIndex = shader.initializeBuffer( (const void*) drawCalls.data(), - drawCalls.size() * sizeof(pod::DrawCall::Storage), + drawCalls.size() * sizeof(pod::DrawCommand), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); } else { diff --git a/engine/src/ext/vulkan/shader.cpp b/engine/src/ext/vulkan/shader.cpp index cfa2a4c7..6b58cc9c 100644 --- a/engine/src/ext/vulkan/shader.cpp +++ b/engine/src/ext/vulkan/shader.cpp @@ -399,7 +399,9 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl }; uf::Serializer payload = ext::json::array(); const auto& type = comp.get_type(type_id); - for ( auto& member_type_id : type.member_types ) { + if ( type.member_types.empty() ) { + payload = parseMember( type_id ); + } else for ( auto& member_type_id : type.member_types ) { const auto& member_type = comp.get_type(member_type_id); uf::stl::string name = comp.get_member_name(type.type_alias, payload.size()); if ( name == "" ) name = comp.get_member_name(type.parent_type, payload.size()); @@ -545,16 +547,74 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl { uniforms.reserve( metadata.definitions.uniforms.size() ); - uf::stl::vector sizes( metadata.definitions.uniforms.size() ); + uf::stl::vector remap( metadata.definitions.uniforms.size() ); for ( auto pair : metadata.definitions.uniforms ) { - sizes[pair.second.index] = pair.second.size; + remap[pair.second.index] = pair.second.name; } - for ( auto size : sizes ) { - auto& uniform = uniforms.emplace_back(); - uniform.create( size ); + for ( auto& name : remap ) { + auto& definition = metadata.definitions.uniforms[name]; + + auto& userdata = uniforms.emplace_back(); + userdata.create( definition.size, nullptr ); + + initializeBuffer( + (const void*) userdata.data().data, + userdata.data().len, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + ); } } + for ( auto i = 0; i < res.stage_inputs.size(); ++i ) { + const auto& resource = res.stage_inputs[i]; + const auto& type = comp.get_type(resource.type_id); + const auto& base_type = comp.get_type(resource.base_type_id); + const size_t binding = comp.get_decoration(resource.id, spv::DecorationBinding); + const uf::stl::string name = resource.name; + size_t size = 0; // comp.get_declared_struct_size(type); + // generate definition to JSON + { + metadata.json["definitions"]["inputs"][name]["name"] = name; + metadata.json["definitions"]["inputs"][name]["index"] = i; + metadata.json["definitions"]["inputs"][name]["binding"] = binding; + metadata.json["definitions"]["inputs"][name]["size"] = size; + metadata.json["definitions"]["inputs"][name]["members"] = parseMembers(resource.type_id); + } + // generate definition to unordered_map + { + metadata.definitions.inputs[name] = Shader::Metadata::Definition::InOut{ + name, + i, + binding, + size, + }; + } + } + for ( auto i = 0; i < res.stage_outputs.size(); ++i ) { + const auto& resource = res.stage_outputs[i]; + const auto& type = comp.get_type(resource.type_id); + const auto& base_type = comp.get_type(resource.base_type_id); + const size_t binding = comp.get_decoration(resource.id, spv::DecorationBinding); + const uf::stl::string name = resource.name; + size_t size = 0; // comp.get_declared_struct_size(type); + // generate definition to JSON + { + metadata.json["definitions"]["outputs"][name]["name"] = name; + metadata.json["definitions"]["outputs"][name]["index"] = i; + metadata.json["definitions"]["outputs"][name]["binding"] = binding; + metadata.json["definitions"]["outputs"][name]["size"] = size; + metadata.json["definitions"]["outputs"][name]["members"] = parseMembers(resource.type_id); + } + // generate definition to unordered_map + { + metadata.definitions.outputs[name] = Shader::Metadata::Definition::InOut{ + name, + i, + binding, + size + }; + } + } for ( const auto& resource : res.push_constant_buffers ) { const auto& type = comp.get_type(resource.type_id); const auto& base_type = comp.get_type(resource.base_type_id); @@ -701,21 +761,9 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl } // organize layouts - { - std::sort( descriptorSetLayoutBindings.begin(), descriptorSetLayoutBindings.end(), [&]( const VkDescriptorSetLayoutBinding& l, const VkDescriptorSetLayoutBinding& r ){ - return l.binding < r.binding; - } ); - } - - // update uniform buffers - for ( auto& uniform : uniforms ) { - auto& userdata = uniform.data(); - initializeBuffer( - (const void*) userdata.data, - userdata.len, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT - ); - } + std::sort( descriptorSetLayoutBindings.begin(), descriptorSetLayoutBindings.end(), [&]( const VkDescriptorSetLayoutBinding& l, const VkDescriptorSetLayoutBinding& r ){ + return l.binding < r.binding; + } ); } void ext::vulkan::Shader::destroy() { @@ -739,7 +787,7 @@ bool ext::vulkan::Shader::validate() { bool valid = true; auto it = uniforms.begin(); for ( auto& buffer : buffers ) { - if ( !(buffer.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; + if ( !(buffer.usage & uf::renderer::enums::Buffer::UNIFORM) ) continue; if ( it == uniforms.end() ) break; auto& uniform = *(it++); if ( uniform.data().len != buffer.allocationInfo.size ) { @@ -758,7 +806,7 @@ ext::vulkan::Buffer& ext::vulkan::Shader::getUniformBuffer( const uf::stl::strin UF_ASSERT( hasUniform(name) ); size_t uniformIndex = metadata.definitions.uniforms[name].index; for ( size_t bufferIndex = 0, uniformCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; + if ( !(buffers[bufferIndex].usage & uf::renderer::enums::Buffer::UNIFORM) ) continue; if ( uniformCounter++ != uniformIndex ) continue; return buffers[bufferIndex]; } @@ -768,7 +816,7 @@ const ext::vulkan::Buffer& ext::vulkan::Shader::getUniformBuffer( const uf::stl: UF_ASSERT( hasUniform(name) ); size_t uniformIndex = metadata.definitions.uniforms.at(name).index; for ( size_t bufferIndex = 0, uniformCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers.at(bufferIndex).usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; + if ( !(buffers.at(bufferIndex).usage & uf::renderer::enums::Buffer::UNIFORM) ) continue; if ( uniformCounter++ != uniformIndex ) continue; return buffers.at(bufferIndex); } @@ -787,7 +835,7 @@ bool ext::vulkan::Shader::updateUniform( const uf::stl::string& name, const void updateBuffer( data, size, getUniformBuffer(name) ); return true; } - +// bool ext::vulkan::Shader::hasStorage( const uf::stl::string& name ) const { return metadata.definitions.storage.count(name) > 0; } @@ -795,7 +843,7 @@ ext::vulkan::Buffer& ext::vulkan::Shader::getStorageBuffer( const uf::stl::strin UF_ASSERT( hasStorage(name) ); size_t storageIndex = metadata.definitions.storage[name].index; for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) ) continue; + if ( !(buffers[bufferIndex].usage & uf::renderer::enums::Buffer::STORAGE) ) continue; if ( storageCounter++ != storageIndex ) continue; return buffers[bufferIndex]; } @@ -805,13 +853,19 @@ const ext::vulkan::Buffer& ext::vulkan::Shader::getStorageBuffer( const uf::stl: UF_ASSERT( hasStorage(name) ); size_t storageIndex = metadata.definitions.storage.at(name).index; for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers.at(bufferIndex).usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) ) continue; + if ( !(buffers.at(bufferIndex).usage & uf::renderer::enums::Buffer::STORAGE) ) continue; if ( storageCounter++ != storageIndex ) continue; return buffers.at(bufferIndex); } UF_EXCEPTION("buffer not found: " << name); } +bool ext::vulkan::Shader::updateStorage( const uf::stl::string& name, const void* data, size_t size ) const { + if ( !hasStorage(name) ) return false; + updateBuffer( data, size, getStorageBuffer(name) ); + return true; +} // JSON shit +/* uf::Serializer ext::vulkan::Shader::getUniformJson( const uf::stl::string& name, bool cache ) { if ( !hasUniform(name) ) return ext::json::null(); if ( cache && !ext::json::isNull(metadata.json["uniforms"][name]) ) return metadata.json["uniforms"][name]; @@ -839,5 +893,5 @@ ext::vulkan::userdata_t ext::vulkan::Shader::getStorageUserdata( const uf::stl:: if ( !hasStorage(name) ) return false; return jsonToUserdata(payload, metadata.json["definitions"]["storage"][name]); } - +*/ #endif \ No newline at end of file diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index c28d2c65..e2aea2f6 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -5,7 +5,9 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { #if UF_USE_XATLAS ::xatlas::Atlas* atlas = ::xatlas::Create(); - for ( auto& mesh : graph.meshes ) { +#if 0 + for ( auto& name : graph.meshes ) { + auto& mesh = uf::graph::storage.meshes[name]; mesh.updateDescriptor(); size_t indices = mesh.attributes.index.length; @@ -16,13 +18,13 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { size_t vertexStride = mesh.attributes.vertex.size; uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeUv, vertexAttributeSt, vertexAttributeId; - for ( auto& attribute : mesh.attributes.descriptor ) { + for ( auto& attribute : mesh.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; @@ -68,10 +70,9 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { ::xatlas::Generate(atlas, chartOptions, packOptions); -#if UF_GRAPH_EXPERIMENTAL for ( size_t i = 0; i < atlas->meshCount; i++ ) { auto& xmesh = atlas->meshes[i]; - auto& mesh = graph.meshes[i]; + auto& mesh = uf::graph::storage.meshes[graph.meshes[i]]; size_t indices = mesh.attributes.index.length; size_t indexStride = mesh.attributes.index.size; @@ -87,18 +88,16 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { uint8_t* oldVertexPointer = oldVertexBuffer.data(); uint8_t* newvertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; - uf::renderer::VertexDescriptor vertexAttributePosition, + uf::renderer::AttributeDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeUv, - vertexAttributeSt, - vertexAttributeId; + vertexAttributeSt; - for ( auto& attribute : mesh.attributes.descriptor ) { + for ( auto& attribute : mesh.attributes.vertex.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; else if ( attribute.name == "st" ) vertexAttributeSt = attribute; - else if ( attribute.name == "id" ) vertexAttributeId = attribute; } UF_ASSERT( vertexAttributePosition.name != "" ); @@ -126,58 +125,8 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { pod::Vector2ui size = pod::Vector2ui{ atlas->width, atlas->height }; ::xatlas::Destroy(atlas); -#else -#if 0 - for (size_t i = 0; i < atlas->meshCount; i++) { - auto& mesh = graph.meshes[i]; - auto& xmesh = atlas->meshes[i]; - for ( size_t v = 0; v < xmesh.vertexCount; v++) { - auto& xvertex = xmesh.vertexArray[v]; - auto& vertex = mesh.vertices[xvertex.xref]; - vertex.st = { xvertex.uv[0] / atlas->width, xvertex.uv[1] / atlas->height }; - } - } -#else - auto oldMeshes = std::move( graph.meshes ); - graph.meshes.resize( oldMeshes.size() ); - for (size_t i = 0; i < atlas->meshCount; i++) { - auto& xmesh = atlas->meshes[i]; - auto& oldMesh = oldMeshes[i]; - auto& newMesh = graph.meshes[i]; - newMesh.vertices.reserve( xmesh.vertexCount ); - newMesh.indices.reserve( xmesh.indexCount ); - for ( size_t v = 0; v < xmesh.vertexCount; v++) { - auto& xvertex = xmesh.vertexArray[v]; - auto& oldVertex = oldMesh.vertices[xvertex.xref]; - auto& newVertex = newMesh.vertices.emplace_back(oldVertex); - newVertex.st = { xvertex.uv[0] / atlas->width, xvertex.uv[1] / atlas->height }; - } - for ( size_t i = 0; i < xmesh.indexCount; ++i ) newMesh.indices.emplace_back( xmesh.indexArray[i] ); - newMesh.updateDescriptor(); - } -#endif - - pod::Vector2ui size = pod::Vector2ui{ atlas->width, atlas->height }; - ::xatlas::Destroy(atlas); - - for ( auto& node : graph.nodes ) { - if ( !(0 <= node.mesh && node.mesh < graph.meshes.size()) ) continue; - auto& nodeMesh = graph.meshes[node.mesh]; - for ( auto& vertex : nodeMesh.vertices ) { - vertex.id.x = node.index; - // in almost-software mode, material ID is actually its albedo ID, as we can't use any other forms of mapping - #if UF_USE_OPENGL_FIXED_FUNCTION - if ( !(graph.mode & uf::graph::LoadMode::ATLAS) ) { - auto& material = graph.materials[vertex.id.y]; - auto& texture = graph.textures[material.storage.indexAlbedo]; - vertex.id.y = texture.storage.index; - } - #endif - } - } -#endif + return size; -#else - return pod::Vector2ui{}; +#endif #endif } \ No newline at end of file diff --git a/engine/src/utils/mesh/grid.cpp b/engine/src/utils/mesh/grid.cpp index f40b0ca6..6f746e62 100644 --- a/engine/src/utils/mesh/grid.cpp +++ b/engine/src/utils/mesh/grid.cpp @@ -2,7 +2,7 @@ #include #include #include - +#if 0 uf::MeshGrid::~MeshGrid() { this->destroy(); } @@ -271,4 +271,5 @@ pod::Vector3i uf::MeshGrid::unwrapIndex( size_t i ) { break; } } +#endif #endif \ No newline at end of file diff --git a/engine/src/utils/mesh/mesh.cpp b/engine/src/utils/mesh/mesh.cpp index 679dea47..ce5bc01b 100644 --- a/engine/src/utils/mesh/mesh.cpp +++ b/engine/src/utils/mesh/mesh.cpp @@ -1,4 +1,5 @@ #include +#include // Used for per-vertex colors UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F4F, @@ -46,48 +47,394 @@ UF_VERTEX_DESCRIPTOR(pod::Vertex_3F, UF_VERTEX_DESCRIPTION(pod::Vertex_3F, R32G32B32_SFLOAT, position) ) -pod::Mesh::~Mesh() {} -void pod::Mesh::generateIndices() { - this->resizeIndices(this->attributes.vertex.length); - switch ( this->attributes.index.size ) { - case sizeof(uint32_t): - for ( size_t i = 0; i < this->attributes.vertex.length; ++i ) ((uint32_t*) this->attributes.index.pointer)[i] = i; - break; - case sizeof(uint16_t): - for ( size_t i = 0; i < this->attributes.vertex.length; ++i ) ((uint16_t*) this->attributes.index.pointer)[i] = i; - break; - case sizeof(uint8_t): - for ( size_t i = 0; i < this->attributes.vertex.length; ++i ) ((uint8_t*) this->attributes.index.pointer)[i] = i; - break; +bool uf::Mesh::defaultInterleaved = false; + +void uf::Mesh::initialize() { +} +void uf::Mesh::destroy() { + _destroy(vertex); + _destroy(index); + _destroy(instance); + _destroy(indirect); + + buffers.clear(); +} +uf::Mesh uf::Mesh::interleave() const { + uf::Mesh interleaved; + auto& buffer = interleaved.buffers.emplace_back(); + +#define PARSE_INPUT_INTERLEAVED(name) {\ + interleaved.name = name;\ + interleaved.name.offset = buffer.size();\ + if ( isInterleaved( name.interleaved ) ) buffer.insert( buffer.end(), buffers[name.interleaved].begin(), buffers[name.interleaved].end() );\ + else for ( auto& attribute : name.attributes ) buffer.insert( buffer.end(), buffers[attribute.buffer].begin(), buffers[attribute.buffer].end() );\ +} + PARSE_INPUT_INTERLEAVED(vertex); + PARSE_INPUT_INTERLEAVED(index); + PARSE_INPUT_INTERLEAVED(instance); + PARSE_INPUT_INTERLEAVED(indirect); + + return interleaved; +} +void uf::Mesh::updateDescriptor() { + _updateDescriptor(vertex); + _updateDescriptor(index); + _updateDescriptor(instance); + _updateDescriptor(indirect); +} +void uf::Mesh::insert( const uf::Mesh& mesh ) { + insertVertex(mesh); + insertIndex(mesh); + insertInstance(mesh); + insertIndirect(mesh); +} +/* +uint32_t indices = 0; // triangle count +uint32_t instances = 0; // instance count +uint32_t indexID = 0; // starting triangle position + int32_t vertexID = 0; // starting vertex position + +uint32_t instanceID = 0; // starting instance position +uint32_t materialID = 0; +uint32_t objectID = 0; +uint32_t vertices = 0; +*/ +void uf::Mesh::generateIndices() { + // deduce type + size_t size = sizeof(uint32_t); + uf::renderer::enums::Type::type_t type; + /*if ( vertex.count <= std::numeric_limits::max() ) { size = sizeof(uint8_t); type = uf::renderer::typeToEnum(); } + else*/ if ( vertex.count <= std::numeric_limits::max() ) { size = sizeof(uint16_t); type = uf::renderer::typeToEnum(); } + else if ( vertex.count <= std::numeric_limits::max() ) { size = sizeof(uint32_t); type = uf::renderer::typeToEnum(); } + + if ( !index.attributes.empty() ) { + _destroy( index ); + } + _bindI( index, size, type ); + _bind( isInterleaved( vertex.interleaved ) ); + + switch ( size ) { + case 1: { uf::stl::vector indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break; + case 2: { uf::stl::vector indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break; + case 4: { uf::stl::vector indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break; } } -void pod::Mesh::updateDescriptor() {} -void pod::Mesh::resizeVertices( size_t n ) {} -void pod::Mesh::resizeIndices( size_t n ) {} +void uf::Mesh::generateIndirect() { + if ( index.count == 0 ) generateIndices(); -pod::Mesh& pod::VaryingMesh::get() { - return uf::pointeredUserdata::get( userdata, false ); -} -const pod::Mesh& pod::VaryingMesh::get() const { - return uf::pointeredUserdata::get( userdata, false ); -} + uf::stl::vector commands; + for ( auto& attribute : index.attributes ) { + auto& buffer = buffers[isInterleaved(index.interleaved) ? index.interleaved : attribute.buffer]; + auto& command = commands.emplace_back(); + command.indices = buffer.size() / attribute.descriptor.size; + command.instances = instance.count == 0 && instance.attributes.empty() ? 1 : instance.count; + command.indexID = 0; + command.vertexID = 0; + command.instanceID = 0; + command.objectID = 0; + command.vertices = vertex.count; + } -void pod::VaryingMesh::destroy() { - uf::pointeredUserdata::destroy( userdata ); + _destroy( indirect ); + bindIndirect(); + _bind(); + insertIndirects( commands ); } -void pod::VaryingMesh::updateDescriptor() { - auto& mesh = get(); - mesh.updateDescriptor(); - attributes = mesh.attributes; +bool uf::Mesh::isInterleaved( size_t i ) const { return 0 <= i && i < buffers.size(); } +void uf::Mesh::print() const { + std::stringstream str; + str << "Buffers: " << buffers.size() << "\n"; + str << "Vertices: " << vertex.count << " | " << (isInterleaved(vertex.interleaved) ? "interleaved" : "deinterleaved") << "\n"; + for ( auto i = 0; i < vertex.count; ++i ) { + if ( isInterleaved(vertex.interleaved) ) { + auto& buffer = buffers[vertex.interleaved]; + uint8_t* e = (uint8_t*) &buffer[i * vertex.stride]; + for ( auto& attribute : vertex.attributes ) { + str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; + switch ( attribute.descriptor.type ) { + case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint32_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int32_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint16_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int16_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint8_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int8_t*) (e + attribute.descriptor.offset))[j] << " "; break; + } + str << ")\n"; + } + } else for ( auto& attribute : vertex.attributes ) { + auto& buffer = buffers[attribute.buffer]; + str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; + switch ( attribute.descriptor.type ) { + case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + } + str << ")\n"; + } + } + str << "Indices: " << index.count << " | " << (isInterleaved(index.interleaved) ? "interleaved" : "deinterleaved") << "\n"; + for ( auto i = 0; i < index.count; ++i ) { + if ( isInterleaved(index.interleaved) ) { + auto& buffer = buffers[index.interleaved]; + switch ( index.stride ) { + case 1: str << "[" << i << "]: " << *(( uint8_t*) &buffer[i * index.stride]) << "\n"; break; + case 2: str << "[" << i << "]: " << *((uint16_t*) &buffer[i * index.stride]) << "\n"; break; + case 4: str << "[" << i << "]: " << *((uint32_t*) &buffer[i * index.stride]) << "\n"; break; + } + } else for ( auto& attribute : index.attributes ) { + auto& buffer = buffers[attribute.buffer]; + switch ( attribute.descriptor.size ) { + case 1: str << "[" << i << "]: " << *(( uint8_t*) &buffer[i * attribute.descriptor.size]) << "\n"; break; + case 2: str << "[" << i << "]: " << *((uint16_t*) &buffer[i * attribute.descriptor.size]) << "\n"; break; + case 4: str << "[" << i << "]: " << *((uint32_t*) &buffer[i * attribute.descriptor.size]) << "\n"; break; + } + } + } + str << "Instances: " << instance.count << " | " << (isInterleaved(instance.interleaved) ? "interleaved" : "deinterleaved") << "\n"; + for ( auto i = 0; i < instance.count; ++i ) { + if ( isInterleaved(instance.interleaved) ) { + auto& buffer = buffers[instance.interleaved]; + uint8_t* e = (uint8_t*) &buffer[i * instance.stride]; + for ( auto& attribute : instance.attributes ) { + str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; + switch ( attribute.descriptor.type ) { + case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint32_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int32_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint16_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int16_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint8_t*) (e + attribute.descriptor.offset))[j] << " "; break; + case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int8_t*) (e + attribute.descriptor.offset))[j] << " "; break; + } + str << ")\n"; + } + } else for ( auto& attribute : instance.attributes ) { + auto& buffer = buffers[attribute.buffer]; + str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; + switch ( attribute.descriptor.type ) { + case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + } + str << ")\n"; + } + } + str << "Indirect: " << indirect.count << " | " << (isInterleaved(indirect.interleaved) ? "interleaved" : "deinterleaved"); + std::cout << str.str() << std::endl; } +// +void uf::Mesh::_destroy( uf::Mesh::Input& input ) { + for ( auto& attribute : input.attributes ) { + attribute.descriptor.length = 0; + attribute.descriptor.pointer = NULL; + attribute.buffer = 0; + } + input.attributes.clear(); +} +void uf::Mesh::_bind( bool interleave ) { + size_t buffer = 0; +#define PARSE_INPUT(INPUT, INTERLEAVED){\ + if ( INTERLEAVED ) INPUT.interleaved = buffer;\ + for ( auto i = 0; i < INPUT.attributes.size(); ++i ) INPUT.attributes[i].buffer = !INTERLEAVED ? buffer++ : buffer;\ + if ( !INPUT.attributes.empty() && INTERLEAVED ) ++buffer;\ +} + + PARSE_INPUT(vertex, interleave) + PARSE_INPUT(index, false) + PARSE_INPUT(instance, interleave) + PARSE_INPUT(indirect, false) -void pod::VaryingMesh::resizeVertices( size_t n ) { - auto& mesh = get(); - mesh.resizeVertices( n ); - attributes = mesh.attributes; + buffers.resize( buffer ); + updateDescriptor(); + +// for ( auto& attribute : vertex.attributes ) UF_MSG_DEBUG( attribute.descriptor.name << "[" << attribute.descriptor.offset << "]: " << attribute.descriptor.size ); +#undef PARSE_INPUT } -void pod::VaryingMesh::resizeIndices( size_t n ) { - auto& mesh = get(); - mesh.resizeIndices( n ); - attributes = mesh.attributes; +void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) { + input.stride = 0; + for ( auto& attribute : input.attributes ) { + auto& buffer = buffers[isInterleaved(input.interleaved) ? input.interleaved : attribute.buffer]; + attribute.descriptor.length = buffer.size(); + attribute.descriptor.pointer = (void*) (buffer.data()); + input.stride += attribute.descriptor.size; + } +} +void uf::Mesh::_insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) { + if ( !_hasV( input, srcInput ) ) return; + _reserveVs( input, input.count += srcInput.count ); + + // both meshes are interleaved, just copy directly + if ( isInterleaved(input.interleaved) && isInterleaved(srcInput.interleaved) ) { + auto& src = mesh.buffers[srcInput.interleaved]; + auto& dst = buffers[input.interleaved]; + dst.insert( dst.end(), src.begin(), src.end() ); + // both meshes are de-interleaved, just copy directly + } else if ( !isInterleaved(input.interleaved) && !isInterleaved(srcInput.interleaved) ) { + for ( auto i = 0; i < input.attributes.size(); ++i ) { + auto& srcAttribute = srcInput.attributes[i]; + auto& dstAttribute = input.attributes[i]; + auto& src = mesh.buffers[srcAttribute.buffer]; + auto& dst = buffers[dstAttribute.buffer]; + dst.insert( dst.end(), src.begin(), src.end() ); + } + // not easy to convert, will implement later + } else { + UF_EXCEPTION("to be implemented"); + } + _updateDescriptor( input ); +} +void uf::Mesh::_insertI( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) { +// if ( !_hasI( source ) ) return; + _reserveIs( input, input.count += srcInput.count ); + + // both meshes are interleaved, just copy directly + if ( isInterleaved(input.interleaved) && isInterleaved(srcInput.interleaved) ) { + auto& src = mesh.buffers[srcInput.interleaved]; + auto& dst = buffers[input.interleaved]; + dst.insert( dst.end(), src.begin(), src.end() ); + // both meshes are de-interleaved, just copy directly + } else if ( !isInterleaved(input.interleaved) && !isInterleaved(srcInput.interleaved) ) { + for ( auto i = 0; i < input.attributes.size(); ++i ) { + auto& srcAttribute = srcInput.attributes[i]; + auto& dstAttribute = input.attributes[i]; + auto& src = mesh.buffers[srcAttribute.buffer]; + auto& dst = buffers[dstAttribute.buffer]; + dst.insert( dst.end(), src.begin(), src.end() ); + } + // not easy to convert, will implement later + } else { + UF_EXCEPTION("to be implemented"); + } + _updateDescriptor( input ); +} +// Vertices +bool uf::Mesh::_hasV( const uf::Mesh::Input& input, const uf::stl::vector& descriptors ) const { + if ( input.attributes.size() != descriptors.size() ) return false; + for ( auto i = 0; i < input.attributes.size(); ++i ) if ( input.attributes[i].descriptor != descriptors[i] ) return false; + return true; +} +bool uf::Mesh::_hasV( const uf::Mesh::Input& input, const uf::Mesh::Input& srcInput ) const { + if ( input.attributes.size() != srcInput.attributes.size() || input.stride != srcInput.stride ) return false; + for ( auto i = 0; i < input.attributes.size(); ++i ) if ( input.attributes[i].descriptor != srcInput.attributes[i].descriptor ) return false; + return true; +} +void uf::Mesh::_bindV( uf::Mesh::Input& input, const uf::stl::vector& descriptors ) { + input.attributes.resize( descriptors.size() ); + for ( auto i = 0; i < descriptors.size(); ++i ) { + auto& attribute = input.attributes[i]; + attribute.descriptor = descriptors[i]; + input.stride += attribute.descriptor.size; + } +} +void uf::Mesh::_reserveVs( uf::Mesh::Input& input, size_t count ) { + if ( isInterleaved(input.interleaved) ) { + buffers[input.interleaved].reserve( count * input.stride ); + for ( auto& attribute : input.attributes ) { + attribute.descriptor.length = buffers[input.interleaved].size(); + attribute.descriptor.pointer = (void*) (buffers[input.interleaved].data()); + } + } else for ( auto& attribute : input.attributes ) { + buffers[attribute.buffer].reserve( count * attribute.descriptor.size ); + attribute.descriptor.length = buffers[attribute.buffer].size(); + attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data()); + } +} +void uf::Mesh::_resizeVs( uf::Mesh::Input& input, size_t count ) { + if ( isInterleaved(input.interleaved) ) { + buffers[input.interleaved].resize( count * input.stride ); + for ( auto& attribute : input.attributes ) { + attribute.descriptor.length = buffers[input.interleaved].size(); + attribute.descriptor.pointer = (void*) (buffers[input.interleaved].data()); + } + } else for ( auto& attribute : input.attributes ) { + buffers[attribute.buffer].resize( count * attribute.descriptor.size ); + attribute.descriptor.length = buffers[attribute.buffer].size(); + attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data()); + } +} +void uf::Mesh::_insertV( uf::Mesh::Input& input, const void* data ) { + _reserveVs( input, ++input.count ); + const uint8_t* pointer = (const uint8_t*) data; + if ( isInterleaved(input.interleaved) ) { + buffers[input.interleaved].insert( buffers[input.interleaved].end(), pointer, pointer + input.stride ); + } else for ( auto& attribute : input.attributes ) { + buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), pointer + attribute.descriptor.offset, pointer + attribute.descriptor.offset + attribute.descriptor.size ); + } +} +void uf::Mesh::_insertVs( uf::Mesh::Input& input, const void* data, size_t size ) { +#if 0 + const uint8_t* pointer = (const uint8_t*) data; + for ( auto i = 0; i < size; ++i ) insertV( pointer + i * input.stride ); +#else + _reserveVs( input, input.count += size ); + const uint8_t* pointer = (const uint8_t*) data; + if ( isInterleaved(input.interleaved) ) { + buffers[input.interleaved].insert( buffers[input.interleaved].end(), pointer, pointer + size * input.stride ); + } else for ( const uint8_t* p = pointer; p < pointer + size * input.stride; p += input.stride ) { + for ( auto& attribute : input.attributes ) + buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), p + attribute.descriptor.offset, p + attribute.descriptor.offset + attribute.descriptor.size ); + } +#endif +} +// Indices +void uf::Mesh::_bindI( uf::Mesh::Input& input, size_t size, ext::RENDERER::enums::Type::type_t type, size_t count ) { + input.attributes.resize( count ); + input.stride = size; + for ( auto i = 0; i < count; ++i ) { + auto& attribute = input.attributes[i]; + attribute.descriptor.offset = 0; + attribute.descriptor.size = size; + attribute.descriptor.components = 1; + attribute.descriptor.type = type; + } +} +void uf::Mesh::_reserveIs( uf::Mesh::Input& input, size_t count, size_t i ) { + auto& attribute = input.attributes[i]; + buffers[attribute.buffer].reserve( count * attribute.descriptor.size ); + attribute.descriptor.length = buffers[attribute.buffer].size(); + attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data()); +} +void uf::Mesh::_resizeIs( uf::Mesh::Input& input, size_t count, size_t i ) { + auto& attribute = input.attributes[i]; + buffers[attribute.buffer].resize( count * attribute.descriptor.size ); + attribute.descriptor.length = buffers[attribute.buffer].size(); + attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data()); +} +void uf::Mesh::_insertI( uf::Mesh::Input& input, const void* data, size_t i ) { + auto& attribute = input.attributes[i]; + _reserveIs( input, ++input.count ); + const uint8_t* pointer = (const uint8_t*) data; +#if 1 + buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), pointer, pointer + attribute.descriptor.size ); +#else + if ( isInterleaved(input.interleaved) ) { + buffers[input.interleaved].insert( buffers[input.interleaved].end(), pointer, pointer + attribute.descriptor.size ); + } else { + buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), pointer, pointer + attribute.descriptor.size ); + } +#endif +} +void uf::Mesh::_insertIs( uf::Mesh::Input& input, const void* data, size_t size, size_t i ) { + auto& attribute = input.attributes[i]; + _reserveIs( input, input.count += size ); + const uint8_t* pointer = (const uint8_t*) data; +#if 1 + for ( const uint8_t* p = pointer; p < pointer + size * attribute.descriptor.size; p += attribute.descriptor.size ) + buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), p + attribute.descriptor.offset, p + attribute.descriptor.offset + attribute.descriptor.size ); +#else + if ( isInterleaved(input.interleaved) ) { + buffers[input.interleaved].insert( buffers[input.interleaved].end(), pointer, pointer + size * attribute.descriptor.size ); + } else for ( const uint8_t* p = pointer; p < pointer + size * attribute.descriptor.size; p += attribute.descriptor.size ) { + buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), p + attribute.descriptor.offset, p + attribute.descriptor.offset + attribute.descriptor.size ); + } +#endif } \ No newline at end of file diff --git a/engine/src/utils/userdata/userdata.cpp b/engine/src/utils/userdata/userdata.cpp index 11c8cd05..d9a7e8c7 100644 --- a/engine/src/utils/userdata/userdata.cpp +++ b/engine/src/utils/userdata/userdata.cpp @@ -61,7 +61,7 @@ void UF_API uf::userdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::Use } pod::Userdata* UF_API uf::userdata::copy( uf::MemoryPool& requestedMemoryPool, const pod::Userdata* userdata ) { if ( !userdata || userdata->len <= 0 ) return NULL; - auto* copied = uf::userdata::create( userdata->len, const_cast((const void*) userdata->data[0]) ); + auto* copied = uf::userdata::create( userdata->len, const_cast((const void*) &userdata->data[0]) ); copied->type = userdata->type; return copied; } diff --git a/ext/behaviors/baking/behavior.cpp b/ext/behaviors/baking/behavior.cpp index 675befe0..b6f8de3f 100644 --- a/ext/behaviors/baking/behavior.cpp +++ b/ext/behaviors/baking/behavior.cpp @@ -7,7 +7,7 @@ #include #include #include - +#include #include #include "../light/behavior.h" @@ -17,6 +17,7 @@ UF_BEHAVIOR_REGISTER_CPP(ext::BakingBehavior) UF_BEHAVIOR_TRAITS_CPP(ext::BakingBehavior, ticks = true, renders = false, multithread = false) #define this (&self) void ext::BakingBehavior::initialize( uf::Object& self ) { +#if 0 #if UF_USE_VULKAN UF_MSG_DEBUG("Ping"); @@ -316,7 +317,7 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { for ( auto& node : graph.nodes ) { instances.emplace_back( uf::transform::model( node.transform ) ); } - metadata.buffers.instance = graphic.initializeBuffer( + metadata.buffers.instance = shader.initializeBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), uf::renderer::enums::Buffer::STORAGE @@ -326,7 +327,7 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { for ( size_t i = 0; i < graph.materials.size(); ++i ) { materials[i] = graph.materials[i].storage; } - metadata.buffers.material = graphic.initializeBuffer( + metadata.buffers.material = shader.initializeBuffer( (const void*) materials.data(), materials.size() * sizeof(pod::Material::Storage), uf::renderer::enums::Buffer::STORAGE @@ -336,13 +337,13 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { for ( size_t i = 0; i < graph.textures.size(); ++i ) { textures[i] = graph.textures[i].storage; } - metadata.buffers.texture = graphic.initializeBuffer( + metadata.buffers.texture = shader.initializeBuffer( (const void*) textures.data(), textures.size() * sizeof(pod::Texture::Storage), uf::renderer::enums::Buffer::STORAGE ); // Light storage buffer - metadata.buffers.light = graphic.initializeBuffer( + metadata.buffers.light = shader.initializeBuffer( (const void*) lights.data(), lights.size() * sizeof(pod::Light::Storage), uf::renderer::enums::Buffer::STORAGE @@ -431,8 +432,10 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { this->queueHook( "entity:PostInitialization.%UID%", ext::json::null(), 1 ); #endif +#endif } void ext::BakingBehavior::tick( uf::Object& self ) { +#if 0 #if UF_USE_VULKAN if ( !this->hasComponent() ) return; auto& metadata = this->getComponent(); @@ -483,6 +486,7 @@ SAVE: { return; } #endif +#endif } void ext::BakingBehavior::render( uf::Object& self ){} void ext::BakingBehavior::destroy( uf::Object& self ){ diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 9e684fec..35f454c0 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -523,7 +523,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string alignas(4) uint32_t lights = 0; alignas(4) uint32_t materials = 0; alignas(4) uint32_t textures = 0; - alignas(4) uint32_t drawCalls = 0; + alignas(4) uint32_t drawCommands = 0; } lengths; pod::Vector3f ambient; @@ -559,41 +559,59 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string texturesCube.reserve( metadata.max.texturesCube ); // lighting information - uf::stl::vector lights; + uf::stl::vector lights; lights.reserve( metadata.max.lights ); // material information - uf::stl::vector materials; + uf::stl::vector materials; materials.reserve( metadata.max.textures2D ); materials.emplace_back().colorBase = {0,0,0,0}; // setup our fallback material information // texture information - uf::stl::vector textures; + uf::stl::vector textures; textures.reserve( metadata.max.textures2D ); // drawcall information - uf::stl::vector drawCalls; - drawCalls.reserve( metadata.max.textures2D ); + uf::stl::vector drawCommands; + drawCommands.reserve( metadata.max.textures2D ); + + // bind materials + for ( auto pair : uf::graph::storage.materials ) materials.emplace_back(pair.second); + for ( auto pair : uf::graph::storage.textures ) textures.emplace_back(pair.second); + // bind textures + // bind texture2Ds + for ( auto pair : uf::graph::storage.images ) { + auto& image = pair.second; + auto& texture2D = uf::graph::storage.texture2Ds[pair.first]; + if ( !texture2D.generated() ) texture2D.loadFromImage( pair.second ); + textures2D.emplace_back().aliasTexture(texture2D); + } // traverse scene graph for ( auto entity : graph ) { // needed to grab our necessary materials/texture information, until i add it globally + #if 0 if ( entity->hasComponent() ) { auto& graph = entity->getComponent(); // pass our draw call information, necessary in shader - drawCalls.emplace_back(pod::DrawCall::Storage{ + /* + drawCommands.emplace_back(pod::DrawCall{ materials.size(), textures.size(), textures2D.size(), 0, }); + */ // pass material information - for ( auto& material : graph.materials ) materials.emplace_back( material.storage ); + for ( auto& material : graph.materials ) { + materials.emplace_back( uf::graph::storage.materials[material] ); + } // pass texture information for ( auto& texture : graph.textures ) { - textures.emplace_back( texture.storage ); + textures.emplace_back( uf::graph::storage.textures[texture] ); // attach the actual texture if the texture information requests it - if ( texture.bind ) textures2D.emplace_back().aliasTexture(texture.texture); + // if ( texture.bind ) textures2D.emplace_back().aliasTexture(texture.texture); } } + #endif // ignore this scene, our controller, and anything that isn't actually a light if ( entity == this || entity == &controller || !entity->hasComponent() ) continue; auto& metadata = entity->getComponent(); @@ -637,15 +655,15 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string uf::Entity* entity = info.entity; if ( !info.shadows ) { - lights.emplace_back(pod::Light::Storage{ + lights.emplace_back(pod::Light{ + .view = uf::matrix::identity(), + .projection = uf::matrix::identity(), .position = info.position, .color = info.color, .type = info.type, .typeMap = 0, .indexMap = -1, .depthBias = info.bias, - .view = uf::matrix::identity(), - .projection = uf::matrix::identity(), }); } else { auto& renderMode = entity->getComponent(); @@ -676,15 +694,15 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string break; } } - lights.emplace_back(pod::Light::Storage{ + lights.emplace_back(pod::Light{ + .view = lightCamera.getView(0), + .projection = lightCamera.getProjection(0), .position = info.position, .color = info.color, .type = info.type, .typeMap = metadata.shadow.experimentalMode, .indexMap = index, .depthBias = info.bias, - .view = lightCamera.getView(0), - .projection = lightCamera.getProjection(0), }); // any other shadowing light, even point lights, are split by shadow maps } else { @@ -692,15 +710,15 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue; for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { - lights.emplace_back(pod::Light::Storage{ + lights.emplace_back(pod::Light{ + .view = lightCamera.getView(view), + .projection = lightCamera.getProjection(view), .position = info.position, .color = info.color, .type = info.type, .typeMap = 0, .indexMap = textures2D.size(), .depthBias = info.bias, - .view = lightCamera.getView(view), - .projection = lightCamera.getProjection(view), }); textures2D.emplace_back().aliasAttachment(attachment, view); } @@ -766,7 +784,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string .lights = MIN( lights.size(), metadata.max.lights ), .materials = MIN( materials.size(), metadata.max.textures2D ), .textures = MIN( textures.size(), metadata.max.textures2D ), - .drawCalls = MIN( drawCalls.size(), metadata.max.textures2D ), + // .drawCommands = MIN( drawCommands.size(), metadata.max.textures2D ), }; uniforms.ambient = metadata.light.ambient; @@ -801,24 +819,24 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string } // update lighting buffer - graphic.updateBuffer( (const void*) lights.data(), uniforms.lengths.lights * sizeof(pod::Light::Storage), renderMode.metadata.lightBufferIndex, false ); + shader.updateBuffer( (const void*) lights.data(), uniforms.lengths.lights * sizeof(pod::Light), renderMode.metadata.lightBufferIndex, false ); // if ( shouldUpdate ) { - graphic.updateBuffer( (const void*) materials.data(), uniforms.lengths.materials * sizeof(pod::Material::Storage), renderMode.metadata.materialBufferIndex, false ); - graphic.updateBuffer( (const void*) textures.data(), uniforms.lengths.textures * sizeof(pod::Texture::Storage), renderMode.metadata.textureBufferIndex, false ); - graphic.updateBuffer( (const void*) drawCalls.data(), uniforms.lengths.drawCalls * sizeof(pod::DrawCall::Storage), renderMode.metadata.drawCallBufferIndex, false ); + shader.updateBuffer( (const void*) materials.data(), uniforms.lengths.materials * sizeof(pod::Material), renderMode.metadata.materialBufferIndex, false ); + shader.updateBuffer( (const void*) textures.data(), uniforms.lengths.textures * sizeof(pod::Texture), renderMode.metadata.textureBufferIndex, false ); + shader.updateBuffer( (const void*) drawCommands.data(), uniforms.lengths.drawCommands * sizeof(pod::DrawCommand), renderMode.metadata.drawCallBufferIndex, false ); graphic.updatePipelines(); } - // graphic.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shader.getUniformBuffer("UBO") ); - graphic.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); + // shader.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shader.getUniformBuffer("UBO") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); /* auto& uniform = shader.getUniform("UBO"); memcpy( (void*) uniform, &uniforms, sizeof(uniforms) ); shader.updateUniform( "UBO", uniform ); */ } -#endif } +#endif #undef this \ No newline at end of file diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index d54b6a7c..613e16c7 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -234,7 +235,7 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { .matrix = metadata.extents.matrix, .cascadePower = metadata.cascadePower, }; - graphic.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); #endif } } diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index 745353c0..97617d8b 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -317,9 +317,9 @@ void ext::Gui::load( const uf::Image& image ) { auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( image ); - auto& mesh = this->getComponent(); +// auto& mesh = this->getComponent(); auto& transform = this->getComponent>(); - mesh.vertices = { + uf::stl::vector vertices = { { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, metadata.color }, { pod::Vector3f{-1.0f, -1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, metadata.color }, { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, metadata.color }, @@ -350,11 +350,9 @@ void ext::Gui::load( const uf::Image& image ) { metadataJson["cull mode"] = "none"; graphic.descriptor.parse( metadataJson ); - if ( metadataJson["flip uv"].as() ) { - for ( auto& v : mesh.vertices ) v.uv.y = 1 - v.uv.y; - } - if ( metadata.depth != 0.0f ) - for ( auto& v : mesh.vertices ) v.position.z = metadata.depth; + if ( metadataJson["flip uv"].as() ) for ( auto& v : vertices ) v.uv.y = 1 - v.uv.y; + if ( metadata.depth != 0.0f ) for ( auto& v : vertices ) v.position.z = metadata.depth; + if ( metadataJson["scaling"].is() ) { uf::stl::string mode = metadataJson["scaling"].as(); if ( mode == "mesh" ) { @@ -379,7 +377,13 @@ void ext::Gui::load( const uf::Image& image ) { } else { graphic.initialize( ::defaultRenderMode ); } + + auto& mesh = this->getComponent(); + mesh.bind(); + mesh.insertVertices( vertices ); + graphic.initializeMesh( mesh ); + struct { uf::stl::string vertex = uf::io::root+"/shaders/gui/base.vert.spv"; uf::stl::string fragment = uf::io::root+"/shaders/gui/base.frag.spv"; @@ -524,7 +528,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { }); this->addHook( "window:Mouse.Moved", [&](ext::json::Value& json){ if ( this->getUid() == 0 ) return; - if ( !this->hasComponent() ) return; + if ( !this->hasComponent() ) return; if ( metadata.world ) return; if ( !metadata.box.min && !metadata.box.max ) return; @@ -596,19 +600,17 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { key += std::to_string(metadataGlyph.sdf); } auto& scene = uf::scene::getCurrentScene(); - auto& mesh = this->getComponent(); + auto& mesh = this->getComponent(); auto& graphic = this->getComponent(); auto& atlas = this->getComponent(); auto& images = atlas.getImages(); if ( !first ) { atlas.clear(); - mesh.vertices.clear(); - mesh.indices.clear(); + mesh.destroy(); for ( auto& texture : graphic.material.textures ) texture.destroy(); graphic.material.textures.clear(); } - mesh.vertices.reserve( glyphs.size() * 6 ); uf::stl::unordered_map glyphHashMap; for ( auto& g : glyphs ) { @@ -637,26 +639,31 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { transform.scale.x = scale; transform.scale.y = scale; + uf::stl::vector vertices; + vertices.reserve( glyphs.size() * 6 ); + for ( auto& g : glyphs ) { auto glyphKey = std::to_string((uint64_t) g.code) + ";"+key; auto& glyph = ::glyphs.cache[font][glyphKey]; auto hash = glyphHashMap[glyphKey]; // add vertices - mesh.vertices.push_back({pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), g.color}); - mesh.vertices.push_back({pod::Vector3f{ g.box.x, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 1.0f }, hash ), g.color}); - mesh.vertices.push_back({pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), g.color}); - mesh.vertices.push_back({pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), g.color}); - mesh.vertices.push_back({pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), g.color}); - mesh.vertices.push_back({pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 0.0f }, hash ), g.color}); + vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), g.color}); + vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 1.0f }, hash ), g.color}); + vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), g.color}); + vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), g.color}); + vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), g.color}); + vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 0.0f }, hash ), g.color}); } - for ( size_t i = 0; i < mesh.vertices.size(); i += 6 ) { + for ( size_t i = 0; i < vertices.size(); i += 6 ) { for ( size_t j = 0; j < 6; ++j ) { - auto& vertex = mesh.vertices[i+j]; + auto& vertex = vertices[i+j]; vertex.position.x /= ext::gui::size.reference.x; vertex.position.y /= ext::gui::size.reference.y; vertex.position.z = metadata.depth; } } + mesh.bind(); + mesh.insertVertices( vertices ); auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( atlas.getAtlas() ); @@ -809,15 +816,13 @@ void ext::GuiBehavior::tick( uf::Object& self ) { .color = metadata.color, .mode = metadata.shader, - .depth = metadata.depth, + .depth = 1 - metadata.depth, }; // set glyph-based uniforms if ( isGlyph && uniform.size() == sizeof(::GlyphUniformDescriptor<>) ) { auto& uniforms = uniform.get<::GlyphUniformDescriptor<>>(); auto& metadataGlyph = this->getComponent(); - // uniforms.gui.sdf = metadataGlyph.sdf; - // uniforms.gui.shadowbox = metadataGlyph.shadowbox; if ( metadataGlyph.sdf ) uniforms.gui.mode &= 1 << 1; if ( metadataGlyph.shadowbox ) uniforms.gui.mode &= 1 << 2; @@ -826,6 +831,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) { uniforms.glyph.weight = metadataGlyph.weight; uniforms.glyph.scale = metadataGlyph.scale; } + // shader.updateBuffer( uniform, shader.getUniformBuffer("UBO") ); shader.updateUniform( "UBO", uniform ); // calculate click box @@ -834,6 +840,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) { pod::Vector2f min = { 1, 1 }; pod::Vector2f max = { -1, -1 }; + /* if ( this->hasComponent() ) { auto& mesh = this->getComponent(); for ( auto& vertex : mesh.vertices ) { @@ -859,6 +866,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) { max.y = std::max( max.y, translated.y ); } } + */ metadata.box.min.x = min.x; metadata.box.min.y = min.y; diff --git a/ext/gui/gui.h b/ext/gui/gui.h index a3426142..5b41caef 100644 --- a/ext/gui/gui.h +++ b/ext/gui/gui.h @@ -22,8 +22,8 @@ namespace pod { namespace ext { class EXT_API Gui : public uf::Object { public: - typedef uf::Mesh mesh_t; - typedef uf::Mesh glyph_mesh_t; + // typedef uf::Mesh mesh_t; + // typedef uf::Mesh glyph_mesh_t; // Gui(); uf::stl::vector generateGlyphs( const uf::stl::string& = "" ); void load( const uf::Image& ); diff --git a/ext/gui/manager/behavior.cpp b/ext/gui/manager/behavior.cpp index 35057e27..be111d07 100644 --- a/ext/gui/manager/behavior.cpp +++ b/ext/gui/manager/behavior.cpp @@ -160,9 +160,9 @@ void ext::GuiManagerBehavior::tick( uf::Object& self ) { uniforms.cursor.color = metadata.overlay.cursor.color; } #if UF_UNIFORMS_REUSE - blitter.updateUniform( "UBO", uniform ); + shader.updateUniform( "UBO", uniform ); #else - blitter.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); + shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); #endif #endif } diff --git a/g++.exe.stackdump b/g++.exe.stackdump new file mode 100644 index 00000000..93d4857c --- /dev/null +++ b/g++.exe.stackdump @@ -0,0 +1,24 @@ +Stack trace: +Frame Function Args +000FFFF5848 00180062C9C (000FFFF5A68, 00010000002, 000FFFFCE00, 000FFFFDE50) +000FFFF58F0 00180065090 (001800FA0BE, 00100140000, 100000000000101, 00000000000) +000FFFF5F70 00180047D1B (00000000000, 00000000000, 00000000000, 00000000000) +000FFFF6050 001801711AC (00000000001, 00000000000, 0000000019C, FFFFFFFF00000000) +000FFFF99F0 0018014761E (0018035B200, 008000F0610, 008000B36F0, 00000001003) +000FFFFAB80 00180148201 (00180352408, 0018037A8A0, 000FFFFAD02, 00000000000) +000FFFFAC30 00180065873 (001801B48F6, 000FFFFAE48, 00000000000, FFFFFFFFFFFFFFFF) +000FFFFAD90 001801389AB (001801B48F6, 000FFFFAE48, 00000000000, FFFFFFFFFFFFFFFF) +000FFFFAD90 0010040E131 (000FFFFAE48, 008000FE8F0, 00000000000, 001FFFFAE48) +00100433CA8 0010040E3DB (0080006D408, 008000F0610, 008000ED0A0, 008000B2AF0) +00100433CA8 0010040E8E4 (00000000000, 008000E8D43, 00000000008, 008000E8D3A) +000FFFFAFF0 0010040F34B (00100000000, 000FFFFB0F0, 00000000000, 00000000001) +000FFFFAFF0 0010040FB20 (00000000000, 183A92A3F1E23A87, 000000020C0, 00800063A21) +00000000001 0010041A5AF (00100000002, 0010040BA66, 00000000001, 001004335A8) +00000000001 0010041A9D9 (0080006CA36, 00000000001, 00000000028, 0080006CF10) +00000000001 00100419958 (00800000000, 6176652D2A2D2824, 2D7367616C662D6C, 00000292D2A) +001004369F0 0010041ADC7 (00100423B48, 00000000001, 00430B39190, 00000000000) +000FFFFB400 00100423FD8 (000FFFFCC90, 00800000160, 00000000000, 00180330BA0) +000FFFFCCE0 0018004A01B (00000000000, 00000000000, 00000000000, 00000000000) +000FFFFCDA0 0018004794A (00000000000, 00000000000, 00000000000, 00000000000) +000FFFFCE50 00180047A0C (00000000000, 00000000000, 00000000000, 00000000000) +End of stack trace