From 6d8fbc6ee514a71a413738dcbfbb2e679697263e Mon Sep 17 00:00:00 2001 From: mrq Date: Fri, 16 Jul 2021 23:54:00 -0500 Subject: [PATCH] Commit for 2021.07.16 23-54-06.7z --- Makefile | 2 +- bin/data/config.json | 46 +- bin/data/entities/light.json | 2 +- bin/data/scenes/mcdonalds/loading.json | 2 +- bin/data/scenes/mcdonalds/mcdonalds.json | 6 +- .../scenes/sh2_mcdonalds/sh2_mcdonalds.json | 4 +- bin/data/scenes/ss2/medsci.json | 3 +- bin/data/shaders/bullet/base.frag.glsl | 13 + bin/data/shaders/bullet/base.vert.glsl | 28 + bin/data/shaders/common/pbr.h | 1 + bin/data/shaders/common/structs.h | 28 +- bin/data/shaders/display/base.vert.glsl | 13 +- .../shaders/display/rendertarget.vert.glsl | 9 +- bin/data/shaders/display/subpass.h | 28 +- bin/data/shaders/display/subpass.vert.glsl | 10 +- bin/data/shaders/display/vxgi.comp.h | 26 +- bin/data/shaders/gltf/baking/bake.vert.glsl | 50 - .../baked.deferredSampling.frag.glsl | 0 .../shaders/{gltf => graph}/baked.frag.glsl | 0 bin/data/shaders/{gltf => graph}/baked.frag.h | 2 +- .../{gltf => graph}/baking/bake.frag.glsl | 0 bin/data/shaders/graph/baking/bake.vert.glsl | 6 + .../base.deferredSampling.frag.glsl | 0 .../shaders/{gltf => graph}/base.frag.glsl | 0 bin/data/shaders/{gltf => graph}/base.frag.h | 16 +- .../shaders/{gltf => graph}/base.vert.glsl | 0 bin/data/shaders/{gltf => graph}/base.vert.h | 57 +- bin/data/shaders/graph/cull.comp.glsl | 267 +++ bin/data/shaders/graph/depth.frag.glsl | 58 + .../{gltf => graph}/instanced.vert.glsl | 0 .../skinned.instanced.vert.glsl | 0 .../shaders/{gltf => graph}/skinned.vert.glsl | 0 .../{gltf => graph}/voxelize.frag.glsl | 0 .../shaders/{gltf => graph}/voxelize.frag.h | 17 +- .../{gltf => graph}/voxelize.geom.glsl | 2 +- client/client/ext.cpp | 5 + client/main.cpp | 40 - engine/inc/uf/config.h | 8 +- engine/inc/uf/engine/graph/graph.h | 88 +- engine/inc/uf/engine/graph/pod.inl | 31 +- engine/inc/uf/ext/bullet/bullet.h | 6 + engine/inc/uf/ext/opengl/opengl.h | 2 +- engine/inc/uf/ext/vulkan/buffer.h | 10 +- engine/inc/uf/ext/vulkan/graphic.h | 34 +- engine/inc/uf/ext/vulkan/rendermode.h | 9 +- .../inc/uf/ext/vulkan/rendermodes/compute.h | 1 - engine/inc/uf/ext/vulkan/shader.h | 5 +- engine/inc/uf/ext/vulkan/swapchain.h | 2 +- engine/inc/uf/ext/vulkan/texture.h | 25 +- engine/inc/uf/ext/vulkan/vulkan.h | 2 +- engine/inc/uf/macros.h | 2 +- engine/inc/uf/utils/image/image.h | 3 +- engine/inc/uf/utils/math/matrix/pod.inl | 10 +- engine/inc/uf/utils/math/vector.h | 5 + engine/inc/uf/utils/math/vector/pod.inl | 30 + engine/inc/uf/utils/mesh/mesh.h | 50 +- engine/src/engine/asset/asset.cpp | 4 +- engine/src/engine/graph/graph.cpp | 1709 +++++++---------- engine/src/engine/object/behaviors/graph.cpp | 4 + engine/src/engine/object/behaviors/render.cpp | 5 +- engine/src/ext/bullet/bullet.cpp | 195 +- engine/src/ext/gltf/gltf.cpp | 214 ++- engine/src/ext/opengl/commands.cpp | 299 +-- engine/src/ext/opengl/opengl.cpp | 6 +- engine/src/ext/vulkan/buffer.cpp | 30 +- engine/src/ext/vulkan/graphic.cpp | 390 ++-- engine/src/ext/vulkan/rendermode.cpp | 68 +- engine/src/ext/vulkan/rendermodes/compute.cpp | 3 +- .../src/ext/vulkan/rendermodes/deferred.cpp | 117 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 78 +- engine/src/ext/vulkan/shader.cpp | 13 +- engine/src/ext/vulkan/texture.cpp | 65 +- engine/src/ext/vulkan/vulkan.cpp | 10 +- engine/src/ext/xatlas/xatlas.cpp | 211 +- engine/src/utils/image/image.cpp | 3 +- engine/src/utils/mesh/mesh.cpp | 112 +- ext/behaviors/baking/behavior.cpp | 4 +- ext/behaviors/light/behavior.cpp | 5 + ext/behaviors/player/behavior.cpp | 3 +- ext/behaviors/scene/behavior.cpp | 369 ++-- ext/behaviors/voxelizer/behavior.cpp | 13 +- ext/gui/behavior.cpp | 8 +- ext/main.cpp | 24 +- g++.exe.stackdump | 24 - 84 files changed, 2645 insertions(+), 2405 deletions(-) create mode 100644 bin/data/shaders/bullet/base.frag.glsl create mode 100644 bin/data/shaders/bullet/base.vert.glsl delete mode 100644 bin/data/shaders/gltf/baking/bake.vert.glsl rename bin/data/shaders/{gltf => graph}/baked.deferredSampling.frag.glsl (100%) rename bin/data/shaders/{gltf => graph}/baked.frag.glsl (100%) rename bin/data/shaders/{gltf => graph}/baked.frag.h (93%) rename bin/data/shaders/{gltf => graph}/baking/bake.frag.glsl (100%) create mode 100644 bin/data/shaders/graph/baking/bake.vert.glsl rename bin/data/shaders/{gltf => graph}/base.deferredSampling.frag.glsl (100%) rename bin/data/shaders/{gltf => graph}/base.frag.glsl (100%) rename bin/data/shaders/{gltf => graph}/base.frag.h (88%) rename bin/data/shaders/{gltf => graph}/base.vert.glsl (100%) rename bin/data/shaders/{gltf => graph}/base.vert.h (60%) create mode 100644 bin/data/shaders/graph/cull.comp.glsl create mode 100644 bin/data/shaders/graph/depth.frag.glsl rename bin/data/shaders/{gltf => graph}/instanced.vert.glsl (100%) rename bin/data/shaders/{gltf => graph}/skinned.instanced.vert.glsl (100%) rename bin/data/shaders/{gltf => graph}/skinned.vert.glsl (100%) rename bin/data/shaders/{gltf => graph}/voxelize.frag.glsl (100%) rename bin/data/shaders/{gltf => graph}/voxelize.frag.h (83%) rename bin/data/shaders/{gltf => graph}/voxelize.geom.glsl (95%) delete mode 100644 g++.exe.stackdump diff --git a/Makefile b/Makefile index 43991f52..34b3cac6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ARCH = win64 -CC = $(shell cat "./bin/exe/default.config") +CC = $(shell cat "./bin/exe/default.config") TARGET_NAME = program TARGET_EXTENSION = exe TARGET_LIB_EXTENSION = dll diff --git a/bin/data/config.json b/bin/data/config.json index d70c3ad2..d986c6b7 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -1,46 +1,52 @@ { "engine": { "scenes": { - "start": "SS2", + "start": "McDonalds", "lights": { - "max": 512, + "max": 64, "enabled": true }, "shadows": { "enabled": true, - "update": 4, + "update": 2, "max": 8, "samples": 2, "experimental mode": 1 }, "textures": { "max": { - "2D": 512, + "2D": 1024, "cube": 128, "3D": 1 } }, + "meshes": { + "interleave": false + }, + "matrix": { + "reverseInfinite": true + }, "vxgi": { "limiter": 0.125, - "size": 64, + "size": 96, "dispatch": 8, - "cascades": 4, + "cascades": 6, "cascadePower": 4, "shadows": 0, "granularity": 4, "extents": { - "min": [ -2.5, -2.5, -2.5 ], - "max": [ 2.5, 2.5, 2.5 ] + "min": [ -1.5, -1.5, -1.5 ], + "max": [ 1.5, 1.5, 1.5 ] } } }, "ext": { "vulkan": { "validation": { - "enabled": true, + "enabled": false, "filters": [ "MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps) - "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) + // "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) "MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) "MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls) // "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?) @@ -66,8 +72,9 @@ "deferred alias output to swapchain": true, "vsync": true, "hdr": false, - "vxgi": false, - "deferred sampling": false + "vxgi": true, + "deferred sampling": true, + "culling": false }, "formats": { "depth": "D32_SFLOAT", @@ -76,6 +83,10 @@ "position": "R16G16B16A16_SFLOAT" }, "features": [ + "shaderDrawParameters", + "multiDrawIndirect", + "fillModeNonSolid", + "wideLines", "independentBlend", "deviceCoherentMemory", "robustBufferAccess", @@ -117,7 +128,8 @@ // "deferred mode": "deferredSampling", "deferred reconstruct position": true, "deferred alias output to swapchain": true, - "hdr": false + "hdr": false, + "culling": true }, "formats": { "depth": "D32_SFLOAT", @@ -159,7 +171,7 @@ }, "debug draw": { "enabled": false, - "rate": 1.0 + "rate": 0.0125 } }, "discord": { @@ -175,7 +187,7 @@ "streams by default": true }, "memory pool": { - "enabled": false, + "enabled": true, "subPools": true, "alignment": 64, "override": false, @@ -212,8 +224,8 @@ "announce": true }, "entity": { - "delete children on destroy": false, - "delete components on destroy": false + "delete children on destroy": true, + "delete components on destroy": true } } }, diff --git a/bin/data/entities/light.json b/bin/data/entities/light.json index 7367d975..aa6ed7cb 100644 --- a/bin/data/entities/light.json +++ b/bin/data/entities/light.json @@ -35,7 +35,7 @@ "slope": 1.75, "shader": 0.000005 //0.000000005 }, - "radius": [0.001, 0], + "radius": [0.001, 256.0], "resolution": 1024, "shadows": true, "static": false diff --git a/bin/data/scenes/mcdonalds/loading.json b/bin/data/scenes/mcdonalds/loading.json index b50ed4ac..0ec6c59c 100644 --- a/bin/data/scenes/mcdonalds/loading.json +++ b/bin/data/scenes/mcdonalds/loading.json @@ -2,7 +2,7 @@ "name": "Gui: Loading", "type": "Object", "behaviors": [ - "GuiBehavior" + // "GuiBehavior" ], "assets": [ { "filename": "./mcdonalds.json", "delay": 0 } diff --git a/bin/data/scenes/mcdonalds/mcdonalds.json b/bin/data/scenes/mcdonalds/mcdonalds.json index 449bb76e..b428dbc7 100644 --- a/bin/data/scenes/mcdonalds/mcdonalds.json +++ b/bin/data/scenes/mcdonalds/mcdonalds.json @@ -5,9 +5,9 @@ "assets": [ // { "filename": "./static.json", "delay": 8 }, - // { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false } + { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false } // { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" } - { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + // { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } ], "behaviors": [ "LoadingBehavior" @@ -44,7 +44,7 @@ // "filter": "NEAREST", "flags": { - "ATLAS": true, + "ATLAS": false, "INVERT": false, "TRANSFORM": false, "SKINNED": false, diff --git a/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json b/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json index b80b3804..d82a7963 100644 --- a/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json +++ b/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json @@ -5,9 +5,9 @@ "assets": [ // { "filename": "./static.json", "delay": 8 }, - // { "filename": "./models/sh_mcd.glb", "delay": 0, "single threaded": false } + { "filename": "./models/sh_mcd.glb", "delay": 0, "single threaded": false } // { "filename": "./models/sh_mcd/graph.json", "delay": 0, "single threaded": false, "category": "models" } - { "filename": "./models/sh_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + // { "filename": "./models/sh_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } ], "behaviors": [ "LoadingBehavior" diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index 933a4ebd..05627bbd 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -50,12 +50,13 @@ // "lightmap": "./lightmap.png", "filter": "NEAREST", "flags": { - "ATLAS": true, + "ATLAS": false, "INVERT": false, "TRANSFORM": false, "SKINNED": false, "RENDER": true, + // "SEPARATE": false, "SEPARATE": false, "NORMALS": false }, diff --git a/bin/data/shaders/bullet/base.frag.glsl b/bin/data/shaders/bullet/base.frag.glsl new file mode 100644 index 00000000..935d731a --- /dev/null +++ b/bin/data/shaders/bullet/base.frag.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(fragment) + +layout (location = 0) in vec3 inPosition; +layout (location = 1) in vec3 inColor; + +layout (location = 0) out uvec2 outId; +layout (location = 1) out vec2 outNormals; +layout (location = 2) out vec4 outAlbedo; + +void main() { + outAlbedo = vec4(inColor, 1); +} \ No newline at end of file diff --git a/bin/data/shaders/bullet/base.vert.glsl b/bin/data/shaders/bullet/base.vert.glsl new file mode 100644 index 00000000..89fae3b1 --- /dev/null +++ b/bin/data/shaders/bullet/base.vert.glsl @@ -0,0 +1,28 @@ +#version 450 +#pragma shader_stage(vertex) + +#include "../common/structs.h" + +layout (constant_id = 0) const uint PASSES = 6; + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (location = 0) out vec3 outPosition; +layout (location = 1) out vec3 outColor; + +void main() { + outPosition = vec3(camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0)); + outColor = inColor; + + gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0); +} \ No newline at end of file diff --git a/bin/data/shaders/common/pbr.h b/bin/data/shaders/common/pbr.h index 5a8ede50..ed957136 100644 --- a/bin/data/shaders/common/pbr.h +++ b/bin/data/shaders/common/pbr.h @@ -24,6 +24,7 @@ void pbr() { if ( light.power <= LIGHT_POWER_CUTOFF ) continue; const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye; const vec3 Li = normalize(Liu); + const bool reverseZ = light.projection[2][2] < 0.00001; const float Ls = shadowFactor( light, 0.0 ); const float La = 1.0 / (PI * pow(length(Liu), 2.0)); if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index 3d6a61d1..a2a68e5e 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -86,9 +86,9 @@ struct Material { int indexOcclusion; int indexMetallicRoughness; - int indexAtlas; int indexLightmap; int modeAlpha; + int padding; }; struct Texture { @@ -107,9 +107,28 @@ struct DrawCommand { int vertexID; // starting vertex position uint instanceID; // starting instance position - uint materialID; // material used for draw - uint objectID; // - uint vertices; // + uint padding; // + uint materialID; // material to use for this draw call + uint vertices; // number of vertices used +}; + +struct Bounds { + vec3 min; + float padding1; + vec3 max; + float padding2; +}; + +struct Instance { + mat4 model; + vec4 color; + + uint materialID; + uint primitiveID; + uint meshID; + uint objectID; + + Bounds bounds; }; struct SurfaceMaterial { @@ -122,7 +141,6 @@ struct SurfaceMaterial { float roughness; float occlusion; int indexLightmap; - }; struct Surface { diff --git a/bin/data/shaders/display/base.vert.glsl b/bin/data/shaders/display/base.vert.glsl index 72856791..2c8ad0a7 100644 --- a/bin/data/shaders/display/base.vert.glsl +++ b/bin/data/shaders/display/base.vert.glsl @@ -1,18 +1,13 @@ #version 450 #pragma shader_stage(vertex) +#if 0 layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; - +#endif layout (location = 0) out vec2 outUv; -out gl_PerVertex { - vec4 gl_Position; -}; - - void main() { - outUv = inUv; - - gl_Position = vec4(inPos.xy, 0.0, 1.0); + outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); } \ No newline at end of file diff --git a/bin/data/shaders/display/rendertarget.vert.glsl b/bin/data/shaders/display/rendertarget.vert.glsl index a269a50f..ff305fa6 100644 --- a/bin/data/shaders/display/rendertarget.vert.glsl +++ b/bin/data/shaders/display/rendertarget.vert.glsl @@ -19,10 +19,6 @@ layout( push_constant ) uniform PushBlock { uint draw; } PushConstant; -out gl_PerVertex { - vec4 gl_Position; -}; - struct Matrices { mat4 model[2]; }; @@ -34,9 +30,8 @@ layout (binding = 0) uniform UBO { } ubo; void main() { - outUv = inUv; + outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); outCursor = ubo.cursor; outAlpha = 1; - - gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, 0.0, 1.0); + gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h index 1d42669f..df0e64dc 100644 --- a/bin/data/shaders/display/subpass.h +++ b/bin/data/shaders/display/subpass.h @@ -53,9 +53,13 @@ layout (binding = 4) uniform UBO { uint shadowSamples; uint indexSkybox; } ubo; - -layout (std140, binding = 5) readonly buffer Lights { - Light lights[]; +/* +layout (std140, binding = 5) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +*/ +layout (std140, binding = 5) readonly buffer Instances { + Instance instances[]; }; layout (std140, binding = 6) readonly buffer Materials { Material materials[]; @@ -63,8 +67,8 @@ layout (std140, binding = 6) readonly buffer Materials { layout (std140, binding = 7) readonly buffer Textures { Texture textures[]; }; -layout (std140, binding = 8) readonly buffer DrawCommands { - DrawCommand drawCommands[]; +layout (std140, binding = 8) readonly buffer Lights { + Light lights[]; }; layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; @@ -161,15 +165,17 @@ void populateSurface() { #endif surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) ); + const uint drawID = ID.x - 1; + const uint instanceID = ID.y - 1; if ( ID.x == 0 || ID.y == 0 ) { surface.fragment.rgb = texture( samplerCubemaps[ubo.indexSkybox], surface.ray.direction ).rgb; surface.fragment.a = 0.0; postProcess(); return; } - const uint drawId = ID.x - 1; - const DrawCommand drawCommand = drawCommands[drawId]; - surface.material.id = ID.y + drawCommand.materialID - 1; +// const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + surface.material.id = instance.materialID; const Material material = materials[surface.material.id]; surface.material.albedo = material.colorBase; surface.fragment = material.colorEmissive; @@ -180,8 +186,6 @@ void populateSurface() { surface.uv = resolve(samplerUv, ubo.msaa).xy; #endif const float mip = mipLevel(inUv.xy); -// 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 ); } @@ -196,8 +200,6 @@ void populateSurface() { } // Emissive textures -// 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 ); } @@ -217,7 +219,7 @@ void populateSurface() { void directLighting() { const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - + if ( ubo.lights == 0 ) { surface.fragment.rgb = surface.material.albedo.rgb; return; } #if PBR pbr(); #elif LAMBERT diff --git a/bin/data/shaders/display/subpass.vert.glsl b/bin/data/shaders/display/subpass.vert.glsl index 84260106..23f845c1 100644 --- a/bin/data/shaders/display/subpass.vert.glsl +++ b/bin/data/shaders/display/subpass.vert.glsl @@ -1,9 +1,10 @@ #version 450 #pragma shader_stage(vertex) +#if 0 layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; - +#endif layout (location = 0) out vec2 outUv; layout (location = 1) out flat uint outPushConstantPass; @@ -18,8 +19,11 @@ out gl_PerVertex { void main() { - outUv = inUv; outPushConstantPass = PushConstant.pass; - + outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); +#if 0 + outUv = inUv; gl_Position = vec4(inPos.xy, 0.0, 1.0); +#endif } \ No newline at end of file diff --git a/bin/data/shaders/display/vxgi.comp.h b/bin/data/shaders/display/vxgi.comp.h index 656960c1..763ca144 100644 --- a/bin/data/shaders/display/vxgi.comp.h +++ b/bin/data/shaders/display/vxgi.comp.h @@ -36,9 +36,13 @@ layout (binding = 4) uniform UBO { uint shadowSamples; uint indexSkybox; } ubo; - -layout (std140, binding = 5) readonly buffer Lights { - Light lights[]; +/* +layout (std140, binding = 5) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +*/ +layout (std140, binding = 5) readonly buffer Instances { + Instance instances[]; }; layout (std140, binding = 6) readonly buffer Materials { Material materials[]; @@ -46,8 +50,8 @@ layout (std140, binding = 6) readonly buffer Materials { layout (std140, binding = 7) readonly buffer Textures { Texture textures[]; }; -layout (std140, binding = 8) readonly buffer DrawCommands { - DrawCommand drawCommands[]; +layout (std140, binding = 8) readonly buffer Lights { + Light lights[]; }; layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; @@ -76,21 +80,21 @@ void main() { surface.position.world = vec3( inverse(ubo.vxgi.matrix) * vec4( surface.position.eye, 1.0f ) ); const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); + const uint drawID = ID.x - 1; + const uint instanceID = ID.y - 1; if ( ID.x == 0 || ID.y == 0 ) { imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); continue; } - const uint drawId = ID.x - 1; - const DrawCommand drawCommand = drawCommands[drawId]; - surface.material.id = ID.y + drawCommand.materialID - 1; + // const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + surface.material.id = instance.materialID; 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( 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 ); } @@ -106,8 +110,6 @@ void main() { } // Emissive textures - // 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 ); } diff --git a/bin/data/shaders/gltf/baking/bake.vert.glsl b/bin/data/shaders/gltf/baking/bake.vert.glsl deleted file mode 100644 index 2042844c..00000000 --- a/bin/data/shaders/gltf/baking/bake.vert.glsl +++ /dev/null @@ -1,50 +0,0 @@ -#version 450 -#pragma shader_stage(vertex) - -layout (constant_id = 0) const uint PASSES = 6; -layout (location = 0) in vec3 inPos; -layout (location = 1) in vec2 inUv; -layout (location = 2) in vec2 inSt; -layout (location = 3) in vec3 inNormal; -layout (location = 4) in vec4 inTangent; -layout (location = 5) in uvec2 inId; - -layout( push_constant ) uniform PushBlock { - uint pass; - uint draw; -} PushConstant; - -layout (std140, binding = 0) readonly buffer Models { - mat4 models[]; -}; - -layout (location = 0) out vec2 outUv; -layout (location = 1) out vec4 outColor; -layout (location = 2) out vec3 outNormal; -layout (location = 3) out mat3 outTBN; -layout (location = 6) out vec3 outPosition; -layout (location = 7) out ivec4 outId; - -out gl_PerVertex { - vec4 gl_Position; -}; - -void main() { - outUv = inUv; - outColor = vec4(1.0); - outId = ivec4(inId, PushConstant.pass, PushConstant.draw); - - mat4 model = models.length() <= 0 ? mat4(1.0) : models[int(inId.x)]; - outPosition = vec3(model * vec4(inPos.xyz, 1.0)); - outNormal = vec3(model * vec4(inNormal.xyz, 0.0)); - outNormal = normalize(outNormal); - - { - vec3 T = vec3(model * vec4(inTangent.xyz, 0.0)); - vec3 N = outNormal; - vec3 B = cross(N, T) * inTangent.w; - outTBN = mat3( T, B, N ); - } - - gl_Position = vec4(inSt * 2.0 - 1.0, 0.0, 1.0); -} \ No newline at end of file diff --git a/bin/data/shaders/gltf/baked.deferredSampling.frag.glsl b/bin/data/shaders/graph/baked.deferredSampling.frag.glsl similarity index 100% rename from bin/data/shaders/gltf/baked.deferredSampling.frag.glsl rename to bin/data/shaders/graph/baked.deferredSampling.frag.glsl diff --git a/bin/data/shaders/gltf/baked.frag.glsl b/bin/data/shaders/graph/baked.frag.glsl similarity index 100% rename from bin/data/shaders/gltf/baked.frag.glsl rename to bin/data/shaders/graph/baked.frag.glsl diff --git a/bin/data/shaders/gltf/baked.frag.h b/bin/data/shaders/graph/baked.frag.h similarity index 93% rename from bin/data/shaders/gltf/baked.frag.h rename to bin/data/shaders/graph/baked.frag.h index d00ef37e..c34b1962 100644 --- a/bin/data/shaders/gltf/baked.frag.h +++ b/bin/data/shaders/graph/baked.frag.h @@ -45,5 +45,5 @@ void main() { A = textureLod( samplerTextures[0], inSt, mip ); #endif outNormals = encodeNormals( N ); - outId = ivec2(inId.w+1, inId.y+1); + outId = ivec2(inId.x+1, inId.y+1); } \ No newline at end of file diff --git a/bin/data/shaders/gltf/baking/bake.frag.glsl b/bin/data/shaders/graph/baking/bake.frag.glsl similarity index 100% rename from bin/data/shaders/gltf/baking/bake.frag.glsl rename to bin/data/shaders/graph/baking/bake.frag.glsl diff --git a/bin/data/shaders/graph/baking/bake.vert.glsl b/bin/data/shaders/graph/baking/bake.vert.glsl new file mode 100644 index 00000000..356141a8 --- /dev/null +++ b/bin/data/shaders/graph/baking/bake.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#include "../base.vert.h" diff --git a/bin/data/shaders/gltf/base.deferredSampling.frag.glsl b/bin/data/shaders/graph/base.deferredSampling.frag.glsl similarity index 100% rename from bin/data/shaders/gltf/base.deferredSampling.frag.glsl rename to bin/data/shaders/graph/base.deferredSampling.frag.glsl diff --git a/bin/data/shaders/gltf/base.frag.glsl b/bin/data/shaders/graph/base.frag.glsl similarity index 100% rename from bin/data/shaders/gltf/base.frag.glsl rename to bin/data/shaders/graph/base.frag.glsl diff --git a/bin/data/shaders/gltf/base.frag.h b/bin/data/shaders/graph/base.frag.h similarity index 88% rename from bin/data/shaders/gltf/base.frag.h rename to bin/data/shaders/graph/base.frag.h index 6f215cc1..539bfe5b 100644 --- a/bin/data/shaders/gltf/base.frag.h +++ b/bin/data/shaders/graph/base.frag.h @@ -1,6 +1,7 @@ #extension GL_EXT_nonuniform_qualifier : enable #define CUBEMAPS 1 +// #define MAX_TEXTURES TEXTURES #define MAX_TEXTURES textures.length() layout (constant_id = 0) const uint TEXTURES = 1; @@ -8,7 +9,6 @@ layout (constant_id = 0) const uint TEXTURES = 1; #include "../common/structs.h" layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; - layout (std140, binding = 1) readonly buffer Materials { Material materials[]; }; @@ -35,28 +35,28 @@ layout (location = 1) out vec2 outNormals; #endif void main() { + const uint drawID = uint(inId.x); + const uint instanceID = uint(inId.y); + const uint materialID = uint(inId.z); const float mip = mipLevel(inUv.xy); const vec2 uv = wrap(inUv.xy); const vec3 P = inPosition; vec3 N = inNormal; vec4 A = vec4(0, 0, 0, 0); + #if DEFERRED_SAMPLING vec4 outAlbedo = vec4(0,0,0,0); #endif #if !DEFERRED_SAMPLING || CAN_DISCARD - const int materialId = int(inId.y); - Material material = materials[materialId]; + Material material = materials[materialID]; float M = material.factorMetallic; float R = material.factorRoughness; float AO = material.factorOcclusion; // sample albedo - const bool useAtlas = validTextureIndex( material.indexAtlas ); - Texture textureAtlas; - if ( useAtlas ) textureAtlas = textures[material.indexAtlas]; if ( !validTextureIndex( material.indexAlbedo ) ) discard; { - Texture t = textures[material.indexAlbedo]; + const Texture t = textures[material.indexAlbedo]; A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { @@ -110,5 +110,5 @@ void main() { outUvs = wrap(inUv.xy); #endif outNormals = encodeNormals( N ); - outId = ivec2(inId.w+1, inId.y+1); + outId = uvec2(drawID + 1, instanceID + 1); } \ No newline at end of file diff --git a/bin/data/shaders/gltf/base.vert.glsl b/bin/data/shaders/graph/base.vert.glsl similarity index 100% rename from bin/data/shaders/gltf/base.vert.glsl rename to bin/data/shaders/graph/base.vert.glsl diff --git a/bin/data/shaders/gltf/base.vert.h b/bin/data/shaders/graph/base.vert.h similarity index 60% rename from bin/data/shaders/gltf/base.vert.h rename to bin/data/shaders/graph/base.vert.h index 2bad338b..7f8ac898 100644 --- a/bin/data/shaders/gltf/base.vert.h +++ b/bin/data/shaders/graph/base.vert.h @@ -1,5 +1,5 @@ layout (constant_id = 0) const uint PASSES = 6; - +#extension GL_ARB_shader_draw_parameters : enable #include "../common/structs.h" layout (location = 0) in vec3 inPos; @@ -7,10 +7,9 @@ layout (location = 1) in vec2 inUv; layout (location = 2) in vec2 inSt; layout (location = 3) in vec3 inNormal; layout (location = 4) in vec4 inTangent; -layout (location = 5) in uvec2 inId; #if SKINNED - layout (location = 6) in uvec4 inJoints; - layout (location = 7) in vec4 inWeights; + layout (location = 5) in uvec4 inJoints; + layout (location = 6) in vec4 inWeights; #endif layout( push_constant ) uniform PushBlock { @@ -18,31 +17,23 @@ layout( push_constant ) uniform PushBlock { uint draw; } PushConstant; - layout (binding = 3) uniform Camera { Viewport viewport[PASSES]; } camera; -#if SKINNED && INSTANCED - layout (std140, binding = 4) readonly buffer Models { - mat4 models[]; - }; +/* +layout (std140, binding = 4) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +*/ +layout (std140, binding = 4) readonly buffer Instances { + Instance instances[]; +}; + +#if SKINNED layout (std140, binding = 5) readonly buffer Joints { mat4 joints[]; }; -#else - layout (binding = 4) uniform UBO { - mat4 model; - } ubo; - #if SKINNED - layout (std140, binding = 5) readonly buffer Joints { - mat4 joints[]; - }; - #elif INSTANCED - layout (std140, binding = 5) readonly buffer Models { - mat4 models[]; - }; - #endif #endif layout (location = 0) out vec2 outUv; @@ -64,21 +55,23 @@ vec4 snap(vec4 vertex, vec2 resolution) { void main() { outUv = inUv; outSt = inSt; - outColor = vec4(1); // ubo.color; - outId = ivec4(inId, PushConstant.pass, PushConstant.draw); - + const mat4 view = camera.viewport[PushConstant.pass].view; const mat4 projection = camera.viewport[PushConstant.pass].projection; #if SKINNED - mat4 skinned = joints.length() <= 0 ? mat4(1.0) : inWeights.x * joints[int(inJoints.x)] + inWeights.y * joints[int(inJoints.y)] + inWeights.z * joints[int(inJoints.z)] + inWeights.w * joints[int(inJoints.w)]; + const mat4 skinned = joints.length() <= 0 ? mat4(1.0) : inWeights.x * joints[int(inJoints.x)] + inWeights.y * joints[int(inJoints.y)] + inWeights.z * joints[int(inJoints.z)] + inWeights.w * joints[int(inJoints.w)]; #else - mat4 skinned = mat4(1.0); -#endif -#if INSTANCED - mat4 model = models.length() <= 0 ? skinned : (models[int(inId.x)] * skinned); -#else - mat4 model = ubo.model * skinned; + const mat4 skinned = mat4(1.0); #endif + const uint drawID = gl_DrawIDARB; +// const DrawCommand drawCommand = drawCommands[drawID]; + const uint instanceID = gl_InstanceIndex; + const Instance instance = instances[instanceID]; + const uint materialID = instance.materialID; + const mat4 model = instances.length() <= 0 ? skinned : (instance.model * skinned); + + outId = ivec4(drawID, instanceID, materialID, PushConstant.pass); + outColor = instance.color; outPosition = vec3(model * vec4(inPos.xyz, 1.0)); outNormal = vec3(model * vec4(inNormal.xyz, 0.0)); outNormal = normalize(outNormal); diff --git a/bin/data/shaders/graph/cull.comp.glsl b/bin/data/shaders/graph/cull.comp.glsl new file mode 100644 index 00000000..65b2d94c --- /dev/null +++ b/bin/data/shaders/graph/cull.comp.glsl @@ -0,0 +1,267 @@ +#version 450 +#pragma shader_stage(compute) + +#extension GL_EXT_nonuniform_qualifier : enable + +layout (constant_id = 0) const uint PASSES = 6; +layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint passes; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (std140, binding = 1) buffer DrawCommands { + DrawCommand drawCommands[]; +}; + +layout (std140, binding = 2) buffer Instances { + Instance instances[]; +}; + +struct Frustum { + vec4 planes[6]; +}; + +float inside( vec3 v, vec3 min, vec3 max ) { + vec3 s = step(min, v) - step(max, v); + return s.x * s.y * s.z; +} +/* + T f = 1 / tan( fov / 2 ); + return pod::Matrix4t({ + f / raidou, 0, 0, 0, + 0, -f, 0, 0, + 0, 0, 0, 1, + 0, 0, znear, 0 + }); +*/ + +vec4 normalizePlane( vec4 p ) { + return p / length(p.xyz); +} + +bool frustumCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = false; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { + // return if our camera position is inside the AABB + vec3 camPos = vec3( inverse(camera.viewport[pass].view)[3] ); + if ( instance.bounds.min.x <= camPos.x && camPos.x <= instance.bounds.max.x && instance.bounds.min.y <= camPos.y && camPos.y <= instance.bounds.max.y && instance.bounds.min.z <= camPos.z && camPos.z <= instance.bounds.max.z ) return true; + // sphere based one, source of this block uses reverse infinite Z, but would be nice if it used AABB + #if 0 + vec3 min = vec3(camera.viewport[pass].view * instance.model * vec4(instance.bounds.min, 1)); + vec3 max = vec3(camera.viewport[pass].view * instance.model * vec4(instance.bounds.max, 1)); + + vec3 center = (max + min) * 0.5; + vec3 extent = (max - min) * 0.5; + float radius = length(extent); + + mat4 projectionT = transpose(camera.viewport[pass].projection); + vec4 frustumX = normalizePlane(projectionT[3] + projectionT[0]); // x + w < 0 + vec4 frustumY = normalizePlane(projectionT[3] + projectionT[1]); // y + w < 0 + vec4 frustum = vec4( frustumX.x, frustumX.z, frustumY.y, frustumY.z ); + + visible = visible && center.z * frustum[1] - abs(center.x) * frustum[0] > -radius; + visible = visible && center.z * frustum[3] - abs(center.y) * frustum[2] > -radius; + // optimized version of the below blocks + #elif 1 + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec3 min = vec3(mat * vec4(instance.bounds.min, 1)); + vec3 max = vec3(mat * vec4(instance.bounds.max, 1)); + + vec3 center = (max + min) * 0.5; + vec3 extent = (max - min) * 0.5; + vec4 planes[6]; { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + for ( uint p = 0; p < 6; ++p ) { + if ( dot(center + extent * sign(planes[p].xyz), planes[p].xyz ) > -planes[p].w ) return true; + } + // transforms each corner into clip space + // an AABB is not visible if a plane has all 8 corners outside of it + #elif 0 + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec4 corners[9] = { + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + + vec4( (instance.bounds.max + instance.bounds.min) * 0.5, 1.0 ), + }; + for ( uint p = 0; p < 9; ++p ) { + vec4 t = mat * corners[p]; + if ( -t.w <= t.x && t.x <= t.w && -t.w <= t.y && t.y <= t.w ) return true; + } + // "optimized" version of the next block, compares bounds to each plane + // an AABB is not visible if a plane has all 8 corners outside of it + #elif 0 + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec4 planes[6]; { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + for ( uint p = 0; p < 6; ++p ) { + float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x) + + max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y) + + max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z); + if ( d > -planes[p].w ) return true; + } + #else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec4 corners[9] = { + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + + vec4( (instance.bounds.max + instance.bounds.min) * 0.5, 1.0 ), + }; + vec4 planes[6]; { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + for ( uint p = 0; p < 9; ++p ) corners[p] = mat * corners[p]; + for ( uint p = 0; p < 6; ++p ) { + for ( uint q = 0; q < 9; ++q ) { + if ( dot( corners[q], planes[p] ) > 0 ) return true; + } + return false; + } +#endif + } + return visible; +} + +void main() { + const uint gID = gl_GlobalInvocationID.x; + if ( !(0 <= gID && gID < drawCommands.length()) ) return; + drawCommands[gID].instances = frustumCull( gID ) ? 1 : 0; +} + + +/* + Frustum frustum; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + frustum.planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + frustum.planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + frustum.planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + frustum.planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + frustum.planes[i*2+j]*= length(frustum.planes[i*2+j].xyz); + } + for ( uint i = 0; i < 6; ++i ) { + vec4 plane = frustum.planes[i]; + float d = dot(instance.bounds.center, plane.xyz); + float r = dot(instance.bounds.extent, abs(plane.xyz)); + bool inside = d + r > -plane.w; + if ( !inside ) return 0; + } + return true; +*/ +/* + vec4 plane; + vec4 center = vec4( (max + min) * 0.5, 1 ); + vec4 extent = vec4( (max - min) * 0.5, 1 ); + center = mat * center; + extent = mat * extent; + center.xyz /= center.w; + extent.xyz /= extent.w; + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][0]; // left + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][0]; // right + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][1]; // bottom + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][1]; // top + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][2]; // near + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][2]; // far + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + +*/ +/* + for ( uint p = 0; p < 8; ++p ) { + vec4 t = corners[p]; + float w = abs(t.w); + visible = -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && 0 <= t.z && t.z <= w; // && -w <= t.z && t.z <= w; + } +*/ +/* +mat4 convert( mat4 proj ) { + float f = -proj[1][1]; + float raidou = f / proj[0][0]; + float zNear = proj[3][2]; + float zFar = 32; + + float range = zNear - zFar; + + float Sx = f * raidou; + float Sy = f; + float Sz = (-zNear - zFar) / range; + float Pz = 2 * zFar * zNear / range; + + mat4 new = mat4(1.0); + new[0][0] = Sx; + new[1][1] = -Sy; + new[2][2] = Sz; + new[3][2] = Pz; + new[2][3] = 1; + return new; +} +*/ \ No newline at end of file diff --git a/bin/data/shaders/graph/depth.frag.glsl b/bin/data/shaders/graph/depth.frag.glsl new file mode 100644 index 00000000..cefc25e5 --- /dev/null +++ b/bin/data/shaders/graph/depth.frag.glsl @@ -0,0 +1,58 @@ +#version 450 +#pragma shader_stage(fragment) + +#extension GL_EXT_nonuniform_qualifier : enable + +#define CUBEMAPS 1 +// #define MAX_TEXTURES TEXTURES +#define MAX_TEXTURES textures.length() +layout (constant_id = 0) const uint TEXTURES = 1; + +#include "../common/macros.h" +#include "../common/structs.h" + +layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 1) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 2) readonly buffer Textures { + Texture textures[]; +}; + +#include "../common/functions.h" + +layout (location = 0) in vec2 inUv; +layout (location = 1) in vec2 inSt; +layout (location = 2) in vec4 inColor; +layout (location = 3) in vec3 inNormal; +layout (location = 4) in mat3 inTBN; +layout (location = 7) in vec3 inPosition; +layout (location = 8) flat in ivec4 inId; + +void main() { + const uint drawID = uint(inId.x); + const uint instanceID = uint(inId.y); + const uint materialID = uint(inId.z); + const float mip = mipLevel(inUv.xy); + const vec2 uv = wrap(inUv.xy); + vec4 A = vec4(0, 0, 0, 0); + + const Material material = materials[materialID]; + // sample albedo + if ( !validTextureIndex( material.indexAlbedo ) ) discard; { + const Texture t = textures[material.indexAlbedo]; + 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; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + // if ( A.a < 1 - 0.00001 ) discard; + } +} \ No newline at end of file diff --git a/bin/data/shaders/gltf/instanced.vert.glsl b/bin/data/shaders/graph/instanced.vert.glsl similarity index 100% rename from bin/data/shaders/gltf/instanced.vert.glsl rename to bin/data/shaders/graph/instanced.vert.glsl diff --git a/bin/data/shaders/gltf/skinned.instanced.vert.glsl b/bin/data/shaders/graph/skinned.instanced.vert.glsl similarity index 100% rename from bin/data/shaders/gltf/skinned.instanced.vert.glsl rename to bin/data/shaders/graph/skinned.instanced.vert.glsl diff --git a/bin/data/shaders/gltf/skinned.vert.glsl b/bin/data/shaders/graph/skinned.vert.glsl similarity index 100% rename from bin/data/shaders/gltf/skinned.vert.glsl rename to bin/data/shaders/graph/skinned.vert.glsl diff --git a/bin/data/shaders/gltf/voxelize.frag.glsl b/bin/data/shaders/graph/voxelize.frag.glsl similarity index 100% rename from bin/data/shaders/gltf/voxelize.frag.glsl rename to bin/data/shaders/graph/voxelize.frag.glsl diff --git a/bin/data/shaders/gltf/voxelize.frag.h b/bin/data/shaders/graph/voxelize.frag.h similarity index 83% rename from bin/data/shaders/gltf/voxelize.frag.h rename to bin/data/shaders/graph/voxelize.frag.h index c73e98a2..7a64a849 100644 --- a/bin/data/shaders/gltf/voxelize.frag.h +++ b/bin/data/shaders/graph/voxelize.frag.h @@ -49,7 +49,7 @@ layout (location = 1) out vec2 outNormals; #endif void main() { - const uint CASCADE = inId.z; + const uint CASCADE = inId.w; if ( CASCADES <= CASCADE ) discard; const vec3 P = inPosition.xzy * 0.5 + 0.5; if ( abs(P.x) > 1 || abs(P.y) > 1 || abs(P.z) > 1 ) discard; @@ -58,20 +58,19 @@ void main() { const vec3 N = inNormal; const vec2 uv = wrap(inUv.xy); const float mip = 0; // mipLevel(inUv.xy); - const int materialId = int(inId.y); - const Material material = materials[materialId]; + const uint drawID = int(inId.x); + const uint instanceID = int(inId.y); + const uint materialID = int(inId.z); + Material material = materials[materialID]; const float M = material.factorMetallic; const float R = material.factorRoughness; const float AO = material.factorOcclusion; // sample albedo - const bool useAtlas = validTextureIndex( material.indexAtlas ); - Texture textureAtlas; - 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 ); + const Texture t = textures[material.indexAlbedo]; + 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; @@ -107,7 +106,7 @@ void main() { imageStore(voxelDepth[CASCADE], uvw, vec4(inDepth, 0, 0, 0)); #endif - imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(inId.w+1, inId.y+1), 0, 0)); + imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(drawID + 1, instanceID + 1), 0, 0)); imageStore(voxelNormal[CASCADE], uvw, vec4(encodeNormals( normalize( N ) ), 0, 0)); #if BLEND // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA diff --git a/bin/data/shaders/gltf/voxelize.geom.glsl b/bin/data/shaders/graph/voxelize.geom.glsl similarity index 95% rename from bin/data/shaders/gltf/voxelize.geom.glsl rename to bin/data/shaders/graph/voxelize.geom.glsl index 24bf0379..77ad232a 100644 --- a/bin/data/shaders/gltf/voxelize.geom.glsl +++ b/bin/data/shaders/graph/voxelize.geom.glsl @@ -47,7 +47,7 @@ void main(){ A = N.z > N[A] ? 2 : A; #endif - const uint CASCADE = inId[0].z; + const uint CASCADE = inId[0].w; vec3 P[3] = { vec3( ubo.voxel * vec4( inPosition[0], 1 ) ) / cascadePower(CASCADE), vec3( ubo.voxel * vec4( inPosition[1], 1 ) ) / cascadePower(CASCADE), diff --git a/client/client/ext.cpp b/client/client/ext.cpp index 320e8089..f301f31e 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -90,6 +90,11 @@ void client::initialize() { client::window.setMousePosition(client::window.getSize()/2); } }); + uf::hooks.addHook( "window:Mouse.Lock", [&](){ + if ( client::window.hasFocus() ) { + client::window.setMousePosition(client::window.getSize()/2); + } + }); uf::hooks.addHook( "window:Closed", [&]( ext::json::Value& json ){ client::ready = false; } ); diff --git a/client/main.cpp b/client/main.cpp index 4d305d72..0faedcdf 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -58,46 +58,6 @@ 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/config.h b/engine/inc/uf/config.h index 50aeae04..ea8a2c8c 100644 --- a/engine/inc/uf/config.h +++ b/engine/inc/uf/config.h @@ -20,8 +20,12 @@ #if defined(__CYGWIN__) #define to_string(var) string(var) #endif - #define _WIN32_WINNT 0x0600 - #define WINVER 0x0600 + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 + #endif + #ifndef WINVER + #define WINVER 0x0600 + #endif #define UF_IO_ROOT "./data/" #elif defined(linux) || defined(__linux) diff --git a/engine/inc/uf/engine/graph/graph.h b/engine/inc/uf/engine/graph/graph.h index 61fe6902..3fbd19f9 100644 --- a/engine/inc/uf/engine/graph/graph.h +++ b/engine/inc/uf/engine/graph/graph.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include @@ -23,28 +23,27 @@ namespace pod { uf::Serializer metadata; pod::Node root; - uf::stl::vector nodes; // node's position corresponds to its drawCommand and instance + uf::stl::vector nodes; // // Render information - uf::stl::vector> drawCommands; // draws to dispatch, one per primitive, gets copied per rendermode + uf::stl::vector instances; // + uf::stl::vector primitives; // + uf::stl::vector drawCommands; // + uf::stl::vector meshes; // - uf::stl::vector instances; // instance data to use, gets copied per rendermode + uf::stl::vector images; // + uf::stl::vector materials; // + uf::stl::vector textures; // - 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 + uf::stl::vector texture2Ds; // + uf::stl::vector samplers; // // Lighting information uf::stl::unordered_map lights; // Animations - uf::stl::vector skins; - uf::stl::unordered_map animations; + uf::stl::vector skins; + uf::stl::vector animations; // Animation queue std::queue sequence; struct { @@ -61,15 +60,55 @@ namespace pod { // 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; + template + struct KeyMap { + public: + uf::stl::vector keys; + uf::stl::unordered_map map; - uf::stl::fifo_map texture2Ds; - uf::stl::fifo_map samplers; - }; + T& operator[]( const Key& key ) { + if ( map.count( key ) == 0 ) keys.emplace_back( key ); + return map[key]; + } + + void reserve( size_t i ) { + keys.reserve(i); + map.reserve(i); + } + }; + + KeyMap instances; + KeyMap> primitives; + KeyMap> drawCommands; + KeyMap meshes; + + KeyMap images; + KeyMap materials; + KeyMap textures; + KeyMap samplers; + uf::stl::vector lights; + KeyMap skins; + KeyMap animations; + + // maps without direct analogues + KeyMap atlases; + KeyMap joints; + KeyMap texture2Ds; + KeyMap entities; + + uf::stl::vector shadow2Ds; + uf::stl::vector shadowCubes; + + struct Buffer { + uf::renderer::Buffer camera; + uf::renderer::Buffer drawCommands; + uf::renderer::Buffer instance; + uf::renderer::Buffer joint; + uf::renderer::Buffer material; + uf::renderer::Buffer texture; + uf::renderer::Buffer light; + } buffers; + } storage; }; } @@ -100,6 +139,11 @@ namespace uf { void UF_API update( pod::Graph&, pod::Node& ); void UF_API destroy( pod::Graph& ); + + void UF_API initialize(); + void UF_API tick(); + void UF_API render(); + void UF_API destroy(); 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& ); diff --git a/engine/inc/uf/engine/graph/pod.inl b/engine/inc/uf/engine/graph/pod.inl index be76a83a..5d6d14ba 100644 --- a/engine/inc/uf/engine/graph/pod.inl +++ b/engine/inc/uf/engine/graph/pod.inl @@ -4,30 +4,36 @@ namespace pod { 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; + // extra data + uint32_t padding1 = 0; // + uint32_t padding2 = 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; + alignas(4) uint32_t primitiveID = 0; + alignas(4) uint32_t meshID = 0; + alignas(4) uint32_t objectID = 0; - struct { - pod::Vector3f min = {}; + struct Bounds { + pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; alignas(4) float padding1 = 0; - pod::Vector3f max = {}; + pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; alignas(4) float padding2 = 0; } bounds; }; + struct Primitive { + pod::DrawCommand drawCommand; + pod::Instance instance; + }; + struct UF_API Material { pod::Vector4f colorBase = { 0, 0, 0, 0 }; pod::Vector4f colorEmissive = { 0, 0, 0, 0 }; @@ -72,11 +78,6 @@ namespace pod { float depthBias = 0; }; // - struct UF_API Mesh { - uf::stl::vector drawCommands; - uf::Mesh mesh; - }; - // struct UF_API Skin { uf::stl::string name = ""; diff --git a/engine/inc/uf/ext/bullet/bullet.h b/engine/inc/uf/ext/bullet/bullet.h index f61ba891..9e6987a7 100644 --- a/engine/inc/uf/ext/bullet/bullet.h +++ b/engine/inc/uf/ext/bullet/bullet.h @@ -58,6 +58,12 @@ namespace ext { // collider for mesh (static or dynamic) pod::Bullet& create( uf::Object&, const uf::Mesh&, bool ); + pod::Bullet& create( uf::Object&, const void* verticesPointer, size_t verticesCount, size_t verticesStride, const void* indicesPointer, size_t indicesCount, size_t indicesStride, bool ); + + template + pod::Bullet& create( uf::Object& o, const uf::Mesh_T& m, bool b ) { + return create( o, m.vertices.data() + offsetof(T, position), m.vertices.size(), sizeof(T), m.indices.data(), m.indices.size(), sizeof(U), b ); + } // collider for boundingbox pod::Bullet& UF_API create( uf::Object&, const pod::Vector3f&, float ); // collider for capsule diff --git a/engine/inc/uf/ext/opengl/opengl.h b/engine/inc/uf/ext/opengl/opengl.h index e7167673..599deac2 100644 --- a/engine/inc/uf/ext/opengl/opengl.h +++ b/engine/inc/uf/ext/opengl/opengl.h @@ -37,9 +37,9 @@ namespace ext { extern UF_API bool multiview; extern UF_API bool vsync; extern UF_API bool hdr; - extern UF_API bool frustrumCull; extern UF_API bool vxgi; extern UF_API bool deferredSampling; + extern UF_API bool culling; } namespace formats { diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index e4084301..9e371828 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -19,11 +19,11 @@ namespace ext { VkDeviceSize alignment = 0; void* mapped = nullptr; - VkBufferUsageFlags usage; - VkMemoryPropertyFlags memoryProperties; + VkBufferUsageFlags usage = 0; + VkMemoryPropertyFlags memoryProperties = 0; - VmaAllocation allocation; - VmaAllocationInfo allocationInfo; + VmaAllocation allocation = {}; + VmaAllocationInfo allocationInfo = {}; void* map( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 ); void unmap(); @@ -49,7 +49,7 @@ namespace ext { }; struct UF_API Buffers { uf::stl::vector buffers; - Device* device; + Device* device = NULL; // ~Buffers(); // diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index 0ca87ccc..9b06a638 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -16,18 +16,19 @@ namespace ext { Device* device = NULL; - VkPipeline pipeline; - VkPipelineLayout pipelineLayout; - VkDescriptorSetLayout descriptorSetLayout; - VkDescriptorPool descriptorPool; - VkDescriptorSet descriptorSet; - GraphicDescriptor descriptor; + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + GraphicDescriptor descriptor = {}; struct { uf::Serializer json; uf::stl::string type = ""; bool process = true; + bool rebuild = false; } metadata; void initialize( const Graphic& graphic ); @@ -43,7 +44,7 @@ namespace ext { struct UF_API Material { bool aliased = false; - Device* device; + Device* device = NULL; uf::stl::vector samplers; uf::stl::vector textures; @@ -51,6 +52,7 @@ namespace ext { struct Metadata { uf::Serializer json; + bool autoInitializeUniforms = true; uf::stl::unordered_map shaders; } metadata; @@ -68,30 +70,17 @@ namespace ext { }; struct UF_API Graphic : public Buffers { - GraphicDescriptor descriptor; + GraphicDescriptor descriptor = {}; bool initialized = false; bool process = true; - Material material; + Material material = {}; uf::stl::unordered_map pipelines; struct { 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(); @@ -101,6 +90,7 @@ namespace ext { // void initializeAttributes( const uf::Mesh::Attributes& mesh ); void initializeMesh( uf::Mesh& mesh, bool buffer = true ); + void updateMesh( uf::Mesh& mesh ); bool hasPipeline( const GraphicDescriptor& descriptor ) const; void initializePipeline(); diff --git a/engine/inc/uf/ext/vulkan/rendermode.h b/engine/inc/uf/ext/vulkan/rendermode.h index b87f4992..15de6ad5 100644 --- a/engine/inc/uf/ext/vulkan/rendermode.h +++ b/engine/inc/uf/ext/vulkan/rendermode.h @@ -12,24 +12,23 @@ namespace ext { bool execute = false; bool executed = false; bool rebuild = false; + uint32_t width = 0; uint32_t height = 0; + struct { uf::Serializer json; uf::stl::string name = ""; uf::stl::string type = ""; uf::stl::string target = ""; + uf::stl::string pipeline = ""; + uf::stl::vector pipelines; uf::stl::vector outputs; uint8_t subpasses = 1; uint8_t samples = 1; uint8_t eyes = 1; - - size_t lightBufferIndex = 0; - size_t materialBufferIndex = 0; - size_t textureBufferIndex = 0; - size_t drawCallBufferIndex = 0; } metadata; Device* device = VK_NULL_HANDLE; diff --git a/engine/inc/uf/ext/vulkan/rendermodes/compute.h b/engine/inc/uf/ext/vulkan/rendermodes/compute.h index 2b27bb72..c3b0b328 100644 --- a/engine/inc/uf/ext/vulkan/rendermodes/compute.h +++ b/engine/inc/uf/ext/vulkan/rendermodes/compute.h @@ -7,7 +7,6 @@ namespace ext { namespace vulkan { struct UF_API ComputeRenderMode : public ext::vulkan::RenderMode { ext::vulkan::Graphic blitter, compute; - pod::Vector2ui dispatchSize = { 32, 32 }; // RAII virtual const uf::stl::string getType() const; diff --git a/engine/inc/uf/ext/vulkan/shader.h b/engine/inc/uf/ext/vulkan/shader.h index 4c4a8a36..b57cb59f 100644 --- a/engine/inc/uf/ext/vulkan/shader.h +++ b/engine/inc/uf/ext/vulkan/shader.h @@ -26,14 +26,15 @@ namespace ext { uf::stl::string filename = ""; VkShaderModule module = VK_NULL_HANDLE; - VkPipelineShaderStageCreateInfo descriptor; + VkPipelineShaderStageCreateInfo descriptor = {}; uf::stl::vector descriptorSetLayoutBindings; uf::stl::vector specializationMapEntries; - VkSpecializationInfo specializationInfo; + VkSpecializationInfo specializationInfo = {}; struct Metadata { uf::Serializer json; + bool autoInitializeUniforms = true; uf::stl::string pipeline = ""; uf::stl::string type = ""; diff --git a/engine/inc/uf/ext/vulkan/swapchain.h b/engine/inc/uf/ext/vulkan/swapchain.h index 9e35b9cd..1cf721ca 100644 --- a/engine/inc/uf/ext/vulkan/swapchain.h +++ b/engine/inc/uf/ext/vulkan/swapchain.h @@ -11,7 +11,7 @@ namespace ext { VkSwapchainKHR swapChain = VK_NULL_HANDLE; bool initialized = false; - uint32_t buffers; + uint32_t buffers = {}; VkSemaphore presentCompleteSemaphore; VkSemaphore renderCompleteSemaphore; diff --git a/engine/inc/uf/ext/vulkan/texture.h b/engine/inc/uf/ext/vulkan/texture.h index 701a6181..1aa3439b 100644 --- a/engine/inc/uf/ext/vulkan/texture.h +++ b/engine/inc/uf/ext/vulkan/texture.h @@ -10,7 +10,7 @@ namespace ext { struct UF_API Sampler { Device* device = NULL; - VkSampler sampler; + VkSampler sampler = VK_NULL_HANDLE; struct Descriptor { struct { VkFilter min = VK_FILTER_LINEAR; @@ -34,7 +34,7 @@ namespace ext { float max = 16.0f; } anisotropy; VkDescriptorImageInfo info; - } descriptor; + } descriptor = {}; void initialize( Device& device ); void destroy(); @@ -46,21 +46,24 @@ namespace ext { struct UF_API Texture { Device* device = nullptr; - VkImage image; - VkImageView view; + VkImage image = VK_NULL_HANDLE; + VkImageView view = VK_NULL_HANDLE; VkImageType type = enums::Image::TYPE_2D; VkImageViewType viewType = enums::Image::VIEW_TYPE_2D; VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - VkDeviceMemory deviceMemory; - VkDescriptorImageInfo descriptor; - VkFormat format = enums::Format::R8G8B8A8_UNORM;; + VkDeviceMemory deviceMemory = VK_NULL_HANDLE; + VkDescriptorImageInfo descriptor = {}; + VkFormat format = enums::Format::R8G8B8A8_UNORM; - Sampler sampler; + Sampler sampler = {}; - VmaAllocation allocation; - VmaAllocationInfo allocationInfo; + VmaAllocation allocation = {}; + VmaAllocationInfo allocationInfo = {}; - uint32_t width, height, depth, layers; + uint32_t width = 0; + uint32_t height = 0; + uint32_t depth = 0; + uint32_t layers = 0; uint32_t mips = 1; // RAII void initialize( Device& device, size_t width, size_t height, size_t depth = 1, size_t layers = 1 ); diff --git a/engine/inc/uf/ext/vulkan/vulkan.h b/engine/inc/uf/ext/vulkan/vulkan.h index 7e2d0f49..950505db 100644 --- a/engine/inc/uf/ext/vulkan/vulkan.h +++ b/engine/inc/uf/ext/vulkan/vulkan.h @@ -64,9 +64,9 @@ namespace ext { extern UF_API bool multiview; extern UF_API bool vsync; extern UF_API bool hdr; - extern UF_API bool frustrumCull; extern UF_API bool vxgi; extern UF_API bool deferredSampling; + extern UF_API bool culling; } namespace formats { diff --git a/engine/inc/uf/macros.h b/engine/inc/uf/macros.h index 4f2084a1..18aa8561 100644 --- a/engine/inc/uf/macros.h +++ b/engine/inc/uf/macros.h @@ -37,7 +37,7 @@ #define UF_MSG_ERROR(X) UF_MSG(X, " ERROR "); #if UF_NO_EXCEPTIONS - #define UF_EXCEPTION(X) { UF_MSG_ERROR(X); } + #define UF_EXCEPTION(X) { UF_MSG_ERROR(X); std::abort(); } #else #define UF_EXCEPTION(X) {\ uf::stl::stringstream str;\ diff --git a/engine/inc/uf/utils/image/image.h b/engine/inc/uf/utils/image/image.h index f4fd1d6b..21f68393 100644 --- a/engine/inc/uf/utils/image/image.h +++ b/engine/inc/uf/utils/image/image.h @@ -21,13 +21,14 @@ namespace uf { std::size_t m_format; public: // C-tor + /* Image(); // Default Image( const Image::vec2_t& size ); // Just Size Image( Image&& move ); // Move pixels Image( const Image& copy ); // Copy pixels Image( Image::container_t&& move, const Image::vec2_t& size ); // Move from vector of pixels Image( const Image::container_t& copy, const Image::vec2_t& size ); // Copy from vector of pixels - + */ bool open( const uf::stl::string& filename, bool = true ); // from file void open( const std::istream& stream ); // from stream void move( Image::container_t&& move, const Image::vec2_t& size ); // move from vector of pixels diff --git a/engine/inc/uf/utils/math/matrix/pod.inl b/engine/inc/uf/utils/math/matrix/pod.inl index 8a162b7c..b3f2364b 100644 --- a/engine/inc/uf/utils/math/matrix/pod.inl +++ b/engine/inc/uf/utils/math/matrix/pod.inl @@ -570,15 +570,15 @@ pod::Matrix4t /*UF_API*/ uf::matrix::perspective( T fov, T raidou, T znear, T }); #elif UF_USE_VULKAN return pod::Matrix4t({ - f / raidou, 0.0f, 0.0f, 0.0f, - 0.0f, -f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, znear, 0.0f + f / raidou, 0, 0, 0, + 0, -f, 0, 0, + 0, 0, 0, 1, + 0, 0, znear, 0 }); #endif } else { T range = znear - zfar; - T f = tanf( static_cast(0.5) * fov ); + T f = tan( static_cast(0.5) * fov ); T Sx = static_cast(1) / (f * raidou); T Sy = static_cast(1) / f; diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index ede6a46d..0ec5bd35 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -131,6 +131,11 @@ namespace uf { template T& /*UF_API*/ divide( T& left, const typename T::type_t& scalar ); // Divides this vector by a scalar template T& /*UF_API*/ negate( T& vector ); // Flip sign of all components template T& /*UF_API*/ normalize( T& vector ); // Normalizes a vector + template T /*UF_API*/ min( const T& left, const T& right ); // + template T /*UF_API*/ max( const T& left, const T& right ); // + template T /*UF_API*/ ceil( const T& vector ); // + template T /*UF_API*/ floor( const T& vector ); // + template T /*UF_API*/ round( const T& vector ); // // Complex arithmetic template typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // Compute the dot product between two vectors template pod::Angle /*UF_API*/ angle( const T& a, const T& b ); // Compute the angle between two vectors diff --git a/engine/inc/uf/utils/math/vector/pod.inl b/engine/inc/uf/utils/math/vector/pod.inl index 26d7231e..4423c74b 100644 --- a/engine/inc/uf/utils/math/vector/pod.inl +++ b/engine/inc/uf/utils/math/vector/pod.inl @@ -266,6 +266,36 @@ T& /*UF_API*/ uf::vector::normalize( T& vector ) { if ( norm == 0 ) return vector; return uf::vector::divide(vector, norm); } +template // +T /*UF_API*/ uf::vector::min( const T& left, const T& right ) { + T res = left; + for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::min( left[i], right[i] ); + return res; +} +template // +T /*UF_API*/ uf::vector::max( const T& left, const T& right ) { + T res; + for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::max( left[i], right[i] ); + return res; +} +template // +T /*UF_API*/ uf::vector::ceil( const T& vector ) { + T res; + for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::ceil( vector[i] ); + return res; +} +template // +T /*UF_API*/ uf::vector::floor( const T& vector ) { + T res; + for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::floor( vector[i] ); + return res; +} +template // +T /*UF_API*/ uf::vector::round( const T& vector ) { + T res; + for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::round( vector[i] ); + return res; +} // Complex arithmetic template // Compute the dot product between two vectors typename T::type_t /*UF_API*/ uf::vector::dot( const T& left, const T& right ) { diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index 03edcd96..527b842c 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -30,9 +30,6 @@ namespace ext { uf::stl::string name = ""; 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 && @@ -56,6 +53,10 @@ namespace uf { ext::RENDERER::AttributeDescriptor descriptor; int32_t buffer = -1; size_t offset = 0; + + size_t stride = 0; + size_t length = 0; + void* pointer = NULL; }; struct Input { uf::stl::vector attributes; @@ -64,16 +65,19 @@ namespace uf { 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 - - struct Settings { - bool interleaved = false; - } settings; } vertex, index, instance, indirect; + /* + struct Bounds { + pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; + pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; + } bounds; + */ uf::stl::vector buffers; protected: void _destroy( uf::Mesh::Input& input ); void _bind( bool interleaved = uf::Mesh::defaultInterleaved ); void _updateDescriptor( uf::Mesh::Input& input ); + uf::Mesh::Attribute _remapAttribute( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute, size_t i = 0 ) const; 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; @@ -81,10 +85,10 @@ namespace uf { 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 ); + void _insertVs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ); - template inline bool _hasV( const uf::Mesh::Input& input ) const { return _hasV( input, T::descriptors ); } + template inline bool _hasV( const uf::Mesh::Input& input ) const { return _hasV( input, T::descriptor ); } 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() ); } @@ -93,8 +97,8 @@ namespace uf { 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 ); + void _insertIs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ); 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 ); } @@ -105,6 +109,8 @@ namespace uf { uf::Mesh interleave() const; void updateDescriptor(); + + void bind( const uf::Mesh& ); void insert( const uf::Mesh& ); void generateIndices(); @@ -121,10 +127,11 @@ namespace uf { 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 insertVertices( const uf::Mesh& mesh ) { return _insertVs( vertex, mesh, mesh.vertex ); } inline void updateVertexDescriptor() { return _updateDescriptor( vertex ); } + inline uf::Mesh::Attribute remapVertexAttribute( const uf::Mesh::Attribute& attribute, size_t i = 0 ) const { return _remapAttribute( vertex, attribute, i ); } - template inline bool hasVertex() const { return _hasV( vertex, T::descriptors ); } + template inline bool hasVertex() const { return _hasV( vertex, T::descriptor ); } 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() ); } @@ -134,8 +141,9 @@ namespace uf { 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 insertIndices( const uf::Mesh& mesh ) { return _insertIs( index, mesh, mesh.index ); } inline void updateIndexDescriptor() { return _updateDescriptor( index ); } + inline uf::Mesh::Attribute remapIndexAttribute( const uf::Mesh::Attribute& attribute, size_t i = 0 ) const { return _remapAttribute( index, attribute, i ); } 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 ); } @@ -148,10 +156,10 @@ namespace uf { 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 insertInstances( const uf::Mesh& mesh ) { return _insertVs( instance, mesh, mesh.instance ); } inline void updateInstanceDescriptor() { return _updateDescriptor( instance ); } - template inline bool hasInstance() const { return _hasV( instance, T::descriptors ); } + template inline bool hasInstance() const { return _hasV( instance, T::descriptor ); } 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() ); } @@ -161,7 +169,7 @@ namespace uf { 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 insertIndirects( const uf::Mesh& mesh ) { return _insertIs( 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 ); } @@ -175,6 +183,15 @@ namespace uf { _bind( interleave ); } }; + + template + struct UF_API Mesh_T { + typedef T vertex_t; + typedef U index_t; + + uf::stl::vector vertices; + uf::stl::vector indices; + }; } namespace ext { @@ -195,6 +212,7 @@ namespace ext { struct { uf::Mesh::Input vertex, index, instance, indirect; size_t bufferOffset = 0; + pod::Vector3ui dispatch = { 0, 0, 0 }; } inputs; ext::RENDERER::enums::PrimitiveTopology::type_t topology = ext::RENDERER::enums::PrimitiveTopology::TRIANGLE_LIST; diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index 7b8f11e2..da17b9a5 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -176,8 +176,8 @@ uf::stl::string uf::Asset::load( const uf::stl::string& uri, const uf::stl::stri metadata[uri]["flags"]["ATLAS"] = false; metadata[uri]["flags"]["SEPARATE"] = true; #elif UF_GRAPH_INDIRECT_DRAW - metadata[uri]["flags"]["ATLAS"] = false; - metadata[uri]["flags"]["SEPARATE"] = false; + // metadata[uri]["flags"]["ATLAS"] = false; + // metadata[uri]["flags"]["SEPARATE"] = false; #endif asset = uf::graph::load( filename, metadata[uri] ); uf::graph::process( asset ); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 34056040..00aff8f2 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #if UF_ENV_DREAMCAST @@ -14,6 +15,10 @@ #define UF_GRAPH_LOAD_MULTITHREAD 1 #endif +namespace { + bool newGraphAdded = true; +} + pod::Graph::Storage uf::graph::storage; UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Base, @@ -52,17 +57,18 @@ namespace { } // standard pipeline + uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/base.vert.spv"); + uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as(""); + uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/base.frag.spv"); { - uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/gltf/base.vert.spv"); - uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as(""); - uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/gltf/base.frag.spv"); + graphic.material.metadata.autoInitializeUniforms = false; if ( uf::renderer::settings::experimental::deferredSampling ) { fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); } { if ( !graph.metadata["flags"]["SEPARATE"].as() ) { - vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as() ? "/gltf/skinned.instanced.vert.spv" : "/gltf/instanced.vert.spv"; - } else if ( graph.metadata["flags"]["SKINNED"].as() ) vertexShaderFilename = "/gltf/skinned.vert.spv"; + vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as() ? "/graph/skinned.instanced.vert.spv" : "/graph/instanced.vert.spv"; + } else if ( graph.metadata["flags"]["SKINNED"].as() ) vertexShaderFilename = "/graph/skinned.vert.spv"; vertexShaderFilename = entity.grabURI( vertexShaderFilename, root ); graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX); } @@ -71,6 +77,7 @@ namespace { graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT); } #if UF_USE_VULKAN + graphic.material.metadata.autoInitializeUniforms = true; if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { geometryShaderFilename = entity.grabURI( geometryShaderFilename, root ); graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY); @@ -79,37 +86,122 @@ namespace { uint32_t maxPasses = 6; auto& shader = graphic.material.getShader("vertex"); - uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; - ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ - uf::stl::string name = sc["name"].as(); - if ( name == "PASSES" ) sc["value"] = (specializationConstants[i] = maxPasses); - }); + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses); + } + + uf::renderer::Buffer* indirect = NULL; + for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.drawCommands ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); } { - uint32_t maxTextures = texture2Ds; + uint32_t maxTextures = graph.textures.size(); // texture2Ds; auto& shader = graphic.material.getShader("fragment"); - uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; - ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ - uf::stl::string name = sc["name"].as(); - if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures); - }); - - ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){ - if ( t["name"].as() != "samplerTextures" ) return; - size_t binding = t["binding"].as(); + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; for ( auto& layout : shader.descriptorSetLayoutBindings ) { - if ( layout.binding == binding ) layout.descriptorCount = maxTextures; + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures; } - }); + } + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); } #endif } + // culling pipeline + if ( uf::renderer::settings::experimental::culling ) { + graphic.material.metadata.autoInitializeUniforms = false; + uf::stl::string compShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/cull.comp.spv"); + { + compShaderFilename = entity.grabURI( compShaderFilename, root ); + graphic.material.attachShader(compShaderFilename, uf::renderer::enums::Shader::COMPUTE, "culling"); + } + graphic.descriptor.inputs.dispatch = { graphic.descriptor.inputs.indirect.count, 1, 1 }; + + auto& shader = graphic.material.getShader("compute", "culling"); + + uf::renderer::Buffer* indirect = NULL; + for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; + UF_ASSERT( indirect ); + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + shader.buffers.emplace_back().aliasBuffer( *indirect ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); + } + // depth only pipeline + #if UF_USE_VULKAN + { + graphic.material.metadata.autoInitializeUniforms = false; + uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/depth.frag.spv"); + { + graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "depth"); + } + { + fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); + graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "depth"); + } + { + uint32_t maxPasses = 6; + + auto& shader = graphic.material.getShader("vertex", "depth"); + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses); + } + + uf::renderer::Buffer* indirect = NULL; + for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.drawCommands ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); + } + { + uint32_t maxTextures = graph.textures.size(); // texture2Ds; + + auto& shader = graphic.material.getShader("fragment", "depth"); + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures; + } + } + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); + } + } // vxgi pipeline if ( uf::renderer::settings::experimental::vxgi ) { - uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/gltf/base.vert.spv"); - uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as("/gltf/voxelize.geom.spv"); - uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/gltf/voxelize.frag.spv"); + // graphic.material.metadata.json["shader"]["autoInitializeUniformBuffers"] = false; + graphic.material.metadata.autoInitializeUniforms = false; + uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/base.vert.spv"); + uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as("/graph/voxelize.geom.spv"); + uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/voxelize.frag.spv"); if ( uf::renderer::settings::experimental::deferredSampling ) { // fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); } @@ -117,7 +209,8 @@ namespace { fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vxgi"); } - #if UF_USE_VULKAN + // graphic.material.metadata.json["shader"]["autoInitializeUniformBuffers"] = true; + graphic.material.metadata.autoInitializeUniforms = true; if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { geometryShaderFilename = entity.grabURI( geometryShaderFilename, root ); graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "vxgi"); @@ -136,8 +229,26 @@ namespace { uint32_t maxCascades = texture3Ds / voxelTypes; auto& shader = graphic.material.getShader("fragment", "vxgi"); - uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures); + else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures; + else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades; + } + } + /* + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ uf::stl::string name = sc["name"].as(); if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures); @@ -156,9 +267,14 @@ namespace { else if ( name == "voxelDepth" ) layout.descriptorCount = maxCascades; } }); + */ + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); } - #endif } + #endif // graphic.process = true; } void initializeGraphics( pod::Graph& graph, uf::Object& entity ) { @@ -179,13 +295,8 @@ namespace { } } { - 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& s : graph.samplers ) { - graphic.material.samplers.emplace_back( uf::graph::storage.samplers[s] ); - } + for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[i] ); + for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[s] ); // bind scene's voxel texture if ( uf::renderer::settings::experimental::vxgi ) { auto& scene = uf::scene::getCurrentScene(); @@ -233,6 +344,20 @@ void uf::graph::process( uf::Object& entity ) { for ( auto index : graph.root.children ) process( graph, index, entity ); } void uf::graph::process( pod::Graph& graph ) { + // copy our local storage to global storage + { + for ( auto& name : graph.storage.atlases.keys ) uf::graph::storage.atlases[name] = graph.storage.atlases[name]; + for ( auto& name : graph.storage.images.keys ) uf::graph::storage.images[name] = graph.storage.images[name]; + for ( auto& name : graph.storage.primitives.keys ) uf::graph::storage.primitives[name] = graph.storage.primitives[name]; + for ( auto& name : graph.storage.meshes.keys ) uf::graph::storage.meshes[name] = graph.storage.meshes[name]; + for ( auto& name : graph.storage.joints.keys ) uf::graph::storage.joints[name] = graph.storage.joints[name]; + for ( auto& name : graph.storage.materials.keys ) uf::graph::storage.materials[name] = graph.storage.materials[name]; + for ( auto& name : graph.storage.textures.keys ) uf::graph::storage.textures[name] = graph.storage.textures[name]; + for ( auto& name : graph.storage.samplers.keys ) uf::graph::storage.samplers[name] = graph.storage.samplers[name]; + for ( auto& name : graph.storage.skins.keys ) uf::graph::storage.skins[name] = graph.storage.skins[name]; + for ( auto& name : graph.storage.animations.keys ) uf::graph::storage.animations[name] = graph.storage.animations[name]; + for ( auto& name : graph.storage.entities.keys ) uf::graph::storage.entities[name] = graph.storage.entities[name]; + } // if ( !graph.root.entity ) graph.root.entity = new uf::Object; @@ -241,480 +366,91 @@ void uf::graph::process( pod::Graph& graph ) { // add atlas // setup textures + uf::graph::storage.texture2Ds.reserve( uf::graph::storage.images.map.size() ); + for ( auto& keyName : graph.images ) { + auto& image = uf::graph::storage.images[keyName]; + auto& texture = uf::graph::storage.texture2Ds[keyName]; + if ( !texture.generated() ) texture.loadFromImage( image ); + } + // process nodes for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity ); - // setup meshes + // remap materials->texture IDs + for ( auto& name : graph.materials ) { + auto& material = uf::graph::storage.materials[name]; + auto& keys = uf::graph::storage.textures.keys; + int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness }; + for ( auto* pointer : IDs ) { + auto& ID = *pointer; + if ( !(0 <= ID && ID < graph.materials.size()) ) continue; + auto it = std::find( keys.begin(), keys.end(), graph.textures[ID] ); + UF_ASSERT( it != keys.end() ); + ID = it - keys.begin(); + } + } + // remap textures->images IDs + for ( auto& name : graph.textures ) { + auto& texture = uf::graph::storage.textures[name]; + auto& keys = uf::graph::storage.images.keys; + + if ( !(0 <= texture.index && texture.index < graph.textures.size()) ) continue; + auto it = std::find( keys.begin(), keys.end(), graph.images[texture.index] ); + UF_ASSERT( it != keys.end() ); + texture.index = it - keys.begin(); + } + // remap instance materials + for ( auto& name : graph.instances ) { + auto& instance = uf::graph::storage.instances[name]; + + if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue; + auto& keys = graph.storage.materials.keys; + auto it = std::find( keys.begin(), keys.end(), graph.materials[instance.materialID] ); + UF_ASSERT( it != keys.end() ); + instance.materialID = it - keys.begin(); + } + ::newGraphAdded = true; + + // setup combined mesh if requested if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { - initializeGraphics( graph, *graph.root.entity ); - } + graph.root.mesh = graph.meshes.size(); + auto keyName = graph.name + "/" + graph.root.name; + auto& mesh = uf::graph::storage.meshes[graph.meshes.emplace_back(keyName)]; + for ( auto& name : graph.meshes ) { + if ( name == keyName ) continue; - // 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]]; + auto& m = uf::graph::storage.meshes.map[name]; + mesh.bindIndirect(); + mesh.bind(); + mesh.insert( m ); } + // fix up draw command for combined mesh + { + auto& attribute = mesh.indirect.attributes.front(); + auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer]; + pod::DrawCommand* drawCommands = (pod::DrawCommand*) buffer.data(); - 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 + size_t totalIndices = 0; + size_t totalVertices = 0; + for ( auto i = 0; i < mesh.indirect.count; ++i ) { + auto& drawCommand = drawCommands[i]; + drawCommand.indexID = totalIndices; + drawCommand.vertexID = totalVertices; + + totalIndices += drawCommand.indices; + totalVertices += drawCommand.vertices; } } - }); -#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 - #define UF_GRAPH_DEFAULT_LIGHTMAP "./lightmap.min.png" -#else - #define UF_GRAPH_DEFAULT_LIGHTMAP "" -#endif - bool lightmapped = false; - const uf::stl::string defaultLightmap = UF_GRAPH_DEFAULT_LIGHTMAP; - // load lightmap, if requested - if ( defaultLightmap != "" || graph.metadata["lightmap"].is() ) { - // check if valid filename, if not it's a texture name - uf::stl::string f = uf::io::sanitize( graph.metadata["lightmap"].as(defaultLightmap), uf::io::directory( graph.name ) ); - if ( (lightmapped = uf::io::exists( f )) ) { - for ( auto& material : graph.materials ) { - material.storage.indexLightmap = graph.textures.size(); - } - - auto& texture = graph.textures.emplace_back(); - texture.name = "lightmap"; - texture.bind = true; - texture.storage.index = graph.images.size(); - texture.storage.sampler = -1; - texture.storage.remap = graph.images.size(); - texture.storage.blend = 0; - auto& image = graph.images.emplace_back(); - #if UF_USE_VULKAN - bool flip = false; - #elif UF_USE_OPENGL - bool flip = false; - #endif - image.open( f, flip ); - - graph.metadata["lightmap"] = texture.name; - graph.metadata["lightmapped"] = true; - - texture.texture.loadFromImage( image ); - - texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST; - texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; - } - // invalidate our ST's if we're in OpenGL - } - - // using an atlas texture will not bind other textures - if ( graph.metadata["flags"]["ATLAS"].as() && graph.atlas.generated() ) { - //UF_MSG_DEBUG( "Processing atlas..." ); - - auto& image = *graph.images.emplace(graph.images.begin(), graph.atlas.getAtlas()); - auto& texture = *graph.textures.emplace(graph.textures.begin()); - texture.name = "atlas"; - texture.bind = true; - texture.storage.index = 0; - texture.storage.sampler = 0; - texture.storage.remap = -1; - texture.storage.blend = 0; - - if ( graph.metadata["filter"].is() ) { - uf::stl::string filter = graph.metadata["filter"].as(); - if ( filter == "NEAREST" ) { - texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST; - texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; - } else if ( filter == "LINEAR" ) { - texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::LINEAR; - texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::LINEAR; - } - } - for ( auto& material : graph.materials ) { - if ( 0 <= material.storage.indexAlbedo ) ++material.storage.indexAlbedo; - if ( 0 <= material.storage.indexNormal ) ++material.storage.indexNormal; - if ( 0 <= material.storage.indexEmissive ) ++material.storage.indexEmissive; - if ( 0 <= material.storage.indexOcclusion ) ++material.storage.indexOcclusion; - if ( 0 <= material.storage.indexMetallicRoughness ) ++material.storage.indexMetallicRoughness; - material.storage.indexAtlas = texture.storage.index; - if ( 0 <= material.storage.indexLightmap ) ++material.storage.indexLightmap; - } - texture.texture.loadFromImage( image ); - - // remap texture slots - size_t textureSlot = 0; - for ( auto& texture : graph.textures ) { - texture.storage.index = -1; - if ( !texture.bind ) continue; - texture.storage.index = textureSlot++; - } - } else { - //UF_MSG_DEBUG( "Processing textures..." ); - for ( size_t i = 0; i < graph.textures.size() && i < graph.images.size(); ++i ) { - auto& image = graph.images[i]; - auto& texture = graph.textures[i]; - texture.bind = true; - if ( graph.metadata["filter"].is() ) { - uf::stl::string filter = graph.metadata["filter"].as(); - if ( filter == "NEAREST" ) { - texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST; - texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; - } else if ( filter == "LINEAR" ) { - texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::LINEAR; - texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::LINEAR; - } - } - UF_MSG_DEBUG("image: " << i); - texture.texture.loadFromImage( image ); - image.clear(); - } - } - - //UF_MSG_DEBUG( "Processing nodes..." ); - if ( !graph.root.entity ) graph.root.entity = new uf::Object; - for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity ); - - //UF_MSG_DEBUG( "Processing graphics..." ); - if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { - initializeGraphics( graph, *graph.root.entity ); - - auto& graphic = graph.root.entity->getComponent(); - - uf::stl::vector instances; - instances.reserve( graph.nodes.size() ); - for ( auto& node : graph.nodes ) { - instances.emplace_back( uf::transform::model( node.transform ) ); - } - // Models storage buffer - graph.buffers.instance = graphic.initializeBuffer( - (const void*) instances.data(), - instances.size() * sizeof(pod::Matrix4f), - uf::renderer::enums::Buffer::STORAGE - ); - // Joints storage buffer - if ( graph.metadata["flags"]["SKINNED"].as() ) { - for ( auto& node : graph.nodes ) { - if ( node.skin < 0 ) continue; - auto& skin = graph.skins[node.skin]; - node.buffers.joint = graphic.initializeBuffer( - (const void*) skin.inverseBindMatrices.data(), - (1 + skin.inverseBindMatrices.size()) * sizeof(pod::Matrix4f), - uf::renderer::enums::Buffer::STORAGE - ); - break; - } - } - // Failsafe - if ( graph.materials.empty() ) graph.materials.emplace_back(); - if ( graph.textures.empty() ) graph.textures.emplace_back(); - - // Materials storage buffer - uf::stl::vector materials( graph.materials.size() ); - for ( size_t i = 0; i < graph.materials.size(); ++i ) { - materials[i] = graph.materials[i].storage; - } - graph.root.buffers.material = graphic.initializeBuffer( - (const void*) materials.data(), - materials.size() * sizeof(pod::Material::Storage), - uf::renderer::enums::Buffer::STORAGE - ); - // Texture storage buffer - uf::stl::vector textures( graph.textures.size() ); - for ( size_t i = 0; i < graph.textures.size(); ++i ) { - textures[i] = graph.textures[i].storage; - } - graph.root.buffers.texture = graphic.initializeBuffer( - (const void*) textures.data(), - textures.size() * sizeof(pod::Texture::Storage), - uf::renderer::enums::Buffer::STORAGE - ); - } - - // calculate extents - pod::Vector3f extentMin = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; - pod::Vector3f extentMax = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; - - //UF_MSG_DEBUG( "Post-processing nodes..." ); - graph.root.entity->process([&]( uf::Entity* entity ) { - 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_VARYING_MESH - auto& mesh = entity->getComponent().get(); - mesh.updateDescriptor(); - #else - auto& mesh = entity->getComponent(); - #endif - - pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; - pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; - - auto model = uf::transform::model( transform ); - - #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; - - 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::AttributeDescriptor vertexAttributePosition; - uf::renderer::AttributeDescriptor vertexAttributeNormal; - - for ( auto& attribute : mesh.attributes.vertex.descriptor ) { - if ( attribute.name == "position" ) vertexAttributePosition = attribute; - else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; - } - UF_ASSERT( vertexAttributePosition.name != "" ); - - for ( size_t currentIndex = 0; currentIndex < vertices; ++currentIndex ) { - uint8_t* vertexSrc = vertexPointer + (currentIndex * vertexStride); - const pod::Vector3f& position = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); - min.x = std::min( min.x, position.x ); - min.y = std::min( min.y, position.y ); - min.z = std::min( min.z, position.z ); - - max.x = std::max( max.x, position.x ); - max.y = std::max( max.y, position.y ); - max.z = std::max( max.z, position.z ); - } - #else - for ( auto& vertex : mesh.vertices ) { - // auto position = uf::matrix::multiply( model, vertex.position, 1.0f ); - min.x = std::min( min.x, vertex.position.x ); - min.y = std::min( min.y, vertex.position.y ); - min.z = std::min( min.z, vertex.position.z ); - - max.x = std::max( max.x, vertex.position.x ); - max.y = std::max( max.y, vertex.position.y ); - max.z = std::max( max.z, vertex.position.z ); - } - #endif - - min = uf::matrix::multiply( model, min, 1.0f ); - max = uf::matrix::multiply( model, max, 1.0f ); - - extentMin.x = std::min( min.x, extentMin.x ); - extentMin.y = std::min( min.y, extentMin.y ); - extentMin.z = std::min( min.z, extentMin.z ); - - extentMax.x = std::max( max.x, extentMax.x ); - extentMax.y = std::max( max.y, extentMax.y ); - extentMax.z = std::max( max.z, extentMax.z ); - - if ( graph.metadata["flags"]["NORMALS"].as() ) { - // bool invert = false; - bool INVERTED = graph.metadata["flags"]["INVERT"].as(); - #if UF_GRAPH_VARYING_MESH - if ( mesh.attributes.index.pointer ) { - uint32_t indexes[3] = {}; - pod::Vector3f positions[3] = {}; - pod::Vector3f normal = {}; - - for ( size_t currentIndex = 0; currentIndex < indices; currentIndex += 3 ) { - for ( auto i = 0; i < 3; ++i ) { - uint8_t* indexSrc = indexPointer + ((currentIndex + i) * indexStride); - switch ( indexStride ) { - case sizeof( uint8_t): indexes[i] = *(( uint8_t*) indexSrc); break; - case sizeof(uint16_t): indexes[i] = *((uint16_t*) indexSrc); break; - case sizeof(uint32_t): indexes[i] = *((uint32_t*) indexSrc); break; - } - - uint8_t* vertexSrc = vertexPointer + (indexes[i] * vertexStride); - positions[i] = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); - } - - // if ( INVERTED ) std::swap( positions[1], positions[2] ); - // normal = uf::vector::normalize( uf::vector::cross( positions[2] - positions[0], positions[1] - positions[0] ) ); - normal = uf::vector::normalize( uf::vector::cross( positions[INVERTED ? 1 : 2] - positions[INVERTED ? 0 : 0], positions[INVERTED ? 2 : 1] - positions[INVERTED ? 0 : 0] ) ); - // if ( INVERTED ) normal *= -1; - - for ( auto i = 0; i < 3; ++i ) { - uint8_t* vertexSrc = vertexPointer + (indexes[i] * vertexStride); - *((pod::Vector3f*) (vertexSrc + vertexAttributeNormal.offset)) = normal; - } - } - } else { - pod::Vector3f positions[3] = {}; - pod::Vector3f normal = {}; - for ( size_t currentIndex = 0; currentIndex < vertices; currentIndex+=3 ) { - for ( auto i = 0; i < 3; ++i ) { - uint8_t* vertexSrc = vertexPointer + ((currentIndex + i) * vertexStride); - positions[i] = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); - } - - // if ( INVERTED ) std::swap( positions[1], positions[2] ); - // normal = uf::vector::normalize( uf::vector::cross( positions[2] - positions[0], positions[1] - positions[0] ) ); - normal = uf::vector::normalize( uf::vector::cross( positions[INVERTED ? 1 : 2] - positions[INVERTED ? 0 : 0], positions[INVERTED ? 2 : 1] - positions[INVERTED ? 0 : 0] ) ); - // if ( INVERTED ) normal *= -1; - - for ( auto i = 0; i < 3; ++i ) { - uint8_t* vertexSrc = vertexPointer + ((currentIndex + i) * vertexStride); - *((pod::Vector3f*) (vertexSrc + vertexAttributeNormal.offset)) = normal; - } - } - } - #else - if ( mesh.indices.empty() ) { - for ( size_t i = 0; i < mesh.vertices.size(); i+=3 ) { - auto& a = mesh.vertices[i+(INVERTED ? 0 : 0)].position; - auto& b = mesh.vertices[i+(INVERTED ? 1 : 2)].position; - auto& c = mesh.vertices[i+(INVERTED ? 2 : 1)].position; - - pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); - - mesh.vertices[i+0].normal = normal; - mesh.vertices[i+1].normal = normal; - mesh.vertices[i+2].normal = normal; - } - } else { - for ( size_t i = 0; i < mesh.indices.size(); i+=3 ) { - auto& A = mesh.vertices[mesh.indices[i+(INVERTED ? 0 : 0)]]; - auto& B = mesh.vertices[mesh.indices[i+(INVERTED ? 1 : 2)]]; - auto& C = mesh.vertices[mesh.indices[i+(INVERTED ? 2 : 1)]]; - - auto& a = A.position; - auto& b = B.position; - auto& c = C.position; - - pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); - - A.normal = normal; - B.normal = normal; - C.normal = normal; - } - } - #endif - } - if ( entity->hasComponent() ) { - auto& graphic = entity->getComponent(); + { + auto& graphic = graph.root.entity->getComponent(); graphic.initialize(); - #if 1 - #if UF_GRAPH_VARYING_MESH - graphic.initializeAttributes( mesh.attributes ); - #else graphic.initializeMesh( mesh ); graphic.process = true; - #endif - #else - #if 1 - if ( entity->getName() == "worldspawn_20" && ext::json::isObject( graph.metadata["grid"] ) ) { - auto sliced = mesh; - auto& grid = entity->getComponent(); - grid.initialize( sliced, uf::vector::decode( graph.metadata["grid"]["size"], pod::Vector3ui{1,1,1} ) ); - grid.analyze(); - auto center = uf::vector::decode( graph.metadata["grid"]["center"], grid.center() ); - sliced.indices = grid.get<>( center ); - graphic.initializeMesh( sliced ); - } else { - graphic.initializeMesh( mesh ); - } - #elif 0 - graphic.initialize(); - graphic.initializeMesh( mesh, 0 ); - if ( ext::json::isObject( graph.metadata["grid"] ) ) { - auto& grid = entity->getComponent(); - grid.initialize( mesh, uf::vector::decode( graph.metadata["grid"]["size"], pod::Vector3ui{1,1,1} ) ); - grid.analyze(); - - auto center = uf::vector::decode( graph.metadata["grid"]["center"], grid.center() ); - auto indices = grid.get<>( center ); - graphic.descriptor.indices = indices.size(); - UF_MSG_DEBUG("Center: " << uf::vector::toString(center) << " | Indices: " << indices.size()); - int32_t indexBuffer = -1; - for ( size_t i = 0; i < graphic.buffers.size(); ++i ) { - if ( graphic.buffers[i].usage & uf::renderer::enums::Buffer::INDEX ) indexBuffer = i; - } - if ( indexBuffer >= 0 && !indices.empty() && indices.size() % 3 == 0 ) { - shader.updateBuffer( - (const void*) indices.data(), - indices.size() * mesh.attributes.index.size, - indexBuffer - ); - } - } - #endif - #endif + initializeGraphics( graph, *graph.root.entity ); } - if ( entity->hasComponent() ) { - auto& mesh = entity->getComponent(); - auto& meshAttributes = entity->getComponent(); - meshAttributes = 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" ) { - 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 - } - } - - //UF_MSG_DEBUG( "Post-processed node...: " << uf::string::toString( entity->as() ) ); - }); - - 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]; @@ -782,9 +518,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) metadataLight["color"][1] = l.color.y; metadataLight["color"][2] = l.color.z; metadataLight["shadows"] = graph.metadata["lights"]["shadows"].as(); - if ( metadataLight["shadows"].as() ) { - metadataLight["radius"][1] = 0; - } + + // if ( metadataLight["shadows"].as() ) metadataLight["radius"][1] = 0; if ( ext::json::isArray( graph.metadata["lights"]["radius"] ) ) { metadataLight["radius"] = graph.metadata["lights"]["radius"]; } @@ -811,8 +546,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) if ( setName ) entity.setName( node.name ); // reference transform to parent + auto& transform = entity.getComponent>(); { - auto& transform = entity.getComponent>(); transform = node.transform; transform.reference = &parent.getComponent>(); // override transform @@ -842,101 +577,88 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) } } } + + size_t objectID = uf::graph::storage.entities.keys.size(); + uf::graph::storage.entities[std::to_string(objectID)] = &entity; + if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { - auto& nodeMesh = graph.meshes[node.mesh]; - auto& mesh = entity.getComponent(); + auto model = uf::transform::model( transform ); + auto& mesh = uf::graph::storage.meshes.map[graph.meshes[node.mesh]]; + auto& primitives = uf::graph::storage.primitives.map[graph.primitives[node.mesh]]; - } + pod::Instance::Bounds bounds; + // setup instances + for ( auto i = 0; i < primitives.size(); ++i ) { + auto& primitive = primitives[i]; -#if 0 - // copy mesh - if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) { - auto& nodeMesh = graph.meshes[node.mesh]; - auto& mesh = entity.getComponent(); - // preprocess mesh - #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; + size_t instanceID = uf::graph::storage.instances.keys.size(); + auto& instance = uf::graph::storage.instances[graph.instances.emplace_back(std::to_string(instanceID))]; + instance = primitive.instance; - uf::renderer::AttributeDescriptor vertexAttributeId; + instance.model = model; + instance.objectID = objectID; - 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)); - id.x = node.index; + bounds.min = uf::vector::min( bounds.min, instance.bounds.min ); + bounds.max = uf::vector::max( bounds.max, instance.bounds.max ); + + if ( mesh.indirect.count && mesh.indirect.count <= primitives.size() ) { + auto& attribute = mesh.indirect.attributes.front(); + auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer]; + pod::DrawCommand* drawCommands = (pod::DrawCommand*) buffer.data(); + auto& drawCommand = drawCommands[i]; + drawCommand.instanceID = instanceID; } } + if ( (graph.metadata["flags"]["SEPARATE"].as()) && graph.metadata["flags"]["RENDER"].as() ) { + uf::instantiator::bind("RenderBehavior", entity); + + auto& graphic = entity.getComponent(); + graphic.initialize(); + graphic.initializeMesh( mesh ); + graphic.process = true; + + initializeGraphics( graph, entity ); + } - if ( nodeMesh.is() ) mesh.insert( nodeMesh ); - else if ( nodeMesh.is() ) mesh.insert( nodeMesh ); - else if ( nodeMesh.is() ) mesh.insert( nodeMesh ); - else UF_EXCEPTION("unrecognized mesh type encountered..."); - #else - for ( auto& vertex : nodeMesh.vertices ) vertex.id.x = node.index; - mesh.insert( nodeMesh ); - #endif + #if 1 + if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) { + auto& info = graph.metadata["tags"][node.name]; + 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(); - if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { - 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 ); - else UF_EXCEPTION("unrecognized mesh type encountered..."); - #else - mesh.insert( nodeMesh ); - #endif - } else if ( graph.metadata["flags"]["RENDER"].as() ) { - uf::instantiator::bind("RenderBehavior", entity); - initializeGraphics( graph, entity ); - auto& graphic = entity.getComponent(); - // Joints storage buffer - if ( graph.metadata["flags"]["SKINNED"].as() && node.skin >= 0 ) { - auto& skin = graph.skins[node.skin]; - node.buffers.joint = graphic.initializeBuffer( - (const void*) skin.inverseBindMatrices.data(), - skin.inverseBindMatrices.size() * sizeof(pod::Matrix4f), - uf::renderer::enums::Buffer::STORAGE - ); + auto min = uf::matrix::multiply( model, bounds.min, 1.0f ); + auto max = uf::matrix::multiply( model, bounds.max, 1.0f ); + + pod::Vector3f center = (max + min) * 0.5f; + pod::Vector3f corner = (max - min) * 0.5f; + + #if UF_USE_BULLET + if ( type == "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 } - // Materials storage buffer - uf::stl::vector materials( graph.materials.size() ); - for ( size_t i = 0; i < graph.materials.size(); ++i ) { - materials[i] = graph.materials[i].storage; - } - node.buffers.material = graphic.initializeBuffer( - (const void*) materials.data(), - materials.size() * sizeof(pod::Material::Storage), - uf::renderer::enums::Buffer::STORAGE - ); - // Texture storage buffer - uf::stl::vector textures( graph.textures.size() ); - for ( size_t i = 0; i < graph.textures.size(); ++i ) { - textures[i] = graph.textures[i].storage; - // textures[i].remap = -1; - } - graph.root.buffers.texture = graphic.initializeBuffer( - (const void*) textures.data(), - textures.size() * sizeof(pod::Texture::Storage), - uf::renderer::enums::Buffer::STORAGE - ); } + #endif } -#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(); - -// graph.images.clear(); -// graph.meshes.clear(); -// graph.atlas.clear(); } void uf::graph::override( pod::Graph& graph ) { graph.settings.animations.override.a = 0; @@ -955,7 +677,7 @@ void uf::graph::override( pod::Graph& graph ) { // set our destination transform per node if ( !toNeutralPose ) { uf::stl::string name = graph.sequence.front(); - pod::Animation& animation = graph.animations[name]; + pod::Animation& animation = uf::graph::storage.animations.map[name]; // graph.animations[name]; for ( auto& channel : animation.channels ) { auto& override = graph.settings.animations.override.map[channel.node]; auto& sampler = animation.samplers[channel.sampler]; @@ -977,7 +699,6 @@ 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(); @@ -988,15 +709,14 @@ 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() ) ); }); } - void uf::graph::animate( pod::Graph& graph, const uf::stl::string& name, float speed, bool immediate ) { if ( !(graph.metadata["flags"]["SKINNED"].as()) ) return; - if ( graph.animations.count( name ) > 0 ) { +// if ( graph.animations.count( name ) > 0 ) { + if ( uf::graph::storage.animations.map.count( name ) > 0 ) { // if already playing, ignore it if ( !graph.sequence.empty() && graph.sequence.front() == name ) return; if ( immediate ) { @@ -1013,13 +733,21 @@ void uf::graph::update( pod::Graph& graph ) { return update( graph, uf::physics::time::delta ); } void uf::graph::update( pod::Graph& graph, float delta ) { - // no override + // update our instances + for ( auto& name : uf::graph::storage.instances.keys ) { + auto& instance = uf::graph::storage.instances[name]; + auto& entity = *uf::graph::storage.entities[std::to_string(instance.objectID)]; + auto& transform = entity.getComponent>(); + instance.model = uf::transform::model( transform ); + } + + // no skins if ( !(graph.metadata["flags"]["SKINNED"].as()) ) return; if ( graph.sequence.empty() ) goto UPDATE; if ( graph.settings.animations.override.a >= 0 ) goto OVERRIDE; { uf::stl::string name = graph.sequence.front(); - pod::Animation* animation = &graph.animations[name]; + pod::Animation* animation = &uf::graph::storage.animations.map[name]; // &graph.animations[name]; // std::cout << "ANIMATION: " << name << "\t" << animation->cur << std::endl; animation->cur += delta * graph.settings.animations.speed; // * graph.settings.animations.override.speed; if ( animation->end < animation->cur ) { @@ -1033,7 +761,7 @@ void uf::graph::update( pod::Graph& graph, float delta ) { goto OVERRIDE; } name = graph.sequence.front(); - animation = &graph.animations[name]; + animation = &uf::graph::storage.animations.map[name]; // &graph.animations[name]; } } for ( auto& channel : animation->channels ) { @@ -1106,59 +834,112 @@ void uf::graph::destroy( pod::Graph& graph ) { #endif } -namespace { - 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; +void uf::graph::initialize() { + uf::graph::storage.buffers.camera.initialize( (const void*) nullptr, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM ); + uf::graph::storage.buffers.drawCommands.initialize( (const void*) nullptr, sizeof(pod::DrawCommand), uf::renderer::enums::Buffer::STORAGE ); + uf::graph::storage.buffers.instance.initialize( (const void*) nullptr, sizeof(pod::Instance) * 1024, uf::renderer::enums::Buffer::STORAGE ); + uf::graph::storage.buffers.joint.initialize( (const void*) nullptr, sizeof(pod::Matrix4f) * 1024, uf::renderer::enums::Buffer::STORAGE ); + uf::graph::storage.buffers.material.initialize( (const void*) nullptr, sizeof(pod::Material) * 1024, uf::renderer::enums::Buffer::STORAGE ); + uf::graph::storage.buffers.texture.initialize( (const void*) nullptr, sizeof(pod::Texture) * 1024, uf::renderer::enums::Buffer::STORAGE ); + uf::graph::storage.buffers.light.initialize( (const void*) nullptr, sizeof(pod::Light) * 1024, uf::renderer::enums::Buffer::STORAGE ); +} +void uf::graph::tick() { + uf::stl::vector instances; instances.reserve(uf::graph::storage.instances.map.size()); + uf::stl::vector joints; joints.reserve(uf::graph::storage.joints.map.size()); - uf::Image& image = uf::graph::storage.images[name]; + for ( auto key : uf::graph::storage.instances.keys ) { + auto& instance = instances.emplace_back( uf::graph::storage.instances.map[key] ); + // instance.bounds.min = uf::matrix::multiply( instance.model, instance.bounds.min, 1.0f ); + // instance.bounds.max = uf::matrix::multiply( instance.model, instance.bounds.max, 1.0f ); + /* + pod::Vector3f min = uf::matrix::multiply( instance.model, instance.bounds.min, 1.0f ); + pod::Vector3f max = uf::matrix::multiply( instance.model, instance.bounds.max, 1.0f ); + + instance.bounds.min = (max + min) * 0.5f; // center + instance.bounds.max = (max - min) * 0.5f; // extent + */ + } + for ( auto key : uf::graph::storage.joints.keys ) joints.emplace_back( uf::graph::storage.joints.map[key] ); + + uf::graph::storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) ); + uf::graph::storage.buffers.joint.update( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f) ); + + if ( ::newGraphAdded ) { + uf::stl::vector drawCommands; drawCommands.reserve(uf::graph::storage.drawCommands.map.size()); + uf::stl::vector materials; materials.reserve(uf::graph::storage.materials.map.size()); + uf::stl::vector textures; textures.reserve(uf::graph::storage.textures.map.size()); + + for ( auto key : uf::graph::storage.drawCommands.keys ) drawCommands.insert( drawCommands.end(), uf::graph::storage.drawCommands.map[key].begin(), uf::graph::storage.drawCommands.map[key].end() ); + for ( auto key : uf::graph::storage.materials.keys ) materials.emplace_back( uf::graph::storage.materials.map[key] ); + for ( auto key : uf::graph::storage.textures.keys ) textures.emplace_back( uf::graph::storage.textures.map[key] ); + + uf::graph::storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) ); + uf::graph::storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ); + uf::graph::storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) ); + ::newGraphAdded = false; + } +} +void uf::graph::render() { + auto& scene = uf::scene::getCurrentScene(); + auto& controller = scene.getController(); + auto& camera = controller.getComponent(); + uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) ); +} +void uf::graph::destroy() { + for ( auto pair : uf::graph::storage.texture2Ds.map ) pair.second.destroy(); + for ( auto& t : uf::graph::storage.shadow2Ds ) t.destroy(); + for ( auto& t : uf::graph::storage.shadowCubes ) t.destroy(); + + for ( auto pair : uf::graph::storage.atlases.map ) pair.second.clear(); + for ( auto pair : uf::graph::storage.images.map ) pair.second.clear(); + for ( auto pair : uf::graph::storage.meshes.map ) pair.second.destroy(); +} +namespace { + uf::Image decodeImage( ext::json::Value& json, pod::Graph& graph ) { + uf::Image image; + + if ( json["filename"].is() ) { + const uf::stl::string directory = uf::io::directory( graph.name ); + const uf::stl::string filename = uf::io::filename( json["filename"].as() ); + const uf::stl::string name = directory + "/" + filename; image.open(name, false); - return name; + } else { + 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 ); } - 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 name; + return image; } - uf::stl::string decodeTexture( ext::json::Value& json, const pod::Graph& graph ) { - auto name = json["name"].as(); + pod::Texture decodeTexture( ext::json::Value& json, pod::Graph& graph ) { + pod::Texture texture; - 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; + return texture; } - uf::stl::string decodeSampler( ext::json::Value& json, const pod::Graph& graph ) { - auto name = json["name"].as(); + uf::renderer::Sampler decodeSampler( ext::json::Value& json, pod::Graph& graph ) { + uf::renderer::Sampler sampler; - 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 name; + return sampler; } - uf::stl::string decodeMaterial( ext::json::Value& json, const pod::Graph& graph ) { - auto name = json["name"].as(); + pod::Material decodeMaterial( ext::json::Value& json, pod::Graph& graph ) { + pod::Material material; - 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); @@ -1172,10 +953,10 @@ namespace { material.indexMetallicRoughness = json["iMetallicRoughness"].as(material.indexMetallicRoughness); material.modeAlpha = json["modeAlpha"].as(material.modeAlpha); - return name; + return material; } - pod::Light decodeLight( ext::json::Value& json, const pod::Graph& graph ) { + pod::Light decodeLight( ext::json::Value& json, pod::Graph& graph ) { pod::Light light; light.color = uf::vector::decode( json["color"], light.color ); light.intensity = json["intensity"].as(light.intensity); @@ -1183,8 +964,9 @@ namespace { return light; } - pod::Animation decodeAnimation( ext::json::Value& json, const pod::Graph& graph ) { + pod::Animation decodeAnimation( ext::json::Value& json, pod::Graph& graph ) { pod::Animation animation; + animation.name = json["name"].as(animation.name); animation.start = json["start"].as(animation.start); animation.end = json["end"].as(animation.end); @@ -1210,11 +992,13 @@ namespace { channel.node = value["node"].as(channel.node); channel.sampler = value["sampler"].as(channel.sampler); }); + return animation; } - pod::Skin decodeSkin( ext::json::Value& json, const pod::Graph& graph ) { + pod::Skin decodeSkin( ext::json::Value& json, pod::Graph& graph ) { pod::Skin skin; + skin.name = json["name"].as(skin.name); skin.joints.reserve( json["joints"].size() ); @@ -1230,96 +1014,147 @@ namespace { return skin; } - 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); + pod::Instance decodeInstance( ext::json::Value& json, pod::Graph& graph ) { + pod::Instance instance; + instance.model = uf::matrix::decode( json["model"], instance.model ); + instance.color = uf::vector::decode( json["color"], instance.color ); + instance.materialID = json["materialID"].as( instance.materialID ); + instance.primitiveID = json["primitiveID"].as( instance.primitiveID ); + instance.meshID = json["meshID"].as( instance.meshID ); + instance.objectID = json["objectID"].as( instance.objectID ); + instance.bounds.min = uf::vector::decode( json["bounds"]["min"], instance.bounds.min ); + instance.bounds.max = uf::vector::decode( json["bounds"]["max"], instance.bounds.max ); + return instance; + } - 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); + pod::DrawCommand decodeDrawCommand( ext::json::Value& json, pod::Graph& graph ) { + pod::DrawCommand drawCommand; + drawCommand.indices = json["indices"].as( drawCommand.indices ); + drawCommand.instances = json["instances"].as( drawCommand.instances ); + drawCommand.indexID = json["indexID"].as( drawCommand.indexID ); + drawCommand.vertexID = json["vertexID"].as( drawCommand.vertexID ); + drawCommand.instanceID = json["instanceID"].as( drawCommand.instanceID ); + // drawCommand.padding1 = json["padding1"].as( drawCommand.padding1 ); + // drawCommand.padding2 = json["padding2"].as( drawCommand.padding2 ); + drawCommand.vertices = json["vertices"].as( drawCommand.vertices ); + return drawCommand; + } + + pod::Primitive decodePrimitive( ext::json::Value& json, pod::Graph& graph ) { + pod::Primitive prim; + prim.instance = decodeInstance( json["instance"], graph ); + prim.drawCommand = decodeDrawCommand( json["drawCommand"], graph ); + return prim; + } + + uf::stl::vector decodePrimitives( ext::json::Value& json, pod::Graph& graph ) { + uf::stl::vector primitives; + auto name = json["name"].as(); + ext::json::forEach( json["primitives"], [&]( ext::json::Value& value ){ + primitives.emplace_back( decodePrimitive( value, graph ) ); + }); + return primitives; + } + uf::stl::vector decodeDrawCommands( ext::json::Value& json, pod::Graph& graph ) { + uf::stl::vector drawCommands; + auto name = json["name"].as(); + ext::json::forEach( json["drawCommands"], [&]( ext::json::Value& value ){ + drawCommands.emplace_back( decodeDrawCommand( value, graph ) ); }); return drawCommands; } - pod::Instance decodeInstance( ext::json::Value& json, const pod::Graph& graph ) { - pod::Instance instance; + uf::Mesh decodeMesh( ext::json::Value& json, pod::Graph& graph ) { + uf::Mesh mesh; - 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() ); + mesh.vertex.count = json["inputs"]["vertex"]["count"].as( mesh.vertex.count ); + mesh.vertex.first = json["inputs"]["vertex"]["first"].as( mesh.vertex.first ); + mesh.vertex.stride = json["inputs"]["vertex"]["stride"].as( mesh.vertex.stride ); + mesh.vertex.offset = json["inputs"]["vertex"]["stride"].as( mesh.vertex.offset ); + mesh.vertex.interleaved = json["inputs"]["vertex"]["interleaved"].as( mesh.vertex.interleaved ); 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.descriptor.offset = value["descriptor"]["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["descriptor"]["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["descriptor"]["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["descriptor"]["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["descriptor"]["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["descriptor"]["components"].as(attribute.descriptor.components); attribute.buffer = value["buffer"].as(attribute.buffer); + attribute.offset = value["offset"].as(attribute.offset); + attribute.stride = value["stride"].as(attribute.stride); }); mesh.index.attributes.reserve( json["inputs"]["index"]["attributes"].size() ); + mesh.index.count = json["inputs"]["index"]["count"].as( mesh.index.count ); + mesh.index.first = json["inputs"]["index"]["first"].as( mesh.index.first ); + mesh.index.stride = json["inputs"]["index"]["stride"].as( mesh.index.stride ); + mesh.index.offset = json["inputs"]["index"]["stride"].as( mesh.index.offset ); + mesh.index.interleaved = json["inputs"]["index"]["interleaved"].as( mesh.index.interleaved ); 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.descriptor.offset = value["descriptor"]["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["descriptor"]["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["descriptor"]["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["descriptor"]["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["descriptor"]["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["descriptor"]["components"].as(attribute.descriptor.components); attribute.buffer = value["buffer"].as(attribute.buffer); + attribute.offset = value["offset"].as(attribute.offset); + attribute.stride = value["stride"].as(attribute.stride); }); mesh.instance.attributes.reserve( json["inputs"]["instance"]["attributes"].size() ); + mesh.instance.count = json["inputs"]["instance"]["count"].as( mesh.instance.count ); + mesh.instance.first = json["inputs"]["instance"]["first"].as( mesh.instance.first ); + mesh.instance.stride = json["inputs"]["instance"]["stride"].as( mesh.instance.stride ); + mesh.instance.offset = json["inputs"]["instance"]["stride"].as( mesh.instance.offset ); + mesh.instance.interleaved = json["inputs"]["instance"]["interleaved"].as( mesh.instance.interleaved ); 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.descriptor.offset = value["descriptor"]["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["descriptor"]["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["descriptor"]["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["descriptor"]["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["descriptor"]["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["descriptor"]["components"].as(attribute.descriptor.components); attribute.buffer = value["buffer"].as(attribute.buffer); + attribute.offset = value["offset"].as(attribute.offset); + attribute.stride = value["stride"].as(attribute.stride); }); mesh.indirect.attributes.reserve( json["inputs"]["indirect"]["attributes"].size() ); + mesh.indirect.count = json["inputs"]["indirect"]["count"].as( mesh.indirect.count ); + mesh.indirect.first = json["inputs"]["indirect"]["first"].as( mesh.indirect.first ); + mesh.indirect.stride = json["inputs"]["indirect"]["stride"].as( mesh.indirect.stride ); + mesh.indirect.offset = json["inputs"]["indirect"]["stride"].as( mesh.indirect.offset ); + mesh.indirect.interleaved = json["inputs"]["indirect"]["interleaved"].as( mesh.indirect.interleaved ); 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.descriptor.offset = value["descriptor"]["offset"].as(attribute.descriptor.offset); + attribute.descriptor.size = value["descriptor"]["size"].as(attribute.descriptor.size); + attribute.descriptor.format = (uf::renderer::enums::Format::type_t) value["descriptor"]["format"].as(attribute.descriptor.format); + attribute.descriptor.name = value["descriptor"]["name"].as(attribute.descriptor.name); + attribute.descriptor.type = (uf::renderer::enums::Type::type_t) value["descriptor"]["type"].as(attribute.descriptor.type); + attribute.descriptor.components = value["descriptor"]["components"].as(attribute.descriptor.components); attribute.buffer = value["buffer"].as(attribute.buffer); + attribute.offset = value["offset"].as(attribute.offset); + attribute.stride = value["stride"].as(attribute.stride); }); 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 )); + auto& buffer = mesh.buffers.emplace_back(uf::io::readAsBuffer( directory + "/" + filename )); }); - - return name; + mesh.updateDescriptor(); + return mesh; } - pod::Node decodeNode( ext::json::Value& json, const pod::Graph& graph ) { + pod::Node decodeNode( ext::json::Value& json, pod::Graph& graph ) { pod::Node node = pod::Node{ .name = json["name"].as(), .index = json["index"].as(), @@ -1360,20 +1195,35 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize graph.metadata = metadata; // serializer["metadata"]; 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 )); + // load images + UF_DEBUG_TIMER_MULTITRACE("Reading instances..."); + graph.instances.reserve( serializer["instances"].size() ); + ext::json::forEach( serializer["instances"], [&]( ext::json::Value& value ){ + auto name = value["name"].as(); + graph.storage.instances[name] = decodeInstance( value, graph ); + graph.instances.emplace_back(name); }); }); 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 )); + // load images + UF_DEBUG_TIMER_MULTITRACE("Reading primitives..."); + graph.primitives.reserve( serializer["primitives"].size() ); + ext::json::forEach( serializer["primitives"], [&]( ext::json::Value& value ){ + auto name = value["name"].as(); + graph.storage.primitives[name] = decodePrimitives( value, graph ); + graph.primitives.emplace_back(name); + }); + }); + jobs.emplace_back([&]{ + // load images + UF_DEBUG_TIMER_MULTITRACE("Reading drawCommands..."); + graph.drawCommands.reserve( serializer["drawCommands"].size() ); + ext::json::forEach( serializer["drawCommands"], [&]( ext::json::Value& value ){ + auto name = value["name"].as(); + graph.storage.drawCommands[name] = decodeDrawCommands( value, graph ); + graph.drawCommands.emplace_back(name); }); }); jobs.emplace_back([&]{ @@ -1381,19 +1231,21 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize UF_DEBUG_TIMER_MULTITRACE("Reading meshes..."); graph.meshes.reserve( serializer["meshes"].size() ); ext::json::forEach( serializer["meshes"], [&]( ext::json::Value& value ){ - if ( value.is() ) { - UF_DEBUG_TIMER_MULTITRACE(directory + "/" + value.as()); - uf::Serializer json; - json.readFromFile( directory + "/" + value.as() ); - graph.meshes.emplace_back(decodeMesh( json, graph )); - } else { - graph.meshes.emplace_back(decodeMesh( value, graph )); - } + auto name = value["name"].as(); + graph.storage.meshes[name] = decodeMesh( value, graph ); + graph.meshes.emplace_back(name); }); }); - #if 0 - #if !UF_ENV_DREAMCAST 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 name = value["name"].as(); + graph.storage.images[name] = decodeImage( value, graph ); + graph.images.emplace_back(name); + }); + #if 0 && !UF_ENV_DREAMCAST if ( !ext::json::isNull( serializer["atlas"] ) ) { UF_DEBUG_TIMER_MULTITRACE("Reading atlas..."); auto& image = graph.atlas.getAtlas(); @@ -1406,23 +1258,16 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize decode( value, image, graph ); } } + #endif }); - #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 ){ - 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 ){ - graph.images.emplace_back(decodeImage( value, graph )); + auto name = value["name"].as(); + graph.storage.textures[name] = decodeTexture( value, graph ); + graph.textures.emplace_back(name); }); }); jobs.emplace_back([&]{ @@ -1430,7 +1275,9 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize UF_DEBUG_TIMER_MULTITRACE("Reading sampler information..."); graph.samplers.reserve( serializer["samplers"].size() ); ext::json::forEach( serializer["samplers"], [&]( ext::json::Value& value ){ - graph.samplers.emplace_back(decodeSampler( value, graph )); + auto name = value["name"].as(); + graph.storage.samplers[name] = decodeSampler( value, graph ); + graph.samplers.emplace_back(name); }); }); jobs.emplace_back([&]{ @@ -1438,14 +1285,16 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize UF_DEBUG_TIMER_MULTITRACE("Reading material information..."); graph.materials.reserve( serializer["materials"].size() ); ext::json::forEach( serializer["materials"], [&]( ext::json::Value& value ){ - graph.materials.emplace_back(decodeMaterial( value, graph )); + auto name = value["name"].as(); + graph.storage.materials[name] = decodeMaterial( value, graph ); + graph.materials.emplace_back(name); }); }); jobs.emplace_back([&]{ // 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 ){ + graph.lights.reserve( serializer["lights"].size() ); + ext::json::forEach( serializer["lights"], [&]( ext::json::Value& value ){ auto name = value["name"].as(); graph.lights[name] = decodeLight( value, graph ); }); @@ -1453,17 +1302,17 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize jobs.emplace_back([&]{ // load animation information UF_DEBUG_TIMER_MULTITRACE("Reading animation information..."); - graph.animations.reserve( serializer["animations"].size() ); + graph.storage.animations.map.reserve( serializer["animations"].size() ); ext::json::forEach( serializer["animations"], [&]( ext::json::Value& value ){ - if ( value.is() ) { + auto name = value["name"].as(); + if ( value["filename"].is() ) { uf::Serializer json; - json.readFromFile( directory + "/" + value.as() ); - uf::stl::string key = json["name"].as(); - graph.animations[key] = decodeAnimation( json, graph ); + json.readFromFile( directory + "/" + value["filename"].as() ); + graph.storage.animations[name] = decodeAnimation( json, graph ); } else { - uf::stl::string key = value["name"].as(); - graph.animations[key] = decodeAnimation( value, graph ); + graph.storage.animations[name] = decodeAnimation( value, graph ); } + graph.animations.emplace_back(name); }); }); jobs.emplace_back([&]{ @@ -1471,7 +1320,9 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize UF_DEBUG_TIMER_MULTITRACE("Reading skinning information..."); graph.skins.reserve( serializer["skins"].size() ); ext::json::forEach( serializer["skins"], [&]( ext::json::Value& value ){ - graph.skins.emplace_back(decodeSkin( value, graph )); + auto name = value["name"].as(); + graph.storage.skins[name] = decodeSkin( value, graph ); + graph.skins.emplace_back(name); }); }); jobs.emplace_back([&]{ @@ -1595,39 +1446,46 @@ namespace { json["inverseBindMatrices"].emplace_back( uf::matrix::encode(inverseBindMatrix, settings) ); return json; } - uf::Serializer encode( const uf::stl::vector& drawCommands, const EncodingSettings& settings ) { - uf::Serializer json; - 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; + json["model"] = uf::matrix::encode( instance.model, settings ); + json["color"] = uf::vector::encode( instance.color, settings ); + json["materialID"] = instance.materialID; + json["primitiveID"] = instance.primitiveID; + json["meshID"] = instance.meshID; + json["objectID"] = instance.objectID; + + json["bounds"]["min"] = uf::vector::encode( instance.bounds.min, settings ); + json["bounds"]["max"] = uf::vector::encode( instance.bounds.max, settings ); + return json; } - uf::Serializer encode( const pod::Mesh& pair, const EncodingSettings& settings ) { + uf::Serializer encode( const pod::DrawCommand& drawCommand, const EncodingSettings& settings ) { + uf::Serializer json; + json["indices"] = drawCommand.indices; + json["instances"] = drawCommand.instances; + json["indexID"] = drawCommand.indexID; + json["vertexID"] = drawCommand.vertexID; + json["instanceID"] = drawCommand.instanceID; + // json["padding1"] = drawCommand.padding1; + // json["padding2"] = drawCommand.padding2; + json["vertices"] = drawCommand.vertices; + return json; + } + uf::Serializer encode( const pod::Primitive& primitive, const EncodingSettings& settings ) { + uf::Serializer json; + json["drawCommand"] = encode( primitive.drawCommand, settings ); + json["instance"] = encode( primitive.instance, settings ); + return json; + } + uf::Serializer encode( const uf::Mesh& mesh, 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; + json["inputs"]["vertex"]["interleaved"] = mesh.vertex.interleaved; 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(); @@ -1638,12 +1496,15 @@ namespace { a["descriptor"]["type"] = attribute.descriptor.type; a["descriptor"]["components"] = attribute.descriptor.components; a["buffer"] = attribute.buffer; + a["offset"] = attribute.offset; + a["stride"] = attribute.stride; } 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; + json["inputs"]["index"]["interleaved"] = mesh.index.interleaved; 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(); @@ -1654,12 +1515,15 @@ namespace { a["descriptor"]["type"] = attribute.descriptor.type; a["descriptor"]["components"] = attribute.descriptor.components; a["buffer"] = attribute.buffer; + a["offset"] = attribute.offset; + a["stride"] = attribute.stride; } 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; + json["inputs"]["instance"]["interleaved"] = mesh.instance.interleaved; 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(); @@ -1670,12 +1534,15 @@ namespace { a["descriptor"]["type"] = attribute.descriptor.type; a["descriptor"]["components"] = attribute.descriptor.components; a["buffer"] = attribute.buffer; + a["offset"] = attribute.offset; + a["stride"] = attribute.stride; } 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; + json["inputs"]["indirect"]["interleaved"] = mesh.indirect.interleaved; 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(); @@ -1686,6 +1553,8 @@ namespace { a["descriptor"]["type"] = attribute.descriptor.type; a["descriptor"]["components"] = attribute.descriptor.components; a["buffer"] = attribute.buffer; + a["offset"] = attribute.offset; + a["stride"] = attribute.stride; } ext::json::reserve( json["buffers"], mesh.buffers.size() ); @@ -1694,128 +1563,6 @@ namespace { 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; - a["type"] = attribute.type; - a["format"] = attribute.format; - a["offset"] = attribute.offset; - a["components"] = attribute.components; - } - - // validation metadata - json["metadata"]["vertices"]["size"] = mesh.attributes.vertex.size; - json["metadata"]["vertices"]["count"] = mesh.attributes.vertex.length; - - json["metadata"]["indices"]["size"] = mesh.attributes.index.size; - json["metadata"]["indices"]["count"] = mesh.attributes.index.length; - - if ( !settings.encodeBuffers ){ - #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; - - size_t vertices = mesh.attributes.vertex.length; - size_t vertexStride = mesh.attributes.vertex.size; - uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; - - ext::json::reserve( json["vertices"], mesh.attributes.vertex.length ); - ext::json::reserve( json["indices"], indices ); - for ( size_t currentIndex = 0; currentIndex < indices; ++currentIndex ) { - uint32_t index {}; - 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; - } - json["indices"].emplace_back( index ); - - auto& v = json["vertices"].emplace_back(); - 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 ) { - case 1: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - case 2: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - case 3: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - case 4: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - } - else - switch ( attribute.components ) { - case 1: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - case 2: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - case 3: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - case 4: v.emplace_back( uf::vector::encode( *((pod::Vector*) vertexSrc), settings ) ); break; - } - } - } - #if 0 - if ( mesh.is() ) { - auto& m = mesh.get(); - for ( auto& vertex : m.vertices ) { - auto& v = json["vertices"].emplace_back(); - v.emplace_back(!vertex.position ? ext::json::array() : uf::vector::encode(vertex.position, settings)); - v.emplace_back(!vertex.uv ? ext::json::array() : uf::vector::encode(vertex.uv, settings)); - v.emplace_back(!vertex.st ? ext::json::array() : uf::vector::encode(vertex.st, settings)); - v.emplace_back(!vertex.normal ? ext::json::array() : uf::vector::encode(vertex.normal, settings)); - } - } else if ( mesh.is() ) { - auto& m = mesh.get(); - for ( auto& vertex : m.vertices ) { - auto& v = json["vertices"].emplace_back(); - v.emplace_back(!vertex.position ? ext::json::array() : uf::vector::encode(vertex.position, settings)); - v.emplace_back(!vertex.uv ? ext::json::array() : uf::vector::encode(vertex.uv, settings)); - v.emplace_back(!vertex.st ? ext::json::array() : uf::vector::encode(vertex.st, settings)); - v.emplace_back(!vertex.normal ? ext::json::array() : uf::vector::encode(vertex.normal, settings)); - v.emplace_back(!vertex.tangent ? ext::json::array() : uf::vector::encode(vertex.tangent, settings)); - v.emplace_back(!vertex.id ? ext::json::array() : uf::vector::encode(vertex.id, settings)); - } - } else if ( mesh.is() ) { - auto& m = mesh.get(); - for ( auto& vertex : m.vertices ) { - auto& v = json["vertices"].emplace_back(); - v.emplace_back(!vertex.position ? ext::json::array() : uf::vector::encode(vertex.position, settings)); - v.emplace_back(!vertex.uv ? ext::json::array() : uf::vector::encode(vertex.uv, settings)); - v.emplace_back(!vertex.st ? ext::json::array() : uf::vector::encode(vertex.st, settings)); - v.emplace_back(!vertex.normal ? ext::json::array() : uf::vector::encode(vertex.normal, settings)); - v.emplace_back(!vertex.tangent ? ext::json::array() : uf::vector::encode(vertex.tangent, settings)); - v.emplace_back(!vertex.id ? ext::json::array() : uf::vector::encode(vertex.id, settings)); - v.emplace_back(!vertex.joints ? ext::json::array() : uf::vector::encode(vertex.joints, settings)); - v.emplace_back(!vertex.weights ? ext::json::array() : uf::vector::encode(vertex.weights, settings)); - } - } - #endif - #else - for ( auto& vertex : mesh.vertices ) { - auto& v = json["vertices"].emplace_back(); - v.emplace_back(!vertex.position ? ext::json::array() : uf::vector::encode(vertex.position, settings)); - v.emplace_back(!vertex.uv ? ext::json::array() : uf::vector::encode(vertex.uv, settings)); - v.emplace_back(!vertex.st ? ext::json::array() : uf::vector::encode(vertex.st, settings)); - v.emplace_back(!vertex.normal ? ext::json::array() : uf::vector::encode(vertex.normal, settings)); - v.emplace_back(!vertex.tangent ? ext::json::array() : uf::vector::encode(vertex.tangent, settings)); - v.emplace_back(!vertex.id ? ext::json::array() : uf::vector::encode(vertex.id, settings)); - v.emplace_back(!vertex.joints ? ext::json::array() : uf::vector::encode(vertex.joints, settings)); - v.emplace_back(!vertex.weights ? ext::json::array() : uf::vector::encode(vertex.weights, settings)); - } - #endif - } else { - const uf::stl::string verticesFilename = settings.filename + ".vertices." + ( settings.compress ? "gz" : "bin" ); - uf::io::write( verticesFilename, mesh.attributes.vertex.pointer, mesh.attributes.vertex.size * mesh.attributes.vertex.length ); - json["vertices"] = uf::io::filename( verticesFilename ); - - if ( mesh.attributes.index.length > 0 ) { - const uf::stl::string indicesFilename = settings.filename + ".indices." + ( settings.compress ? "gz" : "bin" ); - uf::io::write( indicesFilename, mesh.attributes.index.pointer, mesh.attributes.index.size * mesh.attributes.index.length ); - json["indices"] = uf::io::filename( indicesFilename ); - } - } - #endif return json; } uf::Serializer encode( const pod::Node& node, const EncodingSettings& settings ) { @@ -1852,118 +1599,48 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) /*.filename = */directory + "/graph.json", }; if ( !settings.combined ) uf::io::mkdir(directory); - if ( settings.unwrap ) { + if ( !true && settings.unwrap ) { pod::Graph& g = const_cast(graph); auto size = ext::xatlas::unwrap( g ); serializer["wrapped"] = uf::vector::encode( size ); } pod::Thread::container_t jobs; - // store images jobs.emplace_back([&]{ - #if 0 - if ( graph.atlas.generated() ) { - auto& image = graph.atlas.getAtlas(); - if ( !settings.combined ) { - 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 ) { - auto& name = graph.images[i]; - auto& image = uf::graph::storage.images[name]; - uf::stl::string f = "image."+std::to_string(i)+".png"; - - image.save(directory + "/" + f); - uf::Serializer json; - json["name"] = name; - json["filename"] = f; - serializer["images"].emplace_back( json ); - } - } else { - 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& 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& 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& 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 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 - 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); - } - }); - jobs.emplace_back([&]{ - // store skin information - 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) ); + for ( size_t i = 0; i < graph.instances.size(); ++i ) { + auto& name = graph.instances[i]; + auto& instance = graph.storage.instances.map.at(name); + uf::Serializer json = encode( instance, settings ); + json["name"] = name; + serializer["instances"].emplace_back( json ); + } + }); + jobs.emplace_back([&]{ + ext::json::reserve( serializer["primitives"], graph.primitives.size() ); + for ( size_t i = 0; i < graph.primitives.size(); ++i ) { + auto& name = graph.primitives[i]; + auto& primitives = graph.storage.primitives.map.at(name); + auto& json = serializer["primitives"].emplace_back(); + json["name"] = name; + // ext::json::reserve( json["primitives"], primitives.size() ); + for ( auto& primitive : primitives ) { + json["primitives"].emplace_back( encode( primitive, settings ) ); + } + } + }); + jobs.emplace_back([&]{ + ext::json::reserve( serializer["drawCommands"], graph.drawCommands.size() ); + for ( size_t i = 0; i < graph.drawCommands.size(); ++i ) { + auto& name = graph.drawCommands[i]; + auto& drawCommands = graph.storage.drawCommands.map.at(name); + auto& json = serializer["drawCommands"].emplace_back(); + json["name"] = name; + // ext::json::reserve( json["drawCommands"], drawCommands.size() ); + for ( auto& drawCommand : drawCommands ) { + json["drawCommands"].emplace_back( encode( drawCommand, settings ) ); + } + } }); jobs.emplace_back([&]{ // store mesh information @@ -1972,7 +1649,7 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) ::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]; + auto& mesh = graph.storage.meshes.map.at(name); if ( !s.encodeBuffers ) { s.filename = directory+"/mesh."+std::to_string(i)+".json"; encode(mesh, s).writeToFile(s.filename, settings); @@ -1989,13 +1666,117 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) } } else { for ( auto& name : graph.meshes ) { - auto& mesh = uf::graph::storage.meshes[name]; + auto& mesh = graph.storage.meshes.map.at(name); auto json = encode(mesh, settings); json["name"] = name; serializer["meshes"].emplace_back(json); } } }); +#if 0 + jobs.emplace_back([&]{ + if ( uf::graphs::storage.atlases[graph.atlas].generated() ) { + auto atlasName = filename + "/" + "atlas"; + auto& atlas = graph.storage.atlases[atlasName]; + auto& image = atlas.getAtlas(); + if ( !settings.combined ) { + 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 ) { + auto& name = graph.images[i]; + auto& image = graph.storage.images.map.at(name); + uf::stl::string f = "image."+std::to_string(i)+".png"; + + image.save(directory + "/" + f); + uf::Serializer json; + json["name"] = name; + json["filename"] = f; + serializer["images"].emplace_back( json ); + } + } else { + for ( auto& name : graph.images ) { + auto& image = graph.storage.images.map.at(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& name : graph.textures ) { + auto& texture = graph.storage.textures.map.at(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& name : graph.samplers ) { + auto& sampler = graph.storage.samplers.map.at(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& name : graph.materials ) { + auto& material = graph.storage.materials.map.at(name); + auto json = encode(material, settings); + json["name"] = name; + serializer["materials"].emplace_back(json); + } + }); + jobs.emplace_back([&]{ + // store light information + ext::json::reserve( serializer["lights"], graph.lights.size() ); + for ( auto pair : graph.lights ) { + auto& name = pair.first; + auto& light = pair.second; + auto json = encode(light, settings); + json["name"] = name; + serializer["lights"].emplace_back(json); + } + }); + jobs.emplace_back([&]{ + // store animation information + ext::json::reserve( serializer["animations"], graph.animations.size() ); + if ( !settings.combined ) { + for ( auto& name : graph.animations ) { + uf::stl::string f = "animation."+name+".json"; + auto& animation = graph.storage.animations.map.at(name); + encode(animation, settings).writeToFile(directory+"/animation."+name+".json", settings); + serializer["animations"].emplace_back("animation."+name+".json" + (settings.compress ? ".gz" : "")); + } + } else { + for ( auto& name : graph.animations ) { + auto& animation = graph.storage.animations.map.at(name); + serializer["animations"][name] = encode(animation, settings); + } + } + }); + jobs.emplace_back([&]{ + // store skin information + ext::json::reserve( serializer["skins"], graph.skins.size() ); + for ( auto& name : graph.skins ) { + auto& skin = graph.storage.skins.map.at(name); + serializer["skins"].emplace_back( encode(skin, settings) ); + } + }); jobs.emplace_back([&]{ // store node information ext::json::reserve( serializer["nodes"], graph.nodes.size() ); diff --git a/engine/src/engine/object/behaviors/graph.cpp b/engine/src/engine/object/behaviors/graph.cpp index d3580cb8..cc4367ab 100644 --- a/engine/src/engine/object/behaviors/graph.cpp +++ b/engine/src/engine/object/behaviors/graph.cpp @@ -66,6 +66,10 @@ void uf::GraphBehavior::initialize( uf::Object& self ) { } void uf::GraphBehavior::destroy( uf::Object& self ) {} void uf::GraphBehavior::tick( uf::Object& self ) { + if ( this->hasComponent() ) { + auto& graph = this->getComponent(); + uf::graph::update( graph ); + } #if 0 /* Update animations */ if ( this->hasComponent() ) { auto& graph = this->getComponent(); diff --git a/engine/src/engine/object/behaviors/render.cpp b/engine/src/engine/object/behaviors/render.cpp index 69b56473..840d7d14 100644 --- a/engine/src/engine/object/behaviors/render.cpp +++ b/engine/src/engine/object/behaviors/render.cpp @@ -18,6 +18,7 @@ UF_BEHAVIOR_TRAITS_CPP(uf::RenderBehavior, ticks = true, renders = true, multith #define this (&self) void uf::RenderBehavior::initialize( uf::Object& self ) {} void uf::RenderBehavior::tick( uf::Object& self ) { +#if 0 if ( !this->hasComponent() ) return; const auto& metadata = this->getComponent(); const auto& scene = uf::scene::getCurrentScene(); @@ -67,8 +68,10 @@ void uf::RenderBehavior::tick( uf::Object& self ) { #endif } #endif +#endif } void uf::RenderBehavior::render( uf::Object& self ) { +#if 0 if ( !this->hasComponent() ) return; const auto& metadata = this->getComponent(); const auto& scene = uf::scene::getCurrentScene(); @@ -119,7 +122,7 @@ void uf::RenderBehavior::render( uf::Object& self ) { #endif #endif } - +#endif #endif } void uf::RenderBehavior::destroy( uf::Object& self ) {} diff --git a/engine/src/ext/bullet/bullet.cpp b/engine/src/ext/bullet/bullet.cpp index 2029336d..43c21a90 100644 --- a/engine/src/ext/bullet/bullet.cpp +++ b/engine/src/ext/bullet/bullet.cpp @@ -5,8 +5,21 @@ #include #include #include +#include #include +struct VertexLine { + pod::Vector3f position; + pod::Vector3f color; + + static UF_API uf::stl::vector descriptor; +}; + +UF_VERTEX_DESCRIPTOR(VertexLine, + UF_VERTEX_DESCRIPTION(VertexLine, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(VertexLine, R32G32B32_SFLOAT, color) +); + class BulletDebugDrawer : public btIDebugDraw { protected: int m; @@ -16,15 +29,19 @@ public: drawLine( from, to, color, color ); } virtual void drawLine( const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor ) { - 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); + uf::stl::vector vertices; + { + auto& vertex = vertices.emplace_back(); + vertex.position = { from.getX(), from.getY(), from.getZ() }; + vertex.color = { fromColor.getX(), fromColor.getY(), fromColor.getZ() }; + } + { + auto& vertex = vertices.emplace_back(); + vertex.position = { to.getX(), to.getY(), to.getZ() }; + vertex.color = { toColor.getX(), toColor.getY(), toColor.getZ() }; + } + if ( !mesh.hasVertex() ) mesh.bind(); + mesh.insertVertices(vertices); } virtual void drawContactPoint(const btVector3&, const btVector3&, btScalar, int, const btVector3&) { @@ -39,7 +56,9 @@ public: m = p; } virtual void clearLines() { - mesh.destroy(); + for ( auto& buffer : mesh.buffers ) buffer.clear(); + mesh.vertex.count = 0; + mesh.index.count = 0; } virtual void flushLines() { auto& scene = uf::scene::getCurrentScene(); @@ -113,6 +132,9 @@ void ext::bullet::initialize() { ext::bullet::debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe); ext::bullet::dynamicsWorld->setDebugDrawer(&ext::bullet::debugDrawer); + auto& mesh = ext::bullet::debugDrawer.getMesh(); + mesh.bind(); + #if !UF_ENV_DREAMCAST gContactAddedCallback = contactCallback; #endif @@ -276,42 +298,110 @@ void ext::bullet::detach( pod::Bullet& collider ) { } pod::Bullet& ext::bullet::create( uf::Object& object, const uf::Mesh& mesh, bool dynamic ) { - auto& transform = object.getComponent>(); + btTriangleIndexVertexArray* bMesh = new btTriangleIndexVertexArray(); + + if ( mesh.index.count ) { + uf::Mesh::Attribute vertexAttribute; + for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; } + UF_ASSERT( vertexAttribute.descriptor.name == "position" ); + + auto& indexAttribute = mesh.index.attributes.front(); + PHY_ScalarType indexType = PHY_INTEGER; + PHY_ScalarType vertexType = PHY_FLOAT; + switch ( mesh.index.stride ) { + case sizeof(uint8_t): indexType = PHY_UCHAR; break; + case sizeof(uint16_t): indexType = PHY_SHORT; break; + case sizeof(uint32_t): indexType = PHY_INTEGER; break; + default: UF_EXCEPTION("unsupported index type"); break; + } + + btIndexedMesh iMesh; + if ( mesh.indirect.count ) { + uf::Mesh::Attribute remappedVertexAttribute; + uf::Mesh::Attribute remappedIndexAttribute; + for ( auto i = 0; i < mesh.indirect.count; ++i ) { + remappedVertexAttribute = mesh.remapVertexAttribute( vertexAttribute, i ); + remappedIndexAttribute = mesh.remapIndexAttribute( indexAttribute, i ); + + iMesh.m_numTriangles = remappedIndexAttribute.length / 3; + iMesh.m_triangleIndexBase = (const uint8_t*) remappedIndexAttribute.pointer; + iMesh.m_triangleIndexStride = remappedIndexAttribute.stride * 3; + + iMesh.m_numVertices = remappedVertexAttribute.length; + iMesh.m_vertexBase = (const uint8_t*) remappedVertexAttribute.pointer; + iMesh.m_vertexStride = remappedVertexAttribute.stride; + iMesh.m_indexType = indexType; + iMesh.m_vertexType = vertexType; + + bMesh->addIndexedMesh( iMesh, indexType ); + } + } else { + iMesh.m_numTriangles = indexAttribute.length / 3; + iMesh.m_triangleIndexBase = (const uint8_t*) indexAttribute.pointer; + iMesh.m_triangleIndexStride = indexAttribute.stride * 3; + + iMesh.m_numVertices = vertexAttribute.length; + iMesh.m_vertexBase = (const uint8_t*) vertexAttribute.pointer; + iMesh.m_vertexStride = vertexAttribute.stride; + iMesh.m_indexType = indexType; + iMesh.m_vertexType = vertexType; + bMesh->addIndexedMesh( iMesh, indexType ); + } + } else UF_EXCEPTION("to-do: not require indices for meshes"); auto& collider = ext::bullet::create( object ); - auto model = uf::transform::model( collider.transform ); - - btTriangleMesh* bMesh = new btTriangleMesh( true, false ); - 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 ); - } - } - } - - collider.shape = new btBvhTriangleMeshShape(bMesh, true); + collider.shape = new btBvhTriangleMeshShape( bMesh, true, true ); ext::bullet::attach( collider ); + auto& transform = object.getComponent>(); + auto model = uf::transform::model( collider.transform ); + btTransform t = collider.body->getWorldTransform(); + t.setFromOpenGLMatrix(&model[0]); + collider.body->setWorldTransform(t); + collider.body->setCenterOfMassTransform(t); + + btBvhTriangleMeshShape* triangleMeshShape = (btBvhTriangleMeshShape*) collider.shape; + btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap(); + triangleInfoMap->m_edgeDistanceThreshold = 0.01f; + 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 void* verticesPointer, size_t verticesCount, size_t verticesStride, const void* indicesPointer, size_t indicesCount, size_t indicesStride, bool dynamic ) { + btTriangleIndexVertexArray* bMesh = new btTriangleIndexVertexArray(); + + if ( indicesCount ) { + PHY_ScalarType indexType = PHY_INTEGER; + PHY_ScalarType vertexType = PHY_FLOAT; + switch ( indicesStride ) { + case 1: indexType = PHY_UCHAR; break; + case 2: indexType = PHY_SHORT; break; + case 4: indexType = PHY_INTEGER; break; + } + + const uint8_t* indicesBuffer = (const uint8_t*) indicesPointer; + const uint8_t* verticesBuffer = (const uint8_t*) verticesPointer; + + btIndexedMesh iMesh; + iMesh.m_numTriangles = indicesCount / 3; + iMesh.m_triangleIndexBase = indicesBuffer; + iMesh.m_triangleIndexStride = 3 * indicesStride; + iMesh.m_numVertices = verticesCount; + iMesh.m_vertexBase = verticesBuffer; + iMesh.m_vertexStride = verticesStride; + iMesh.m_indexType = indexType; + iMesh.m_vertexType = vertexType; + bMesh->addIndexedMesh( iMesh, indexType ); + } else UF_EXCEPTION("to-do: not require indices for meshes"); + + + auto& collider = ext::bullet::create( object ); + collider.shape = new btBvhTriangleMeshShape( bMesh, true, true ); + ext::bullet::attach( collider ); + + auto& transform = object.getComponent>(); + auto model = uf::transform::model( collider.transform ); btTransform t = collider.body->getWorldTransform(); t.setFromOpenGLMatrix(&model[0]); collider.body->setWorldTransform(t); @@ -443,33 +533,32 @@ 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(); - mesh.bind(); - if ( !mesh.vertex.count ) return; bool create = !object.hasComponent(); auto& graphic = object.getComponent(); graphic.process = false; if ( create ) { - graphic.process = true; - graphic.device = &uf::renderer::device; graphic.material.device = &uf::renderer::device; graphic.descriptor.cullMode = uf::renderer::enums::CullMode::NONE; - graphic.material.attachShader(uf::io::root + "/shaders/base/colored.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root + "/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.metadata.json["shader"]["autoInitializeUniformBuffers"] = false; - graphic.initialize(); + graphic.material.attachShader(uf::io::root + "/shaders/bullet/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root + "/shaders/bullet/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + + graphic.material.getShader("vertex").buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + + graphic.initialize("Gui"); 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 ); - graphic.getPipeline().update( graphic ); + graphic.updateMesh( mesh ); } + graphic.process = true; } #endif \ No newline at end of file diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index 4b0cacfc..c8290151 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -133,11 +133,26 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize return graph; } + // load images + { + graph.images.reserve(model.images.size()); + graph.storage.images.reserve(model.images.size()); + + for ( auto& i : model.images ) { + auto imageID = graph.images.size(); + auto keyName = graph.images.emplace_back(filename + "/" + i.name); + auto& image = graph.storage.images[keyName]; + image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, true ); + } + } // load samplers { - uf::graph::storage.samplers.reserve(model.samplers.size()); + graph.storage.samplers.reserve(model.samplers.size()); for ( auto& s : model.samplers ) { - auto& sampler = uf::graph::storage.samplers[graph.samplers.emplace_back(s.name)]; + auto samplerID = graph.samplers.size(); + auto keyName = graph.samplers.emplace_back(filename + "/" + s.name); + auto& sampler = graph.storage.samplers[keyName]; + sampler.descriptor.filter.min = getFilterMode( s.minFilter ); sampler.descriptor.filter.mag = getFilterMode( s.magFilter ); sampler.descriptor.addressMode.u = getWrapMode( s.wrapS ); @@ -145,44 +160,30 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize sampler.descriptor.addressMode.w = sampler.descriptor.addressMode.v; } } - - // load images - { - uf::graph::storage.images.reserve(model.images.size()); - for ( auto& i : model.images ) { - 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 ( graph.metadata["flags"]["ATLAS"].as() ) { - // uf::graph::storage.atlases[filename].generate(); - } // load textures { - uf::graph::storage.textures.reserve(model.textures.size()); + graph.textures.reserve(model.textures.size()); + graph.storage.textures.reserve(model.textures.size()); + for ( auto& t : model.textures ) { - auto& texture = uf::graph::storage.textures[graph.textures.emplace_back(t.name)]; + auto textureID = graph.textures.size(); + auto keyName = graph.textures.emplace_back((t.name == "" ? graph.images[t.source] : (filename + "/" + t.name))); + auto& texture = graph.storage.textures[keyName]; + 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, }; - } } } - // clear source images - if ( uf::graph::storage.atlases[filename].generated() ) { - uf::graph::storage.atlases[filename].clear(false); - } // load materials { - uf::graph::storage.materials.reserve(model.materials.size()); + graph.materials.reserve(model.materials.size()); + graph.storage.materials.reserve(model.materials.size()); + for ( auto& m : model.materials ) { - auto& material = uf::graph::storage.materials[graph.materials.emplace_back(m.name)]; + auto materialID = graph.materials.size(); + auto keyName = graph.materials.emplace_back(filename + "/" + m.name); + auto& material = graph.storage.materials[keyName]; + material.indexAlbedo = m.pbrMetallicRoughness.baseColorTexture.index; material.indexNormal = m.normalTexture.index; material.indexEmissive = m.emissiveTexture.index; @@ -219,14 +220,28 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize // load meshes { graph.meshes.reserve(model.meshes.size()); - for ( auto& m : model.meshes ) { - auto& pair = uf::graph::storage.meshes[graph.meshes.emplace_back(m.name)]; - auto& mesh = pair.mesh; - mesh.bind(); + graph.storage.meshes.reserve(model.meshes.size()); + for ( auto& m : model.meshes ) { + auto meshID = graph.meshes.size(); + auto keyName = graph.meshes.emplace_back(filename + "/" + m.name); + graph.primitives.emplace_back(keyName); + graph.drawCommands.emplace_back(keyName); + + auto& drawCommands = graph.storage.drawCommands[keyName]; + auto& primitives = graph.storage.primitives[keyName]; + auto& mesh = graph.storage.meshes[keyName]; + mesh.bindIndirect(); + mesh.bind(); + /* + size_t primitiveID = 0; + */ + uf::stl::vector vertices; + uf::stl::vector indices; for ( auto& p : m.primitives ) { - uf::stl::vector vertices; - uf::stl::vector indices; + vertices.clear(); + indices.clear(); + auto& primitive = primitives.emplace_back(); struct Attribute { uf::stl::string name = ""; @@ -234,6 +249,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize uf::stl::vector floats; uf::stl::vector ints; }; + uf::stl::unordered_map attributes = { {"POSITION", {}}, {"TEXCOORD_0", {}}, @@ -254,11 +270,8 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize if ( attribute.name == "POSITION" ) { 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] }; - - pod::Vector3f origin = (maxCorner + minCorner) * 0.5f; - pod::Vector3f size = (maxCorner - minCorner) * 0.5f; + primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] }; + primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] }; } if ( attribute.name == "JOINTS_0" ) { auto* buffer = reinterpret_cast(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); @@ -300,8 +313,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize vertex.normal.x *= -1; vertex.tangent.x *= -1; } - - } if ( p.indices > -1 ) { @@ -311,9 +322,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize indices.reserve( static_cast(accessor.count) ); - #define COPY_INDICES()\ - for (size_t index = 0; index < indices.size(); index++)\ - indices.emplace_back(buf[index]); + #define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) indices.emplace_back(buf[index]); const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]); switch (accessor.componentType) { @@ -336,49 +345,46 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize #undef COPY_INDICES } - pair.drawCommands.emplace_back(pod::DrawCommand{ + primitive.instance.materialID = p.material; + primitive.instance.primitiveID = primitives.size() - 1; + primitive.instance.meshID = meshID; + primitive.instance.objectID = 0; + + primitive.drawCommand.indices = indices.size(); + primitive.drawCommand.instances = 1; + primitive.drawCommand.indexID = 0; + primitive.drawCommand.vertexID = 0; + primitive.drawCommand.instanceID = 0; + primitive.drawCommand.vertices = vertices.size(); + + auto& drawCommand = 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, + .instanceID = 0, + // .meshID = meshID, + // .objectID = materialID, .vertices = vertices.size(), }); - + mesh.insertVertices(vertices); mesh.insertIndices(indices); } + mesh.insertIndirects(drawCommands); mesh.updateDescriptor(); } } - // load node information/meshes - { - const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0]; - graph.nodes.resize( model.nodes.size() ); - graph.root.index = -1; - graph.root.children.reserve( scene.nodes.size() ); - for ( auto i : scene.nodes ) { - size_t childIndex = loadNode( model, graph, i, -1 ); - graph.root.children.emplace_back(childIndex); - } - } - // load lights - { - for ( auto& l : model.lights ) { - 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; - } - } // load skins { graph.skins.reserve( model.skins.size() ); + graph.storage.skins.reserve( model.skins.size() ); + for ( auto& s : model.skins ) { - auto& skin = graph.skins.emplace_back(); + auto skinID = graph.skins.size(); + auto keyName = graph.skins.emplace_back(filename + "/" + s.name); + auto& skin = graph.storage.skins[keyName]; + skin.name = s.name; if ( s.inverseBindMatrices > -1 ) { const tinygltf::Accessor& accessor = model.accessors[s.inverseBindMatrices]; @@ -406,8 +412,12 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize // load animations { graph.animations.reserve( model.animations.size() ); + graph.storage.animations.reserve( model.animations.size() ); + for ( auto& a : model.animations ) { - auto& animation = graph.animations[a.name]; + auto animationID = graph.animations.size(); + auto keyName = graph.animations.emplace_back(filename + "/" + a.name); + auto& animation = graph.storage.animations[keyName]; animation.name = a.name; // load samplers @@ -460,6 +470,62 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize } } } + // load lights + { + for ( auto& l : model.lights ) { + 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; + } + } + // load node information/meshes + { + const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0]; + graph.nodes.resize( model.nodes.size() ); + + graph.root.name = "%ROOT%"; + graph.root.index = -1; + graph.root.children.reserve( scene.nodes.size() ); + for ( auto i : scene.nodes ) { + size_t childIndex = loadNode( model, graph, i, -1 ); + graph.root.children.emplace_back(childIndex); + } + } + // generate atlas + if ( graph.metadata["flags"]["ATLAS"].as() ) { + auto atlasName = filename + "/" + "atlas"; + auto& atlas = graph.storage.atlases[atlasName]; + auto atlasImageIndex = graph.images.size(); + auto atlasTextureIndex = graph.textures.size(); + + for ( auto& keyName : graph.images ) atlas.addImage( graph.storage.images[keyName] ); + atlas.generate(); + + for ( auto& keyName : graph.images ) { + auto& texture = graph.storage.textures[keyName]; + if ( texture.index < 0 ) continue; + auto& image = graph.storage.images[keyName]; + + const auto& hash = image.getHash(); + auto min = atlas.mapUv( {0, 0}, hash ); + auto max = atlas.mapUv( {1, 1}, hash ); + + texture.lerp = pod::Vector4f{ min.x, min.y, max.x, max.y, }; + texture.index = atlasImageIndex; + } + + { + graph.images.emplace_back(atlasName); + auto& image = graph.storage.images[atlasName]; + image = atlas.getAtlas(); + + graph.textures.emplace_back(atlasName); + auto& texture = graph.storage.textures[atlasName]; + texture.index = atlasImageIndex; + } + } + 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/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index 160b8d82..83e12a52 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -163,61 +163,6 @@ void ext::opengl::CommandBuffer::record( const CommandBuffer::Info& header ) { info = &userdata.get(); info->type = enums::Command::DRAW; } break; - /* - case ext::opengl::enums::Command::BIND_BUFFER: { - InfoBuffer* info = (InfoBuffer*) &header; - info->next = NULL; - auto& userdata = infos.emplace_back(); - userdata.autoDestruct = false; - userdata.create( *info ); - info = &userdata.get(); - info->type = enums::Command::BIND_BUFFER; - } break; - case ext::opengl::enums::Command::BIND_GRAPHIC_BUFFER: { - InfoGraphicBuffer* info = (InfoGraphicBuffer*) &header; - info->next = NULL; - auto& userdata = infos.emplace_back(); - userdata.autoDestruct = false; - userdata.create( *info ); - info = &userdata.get(); - info->type = enums::Command::BIND_GRAPHIC_BUFFER; - } break; - case ext::opengl::enums::Command::BIND_TEXTURE: { - InfoTexture* info = (InfoTexture*) &header; - info->next = NULL; - auto& userdata = infos.emplace_back(); - userdata.autoDestruct = false; - userdata.create( *info ); - info = &userdata.get(); - info->type = enums::Command::BIND_TEXTURE; - } break; - case ext::opengl::enums::Command::BIND_PIPELINE: { - InfoPipeline* info = (InfoPipeline*) &header; - info->next = NULL; - auto& userdata = infos.emplace_back(); - userdata.autoDestruct = false; - userdata.create( *info ); - info = &userdata.get(); - info->type = enums::Command::BIND_PIPELINE; - } break; - case ext::opengl::enums::Command::DRAW: { - InfoDraw* info = (InfoDraw*) &header; - info->next = NULL; - auto& userdata = infos.emplace_back(); - userdata.autoDestruct = false; - userdata.create( *info ); - info = &userdata.get(); - info->type = enums::Command::DRAW; - } break; - case ext::opengl::enums::Command::GENERATE_TEXTURE: { - InfoGenerateTexture* info = (InfoGenerateTexture*) &header; - auto& userdata = infos.emplace_back(); - userdata.autoDestruct = false; - userdata.create( *info ); - info = &userdata.get(); - info->type = enums::Command::GENERATE_TEXTURE; - } break; - */ default: { } break; } @@ -271,82 +216,6 @@ void ext::opengl::CommandBuffer::submit() { } break; } } -#if 0 - CommandBuffer::Info* vertexBufferInfo = GL_NULL_HANDLE; - CommandBuffer::Info* indexBufferInfo = GL_NULL_HANDLE; - uf::stl::vector textureInfos; - textureInfos.reserve(maxTextures); - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "==== ["<type ) { - case ext::opengl::enums::Command::CLEAR: { - InfoClear* info = (InfoClear*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<color ) << " | DEPTH: " << info->depth << " | BITS: " << std::bitset<32>(info->bits) << "\n"; - GL_ERROR_CHECK(glClearColor(info->color[0], info->color[1], info->color[2], info->color[3])); - GL_ERROR_CHECK(glClearDepth(info->depth)); - GL_ERROR_CHECK(glClear(info->bits)); - GL_ERROR_CHECK(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &info->color[0])); - } break; - case ext::opengl::enums::Command::VIEWPORT: { - InfoViewport* info = (InfoViewport*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<corner) << " | " << uf::vector::toString(info->size) << "\n"; - GL_ERROR_CHECK(glViewport(info->corner[0], info->corner[1], info->size[0], info->size[1])); - } break; - case ext::opengl::enums::Command::VARIANT: { - InfoVariant* info = (InfoVariant*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<lambda ) info->lambda(); - } break; - case ext::opengl::enums::Command::BIND_BUFFER: { - InfoBuffer* info = (InfoBuffer*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<descriptor.buffer << " | FLAGS: " << /*std::bitset<16>*/(info->usage) << "\n"; - if ( info->usage & enums::Buffer::UNIFORM ) bindUniform( info->descriptor ); - if ( info->usage & enums::Buffer::VERTEX ) vertexBufferInfo = header; - if ( info->usage & enums::Buffer::INDEX ) indexBufferInfo = header; - } break; - case ext::opengl::enums::Command::BIND_GRAPHIC_BUFFER: { - InfoGraphicBuffer* info = (InfoGraphicBuffer*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<graphic->buffers[info->bufferIndex]; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << buffer.descriptor.buffer << " | FLAGS: " << /*std::bitset<16>*/(buffer.usage) << "\n"; - if ( buffer.usage & enums::Buffer::UNIFORM ) bindUniform( buffer.descriptor ); - if ( buffer.usage & enums::Buffer::VERTEX ) vertexBufferInfo = header; - if ( buffer.usage & enums::Buffer::INDEX ) indexBufferInfo = header; - } break; - case ext::opengl::enums::Command::BIND_TEXTURE: { - InfoTexture* info = (InfoTexture*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<descriptor.image << " | " << info->descriptor.viewType << "\n"; - textureInfos.emplace_back(info); - } break; - case ext::opengl::enums::Command::BIND_PIPELINE: { - InfoPipeline* info = (InfoPipeline*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<descriptor.pipeline << " | " << info->descriptor.vertexArray << "\n"; - #if !UF_USE_OPENGL_FIXED_FUNCTION - GL_ERROR_CHECK(glUseProgram(info->descriptor.pipeline)); - #endif - } break; - case ext::opengl::enums::Command::DRAW: { - InfoDraw* info = (InfoDraw*) header; - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<length << " | VERTEX INFO: " << vertexBufferInfo << " | INDEX INFO: " << indexBufferInfo << "\n"; - if ( vertexBufferInfo ) { - if ( indexBufferInfo ) drawIndexed( *info, *vertexBufferInfo, *indexBufferInfo, textureInfos ); - else draw( *info, *vertexBufferInfo, textureInfos ); - } - textureInfos.clear(); - vertexBufferInfo = NULL; - indexBufferInfo = NULL; - } break; - default: { - if ( state == 2 && VERBOSE_SUBMIT ) { - std::cout << "["<type << ": " << info.data().len << std::endl;; - } - } break; - } - } - if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "==== ["<unlock(); } @@ -355,10 +224,6 @@ void ext::opengl::CommandBuffer::flush() { for ( auto& userdata : infos ) userdata.destroy(); infos.clear(); state = 0; -/* - startInfo = NULL; - endInfo = NULL; -*/ mutex->unlock(); } size_t ext::opengl::CommandBuffer::size() const { @@ -378,164 +243,6 @@ pod::Matrix4f ext::opengl::CommandBuffer::bindUniform( const ext::opengl::Buffer return uniform->projection * uniform->modelView; #endif } -#if 0 -void ext::opengl::CommandBuffer::draw( const ext::opengl::CommandBuffer::InfoDraw& drawInfo, const ext::opengl::CommandBuffer::Info& vertexBufferInfo, const uf::stl::vector& textureInfos ) { - ext::opengl::Buffer::Descriptor vertexBuffer = {}; - - switch ( vertexBufferInfo.type ) { - case ext::opengl::enums::Command::BIND_BUFFER: { - ext::opengl::CommandBuffer::InfoBuffer* info = (ext::opengl::CommandBuffer::InfoBuffer*) &vertexBufferInfo; - vertexBuffer = info->descriptor; - } break; - case ext::opengl::enums::Command::BIND_GRAPHIC_BUFFER: { - ext::opengl::CommandBuffer::InfoGraphicBuffer* info = (ext::opengl::CommandBuffer::InfoGraphicBuffer*) &vertexBufferInfo; - vertexBuffer = info->graphic->buffers[info->bufferIndex].descriptor; - } break; - } - if ( !vertexBuffer.buffer ) return; - - size_t vertexStride = drawInfo.descriptor.attributes.vertex.size; - size_t vertices = vertexBuffer.range / vertexStride; - - uf::renderer::AttributeDescriptor vertexAttributePosition, - vertexAttributeNormal, - vertexAttributeColor, - vertexAttributeUv, - vertexAttributeSt, - vertexAttributeId; - - 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; - else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; - else if ( attribute.name == "st" ) vertexAttributeSt = attribute; - else if ( attribute.name == "id" ) vertexAttributeId = attribute; - } - if ( vertexAttributePosition.name == "" ) return; - - if ( drawInfo.descriptor.cullMode == GL_NONE ) { - GL_ERROR_CHECK(glDisable(GL_CULL_FACE)); - } else { - GL_ERROR_CHECK(glEnable(GL_CULL_FACE)); - GL_ERROR_CHECK(glFrontFace(drawInfo.descriptor.frontFace)); - GL_ERROR_CHECK(glCullFace(drawInfo.descriptor.cullMode)); - } - if ( drawInfo.descriptor.depth.test ) { - GL_ERROR_CHECK(glEnable(GL_DEPTH_TEST)); - } else { - GL_ERROR_CHECK(glDisable(GL_DEPTH_TEST)); - } - GL_ERROR_CHECK(glDepthMask(drawInfo.descriptor.depth.write ? GL_TRUE : GL_FALSE)); - - // GPU-buffer based command dispatching -#if !UF_USE_OPENGL_FIXED_FUNCTION - -#else - // CPU-buffer based command dispatching - uint8_t* vertexPointer = (uint8_t*) ( device->getBuffer( vertexBuffer.buffer ) + vertexBuffer.offset ); - - // vertices do not need to be transformed - //if ( vertexAttributeId.name == "" ) -#if !UF_USE_OPENGL_IMMEDIATE_MODE - if ( vertexAttributeNormal.name != "" ) GL_ERROR_CHECK(glEnableClientState(GL_NORMAL_ARRAY)); - if ( vertexAttributeColor.name != "" )GL_ERROR_CHECK(glEnableClientState(GL_COLOR_ARRAY)); - if ( vertexAttributeUv.name != "" ) GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); - GL_ERROR_CHECK(glEnableClientState(GL_VERTEX_ARRAY)); - - - // no ID attribute found, fallback - if ( vertexAttributeId.name == "" ) { - if ( !textureInfos.empty() ) { - InfoTexture* info = textureInfos.front(); - GL_ERROR_CHECK(glEnable(info->descriptor.viewType)); - GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image)); - } - GL_BIND_POINTERS(); - GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, 0, vertices)); - } else { - if ( textureInfos.empty() ) { - GL_BIND_POINTERS(); - GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, 0, vertices)); - } else if ( textureInfos.size() == 1 ) { - InfoTexture* info = textureInfos.front(); - GL_ERROR_CHECK(glEnable(info->descriptor.viewType)); - GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image)); - GL_BIND_POINTERS(); - GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, 0, vertices)); - } else { - uf::stl::vector> sorted( textureInfos.size() ); - for ( uf::renderer::index_t index = 0; index < vertices; ++index ) { - uint8_t* vertex = vertexPointer + (index * vertexStride); - - const pod::Vector& id = *((pod::Vector*) (vertex + vertexAttributeId.offset)); - size_t textureId = id.y; - if ( textureInfos.size() < textureId ) continue; - sorted[textureId].emplace_back(index); - } - GLenum indicesType = GL_UNSIGNED_INT; - switch ( sizeof(uf::renderer::index_t) ) { - case sizeof(uint32_t): indicesType = GL_UNSIGNED_INT; break; - case sizeof(uint16_t): indicesType = GL_UNSIGNED_SHORT; break; - case sizeof(uint8_t): indicesType = GL_UNSIGNED_BYTE; break; - } - for ( size_t textureId = 0; textureId < sorted.size(); ++textureId ) { - auto& indices = sorted[textureId]; - if ( indices.empty() ) continue; - InfoTexture* info = textureInfos[textureId]; - GL_ERROR_CHECK(glEnable(info->descriptor.viewType)); - GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image)); - GL_BIND_POINTERS(); - GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, indices.size(), indicesType, &indices[0])); - } - } - } - - if ( vertexAttributeNormal.name != "" ) GL_ERROR_CHECK(glDisableClientState(GL_NORMAL_ARRAY)); - if ( vertexAttributeColor.name != "" ) GL_ERROR_CHECK(glDisableClientState(GL_COLOR_ARRAY)); - if ( vertexAttributeUv.name != "" ) GL_ERROR_CHECK(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); - GL_ERROR_CHECK(glDisableClientState(GL_VERTEX_ARRAY)); -#else - // no ID attribute found, fallback - if ( vertexAttributeId.name == "" ) { - if ( !textureInfos.empty() ) { - InfoTexture* info = textureInfos.front(); - GL_ERROR_CHECK(glEnable(info->descriptor.viewType)); - GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image)); - } - GL_DRAW_ARRAYS( vertexPointer, vertices ); - } else { - if ( textureInfos.empty() ) { - GL_DRAW_ARRAYS( vertexPointer, vertices ); - } else if ( textureInfos.size() == 1 ) { - InfoTexture* info = textureInfos.front(); - GL_ERROR_CHECK(glEnable(info->descriptor.viewType)); - GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image)); - GL_DRAW_ARRAYS( vertexPointer, vertices ); - } else { - uf::stl::vector> sorted( textureInfos.size() ); - for ( uf::renderer::index_t index = 0; index < vertices; ++index ) { - uint8_t* vertex = vertexPointer + (index * vertexStride); - - const pod::Vector& id = *((pod::Vector*) (vertex + vertexAttributeId.offset)); - size_t textureId = id.y; - if ( textureInfos.size() < textureId ) continue; - sorted[textureId].emplace_back(index); - } - for ( size_t textureId = 0; textureId < sorted.size(); ++textureId ) { - auto& indices = sorted[textureId]; - if ( indices.empty() ) continue; - InfoTexture* info = textureInfos[textureId]; - GL_ERROR_CHECK(glEnable(info->descriptor.viewType)); - GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image)); - GL_DRAW_ELEMENTS( (&indices[0]) , (indices.size()) ); - } - } - } -#endif -#endif -} -#endif void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::InfoDraw& drawInfo ) { auto projectionViewMatrix = bindUniform( drawInfo.uniformBuffer ); @@ -601,7 +308,8 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glVertexPointer(3, GL_FLOAT, vertexStride, vertexPointer + drawInfo.attributes.position)); // frustrum culling - if ( ext::opengl::settings::experimental::frustrumCull ) { +#if 0 + if ( ext::opengl::settings::experimental::culling ) { uf::stl::vector unculled; unculled.reserve(indices); for ( size_t currentIndex = 0; currentIndex < indices; currentIndex += 3 ) { @@ -641,6 +349,9 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: } else { GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, indices, indicesType, indicesPointer)); } +#else + GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, indices, indicesType, indicesPointer)); +#endif if ( drawInfo.auxTexture.image ) { #if UF_ENV_DREAMCAST diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index 8cb78429..44238818 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -38,9 +38,9 @@ bool ext::opengl::settings::experimental::deferredAliasOutputToSwapchain = true; bool ext::opengl::settings::experimental::multiview = true; bool ext::opengl::settings::experimental::vsync = true; bool ext::opengl::settings::experimental::hdr = true; -bool ext::opengl::settings::experimental::frustrumCull = false; bool ext::opengl::settings::experimental::vxgi = true; bool ext::opengl::settings::experimental::deferredSampling = true; +bool ext::opengl::settings::experimental::culling = false; GLhandle(VkColorSpaceKHR) ext::opengl::settings::formats::colorSpace; ext::opengl::enums::Format::type_t ext::opengl::settings::formats::color = ext::opengl::enums::Format::R8G8B8A8_UNORM; @@ -171,7 +171,7 @@ void UF_API ext::opengl::initialize() { // bind shaders #if !UF_ENV_DREAMCAST { - ext::opengl::Shader::bind( uf::io::root + "shaders/gltf/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { + ext::opengl::Shader::bind( uf::io::root + "shaders/graph/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { if ( !userdata ) return; uint8_t* verticesSrc = (uint8_t*) userdata; @@ -240,7 +240,7 @@ void UF_API ext::opengl::initialize() { } } }); - ext::opengl::Shader::bind( uf::io::root + "shaders/gltf/skinned.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { + ext::opengl::Shader::bind( uf::io::root + "shaders/graph/skinned.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { if ( !userdata ) return; uint8_t* verticesSrc = (uint8_t*) userdata; diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index c9e391c0..421371ff 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -55,31 +55,14 @@ void ext::vulkan::Buffer::copyTo( void* data, VkDeviceSize size ) { } VkResult ext::vulkan::Buffer::flush( VkDeviceSize size, VkDeviceSize offset ) const { -/* - VkMappedMemoryRange mappedRange = {}; - mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mappedRange.memory = memory; - mappedRange.offset = offset; - mappedRange.size = size; - return vkFlushMappedMemoryRanges(device, 1, &mappedRange); -*/ return VK_SUCCESS; } VkResult ext::vulkan::Buffer::invalidate( VkDeviceSize size, VkDeviceSize offset ) { -/* - VkMappedMemoryRange mappedRange = {}; - mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mappedRange.memory = memory; - mappedRange.offset = offset; - mappedRange.size = size; - return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange); -*/ return VK_SUCCESS; } void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) { -// VK_CHECK_RESULT(vkCreateBuffer( device, &bufferCreateInfo, nullptr, &buffer)); VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; @@ -89,10 +72,6 @@ void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) { } vmaCreateBuffer( allocator, &bufferCreateInfo, &allocCreateInfo, &buffer, &allocation, &allocationInfo ); -// VkMemoryPropertyFlags memFlags; -// vmaGetMemoryTypeProperties(allocator, allocationInfo.memoryType, &memFlags); -// memory = allocationInfo.deviceMemory; -// size = allocationInfo.size; } // RAII @@ -107,14 +86,13 @@ void ext::vulkan::Buffer::destroy() { if ( buffer ) { vmaDestroyBuffer( allocator, buffer, allocation ); -// vkDestroyBuffer(device, buffer, nullptr); } -// if ( memory ) vkFreeMemory(device, memory, nullptr); buffer = nullptr; memory = nullptr; } void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) { + if ( !device ) device = &ext::vulkan::device; if ( stage ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties VK_CHECK_RESULT(device->createBuffer( usage, @@ -122,9 +100,11 @@ void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkB *this, length )); - if ( data ) update( data, length, stage ); + if ( data && length ) update( data, length, stage ); } void ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool stage ) const { + if ( !data || !length ) return; + if ( length > allocationInfo.size ) { UF_MSG_DEBUG("LENGTH OF " << length << " EXCEEDS BUFFER SIZE " << allocationInfo.size ); Buffer& b = *const_cast(this); @@ -141,6 +121,8 @@ void ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st } Buffer staging; + + ext::vulkan::Device* device = this->device ? this->device : &ext::vulkan::device; device->createBuffer( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 1b126de9..e09914e3 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -42,15 +43,16 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes uf::stl::vector blendAttachmentStates; uf::stl::vector shaderDescriptors; + uf::stl::vector shaderSpecializationInfos; uf::stl::vector inputBindingDescriptions; uf::stl::vector attributeDescriptions; { for ( auto* shaderPointer : shaders ) { auto& shader = *shaderPointer; - descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); + descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.end(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); - std::size_t offset = 0; + size_t offset = 0; for ( auto& pushConstant : shader.pushConstants ) { size_t len = pushConstant.data().len; if ( len <= 0 || len > device.properties.limits.maxPushConstantsSize ) { @@ -186,6 +188,15 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes descriptor.depth.write, descriptor.depth.operation ); + if ( uf::matrix::reverseInfiniteProjection ) { + depthStencilState.depthCompareOp = ext::vulkan::enums::Compare::GREATER_OR_EQUAL; + depthStencilState.minDepthBounds = 1.0f; + depthStencilState.maxDepthBounds = 0.0f; + } else { + depthStencilState.depthCompareOp = ext::vulkan::enums::Compare::LESS; + depthStencilState.minDepthBounds = 0.0f; + depthStencilState.maxDepthBounds = 1.0f; + } VkPipelineViewportStateCreateInfo viewportState = ext::vulkan::initializers::pipelineViewportStateCreateInfo( 1, 1, 0 ); @@ -250,7 +261,38 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes vertexInputState.vertexAttributeDescriptionCount = attributeDescriptions.size(); vertexInputState.pVertexAttributeDescriptions = attributeDescriptions.data(); + #if 0 + for ( auto* SHADER : shaders ) { + ext::vulkan::Shader* shader = const_cast(SHADER); + void* s = (void*) shader->specializationConstants; + size_t len = shader->specializationConstants.data().len; + bool invalidated = true; + for ( auto pair : shader->metadata.definitions.specializationConstants ) { + auto& name = pair.first; + auto& payload = pair.second; + uf::stl::string type = payload.type; + if ( type == "int32_t" ) { + int32_t& v = ((int32_t*) s)[payload.index]; + UF_MSG_DEBUG("SC " << payload.name << " = " << v << " = " << payload.value.i << "`" << shader->filename << "`"); + if ( payload.validate && v != payload.value.i ) v = payload.value.i; + payload.value.i = v; + } else if ( type == "uint32_t" ) { + uint32_t& v = ((uint32_t*) s)[payload.index]; + UF_MSG_DEBUG("SC " << payload.name << " = " << v << " = " << payload.value.ui << "`" << shader->filename << "`"); + if ( payload.validate && v != payload.value.ui ) v = payload.value.ui; + payload.value.ui = v; + } else if ( type == "float" ) { + float& v = ((float*) s)[payload.index]; + UF_MSG_DEBUG("SC " << payload.name << " = " << v << " = " << payload.value.f << "`" << shader->filename << "`"); + if ( payload.validate && v != payload.value.f ) v = payload.value.f; + payload.value.f = v; + } + } + shaderDescriptors.push_back(shader->descriptor); + } + #else for ( auto* shader : shaders ) shaderDescriptors.emplace_back(shader->descriptor); + #endif VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo( pipelineLayout, @@ -287,15 +329,15 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer comm auto shaders = getShaders( graphic.material.shaders ); for ( auto* shader : shaders ) { if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; - #if 0 + #if 1 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 ); - } + if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT || shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) { + struct PushConstant { + uint32_t pass; + uint32_t draw; + } pushConstant = { pass, draw }; + vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, sizeof(pushConstant), &pushConstant ); + } } else #endif if ( !shader->pushConstants.empty() ) { @@ -332,6 +374,10 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer comm // Bind the rendering pipeline // The pipeline (state object) contains all states of the rendering pipeline, binding it will set all the states specified at pipeline creation time vkCmdBindPipeline(commandBuffer, bindPoint, pipeline); + + if ( bindPoint == VK_PIPELINE_BIND_POINT_COMPUTE && descriptor.inputs.dispatch.x != 0 && descriptor.inputs.dispatch.y != 0 && descriptor.inputs.dispatch.z != 0 ) { + vkCmdDispatch(commandBuffer, descriptor.inputs.dispatch.x, descriptor.inputs.dispatch.y, descriptor.inputs.dispatch.z); + } } void ext::vulkan::Pipeline::update( const Graphic& graphic ) { return this->update( graphic, descriptor ); @@ -348,7 +394,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip auto shaders = getShaders( graphic.material.shaders ); uf::stl::vector writeDescriptorSets; - struct { + struct Infos { uf::stl::vector uniform; uf::stl::vector storage; @@ -360,35 +406,38 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip uf::stl::vector sampler; uf::stl::vector input; - } infos; + }; + uf::stl::vector INFOS; INFOS.reserve( shaders.size() ); - uf::stl::vector types; - - if ( descriptor.subpass < renderTarget.passes.size() ) { - auto& subpass = renderTarget.passes[descriptor.subpass]; - for ( auto& input : subpass.inputs ) { - infos.input.emplace_back(ext::vulkan::initializers::descriptorImageInfo( - renderTarget.attachments[input.attachment].views[subpass.layer], - input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout - )); - } - } - - 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); - } - - size_t consumes = 0; for ( auto* shader : shaders ) { + auto& infos = INFOS.emplace_back(); + + uf::stl::vector types; + + if ( descriptor.subpass < renderTarget.passes.size() ) { + auto& subpass = renderTarget.passes[descriptor.subpass]; + for ( auto& input : subpass.inputs ) { + infos.input.emplace_back(ext::vulkan::initializers::descriptorImageInfo( + renderTarget.attachments[input.attachment].views[subpass.layer], + input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout + )); + } + } + + 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); + } + + size_t consumes = 0; 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); @@ -408,45 +457,43 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip } break; } } - } - - size_t maxTextures2D = 0; - size_t maxTextures3D = 0; - size_t maxTexturesCube = 0; - size_t maxTexturesUnknown = 0; - for ( auto& type : types ) { - if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) ++maxTextures3D; - else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) ++maxTexturesCube; - else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) ++maxTextures2D; - else ++maxTexturesUnknown; - } + + size_t maxTextures2D = 0; + size_t maxTextures3D = 0; + size_t maxTexturesCube = 0; + size_t maxTexturesUnknown = 0; + for ( auto& type : types ) { + if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) ++maxTextures3D; + else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) ++maxTexturesCube; + else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) ++maxTextures2D; + else ++maxTexturesUnknown; + } - while ( infos.image2D.size() < maxTextures2D ) infos.image2D.emplace_back(Texture2D::empty.descriptor); - while ( infos.imageCube.size() < maxTexturesCube ) infos.imageCube.emplace_back(TextureCube::empty.descriptor); - while ( infos.image3D.size() < maxTextures3D ) infos.image3D.emplace_back(Texture3D::empty.descriptor); - while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.emplace_back(Texture2D::empty.descriptor); + while ( infos.image2D.size() < maxTextures2D ) infos.image2D.emplace_back(Texture2D::empty.descriptor); + while ( infos.imageCube.size() < maxTexturesCube ) infos.imageCube.emplace_back(TextureCube::empty.descriptor); + while ( infos.image3D.size() < maxTextures3D ) infos.image3D.emplace_back(Texture3D::empty.descriptor); + while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.emplace_back(Texture2D::empty.descriptor); - for ( size_t i = infos.image.size(); i < consumes; ++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); - else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) infos.image.emplace_back(Texture2D::empty.descriptor); - else infos.image.emplace_back(Texture2D::empty.descriptor); - } - - auto uniformBufferInfo = infos.uniform.begin(); - auto storageBufferInfo = infos.storage.begin(); - - auto imageInfo = infos.image.begin(); - auto image2DInfo = infos.image2D.begin(); - auto imageCubeInfo = infos.imageCube.begin(); - auto image3DInfo = infos.image3D.begin(); - auto imageUnknownInfo = infos.imageUnknown.begin(); + for ( size_t i = infos.image.size(); i < consumes; ++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); + else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) infos.image.emplace_back(Texture2D::empty.descriptor); + else infos.image.emplace_back(Texture2D::empty.descriptor); + } + + auto uniformBufferInfo = infos.uniform.begin(); + auto storageBufferInfo = infos.storage.begin(); + + auto imageInfo = infos.image.begin(); + auto image2DInfo = infos.image2D.begin(); + auto imageCubeInfo = infos.imageCube.begin(); + auto image3DInfo = infos.image3D.begin(); + auto imageUnknownInfo = infos.imageUnknown.begin(); - auto samplerInfo = infos.sampler.begin(); - auto inputInfo = infos.input.begin(); + auto samplerInfo = infos.sampler.begin(); + auto inputInfo = infos.input.begin(); - for ( auto* shader : shaders ) { for ( auto& layout : shader->descriptorSetLayoutBindings ) { switch ( layout.descriptorType ) { // consume an texture image info @@ -635,8 +682,14 @@ void ext::vulkan::Pipeline::destroy() { uf::stl::vector ext::vulkan::Pipeline::getShaders( uf::stl::vector& shaders ) { uf::stl::unordered_map map; uf::stl::vector res; + bool isCompute = false; for ( auto& shader : shaders ) { if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; + if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true; + } + for ( auto& shader : shaders ) { + if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; + if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; map[shader.metadata.type] = &shader; } for ( auto pair : map ) res.insert( res.begin(), pair.second); @@ -645,8 +698,14 @@ uf::stl::vector ext::vulkan::Pipeline::getShaders( uf::stl uf::stl::vector ext::vulkan::Pipeline::getShaders( const uf::stl::vector& shaders ) const { uf::stl::unordered_map map; uf::stl::vector res; + bool isCompute = false; for ( auto& shader : shaders ) { if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; + if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true; + } + for ( auto& shader : shaders ) { + if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; + if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; map[shader.metadata.type] = &shader; } for ( auto pair : map ) res.insert( res.begin(), pair.second); @@ -668,9 +727,12 @@ void ext::vulkan::Material::destroy() { } void ext::vulkan::Material::attachShader( const uf::stl::string& filename, VkShaderStageFlagBits stage, const uf::stl::string& pipeline ) { auto& shader = shaders.emplace_back(); + shader.metadata.json = metadata.json["shader"]; + shader.metadata.autoInitializeUniforms = metadata.autoInitializeUniforms; shader.initialize( *device, filename, stage ); // repoint our specialization info descriptor because our shaders will change memory locations when attaching one by one + for ( auto& shader : shaders ) { shader.specializationInfo.mapEntryCount = shader.specializationMapEntries.size(); shader.specializationInfo.pMapEntries = shader.specializationMapEntries.data(); @@ -755,7 +817,6 @@ ext::vulkan::Pipeline& ext::vulkan::Graphic::initializePipeline( const GraphicDe pipeline.initialize(*this, descriptor); pipeline.update(*this, descriptor); -// process = true; initialized = true; material.validate(); @@ -763,9 +824,9 @@ ext::vulkan::Pipeline& ext::vulkan::Graphic::initializePipeline( const GraphicDe } void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { // generate indices if not found - if ( mesh.index.count == 0 ) mesh.generateIndices(); +// if ( mesh.index.count == 0 ) mesh.generateIndices(); // generate indirect data if not found - if ( mesh.indirect.count == 0 ) mesh.generateIndirect(); +// if ( mesh.indirect.count == 0 ) mesh.generateIndirect(); // ensure our descriptors are proper mesh.updateDescriptor(); @@ -776,12 +837,12 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { descriptor.inputs.indirect = mesh.indirect; // create buffer if not set and requested - if ( !initialized && buffer ) { + if ( buffer ) { // ensures each buffer index reflects nicely struct Queue { void* data; size_t size; - uf::renderer::enums::Buffer::type_t usage; + VkBufferUsageFlags usage; }; uf::stl::vector queue; descriptor.inputs.bufferOffset = buffers.empty() ? 0 : buffers.size() - 1; @@ -799,10 +860,11 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { 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) + PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT | uf::renderer::enums::Buffer::STORAGE) // allocate buffers - for ( auto& q : queue ) { + for ( auto i = 0; i < queue.size(); ++i ) { + auto& q = queue[i]; initializeBuffer( q.data, q.size, q.usage ); } } @@ -811,6 +873,54 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { descriptor.inputs.instance.count = 1; } } +void ext::vulkan::Graphic::updateMesh( uf::Mesh& mesh ) { + // 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(); + + // copy descriptors + descriptor.inputs.vertex = mesh.vertex; + descriptor.inputs.index = mesh.index; + descriptor.inputs.instance = mesh.instance; + descriptor.inputs.indirect = mesh.indirect; + + // create buffer if not set and requested + // ensures each buffer index reflects nicely + struct Queue { + void* data; + size_t size; + uf::renderer::enums::Buffer::type_t usage; + }; + uf::stl::vector queue; + + #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 i = 0; i < queue.size(); ++i ) { + auto& q = queue[i]; + updateBuffer( q.data, q.size, descriptor.inputs.bufferOffset + i ); + } + + 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; } @@ -849,44 +959,8 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD if ( !pipeline.metadata.process ) return; pipeline.record(*this, commandBuffer, pass, draw); -/* - 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); - } -*/ + auto shaders = pipeline.getShaders( material.shaders ); + for ( auto* shader : shaders ) if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return; struct { uf::stl::vector buffer; @@ -918,6 +992,26 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD 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; + + /* + .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(), + + if ( attribute.descriptor.pointer ) { + pod::DrawCommand* drawCommands = (pod::DrawCommand*) attribute.descriptor.pointer; + for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) { + auto& drawCommand = drawCommands[i]; + // UF_MSG_DEBUG( "DrawCommand[" << i << "]: " << drawCommand.indices << " " << drawCommand.instances << " " << drawCommand.indexID << " " << drawCommand.vertexID << " " << drawCommand.instanceID << " " << drawCommand.materialID << " " << drawCommand.objectID << " " << drawCommand.vertices ); + } + } + */ } for ( auto& buffer : buffers ) { @@ -941,12 +1035,36 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD } 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 - ); + const bool cpuSideIndirection = false; + if ( index.buffer && indirect.buffer && cpuSideIndirection ) { + auto& indirectAttribute = descriptor.inputs.indirect.attributes.front(); + const pod::DrawCommand* drawCommands = (const pod::DrawCommand*) indirectAttribute.pointer; + for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) { + auto& drawCommand = drawCommands[i]; + vkCmdDrawIndexed(commandBuffer, + drawCommand.indices, // indexCount + drawCommand.instances, // instanceCount + drawCommand.indexID, // firstIndex + drawCommand.vertexID, // vertexOffset + drawCommand.instanceID // firstInstance + ); + } + } else if ( index.buffer && indirect.buffer ) { + if ( device->enabledFeatures.multiDrawIndirect || descriptor.inputs.indirect.count <= 1 ) { + vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, + descriptor.inputs.indirect.offset, // offset + descriptor.inputs.indirect.count, // drawCount + descriptor.inputs.indirect.stride // stride + ); + } else { + for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) { + vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, + descriptor.inputs.indirect.offset + i * descriptor.inputs.indirect.stride, // offset + 1, // drawCount + descriptor.inputs.indirect.stride // stride + ); + } + } } else if ( index.buffer && !indirect.buffer ) { vkCmdDrawIndexed(commandBuffer, descriptor.inputs.index.count, // indexCount @@ -1006,24 +1124,26 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co hash += std::hash{}(renderMode); hash += std::hash{}(renderTarget); + hash += std::hash{}(pipeline); -/* - 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 ) { + for ( auto 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 ) { + for ( auto 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); } + for ( auto i = 0; i < inputs.instance.attributes.size(); ++i ) { + hash += std::hash{}(inputs.instance.attributes[i].descriptor.format); + hash += std::hash{}(inputs.instance.attributes[i].descriptor.offset); + } +/* + for ( auto i = 0; i < inputs.indirect.attributes.size(); ++i ) { + hash += std::hash{}(inputs.indirect.attributes[i].descriptor.format); + hash += std::hash{}(inputs.indirect.attributes[i].descriptor.offset); + } +*/ hash += std::hash{}(topology); hash += std::hash{}(cullMode); diff --git a/engine/src/ext/vulkan/rendermode.cpp b/engine/src/ext/vulkan/rendermode.cpp index 7db3b2d0..6b4eac66 100644 --- a/engine/src/ext/vulkan/rendermode.cpp +++ b/engine/src/ext/vulkan/rendermode.cpp @@ -163,6 +163,7 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderMode::bindGraphicDescriptor( c ext::vulkan::GraphicDescriptor descriptor = reference; // descriptor.renderMode = this->getName(); descriptor.subpass = pass; + descriptor.pipeline = metadata.pipeline; descriptor.parse( metadata.json["descriptor"] ); return descriptor; } @@ -177,7 +178,7 @@ void ext::vulkan::RenderMode::createCommandBuffers() { if ( !entity->hasComponent() ) continue; ext::vulkan::Graphic& graphic = entity->getComponent(); if ( !graphic.initialized || !graphic.process ) continue; - graphics.push_back(&graphic); + graphics.emplace_back(&graphic); } this->synchronize(); @@ -196,7 +197,7 @@ ext::vulkan::RenderMode::commands_container_t& ext::vulkan::RenderMode::getComma commands.resize( swapchain.buffers ); VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( - this->getType() == "Compute" ? device->getCommandPool(Device::QueueEnum::COMPUTE) : device->getCommandPool(Device::QueueEnum::GRAPHICS), + device->getCommandPool(this->getType() == "Compute" ? Device::QueueEnum::COMPUTE : Device::QueueEnum::GRAPHICS), VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(commands.size()) ); @@ -219,7 +220,7 @@ void ext::vulkan::RenderMode::bindPipelines() { ext::vulkan::Graphic& graphic = entity->getComponent(); if ( !graphic.initialized || !graphic.process ) continue; // if ( graphic.descriptor.renderMode != "" && graphic.descriptor.renderMode != this->getName() ) continue; - graphics.push_back(&graphic); + graphics.emplace_back(&graphic); } this->synchronize(); this->bindPipelines( graphics ); @@ -230,42 +231,26 @@ void ext::vulkan::RenderMode::bindPipelines( const uf::stl::vector(); - for ( auto* pointer : graphics ) { - auto& graphic = *pointer; - for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) { - // bind to this render mode - ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic.descriptor, currentPass); - // ignore if pipeline exists for this render mode - if ( graphic.hasPipeline( descriptor ) ) continue; - graphic.initializePipeline( descriptor ); - } - } -*/ } void ext::vulkan::RenderMode::render() { -/* - if ( ext::openvr::context ) { - ext::openvr::submit(); - } -*/ auto& commands = getCommands( this->mostRecentCommandPoolId ); // Get next image in the swap chain (back/front buffer) VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphore)); @@ -308,20 +293,6 @@ void ext::vulkan::RenderMode::initialize( Device& device ) { if ( this->height > 0 ) renderTarget.height = this->height; } - // Create command buffers -/* - { - commands.resize( swapchain.buffers ); - - VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( - this->getType() == "Compute" ? device.getCommandPool(Device::QueueEnum::COMPUTE) : device.getCommandPool(Device::QueueEnum::GRAPHICS), - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - static_cast(commands.size()) - ); - - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commands.data())); - } -*/ // Set sync objects { // Fences (Used to check draw command buffer completion) @@ -343,6 +314,11 @@ void ext::vulkan::RenderMode::initialize( Device& device ) { VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderCompleteSemaphore)); } } + + if ( std::find( metadata.pipelines.begin(), metadata.pipelines.end(), metadata.pipeline ) == metadata.pipelines.end() ) { + metadata.pipelines.emplace_back(metadata.pipeline); + } + } void ext::vulkan::RenderMode::tick() { diff --git a/engine/src/ext/vulkan/rendermodes/compute.cpp b/engine/src/ext/vulkan/rendermodes/compute.cpp index 099b64f3..bf5bb287 100644 --- a/engine/src/ext/vulkan/rendermodes/compute.cpp +++ b/engine/src/ext/vulkan/rendermodes/compute.cpp @@ -104,9 +104,11 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { 0, 1, 2, 2, 3, 0 }; */ + blitter.device = &device; blitter.material.device = &device; blitter.descriptor.subpass = 1; + blitter.descriptor.inputs.dispatch = { (width / 32) + 1, (height / 32) + 1, 1 }; blitter.descriptor.depth.test = false; blitter.descriptor.depth.write = false; @@ -246,7 +248,6 @@ void ext::vulkan::ComputeRenderMode::createCommandBuffers( ) { for (size_t i = 0; i < commands.size(); ++i) { VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo)); pipeline.record(compute, commands[i]); - vkCmdDispatch(commands[i], width / dispatchSize.x, height / dispatchSize.y, 1); VK_CHECK_RESULT(vkEndCommandBuffer(commands[i])); } diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index bb5137a7..5cc87abd 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -193,6 +193,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { { uf::Mesh mesh; + mesh.vertex.count = 3; + /* mesh.bind(); mesh.insertVertices({ { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, @@ -203,18 +205,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { mesh.insertIndices({ 0, 1, 2, 2, 3, 0 }); - /* - uf::Mesh mesh; - mesh.vertices = { - { {-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 = { - 0, 1, 2, 0, 2, 3 - }; */ + blitter.descriptor.subpass = 1; blitter.descriptor.depth.test = false; blitter.descriptor.depth.write = false; @@ -237,20 +229,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { {uf::io::resolveURI(vertexShaderFilename), VK_SHADER_STAGE_VERTEX_BIT}, {uf::io::resolveURI(fragmentShaderFilename), VK_SHADER_STAGE_FRAGMENT_BIT} }); - /* - uf::stl::string fragmentShaderFilename = ( msaa <= 1 ) ? "no-msaa." : ""; - if ( ext::vulkan::settings::experimental::vxgi ) { - fragmentShaderFilename = ( msaa <= 1 ) ? "vxgi.no-msaa." : "vxgi."; - } - blitter.material.initializeShaders({ - {uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {uf::io::root+"/shaders/display/subpass." + fragmentShaderFilename + "frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} - }); - */ { auto& scene = uf::scene::getCurrentScene(); - auto& shader = blitter.material.shaders.back(); + auto& shader = blitter.material.getShader("fragment"); auto& sceneMetadataJson = scene.getComponent(); size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(512); size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as(512); @@ -258,19 +240,35 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as(128); size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(16); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); + if ( ext::vulkan::settings::experimental::vxgi ) { + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D); + else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube); + else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; + else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; + else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades; + } + } /* - struct SpecializationConstant { - uint32_t maxTextures2D = 512; - uint32_t maxTexturesCube = 128; - uint32_t maxCascades = 16; - }; - auto& specializationConstants = shader.specializationConstants.get(); - specializationConstants.maxTextures2D = maxTextures2D; - specializationConstants.maxTexturesCube = maxTexturesCube; - specializationConstants.maxCascades = maxCascades; - */ - uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ uf::stl::string name = sc["name"].as(); if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); @@ -290,17 +288,24 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; } }); - } else { - /* - struct SpecializationConstant { - uint32_t maxTextures2D = 512; - uint32_t maxTexturesCube = 128; - }; - auto& specializationConstants = shader.specializationConstants.get(); - specializationConstants.maxTextures2D = maxTextures2D; - specializationConstants.maxTexturesCube = maxTexturesCube; */ - uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + } else { + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D); + else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; + else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; + } + } + /* + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ uf::stl::string name = sc["name"].as(); if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); @@ -316,15 +321,15 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; } }); + */ } - + /* 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 = shader.initializeBuffer( (const void*) lights.data(), lights.size() * sizeof(pod::Light), @@ -347,6 +352,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { drawCommands.size() * sizeof(pod::DrawCommand), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); + */ } // blitter.initializePipeline(); for ( size_t eye = 0; eye < metadata.eyes; ++eye ) { @@ -427,10 +433,16 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto clearValue.color = { { 0, 0, 0, 0 } }; } } else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) { - clearValue.depthStencil = { 0.0f, 0 }; + if ( uf::matrix::reverseInfiniteProjection ) { + clearValue.depthStencil = { 0.0f, 0 }; + } else { + clearValue.depthStencil = { 1.0f, 0 }; + } } clearValues.push_back(clearValue); } + // uf::matrix::reverseInfiniteProjection + // descriptor.depth.operation ext::RENDERER::enums::Compare::GREATER_OR_EQUAL VkRenderPassBeginInfo renderPassBeginInfo = {}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -462,8 +474,19 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto for ( auto layer : layers ) { layer->pipelineBarrier( commands[i], 0 ); } - + size_t currentSubpass = 0; + + for ( auto& pipeline : metadata.pipelines ) { + if ( pipeline == metadata.pipeline ) continue; + for ( auto graphic : graphics ) { + if ( graphic->descriptor.renderMode != this->getName() ) continue; + ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass); + descriptor.pipeline = pipeline; + graphic->record( commands[i], descriptor, 0, metadata.eyes ); + } + } + vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdSetViewport(commands[i], 0, 1, &viewport); vkCmdSetScissor(commands[i], 0, 1, &scissor); diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 398b0135..6df1f6d1 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -42,7 +42,6 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD descriptor.cullMode = VK_CULL_MODE_NONE; descriptor.depth.test = false; descriptor.depth.write = false; - descriptor.pipeline = "vxgi"; } else if ( metadata.type == "depth" ) { descriptor.cullMode = VK_CULL_MODE_NONE; } @@ -304,6 +303,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { if ( blitter.process ) { uf::Mesh mesh; + mesh.vertex.count = 3; + /* mesh.bind(); mesh.insertVertices({ { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, @@ -314,6 +315,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { mesh.insertIndices({ 0, 1, 2, 2, 3, 0 }); + */ blitter.device = &device; blitter.material.device = &device; @@ -412,15 +414,39 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(16); auto& shader = blitter.material.getShader("compute"); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); - uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D); + else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube); + else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; + else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; + else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades; + else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades; + } + } + /* ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ uf::stl::string name = sc["name"].as(); if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube); else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades); }); - ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){ size_t binding = t["binding"].as(); uf::stl::string name = t["name"].as(); @@ -434,36 +460,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; } }); + */ - 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 = shader.initializeBuffer( - (const void*) lights.data(), - lights.size() * sizeof(pod::Light), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - metadata.materialBufferIndex = shader.initializeBuffer( - (const void*) materials.data(), - materials.size() * sizeof(pod::Material), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - - metadata.textureBufferIndex = shader.initializeBuffer( - (const void*) textures.data(), - textures.size() * sizeof(pod::Texture), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - - metadata.drawCallBufferIndex = shader.initializeBuffer( - (const void*) drawCalls.data(), - drawCalls.size() * sizeof(pod::DrawCommand), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); } else { for ( auto& attachment : renderTarget.attachments ) { if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue; @@ -648,7 +646,11 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) { clearValue.color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; } else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) { - clearValue.depthStencil = { 0.0f, 0 }; + if ( uf::matrix::reverseInfiniteProjection ) { + clearValue.depthStencil = { 0.0f, 0 }; + } else { + clearValue.depthStencil = { 1.0f, 0 }; + } } clearValues.push_back(clearValue); } @@ -684,6 +686,16 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v size_t currentPass = 0; // pre-renderpass commands if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i] ); + + for ( auto& pipeline : metadata.pipelines ) { + if ( pipeline == metadata.pipeline ) continue; + for ( auto graphic : graphics ) { + if ( graphic->descriptor.renderMode != this->getTarget() ) continue; + ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass); + descriptor.pipeline = pipeline; + graphic->record( commands[i], descriptor, 0, metadata.type == "vxgi" ? 0 : MIN(subpasses,6) ); + } + } vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdSetViewport(commands[i], 0, 1, &viewport); diff --git a/engine/src/ext/vulkan/shader.cpp b/engine/src/ext/vulkan/shader.cpp index 6b58cc9c..979fff97 100644 --- a/engine/src/ext/vulkan/shader.cpp +++ b/engine/src/ext/vulkan/shader.cpp @@ -557,7 +557,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl auto& userdata = uniforms.emplace_back(); userdata.create( definition.size, nullptr ); - initializeBuffer( + if ( metadata.autoInitializeUniforms ) initializeBuffer( (const void*) userdata.data().data, userdata.data().len, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT @@ -658,19 +658,26 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl } size_t specializationSize = 0; + uf::stl::vector specializationRemap; + specializationRemap.resize( comp.get_specialization_constants().size() ); + for ( const auto& constant : comp.get_specialization_constants() ) { const auto& value = comp.get_constant(constant.id); const auto& type = comp.get_type(value.constant_type); + uf::stl::string name = comp.get_name (constant.id); size_t size = 4; //comp.get_declared_struct_size(type); - VkSpecializationMapEntry specializationMapEntry; + auto& specializationMapEntry = specializationRemap[constant.constant_id]; specializationMapEntry.constantID = constant.constant_id; specializationMapEntry.size = size; specializationMapEntry.offset = specializationSize; - specializationMapEntries.emplace_back(specializationMapEntry); specializationSize += size; } if ( specializationSize > 0 ) { + specializationRemap.reserve( specializationRemap.size() ); + for ( auto& specializationMapEntry : specializationRemap ) { + specializationMapEntries.emplace_back(specializationMapEntry); + } specializationConstants.create( specializationSize ); VK_DEBUG_VALIDATION_MESSAGE("Specialization constants size of " << specializationSize << " for shader " << filename); diff --git a/engine/src/ext/vulkan/texture.cpp b/engine/src/ext/vulkan/texture.cpp index 8a257648..f591ca63 100644 --- a/engine/src/ext/vulkan/texture.cpp +++ b/engine/src/ext/vulkan/texture.cpp @@ -81,6 +81,7 @@ void ext::vulkan::Texture::initialize( Device& device, size_t width, size_t heig this->height = height; this->depth = depth; this->layers = layers; + // implicitly set type if ( width > 1 && height > 1 && depth > 1 ) { this->type = ext::vulkan::enums::Image::TYPE_3D; @@ -361,8 +362,8 @@ void ext::vulkan::Texture::loadFromImage( (void*) image.getPixelsPtr(), image.getPixels().size(), format, - image.getDimensions()[0], - image.getDimensions()[1], + image.getDimensions().x, + image.getDimensions().y, 1, 1, device, @@ -500,29 +501,8 @@ void ext::vulkan::Texture::fromBuffers( device.flushCommandBuffer(commandBuffer); this->imageLayout = imageLayout; - this->updateDescriptors(); } -/* - if ( this->layers > 1 ) { - // Create image view - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.baseArrayLayer = 1; - subresourceRange.levelCount = this->mips; - subresourceRange.layerCount = this->layers - 1; - VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - setImageLayout( - commandBuffer, - image, - VK_IMAGE_LAYOUT_UNDEFINED, - imageLayout, - subresourceRange - ); - device.flushCommandBuffer(commandBuffer); - } -*/ this->updateDescriptors(); } @@ -588,20 +568,31 @@ void ext::vulkan::Texture::asRenderTarget( Device& device, uint32_t width, uint3 this->updateDescriptors(); } void ext::vulkan::Texture::aliasTexture( const Texture& texture ) { - image = texture.image; - view = texture.view; - type = texture.type; - viewType = texture.viewType; - imageLayout = texture.imageLayout; - deviceMemory = texture.deviceMemory; - width = texture.width; - height = texture.height; - depth = texture.depth; - layers = texture.layers; - - sampler = texture.sampler; - sampler.device = NULL; - + *this = { + .device = nullptr, + .image = texture.image, + .view = texture.view, + .type = texture.type, + .viewType = texture.viewType, + .imageLayout = texture.imageLayout, + .deviceMemory = texture.deviceMemory, + .descriptor = texture.descriptor, + .format = texture.format, + + .sampler = texture.sampler, + + .allocation = texture.allocation, + .allocationInfo = texture.allocationInfo, + + .width = texture.width, + .height = texture.height, + .depth = texture.depth, + .layers = texture.layers, + .mips = texture.mips, + }; + + sampler.device = nullptr; + this->updateDescriptors(); } void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& attachment, bool createSampler ) { diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index 327914f9..a289a0da 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -37,9 +38,9 @@ bool ext::vulkan::settings::experimental::deferredAliasOutputToSwapchain = true; bool ext::vulkan::settings::experimental::multiview = true; bool ext::vulkan::settings::experimental::vsync = true; bool ext::vulkan::settings::experimental::hdr = true; -bool ext::vulkan::settings::experimental::frustrumCull = false; bool ext::vulkan::settings::experimental::vxgi = true; bool ext::vulkan::settings::experimental::deferredSampling = true; +bool ext::vulkan::settings::experimental::culling = false; VkColorSpaceKHR ext::vulkan::settings::formats::colorSpace; ext::vulkan::enums::Format::type_t ext::vulkan::settings::formats::color = ext::vulkan::enums::Format::R8G8B8A8_UNORM; @@ -213,6 +214,7 @@ void ext::vulkan::removeRenderMode( ext::vulkan::RenderMode* mode, bool free ) { } void ext::vulkan::initialize() { + ext::vulkan::mutex.lock(); device.initialize(); swapchain.initialize( device ); { @@ -260,6 +262,9 @@ void ext::vulkan::initialize() { TextureCube::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; TextureCube::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 1, 6, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); } + + uf::graph::initialize(); + for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; renderMode->initialize(device); @@ -272,6 +277,7 @@ void ext::vulkan::initialize() { else renderMode->createCommandBuffers(); } if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + ext::vulkan::mutex.unlock(); } void ext::vulkan::tick() { ext::vulkan::mutex.lock(); @@ -335,11 +341,13 @@ void ext::vulkan::render() { ext::vulkan::currentRenderMode = renderMode; if ( settings::experimental::multithreadedCommandRendering ) { jobs.emplace_back([&]{ + uf::graph::render(); uf::scene::render(); renderMode->render(); renderMode->executed = true; }); } else { + uf::graph::render(); uf::scene::render(); renderMode->render(); renderMode->executed = true; diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index e2aea2f6..a25d18d9 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -4,60 +4,93 @@ #endif pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { #if UF_USE_XATLAS + struct Pair { + size_t index = 0; + size_t command = 0; + ::xatlas::MeshDecl decl; + }; + + uf::stl::vector entries; + entries.reserve(graph.meshes.size()); + + uf::stl::vector sources; + sources.reserve(graph.meshes.size()); + ::xatlas::Atlas* atlas = ::xatlas::Create(); -#if 0 - for ( auto& name : graph.meshes ) { + for ( auto index = 0; index < graph.meshes.size(); ++index ) { + auto& name = graph.meshes[index]; auto& mesh = uf::graph::storage.meshes[name]; - mesh.updateDescriptor(); + sources.emplace_back(mesh); - size_t indices = mesh.attributes.index.length; - size_t indexStride = mesh.attributes.index.size; - uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer; + if ( mesh.index.count ) { + uf::Mesh::Attribute positionAttribute; + uf::Mesh::Attribute uvAttribute; + uf::Mesh::Attribute stAttribute; + for ( auto& attribute : mesh.vertex.attributes ) { + if ( attribute.descriptor.name == "position" ) positionAttribute = attribute; + else if ( attribute.descriptor.name == "uv" ) uvAttribute = attribute; + else if ( attribute.descriptor.name == "st" ) stAttribute = attribute; + } + UF_ASSERT( positionAttribute.descriptor.name == "position" && uvAttribute.descriptor.name == "uv" && uvAttribute.descriptor.name == "st" ); - size_t vertices = mesh.attributes.vertex.length; - size_t vertexStride = mesh.attributes.vertex.size; - uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; + auto& indexAttribute = mesh.index.attributes.front(); + ::xatlas::IndexFormat indexType = ::xatlas::IndexFormat::UInt32; + switch ( mesh.index.stride ) { + case sizeof(uint16_t): indexType = ::xatlas::IndexFormat::UInt16; break; + case sizeof(uint32_t): indexType = ::xatlas::IndexFormat::UInt32; break; + default: UF_EXCEPTION("unsupported index type"); break; + } - uf::renderer::AttributeDescriptor vertexAttributePosition, - vertexAttributeNormal, - vertexAttributeUv, - vertexAttributeSt, - vertexAttributeId; + if ( mesh.indirect.count ) { + uf::Mesh::Attribute remappedPositionAttribute; + uf::Mesh::Attribute remappedUvAttribute; + uf::Mesh::Attribute remappedIndexAttribute; + for ( auto i = 0; i < mesh.indirect.count; ++i ) { + remappedPositionAttribute = mesh.remapVertexAttribute( positionAttribute, i ); + remappedUvAttribute = mesh.remapVertexAttribute( uvAttribute, i ); + remappedIndexAttribute = mesh.remapIndexAttribute( indexAttribute, i ); - 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 != "" ); + auto& entry = entries.emplace_back(); + entry.index = index; + entry.command = i; - ::xatlas::MeshDecl meshDecl; - meshDecl.vertexCount = vertices; // mesh.vertices.size(); - meshDecl.vertexPositionData = (uint8_t*) mesh.attributes.vertex.pointer + vertexAttributePosition.offset; /*((uint8_t*) mesh.vertices.data()) + vertexAttributePosition.offset*/ - meshDecl.vertexPositionStride = vertexStride; - if ( vertexAttributeUv.name != "" ) { - meshDecl.vertexUvData = (uint8_t*) mesh.attributes.vertex.pointer + vertexAttributeUv.offset;// ((uint8_t*) mesh.vertices.data()) + vertexAttributeUv.offset; - meshDecl.vertexUvStride = vertexStride; - } - /* - if ( vertexAttributeNormal.name != "" ) { - meshDecl.vertexNormalData = ((uint8_t*) mesh.vertices.data()) + vertexAttributeNormal.offset; - meshDecl.vertexNormalStride = mesh.attributes.vertex.size; - } - */ - meshDecl.indexCount = indices; // mesh.indices.size(); - meshDecl.indexData = mesh.attributes.index.pointer; // mesh.indices.data(); - meshDecl.indexFormat = indexStride == 4 ? ::xatlas::IndexFormat::UInt32 : ::xatlas::IndexFormat::UInt16; + auto& decl = entry.decl; + decl.vertexCount = remappedUvAttribute.length; + decl.vertexPositionData = remappedPositionAttribute.pointer; + decl.vertexPositionStride = remappedPositionAttribute.stride; + decl.vertexUvData = remappedUvAttribute.pointer; + decl.vertexUvStride = remappedUvAttribute.stride; - ::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas, meshDecl, graph.meshes.size()); + decl.indexCount = remappedIndexAttribute.length; + decl.indexData = remappedIndexAttribute.pointer; + decl.indexFormat = indexType; + } + } else { + auto& entry = entries.emplace_back(); + entry.index = index; + + auto& decl = entry.decl; + decl.vertexCount = uvAttribute.length; + decl.vertexPositionData = positionAttribute.pointer; + decl.vertexPositionStride = positionAttribute.stride; + decl.vertexUvData = uvAttribute.pointer; + decl.vertexUvStride = uvAttribute.stride; + + decl.indexCount = indexAttribute.length; + decl.indexData = indexAttribute.pointer; + decl.indexFormat = indexType; + decl.indexFormat = indexType; + + } + } else UF_EXCEPTION("to-do: not require indices for meshes"); + } + for ( auto& mesh : entries ) { + ::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas, mesh.decl, entries.size()); if (error != ::xatlas::AddMeshError::Success) { ::xatlas::Destroy(atlas); - UF_MSG_ERROR(::xatlas::StringForEnum(error)); - return {}; + UF_EXCEPTION(::xatlas::StringForEnum(error)); } - } + } ::xatlas::ChartOptions chartOptions{}; // chartOptions.useInputMeshUvs = true; @@ -72,61 +105,79 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { for ( size_t i = 0; i < atlas->meshCount; i++ ) { auto& xmesh = atlas->meshes[i]; - auto& mesh = uf::graph::storage.meshes[graph.meshes[i]]; + auto& entry = entries[i]; + auto& mesh = graph.meshes[entry.index]; + auto& source = sources[entry.index]; + source.updateDescriptor(); - size_t indices = mesh.attributes.index.length; - size_t indexStride = mesh.attributes.index.size; - uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer; - uf::stl::vector oldVertexBuffer( (uint8_t*) mesh.attributes.vertex.pointer, (uint8_t*) mesh.attributes.vertex.pointer + mesh.attributes.vertex.length * mesh.attributes.vertex.size ); + } - size_t vertices = xmesh.vertexCount; - size_t vertexStride = mesh.attributes.vertex.size; - - mesh.resizeVertices( vertices ); +#if 0 + for ( size_t i = 0; i < atlas->meshCount; i++ ) { + auto& xmesh = atlas->meshes[i]; + auto& mesh = *meshes[i]; - uint8_t* oldVertexPointer = oldVertexBuffer.data(); - uint8_t* newvertexPointer = (uint8_t*) mesh.attributes.vertex.pointer; + uf::Mesh src; + src.buffers = mesh.buffers; + src.vertex = mesh.vertex; + src.index = mesh.index; + src.instance = mesh.instance; + src.indirect = mesh.indirect; - uf::renderer::AttributeDescriptor vertexAttributePosition, - vertexAttributeNormal, - vertexAttributeUv, - vertexAttributeSt; + mesh.resizeVertices( xmesh.vertexCount ); - 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; - } - UF_ASSERT( vertexAttributePosition.name != "" ); + if ( mesh.isInterleaved( mesh.vertex.interleaved ) ) { + for ( auto& attribute : mesh.vertex.attributes ) { + if ( attribute.descriptor.name != "st" ) continue; - for ( size_t v = 0; v < xmesh.vertexCount; v++) { - auto& xvertex = xmesh.vertexArray[v]; - uint8_t* oldVertexSrc = oldVertexPointer + (xvertex.xref * vertexStride); - uint8_t* newVertexSrc = newvertexPointer + (v * vertexStride); + uint8_t* srcBuffer = src.buffers[mesh.vertex.interleaved].data(); + uint8_t* dstBuffer = mesh.buffers[mesh.vertex.interleaved].data(); + for ( auto v = 0; v < xmesh.vertexCount; ++v ) { + auto& vertex = xmesh.vertexArray[v]; + auto ref = vertex.xref; - memcpy( newVertexSrc, oldVertexSrc, vertexStride ); + memcpy( dstBuffer + v * mesh.vertex.stride, srcBuffer + ref * mesh.vertex.stride, mesh.vertex.stride ); - pod::Vector2f& st = *((pod::Vector2f*) (newVertexSrc + vertexAttributeSt.offset)); - st = { xvertex.uv[0] / atlas->width, xvertex.uv[1] / atlas->height }; + pod::Vector2f& st = *((pod::Vector2f*) dstBuffer + v * mesh.vertex.stride + attribute.descriptor.offset); + st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; + } + + break; + } + } else for ( auto& attribute : mesh.vertex.attributes ) { + uint8_t* srcBuffer = src.buffers[attribute.buffer].data(); + uint8_t* dstBuffer = mesh.buffers[attribute.buffer].data(); + for ( auto v = 0; v < xmesh.vertexCount; ++v ) { + auto& vertex = xmesh.vertexArray[v]; + auto ref = vertex.xref; + + if ( attribute.descriptor.name == "st" ) { + pod::Vector2f& st = *((pod::Vector2f*) dstBuffer + v * attribute.descriptor.size); + st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; + } else { + memcpy( dstBuffer + v * attribute.descriptor.size, srcBuffer + ref * attribute.descriptor.size, attribute.descriptor.size ); + } + } } - for ( size_t currentIndex = 0; currentIndex < xmesh.indexCount; ++currentIndex ) { - uint32_t index = xmesh.indexArray[currentIndex]; - 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; + { + auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer]; + uint8_t* pointer = (uint8_t*) buffer.data(); + for ( auto index = 0; index < mesh.index.count; ++index ) { + switch ( mesh.index.stride ) { + case 1: *( uint8_t*) pointer = xmesh.indexArray[index]; break; + case 2: *(uint16_t*) pointer = xmesh.indexArray[index]; break; + case 4: *(uint32_t*) pointer = xmesh.indexArray[index]; break; + } } } } +#endif pod::Vector2ui size = pod::Vector2ui{ atlas->width, atlas->height }; ::xatlas::Destroy(atlas); return size; #endif -#endif } \ No newline at end of file diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index 9a58abb8..8125c435 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -14,6 +14,7 @@ // C-tor // Default +/* uf::Image::Image() : m_bpp(8), m_channels(4), @@ -71,7 +72,7 @@ uf::Image::Image( const Image::container_t& copy, const Image::vec2_t& size ) : { } - +*/ uf::stl::string uf::Image::getFilename() const { return this->m_filename; } diff --git a/engine/src/utils/mesh/mesh.cpp b/engine/src/utils/mesh/mesh.cpp index ce5bc01b..c46eaaba 100644 --- a/engine/src/utils/mesh/mesh.cpp +++ b/engine/src/utils/mesh/mesh.cpp @@ -48,7 +48,6 @@ UF_VERTEX_DESCRIPTOR(pod::Vertex_3F, ) bool uf::Mesh::defaultInterleaved = false; - void uf::Mesh::initialize() { } void uf::Mesh::destroy() { @@ -82,23 +81,26 @@ void uf::Mesh::updateDescriptor() { _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 +void uf::Mesh::bind( const uf::Mesh& mesh ) { + vertex.attributes = mesh.vertex.attributes; + vertex.interleaved = mesh.vertex.interleaved; + index.attributes = mesh.index.attributes; + index.interleaved = mesh.index.interleaved; + instance.attributes = mesh.instance.attributes; + instance.interleaved = mesh.instance.interleaved; + indirect.attributes = mesh.indirect.attributes; + indirect.interleaved = mesh.indirect.interleaved; -uint32_t instanceID = 0; // starting instance position -uint32_t materialID = 0; -uint32_t objectID = 0; -uint32_t vertices = 0; -*/ + _bind(); +} +void uf::Mesh::insert( const uf::Mesh& mesh ) { + if ( vertex.attributes.empty() && index.attributes.empty() && instance.attributes.empty() && indirect.attributes.empty() ) bind( mesh ); + + insertVertices(mesh); + insertIndices(mesh); + insertInstances(mesh); + insertIndirects(mesh); +} void uf::Mesh::generateIndices() { // deduce type size_t size = sizeof(uint32_t); @@ -125,14 +127,16 @@ void uf::Mesh::generateIndirect() { 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; + commands.emplace_back(pod::DrawCommand{ + .indices = buffer.size() / attribute.descriptor.size, + .instances = instance.count == 0 && instance.attributes.empty() ? 1 : instance.count, + .indexID = 0, + .vertexID = 0, + .instanceID = 0, + // .materialID = 0, + // .objectID = 0, + // .vertices = vertex.count, + }); } _destroy( indirect ); @@ -234,8 +238,8 @@ void uf::Mesh::print() const { // void uf::Mesh::_destroy( uf::Mesh::Input& input ) { for ( auto& attribute : input.attributes ) { - attribute.descriptor.length = 0; - attribute.descriptor.pointer = NULL; + attribute.length = 0; + attribute.pointer = NULL; attribute.buffer = 0; } input.attributes.clear(); @@ -262,13 +266,33 @@ void uf::Mesh::_bind( bool interleave ) { 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()); + const bool interleaved = isInterleaved(input.interleaved); + auto& buffer = buffers[interleaved ? input.interleaved : attribute.buffer]; + attribute.length = buffer.size(); + attribute.pointer = (void*) (buffer.data()); + if ( !interleaved ) attribute.stride = attribute.descriptor.size; input.stride += attribute.descriptor.size; } + for ( auto& attribute : input.attributes ) { + const bool interleaved = isInterleaved(input.interleaved); + if ( interleaved ) attribute.stride = input.stride; + } } -void uf::Mesh::_insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) { +uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute, size_t i ) const { + uf::Mesh::Attribute res = attribute; + if ( i < indirect.count ) { + auto& drawCommand = ((const pod::DrawCommand*) buffers[isInterleaved(indirect.interleaved) ? indirect.interleaved : indirect.attributes.front().buffer].data())[i]; + if ( &input == &vertex ) { + res.pointer = (void*) ((uint8_t*) res.pointer + drawCommand.vertexID * res.stride); + res.length = drawCommand.vertices; + } else if ( &input == &index ) { + res.pointer = (void*) ((uint8_t*) res.pointer + drawCommand.indexID * res.stride); + res.length = drawCommand.indices; + } + } + return res; +} +void uf::Mesh::_insertVs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) { if ( !_hasV( input, srcInput ) ) return; _reserveVs( input, input.count += srcInput.count ); @@ -292,7 +316,7 @@ void uf::Mesh::_insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf: } _updateDescriptor( input ); } -void uf::Mesh::_insertI( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) { +void uf::Mesh::_insertIs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) { // if ( !_hasI( source ) ) return; _reserveIs( input, input.count += srcInput.count ); @@ -339,26 +363,26 @@ 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()); + attribute.length = buffers[input.interleaved].size(); + attribute.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()); + attribute.length = buffers[attribute.buffer].size(); + attribute.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()); + attribute.length = buffers[input.interleaved].size(); + attribute.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()); + attribute.length = buffers[attribute.buffer].size(); + attribute.pointer = (void*) (buffers[attribute.buffer].data()); } } void uf::Mesh::_insertV( uf::Mesh::Input& input, const void* data ) { @@ -400,14 +424,14 @@ void uf::Mesh::_bindI( uf::Mesh::Input& input, size_t size, ext::RENDERER::enums 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()); + attribute.length = buffers[attribute.buffer].size(); + attribute.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()); + attribute.length = buffers[attribute.buffer].size(); + attribute.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]; diff --git a/ext/behaviors/baking/behavior.cpp b/ext/behaviors/baking/behavior.cpp index b6f8de3f..0dde419d 100644 --- a/ext/behaviors/baking/behavior.cpp +++ b/ext/behaviors/baking/behavior.cpp @@ -369,9 +369,9 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { // standard pipeline { - uf::stl::string vertexShaderFilename = "/gltf/baking/bake.vert.spv"; + uf::stl::string vertexShaderFilename = "/graph/baking/bake.vert.spv"; uf::stl::string geometryShaderFilename = ""; - uf::stl::string fragmentShaderFilename = "/gltf/baking/bake.frag.spv"; + uf::stl::string fragmentShaderFilename = "/graph/baking/bake.frag.spv"; if ( uf::renderer::settings::experimental::deferredSampling ) { fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); } diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index 3191feee..c4b23d2a 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -64,6 +64,10 @@ void ext::LightBehavior::initialize( uf::Object& self ) { auto& renderMode = this->getComponent(); renderMode.metadata.type = "depth"; + renderMode.metadata.pipeline = "depth"; + if ( uf::renderer::settings::experimental::culling ) { + renderMode.metadata.pipelines.emplace_back("culling"); + } renderMode.metadata.json["descriptor"]["depth bias"] = metadataJson["light"]["bias"]; renderMode.metadata.json["descriptor"]["renderMode"] = metadataJson["renderMode"]; @@ -84,6 +88,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) { } else { size = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height }; } + if ( radius.y < radius.x ) radius.y = 256; camera.setProjection( uf::matrix::perspective( fov, (float) size.x / (float) size.y, radius.x, radius.y ) ); camera.update(true); diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index dc0cc27f..6f9a868c 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -241,7 +241,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.menu == "" && keys.paused ) { stats.menu = "paused"; metadata.system.control = false; - uf::hooks.call("menu:Pause"); + uf::Serializer payload; + uf::hooks.call("menu:Pause", payload); } else if ( !metadata.system.control ) { stats.menu = "menu"; diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 35f454c0..ca648d26 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -67,17 +67,14 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { if ( !timer.running() ) timer.start( uf::Time<>(-1000000) ); if ( timer.elapsed().asDouble() < 1 ) return; timer.reset(); - uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager"); if ( !manager ) return; uf::Serializer payload; - uf::stl::string config = metadataJson["menus"]["pause"].is() ? metadataJson["menus"]["pause"].as() : "/scenes/worldscape/gui/pause/menu.json"; + uf::stl::string config = metadataJson["menus"]["pause"].as("/entites/gui/pause/menu.json"); uf::Object& gui = manager->loadChild(config, false); payload["uid"] = gui.getUid(); - uf::Serializer& metadataJson = gui.getComponent(); metadataJson["menu"] = json["menu"]; - gui.initialize(); }); this->addHook( "world:Entity.LoadAsset", [&](ext::json::Value& json){ @@ -318,6 +315,159 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { metadata.shader.parameters[metadata.shader.time] = uf::physics::time::current; } #endif + + { + auto& graph = this->getGraph(); + auto& controller = this->getController(); + auto& camera = controller.getComponent(); + auto& controllerMetadata = controller.getComponent(); + auto& controllerTransform = controller.getComponent>(); + auto& metadata = this->getComponent(); + auto& metadataVxgi = this->getComponent(); + auto& metadataJson = this->getComponent(); + + struct LightInfo { + uf::Entity* entity = NULL; + pod::Vector3f position = {0,0,0}; + float range = 0.0f; + pod::Vector3f color = {0,0,0}; + float intensity = 0.0f; + float distance = 0; + float bias = 0; + int32_t type = 0; + bool shadows = false; + }; + + uf::stl::vector entities; entities.reserve(graph.size() / 2); + + uf::graph::storage.lights.clear(); uf::graph::storage.lights.reserve(metadata.max.lights); + uf::graph::storage.shadow2Ds.clear(); uf::graph::storage.shadow2Ds.reserve(metadata.max.lights); + uf::graph::storage.shadowCubes.clear(); uf::graph::storage.shadowCubes.reserve(metadata.max.lights); + + // traverse scene graph + for ( auto entity : graph ) { + // 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(); + // disables shadow mappers that activate when in range + bool hasRT = entity->hasComponent(); + if ( hasRT ) { + auto& renderMode = entity->getComponent(); + if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false; + } + if ( metadata.power <= 0 ) continue; + auto flatten = uf::transform::flatten( entity->getComponent>() ); + LightInfo& info = entities.emplace_back(LightInfo{ + .entity = entity, + .position = flatten.position, + .range = 0, + .color = pod::Vector4f{ metadata.color.x, metadata.color.y, metadata.color.z }, + .intensity = metadata.power, + .distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ), + .bias = metadata.bias, + .type = metadata.type, + .shadows = metadata.shadows && hasRT, + }); + } + // prioritize closer lights; it would be nice to also prioritize lights in view, but because of VXGI it's not really something to do + std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){ + return l.distance < r.distance; + }); + + int32_t shadowUpdateThreshold = metadata.shadow.update; // how many shadow maps we should update, based on range + int32_t shadowCount = metadata.shadow.max; // how many shadow maps we should pass, based on range + if ( shadowCount <= 0 ) shadowCount = std::numeric_limits::max(); + + // disable shadows if that light is outside our threshold + for ( auto& info : entities ) if ( info.shadows && shadowCount-- <= 0 ) info.shadows = false; + + // bind lighting and requested shadow maps + for ( uint32_t i = 0; i < entities.size() && uf::graph::storage.lights.size() < metadata.max.lights; ++i ) { + auto& info = entities[i]; + uf::Entity* entity = info.entity; + + if ( !info.shadows ) { + uf::graph::storage.lights.emplace_back(pod::Light{ + .view = uf::matrix::identity(), + .projection = uf::matrix::identity(), + .position = info.position, + .range = info.range, + .color = info.color, + .intensity = info.intensity, + .type = info.type, + .typeMap = 0, + .indexMap = -1, + .depthBias = info.bias, + }); + } else { + auto& renderMode = entity->getComponent(); + auto& lightCamera = entity->getComponent(); + auto& lightMetadata = entity->getComponent(); + lightMetadata.renderer.rendered = true; + // activate our shadow mapper if it's range-basedd + if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) renderMode.execute = true; + // if point light, and combining is requested + if ( metadata.shadow.experimentalMode > 0 && renderMode.renderTarget.views == 6 ) { + int32_t index = -1; + // separated texture2Ds + if ( metadata.shadow.experimentalMode == 2 ) { + index = uf::graph::storage.shadow2Ds.size(); + for ( auto& attachment : renderMode.renderTarget.attachments ) { + if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; + for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { + uf::graph::storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view); + } + break; + } + // cubemapped + } else { + index = uf::graph::storage.shadowCubes.size(); + for ( auto& attachment : renderMode.renderTarget.attachments ) { + if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; + uf::graph::storage.shadowCubes.emplace_back().aliasAttachment(attachment); + break; + } + } + uf::graph::storage.lights.emplace_back(pod::Light{ + .view = lightCamera.getView(0), + .projection = lightCamera.getProjection(0), + .position = info.position, + .range = info.range, + .color = info.color, + .intensity = info.intensity, + .type = info.type, + .typeMap = metadata.shadow.experimentalMode, + .indexMap = index, + .depthBias = info.bias, + }); + // any other shadowing light, even point lights, are split by shadow maps + } else { + for ( auto& attachment : renderMode.renderTarget.attachments ) { + 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 ) { + uf::graph::storage.lights.emplace_back(pod::Light{ + .view = lightCamera.getView(view), + .projection = lightCamera.getProjection(view), + .position = info.position, + .range = info.range, + .color = info.color, + .intensity = info.intensity, + .type = info.type, + .typeMap = 0, + .indexMap = uf::graph::storage.shadow2Ds.size(), + .depthBias = info.bias, + }); + uf::graph::storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view); + } + } + } + } + } + + uf::graph::storage.buffers.light.update( (const void*) uf::graph::storage.lights.data(), uf::graph::storage.lights.size() * sizeof(pod::Light) ); + } + /* Update lights */ if ( !uf::renderer::settings::experimental::vxgi ) { ext::ExtSceneBehavior::bindBuffers( *this ); } @@ -535,18 +685,6 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string alignas(4) uint32_t indexSkybox; }; - struct LightInfo { - uf::Entity* entity = NULL; - pod::Vector4f color = {0,0,0,0}; - pod::Vector3f position = {0,0,0}; - float distance = 0; - float bias = 0; - int32_t type = 0; - bool shadows = false; - }; - uf::stl::vector entities; - entities.reserve(graph.size() / 2); - // struct that contains our skybox cubemap, noise texture, and VXGI voxels auto& sceneTextures = this->getComponent(); uf::stl::vector textures2D; @@ -558,174 +696,19 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string uf::stl::vector texturesCube; texturesCube.reserve( metadata.max.texturesCube ); - // lighting information - uf::stl::vector lights; - lights.reserve( metadata.max.lights ); - - // material information - 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; - textures.reserve( metadata.max.textures2D ); - // drawcall information - 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 - /* - drawCommands.emplace_back(pod::DrawCall{ - materials.size(), - textures.size(), - textures2D.size(), - 0, - }); - */ - // pass material information - for ( auto& material : graph.materials ) { - materials.emplace_back( uf::graph::storage.materials[material] ); - } - // pass texture information - for ( auto& texture : graph.textures ) { - 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); - } - } - #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(); - // disables shadow mappers that activate when in range - bool hasRT = entity->hasComponent(); - if ( hasRT ) { - auto& renderMode = entity->getComponent(); - if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false; - } - if ( metadata.power <= 0 ) continue; - auto flatten = uf::transform::flatten( entity->getComponent>() ); - LightInfo& info = entities.emplace_back(LightInfo{ - .entity = entity, - .color = pod::Vector4f{ metadata.color.x, metadata.color.y, metadata.color.z, metadata.power }, - .position = flatten.position, - .distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ), - .bias = metadata.bias, - .type = metadata.type, - .shadows = metadata.shadows && hasRT, - }); - } - // prioritize closer lights; it would be nice to also prioritize lights in view, but because of VXGI it's not really something to do - std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){ - return l.distance < r.distance; - }); - - int32_t shadowUpdateThreshold = metadata.shadow.update; // how many shadow maps we should update, based on range - int32_t shadowCount = metadata.shadow.max; // how many shadow maps we should pass, based on range - if ( shadowCount <= 0 ) shadowCount = std::numeric_limits::max(); - - // disable shadows if that light is outside our threshold - for ( auto& info : entities ) if ( info.shadows && shadowCount-- <= 0 ) info.shadows = false; + // bind scene textures + for ( auto& key : uf::graph::storage.texture2Ds.keys ) textures2D.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[key] ); + + // bind shadow maps + for ( auto& texture : uf::graph::storage.shadow2Ds ) textures2D.emplace_back().aliasTexture(texture); + for ( auto& texture : uf::graph::storage.shadowCubes ) texturesCube.emplace_back().aliasTexture(texture); // bind skybox + size_t indexSkybox = texturesCube.size(); texturesCube.emplace_back().aliasTexture(sceneTextures.skybox); // bind noise texture + size_t indexNoise = textures3D.size(); textures3D.emplace_back().aliasTexture(sceneTextures.noise); - // bind lighting and requested shadow maps - for ( uint32_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) { - auto& info = entities[i]; - uf::Entity* entity = info.entity; - - if ( !info.shadows ) { - 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, - }); - } else { - auto& renderMode = entity->getComponent(); - auto& lightCamera = entity->getComponent(); - auto& lightMetadata = entity->getComponent(); - lightMetadata.renderer.rendered = true; - // activate our shadow mapper if it's range-basedd - if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) renderMode.execute = true; - // if point light, and combining is requested - if ( metadata.shadow.experimentalMode > 0 && renderMode.renderTarget.views == 6 ) { - int32_t index = -1; - // separated texture2Ds - if ( metadata.shadow.experimentalMode == 2 ) { - index = textures2D.size(); - for ( auto& attachment : renderMode.renderTarget.attachments ) { - if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; - for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { - textures2D.emplace_back().aliasAttachment(attachment, view); - } - break; - } - // cubemapped - } else { - index = texturesCube.size(); - for ( auto& attachment : renderMode.renderTarget.attachments ) { - if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; - texturesCube.emplace_back().aliasAttachment(attachment); - break; - } - } - 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, - }); - // any other shadowing light, even point lights, are split by shadow maps - } else { - for ( auto& attachment : renderMode.renderTarget.attachments ) { - 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{ - .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, - }); - textures2D.emplace_back().aliasAttachment(attachment, view); - } - } - } - } - } // attach VXGI voxels if ( uf::renderer::settings::experimental::vxgi ) { @@ -781,10 +764,10 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string }; uniforms.lengths = UniformDescriptor::Lengths{ - .lights = MIN( lights.size(), metadata.max.lights ), - .materials = MIN( materials.size(), metadata.max.textures2D ), - .textures = MIN( textures.size(), metadata.max.textures2D ), - // .drawCommands = MIN( drawCommands.size(), metadata.max.textures2D ), + .lights = MIN( uf::graph::storage.lights.size(), metadata.max.lights ), + .materials = MIN( uf::graph::storage.materials.keys.size(), metadata.max.textures2D ), + .textures = MIN( uf::graph::storage.textures.keys.size(), metadata.max.textures2D ), + .drawCommands = MIN( 0, metadata.max.textures2D ), }; uniforms.ambient = metadata.light.ambient; @@ -793,7 +776,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string uniforms.exposure = metadata.light.exposure; uniforms.msaa = ext::vulkan::settings::msaa; uniforms.shadowSamples = std::min( 0, metadata.shadow.samples ); - uniforms.indexSkybox = 0; + uniforms.indexSkybox = indexSkybox; } for ( auto* blitter : blitters ) { @@ -817,25 +800,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string if ( previousTextures[i] != graphic.material.textures[i].image ) shouldUpdate = true; } - - // update lighting buffer - shader.updateBuffer( (const void*) lights.data(), uniforms.lengths.lights * sizeof(pod::Light), renderMode.metadata.lightBufferIndex, false ); - // - if ( shouldUpdate ) { - 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(); - } + if ( shouldUpdate ) graphic.updatePipelines(); - // 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 diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index 613e16c7..20c60f9a 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -82,6 +82,11 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); renderMode.metadata.type = "vxgi"; + renderMode.metadata.pipeline = "vxgi"; + renderMode.metadata.pipelines.emplace_back("vxgi"); + if ( uf::renderer::settings::experimental::culling ) { + renderMode.metadata.pipelines.emplace_back("culling"); + } renderMode.metadata.samples = 1; renderMode.metadata.subpasses = metadata.cascades; @@ -99,6 +104,11 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { renderMode.metadata.json["shaders"]["compute"] = computeShaderFilename; renderMode.blitter.descriptor.renderMode = metadata.renderModeName; renderMode.blitter.descriptor.subpass = -1; + renderMode.blitter.descriptor.inputs.dispatch = { + (metadata.voxelSize.x / metadata.dispatchSize.x), + (metadata.voxelSize.y / metadata.dispatchSize.y), + (metadata.voxelSize.z / metadata.dispatchSize.z), + }; renderMode.blitter.process = true; size_t maxTextures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as(512); @@ -136,7 +146,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { if ( renderMode.blitter.initialized ) { auto& pipeline = renderMode.blitter.getPipeline(); pipeline.record(renderMode.blitter, commandBuffer); - vkCmdDispatch(commandBuffer, metadata.voxelSize.x / metadata.dispatchSize.x, metadata.voxelSize.y / metadata.dispatchSize.y, metadata.voxelSize.z / metadata.dispatchSize.z); + // vkCmdDispatch(commandBuffer, metadata.voxelSize.x / metadata.dispatchSize.x, metadata.voxelSize.y / metadata.dispatchSize.y, metadata.voxelSize.z / metadata.dispatchSize.z); } // generate mipmaps @@ -198,7 +208,6 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { controllerPosition.y = floor(controllerPosition.y); controllerPosition.z = floor(controllerPosition.z); controllerPosition += metadata.extents.min; - controllerPosition.x = floor(controllerPosition.x); controllerPosition.y = floor(controllerPosition.y); controllerPosition.z = -floor(controllerPosition.z); diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index 97617d8b..fadb5e28 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -349,7 +349,10 @@ void ext::Gui::load( const uf::Image& image ) { } metadataJson["cull mode"] = "none"; graphic.descriptor.parse( metadataJson ); - + if ( uf::matrix::reverseInfiniteProjection ) { + } else { + metadata.depth = -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; @@ -816,7 +819,8 @@ void ext::GuiBehavior::tick( uf::Object& self ) { .color = metadata.color, .mode = metadata.shader, - .depth = 1 - metadata.depth, + // .depth = 1 - metadata.depth, + .depth = uf::matrix::reverseInfiniteProjection ? 1 - metadata.depth : metadata.depth, }; // set glyph-based uniforms if ( isGlyph && uniform.size() == sizeof(::GlyphUniformDescriptor<>) ) { diff --git a/ext/main.cpp b/ext/main.cpp index f8c1f177..aa186be5 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -24,6 +24,7 @@ #include #include +#include #include @@ -241,6 +242,10 @@ void EXT_API ext::initialize() { } uf::allocator::override = ::config["engine"]["memory pool"]["override"].as( uf::allocator::override ); } + { + uf::Mesh::defaultInterleaved = ::config["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved ); + uf::matrix::reverseInfiniteProjection = ::config["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection ); + } /* Create initial scene (kludge) */ { uf::Scene& scene = uf::instantiator::instantiate(); //new uf::Scene; @@ -348,6 +353,7 @@ void EXT_API ext::initialize() { uf::renderer::settings::experimental::hdr = ::config["engine"]["ext"][RENDERER]["experimental"]["hdr"].as( uf::renderer::settings::experimental::hdr ); uf::renderer::settings::experimental::vxgi = ::config["engine"]["ext"][RENDERER]["experimental"]["vxgi"].as( uf::renderer::settings::experimental::vxgi ); uf::renderer::settings::experimental::deferredSampling = ::config["engine"]["ext"][RENDERER]["experimental"]["deferred sampling"].as( uf::renderer::settings::experimental::deferredSampling ); + uf::renderer::settings::experimental::culling = ::config["engine"]["ext"][RENDERER]["experimental"]["culling"].as( uf::renderer::settings::experimental::culling ); #define JSON_TO_VKFORMAT( key ) if ( ::config["engine"]["ext"][RENDERER]["formats"][#key].is() ) {\ uf::stl::string format = ::config["engine"]["ext"][RENDERER]["formats"][#key].as();\ format = uf::string::replace( uf::string::uppercase(format), " ", "_" );\ @@ -408,7 +414,12 @@ void EXT_API ext::initialize() { if ( ::config["engine"]["render modes"]["deferred"].as() ) { uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" ); auto& renderMode = uf::renderer::getRenderMode("Deferred", true); - if ( ::config["engine"]["render modes"]["stereo deferred"].as() ) renderMode.metadata.eyes = 2; + if ( ::config["engine"]["render modes"]["stereo deferred"].as() ) { + renderMode.metadata.eyes = 2; + } + if ( uf::renderer::settings::experimental::culling ) { + renderMode.metadata.pipelines.emplace_back("culling"); + } } #endif @@ -470,7 +481,6 @@ void EXT_API ext::initialize() { }); } #endif - uf::renderer::initialize(); } @@ -622,6 +632,9 @@ void EXT_API ext::tick() { } #endif //UF_TIMER_TRACE("ticking physics"); + /* Update graph */ { + uf::graph::tick(); + } /* Update entities */ { uf::scene::tick(); } @@ -740,7 +753,12 @@ void EXT_API ext::terminate() { ext::lua::terminate(); } #endif - uf::scene::destroy(); + { + uf::graph::destroy(); + } + { + uf::scene::destroy(); + } /* Garbage collection */ if ( false ) { uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as(); diff --git a/g++.exe.stackdump b/g++.exe.stackdump deleted file mode 100644 index 93d4857c..00000000 --- a/g++.exe.stackdump +++ /dev/null @@ -1,24 +0,0 @@ -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