diff --git a/Assets/CollisionTags.SHConfig b/Assets/CollisionTags.SHConfig new file mode 100644 index 00000000..d3ebe7e2 --- /dev/null +++ b/Assets/CollisionTags.SHConfig @@ -0,0 +1,16 @@ +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +11 12 +12 13 +13 14 +14 15 +15 16 diff --git a/Assets/Fonts/ALGER.shfont b/Assets/Fonts/ALGER.shfont new file mode 100644 index 00000000..1acab9da Binary files /dev/null and b/Assets/Fonts/ALGER.shfont differ diff --git a/Assets/Fonts/ALGER.shfont.shmeta b/Assets/Fonts/ALGER.shfont.shmeta new file mode 100644 index 00000000..e6350c15 --- /dev/null +++ b/Assets/Fonts/ALGER.shfont.shmeta @@ -0,0 +1,3 @@ +Name: ALGER +ID: 182525173 +Type: 10 diff --git a/Assets/Fonts/ALGER.ttf b/Assets/Fonts/ALGER.ttf new file mode 100644 index 00000000..dcc72ae9 Binary files /dev/null and b/Assets/Fonts/ALGER.ttf differ diff --git a/Assets/Fonts/SegoeUI.shfont b/Assets/Fonts/SegoeUI.shfont new file mode 100644 index 00000000..321f62c8 Binary files /dev/null and b/Assets/Fonts/SegoeUI.shfont differ diff --git a/Assets/Fonts/SegoeUI.shfont.shmeta b/Assets/Fonts/SegoeUI.shfont.shmeta new file mode 100644 index 00000000..33ee953d --- /dev/null +++ b/Assets/Fonts/SegoeUI.shfont.shmeta @@ -0,0 +1,3 @@ +Name: SegoeUI +ID: 176667660 +Type: 10 diff --git a/Assets/Fonts/SegoeUI.ttf b/Assets/Fonts/SegoeUI.ttf new file mode 100644 index 00000000..46b3b993 Binary files /dev/null and b/Assets/Fonts/SegoeUI.ttf differ diff --git a/Assets/Materials/UIMat.shmat b/Assets/Materials/UIMat.shmat new file mode 100644 index 00000000..b31fed2e --- /dev/null +++ b/Assets/Materials/UIMat.shmat @@ -0,0 +1,8 @@ +- VertexShader: 46580970 + FragmentShader: 35983630 + SubPass: G-Buffer Write + Properties: + data.color: {x: 1, y: 1, z: 1, w: 1} + data.textureIndex: 0 + data.alpha: 0 + data.beta: {x: 1, y: 1, z: 1} \ No newline at end of file diff --git a/Assets/Materials/UIMat.shmat.shmeta b/Assets/Materials/UIMat.shmat.shmeta new file mode 100644 index 00000000..2a2d2572 --- /dev/null +++ b/Assets/Materials/UIMat.shmat.shmeta @@ -0,0 +1,3 @@ +Name: UIMat +ID: 129340704 +Type: 7 diff --git a/Assets/Models/Quad.gltf b/Assets/Models/Quad.gltf new file mode 100644 index 00000000..493c164d --- /dev/null +++ b/Assets/Models/Quad.gltf @@ -0,0 +1,104 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v3.3.27", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Quad" + } + ], + "meshes" : [ + { + "name" : "Plane", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "NORMAL" : 1, + "TEXCOORD_0" : 2 + }, + "indices" : 3 + } + ] + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 4, + "max" : [ + 0.5, + 0.5, + 3.774895063202166e-08 + ], + "min" : [ + -0.5, + -0.5, + -3.774895063202166e-08 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 4, + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 4, + "type" : "VEC2" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 6, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 48, + "byteOffset" : 0, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 48, + "byteOffset" : 48, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 32, + "byteOffset" : 96, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 12, + "byteOffset" : 128, + "target" : 34963 + } + ], + "buffers" : [ + { + "byteLength" : 140, + "uri" : "data:application/octet-stream;base64,AAAAvwAAAL9pISIzAAAAPwAAAL9pISIzAAAAvwAAAD9pISKzAAAAPwAAAD9pISKzAAAAAGkhojMAAIA/AAAAAGkhojMAAIA/AAAAAGkhojMAAIA/AAAAAGkhojMAAIA/AAAAAAAAgD8AAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAEAAwAAAAMAAgA=" + } + ] +} diff --git a/Assets/Models/Quad.shmodel b/Assets/Models/Quad.shmodel new file mode 100644 index 00000000..aebbb0a6 Binary files /dev/null and b/Assets/Models/Quad.shmodel differ diff --git a/Assets/Models/Quad.shmodel.shmeta b/Assets/Models/Quad.shmodel.shmeta new file mode 100644 index 00000000..9fbd4b9c --- /dev/null +++ b/Assets/Models/Quad.shmodel.shmeta @@ -0,0 +1,7 @@ +Name: Quad +ID: 80501355 +Type: 4 +Sub Assets: +Name: Quad +ID: 141771688 +Type: 8 diff --git a/Assets/Shaders/DebugDraw_VS.glsl b/Assets/Shaders/DebugDraw_VS.glsl index cb0886d1..7b370730 100644 --- a/Assets/Shaders/DebugDraw_VS.glsl +++ b/Assets/Shaders/DebugDraw_VS.glsl @@ -15,6 +15,9 @@ layout(set = 2, binding = 0) uniform CameraData { vec4 position; mat4 vpMat; + mat4 viewMat; + mat4 perspectiveMat; + mat4 orthoMat; } cameraData; void main() diff --git a/Assets/Shaders/TestCube_VS.glsl b/Assets/Shaders/TestCube_VS.glsl index 0e055395..774bc580 100644 --- a/Assets/Shaders/TestCube_VS.glsl +++ b/Assets/Shaders/TestCube_VS.glsl @@ -34,7 +34,8 @@ layout(set = 2, binding = 0) uniform CameraData vec4 position; mat4 vpMat; mat4 viewMat; - mat4 projMat; + mat4 perspectiveMat; + mat4 orthoMat; } cameraData; void main() diff --git a/Assets/Shaders/TestCube_VS.shshaderb b/Assets/Shaders/TestCube_VS.shshaderb index fb282b4d..28c4655b 100644 Binary files a/Assets/Shaders/TestCube_VS.shshaderb and b/Assets/Shaders/TestCube_VS.shshaderb differ diff --git a/Assets/Shaders/Text_FS.glsl b/Assets/Shaders/Text_FS.glsl new file mode 100644 index 00000000..fdf32583 --- /dev/null +++ b/Assets/Shaders/Text_FS.glsl @@ -0,0 +1,59 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +#extension GL_EXT_nonuniform_qualifier : require + +struct MatPropData +{ + vec4 color; + int textureIndex; + float alpha; + vec3 beta; +}; + +layout(location = 0) in struct +{ + vec4 vertPos; // location 0 + vec2 uv; // location = 1 + vec4 normal; // location = 2 + +} In; + +// material stuff +layout(location = 3) flat in struct +{ + uint eid; + vec3 textColor; +} In2; + + + +layout(set = 4, binding = 0) uniform sampler2D fontBitmap; + +layout(location = 0) out vec4 color; +layout(location = 1) out uint outEntityID; + +float median(float r, float g, float b) +{ + return max(min(r, g), min(max(r, g), b)); +} + +void main() +{ + vec3 msd = texture (fontBitmap, In.uv).rgb; + float sd = median (msd.r, msd.g, msd.b); + float screenPxDistance = 2 * (sd - 0.5f); + float opacity = clamp (screenPxDistance + 0.5f, 0.0f, 2.0f); + + vec4 fragColor; + + if (opacity < 0.2f) + discard; + else + fragColor = mix(vec4(0.0f), vec4(In2.textColor, 1.0f), min (opacity, 1.0f)); + + // fragColor = vec4 (1.0f); + + color = fragColor; + outEntityID = In2.eid; +} \ No newline at end of file diff --git a/Assets/Shaders/Text_FS.shshaderb b/Assets/Shaders/Text_FS.shshaderb new file mode 100644 index 00000000..d9b47d6e Binary files /dev/null and b/Assets/Shaders/Text_FS.shshaderb differ diff --git a/Assets/Shaders/Text_FS.shshaderb.shmeta b/Assets/Shaders/Text_FS.shshaderb.shmeta new file mode 100644 index 00000000..af5a44b7 --- /dev/null +++ b/Assets/Shaders/Text_FS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: Text_FS +ID: 38024754 +Type: 2 diff --git a/Assets/Shaders/Text_VS.glsl b/Assets/Shaders/Text_VS.glsl new file mode 100644 index 00000000..3501a13d --- /dev/null +++ b/Assets/Shaders/Text_VS.glsl @@ -0,0 +1,101 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + +//#include "ShaderDescriptorDefinitions.glsl" + + +// vertex inputs +layout(location = 0) in vec4 positionalOffset; +layout(location = 1) in uint glyphIndex; + +// between shader stages +layout(location = 0) out struct +{ + vec4 vertPos; // location 0 + vec2 uv; // location = 1 + vec4 normal; // location = 2 + +} Out; + +// material stuff +layout(location = 3) out struct +{ + uint eid; + vec3 textColor; +} Out2; + +// Camera data +layout(set = 2, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 perspectiveMat; + mat4 orthoMat; +} cameraData; + +// push constants +layout(std140, push_constant) uniform TestPushConstant +{ + mat4 worldTransform; + uint eid; + vec3 textColor; + +} testPushConstant; + +// Descriptor sets +layout(std430, set = 4, binding = 1) buffer GlyphTransforms +{ + mat4 matrices[]; +} glyphTransforms; + +vec2 CreateQuad(in uint vertexID) +{ + uint b = 1 << vertexID; + return vec2 ((0x3 & b) != 0, (0x9 & b) != 0); +} + +void main() +{ + // write EID data to FS + Out2.eid = testPushConstant.eid; + + // local variable for font index + uint fontIndex = glyphIndex; + + // get font data + mat4 fontData = glyphTransforms.matrices[fontIndex]; + + // Generate UV coords and vertex positions + Out.uv = CreateQuad(gl_VertexIndex); + vec3 vertexPos = vec3(Out.uv, 0.0f); + + // Get the local matrices + mat4 localModel = testPushConstant.worldTransform; + + //mat4 uiScale = mat4(1.0f); + //uiScale[0][0] = cameraData.cameraRight / 20.49f; + //uiScale[1][1] = cameraData.cameraTop / 11.323f; + + // transform the UV to atlas space to sample the font bitmap correctly + Out.uv = vec2(mat3(fontData) * vec3(Out.uv, 1.0f)); + + // Matrix to transform the quad from local to font space (for a font to be of correct size) + mat3 toFontSpace = mat3(1.0f); + toFontSpace[0][0] = fontData[3][0]; + toFontSpace[1][1] = fontData[3][1]; + toFontSpace[2][0] = positionalOffset.x; + toFontSpace[2][1] = positionalOffset.y; + + // Initialize variables for use in FS + //characterIndex = gl_InstanceID; + + // Transform the vertices to font space + vertexPos = toFontSpace * vec3(vertexPos.xy, 1.0f); + + Out2.textColor = testPushConstant.textColor; + + // transform the vertex position to font space + gl_Position = cameraData.orthoMat * localModel * vec4(vertexPos, 1.0f); + // gl_Position = vec4(vertexPos, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/Text_VS.shshaderb b/Assets/Shaders/Text_VS.shshaderb new file mode 100644 index 00000000..25eff84a Binary files /dev/null and b/Assets/Shaders/Text_VS.shshaderb differ diff --git a/Assets/Shaders/Text_VS.shshaderb.shmeta b/Assets/Shaders/Text_VS.shshaderb.shmeta new file mode 100644 index 00000000..17df2e98 --- /dev/null +++ b/Assets/Shaders/Text_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: Text_VS +ID: 39816727 +Type: 2 diff --git a/Assets/Shaders/ToSwapchain_FS.glsl b/Assets/Shaders/ToSwapchain_FS.glsl new file mode 100644 index 00000000..a68fa0c7 --- /dev/null +++ b/Assets/Shaders/ToSwapchain_FS.glsl @@ -0,0 +1,14 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +#extension GL_EXT_nonuniform_qualifier : require + +layout (input_attachment_index = 0, set = 4, binding = 0) uniform subpassInput sceneTexture; + + +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = vec4 (subpassLoad(sceneTexture).rgb, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/ToSwapchain_FS.shshaderb b/Assets/Shaders/ToSwapchain_FS.shshaderb new file mode 100644 index 00000000..b10a9d6c Binary files /dev/null and b/Assets/Shaders/ToSwapchain_FS.shshaderb differ diff --git a/Assets/Shaders/ToSwapchain_FS.shshaderb.shmeta b/Assets/Shaders/ToSwapchain_FS.shshaderb.shmeta new file mode 100644 index 00000000..731b2783 --- /dev/null +++ b/Assets/Shaders/ToSwapchain_FS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ToSwapchain_FS +ID: 36869006 +Type: 2 diff --git a/Assets/Shaders/ToSwapchain_VS.glsl b/Assets/Shaders/ToSwapchain_VS.glsl new file mode 100644 index 00000000..eee22015 --- /dev/null +++ b/Assets/Shaders/ToSwapchain_VS.glsl @@ -0,0 +1,15 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + + +vec2 CreateQuad(in uint vertexID) +{ + uint b = 1 << vertexID; + return vec2 ((0x3 & b) != 0, (0x9 & b) != 0); +} + +void main() +{ + vec2 vertexPos = 2 * (CreateQuad(gl_VertexIndex) - vec2(0.5f)); + gl_Position = vec4 (vertexPos, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/ToSwapchain_VS.shshaderb b/Assets/Shaders/ToSwapchain_VS.shshaderb new file mode 100644 index 00000000..4c3157f9 Binary files /dev/null and b/Assets/Shaders/ToSwapchain_VS.shshaderb differ diff --git a/Assets/Shaders/ToSwapchain_VS.shshaderb.shmeta b/Assets/Shaders/ToSwapchain_VS.shshaderb.shmeta new file mode 100644 index 00000000..23bcbe08 --- /dev/null +++ b/Assets/Shaders/ToSwapchain_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ToSwapchain_VS +ID: 48082949 +Type: 2 diff --git a/Assets/Shaders/UI_FS.glsl b/Assets/Shaders/UI_FS.glsl new file mode 100644 index 00000000..4f919a04 --- /dev/null +++ b/Assets/Shaders/UI_FS.glsl @@ -0,0 +1,50 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +#extension GL_EXT_nonuniform_qualifier : require + +struct MatPropData +{ + vec4 color; + int textureIndex; + float alpha; + vec3 beta; +}; + +layout(location = 0) in struct +{ + vec4 vertPos; // location 0 + vec2 uv; // location = 1 + vec4 normal; // location = 2 + +} In; + +// material stuff +layout(location = 3) flat in struct +{ + int materialIndex; + uint eid; + uint lightLayerIndex; +} In2; + +layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global) +layout (std430, set = 3, binding = 0) buffer MaterialProperties // For materials +{ + MatPropData data[]; +} MatProp; + +layout(location = 0) out vec4 position; +layout(location = 1) out uint outEntityID; +layout(location = 2) out uint lightLayerIndices; +layout(location = 3) out vec4 normals; +layout(location = 4) out vec4 albedo; + +void main() +{ + position = In.vertPos; + normals = In.normal; + albedo = vec4(1.0f); + + outEntityID = In2.eid; + lightLayerIndices = In2.lightLayerIndex; +} \ No newline at end of file diff --git a/Assets/Shaders/UI_FS.shshaderb b/Assets/Shaders/UI_FS.shshaderb new file mode 100644 index 00000000..6be9c565 Binary files /dev/null and b/Assets/Shaders/UI_FS.shshaderb differ diff --git a/Assets/Shaders/UI_FS.shshaderb.shmeta b/Assets/Shaders/UI_FS.shshaderb.shmeta new file mode 100644 index 00000000..80bb5dad --- /dev/null +++ b/Assets/Shaders/UI_FS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: UI_FS +ID: 35983630 +Type: 2 diff --git a/Assets/Shaders/UI_VS.glsl b/Assets/Shaders/UI_VS.glsl new file mode 100644 index 00000000..c4393b98 --- /dev/null +++ b/Assets/Shaders/UI_VS.glsl @@ -0,0 +1,66 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + +//#include "ShaderDescriptorDefinitions.glsl" + + +layout(location = 0) in vec3 aVertexPos; +layout(location = 1) in vec2 aUV; +layout(location = 2) in vec3 aNormal; +layout(location = 3) in vec3 aTangent; +layout(location = 4) in mat4 worldTransform; +layout(location = 8) in uvec2 integerData; + + +layout(location = 0) out struct +{ + vec4 vertPos; // location 0 + vec2 uv; // location = 1 + vec4 normal; // location = 2 + +} Out; + +// material stuff +layout(location = 3) out struct +{ + int materialIndex; + uint eid; + uint lightLayerIndex; + +} Out2; + +layout(set = 2, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 perspectiveMat; + mat4 orthoMat; +} cameraData; + +void main() +{ + Out2.materialIndex = gl_InstanceIndex; + Out2.eid = integerData[0]; + Out2.lightLayerIndex = integerData[1]; + + // for transforming gBuffer position and normal data + mat4 modelViewMat = cameraData.viewMat * worldTransform; + + // gBuffer position will be in view space + Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); + + // uvs for texturing in fragment shader + Out.uv = aUV; + + mat3 transposeInv = mat3 (transpose(inverse(modelViewMat))); + + // normals are also in view space + Out.normal.rgb = transposeInv * aNormal.rgb; + Out.normal.rgb = normalize (Out.normal.rgb); + + // clip space for rendering + gl_Position = cameraData.orthoMat * worldTransform * vec4 (aVertexPos, 1.0f); + gl_Position.z += 0.1f; // HAX + // gl_Position = vec4 (aVertexPos, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/UI_VS.shshaderb b/Assets/Shaders/UI_VS.shshaderb new file mode 100644 index 00000000..a1f1a8b7 Binary files /dev/null and b/Assets/Shaders/UI_VS.shshaderb differ diff --git a/Assets/Shaders/UI_VS.shshaderb.shmeta b/Assets/Shaders/UI_VS.shshaderb.shmeta new file mode 100644 index 00000000..08fa8435 --- /dev/null +++ b/Assets/Shaders/UI_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: UI_VS +ID: 46580970 +Type: 2 diff --git a/Dependencies.bat b/Dependencies.bat index 44185ff8..ba411815 100644 --- a/Dependencies.bat +++ b/Dependencies.bat @@ -6,7 +6,7 @@ echo --------------------------------------------------- echo "SHADE DEPENDENCIES (Default - All in 10 Seconds)" echo "A - All" echo "B - VMA" -echo "C - msdf" +echo "C - FontCompiler" echo "D - ModelCompiler" echo "E - spdlog" echo "F - reactphysics3d" @@ -28,7 +28,7 @@ set _e=%ERRORLEVEL% if %_e%==1 goto VMA if %_e%==2 goto VMA -if %_e%==3 goto MSDF +if %_e%==3 goto FontCompiler if %_e%==4 goto ModelCompiler if %_e%==5 goto spdlog if %_e%==6 goto reactphysics3d @@ -47,12 +47,13 @@ if %_e%==16 goto fmod echo -----------------------VMA---------------------------- rmdir "Dependencies/VMA" /S /Q git clone https://github.com/SHADE-DP/VulkanMemoryAllocator.git "Dependencies/VMA" -if %_e%==2 (goto :done) else (goto :MSDF) +if %_e%==2 (goto :done) else (goto :FontCompiler) -:MSDF -echo -----------------------MSDF---------------------------- -rmdir "Dependencies/msdf" /S /Q -git clone --recurse-submodules https://github.com/SHADE-DP/msdf-atlas-gen.git "Dependencies/msdf" +:FontCompiler +echo -----------------------FontCompiler---------------------------- +rmdir "Dependencies/FontCompiler" /S /Q +git clone https://github.com/SHADE-DP/FontCompiler.git "Dependencies/FontCompiler" +git clone --recurse-submodules https://github.com/SHADE-DP/msdf-atlas-gen "Dependencies/FontCompiler/Dependencies/msdf" if %_e%==3 (goto :done) else (goto :ModelCompiler) :ModelCompiler diff --git a/Dependencies.lua b/Dependencies.lua index 2e24222b..fe75c3f4 100644 --- a/Dependencies.lua +++ b/Dependencies.lua @@ -3,8 +3,9 @@ IncludeDir["ModelCompiler"] = "%{wks.location}\\Dependencies\\ModelCompiler" IncludeDir["imgui"] = "%{wks.location}\\Dependencies\\imgui" IncludeDir["imguizmo"] = "%{wks.location}\\Dependencies\\imguizmo" IncludeDir["imnodes"] = "%{wks.location}\\Dependencies\\imnodes" -IncludeDir["msdf_atlas_gen"] = "%{wks.location}\\Dependencies\\msdf" -IncludeDir["msdfgen"] = "%{wks.location}\\Dependencies\\msdf\\msdfgen" +IncludeDir["FontCompiler"] = "%{wks.location}\\Dependencies\\FontCompiler" +IncludeDir["msdf_atlas_gen"] = "%{wks.location}\\Dependencies\\FontCompiler\\Dependencies\\msdf" +IncludeDir["msdfgen"] = "%{wks.location}\\Dependencies\\FontCompiler\\Dependencies\\msdf\\msdfgen" IncludeDir["spdlog"] = "%{wks.location}\\Dependencies\\spdlog" IncludeDir["tracy"] = "%{wks.location}\\Dependencies\\tracy" IncludeDir["VMA"] = "%{wks.location}\\Dependencies\\VMA" diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index cba0c35e..014df726 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -38,7 +38,9 @@ project "SHADE_Application" "%{IncludeDir.spdlog}/include", "%{IncludeDir.tinyddsloader}", "%{IncludeDir.reactphysics3d}\\include", - "%{IncludeDir.yamlcpp}" + "%{IncludeDir.yamlcpp}", + "%{IncludeDir.msdf_atlas_gen}", + "%{IncludeDir.msdfgen}" } externalwarnings "Off" @@ -76,7 +78,10 @@ project "SHADE_Application" "26451", "26437", "4275", - "4635" + "4633", + "4634", + "4635", + "4638" } linkoptions { "-IGNORE:4006" } diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 291fdcb1..1a00941f 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -80,9 +80,12 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); + //std::system("FontCompiler.exe ../../Assets/Fonts/SegoeUI.ttf"); + //std::system("FontCompiler.exe ../../Assets/Fonts/ALGER.ttf"); SHSystemManager::CreateSystem(); SHGraphicsSystem* graphicsSystem = static_cast(SHSystemManager::GetSystem()); + SHPhysicsSystem* physicsSystem = SHSystemManager::GetSystem(); // Link up SHDebugDraw SHSystemManager::CreateSystem(); @@ -140,7 +143,7 @@ namespace Sandbox //SHComponentManager::CreateComponentSparseSet(); SHAssetManager::Load(); - + //auto font = SHAssetManager::GetData(176667660); SHSystemManager::RegisterRoutine(); @@ -160,26 +163,49 @@ namespace Sandbox void SBApplication::Update(void) { SHGraphicsSystem* graphicsSystem = SHADE::SHSystemManager::GetSystem(); + +#ifdef SHEDITOR SHEditor* editor = SHADE::SHSystemManager::GetSystem(); +#endif + //TODO: Change true to window is open while (!window.WindowShouldClose()) { SHFrameRateController::UpdateFRC(); SHInputManager::UpdateInput(SHFrameRateController::GetRawDeltaTime()); SHSceneManager::UpdateSceneManager(); + #ifdef SHEDITOR if(editor->editorState == SHEditor::State::PLAY) - SHSceneManager::SceneUpdate(0.016f); -#endif - SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f); - editor->PollPicking(); +#endif + SHSceneManager::SceneUpdate(0.016f); +#ifdef SHEDITOR + SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, SHFrameRateController::GetRawDeltaTime()); + editor->PollPicking(); +#else + SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime()); +#endif + // TODO: Move into an Editor menu static bool drawColliders = false; if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) { drawColliders = !drawColliders; SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders); } + static bool drawRays = false; + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F11)) + { + drawRays = !drawRays; + SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); + } + static bool drawContacts = false; + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9)) + { + drawContacts = !drawContacts; + SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts); + SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts); + } } // Finish all graphics jobs first graphicsSystem->AwaitGraphicsExecution(); diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp index b14f2e6f..e9611fd8 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -7,12 +7,14 @@ #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Scene/SHSceneManager.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" +#include "Physics/System/SHPhysicsSystem.h" #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Assets/SHAssetManager.h" #include "Camera/SHCameraComponent.h" @@ -41,6 +43,28 @@ namespace Sandbox void SBMainScene::Init() { sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID); + + auto* physicsSystem = SHSystemManager::GetSystem(); + if (!physicsSystem) + { + SHLOGV_CRITICAL("Failed to get the physics system for building the scene!") + return; + } + + physicsSystem->BuildScene(SHSceneManager::GetCurrentSceneGraph()); + + /*-----------------------------------------------------------------------*/ + /* TESTING CODE */ + /*-----------------------------------------------------------------------*/ + //testText = SHEntityManager::CreateEntity(MAX_EID, "Test Text"); + //auto gfxSystem =SHSystemManager::GetSystem(); + + //auto textComp = SHComponentManager::GetComponent(testText); + + //textComp->SetFont(gfxSystem->GetFontLibrary().GetFonts()[0]); + /*-----------------------------------------------------------------------*/ + /* TESTING CODE */ + /*-----------------------------------------------------------------------*/ } void SBMainScene::Update(float dt) diff --git a/SHADE_Application/src/Scenes/SBMainScene.h b/SHADE_Application/src/Scenes/SBMainScene.h index 7bd10118..18d43e33 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.h +++ b/SHADE_Application/src/Scenes/SBMainScene.h @@ -12,6 +12,8 @@ namespace Sandbox EntityID testObj; std::vector stressTestObjects; + EntityID testText; + public: virtual void Load(); virtual void Init(); diff --git a/SHADE_CSharp/premake5.lua b/SHADE_CSharp/premake5.lua index 39ef8281..8844b84c 100644 --- a/SHADE_CSharp/premake5.lua +++ b/SHADE_CSharp/premake5.lua @@ -50,6 +50,9 @@ project "SHADE_CSharp" function platformsElementCS(cfg) _p(2,'x64') end + function configElementCS(cfg) + _p(2,'Debug;Release;Publish') + end function docsElementCS(cfg) _p(2,'true') end @@ -59,6 +62,6 @@ project "SHADE_CSharp" premake.override(premake.vstudio.cs2005.elements, "projectProperties", function (oldfn, cfg) return table.join(oldfn(cfg), { - platformsElementCS, docsElementCS, docsLocationElementCS, + platformsElementCS, configElementCS, docsElementCS, docsLocationElementCS, }) end) \ No newline at end of file diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index 1d6d7bef..7fb7291d 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -79,7 +79,10 @@ project "SHADE_Engine" "26451", "26437", "4275", - "4635" + "4633", + "4634", + "4635", + "4638" } linkoptions { "-IGNORE:4006" } @@ -119,6 +122,7 @@ project "SHADE_Engine" { "xcopy /r /y /q \"%{IncludeDir.ModelCompiler}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.ModelCompiler}\\bin\\Debug\\ModelCompiler.exe\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.FontCompiler}\\bin\\Debug\\FontCompiler.exe\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodL.dll\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudioL.dll\" \"$(OutDir)\"" } @@ -128,6 +132,7 @@ project "SHADE_Engine" { "xcopy /r /y /q \"%{IncludeDir.ModelCompiler}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.ModelCompiler}\\bin\\Release\\ModelCompiler.exe\" \"$(OutDir)\"", + "xcopy /r /y /q \"%{IncludeDir.FontCompiler}\\bin\\Release\\FontCompiler.exe\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmod.dll\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\"" } diff --git a/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h new file mode 100644 index 00000000..8d2cb67a --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHFontAsset.h @@ -0,0 +1,47 @@ +#pragma once + +#include "SHAssetData.h" +#include "SH_API.h" +#include +#include +#include "msdf-atlas-gen/msdf-atlas-gen.h" +#include "math/SHMatrix.h" + +namespace SHADE +{ + struct SH_API SHFontAsset : SHAssetData + { + using GlyphData = SHMatrix; + static constexpr uint32_t NUM_CHANNELS = 3; + static constexpr uint32_t BYTES_PER_CHANNEL = 3; + static constexpr uint8_t BASELINE_LEFT_MATRIX_INDEX_ROW = 3; + static constexpr uint8_t BASELINE_LEFT_MATRIX_INDEX_COL = 2; + static constexpr uint8_t BASELINE_BOTTOM_MATRIX_INDEX_ROW = 3; + static constexpr uint8_t BASELINE_BOTTOM_MATRIX_INDEX_COL = 3; + + /*-----------------------------------------------------------------------*/ + /* MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + //! Name of the shader file (without parent path) + std::string fontName; + + //! Glyphs. Corresponds to the transformation container below. + std::vector glyphs; + + //! Data containing character and uv transformation data and other misc data + std::vector glyphTransformations; + + //! The actual data of the atlas to go into the binary. Was unique_ptr, vector easier to copy. + std::vector bitmapData; + + //! Width of the bitmap + uint32_t bitmapWidth; + + //! Height of the bitmap + uint32_t bitmapHeight; + + //! Font geometry required to get kerning from + msdf_atlas::FontGeometry fontGeometry; + + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp new file mode 100644 index 00000000..7217b551 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.cpp @@ -0,0 +1,83 @@ +#include "SHpch.h" +#include "SHFontLoader.h" +#include "Assets/Asset Types/SHFontAsset.h" +#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" +#include "msdf-atlas-gen/msdf-atlas-gen.h" + +#include +#include +#include +#include + +namespace SHADE +{ + SHADE::SHAssetData* SHFontLoader::Load(AssetPath path) + { + auto newFontAsset = new SHFontAsset(); + + std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open compiled font file: {}", path.string()); + return nullptr; + } + + // Attempt to load font geometry for advance data + auto ttfFilePath = path.string(); + ttfFilePath = ttfFilePath.substr(0, ttfFilePath.find_last_of('.')); + ttfFilePath += TTF_EXTENSION.data(); + msdfgen::FontHandle* fontHandle = nullptr; + fontHandle = msdfgen::loadFont(SHFreetypeInstance::GetFreetypeHandle(), ttfFilePath.c_str()); + newFontAsset->fontGeometry.loadCharset(fontHandle, 1.0f, msdf_atlas::Charset::ASCII); + + uint32_t numGlyphs = 0; + + // read how many glyphs we have + file.read (reinterpret_cast(&numGlyphs), sizeof (uint32_t)); + + newFontAsset->glyphs.resize(numGlyphs); + newFontAsset->glyphTransformations.resize(numGlyphs); + + for (uint32_t i = 0; i < numGlyphs; ++i) + { + // Read the data for the glyph + file.read(reinterpret_cast(&newFontAsset->glyphs[i]), sizeof(msdf_atlas::unicode_t)); + } + + for (uint32_t i = 0; i < numGlyphs; ++i) + { + // Read the data for the glyph transformations + file.read(reinterpret_cast(&newFontAsset->glyphTransformations[i]), sizeof(SHMatrix)); + } + + // read the width + file.read(reinterpret_cast(&newFontAsset->bitmapWidth), sizeof(SHFontAsset::bitmapWidth)); + + // read the height + file.read(reinterpret_cast(&newFontAsset->bitmapHeight), sizeof(SHFontAsset::bitmapHeight)); + + uint32_t bytesRequired = 0; + file.read(reinterpret_cast(&bytesRequired), sizeof(uint32_t)); + + // Read the bitmap + newFontAsset->bitmapData.resize(bytesRequired); + file.read(reinterpret_cast(newFontAsset->bitmapData.data()), bytesRequired); + + + file.close(); + + return newFontAsset; + } + + void SHFontLoader::Write(SHAssetData const* data, AssetPath path) + { + /* + Stuff to write to binary file : + - Interleaved per character data + - codepoint (actual character) + - 4x4 Matrix data (stores UV transform + extra data) + - Actual atlas texture + */ + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.h new file mode 100644 index 00000000..7221d2f2 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHFontLoader.h @@ -0,0 +1,24 @@ +/*************************************************************************//** + * \file SHSFontLoader.h + * \author Loh Xiao Qi + * \date 23 10 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ + +#pragma once + +#include "Assets/Libraries/Loaders/SHAssetLoader.h" + +namespace SHADE +{ + struct SHFontLoader : SHAssetLoader + { + + SHAssetData* Load(AssetPath path) override; + void Write(SHAssetData const* data, AssetPath path) override; + }; +} diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h index 44dfd5c5..5ab1945d 100644 --- a/SHADE_Engine/src/Assets/SHAssetMacros.h +++ b/SHADE_Engine/src/Assets/SHAssetMacros.h @@ -67,8 +67,9 @@ constexpr std::string_view ASSET_ROOT {"../../Assets"}; constexpr std::string_view BUILT_IN_ASSET_ROOT{ "../../Built_In" }; #endif -// COMPILER PATHS +// COMPILER EXE constexpr std::string_view MODEL_COMPILER_EXE{ "ModelCompiler.exe" }; +constexpr std::string_view FONT_COMPILER_EXE{ "FontCompiler.exe" }; // INTERNAL ASSET PATHS constexpr std::string_view SCENE_FOLDER{ "/Scenes/" }; @@ -81,14 +82,14 @@ constexpr std::string_view META_EXTENSION {".shmeta"}; constexpr std::string_view AUDIO_EXTENSION {".ogg"}; constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"}; constexpr std::string_view SHADER_EXTENSION{ ".shshader" }; -constexpr std::string_view SHADER_BUILT_IN_EXTENSION{".shshaderb"}; +constexpr std::string_view SHADER_BUILT_IN_EXTENSION{ ".shshaderb" }; +constexpr std::string_view FONT_EXTENSION{ ".shfont" }; constexpr std::string_view SCRIPT_EXTENSION {".cs"}; constexpr std::string_view SCENE_EXTENSION {".shade"}; constexpr std::string_view PREFAB_EXTENSION {".shprefab"}; constexpr std::string_view MATERIAL_EXTENSION {".shmat"}; constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; constexpr std::string_view MODEL_EXTENSION{ ".shmodel" }; -constexpr std::string_view FONT_EXTENSION{ ".shfont" }; constexpr std::string_view EXTENSIONS[] = { AUDIO_EXTENSION, diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index eecbeaea..19ed7d9c 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -20,6 +20,7 @@ #include "Libraries/Loaders/SHTextureLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h" #include "Libraries/Loaders/SHTextBasedLoader.h" +#include "Libraries/Loaders/SHFontLoader.h" //#include "Libraries/Compilers/SHMeshCompiler.h" #include "Libraries/Compilers/SHTextureCompiler.h" @@ -392,7 +393,13 @@ namespace SHADE auto const ext{ path.extension().string() }; if (ext == GLSL_EXTENSION.data()) { - newPath = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); + auto value { SHShaderSourceCompiler::LoadAndCompileShader(path) }; + if (!value.has_value()) + { + SHLOG_ERROR("Shader compile failed: {}", path.string()); + return; + } + newPath = value.value(); } else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data()) { @@ -414,6 +421,16 @@ namespace SHADE } newPath = pathGen.value(); } + else if (ext == TTF_EXTENSION.data()) + { + std::string command = FONT_COMPILER_EXE.data(); + command += " " + path.string(); + std::system(command.c_str()); + + std::string fontPath = path.string().substr(0, path.string().find_last_of('.')); + fontPath += FONT_EXTENSION; + newPath = fontPath; + } else { SHLOG_WARNING("[Asset Manager] File Type compilation not yet Implemented: {}", path.string()); @@ -466,6 +483,8 @@ namespace SHADE loaders[static_cast(AssetType::PREFAB)] = loaders[static_cast(AssetType::SCENE)]; loaders[static_cast(AssetType::MATERIAL)] = loaders[static_cast(AssetType::SCENE)]; loaders[static_cast(AssetType::MESH)] = nullptr; + loaders[static_cast(AssetType::SCRIPT)] = nullptr; + loaders[static_cast(AssetType::FONT)] = dynamic_cast(new SHFontLoader()); } /**************************************************************************** diff --git a/SHADE_Engine/src/Camera/SHCameraDirector.cpp b/SHADE_Engine/src/Camera/SHCameraDirector.cpp index ec539fa1..29e2dcde 100644 --- a/SHADE_Engine/src/Camera/SHCameraDirector.cpp +++ b/SHADE_Engine/src/Camera/SHCameraDirector.cpp @@ -43,7 +43,9 @@ namespace SHADE if (!camComponent) { SHLOG_WARNING("Camera Director warning: Entity does not have a camera"); + return nullptr; } + return camComponent; } diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 78dabc37..489b05a1 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -246,7 +246,7 @@ namespace SHADE camera.orthoProjMatrix(2, 3) = -n / (f-n); camera.orthoProjMatrix(3, 3) = 1.0f; - camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); //camera.projMatrix.Transpose(); camera.dirtyProj = false; diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp index 19eb5168..1c603c57 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp +++ b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp @@ -146,7 +146,7 @@ namespace SHADE //Call all the children to Destroy themselves first before the parent is destroyed. if (entityVec[eIndex]) { - auto& children = SHSceneManager::GetCurrentSceneGraph().GetChildren(eID); + auto children = SHSceneManager::GetCurrentSceneGraph().GetChildren(eID); for (auto& child : children) { DestroyEntity(child->GetEntityID()); diff --git a/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp b/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp index f111eaeb..50930e4f 100644 --- a/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp +++ b/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp @@ -21,7 +21,7 @@ namespace SHADE template static bool SetPayload(DragDropTag const& type, T* object, ImGuiCond const cond = 0) { - ImGui::SetDragDropPayload(type.data(), static_cast(object), sizeof(T), cond); + hasDragDrop = ImGui::SetDragDropPayload(type.data(), static_cast(object), sizeof(T), cond); hasDragDrop = true; currentDragDropTag = type; diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 46ffd3bf..f8be2af9 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -252,7 +252,7 @@ namespace SHADE if(rbType == SHRigidBodyComponent::Type::DYNAMIC) //Dynamic only fields { SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetGravityEnabled(value);}, "Gravity"); - SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); + //SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); } if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { @@ -264,14 +264,19 @@ namespace SHADE SHEditorWidgets::BeginPanel(std::format("{} Constraints", ICON_FA_LOCK).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::TextLabel("Freeze Position"); + ImGui::PushID("FreezePos"); SHEditorWidgets::CheckBox("X", [component] {return component->GetFreezePositionX(); }, [component](bool const& value) {component->SetFreezePositionX(value); }, "Freeze Position - X"); ImGui::SameLine(); SHEditorWidgets::CheckBox("Y", [component] {return component->GetFreezePositionY(); }, [component](bool const& value) {component->SetFreezePositionY(value); }, "Freeze Position - Y"); ImGui::SameLine(); SHEditorWidgets::CheckBox("Z", [component] {return component->GetFreezePositionZ(); }, [component](bool const& value) {component->SetFreezePositionZ(value); }, "Freeze Position - Z"); + ImGui::PopID(); + SHEditorWidgets::TextLabel("Freeze Rotation"); + ImGui::PushID("FreezeRot"); SHEditorWidgets::CheckBox("X", [component] {return component->GetFreezeRotationX(); }, [component](bool const& value) {component->SetFreezeRotationX(value); }, "Freeze Rotation - X"); ImGui::SameLine(); SHEditorWidgets::CheckBox("Y", [component] {return component->GetFreezeRotationY(); }, [component](bool const& value) {component->SetFreezeRotationY(value); }, "Freeze Rotation - Y"); ImGui::SameLine(); SHEditorWidgets::CheckBox("Z", [component] {return component->GetFreezeRotationZ(); }, [component](bool const& value) {component->SetFreezeRotationZ(value); }, "Freeze Rotation - Z"); + ImGui::PopID(); SHEditorWidgets::EndPanel(); } @@ -279,6 +284,7 @@ namespace SHADE //Debug Info (Read-Only) if(ImGui::CollapsingHeader("Debug Information", ImGuiTreeNodeFlags_DefaultOpen))//Dynamic or Kinematic only fields { + SHEditorWidgets::DragFloat("Mass", [component] { return component->GetMass(); }, [](float value){}, "Mass", 0.1f, 0.0f, std::numeric_limits::infinity(), "%.3f", ImGuiSliderFlags_ReadOnly); SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component] {return component->GetPosition(); }, [](SHVec3 const& value) {}, false, "Position", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, [component] {return component->GetRotation(); }, [](SHVec3 const& value) {}, false, "Rotation", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields @@ -490,4 +496,52 @@ namespace SHADE } ImGui::PopID(); } + + template<> + static void DrawComponent(SHTextRenderableComponent* component) + { + if (!component) + return; + ImGui::PushID(SHFamilyID::GetID()); + const auto componentType = rttr::type::get(*component); + SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); + ImGui::SameLine(); + if (ImGui::CollapsingHeader(componentType.get_name().data())) + { + DrawContextMenu(component); + Handle const& font = component->GetFont(); + const auto FONT_NAME = SHResourceManager::GetAssetName(font).value_or(""); + SHEditorWidgets::DragDropReadOnlyField("Font", FONT_NAME, [component]() + { + Handle const& font = component->GetFont(); + return SHResourceManager::GetAssetID(font).value_or(0); + }, + [component](AssetID const& id) + { + if (SHAssetManager::GetType(id) != AssetType::FONT) + { + SHLOG_WARNING("Attempted to assign non font asset to TextRendererComponent Font property!") + return; + } + component->SetFont(SHResourceManager::LoadOrGet(id)); + SHResourceManager::FinaliseChanges(); + }, SHDragDrop::DRAG_RESOURCE); + + SHEditorWidgets::InputText("Text", + [component](void) + { + return component->GetText(); + }, + [component](std::string const& val) + { + component->SetText(val); + } + ); + } + else + { + DrawContextMenu(component); + } + ImGui::PopID(); + } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 655ad68a..c4287e6f 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -22,6 +22,7 @@ #include "UI/SHCanvasComponent.h" #include "SHEditorComponentView.h" #include "AudioSystem/SHAudioListenerComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" namespace SHADE { @@ -144,6 +145,10 @@ namespace SHADE { DrawComponent(uiComponent); } + if (auto textRendererComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(textRendererComponent); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -162,6 +167,7 @@ namespace SHADE DrawAddComponentWithEnforcedComponentButton(eid); DrawAddComponentWithEnforcedComponentButton(eid); DrawAddComponentWithEnforcedComponentButton(eid); + DrawAddComponentWithEnforcedComponentButton(eid); ImGui::EndMenu(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp index 88de7b73..9dbb9542 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp @@ -172,17 +172,24 @@ namespace SHADE // Shader bool shaderChanged = false; - const auto* SHADER_INFO = SHAssetManager::GetData(currentMatSpec->fragShader); - const std::string SHADER_NAME = SHADER_INFO ? SHADER_INFO->name : "Unknown Shader"; - ImGui::BeginDisabled(); + const auto* VERT_SHADER_INFO = SHAssetManager::GetData(currentMatSpec->vertexShader); + const std::string VERT_SHADER_NAME = VERT_SHADER_INFO ? VERT_SHADER_INFO->name : "Unknown Shader"; isDirty |= SHEditorWidgets::DragDropReadOnlyField ( - "Fragment Shader", SHADER_NAME.data(), + "Fragment Shader", VERT_SHADER_NAME.data(), + [this]() { return currentMatSpec->vertexShader; }, + [this](const AssetID& id) { currentMatSpec->vertexShader = id; }, + SHDragDrop::DRAG_RESOURCE + ); + const auto* FRAG_SHADER_INFO = SHAssetManager::GetData(currentMatSpec->fragShader); + const std::string FRAG_SHADER_NAME = FRAG_SHADER_INFO ? FRAG_SHADER_INFO->name : "Unknown Shader"; + isDirty |= SHEditorWidgets::DragDropReadOnlyField + ( + "Fragment Shader", FRAG_SHADER_NAME.data(), [this]() { return currentMatSpec->fragShader; }, [this](const AssetID& id) { currentMatSpec->fragShader = id; }, SHDragDrop::DRAG_RESOURCE ); - ImGui::EndDisabled(); // Load the shader to access it's data auto fragShader = SHResourceManager::LoadOrGet(currentMatSpec->fragShader); diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 7372f227..07caee7a 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -516,7 +516,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle& cmd) + renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle& cmd, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp index 40e08042..9fdcbde7 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.cpp +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -4,9 +4,9 @@ \par email: kahwei.tng\@digipen.edu \date Nov 7, 2021 \brief Contains the implementation of the EditorUI class. - + Copyright (C) 2021 DigiPen Institute of Technology. -Reproduction or disclosure of this file or its contents without the prior written consent +Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ // Precompiled Header @@ -57,10 +57,10 @@ namespace SHADE { const bool OPENED = ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen); if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered = ImGui::IsItemHovered(); return OPENED; } - + void SHEditorUI::SameLine() { ImGui::SameLine(); @@ -98,7 +98,7 @@ namespace SHADE void SHEditorUI::EndTooltip() { - ImGui::EndTooltip(); + ImGui::EndTooltip(); } /*-----------------------------------------------------------------------------------*/ @@ -146,7 +146,7 @@ namespace SHADE bool SHEditorUI::Selectable(const std::string& label) { - return ImGui::Selectable(label.data()); + return ImGui::Selectable(label.data()); } bool SHEditorUI::Selectable(const std::string& label, const char* icon) @@ -156,30 +156,41 @@ namespace SHADE bool SHEditorUI::InputCheckbox(const std::string& label, bool& value, bool* isHovered) { - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) - *isHovered = ImGui::IsItemHovered(); - ImGui::SameLine(); + *isHovered = ImGui::IsItemHovered(); return ImGui::Checkbox("##", &value); } bool SHEditorUI::InputInt(const std::string& label, int& value, bool* isHovered) { - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); return ImGui::DragInt("##", &value, 0.001f, - std::numeric_limits::min(), - std::numeric_limits::max(), - "%d", - ImGuiInputTextFlags_EnterReturnsTrue); + std::numeric_limits::min(), + std::numeric_limits::max(), + "%d", + ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value, bool* isHovered) { int signedVal = static_cast(value); - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); const bool CHANGED = InputInt("##", signedVal); if (CHANGED) @@ -191,15 +202,19 @@ namespace SHADE } bool SHEditorUI::InputFloat(const std::string& label, float& value, bool* isHovered) { - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); return ImGui::DragFloat("##", &value, 0.001f, - std::numeric_limits::lowest(), - std::numeric_limits::max(), - "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); + std::numeric_limits::lowest(), + std::numeric_limits::max(), + "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputDouble(const std::string& label, double& value, bool* isHovered) { @@ -213,48 +228,56 @@ namespace SHADE } bool SHEditorUI::InputSlider(const std::string& label, int min, int max, int& value, bool* isHovered /*= nullptr*/) { + if (!label.empty()) + { ImGui::Text(label.c_str()); - if (isHovered) - *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); - return ImGui::SliderInt("##", &value, - static_cast(min), static_cast(max), "%d", - ImGuiInputTextFlags_EnterReturnsTrue); + } + if (isHovered) + *isHovered = ImGui::IsItemHovered(); + ImGui::SameLine(); + return ImGui::SliderInt("##", &value, + static_cast(min), static_cast(max), "%d", + ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputSlider(const std::string& label, unsigned int min, unsigned int max, unsigned int& value, bool* isHovered /*= nullptr*/) { - int val = static_cast(value); - const bool CHANGED = InputSlider(label, min, max, val, isHovered); - if (CHANGED) - { - value = static_cast(val); - } + int val = static_cast(value); + const bool CHANGED = InputSlider(label, min, max, val, isHovered); + if (CHANGED) + { + value = static_cast(val); + } - return CHANGED; + return CHANGED; } bool SHEditorUI::InputSlider(const std::string& label, float min, float max, float& value, bool* isHovered) { + if (!label.empty()) + { ImGui::Text(label.c_str()); - if (isHovered) - *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); - return ImGui::SliderFloat("##", &value, - static_cast(min), static_cast(max), "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); + } + if (isHovered) + *isHovered = ImGui::IsItemHovered(); + ImGui::SameLine(); + return ImGui::SliderFloat("##", &value, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputSlider(const std::string& label, double min, double max, double& value, bool* isHovered /*= nullptr*/) { - float val = static_cast(value); - const bool CHANGED = InputSlider(label, min, max, val, isHovered); - if (CHANGED) - { - value = static_cast(val); - } + float val = static_cast(value); + const bool CHANGED = InputSlider(label, min, max, val, isHovered); + if (CHANGED) + { + value = static_cast(val); + } - return CHANGED; + return CHANGED; } bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value, bool* isHovered) @@ -264,7 +287,7 @@ namespace SHADE } bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, bool* isHovered) { - static const std::vector COMPONENT_LABELS = { "X", "Y", "Z"}; + static const std::vector COMPONENT_LABELS = { "X", "Y", "Z" }; return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, 0.1f, "%.3f", float{}, float{}, 0, isHovered); } @@ -272,9 +295,13 @@ namespace SHADE { std::array buffer = { '\0' }; strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str()); - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); const bool CHANGED = ImGui::InputText("##", &buffer[0], TEXT_FIELD_MAX_LENGTH); if (CHANGED) @@ -286,7 +313,11 @@ namespace SHADE bool SHEditorUI::InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered, bool alwaysNull) { - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); @@ -326,9 +357,13 @@ namespace SHADE const std::string& INITIAL_NAME = v >= static_cast(enumNames.size()) ? "Unknown" : enumNames[v]; bool b = false; - ImGui::Text(label.c_str()); + if (!label.empty()) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + } if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); if (ImGui::BeginCombo("##", INITIAL_NAME.c_str(), ImGuiComboFlags_None)) { diff --git a/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.cpp b/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.cpp index 36108628..8d9c01e6 100644 --- a/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.cpp @@ -25,12 +25,9 @@ namespace SHADE { if (cmdBufferHdl && (bufferUsageFlags & vk::BufferUsageFlagBits::eTransferDst)) { - vk::BufferCopy copyRegion - { - .srcOffset = 0, - .dstOffset = 0, - .size = sizeStored, - }; + vk::BufferCopy copyRegion{}; + PrepareBufferCopy(copyRegion); + cmdBufferHdl->GetVkCommandBuffer().copyBuffer(stagingBuffer, vkBuffer, 1, ©Region); } } @@ -54,6 +51,13 @@ namespace SHADE vmaFlushAllocation(vmaAllocator, alloc, srcOffset, dstOffset); } + void SHVkBuffer::PrepareBufferCopy(vk::BufferCopy& bufferCopy) noexcept + { + bufferCopy.srcOffset = 0; + bufferCopy.dstOffset = 0; + bufferCopy.size = sizeStored; + } + vk::Buffer SHVkBuffer::GetVkBuffer(void) const noexcept { return vkBuffer; diff --git a/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h b/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h index 1119342c..edcc968f 100644 --- a/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h +++ b/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h @@ -106,6 +106,7 @@ namespace SHADE void ResizeNoCopy (uint32_t newSize); void ResizeReplace (uint32_t newSize, void* data, uint32_t srcSize); void FlushAllocation (uint32_t srcOffset, uint32_t dstOffset) noexcept; + void PrepareBufferCopy (vk::BufferCopy& bufferCopy) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 272a838d..95cf2e91 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -459,7 +459,7 @@ namespace SHADE return SHVkInstance::GetResourceManager().Create(GetHandle(), &vmaAllocator, w, h, levels, format, usage, create); } - Handle SHVkLogicalDevice::CreateImage(SHImageCreateParams const& imageDetails, unsigned char* data, uint32_t dataSize, std::span inMipOffsets, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags) noexcept + Handle SHVkLogicalDevice::CreateImage(SHImageCreateParams const& imageDetails, unsigned char* data, uint32_t dataSize, std::vector const& inMipOffsets, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags) noexcept { return SHVkInstance::GetResourceManager().Create(GetHandle(), &vmaAllocator, imageDetails, data, dataSize, inMipOffsets, memUsage, allocFlags); } diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 158c20b2..ed09b482 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -162,7 +162,7 @@ namespace SHADE SHImageCreateParams const& imageDetails, unsigned char* data, uint32_t dataSize, - std::span inMipOffsets, + std::vector const& inMipOffsets, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags ) noexcept; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp index fa43cd53..53703924 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp @@ -123,7 +123,7 @@ namespace SHADE SHImageCreateParams const& imageDetails, const unsigned char* data, uint32_t dataSize, - std::span inMipOffsets, + std::vector const& inMipOffsets, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags ) noexcept @@ -311,6 +311,22 @@ namespace SHADE CreateFramebufferImage(); } + void SHVkImage::PrepareImageCopy(std::vector& bufferImageCopy) noexcept + { + for (uint32_t i = 0; i < mipOffsets.size(); ++i) + { + bufferImageCopy[i].bufferOffset = mipOffsets[i]; + bufferImageCopy[i].bufferRowLength = 0; // for padding + bufferImageCopy[i].bufferImageHeight = 0; // for padding + bufferImageCopy[i].imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; // TODO: Need to change this to base it off image format. + bufferImageCopy[i].imageSubresource.mipLevel = i; + bufferImageCopy[i].imageSubresource.baseArrayLayer = 0; // TODO: Array textures not supported yet + bufferImageCopy[i].imageSubresource.layerCount = layerCount; + bufferImageCopy[i].imageOffset = vk::Offset3D{ 0,0,0 }; + bufferImageCopy[i].imageExtent = vk::Extent3D{ width >> i, height >> i, 1 }; + } + } + void SHVkImage::LinkWithExteriorImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t layers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept { vkImage = inVkImage; @@ -405,4 +421,9 @@ namespace SHADE return height; } + uint32_t SHVkImage::GetMipLevels(void) const noexcept + { + return mipLevelCount; + } + } diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.h b/SHADE_Engine/src/Graphics/Images/SHVkImage.h index ba459def..98d8d0af 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.h @@ -102,7 +102,7 @@ namespace SHADE vk::Buffer stagingBuffer; //! Mipmap offsets for initializing the vk::BufferImageCopy during transfer to GPU resource - std::span mipOffsets; + std::vector mipOffsets; //! Handle to the device that creates these images Handle device; @@ -125,7 +125,7 @@ namespace SHADE SHImageCreateParams const& imageDetails, const unsigned char* data, uint32_t dataSize, - std::span inMipOffsets, + std::vector const& inMipOffsets, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags ) noexcept; @@ -142,6 +142,7 @@ namespace SHADE void TransferToDeviceResource (Handle cmdBufferHdl) noexcept; void PrepareImageTransitionInfo (vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::ImageMemoryBarrier& barrier) noexcept; void HandleResizeFramebufferImage(uint32_t newWidth, uint32_t newHeight) noexcept; + void PrepareImageCopy (std::vector& bufferImageCopy) noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ @@ -153,6 +154,7 @@ namespace SHADE vk::Format GetImageFormat (void) const noexcept; uint32_t GetWidth (void) const noexcept; uint32_t GetHeight (void) const noexcept; + uint32_t GetMipLevels (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 2a2b66d4..9b4b02b0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -27,6 +27,8 @@ of DigiPen Institute of Technology is prohibited. #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" #include "Graphics/Descriptors/SHVkDescriptorPool.h" +#include "Scene/SHSceneManager.h" +#include "UI/SHUIComponent.h" namespace SHADE { @@ -49,7 +51,7 @@ namespace SHADE , referencedMatInstances { std::move(rhs.referencedMatInstances) } , matBufferDirty { std::move(rhs.matBufferDirty) } , subBatches { std::move(rhs.subBatches) } - , drawData { std::move(drawData) } + , drawData { std::move(rhs.drawData) } , transformData { std::move(rhs.transformData) } , instancedIntegerData { std::move(rhs.instancedIntegerData) } , matPropsData { std::move(rhs.matPropsData) } @@ -80,7 +82,7 @@ namespace SHADE referencedMatInstances = std::move(rhs.referencedMatInstances); matBufferDirty = std::move(rhs.matBufferDirty) ; subBatches = std::move(rhs.subBatches) ; - drawData = std::move(drawData) ; + drawData = std::move(rhs.drawData) ; transformData = std::move(rhs.transformData) ; instancedIntegerData = std::move(rhs.instancedIntegerData) ; matPropsData = std::move(rhs.matPropsData) ; @@ -218,9 +220,13 @@ namespace SHADE for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) { drawDataBuffer[i].Free(); + drawDataBuffer[i] = {}; transformDataBuffer[i].Free(); + transformDataBuffer[i] = {}; instancedIntegerBuffer[i].Free(); + instancedIntegerBuffer[i] = {}; matPropsBuffer[i].Free(); + matPropsBuffer[i] = {}; } } @@ -302,7 +308,28 @@ namespace SHADE auto transform = SHComponentManager::GetComponent(rendId); if (transform) { - transformData.emplace_back(transform->GetTRS()); + if (SHSceneManager::CheckNodeAndComponentsActive(rendId)) + { + auto uiComp = SHComponentManager::GetComponent_s(rendId); + if (uiComp) + { + transformData.emplace_back(uiComp->GetMatrix()); + } + else + transformData.emplace_back(transform->GetTRS()); + } + else + { + // Should be deactivated + static const SHMatrix ZERO_MTX = + { + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f + }; + transformData.emplace_back(ZERO_MTX); + } } else { @@ -424,15 +451,30 @@ namespace SHADE for (auto rendId : subBatch.Renderables) { // Transform - auto transform = SHComponentManager::GetComponent_s(rendId); - if (!transform) + auto transform = SHComponentManager::GetComponent_s(rendId); + if (transform) { - SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!"); - transformData.emplace_back(); + if (SHSceneManager::CheckNodeAndComponentsActive(rendId)) + { + transformData.emplace_back(transform->GetTRS()); + } + else + { + // Should be deactivated + static const SHMatrix ZERO_MTX = + { + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f + }; + transformData.emplace_back(ZERO_MTX); + } } else { - transformData.emplace_back(transform->GetTRS()); + SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!"); + transformData.emplace_back(); } const SHRenderable* renderable = SHComponentManager::GetComponent(rendId); @@ -507,9 +549,13 @@ namespace SHADE return; } + // Nothing to draw + if (subBatches.empty()) + return; + // Bind all required objects before drawing static std::array dynamicOffset{ 0 }; - cmdBuffer->BeginLabeledSegment("SHBatch"); + cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); cmdBuffer->BindPipeline(pipeline); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index 6760d937..ec19691f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -55,13 +55,14 @@ namespace SHADE void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept { - const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); + Handle baseMat = (renderable->HasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial())->GetBaseMaterial(); + const Handle PIPELINE = baseMat->HasPipelineChanged() ? baseMat->GetPrevPipeline() : baseMat->GetPipeline(); // Check if we have a Batch with the same pipeline yet auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) - { - return batch.GetPipeline() == PIPELINE; - }); + { + return batch.GetPipeline() == PIPELINE; + }); // Attempt to remove if it exists if (batch == batches.end()) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp index 28333820..d0fbaf2c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp @@ -97,6 +97,8 @@ namespace SHADE Handle materialDataPerInstanceLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, { materialDataBinding }); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, materialDataPerInstanceLayout->GetVkHandle(), "[Descriptor Set Layout] Material Globals"); + + globalDescSetLayouts.push_back(staticGlobalLayout); globalDescSetLayouts.push_back(dynamicGlobalLayout); globalDescSetLayouts.push_back(cameraDataGlobalLayout); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index 60262607..0bfa89a2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -90,7 +90,7 @@ namespace SHADE auto const& RENDERERS = GFX_SYSTEM->GetDefaultViewport()->GetRenderers(); auto renderGraph = RENDERERS[SHGraphicsConstants::RenderGraphIndices::WORLD]->GetRenderGraph(); auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); - subPass->AddExteriorDrawCalls([this, GFX_SYSTEM](Handle& cmdBuffer) + subPass->AddExteriorDrawCalls([this, GFX_SYSTEM](Handle& cmdBuffer, uint32_t frameIndex) { // Get Current frame index const uint32_t FRAME_IDX = GFX_SYSTEM->GetCurrentFrameIndex(); @@ -106,7 +106,7 @@ namespace SHADE } }); auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); - subPassWithDepth->AddExteriorDrawCalls([this, GFX_SYSTEM](Handle& cmdBuffer) + subPassWithDepth->AddExteriorDrawCalls([this, GFX_SYSTEM](Handle& cmdBuffer, uint32_t frameIndex) { // Get Current frame index const uint32_t FRAME_IDX = GFX_SYSTEM->GetCurrentFrameIndex(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index 0a67cd9f..e6051841 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -66,7 +66,9 @@ namespace SHADE /***************************************************************************/ /*! \brief - DescriptorSet Index for render graph resources. + DescriptorSet Index for render graph resources. Unlike the sets from + 1 to 3 and 6, this set index does not have hard coded bindings and is + NOT part of the layouts included in the global data. */ /***************************************************************************/ static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; @@ -75,13 +77,21 @@ namespace SHADE \brief DescriptorSet Index for render graph node compute resources. For data that we wish to pass to compute shaders in the render graph, this is - the set to use. Unlike the sets from 1 to 3, this set index does not have + the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have hard coded bindings and is NOT part of the layouts included in the global data. */ /***************************************************************************/ static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5; + /***************************************************************************/ + /*! + \brief + To store font data. + + */ + /***************************************************************************/ + static constexpr uint32_t FONT_DATA = 4; }; struct DescriptorSetBindings @@ -107,7 +117,7 @@ namespace SHADE /***************************************************************************/ /*! \brief - DescriptorSet binding for combined image sampler data. + DescriptorSet binding for light data. */ /***************************************************************************/ @@ -116,7 +126,7 @@ namespace SHADE /***************************************************************************/ /*! \brief - DescriptorSet binding for lights. + DescriptorSet binding for camera data. */ /***************************************************************************/ @@ -130,6 +140,24 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t BATCHED_PER_INST_DATA = 0; + /***************************************************************************/ + /*! + \brief + Descriptor set binding for font bitmaps. + + */ + /***************************************************************************/ + static constexpr uint32_t FONT_BITMAP_DATA = 0; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for font matrix data. + + */ + /***************************************************************************/ + static constexpr uint32_t FONT_MATRIX_DATA = 1; + }; struct VertexBufferBindings @@ -177,6 +205,10 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t INTEGER_DATA = 5; + static constexpr uint32_t CALCULATED_GLYPH_POSITION = 0; + static constexpr uint32_t GLYPH_INDEX = 1; + + }; /*******************************************************************************/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index ff265c49..af09c819 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -42,6 +42,8 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/SHVkUtil.h" #include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" #include "../Meshes/SHPrimitiveGenerator.h" +#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" namespace SHADE { @@ -82,7 +84,7 @@ namespace SHADE if (width == 0 || height == 0) return; - PrepareResize(resizeWidth, resizeHeight); + PrepareResize(width, height); }); window->RegisterWindowCloseCallback([&](void) @@ -115,14 +117,29 @@ namespace SHADE // Create generic command buffer graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); + SHFreetypeInstance::Init(); + + //SHAssetManager::CompileAsset("../../Assets/Shaders/Text_VS.glsl", false); + //SHAssetManager::CompileAsset("../../Assets/Shaders/Text_FS.glsl", false); + //SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false); + //SHAssetManager::CompileAsset("../../Assets/Shaders/UI_VS.glsl", false); + //SHAssetManager::CompileAsset("../../Assets/Shaders/UI_FS.glsl", false); + //SHAssetManager::CompileAsset("../../Assets/Models/Quad.gltf", false); + //SHAssetManager::CompileAsset("../../Assets/Shaders/ToSwapchain_VS.glsl", false); + //SHAssetManager::CompileAsset("../../Assets/Shaders/ToSwapchain_FS.glsl", false); + // Load Built In Shaders - static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); - static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet(FS_DEFAULT); - static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet(VS_DEBUG); - static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet(FS_DEBUG); - static constexpr AssetID CS_COMPOSITE = 45072428; deferredCompositeShader = SHResourceManager::LoadOrGet(CS_COMPOSITE); - static constexpr AssetID SSAO = 38430899; ssaoShader = SHResourceManager::LoadOrGet(SSAO); - static constexpr AssetID SSAO_BLUR = 39760835; ssaoBlurShader = SHResourceManager::LoadOrGet(SSAO_BLUR); + static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); + static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet(FS_DEFAULT); + static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet(VS_DEBUG); + static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet(FS_DEBUG); + static constexpr AssetID CS_COMPOSITE = 45072428; deferredCompositeShader = SHResourceManager::LoadOrGet(CS_COMPOSITE); + static constexpr AssetID SSAO = 38430899; ssaoShader = SHResourceManager::LoadOrGet(SSAO); + static constexpr AssetID SSAO_BLUR = 39760835; ssaoBlurShader = SHResourceManager::LoadOrGet(SSAO_BLUR); + static constexpr AssetID TEXT_VS = 39816727; textVS = SHResourceManager::LoadOrGet(TEXT_VS); + static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet(TEXT_FS); + static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet(RENDER_SC_VS); + static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet(RENDER_SC_FS); } void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept @@ -149,6 +166,8 @@ namespace SHADE worldCamera->SetLookAt(SHVec3(0.0f, 0.0f, 0.0f), SHVec3(0.0f, 0.0f, -2.0f), SHVec3(0.0f, 1.0f, 0.0f)); worldCamera->SetPerspective(90.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); + worldCameraDirector = cameraSystem->CreateDirector(); + // Create Default Viewport worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); @@ -162,20 +181,21 @@ namespace SHADE } /*-----------------------------------------------------------------------*/ - /* SCENE RENDER GRAPH RESOURCES */ + /* WORLD RENDER GRAPH RESOURCES */ /*-----------------------------------------------------------------------*/ // Initialize world render graph - worldRenderGraph->Init("World Render Graph", device, swapchain); - worldRenderGraph->AddResource("Position", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - worldRenderGraph->AddResource("Normals", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + worldRenderGraph->Init("World Render Graph", device, swapchain, &resourceManager); + worldRenderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + worldRenderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); //worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - worldRenderGraph->AddResource("Albedo", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); - worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - worldRenderGraph->AddResource("SSAO", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - worldRenderGraph->AddResource("SSAO Blur", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + worldRenderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second); + worldRenderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); + worldRenderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + worldRenderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + worldRenderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second); + worldRenderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + worldRenderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + /*-----------------------------------------------------------------------*/ /* MAIN NODE */ @@ -205,7 +225,7 @@ namespace SHADE gBufferSubpass->AddColorOutput("Normals"); //gBufferSubpass->AddColorOutput("Tangents"); gBufferSubpass->AddColorOutput("Albedo"); - gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); + gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); /*-----------------------------------------------------------------------*/ /* SSAO PASS AND DATA INIT */ @@ -250,25 +270,66 @@ namespace SHADE /*-----------------------------------------------------------------------*/ gBufferNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene"}); - // Dummy Node - auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Debug Draw" }); // no predecessors - auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass"); - dummySubpass->AddInput("Scene"); + { + //// Dummy Node to transition scene render graph resource + //auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Debug Draw" }); // no predecessors + //auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass"); + //dummySubpass->AddInput("Scene"); + } /*-----------------------------------------------------------------------*/ - /* GENERATE RENDER GRAPH */ + /* GENERATE WORLD RENDER GRAPH */ /*-----------------------------------------------------------------------*/ // Generate world render graph worldRenderGraph->Generate(); + + /*-----------------------------------------------------------------------*/ + /* SCREEN RENDER GRAPH */ + /*-----------------------------------------------------------------------*/ + // Initialize screen render graph + screenRenderGraph = resourceManager.Create(); + screenRenderGraph->Init("Screen Render Graph", device, swapchain, &resourceManager); + screenRenderGraph->LinkNonOwningResource(worldRenderGraph, "Scene"); + screenRenderGraph->LinkNonOwningResource(worldRenderGraph, "Entity ID"); + screenRenderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + + auto screenSpaceNode = screenRenderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID"}, {}); + auto uiSubpass = screenSpaceNode->AddSubpass("UI"); + uiSubpass->AddColorOutput("Scene"); + uiSubpass->AddColorOutput("Entity ID"); + uiSubpass->AddExteriorDrawCalls([=](Handle& cmdBuffer, uint32_t frameIndex) + { + textRenderingSubSystem->Render(cmdBuffer, frameIndex); + }); + +#ifdef SHEDITOR + { + // Dummy Node to transition scene render graph resource + auto dummyNode = screenRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" }); // no predecessors + auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass"); + dummySubpass->AddInput("Scene"); + } + +#else + screenRenderGraph->AddRenderToSwapchainNode("Scene", "Present", {"Screen Space Pass"}, {renderToSwapchainVS, renderToSwapchainFS}); +#endif + + screenRenderGraph->Generate(); + /*-----------------------------------------------------------------------*/ /* BIND RENDER GRAPH TO RENDERER */ /*-----------------------------------------------------------------------*/ // Add world renderer to default viewport worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer->SetCamera(worldCamera); + worldRenderer->SetCameraDirector(worldCameraDirector); + + // Add screen renderer to default viewport + screenRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], screenRenderGraph); + screenRenderer->SetCamera(screenCamera); + screenRenderer->SetCameraDirector(worldCameraDirector); - worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); // Create debug draw pipeline debugDrawPipeline = createDebugDrawPipeline(debugDrawNode->GetRenderpass(), debugDrawSubpass); @@ -315,6 +376,16 @@ namespace SHADE lightingSubSystem = resourceManager.Create(); lightingSubSystem->Init(device, descPool); + + textRenderingSubSystem = resourceManager.Create(); + + // initialize the text renderer + auto uiNode = screenRenderGraph->GetNode("Screen Space Pass"); + textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS, [=](Handle cmdBuffer, uint32_t frameIndex) + { + screenRenderer->BindDescSet(cmdBuffer, frameIndex); + }); + } void SHGraphicsSystem::InitBuiltInResources(void) @@ -355,8 +426,8 @@ namespace SHADE for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) renderContextCmdPools[i] = renderContext.GetFrameData(i).cmdPoolHdls[0]; - editorRenderGraph->Init("Editor Render Graph", device, swapchain); - editorRenderGraph->AddResource("Present", { SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + editorRenderGraph->Init("Editor Render Graph", device, swapchain, &resourceManager); + editorRenderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); auto imguiNode = editorRenderGraph->AddNode("ImGui Node", { "Present"}, {}); @@ -385,6 +456,7 @@ namespace SHADE void SHGraphicsSystem::Exit(void) { + SHFreetypeInstance::Exit(); } #pragma endregion INIT_EXIT @@ -454,6 +526,8 @@ namespace SHADE #endif } + textRenderingSubSystem->Run(frameIndex); + // For every viewport for (int vpIndex = 0; vpIndex < static_cast(viewports.size()); ++vpIndex) { @@ -513,7 +587,7 @@ namespace SHADE { auto editorSystem = SHSystemManager::GetSystem(); if (editorSystem->editorState != SHEditor::State::PLAY) - worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, cameraSystem->GetEditorCamera()->GetViewMatrix(), cameraSystem->GetEditorCamera()->GetProjMatrix()); + worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, cameraSystem->GetEditorCamera()->GetViewMatrix(), cameraSystem->GetEditorCamera()->GetProjMatrix(), cameraSystem->GetEditorCamera()->GetOrthoMatrix()); else renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); } @@ -761,7 +835,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Handle SHGraphicsSystem::AddTexture(const SHTextureAsset& texAsset) { - const int MIPS = texAsset.mipOffsets.size(); + const int MIPS = static_cast (texAsset.mipOffsets.size()); auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast(MIPS) }); SET_VK_OBJ_NAME(device, vk::ObjectType::eSampler, sampler->GetVkSampler(), "[Sampler] Mips " + std::to_string(MIPS)); return texLibrary.Add(texAsset, sampler); @@ -769,7 +843,7 @@ namespace SHADE SHADE::Handle SHGraphicsSystem::AddTexture(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets) { - const int MIPS = mipOffsets.size(); + const int MIPS = static_cast (mipOffsets.size()); auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast(MIPS) }); SET_VK_OBJ_NAME(device, vk::ObjectType::eSampler, sampler->GetVkSampler(), "[Sampler] Mips " + std::to_string(MIPS)); return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler); @@ -798,6 +872,19 @@ namespace SHADE return texLibrary.GetTextureHandle(textureId); } + /*---------------------------------------------------------------------------------*/ + /* Font Registration Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHGraphicsSystem::AddFont(SHFontAsset const& fontAsset) noexcept + { + return fontLibrary.AddFont(device, resourceManager, fontAsset); + } + + void SHGraphicsSystem::BuildFonts(void) noexcept + { + fontLibrary.BuildFonts(device, graphicsQueue, graphicsCmdPool, descPool, textRenderingSubSystem->GetFontDataDescSetLayout(), resourceManager); + } + #pragma endregion ADD_REMOVE #pragma region ROUTINES @@ -890,7 +977,9 @@ namespace SHADE Handle prevMaterial = renderable.HasMaterialChanged() ? renderable.GetPrevMaterial() : renderable.GetMaterial(); if (prevMaterial) { - Handle oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); + Handle baseMat = prevMaterial->GetBaseMaterial(); + Handle prevPipeline = baseMat->HasPipelineChanged() ? baseMat->GetPrevPipeline() : baseMat->GetPipeline(); + Handle oldSuperBatch = prevPipeline->GetPipelineState().GetSubpass()->GetSuperBatch(); oldSuperBatch->Remove(&renderable); } @@ -905,11 +994,20 @@ namespace SHADE // Unset change flag renderable.ResetChangedFlag(); } + + // Unset all material old pipeline since we would have finished processing + auto gfxSystem = reinterpret_cast(system); + auto [matBegin, matEnd] = gfxSystem->resourceManager.GetDenseAccess(); + for (auto iter = matBegin; iter != matEnd; ++iter) + { + iter->ForgetOldPipeline(); + } } #pragma endregion ROUTINES #pragma region MISC + void SHGraphicsSystem::PrepareResize(uint32_t newWidth, uint32_t newHeight) noexcept { resizeWidth = newWidth; @@ -936,7 +1034,12 @@ namespace SHADE renderContext.HandleResize(); worldRenderGraph->HandleResize(resizeWidth, resizeHeight); + +#ifdef SHEDITOR editorRenderGraph->HandleResize(windowDims.first, windowDims.second); +#endif + + screenRenderGraph->HandleResize(resizeWidth, resizeHeight); mousePickSystem->HandleResize(); postOffscreenRender->HandleResize(); @@ -944,7 +1047,8 @@ namespace SHADE worldViewport->SetWidth(static_cast(resizeWidth)); worldViewport->SetHeight(static_cast(resizeHeight)); - worldCamera->SetPerspective(90.0f, static_cast(resizeWidth), static_cast(resizeHeight), 0.0f, 100.0f); + //worldCamera->SetPerspective(90.0f, static_cast(resizeWidth), static_cast(resizeHeight), 0.0f, 100.0f); + //screenCamera->SetOrthographic(static_cast(resizeWidth), static_cast(resizeHeight), 0.01f, 100.0f); auto cameraSystem = SHSystemManager::GetSystem(); #ifdef SHEDITOR @@ -956,8 +1060,6 @@ namespace SHADE for (auto& semaHandle : graphSemaphores) semaHandle = device->CreateSemaphore(); - - } void SHGraphicsSystem::AwaitGraphicsExecution() @@ -976,6 +1078,11 @@ namespace SHADE return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); } + SHADE::SHFontLibrary const& SHGraphicsSystem::GetFontLibrary(void) const noexcept + { + return fontLibrary; + } + Handle SHGraphicsSystem::createDebugDrawPipeline(Handle renderPass, Handle subpass) { auto pipelineLayout = resourceManager.Create diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 2a186041..8c65f233 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -32,6 +32,8 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h" #include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h" #include "Graphics/MiddleEnd/PostProcessing/SHSSAO.h" +#include "Camera/SHCameraDirector.h" +#include "Graphics/MiddleEnd/TextRendering/SHFontLibrary.h" namespace SHADE { @@ -54,6 +56,7 @@ namespace SHADE class SHMaterial; class SHMaterialInstance; class SHMousePickSystem; + class SHTextRenderingSubSystem; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -326,6 +329,22 @@ namespace SHADE */ /***************************************************************************/ Handle GetDefaultTexture() const noexcept { return defaultTexture; } + /***************************************************************************/ + /*! + + \brief + Adds a font into the font library. + + \param fontAsset + Font asset to add. + + \return + Handle to the new font. + + */ + /***************************************************************************/ + Handle AddFont (SHFontAsset const& fontAsset) noexcept; + void BuildFonts (void) noexcept; void PrepareResize(uint32_t newWidth, uint32_t newHeight) noexcept; void HandleResize(void) noexcept; @@ -355,6 +374,7 @@ namespace SHADE Handle GetDebugDrawPipeline(void) const noexcept { return debugDrawPipeline; } Handle GetDebugDrawDepthPipeline(void) const noexcept { return debugDrawDepthPipeline; } uint32_t GetCurrentFrameIndex(void) const noexcept { return renderContext.GetCurrentFrame(); } + SHFontLibrary const& GetFontLibrary (void) const noexcept; /*-----------------------------------------------------------------------------*/ /* Getters */ @@ -391,6 +411,7 @@ namespace SHADE SHResourceHub resourceManager; SHMeshLibrary meshLibrary; SHTextureLibrary texLibrary; + SHFontLibrary fontLibrary; SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; @@ -398,18 +419,20 @@ namespace SHADE #ifdef SHEDITOR Handle editorViewport; Handle editorRenderer; - Handle editorRenderGraph; #endif Handle worldViewport; // Whole screen - std::vector> viewports; // Additional viewports + std::vector> viewports; // Additional viewports - // Temp renderers + // Renderers Handle worldRenderer; + Handle screenRenderer; // Temp Cameras Handle worldCamera; Handle screenCamera; + DirectorHandle worldCameraDirector; + // Built-In Shaders Handle defaultVertShader; @@ -419,7 +442,13 @@ namespace SHADE Handle deferredCompositeShader; Handle ssaoShader; Handle ssaoBlurShader; + Handle textVS; + Handle textFS; + Handle renderToSwapchainVS; + Handle renderToSwapchainFS; + // Fonts + Handle testFont; // Built-In Materials Handle defaultMaterial; @@ -434,11 +463,16 @@ namespace SHADE // Render Graphs Handle worldRenderGraph; + Handle screenRenderGraph; +#ifdef SHEDITOR + Handle editorRenderGraph; +#endif // Sub systems Handle mousePickSystem; Handle postOffscreenRender; Handle lightingSubSystem; + Handle textRenderingSubSystem; Handle ssaoStorage; uint32_t resizeWidth = 1; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp index 7ca7c394..1a007b95 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp @@ -21,6 +21,8 @@ namespace SHADE if (_pipeline == pipeline) return; + // Mark old pipeline and set new pipeline + oldPipeline = pipeline; pipeline = _pipeline; // Set up properties based on the pipeline @@ -41,9 +43,6 @@ namespace SHADE // Reset since pipeline changed ResetProperties(); - - // Mark changed so that we know to update dependent material instances - propertiesChanged = true; } Handle SHMaterial::GetPipeline() const @@ -111,4 +110,9 @@ namespace SHADE { propertiesChanged = false; } + + void SHMaterial::ForgetOldPipeline() noexcept + { + oldPipeline = {}; + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h index c75692f2..7913d912 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h @@ -44,6 +44,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ void SetPipeline(Handle _pipeline); Handle GetPipeline() const; + Handle GetPrevPipeline() const { return oldPipeline; }; /*-----------------------------------------------------------------------------*/ /* Property Functions */ @@ -68,10 +69,11 @@ namespace SHADE /* Query Functions */ /*-----------------------------------------------------------------------------*/ Handle GetShaderBlockInterface() const noexcept; - bool HasPipelineChanged() const noexcept { return pipelineChanged; } + bool HasPipelineChanged() const noexcept { return oldPipeline; } bool HasPropertiesChanged() const noexcept { return propertiesChanged; } - bool HasChanged() const noexcept { return pipelineChanged || propertiesChanged; } + bool HasChanged() const noexcept { return oldPipeline || propertiesChanged; } void ClearChangeFlag() noexcept; + void ForgetOldPipeline() noexcept; private: /*-----------------------------------------------------------------------------*/ @@ -81,7 +83,7 @@ namespace SHADE std::unique_ptr propMemory; Byte propMemorySize = 0; bool propertiesChanged = true; - bool pipelineChanged = true; + Handle oldPipeline; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index 63d374eb..e47055df 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -90,17 +90,22 @@ namespace SHADE if (camera && cameraDirector) { //UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix())); - UpdateDataAndBind(cmdBuffer, frameIndex, cameraDirector->GetViewMatrix(), cameraDirector->GetProjMatrix()); + UpdateDataAndBind(cmdBuffer, frameIndex, cameraDirector->GetViewMatrix(), cameraDirector->GetProjMatrix(), cameraDirector->GetOrthoMatrix()); } } - void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept + void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix, SHMatrix const& orthoMatrix) noexcept { - SetViewProjectionMatrix(viewMatrix, projMatrix); + SetViewProjectionMatrix(viewMatrix, projMatrix, orthoMatrix); //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex); + BindDescSet(cmdBuffer, frameIndex); + } + + void SHRenderer::BindDescSet(Handle cmdBuffer, uint32_t frameIndex) noexcept + { std::array dynamicOffsets{ frameIndex * cameraDataAlignedSize }; cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 }); @@ -111,12 +116,13 @@ namespace SHADE { } - void SHRenderer::SetViewProjectionMatrix(SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept + void SHRenderer::SetViewProjectionMatrix(SHMatrix const& viewMatrix, SHMatrix const& projMatrix, SHMatrix const& orthoMatrix) noexcept { //cpuCameraData.viewProjectionMatrix = camera->GetViewMatrix() * camera->GetProjectionMatrix(); cpuCameraData.viewProjectionMatrix = SHMatrix::Transpose(projMatrix * viewMatrix); cpuCameraData.viewMatrix = SHMatrix::Transpose(viewMatrix); cpuCameraData.projectionMatrix = SHMatrix::Transpose(projMatrix); + cpuCameraData.orthoMatrix = SHMatrix::Transpose (orthoMatrix); } Handle SHRenderer::GetRenderGraph(void) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index 140cf53b..83291700 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -48,6 +48,7 @@ namespace SHADE SHMatrix viewProjectionMatrix; SHMatrix viewMatrix; SHMatrix projectionMatrix; + SHMatrix orthoMatrix; }; /*---------------------------------------------------------------------------------*/ @@ -63,6 +64,7 @@ namespace SHADE /***********************************************************************************/ class SHRenderer { + public: /*-----------------------------------------------------------------------------*/ /* Constructor/Destructors */ @@ -81,9 +83,10 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ void Draw(uint32_t frameIndex, Handle descPool) noexcept; void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept; - void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept; + void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix, SHMatrix const& orthoMatrix) noexcept; + void BindDescSet (Handle cmdBuffer, uint32_t frameIndex) noexcept; void UpdateCameraDataToBuffer (void) noexcept; - void SetViewProjectionMatrix (SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept; + void SetViewProjectionMatrix (SHMatrix const& viewMatrix, SHMatrix const& projMatrix, SHMatrix const& orthoMatrix) noexcept; /*-----------------------------------------------------------------------------*/ /* Setters and Getters */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 2949ad43..3d5a5773 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -423,9 +423,8 @@ namespace SHADE /*! \brief - Loops through every single light component and checks for dirty light - data. If light data is dirty, rewrite to the CPU container. We also want - to bind the descriptor set for the light data. + Loops through every single light component and writes light data to CPU + then GPU. */ /***************************************************************************/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp index 2bf32fd8..db5b08c3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PostProcessing/SHSSAO.cpp @@ -76,7 +76,7 @@ namespace SHADE }; uint32_t mipOffset = 0; - rotationVectorsImage = logicalDevice->CreateImage(imageDetails, reinterpret_cast( rotationVectors.data()), static_cast(sizeof(rotationVectors)), {&mipOffset, 1}, VMA_MEMORY_USAGE_AUTO, {}); + rotationVectorsImage = logicalDevice->CreateImage(imageDetails, reinterpret_cast(rotationVectors.data()), static_cast(sizeof(rotationVectors)), { mipOffset }, VMA_MEMORY_USAGE_AUTO, {}); vk::ImageMemoryBarrier transferBarrier{}; rotationVectorsImage->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, transferBarrier); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFont.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFont.cpp new file mode 100644 index 00000000..3dd54ca5 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFont.cpp @@ -0,0 +1,160 @@ +#include "SHpch.h" +#include "SHFont.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Buffers/SHVkBuffer.h" +#include "Graphics/Images/SHVkSampler.h" + +namespace SHADE +{ + /***************************************************************************/ + /*! + + \brief + Non-default ctor. Prepares objects in staging buffers with data from + SHFontAsset. + + \param inLogicalDeviceHdl + Logical device required for vulkan object creation. + + \param asset + Font asset to copy data from. + + */ + /***************************************************************************/ + SHFont::SHFont(Handle inLogicalDeviceHdl, SHFontAsset const& asset) noexcept + { + /*-----------------------------------------------------------------------*/ + /* PREPARE GPU DATA */ + /*-----------------------------------------------------------------------*/ + + // assign device for convenient usage + logicalDevice = inLogicalDeviceHdl; + + // Copy the font data + fontAsset = asset; + + SHImageCreateParams imageParams + { + .imageType = vk::ImageType::e2D, + .width = fontAsset.bitmapWidth, + .height = fontAsset.bitmapHeight, + .depth = 1, + .levels = 1, + .arrayLayers = 1, + .imageFormat = vk::Format::eR8G8B8A8Unorm, + //.imageFormat = vk::Format::eR32Sfloat, + //.imageFormat = vk::Format::eR32G32B32Sfloat, + .usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, + .createFlags = {} + }; + + uint32_t bytesRequired = asset.bitmapData.size(); + uint32_t mipOffset = 0; + + // Create the image + bitmapDataImage = logicalDevice->CreateImage(imageParams, fontAsset.bitmapData.data(), bytesRequired, { mipOffset }, VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, {}); + + // Amount of data required to hold matrices for all glyphs + uint32_t glyphDataSize = fontAsset.glyphTransformations.size() * sizeof (SHMatrix); + + // For indexing + for (uint32_t i = 0; i < fontAsset.glyphs.size(); ++i) + unicodeIndexing.emplace(fontAsset.glyphs[i], i); + + // allocate GPU buffer for matrices + matrixDataBuffer = logicalDevice->CreateBuffer(glyphDataSize, fontAsset.glyphTransformations.data(), glyphDataSize, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, {}); + + sampler = logicalDevice->CreateSampler(SHVkSamplerParams{}); + + } + + /***************************************************************************/ + /*! + + \brief + Transfers data from staging buffers to GPU. Does not issue any of the + barriers (we want this done outside). + + \param commandBuffer + Command buffer used to + + \return + + */ + /***************************************************************************/ + void SHFont::TransferToGPU(Handle commandBuffer) noexcept + { + /*-----------------------------------------------------------------------*/ + /* COMMANDS TO TRANSFER TO DEVICE MEMORY */ + /*-----------------------------------------------------------------------*/ + // Transfer to device memory + bitmapDataImage->TransferToDeviceResource(commandBuffer); + + // Transfer to GPU buffer + matrixDataBuffer->TransferToDeviceResource(commandBuffer); + } + + void SHFont::DoPostTransfer(Handle descPool, Handle layout) noexcept + { + /*-----------------------------------------------------------------------*/ + /* CREATE IMAGE VIEW */ + /*-----------------------------------------------------------------------*/ + // Create the image view to the device resource + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = bitmapDataImage->GetImageFormat(), + .imageAspectFlags = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .mipLevelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + bitmapDataImageView = bitmapDataImage->CreateImageView(logicalDevice, bitmapDataImage, viewDetails); + + /*-----------------------------------------------------------------------*/ + /* DESCRIPTORS */ + /*-----------------------------------------------------------------------*/ + // allocate desc set for the bitmap and matrix data + descSet = descPool->Allocate({ layout }, { 1 }); + + auto viewLayoutSampler = std::make_tuple(bitmapDataImageView, sampler, vk::ImageLayout::eShaderReadOnlyOptimal); + descSet->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::FONT_DATA, SHGraphicsConstants::DescriptorSetBindings::FONT_BITMAP_DATA, {&viewLayoutSampler, 1}); + + descSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::FONT_DATA, + SHGraphicsConstants::DescriptorSetBindings::FONT_MATRIX_DATA, { &matrixDataBuffer, 1 }, 0, fontAsset.glyphTransformations.size() * sizeof(SHMatrix)); + + // Bind image and buffer to desc set. + descSet->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::FONT_DATA, SHGraphicsConstants::DescriptorSetBindings::FONT_BITMAP_DATA); + descSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::FONT_DATA, SHGraphicsConstants::DescriptorSetBindings::FONT_MATRIX_DATA); + + } + + std::unordered_map SHFont::GetUnicodeIndexing(void) const noexcept + { + return unicodeIndexing; + } + + SHFontAsset const& SHFont::GetFontAsset(void) const noexcept + { + return fontAsset; + } + + Handle SHFont::GetImage(void) const noexcept + { + return bitmapDataImage; + } + + Handle SHFont::GetMatrixBuffer(void) const noexcept + { + return matrixDataBuffer; + } + + Handle SHFont::GetDescriptorSet(void) const noexcept + { + return descSet; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFont.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFont.h new file mode 100644 index 00000000..1439281a --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFont.h @@ -0,0 +1,72 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include "msdf-atlas-gen/msdf-atlas-gen.h" +#include "Assets/Asset Types/SHFontAsset.h" + +namespace SHADE +{ + class SHVkLogicalDevice; + class SHVkDescriptorPool; + class SHVkDescriptorSetGroup; + class SHVkDescriptorSetLayout; + class SHVkCommandBuffer; + class SHVkCommandPool; + class SHVkImage; + class SHVkImageView; + class SHVkBuffer; + class SHVkQueue; + class SHVkSampler; + + class SHFont + { + private: + //! Device for creation and destruction + Handle logicalDevice; + + //! Font asset contains exactly what we need, so we'll use it + SHFontAsset fontAsset; + + //! Device memory that stores bitmap data + Handle bitmapDataImage; + + //! View to device memory + Handle bitmapDataImageView; + + //! Device memory that stores matrix data + Handle matrixDataBuffer; + + //! Descriptor set required to store the bitmap AND matrix data for the UV and quad transformation + Handle descSet; + + Handle sampler; + + //! Used for getting the correct indices into the matrix data buffer + std::unordered_map unicodeIndexing; + + ////! To transition images for transfer ops + //vk::ImageMemoryBarrier preTransferBarrier; + + ////! To transition images for shader reads + //vk::ImageMemoryBarrier postTransferBarrier; + + public: + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + SHFont (Handle inLogicalDeviceHdl, SHFontAsset const& asset) noexcept; + void TransferToGPU (Handle commandBuffer) noexcept; + void DoPostTransfer (Handle descPool, Handle layout) noexcept; + + + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + std::unordered_map GetUnicodeIndexing (void) const noexcept; + SHFontAsset const& GetFontAsset (void) const noexcept; + Handle GetImage (void) const noexcept; + Handle GetMatrixBuffer (void) const noexcept; + Handle GetDescriptorSet (void) const noexcept; + + }; +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontAtlasData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontAtlasData.cpp new file mode 100644 index 00000000..6ea1bceb --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontAtlasData.cpp @@ -0,0 +1,7 @@ +#include "SHpch.h" +#include "SHFontAtlasData.h" + +namespace SHADE +{ + +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontAtlasData.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontAtlasData.h new file mode 100644 index 00000000..1e6e7470 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontAtlasData.h @@ -0,0 +1,7 @@ +#pragma once + + +namespace SHADE +{ + +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontLibrary.cpp new file mode 100644 index 00000000..3ae5c2ec --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontLibrary.cpp @@ -0,0 +1,108 @@ +#include "SHpch.h" +#include "SHFontLibrary.h" +#include "Graphics/Images/SHVkImage.h" +#include "Graphics/Commands/SHVkCommandPool.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Synchronization/SHVkFence.h" +#include "Graphics/Buffers/SHVkBuffer.h" + +namespace SHADE +{ + /***************************************************************************/ + /*! + + \brief + For adding fonts to the library + + \param asset + The asset we want to create an SHFont from. + + */ + /***************************************************************************/ + Handle SHFontLibrary::AddFont(Handle logicalDevice, SHResourceHub& resourceHub, SHFontAsset const& asset) noexcept + { + // Create new font + Handle newFont = resourceHub.Create(logicalDevice, asset); + + // emplace new barriers and prepare them for transfer ops + preTransferBarriers.emplace_back(); + postTransferBarriers.emplace_back(); + newFont->GetImage()->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, preTransferBarriers[preTransferBarriers.size() - 1]); + newFont->GetImage()->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, postTransferBarriers[postTransferBarriers.size() - 1]); + + unpreparedFonts.emplace_back (newFont); + + return newFont; + } + + /***************************************************************************/ + /*! + + \brief + Transfers staging buffer font memory to the GPU for optimized access. + + \param cmdBuffer + Command buffer to record the transfer operations. + + \param descPool + + \return + + */ + /***************************************************************************/ + void SHFontLibrary::BuildFonts(Handle logicalDevice, Handle queue, Handle cmdPool, Handle descPool, Handle layout, SHResourceHub& resourceHub) noexcept + { + // create fence to wait on after transfer + Handle finishCopyFence = resourceHub.Create(logicalDevice); + finishCopyFence->Reset(); + + // allocate new command buffer + Handle transferCommandBuffer = cmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + + // Begin recording transfer ops + transferCommandBuffer->BeginRecording(); + { + // Transition image to dst + transferCommandBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, preTransferBarriers); + + // Transfer data from staging to image + for (auto& font : unpreparedFonts) + font->TransferToGPU(transferCommandBuffer); + + // Transition dst to shader read + transferCommandBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, postTransferBarriers); + } + + // End recording for transfer ops + transferCommandBuffer->EndRecording(); + + // Submit command buffer to queue + queue->SubmitCommandBuffer({transferCommandBuffer}, {}, {}, vk::PipelineStageFlagBits::eTransfer, finishCopyFence); + + // wait for copy to finish + finishCopyFence->Wait(true, std::numeric_limits::max()); + + // Prepare image views and desc sets + for (auto& font : unpreparedFonts) + font->DoPostTransfer(descPool, layout); + + // Free the command buffer and fence + transferCommandBuffer.Free(); + resourceHub.Free(finishCopyFence); + + // Once unprepared fonts are now ready for use, push them into container + uint32_t i = static_cast (unpreparedFonts.size()); + std::copy (unpreparedFonts.begin(), unpreparedFonts.end(), std::back_inserter(fonts)); + + // All fonts have been prepared for GPU usage + unpreparedFonts.clear(); + preTransferBarriers.clear(); + postTransferBarriers.clear(); + } + + std::vector> const& SHFontLibrary::GetFonts(void) const noexcept + { + return fonts; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontLibrary.h new file mode 100644 index 00000000..a3762e6b --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFontLibrary.h @@ -0,0 +1,36 @@ +#pragma once + +#include "SHFont.h" +#include +#include "Graphics/SHVulkanIncludes.h" + +namespace SHADE +{ + class SHVkLogicalDevice; + class SHVkDescriptorPool; + class SHVkCommandPool; + class SHVkCommandBuffer; + class SHVkQueue; + class SHVkDescriptorSetLayout; + + class SH_API SHFontLibrary + { + private: + //! Handles to all the fonts usable in SHTextRendererComponents + std::vector> fonts; + + //! Fonts that have yet to be properly prepared for usage + std::vector> unpreparedFonts; + + //! For transitioning images for transfer operations + std::vector preTransferBarriers; + + //! For transitioning images for shader reads + std::vector postTransferBarriers; + + public: + Handle AddFont (Handle logicalDevice, SHResourceHub& resourceHub, SHFontAsset const& asset) noexcept; + void BuildFonts (Handle logicalDevice, Handle queue, Handle cmdPool, Handle descPool, Handle layout, SHResourceHub& resourceHub) noexcept; + std::vector> const& GetFonts (void) const noexcept; + }; +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.cpp new file mode 100644 index 00000000..9e629020 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.cpp @@ -0,0 +1,27 @@ +#include "SHpch.h" +#include "SHFreetypeInstance.h" +#include "msdf-atlas-gen/msdf-atlas-gen.h" +#include "msdfgen-ext.h" + +namespace SHADE +{ + + msdfgen::FreetypeHandle* SHFreetypeInstance::freetypeHandle = nullptr; + + void SHFreetypeInstance::Init(void) noexcept + { + // initialize freetype + freetypeHandle = msdfgen::initializeFreetype(); + } + + void SHFreetypeInstance::Exit(void) noexcept + { + msdfgen::deinitializeFreetype(freetypeHandle); + } + + msdfgen::FreetypeHandle* SHFreetypeInstance::GetFreetypeHandle(void) noexcept + { + return freetypeHandle; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h new file mode 100644 index 00000000..4d1bed9c --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h @@ -0,0 +1,23 @@ +#pragma once + +namespace msdfgen +{ + class FreetypeHandle; +} + +namespace SHADE +{ + class SHFreetypeInstance + { + private: + //! Only need this to be initialized once + static msdfgen::FreetypeHandle* freetypeHandle; + + public: + static void Init (void) noexcept; + static void Exit (void) noexcept; + + static msdfgen::FreetypeHandle* GetFreetypeHandle(void) noexcept; + + }; +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp new file mode 100644 index 00000000..b407b599 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp @@ -0,0 +1,95 @@ +#include "SHpch.h" +#include "SHTextRenderableComponent.h" + +namespace SHADE +{ + + void SHTextRenderableComponent::MakeDirty(void) noexcept + { + requiresRecompute = true; + } + + void SHTextRenderableComponent::Clean(void) noexcept + { + requiresRecompute = false; + } + + /***************************************************************************/ + /*! + + \brief + On create the text has nothing. + + */ + /***************************************************************************/ + void SHTextRenderableComponent::OnCreate(void) + { + text = "My name is Brandon."; + requiresRecompute = true; + + // Default white color. + color = SHColour::WHITE; + } + + void SHTextRenderableComponent::OnDestroy(void) + { + + } + + /***************************************************************************/ + /*! + + \brief + Sets the text to be rendered. + + \param newText + + + \return + + */ + /***************************************************************************/ + void SHTextRenderableComponent::SetText(std::string_view newText) noexcept + { + text = newText; + MakeDirty(); + } + + void SHTextRenderableComponent::SetFont(Handle font) noexcept + { + fontHandle = font; + MakeDirty(); + } + + /***************************************************************************/ + /*! + + \brief + Getter for the text required to render. + + \return + + + */ + /***************************************************************************/ + std::string const& SHTextRenderableComponent::GetText(void) const noexcept + { + return text; + } + + Handle SHTextRenderableComponent::GetFont(void) const noexcept + { + return fontHandle; + } + +} + +namespace rttr +{ + RTTR_REGISTRATION + { + using namespace SHADE; + + registration::class_("Text Renderer Component"); + }; +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h new file mode 100644 index 00000000..ef907409 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include "ECS_Base/Components/SHComponent.h" +#include "Math/SHColour.h" +#include "Resource/SHHandle.h" +#include + +namespace SHADE +{ + class SHFont; + class SHVkDescriptorSetGroup; + class SHVkBuffer; + + class SH_API SHTextRenderableComponent final : public SHComponent + { + public: + static constexpr uint32_t MAX_CHARACTERS = 500; + + private: + using TextIndexingType = uint32_t; + + private: + //! Text required to be rendered + std::string text; + + //! Color of the text + SHColour color; + + //! Requires to recompute the positions of each glyph/character + bool requiresRecompute; + + //! Handle to the font used to render the text + Handle fontHandle; + + //! We want to index into the buffer with matrices + Handle indexingDataBuffer; + + //! character position data for each letter in the text + Handle charPositionDataBuffer; + + void MakeDirty (void) noexcept; + void Clean (void) noexcept; + + public: + void OnCreate(void) override final; + void OnDestroy(void) override final; + + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetText (std::string_view newText) noexcept; + void SetFont (Handle font) noexcept; + + std::string const& GetText (void) const noexcept; + Handle GetFont (void) const noexcept; + + friend class SHTextRenderingSubSystem; + + RTTR_ENABLE() + + }; +} + diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.cpp new file mode 100644 index 00000000..6748311e --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.cpp @@ -0,0 +1,242 @@ +#include "SHpch.h" +#include "SHTextRenderingSubSystem.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Math/Vector/SHVec4.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/MiddleEnd/TextRendering/SHFont.h" +#include "Graphics/Buffers/SHVkBuffer.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/SHVkUtil.h" +#include "Graphics/RenderGraph/SHSubpass.h" +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + void SHTextRenderingSubSystem::RecomputePositions(SHTextRenderableComponent& textComp) noexcept + { + if (textComp.text.empty() || !textComp.fontHandle) + return; + + // Create the buffer + if (!textComp.indexingDataBuffer) + textComp.indexingDataBuffer = logicalDevice->CreateBuffer(SHTextRenderableComponent::MAX_CHARACTERS * sizeof(uint32_t), nullptr, SHTextRenderableComponent::MAX_CHARACTERS * sizeof(uint32_t), vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); + + if (!textComp.charPositionDataBuffer) + textComp.charPositionDataBuffer = logicalDevice->CreateBuffer(SHTextRenderableComponent::MAX_CHARACTERS * sizeof(SHVec4), nullptr, SHTextRenderableComponent::MAX_CHARACTERS * sizeof(SHVec4), vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); + + // For indexing font transformation in the shader + std::vector indexingData; + + // For placing glyphs correctly + std::vector charPositionData; + + // Baseline relative to entity with this component + SHVec4 baselineOrigin{ 0.0f, 0.0f, 0.0f, 1.0f }; + + // Number of characters in the string + uint32_t numChars = static_cast(textComp.text.size()); + + // Get a ref to the transform indices + auto const& glyphTransformIndices = textComp.fontHandle->GetUnicodeIndexing(); + + // Get a ref to the glyph transformations + auto const& glyphTransforms = textComp.fontHandle->GetFontAsset().glyphTransformations; + + bool dueNextLine = false; + + // for every character + for (uint32_t i = 0; i < numChars; ++i) + { + SHTextRenderableComponent::TextIndexingType index = glyphTransformIndices.at(textComp.text[i]); + + // Copy baseline + SHVec4 characterPos = baselineOrigin; + + // Get where to draw the glyph relative to the baseline + characterPos[0] += glyphTransforms[index].m[SHFontAsset::BASELINE_LEFT_MATRIX_INDEX_ROW][SHFontAsset::BASELINE_LEFT_MATRIX_INDEX_COL]; // Inside the matrix but not used in the shader so this value has no positional value + characterPos[1] += glyphTransforms[index].m[SHFontAsset::BASELINE_BOTTOM_MATRIX_INDEX_ROW][SHFontAsset::BASELINE_BOTTOM_MATRIX_INDEX_COL]; // Inside the matrix but not used in the shader so this value has no positional value + + indexingData.push_back(index); + charPositionData.push_back(characterPos); + + // if not the last character + if (i != numChars - 1) + { + // Get the advance and move the baseline + double advance = 0.0; + textComp.fontHandle->GetFontAsset().fontGeometry.getAdvance(advance, textComp.text[i], textComp.text[static_cast(i) + 1]); + baselineOrigin[0] += static_cast(advance); + + //if (baselineOrigin[0] >= textComp.estimatedLineLength) + //{ + // dueNextLine = true; + //} + } + + //if (dueNextLine && textComp.renderedText[i] == ' ') + //{ + // baselineOrigin[0] = 0.0f; + // baselineOrigin[1] -= textComp.lineSpacing; + // dueNextLine = false; + //} + } + + textComp.indexingDataBuffer->WriteToMemory(indexingData.data(), static_cast(indexingData.size()) * sizeof (SHTextRenderableComponent::TextIndexingType),0, 0); + textComp.charPositionDataBuffer->WriteToMemory(charPositionData.data(), static_cast(charPositionData.size()) * sizeof (SHVec4), 0, 0); + + indexingData.clear(); + charPositionData.clear(); + + } + + void SHTextRenderingSubSystem::Init(Handle device, Handle compatibleRenderpass, Handle subpass, Handle descPool, Handle textVS, Handle textFS, std::function, uint32_t)> const& bindFunction) noexcept + { + SHComponentManager::CreateComponentSparseSet(); + + cameraDescSetBind = bindFunction; + + logicalDevice = device; + + // prepare pipeline layout params + SHPipelineLayoutParams plParams + { + .shaderModules = {textVS, textFS}, + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() + }; + + pipelineLayout = logicalDevice->CreatePipelineLayout(plParams); + + // Create pipeline + pipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, compatibleRenderpass, subpass); + + // vertex input state of the pipeline + SHVertexInputState vertexInputState; + + // Configure vertex attributes + vertexInputState.AddBinding(true, false, { SHVertexAttribute(SHAttribFormat::FLOAT_4D) }); // location = 0 (character position data) + vertexInputState.AddBinding(true, false, { SHVertexAttribute(SHAttribFormat::UINT32_1D) }); // location = 1 (glyph index to index matrices) + + // Set vertex state for new pipeline + pipeline->GetPipelineState().SetVertexInputState(vertexInputState); + + SHColorBlendState colorBlendState{}; + colorBlendState.logic_op_enable = VK_FALSE; + colorBlendState.logic_op = vk::LogicOp::eCopy; + + auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); + colorBlendState.attachments.reserve(static_cast(subpassColorReferences.size())); + + for (auto& att : subpassColorReferences) + { + colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState + { + .blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(att.attachment)) ? true : false, + .srcColorBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eOne, + .dstAlphaBlendFactor = vk::BlendFactor::eZero, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + } + ); + } + + pipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + SHInputAssemblyState inputAssembly{}; + inputAssembly.topology = vk::PrimitiveTopology::eTriangleFan; + pipeline->GetPipelineState().SetInputAssemblyState(inputAssembly); + + SHRasterizationState rasterState{}; + rasterState.frontFacingOrientation = vk::FrontFace::eClockwise; + pipeline->GetPipelineState().SetRasterizationState(rasterState); + + // Construct pipeline + pipeline->ConstructPipeline(); + + SHVkDescriptorSetLayout::Binding fontBitmapBinding + { + .Type = vk::DescriptorType::eCombinedImageSampler, + .Stage = vk::ShaderStageFlagBits::eFragment, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::FONT_BITMAP_DATA, + .DescriptorCount = 1, + }; + + SHVkDescriptorSetLayout::Binding fontMatrixBinding + { + .Type = vk::DescriptorType::eStorageBuffer, + .Stage = vk::ShaderStageFlagBits::eVertex, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::FONT_MATRIX_DATA, + .DescriptorCount = 1, + }; + + fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::FONT_DATA, { fontBitmapBinding, fontMatrixBinding }); + + } + + void SHTextRenderingSubSystem::Run(uint32_t frameIndex) noexcept + { + auto& textRendererComps = SHComponentManager::GetDense(); + + for (auto& comp : textRendererComps) + { + // If the component is dirty + if (comp.requiresRecompute) + { + RecomputePositions(comp); + comp.Clean(); + } + } + } + + void SHTextRenderingSubSystem::Render(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + auto& textRendererComps = SHComponentManager::GetDense(); + for (auto& comp : textRendererComps) + { + auto* transform = SHComponentManager::GetComponent(comp.GetEID()); + + Handle fontHandle = comp.fontHandle; + if (fontHandle && transform) + { + // bind the pipeline + cmdBuffer->BindPipeline(pipeline); + + // bind VBO (position and indices) + cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::CALCULATED_GLYPH_POSITION, comp.charPositionDataBuffer, 0); + cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::GLYPH_INDEX, comp.indexingDataBuffer, 0); + + cameraDescSetBind(cmdBuffer, frameIndex); + + // bind descriptors for font (matrices) + cmdBuffer->BindDescriptorSet(fontHandle->GetDescriptorSet(), SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::FONT_DATA, {}); + + cmdBuffer->SetPushConstantVariable("TestPushConstant.worldTransform", transform->GetTRS(), SH_PIPELINE_TYPE::GRAPHICS); + cmdBuffer->SetPushConstantVariable("TestPushConstant.eid", comp.GetEID(), SH_PIPELINE_TYPE::GRAPHICS); + cmdBuffer->SetPushConstantVariable("TestPushConstant.textColor", SHVec3 (1.0f, 1.0f, 1.0f), SH_PIPELINE_TYPE::GRAPHICS); + + cmdBuffer->SubmitPushConstants(SH_PIPELINE_TYPE::GRAPHICS); + + // call draw call + cmdBuffer->DrawArrays(4, comp.text.size(), 0, 0); + //glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, static_cast(textComp.lastRenderedCharacterIndex) + 1); + + } + + } + } + + void SHTextRenderingSubSystem::Exit(void) noexcept + { + + } + + Handle SHTextRenderingSubSystem::GetFontDataDescSetLayout(void) const noexcept + { + return fontDataDescSetLayout; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h new file mode 100644 index 00000000..05ab01da --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h @@ -0,0 +1,65 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include "Graphics/Pipeline/SHPipelineState.h" +#include "Math/SHMatrix.h" +#include "Math/Vector/SHVec3.h" + +namespace SHADE +{ + class SHVkLogicalDevice; + class SHVkDescriptorPool; + class SHVkDescriptorSetGroup; + class SHVkDescriptorSetLayout; + class SHVkBuffer; + class SHLightComponent; + class SHVkCommandBuffer; + class SHTextRenderableComponent; + class SHVkPipeline; + class SHVkPipelineLayout; + class SHVkRenderpass; + class SHSubpass; + class SHVkShaderModule; + + class SHTextRenderingSubSystem + { + private: + struct ShaderPushConstantData + { + SHMatrix worldTransform; + uint32_t eid; + SHVec3 textColor; + }; + + //! Logical device for creation and destruction + Handle logicalDevice; + + //! Pipeline for rendering the text + Handle pipeline; + + //! Pipeline layout for the pipeline + Handle pipelineLayout; + + //! Descriptor set for font data access in shaders + Handle fontDataDescSetLayout; + + //! Super temporary. Global descriptor set needs to be revamped along with + //! entire graphics system. + std::function, uint32_t)> cameraDescSetBind; + + private: + void RecomputePositions(SHTextRenderableComponent& textComp) noexcept; + + public: + void Init(Handle device, Handle compatibleRenderpass, Handle subpass, Handle descPool, Handle textVS, Handle textFS, std::function, uint32_t)> const& bindFunction) noexcept; + void Run(uint32_t frameIndex) noexcept; + + void Render (Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Exit(void) noexcept; + + + Handle GetFontDataDescSetLayout (void) const noexcept; + + + }; +} diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 589e66d2..0333aa09 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -79,9 +79,9 @@ namespace SHADE startOffset += pcInfo.size; } + stageFlags |= shaderModule->GetShaderStageFlagBits(); } - stageFlags |= shaderModule->GetShaderStageFlagBits(); } // After all the sizes of the push constant blocks have been added, record the size in the interface diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h index c4d44ea8..16c07cdf 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -3,7 +3,7 @@ namespace SHADE { // Used for attachment description creation for renderpass node - enum class SH_ATT_DESC_TYPE_FLAGS + enum class SH_RENDER_GRAPH_RESOURCE_FLAGS { COLOR = 0x01, COLOR_PRESENT = 0x02, @@ -11,7 +11,8 @@ namespace SHADE STENCIL = 0x08, DEPTH_STENCIL = 0x10, INPUT = 0x20, - STORAGE = 0x40 + STORAGE = 0x40, + SHARED = 0x80 // if resource is meant to be used across render graphs, mark this flag }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index e798bfe7..2ffd6d13 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -11,6 +11,9 @@ #include "SHAttachmentDescInitParams.h" #include "SHRenderGraphStorage.h" #include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" +#include "Tools/Utilities/SHUtilities.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Graphics/RenderGraph/SHRenderToSwapchainImageSystem.h" namespace SHADE { @@ -49,7 +52,7 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) + void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) { // If we set to if (w == static_cast(-1) && h == static_cast(-1)) @@ -59,10 +62,41 @@ namespace SHADE format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - auto resource = resourceManager->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); + auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); renderGraphStorage->graphResources->try_emplace(resourceName, resource); } + void SHRenderGraph::LinkNonOwningResource(Handle resourceOrigin, std::string resourceName) noexcept + { + // resource to link + Handle resourceToLink = resourceOrigin->GetRenderGraphResource(resourceName); + if (!resourceToLink) + { + SHLOG_ERROR("Resource does not exist in render graph, cannot link resource."); + return; + } + + // Get the final layout of the resource from the previous render graph + vk::ImageLayout finalLayout{vk::ImageLayout::eUndefined}; + auto const& nodes = resourceOrigin->GetNodes(); + for (auto& node : nodes) + { + if (vk::ImageLayout layout = resourceToLink->GetInfoTracker()->GetLayout(node, {}); layout != vk::ImageLayout::eUndefined) + finalLayout = layout; + + for (auto& compute : node->nodeComputes) + { + if (vk::ImageLayout layout = resourceToLink->GetInfoTracker()->GetLayout(compute); layout != vk::ImageLayout::eUndefined) + finalLayout = layout; + } + } + + renderGraphStorage->graphResources->try_emplace(resourceName, resourceToLink); + + // add to this pool so that when we generate later, the attachment descriptions will make its initial layout the layout stored here + renderGraphStorage->nonOwningResourceInitialLayouts.emplace(resourceToLink.GetId().Raw, finalLayout); + } + /***************************************************************************/ /*! @@ -88,30 +122,59 @@ namespace SHADE return; } + // We first want to take all resources track their layout as undefined at the start of the node/renderpass + auto const resources = node->GetResources(); + for (auto& resource : resources) + { + resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); + } + // attempt to get all final layouts for all resources for (auto& subpass : node->subpasses) { for (auto& color : subpass->colorReferences) { // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass - if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT))) + if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; else resourceAttFinalLayouts[color.attachment] = color.layout; + + node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); } for (auto& depth : subpass->depthReferences) + { resourceAttFinalLayouts[depth.attachment] = depth.layout; + node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); + } for (auto& input : subpass->inputReferences) + { resourceAttFinalLayouts[input.attachment] = input.layout; + node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); + } } for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) { auto& att = node->attachmentDescriptions[j]; - att.initialLayout = vk::ImageLayout::eUndefined; + auto& resource = node->attResources[j]; + + // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. + // We also want to load the attachment, not "don't care". + if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && + renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) + { + att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at (resource.GetId().Raw); + att.loadOp = vk::AttachmentLoadOp::eLoad; + att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; + } + else + att.initialLayout = vk::ImageLayout::eUndefined; + att.finalLayout = resourceAttFinalLayouts[j]; + resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); } ++i; } @@ -146,12 +209,13 @@ namespace SHADE attDesc.stencilLoadOp = vk::AttachmentLoadOp::eLoad; attDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; - // TODO: Stencil load and store - // When an image is done being used in a renderpass, the image layout will end up being the finalLayout // value of the attachment description. We want this to carry over to the next renderpass; specifically // to have the initialLayout of the attachment description in the next renderpass match the finalLayout in the previous. attDesc.initialLayout = predAttDesc.finalLayout; + + // We also want to track it + predResource->GetInfoTracker()->TrackLayout(node, {}, attDesc.initialLayout); } } } @@ -225,12 +289,12 @@ namespace SHADE for (auto& inputAtt : subpass->inputReferences) { auto resource = node->attResources[inputAtt.attachment]; - if (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::INPUT)) + if (resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT)) { - if (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR) || - resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) + if (resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR) || + resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) colorRead |= (1 << i); - else if (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL)) + else if (resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL)) depthRead |= (1 << i); } else @@ -323,6 +387,12 @@ namespace SHADE } } + void SHRenderGraph::ConfigureSubSystems(void) noexcept + { + if (renderToSwapchainImageSystem) + renderToSwapchainImageSystem->ConstructPipelines(renderGraphStorage->logicalDevice); + } + /***************************************************************************/ /*! @@ -354,17 +424,17 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::Init(std::string graphName, Handle logicalDevice, Handle swapchain) noexcept + void SHRenderGraph::Init(std::string graphName, Handle logicalDevice, Handle swapchain, SHResourceHub* resourceHub) noexcept { - resourceManager = std::make_shared(); + //resourceHub = std::make_shared(); - renderGraphStorage = resourceManager->Create(); - renderGraphStorage->graphResources = resourceManager->Create>>(); + renderGraphStorage = resourceHub->Create(); + renderGraphStorage->graphResources = resourceHub->Create>>(); renderGraphStorage->logicalDevice = logicalDevice; renderGraphStorage->swapchain = swapchain; - renderGraphStorage->resourceManager = resourceManager; + renderGraphStorage->resourceHub = resourceHub; renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools(); name = std::move(graphName); @@ -384,7 +454,6 @@ namespace SHADE SHRenderGraph::SHRenderGraph(void) noexcept : renderGraphStorage{} , nodes{} - , resourceManager{nullptr} { } @@ -392,7 +461,6 @@ namespace SHADE : renderGraphStorage{ rhs.renderGraphStorage } , nodeIndexing{ std::move(rhs.nodeIndexing) } , nodes{ std::move(rhs.nodes) } - , resourceManager{ std::move(rhs.resourceManager) } , name { std::move(rhs.name) } { @@ -406,7 +474,6 @@ namespace SHADE renderGraphStorage = rhs.renderGraphStorage; nodeIndexing = std::move(rhs.nodeIndexing); nodes = std::move(rhs.nodes); - resourceManager = std::move(rhs.resourceManager); name = std::move(rhs.name); return *this; @@ -472,11 +539,40 @@ namespace SHADE } } - auto node = nodes.emplace_back(resourceManager->Create(nodeName, renderGraphStorage, std::move(descInitParams), std::move(predecessors))); + auto node = nodes.emplace_back(renderGraphStorage->resourceHub->Create(nodeName, renderGraphStorage, std::move(descInitParams), std::move(predecessors))); nodeIndexing.emplace(std::move(nodeName), static_cast(nodes.size()) - 1u); return node; } + void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list predecessorNodes, std::pair, Handle> shaderModules) noexcept + { + for (auto& node : predecessorNodes) + { + if (!nodeIndexing.contains(node)) + return; + } + + if (renderGraphStorage->graphResources->contains(toSwapchainResource) && renderGraphStorage->graphResources->contains(swapchainResource)) + { + auto newNode = AddNode("Render To Present", { ResourceInstruction (toSwapchainResource.c_str()), ResourceInstruction(swapchainResource.c_str()) }, predecessorNodes); + auto newSubpass = newNode->AddSubpass("Render"); + newSubpass->AddColorOutput(swapchainResource); + newSubpass->AddInput(toSwapchainResource); + + renderToSwapchainImageSystem = renderGraphStorage->resourceHub->Create (newNode, newSubpass, shaderModules); + + newSubpass->AddExteriorDrawCalls([=](Handle& cmdBuffer, uint32_t frameIndex) + { + cmdBuffer->BindPipeline(renderToSwapchainImageSystem->GetPipeline()); + + newSubpass->BindDescriptorInputDescriptorSets (cmdBuffer, frameIndex); + + // draw a quad. + cmdBuffer->DrawArrays(4, 1, 0, 0); + }); + } + } + /***************************************************************************/ /*! @@ -497,6 +593,7 @@ namespace SHADE ConfigureSubpasses(); ConfigureRenderpasses(); ConfigureFramebuffers(); + ConfigureSubSystems(); } /***************************************************************************/ @@ -539,7 +636,10 @@ namespace SHADE { // resize resources for (auto& [name, resource] : *renderGraphStorage->graphResources) - resource->HandleResize(newWidth, newHeight); + { + if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) + resource->HandleResize(newWidth, newHeight); + } for (auto& node : nodes) { @@ -556,6 +656,11 @@ namespace SHADE } + std::vector> const& SHRenderGraph::GetNodes(void) const noexcept + { + return nodes; + } + Handle SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept { if (renderGraphStorage->graphResources->contains(resourceName)) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 741cc522..0a9ed376 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -32,6 +32,7 @@ namespace SHADE class SHGraphicsGlobalData; class SHVkDescriptorPool; class SHRenderGraphStorage; + class SHRenderToSwapchainImageSystem; class SH_API SHRenderGraph { @@ -41,7 +42,7 @@ namespace SHADE std::string resourceName; bool dontClearOnLoad; - ResourceInstruction (char const* resourceName, bool dontClearOnLoad = false) noexcept; + ResourceInstruction(char const* resourceName, bool dontClearOnLoad = false) noexcept; }; private: @@ -52,6 +53,7 @@ namespace SHADE void ConfigureAttachmentDescriptions (void) noexcept; void ConfigureSubpasses (void) noexcept; void ConfigureRenderpasses (void) noexcept; + void ConfigureSubSystems (void) noexcept; void ConfigureFramebuffers (void) noexcept; /*-----------------------------------------------------------------------*/ @@ -66,12 +68,12 @@ namespace SHADE //! Render graph nodes std::vector> nodes; - //! Resource library for graph handles - std::shared_ptr resourceManager; - //! Name of the RenderGraph std::string name; + //! For rendering onto the swapchain + Handle renderToSwapchainImageSystem; + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ @@ -84,9 +86,11 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (std::string graphName, Handle logicalDevice, Handle swapchain) noexcept; - void AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {}); + void Init (std::string graphName, Handle logicalDevice, Handle swapchain, SHResourceHub* resourceHub) noexcept; + void AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {}); + void LinkNonOwningResource (Handle resourceOrigin, std::string resourceName) noexcept; Handle AddNode (std::string nodeName, std::initializer_list resourceInstruction, std::initializer_list predecessorNodes) noexcept; + void AddRenderToSwapchainNode (std::string toSwapchainResource, std::string swapchainResource, std::initializer_list predecessorNodes, std::pair, Handle> shaderModules) noexcept; void Generate (void) noexcept; void CheckForNodeComputes (void) noexcept; @@ -97,9 +101,30 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - Handle GetNode (std::string const& nodeName) const noexcept; - Handle GetRenderGraphResource (std::string const& resourceName) const noexcept; + Handle GetNode (std::string const& nodeName) const noexcept; + std::vector> const& GetNodes (void) const noexcept; + Handle GetRenderGraphResource (std::string const& resourceName) const noexcept; }; } #endif + + + +/* Some notes here: + * - The graph wasn't implemented with the intention of it being this versatile. + * - Graphs weren't meant to share resources and hence the generating of the render graph doesn't account for it. + * However, because it was eventually necessary that some resources had to be shared and its contents carried over to + * other graphs, the functionality was implemented through a link function in SHRenderGraph.cpp to facilitate this linkage. + * This should ideally be replaced by an implementation more self-contained, perhaps through a higher level class like a canvas + * that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph, + * but different matrices (SHRenderer) can be used in different nodes. + * - There are also way too many hash maps created for ease of access. This definitely can be cut down. + * - + * + */ + + + + + diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 3f6be1d9..0f9379fe 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -46,7 +46,7 @@ namespace SHADE for (uint32_t j = 0; j < attResources.size(); ++j) { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; imageViews[j] = attResources[j]->imageViews[imageViewIndex]; // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's @@ -74,7 +74,7 @@ namespace SHADE for (uint32_t j = 0; j < attResources.size(); ++j) { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; imageViews[j] = attResources[j]->imageViews[imageViewIndex]; // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's @@ -160,7 +160,7 @@ namespace SHADE newDesc.format = attResources[i]->resourceFormat; - if (attResources[i]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) + if (attResources[i]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) containsSwapchainImage = true; resourceAttachmentMapping->try_emplace(attResources[i].GetId().Raw, i); @@ -250,7 +250,7 @@ namespace SHADE // Add subpass to container and create mapping for it subpasses.emplace_back ( - graphStorage->resourceManager->Create + graphStorage->resourceHub->Create ( subpassName, graphStorage, GetHandle(), static_cast(subpasses.size()), @@ -259,7 +259,7 @@ namespace SHADE ); subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); Handle subpass = subpasses.back(); - subpass->Init(*graphStorage->resourceManager); + subpass->Init(*graphStorage->resourceHub); // Register the SuperBatch batcher.RegisterSuperBatch(subpass->GetSuperBatch()); @@ -279,10 +279,18 @@ namespace SHADE nodeComputeResources.push_back(resource); } + // need to use for tracking resources + std::vector> temp (nodeComputeResources); + // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceManager->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); nodeComputes.push_back(nodeCompute); + for (auto& resource : temp) + { + resource->GetInfoTracker()->TrackLayout(nodeCompute); + } + return nodeCompute; } @@ -405,4 +413,9 @@ namespace SHADE return {}; } + std::vector> const& SHRenderGraphNode::GetResources(void) const noexcept + { + return attResources; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 299578f2..775d64f7 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -117,6 +117,7 @@ namespace SHADE Handle GetRenderpass(void) const noexcept; Handle GetSubpass(std::string_view subpassName) const noexcept; Handle GetResource (uint32_t resourceIndex) const noexcept; + std::vector> const& GetResources (void) const noexcept; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index f4a103f7..2f8fd968 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -45,6 +45,7 @@ namespace SHADE // save the resources resources = std::move (subpassComputeResources); + //Get the descriptor set layouts required to allocate. We only want the ones for allocate because //global descriptors are already bound in the main system. auto const& graphResourceLayout = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE]; @@ -65,7 +66,7 @@ namespace SHADE if (layouts.size() == SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE + 1) { // create compute resources - computeResource = graphStorage->resourceManager->Create(); + computeResource = graphStorage->resourceHub->Create(); auto computeResourceLayout = layouts[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE]; computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 }); #ifdef _DEBUG @@ -119,7 +120,7 @@ namespace SHADE // loop through bindings and write descriptor sets for (auto& binding : pipelineDescSetLayouts->GetBindings()) { - uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0; + uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0; SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle{}, vk::ImageLayout::eGeneral); graphResourceDescSets[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 }); @@ -154,7 +155,7 @@ namespace SHADE .newLayout = vk::ImageLayout::eGeneral, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), + .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), .subresourceRange = vk::ImageSubresourceRange { .aspectMask = resource->imageAspectFlags, diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index 4d4099c6..ce7e1622 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -6,9 +6,41 @@ #include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/SHVkUtil.h" #include "SHRenderGraphStorage.h" +#include "Graphics/RenderGraph/SHSubpass.h" +#include "Graphics/RenderGraph/SHRenderGraphNode.h" namespace SHADE { + void SHRenderGraphResource::InfoTracker::TrackLayout(Handle node, Handle subpass, vk::ImageLayout layout) noexcept + { + NodeSubpassPair nodeSubpassPair = std::pair(node, subpass); + layoutTracker[std::hash{}(nodeSubpassPair)] = layout; + } + + + void SHRenderGraphResource::InfoTracker::TrackLayout(Handle compute) noexcept + { + computeTracker.emplace (compute.GetId().Raw); + } + + vk::ImageLayout SHRenderGraphResource::InfoTracker::GetLayout(Handle node, Handle subpass) const noexcept + { + NodeSubpassPair nodeSubpassPair = std::pair(node, subpass); + std::size_t hashedValue = std::hash{}(nodeSubpassPair); + + if (layoutTracker.contains(hashedValue)) + return layoutTracker.at(hashedValue); + else + return vk::ImageLayout::eUndefined; + } + + vk::ImageLayout SHRenderGraphResource::InfoTracker::GetLayout(Handle compute) const noexcept + { + if (computeTracker.contains (compute.GetId().Raw)) + return vk::ImageLayout::eGeneral; + else + return vk::ImageLayout::eUndefined; + } /***************************************************************************/ /*! @@ -46,7 +78,7 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } @@ -58,9 +90,9 @@ namespace SHADE , resourceName{ name } { // If the resource type is an arbitrary image and not swapchain image - if (typeFlags.size() == 1 && *typeFlags.begin() == SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT) + if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT) { - resourceTypeFlags |= static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT); + resourceTypeFlags |= static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT); // Prepare image view details SHImageViewDetails viewDetails @@ -98,30 +130,30 @@ namespace SHADE // Check the resource type and set image usage flags and image aspect flags accordingly switch (type) { - case SH_ATT_DESC_TYPE_FLAGS::COLOR: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR: usage |= vk::ImageUsageFlagBits::eColorAttachment; imageAspectFlags |= vk::ImageAspectFlagBits::eColor; break; - case SH_ATT_DESC_TYPE_FLAGS::DEPTH: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; break; - case SH_ATT_DESC_TYPE_FLAGS::STENCIL: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; break; - case SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL: usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; break; - case SH_ATT_DESC_TYPE_FLAGS::INPUT: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT: usage |= vk::ImageUsageFlagBits::eInputAttachment; usage |= vk::ImageUsageFlagBits::eSampled; break; - case SH_ATT_DESC_TYPE_FLAGS::STORAGE: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE: usage |= vk::ImageUsageFlagBits::eStorage; break; - case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT: { SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. "); return; @@ -151,6 +183,8 @@ namespace SHADE imageViews.push_back(imageView); SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eImageView, imageView->GetImageView(), "[Image View] " + resourceName); } + + infoTracker = renderGraphStorage->resourceHub->Create(); } /***************************************************************************/ @@ -175,6 +209,7 @@ namespace SHADE , mipLevels{ rhs.mipLevels } , imageAspectFlags{ rhs.imageAspectFlags } , graphStorage{rhs.graphStorage} + , infoTracker {std::move (rhs.infoTracker)} { } @@ -207,6 +242,7 @@ namespace SHADE mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; graphStorage = rhs.graphStorage; + infoTracker = std::move(infoTracker); return *this; } @@ -229,7 +265,7 @@ namespace SHADE width = newWidth; height = newHeight; - if ((resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) == 0) + if ((resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) == 0) { // prepare image view details SHImageViewDetails viewDetails @@ -347,4 +383,9 @@ namespace SHADE return resourceName; } + SHADE::Handle SHRenderGraphResource::GetInfoTracker(void) const noexcept + { + return infoTracker; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index e2fc5d8d..7ac2b824 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -6,6 +6,7 @@ #include "Resource/SHHandle.h" #include "Graphics/SHVulkanIncludes.h" #include "SH_API.h" +#include namespace SHADE { @@ -16,11 +17,41 @@ namespace SHADE class SHVkCommandBuffer; class SHVkBuffer; class SHRenderGraphStorage; + class SHRenderGraphNode; + class SHSubpass; + class SHRenderGraphNodeCompute; static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0; class SH_API SHRenderGraphResource { + public: + // For keeping track of resources as it gets passed down the pipeline (between multiple render graphs) + class InfoTracker + { + private: + using NodeSubpassPair = std::pair, Handle>; + + //! key here is the render graph node and subpass name combined, value is the layout of the resource at that node and subpass + std::unordered_map layoutTracker; + + //! if a resource is involved in a compute process, record it here + std::unordered_set computeTracker; + + public: + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + void TrackLayout (Handle node, Handle subpass, vk::ImageLayout layout) noexcept; + void TrackLayout (Handle compute) noexcept; + + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + vk::ImageLayout GetLayout(Handle node, Handle subpass) const noexcept; + vk::ImageLayout GetLayout(Handle compute) const noexcept; + }; + private: /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -62,12 +93,14 @@ namespace SHADE //! usage flags vk::ImageUsageFlags usage = {}; + //! For tracking resource states in stages of the render graphs + Handle infoTracker; public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; @@ -89,6 +122,7 @@ namespace SHADE Handle GetImage (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; uint8_t GetMipLevels (void) const noexcept; std::string GetName (void) const noexcept; + Handle GetInfoTracker (void) const noexcept; friend class SHRenderGraphNode; friend class SHRenderGraph; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h index 54ef705a..d02d8d39 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h @@ -20,7 +20,7 @@ namespace SHADE Handle swapchain; //! Resource manager for creation of objects - std::shared_ptr resourceManager; + SHResourceHub* resourceHub; //! Descriptor pool for the descriptor sets to be created in the subpasses Handle descriptorPool; @@ -28,6 +28,10 @@ namespace SHADE //! For accessing resources anywhere in the graph Handle>> graphResources; + //! HACK: Because there's no interface to specify a dependency between graphs, this will help attachment descriptions + //! use the correct layout, when a resource is shared between graphs + std::unordered_map nonOwningResourceInitialLayouts{}; + //SHRenderGraphStorage(void) noexcept; //SHRenderGraphStorage(SHRenderGraphStorage&& rhs) noexcept; //SHRenderGraphStorage& operator=(SHRenderGraphStorage&& rhs) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderToSwapchainImageSystem.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderToSwapchainImageSystem.cpp new file mode 100644 index 00000000..770217ee --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderToSwapchainImageSystem.cpp @@ -0,0 +1,66 @@ +#include "SHpch.h" +#include "SHRenderToSwapchainImageSystem.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Graphics/RenderGraph/SHRenderGraphNode.h" +#include "Graphics/RenderGraph/SHSubpass.h" +#include "Graphics/SHVkUtil.h" + +namespace SHADE +{ + + SHRenderToSwapchainImageSystem::SHRenderToSwapchainImageSystem(Handle node, Handle subpass, std::pair, Handle> shaders) noexcept + : renderGraphNode {node} + , subpass{subpass} + , shaderModules{shaders} + , pipeline{} + , pipelineLayout{} + { + + } + + void SHRenderToSwapchainImageSystem::ConstructPipelines(Handle logicalDevice) noexcept + { + auto pipelineLayout = logicalDevice->CreatePipelineLayout(SHPipelineLayoutParams + { + .shaderModules = {shaderModules.first, shaderModules.second}, + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts(), + }); + + pipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderGraphNode->GetRenderpass(), subpass); + + SHInputAssemblyState inputAssembly{}; + inputAssembly.topology = vk::PrimitiveTopology::eTriangleFan; + + pipeline->GetPipelineState().SetInputAssemblyState(inputAssembly); + + SHColorBlendState colorBlendState{}; + colorBlendState.logic_op_enable = VK_FALSE; + colorBlendState.logic_op = vk::LogicOp::eCopy; + + auto const& subpassColorReference = subpass->GetColorAttachmentReferences()[0]; + colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState + { + .blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(subpassColorReference.attachment)), + .srcColorBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eOne, + .dstAlphaBlendFactor = vk::BlendFactor::eZero, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + } + ); + + pipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + pipeline->ConstructPipeline(); + + } + + Handle SHRenderToSwapchainImageSystem::GetPipeline(void) const noexcept + { + return pipeline; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderToSwapchainImageSystem.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderToSwapchainImageSystem.h new file mode 100644 index 00000000..808fd9a0 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderToSwapchainImageSystem.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkPipelineLayout; + class SHVkShaderModule; + class SHRenderGraphNode; + class SHSubpass; + class SHVkLogicalDevice; + class SHSubpass; + + + class SHRenderToSwapchainImageSystem + { + private: + //! Render Graph node to get the renderpass from to initialize the pipeline + Handle renderGraphNode; + + //! Subpass to initialize the pipeline with + Handle subpass; + + //! Shader module required to render the quad on screen + std::pair, Handle> shaderModules; + + //! pipeline required to draw the image + Handle pipeline; + + //! Pipeline layout of the pipeline + Handle pipelineLayout; + + public: + SHRenderToSwapchainImageSystem (Handle node, Handle subpass, std::pair, Handle> shaders) noexcept; + + void ConstructPipelines (Handle logicalDevice) noexcept; + + Handle GetPipeline (void) const noexcept; + + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index dfa5977b..c1d53632 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -40,7 +40,7 @@ namespace SHADE , inputReferences{} , name { name } , graphStorage{ renderGraphStorage } - , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS} + , inputImageDescriptorSets{} { } @@ -67,7 +67,7 @@ namespace SHADE , exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) } , graphStorage{ rhs.graphStorage } , inputNames{ std::move(rhs.inputNames) } - , inputImageDescriptors{ std::move(rhs.inputImageDescriptors) } + , inputImageDescriptorSets{ std::move(rhs.inputImageDescriptorSets) } , inputDescriptorLayout{ rhs.inputDescriptorLayout } , inputSamplers{ rhs.inputSamplers } , name { rhs.name } @@ -102,7 +102,7 @@ namespace SHADE exteriorDrawCalls = std::move(rhs.exteriorDrawCalls); graphStorage = rhs.graphStorage; inputNames = std::move(rhs.inputNames); - inputImageDescriptors = std::move(rhs.inputImageDescriptors); + inputImageDescriptorSets = std::move(rhs.inputImageDescriptorSets); inputDescriptorLayout = rhs.inputDescriptorLayout; inputSamplers = rhs.inputSamplers; name = std::move(rhs.name); @@ -148,18 +148,18 @@ namespace SHADE */ /***************************************************************************/ - void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType) noexcept + void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_RENDER_GRAPH_RESOURCE_FLAGS attachmentDescriptionType) noexcept { vk::ImageLayout imageLayout; switch (attachmentDescriptionType) { - case SH_ATT_DESC_TYPE_FLAGS::DEPTH: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; break; - case SH_ATT_DESC_TYPE_FLAGS::STENCIL: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; break; - case SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL: + case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL: imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; break; default: @@ -202,6 +202,8 @@ namespace SHADE void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { commandBuffer->BeginLabeledSegment(name); + + // Ensure correct transforms are provided superBatch->UpdateBuffers(frameIndex, descPool); @@ -211,7 +213,7 @@ namespace SHADE // Draw all the exterior draw calls for (auto& drawCall : exteriorDrawCalls) { - drawCall(commandBuffer); + drawCall(commandBuffer, frameIndex); } commandBuffer->EndLabeledSegment(); } @@ -221,7 +223,15 @@ namespace SHADE UpdateWriteDescriptors(); } - void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept + void SHSubpass::BindDescriptorInputDescriptorSets(Handle cmdBuffer, uint32_t frameIndex) const noexcept + { + if (!inputImageDescriptorSets.empty()) + { + cmdBuffer->BindDescriptorSet(inputImageDescriptorSets[frameIndex], SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, { }); + } + } + + void SHSubpass::AddExteriorDrawCalls(std::function&, uint32_t)> const& newDrawCall) noexcept { exteriorDrawCalls.push_back(newDrawCall); } @@ -237,6 +247,8 @@ namespace SHADE if (inputNames.empty()) return; + inputImageDescriptorSets.resize(SHGraphicsConstants::NUM_FRAME_BUFFERS); + std::vector bindings{}; for (auto& input : inputReferences) @@ -280,8 +292,8 @@ namespace SHADE } } - //// maybe do this in handle resize? - //UpdateWriteDescriptors(); + // maybe do this in handle resize? + UpdateWriteDescriptors(); } void SHSubpass::UpdateWriteDescriptors(void) noexcept @@ -296,7 +308,7 @@ namespace SHADE // For every frame's descriptor set - for (auto& group : inputImageDescriptors) + for (auto& group : inputImageDescriptorSets) { if (group) group.Free(); @@ -315,7 +327,7 @@ namespace SHADE auto resource = graphStorage->graphResources->at(inputNames[binding.BindPoint]); // If resource is swapchain image, get the correct image, if not just get 0. - uint32_t viewIndex = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; + uint32_t viewIndex = (resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; // layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index c82ebdd0..69b8fd56 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -55,8 +55,11 @@ namespace SHADE //! For getting attachment reference indices using handles std::unordered_map const* resourceAttachmentMapping; - //! Descriptor set group to hold the images for input - std::vector> inputImageDescriptors; + //! Descriptor set group to hold the images for input. We have 3 here just in case + //! one of the images is a swapchain image. Practically speaking its not likely not + //! swapchain images will end up being images used in descriptor sets, but this is + //! to have the support for it. The cost is not much. + std::vector> inputImageDescriptorSets; //! Descriptor set layout for allocating descriptor set for inputs Handle inputDescriptorLayout; @@ -76,7 +79,7 @@ namespace SHADE //! after we draw everything from the batch. Because of this, these draw calls //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING //! COMPLEX. - std::vector&)>> exteriorDrawCalls; + std::vector&, uint32_t)>> exteriorDrawCalls; /// For identifying subpasses std::string name; @@ -95,15 +98,16 @@ namespace SHADE // Preparation functions void AddColorOutput(std::string resourceToReference) noexcept; void AddGeneralColorOutput(std::string resourceToReference) noexcept; - void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept; + void AddDepthOutput(std::string resourceToReference, SH_RENDER_GRAPH_RESOURCE_FLAGS attachmentDescriptionType = SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL) noexcept; void AddGeneralDepthOutput(std::string resourceToReference) noexcept; void AddInput(std::string resourceToReference) noexcept; void AddGeneralInput (std::string resourceToReference) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + void AddExteriorDrawCalls(std::function&, uint32_t)> const& newDrawCall) noexcept; // Runtime functions void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; + void BindDescriptorInputDescriptorSets (Handle cmdBuffer, uint32_t frameIndex) const noexcept; void Init(SHResourceHub& resourceManager) noexcept; diff --git a/SHADE_Engine/src/Graphics/SHVkUtil.cpp b/SHADE_Engine/src/Graphics/SHVkUtil.cpp index 3a405e0d..040433cb 100644 --- a/SHADE_Engine/src/Graphics/SHVkUtil.cpp +++ b/SHADE_Engine/src/Graphics/SHVkUtil.cpp @@ -129,7 +129,7 @@ namespace SHADE // Otherwise just copy the data over else { - bufferHandle->MapWriteUnmap(src, size, 0, 0); + bufferHandle->WriteToMemory(src, size, 0, 0); } } else diff --git a/SHADE_Engine/src/Math/SHRay.cpp b/SHADE_Engine/src/Math/SHRay.cpp index 87f12b81..c4931aba 100644 --- a/SHADE_Engine/src/Math/SHRay.cpp +++ b/SHADE_Engine/src/Math/SHRay.cpp @@ -30,11 +30,17 @@ namespace SHADE , direction { dir } {} + SHRay::SHRay(const reactphysics3d::Ray rp3dRay) noexcept + : position { rp3dRay.point1 } + , direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) } + {} + + /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHRay::operator==(const SHRay& rhs) noexcept + bool SHRay::operator==(const SHRay& rhs) const noexcept { const XMVECTOR LHS_POS = XMLoadFloat3(&position); const XMVECTOR RHS_POS = XMLoadFloat3(&rhs.position); @@ -45,7 +51,7 @@ namespace SHADE return XMVector3Equal(LHS_POS, RHS_POS) && XMVector3NotEqual(LHS_DIR, RHS_DIR); } - bool SHRay::operator!=(const SHRay& rhs) noexcept + bool SHRay::operator!=(const SHRay& rhs) const noexcept { const XMVECTOR LHS_POS = XMLoadFloat3(&position); const XMVECTOR RHS_POS = XMLoadFloat3(&rhs.position); @@ -56,5 +62,16 @@ namespace SHADE return XMVector3NotEqual(LHS_POS, RHS_POS) || XMVector3NotEqual(LHS_DIR, RHS_DIR); } + SHRay::operator reactphysics3d::Ray() const noexcept + { + // We use 2km. Temp solution. + return reactphysics3d::Ray{ position, position + (direction * MAX_RAYCAST_DIST) }; + } + + SHRaycastResult::operator bool() const noexcept + { + return hit; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHRay.h b/SHADE_Engine/src/Math/SHRay.h index 29d55b16..18efc224 100644 --- a/SHADE_Engine/src/Math/SHRay.h +++ b/SHADE_Engine/src/Math/SHRay.h @@ -1,7 +1,7 @@ /**************************************************************************************** * \file SHRay.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Ray. + * \brief Interface for a Ray & Raycast Result * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -10,7 +10,7 @@ #pragma once -#include +#include // Project Headers #include "SH_API.h" @@ -29,6 +29,8 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ + static constexpr float MAX_RAYCAST_DIST = 2000.0f; // We use 2km as physics typically tends to lose accuracy beyond 2km. + SHVec3 position; SHVec3 direction; @@ -36,19 +38,46 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHRay() noexcept; - SHRay(const SHVec3& pos, const SHVec3& dir) noexcept; - SHRay(const SHRay& rhs) noexcept = default; - SHRay(SHRay&& rhs) noexcept = default; + SHRay () noexcept; + SHRay (const SHVec3& pos, const SHVec3& dir) noexcept; + SHRay (const reactphysics3d::Ray rp3dRay) noexcept; + + SHRay (const SHRay&) noexcept = default; + SHRay (SHRay&& ) noexcept = default; + ~SHRay() = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHRay& operator= (const SHRay& rhs) noexcept = default; - SHRay& operator= (SHRay&& rhs) noexcept = default; + SHRay& operator= (const SHRay&) noexcept = default; + SHRay& operator= (SHRay&&) noexcept = default; + + [[nodiscard]] bool operator==(const SHRay& rhs) const noexcept; + [[nodiscard]] bool operator!=(const SHRay& rhs) const noexcept; + + operator reactphysics3d::Ray() const noexcept; + }; + + struct SH_API SHRaycastResult + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + bool hit = false; + float distance = std::numeric_limits::infinity(); + float angle = 0.0f; + + SHVec3 position; + SHVec3 normal; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + operator bool() const noexcept; - [[nodiscard]] bool operator==(const SHRay& rhs) noexcept; - [[nodiscard]] bool operator!=(const SHRay& rhs) noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h index 6262b946..62882556 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h @@ -32,7 +32,6 @@ namespace SHADE class SH_API SHCollisionListener final : public rp3d::EventListener { public: - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp new file mode 100644 index 00000000..b687c6ca --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp @@ -0,0 +1,223 @@ +/**************************************************************************************** + * \file SHCollisionTagMatrix.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for Collision Tag Matrix for handling sets of Collision Tags. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include +#include + +// Primary Header +#include "SHCollisionTagMatrix.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionTag SHCollisionTagMatrix::collisionTags[SHCollisionTag::NUM_LAYERS]; + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const std::string& SHCollisionTagMatrix::GetTagName(int tagIndex) + { + if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + return collisionTags[tagIndex].GetName(); + } + + int SHCollisionTagMatrix::GetTagIndex(const std::string& tagName) noexcept + { + for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) + { + if (collisionTags[i].GetName() == tagName) + return i; + } + + SHLOGV_WARNING("Collision Tag {} cannot be found!", tagName) + return -1; + } + + SHCollisionTag* SHCollisionTagMatrix::GetTag(int tagIndex) + { + if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + return &collisionTags[tagIndex]; + } + + SHCollisionTag* SHCollisionTagMatrix::GetTag(const std::string& tagName) noexcept + { + for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) + { + if (collisionTags[i].GetName() == tagName) + return &collisionTags[i]; + } + + SHLOGV_WARNING("Collision Tag {} cannot be found!", tagName) + return nullptr; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionTagMatrix::SetTagName(const std::string& oldTagName, const std::string& newTagName) noexcept + { + for (auto& collisionTag : collisionTags) + { + if (collisionTag.GetName() != oldTagName) + continue; + + collisionTag.SetName(newTagName); + return; + } + + SHLOGV_WARNING("Collision tag {} cannot be found!", oldTagName) + } + + void SHCollisionTagMatrix::SetTag(const std::string& tagName, const SHCollisionTag& newTag) noexcept + { + for (auto& collisionTag : collisionTags) + { + if (collisionTag.GetName() != tagName) + continue; + + collisionTag = newTag; + return; + } + + SHLOGV_WARNING("Collision tag {} cannot be found!", tagName) + } + + void SHCollisionTagMatrix::SetTag(const std::string& tagName, uint16_t mask) noexcept + { + for (auto& collisionTag : collisionTags) + { + if (collisionTag.GetName() != tagName) + continue; + + collisionTag.SetMask(mask); + return; + } + + SHLOGV_WARNING("Collision tag {} cannot be found!", tagName) + } + + void SHCollisionTagMatrix::SetTagName(int tagIndex, const std::string& newTagName) + { + if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + collisionTags[tagIndex].SetName(newTagName); + } + + void SHCollisionTagMatrix::SetTag(int tagIndex, const SHCollisionTag& newTag) + { + if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + collisionTags[tagIndex] = newTag; + } + + void SHCollisionTagMatrix::SetTag(int tagIndex, uint16_t mask) + { + if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + collisionTags[tagIndex].SetMask(mask); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionTagMatrix::Init(const std::filesystem::path& tagNameFilePath) noexcept + { + /** + * I HATE FILE IO + * + * Each line in the file should be "indextag name". + * If the line fails to follow this format, use the default tag name (index + 1) + */ + + // Populate tag names with default + for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) + collisionTags[i].SetName(std::to_string(i + 1)); + + std::ifstream collisionTagNamesFile { tagNameFilePath }; + + if (!collisionTagNamesFile.is_open()) + { + SHLOG_ERROR("Failed to open file for Collision Tag Names! Default tag names used!") + return; + } + + std::stringstream ss; + std::string line; + + int linesRead = 0; + while (std::getline(collisionTagNamesFile, line)) + { + // Do not read anything beyond the first 16 lines + if (linesRead >= 16) + break; + + ss << line; + ++linesRead; + + // First element is index. + int tagIndex; + ss >> tagIndex; + + // Next element is name of the tag + std::string tagName; + ss >> tagName; + + // If no tag name read, use default. + if (tagName.empty()) + { + SHLOG_ERROR + ( + "Collision tag file line {} does not match the required format of 'indextag name'. Default tag used for index {}" + , linesRead + 1 + , tagIndex + ) + + // Use default + collisionTags[tagIndex].SetName(std::to_string(tagIndex + 1)); + continue; + } + + collisionTags[tagIndex].SetName(tagName); + + ss.clear(); + } + + collisionTagNamesFile.close(); + } + + void SHCollisionTagMatrix::Exit(const std::filesystem::path& tagNameFilePath) noexcept + { + std::ofstream collisionTagNamesFile { tagNameFilePath }; + + if (!collisionTagNamesFile.is_open()) + { + SHLOG_ERROR("Failed to open file for Collision Tag Names! Tag names not saved!") + return; + } + + for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) + collisionTagNamesFile << i << " " << collisionTags[i].GetName() << std::endl; + + collisionTagNamesFile.close(); + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h new file mode 100644 index 00000000..90018fe4 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h @@ -0,0 +1,67 @@ +/**************************************************************************************** + * \file SHCollisionTagMatrix.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for Collision Tag Matrix for handling sets of Collision Tags. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include + +// Project Includes +#include "SH_API.h" +#include "SHCollisionTags.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHCollisionTagMatrix + { + public: + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static const std::string& GetTagName (int tagIndex); + [[nodiscard]] static int GetTagIndex (const std::string& tagName) noexcept; + + [[nodiscard]] static SHCollisionTag* GetTag (int tagIndex); + [[nodiscard]] static SHCollisionTag* GetTag (const std::string& tagName) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + static void SetTagName (const std::string& oldTagName, const std::string& newTagName) noexcept; + static void SetTag (const std::string& tagName, const SHCollisionTag& newTag) noexcept; + static void SetTag (const std::string& tagName, uint16_t mask) noexcept; + + // Unsafe Setters: Can throw exceptions + + static void SetTagName (int tagIndex, const std::string& newTagName); + static void SetTag (int tagIndex, const SHCollisionTag& newTag); + static void SetTag (int tagIndex, uint16_t mask); + + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + static void Init (const std::filesystem::path& tagNameFilePath) noexcept; + static void Exit (const std::filesystem::path& tagNameFilePath) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static SHCollisionTag collisionTags[SHCollisionTag::NUM_LAYERS]; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp new file mode 100644 index 00000000..b1d2d5fc --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp @@ -0,0 +1,116 @@ +/**************************************************************************************** + * \file SHCollisionTags.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for Collision Tags for filtering collisions. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include +#include + +// Primary Header +#include "SHCollisionTags.h" +// Project Headers +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionTag::SHCollisionTag() noexcept + : mask { SHUtilities::ConvertEnum(Layer::ALL) } + {} + + SHCollisionTag::SHCollisionTag(uint16_t _mask) noexcept + : mask { _mask } + {} + + SHCollisionTag::SHCollisionTag(Layer layer) noexcept + : mask { SHUtilities::ConvertEnum(layer) } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollisionTag::operator==(const SHCollisionTag& rhs) const noexcept + { + return mask == rhs.mask; + } + + bool SHCollisionTag::operator!=(const SHCollisionTag& rhs) const noexcept + { + return mask != rhs.mask; + } + + SHCollisionTag::operator uint16_t() const noexcept + { + return mask; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + uint16_t SHCollisionTag::GetMask() const noexcept + { + return mask; + } + + const std::string& SHCollisionTag::GetName() const noexcept + { + return name; + } + + bool SHCollisionTag::GetLayerState(Layer layer) const noexcept + { + return (mask & SHUtilities::ConvertEnum(layer)) > 0; + } + + bool SHCollisionTag::GetLayerState(int layerIndex) const + { + if (layerIndex < 0 || layerIndex > NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + return (mask & (1U << layerIndex)) > 0; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionTag::SetMask(uint16_t newMask) noexcept + { + mask = newMask; + } + + void SHCollisionTag::SetName(const std::string_view& newName) noexcept + { + name = newName; + } + + void SHCollisionTag::SetLayerState(Layer layer, bool state) noexcept + { + const auto VALUE = SHUtilities::ConvertEnum(layer); + state ? mask |= VALUE : mask &= ~(VALUE); + } + + void SHCollisionTag::SetLayerState(int layerIndex, bool state) + { + if (layerIndex < 0 || layerIndex > NUM_LAYERS) + throw std::invalid_argument("Index out of range!"); + + const auto VALUE = 1U << layerIndex; + state ? mask |= (VALUE) : mask &= ~(VALUE); + } +} // namespace SHADE + +SHADE::SHCollisionTag::Layer operator|(SHADE::SHCollisionTag::Layer lhs, SHADE::SHCollisionTag::Layer rhs) noexcept +{ + return static_cast(SHADE::SHUtilities::ConvertEnum(lhs) | SHADE::SHUtilities::ConvertEnum(rhs)); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTags.h b/SHADE_Engine/src/Physics/Collision/SHCollisionTags.h new file mode 100644 index 00000000..9c7b4364 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionTags.h @@ -0,0 +1,112 @@ +/**************************************************************************************** + * \file SHCollisionTags.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for Collision Tags for filtering collisions. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include + +// Project Headers +#include "SH_API.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHCollisionTag + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Layer : uint16_t + { + _1 = 0x0001 + , _2 = 0x0002 + , _3 = 0x0004 + , _4 = 0x0008 + , _5 = 0x0010 + , _6 = 0x0020 + , _7 = 0x0040 + , _8 = 0x0080 + , _9 = 0x0100 + , _10 = 0x0200 + , _11 = 0x0400 + , _12 = 0x0800 + , _13 = 0x1000 + , _14 = 0x2000 + , _15 = 0x4000 + , _16 = 0x8000 + , ALL = 0xFFFF + }; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + static constexpr int NUM_LAYERS = 16; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionTag () noexcept; + SHCollisionTag (uint16_t mask) noexcept; + SHCollisionTag (Layer layer) noexcept; + + SHCollisionTag (const SHCollisionTag&) noexcept = default; + SHCollisionTag (SHCollisionTag&&) noexcept = default; + ~SHCollisionTag () = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionTag& operator=(const SHCollisionTag&) noexcept = default; + SHCollisionTag& operator=(SHCollisionTag&&) noexcept = default; + + [[nodiscard]] bool operator==(const SHCollisionTag& rhs) const noexcept; + [[nodiscard]] bool operator!=(const SHCollisionTag& rhs) const noexcept; + + operator uint16_t() const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] uint16_t GetMask () const noexcept; + [[nodiscard]] const std::string& GetName () const noexcept; + [[nodiscard]] bool GetLayerState (Layer layer) const noexcept; + [[nodiscard]] bool GetLayerState (int layerIndex) const; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetMask (uint16_t newMask) noexcept; + void SetName (const std::string_view& newName) noexcept; + void SetLayerState (Layer layer, bool state) noexcept; + void SetLayerState (int layerIndex, bool state); + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + uint16_t mask; + std::string name; + }; + +} // namespace SHADE + +SHADE::SHCollisionTag::Layer SH_API operator|(SHADE::SHCollisionTag::Layer lhs, SHADE::SHCollisionTag::Layer rhs) noexcept; + + diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycastResult.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycastResult.h new file mode 100644 index 00000000..cce01845 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycastResult.h @@ -0,0 +1,34 @@ +/**************************************************************************************** + * \file SHPhysicsRaycastResult.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Raycast Result + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +// Project Includes +#include "ECS_Base/SHECSMacros.h" +#include "Math/SHRay.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + struct SH_API SHPhysicsRaycastResult : public SHRaycastResult + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + EntityID entityHit = MAX_EID; + int shapeIndex = -1; + + }; +} diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp new file mode 100644 index 00000000..11b9fcab --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp @@ -0,0 +1,350 @@ +/**************************************************************************************** + * \file SHPhysicsRaycaster.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Raycaster. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHPhysicsRaycaster.h" + +/* + * TODO(DIREN): + * Once the physics engine has been rebuilt, this whole implementation should change + * and just call PhysicsWorld.Raycast etc. + * + * SHRaycastResult can be converted to a bool when necessary. + */ + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsRaycaster::SHPhysicsRaycaster() noexcept + : world { nullptr } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHPhysicsRaycaster::RaycastPairs& SHPhysicsRaycaster::GetRaycasts() const noexcept + { + return raycasts; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsRaycaster::SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept + { + objectManager = physicsObjectManager; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept + { + world = physicsWorld; + } + + void SHPhysicsRaycaster::ClearFrame() noexcept + { + raycasts.clear(); + } + + SHPhysicsRaycastResult SHPhysicsRaycaster::Raycast(const SHRay& ray, float distance) noexcept + { + // Reset temp + temp = SHPhysicsRaycastResult{}; + temp.distance = distance; + + if (!world) + { + SHLOG_ERROR("Physics world missing for raycasting!") + return temp; + } + + // If distance in infinity, cast to the default max distance of 2 km. + if (distance == std::numeric_limits::infinity()) + { + world->raycast(ray, this); + } + else + { + const SHVec3 END_POINT = ray.position + ray.direction * distance; + const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; + world->raycast(RP3D_RAY, this); + } + + // If a hit was found, populate temp info for return. + if (temp.hit) + { + temp.distance = SHVec3::Distance(ray.position, temp.position); + temp.angle = SHVec3::Angle(ray.position, temp.position); + } + + raycasts.emplace_back(ray, temp); + return temp; + } + + SHPhysicsRaycastResult SHPhysicsRaycaster::Linecast(const SHVec3& start, const SHVec3& end) noexcept + { + temp = SHPhysicsRaycastResult{}; + temp.distance = SHVec3::Distance(start, end); + + if (!world) + { + SHLOG_ERROR("Physics world missing for raycasting!") + return temp; + } + + const rp3d::Ray RP3D_RAY{ start, end }; + world->raycast(RP3D_RAY, this); + + if (temp.hit) + { + temp.distance = SHVec3::Distance(start, temp.position); + temp.angle = SHVec3::Angle(start, temp.position); + } + + raycasts.emplace_back(RP3D_RAY, temp); + return temp; + } + + SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept + { + SHPhysicsRaycastResult result; + result.distance = distance; + + // Get a valid physics object with at least 1 collider. + const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); + if (!PHYSICS_OBJECT) + return result; + + auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody(); + + // Data to populate + rp3d::RaycastInfo rp3dRaycastInfo; + bool hit = false; + + if (distance == std::numeric_limits::infinity()) + { + hit = rp3dBody->raycast(ray, rp3dRaycastInfo); + } + else + { + const SHVec3 END_POINT = ray.position + ray.direction * distance; + const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; + hit = rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo); + } + + if (hit) + { + result.hit = true; + result.position = rp3dRaycastInfo.worldPoint; + result.normal = rp3dRaycastInfo.worldPoint; + result.distance = SHVec3::Distance(ray.position, result.position); + result.angle = SHVec3::Angle(ray.position, result.position); + result.entityHit = eid; + result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity()); + } + + raycasts.emplace_back(ray, result); + return result; + } + + SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept + { + SHPhysicsRaycastResult result; + result.distance = distance; + + // Get a valid physics object with at least 1 collider. + const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); + if (!PHYSICS_OBJECT) + return result; + + // Boundary check for shape index + if (shapeIndex < 0 || shapeIndex >= static_cast(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders())) + { + SHLOGV_WARNING("Invalid collision shape index passed in") + return result; + } + + auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex); + + rp3d::RaycastInfo rp3dRaycastInfo; + bool hit = false; + if (distance == std::numeric_limits::infinity()) + { + hit = rp3dCollider->raycast(ray, rp3dRaycastInfo); + } + else + { + const SHVec3 END_POINT = ray.position + ray.direction * distance; + const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; + hit = rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo); + } + + if (hit) + { + result.hit = true; + result.position = rp3dRaycastInfo.worldPoint; + result.normal = rp3dRaycastInfo.worldPoint; + result.distance = SHVec3::Distance(ray.position, result.position); + result.angle = SHVec3::Angle(ray.position, result.position); + result.entityHit = eid; + result.shapeIndex = shapeIndex; + } + + raycasts.emplace_back(ray, result); + return result; + } + + SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept + { + SHPhysicsRaycastResult result; + result.distance = SHVec3::Distance(start, end); + + const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); + if (!PHYSICS_OBJECT) + return result; + + auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody(); + + rp3d::RaycastInfo rp3dRaycastInfo; + + const rp3d::Ray RP3D_RAY{ start, end }; + if (rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo)) + { + result.hit = true; + result.position = rp3dRaycastInfo.worldPoint; + result.normal = rp3dRaycastInfo.worldPoint; + result.distance = SHVec3::Distance(start, result.position); + result.angle = SHVec3::Angle(end, result.position); + result.entityHit = eid; + result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity()); + } + + raycasts.emplace_back(RP3D_RAY, result); + return result; + } + + SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept + { + SHPhysicsRaycastResult result; + result.distance = SHVec3::Distance(start, end); + + const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); + if (!PHYSICS_OBJECT) + return result; + + if (shapeIndex < 0 || shapeIndex >= static_cast(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders())) + { + SHLOGV_WARNING("Invalid collision shape index passed in") + return result; + } + + auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex); + + rp3d::RaycastInfo rp3dRaycastInfo; + + const rp3d::Ray RP3D_RAY{ start, end }; + if (rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo)) + { + result.hit = true; + result.position = rp3dRaycastInfo.worldPoint; + result.normal = rp3dRaycastInfo.worldPoint; + result.distance = SHVec3::Distance(start, result.position); + result.angle = SHVec3::Angle(end, result.position); + result.entityHit = eid; + result.shapeIndex = shapeIndex; + } + + raycasts.emplace_back(RP3D_RAY, result); + return result; + } + + rp3d::decimal SHPhysicsRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) + { + temp.hit = true; + temp.position = raycastInfo.worldPoint; + temp.normal = raycastInfo.worldNormal; + + if (!objectManager) + { + SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies") + return 0.0f; + } + + // Compare body IDs to find the matching physics object + const auto HIT_BODY_EID = raycastInfo.body->getEntity(); + + for (const auto& [entityID, physicsObject] : objectManager->GetPhysicsObjects()) + { + const auto RP3D_BODY = physicsObject.GetCollisionBody(); + + // Match rp3d bodies + if (RP3D_BODY->getEntity() != HIT_BODY_EID) + continue; + + temp.entityHit = entityID; + + // Find collider index + if (const int INDEX = findColliderIndex(RP3D_BODY, raycastInfo.collider->getEntity()); INDEX > -1) + { + temp.shapeIndex = INDEX; + break; + } + } + + return 0.0f; + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject* SHPhysicsRaycaster::validateColliderRaycast(EntityID eid) noexcept + { + if (!objectManager) + { + SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies") + return nullptr; + } + + auto* physicsObject = objectManager->GetPhysicsObject(eid); + if (!physicsObject || physicsObject->GetCollisionBody()->getNbColliders() == 0) + { + SHLOGV_WARNING("Cannot cast ray at an entity without colliders!") + return nullptr; + } + + return physicsObject; + } + + int SHPhysicsRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept + { + const int NUM_COLLISION_SHAPES = static_cast(rp3dBody->getNbColliders()); + for (int i = 0; i < NUM_COLLISION_SHAPES; ++i) + { + const auto COLLIDER_EID = rp3dBody->getCollider(i)->getEntity(); + if (COLLIDER_EID == rp3dColliderEID) + return i; + } + + return -1; + } + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h new file mode 100644 index 00000000..81165b56 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h @@ -0,0 +1,131 @@ +/**************************************************************************************** + * \file SHPhysicsRaycaster.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Raycaster. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include + +#include + +// Project Headers +#include "Math/SHRay.h" +#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" +#include "Physics/SHPhysicsWorld.h" +#include "SH_API.h" +#include "SHPhysicsRaycastResult.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHPhysicsRaycaster : public reactphysics3d::RaycastCallback + { + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using RaycastPair = std::pair; + using RaycastPairs = std::vector; + + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsRaycaster() noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const RaycastPairs& GetRaycasts() const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept; + void ClearFrame () noexcept; + + // TODO(Diren): Filtering, return all shades ray hits + + SHPhysicsRaycastResult Raycast + ( + const SHRay& ray + , float distance = std::numeric_limits::infinity() + ) noexcept; + + SHPhysicsRaycastResult Linecast + ( + const SHVec3& start + , const SHVec3& end + ) noexcept; + + SHPhysicsRaycastResult ColliderRaycast + ( + EntityID eid + , const SHRay& ray + , float distance = std::numeric_limits::infinity() + ) noexcept; + + SHPhysicsRaycastResult ColliderRaycast + ( + EntityID eid + , int shapeIndex + , const SHRay& ray + , float distance = std::numeric_limits::infinity() + ) noexcept; + + SHPhysicsRaycastResult ColliderLinecast + ( + EntityID eid + , const SHVec3& start + , const SHVec3& end + ) noexcept; + + SHPhysicsRaycastResult ColliderLinecast + ( + EntityID eid + , int shapeIndex + , const SHVec3& start + , const SHVec3& end + ) noexcept; + + rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + rp3d::PhysicsWorld* world; + SHPhysicsObjectManager* objectManager; // For + SHPhysicsRaycastResult temp; // Holds the temporary result after casting into the world + RaycastPairs raycasts; // Used for debug drawing + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsObject* validateColliderRaycast (EntityID eid) noexcept; + static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept; + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index 877d238f..135e7e42 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -80,6 +80,14 @@ namespace SHADE } system = physicsSystem; + + // Sync with transform if one already exists + if (auto* transformComponent = SHComponentManager::GetComponent_s(GetEID()); transformComponent) + { + position = transformComponent->GetWorldPosition(); + orientation = transformComponent->GetWorldOrientation(); + scale = transformComponent->GetWorldScale(); + } } void SHColliderComponent::OnDestroy() diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp index 14743845..c8a082a5 100644 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp @@ -16,6 +16,7 @@ #include "Math/Geometry/SHBox.h" #include "Math/Geometry/SHSphere.h" #include "Math/SHMathHelpers.h" +#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Reflection/SHReflectionMetadata.h" #include "SHColliderComponent.h" @@ -26,12 +27,13 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHCollisionShape::SHCollisionShape(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial) - : type { colliderType } - , entityID { eid } - , isTrigger { false } - , dirty { true } - , shape { nullptr } - , material { physicsMaterial } + : type { colliderType } + , entityID { eid } + , isTrigger { false } + , dirty { true } + , shape { nullptr } + , material { physicsMaterial } + , collisionTag { SHCollisionTagMatrix::GetTag(0) } { switch (type) { @@ -57,6 +59,8 @@ namespace SHADE , shape { nullptr } , material { rhs.material } , positionOffset { rhs.positionOffset } + , rotationOffset { rhs.rotationOffset } + , collisionTag { rhs.collisionTag } { CopyShape(rhs.shape); } @@ -69,6 +73,8 @@ namespace SHADE , shape { nullptr } , material { rhs.material } , positionOffset { rhs.positionOffset } + , rotationOffset { rhs.rotationOffset } + , collisionTag { rhs.collisionTag } { CopyShape(rhs.shape); } @@ -93,6 +99,8 @@ namespace SHADE dirty = true; material = rhs.material; positionOffset = rhs.positionOffset; + rotationOffset = rhs.rotationOffset; + collisionTag = rhs.collisionTag; delete shape; CopyShape(rhs.shape); @@ -108,6 +116,8 @@ namespace SHADE dirty = true; material = rhs.material; positionOffset = rhs.positionOffset; + rotationOffset = rhs.rotationOffset; + collisionTag = rhs.collisionTag; delete shape; CopyShape(rhs.shape); @@ -134,6 +144,11 @@ namespace SHADE return type; } + const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept + { + return *collisionTag; + } + float SHCollisionShape::GetFriction() const noexcept { return material.GetFriction(); @@ -240,6 +255,12 @@ namespace SHADE isTrigger = trigger; } + void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept + { + dirty = true; + collisionTag = newCollisionTag; + } + void SHCollisionShape::SetFriction(float friction) noexcept { dirty = true; diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h index 526428fd..597814a6 100644 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h @@ -17,6 +17,7 @@ #include "Math/Geometry/SHShape.h" #include "Math/SHQuaternion.h" #include "SHPhysicsMaterial.h" +#include "Physics/Collision/SHCollisionTags.h" namespace SHADE { @@ -74,6 +75,8 @@ namespace SHADE [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; + [[nodiscard]] float GetFriction () const noexcept; [[nodiscard]] float GetBounciness () const noexcept; [[nodiscard]] float GetDensity () const noexcept; @@ -92,6 +95,7 @@ namespace SHADE void SetBoundingSphere (float radius); void SetIsTrigger (bool isTrigger) noexcept; + void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; void SetFriction (float friction) noexcept; void SetBounciness (float bounciness) noexcept; void SetDensity (float density) noexcept; @@ -109,11 +113,15 @@ namespace SHADE EntityID entityID; // The entity this collider belongs to bool isTrigger; bool dirty; + SHShape* shape; SHPhysicsMaterial material; + SHVec3 positionOffset; SHVec3 rotationOffset; + SHCollisionTag* collisionTag; + /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index 28b6f842..4fddc892 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -322,25 +322,25 @@ namespace SHADE // dirtyFlags |= 1U << FLAG_POS; //} - void SHRigidBodyComponent::SetMass(float newMass) noexcept - { - static constexpr int FLAG_POS = 9; + //void SHRigidBodyComponent::SetMass(float newMass) noexcept + //{ + // static constexpr int FLAG_POS = 9; - if (newMass < 0.0f) - return; + // if (newMass < 0.0f) + // return; - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) - return; - } + // if (type != Type::DYNAMIC) + // { + // SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) + // return; + // } - dirtyFlags |= 1U << FLAG_POS; - mass = newMass; + // dirtyFlags |= 1U << FLAG_POS; + // mass = newMass; - // Turn off automass - flags &= ~(1U << FLAG_POS); - } + // // Turn off automass + // flags &= ~(1U << FLAG_POS); + //} void SHRigidBodyComponent::SetDrag(float newDrag) noexcept { @@ -411,6 +411,13 @@ namespace SHADE } system = physicsSystem; + + // Sync with transform if one already exists + if (auto* transformComponent = SHComponentManager::GetComponent_s(GetEID()); transformComponent) + { + position = transformComponent->GetWorldPosition(); + orientation = transformComponent->GetWorldOrientation(); + } } void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept @@ -489,7 +496,7 @@ RTTR_REGISTRATION registration::class_("RigidBody Component") .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) - .property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) + //.property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) .property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag ) .property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag ) .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled ) diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index d5204d94..532b3312 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -114,7 +114,7 @@ namespace SHADE void SetInterpolate (bool allowInterpolation) noexcept; //void SetAutoMass (bool autoMass) noexcept; - void SetMass (float newMass) noexcept; + //void SetMass (float newMass) noexcept; void SetDrag (float newDrag) noexcept; void SetAngularDrag (float newAngularDrag) noexcept; diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp index 0a0ff201..00f280e9 100644 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp @@ -94,7 +94,7 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - int SHPhysicsObject::AddCollisionShape(int index) const + int SHPhysicsObject::AddCollisionShape(int index) { // Get collider component auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); @@ -123,13 +123,19 @@ namespace SHADE default: break; } - rp3dBody->updateLocalCenterOfMassFromColliders(); - rp3dBody->updateLocalInertiaTensorFromColliders(); + if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC) + { + rp3dBody->updateMassPropertiesFromColliders(); + + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); + if (rigidBodyComponent) + rigidBodyComponent->mass = rp3dBody->getMass(); + } return index; } - void SHPhysicsObject::RemoveCollisionShape(int index) const + void SHPhysicsObject::RemoveCollisionShape(int index) { const int NUM_COLLIDERS = static_cast(rp3dBody->getNbColliders()); if (NUM_COLLIDERS == 0) @@ -140,6 +146,15 @@ namespace SHADE auto* collider = rp3dBody->getCollider(index); rp3dBody->removeCollider(collider); + + if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC) + { + rp3dBody->updateMassPropertiesFromColliders(); + + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); + if (rigidBodyComponent) + rigidBodyComponent->mass = rp3dBody->getMass(); + } } void SHPhysicsObject::RemoveAllCollisionShapes() const noexcept @@ -254,6 +269,8 @@ namespace SHADE } case 9: // Mass { + //rp3dBody->setMass(component.mass); + //if (component.GetAutoMass()) //{ // rp3dBody->updateMassPropertiesFromColliders(); @@ -261,9 +278,9 @@ namespace SHADE //} //else //{ - rp3dBody->setMass(component.mass); - rp3dBody->updateLocalCenterOfMassFromColliders(); - rp3dBody->updateLocalInertiaTensorFromColliders(); + // rp3dBody->setMass(component.mass); + // rp3dBody->updateLocalCenterOfMassFromColliders(); + // rp3dBody->updateLocalInertiaTensorFromColliders(); //} break; @@ -294,7 +311,7 @@ namespace SHADE if (!rp3dBody->isActive()) return; - const int NUM_SHAPES = static_cast(component.collisionShapes.size()); + const int NUM_SHAPES = static_cast(rp3dBody->getNbColliders()); for (int i = 0; i < NUM_SHAPES; ++i) { auto& collisionShape = component.collisionShapes[i]; @@ -309,7 +326,18 @@ namespace SHADE default: break; } - syncMaterial(i, collisionShape); + // Sync material + auto* rp3dCollider = rp3dBody->getCollider(i); + auto& rp3dMaterial = rp3dCollider->getMaterial(); + + rp3dMaterial.setFrictionCoefficient(collisionShape.GetFriction()); + rp3dMaterial.setBounciness(collisionShape.GetBounciness()); + rp3dMaterial.setMassDensity(collisionShape.GetDensity()); + + // Sync tags + const unsigned short MASK_BITS = collisionShape.GetCollisionTag(); + rp3dCollider->setCollisionCategoryBits(MASK_BITS); + rp3dCollider->setCollideWithMaskBits(MASK_BITS); collisionShape.dirty = false; } @@ -319,14 +347,6 @@ namespace SHADE /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsObject::syncMaterial(int colliderIndex, SHCollisionShape& collisionShape) const noexcept - { - auto& rp3dMaterial = rp3dBody->getCollider(colliderIndex)->getMaterial(); - rp3dMaterial.setFrictionCoefficient(collisionShape.GetFriction()); - rp3dMaterial.setBounciness(collisionShape.GetBounciness()); - rp3dMaterial.setMassDensity(collisionShape.GetDensity()); - } - void SHPhysicsObject::addBoxShape(SHCollisionShape& boxShape) const noexcept { const rp3d::Transform OFFSETS diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h index 5a0e62ac..818e5471 100644 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h @@ -71,8 +71,8 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - int AddCollisionShape (int index) const; - void RemoveCollisionShape (int index) const; + int AddCollisionShape (int index); + void RemoveCollisionShape (int index); void RemoveAllCollisionShapes () const noexcept; void SyncRigidBody (SHRigidBodyComponent& component) const noexcept; @@ -96,16 +96,14 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void syncMaterial (int colliderIndex, SHCollisionShape& collisionShape) const noexcept; - // Box Shapes - void addBoxShape (SHCollisionShape& boxShape) const noexcept; - void syncBoxShape (int index, SHCollisionShape& boxShape) const noexcept; + void addBoxShape (SHCollisionShape& boxShape) const noexcept; + void syncBoxShape (int index, SHCollisionShape& boxShape) const noexcept; // Sphere Shapes - void addSphereShape (SHCollisionShape& sphereShape) const noexcept; - void syncSphereShape (int index, SHCollisionShape& sphereShape) const noexcept; + void addSphereShape (SHCollisionShape& sphereShape) const noexcept; + void syncSphereShape (int index, SHCollisionShape& sphereShape) const noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp index ffd10e0c..389983c3 100644 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp @@ -23,11 +23,10 @@ namespace SHADE /* Static Data Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[2][3] + SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[3][2] { - addRigidBody , addCollider - , removeRigidBody , removeCollider - , addCollisionShape , removeCollisionShape + addRigidBody , addCollider , addCollisionShape + , removeRigidBody , removeCollider , removeCollisionShape }; /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h index 641fd9df..f41c62ad 100644 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h @@ -150,7 +150,7 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - static CommandFunctionPtr componentFunc[2][3]; // 2 commands, 3 components + static CommandFunctionPtr componentFunc[3][2]; // 3 components, 2 commands rp3d::PhysicsCommon* factory = nullptr; rp3d::PhysicsWorld* world = nullptr; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 7ccfb225..3c80883c 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -15,7 +15,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" -#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" +#include "Editor/SHEditor.h" #include "Scene/SHSceneManager.h" namespace SHADE @@ -26,11 +26,12 @@ namespace SHADE const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[NUM_FLAGS] = { - SHPhysicsDebugDrawSystem::drawColliders - , SHPhysicsDebugDrawSystem::drawColliderAABBs - , SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs - , SHPhysicsDebugDrawSystem::drawContactPoints - , SHPhysicsDebugDrawSystem::drawContactNormals + drawColliders + , drawColliderAABBs + , drawBroadPhaseAABBs + , drawContactPoints + , drawContactNormals + , drawRaycasts }; SHVec3 SHPhysicsDebugDrawSystem::boxVertices[NUM_BOX_VERTICES]; @@ -42,13 +43,13 @@ namespace SHADE SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept : debugDrawFlags { 0 } , physicsSystem { nullptr } - , rp3dDebugRenderer { nullptr } { debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER)] = SHColour::GREEN; debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB)] = SHColour::YELLOW; debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB)] = SHColour::CYAN; debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS)] = SHColour::RED; debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS)] = SHColour::RED; + debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::RAYCASTS)] = SHColour::ORANGE; } SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine() @@ -111,19 +112,41 @@ namespace SHADE { auto* system = reinterpret_cast(GetSystem()); + auto* debugDrawSystem = SHSystemManager::GetSystem(); + if (debugDrawSystem == nullptr) + { + SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") + return; + } + + rp3d::DebugRenderer* rp3dRenderer = nullptr; + #ifdef SHEDITOR + const auto* EDITOR = SHSystemManager::GetSystem(); + if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) + { + rp3dRenderer = &system->physicsSystem->worldState.world->getDebugRenderer(); + rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, false); + rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, false); + } + #endif + for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i) { const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0; if (DRAW) - drawFunctions[i](system->rp3dDebugRenderer); + drawFunctions[i](debugDrawSystem, rp3dRenderer); } + + // Automatically clear the container of raycasts despite debug drawing state + // TODO(Diren): Move this somewhere else + system->physicsSystem->raycaster.ClearFrame(); } /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsDebugDrawSystem::drawColliders(rp3d::DebugRenderer* debugRenderer) noexcept + void SHPhysicsDebugDrawSystem::drawColliders(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept { const auto& COLLIDER_SET = SHComponentManager::GetDense(); for (const auto& COLLIDER : COLLIDER_SET) @@ -136,34 +159,84 @@ namespace SHADE { switch (collisionShape.GetType()) { - case SHCollisionShape::Type::BOX: debugDrawBox(COLLIDER, collisionShape); break; - case SHCollisionShape::Type::SPHERE: debugDrawSphere(COLLIDER, collisionShape); break; + case SHCollisionShape::Type::BOX: debugDrawBox(debugRenderer, COLLIDER, collisionShape); break; + case SHCollisionShape::Type::SPHERE: debugDrawSphere(debugRenderer, COLLIDER, collisionShape); break; default: break; } } } } - void SHPhysicsDebugDrawSystem::drawColliderAABBs(rp3d::DebugRenderer* debugRenderer) noexcept + void SHPhysicsDebugDrawSystem::drawColliderAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept { } - void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(rp3d::DebugRenderer* debugRenderer) noexcept + void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept { } - void SHPhysicsDebugDrawSystem::drawContactPoints(rp3d::DebugRenderer* debugRenderer) noexcept + void SHPhysicsDebugDrawSystem::drawContactPoints(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept { - + #ifdef SHEDITOR + const auto* EDITOR = SHSystemManager::GetSystem(); + if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) + { + rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true); + const int NUM_TRIS = static_cast(rp3dRenderer->getNbTriangles()); + if (NUM_TRIS == 0) + return; + + const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray(); + for (int i = 0; i < NUM_TRIS; ++i) + debugRenderer->DrawTri(SHColour::RED, TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3); + } + #endif } - void SHPhysicsDebugDrawSystem::drawContactNormals(rp3d::DebugRenderer* debugRenderer) noexcept + void SHPhysicsDebugDrawSystem::drawContactNormals(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept { - + #ifdef SHEDITOR + const auto* EDITOR = SHSystemManager::GetSystem(); + if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) + { + rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true); + const int NUM_LINES = static_cast(rp3dRenderer->getNbLines()); + if (NUM_LINES == 0) + return; + + const auto& LINE_ARRAY = rp3dRenderer->getLinesArray(); + for (int i = 0; i < NUM_LINES; ++i) + debugRenderer->DrawLine(SHColour::RED, LINE_ARRAY[i].point1, LINE_ARRAY[i].point2); + } + #endif } + void SHPhysicsDebugDrawSystem::drawRaycasts(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (!physicsSystem) + { + SHLOG_ERROR("Unable to retrieve physics system for debug drawing raycasts!") + return; + } + + const SHColour& RAY_COLOUR = SHColour::ORANGE; + + // Draw all raycast pairs + for (const auto& [ray, raycastResult] : physicsSystem->raycaster.GetRaycasts()) + { + // If infinity, it is an infinite raycast. If not, render the distance in raycastResult. + // Ignore the hit variable as it will always correspond to the length of the raycast, hit or miss. + const float RENDER_DIST = raycastResult.distance == std::numeric_limits::infinity() ? SHRay::MAX_RAYCAST_DIST : raycastResult.distance; + const SHVec3 END_POS = ray.position + (ray.direction * RENDER_DIST); + + debugRenderer->DrawLine(RAY_COLOUR, ray.position, END_POS); + } + } + + void SHPhysicsDebugDrawSystem::generateBox() noexcept { boxVertices[0] = { 0.5f, 0.5f, -0.5f }; // TOP_RIGHT_BACK @@ -176,15 +249,8 @@ namespace SHADE boxVertices[7] = { -0.5f, -0.5f, 0.5f }; // BTM_LEFT_FRONT } - void SHPhysicsDebugDrawSystem::debugDrawBox(const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept + void SHPhysicsDebugDrawSystem::debugDrawBox(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept { - auto* debugDrawSystem = SHSystemManager::GetSystem(); - if (debugDrawSystem == nullptr) - { - SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") - return; - } - auto* BOX = reinterpret_cast(collisionShape.GetShape()); // Calculate final position & orientation @@ -211,27 +277,20 @@ namespace SHADE transformedVertices[IDX2] = SHVec3::Transform(boxVertices[IDX2], FINAL_TRS); // Draw 4 line to connect the quads - debugDrawSystem->DrawLine(COLLIDER_COLOUR, transformedVertices[IDX1], transformedVertices[IDX2]); + debugRenderer->DrawLine(COLLIDER_COLOUR, transformedVertices[IDX1], transformedVertices[IDX2]); } // A, B, C, D std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] }; - debugDrawSystem->DrawPoly(COLLIDER_COLOUR, backQuad.begin(), backQuad.end()); + debugRenderer->DrawPoly(COLLIDER_COLOUR, backQuad.begin(), backQuad.end()); // E, F, G, H std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] }; - debugDrawSystem->DrawPoly(COLLIDER_COLOUR, frontQuad.begin(), frontQuad.end()); + debugRenderer->DrawPoly(COLLIDER_COLOUR, frontQuad.begin(), frontQuad.end()); } - void SHPhysicsDebugDrawSystem::debugDrawSphere(const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept + void SHPhysicsDebugDrawSystem::debugDrawSphere(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept { - auto* debugDrawSystem = SHSystemManager::GetSystem(); - if (debugDrawSystem == nullptr) - { - SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") - return; - } - auto* SPHERE = reinterpret_cast(collisionShape.GetShape()); const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN; @@ -240,7 +299,7 @@ namespace SHADE const SHQuaternion FINAL_ROT = colliderComponent.GetOrientation() * SHQuaternion::FromEuler(collisionShape.GetRotationOffset()); const SHMatrix TR = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(colliderComponent.GetPosition()); - debugDrawSystem->DrawSphere(COLLIDER_COLOUR, SHVec3::Transform(collisionShape.GetPositionOffset(), TR), SPHERE->GetWorldRadius()); + debugRenderer->DrawSphere(COLLIDER_COLOUR, SHVec3::Transform(collisionShape.GetPositionOffset(), TR), SPHERE->GetWorldRadius()); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index 149ed6c1..dc703092 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -14,6 +14,7 @@ // Project Headers #include "ECS_Base/System/SHSystemRoutine.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Math/SHColour.h" #include "SHPhysicsSystem.h" #include "Tools/Utilities/SHUtilities.h" @@ -38,6 +39,7 @@ namespace SHADE , BROAD_PHASE_AABB , CONTACT_POINTS , CONTACT_NORMALS + , RAYCASTS , NUM_FLAGS }; @@ -91,7 +93,7 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using DebugDrawFunction = void(*)(rp3d::DebugRenderer*) noexcept; + using DebugDrawFunction = void(*)(SHDebugDrawSystem*, rp3d::DebugRenderer*) noexcept; /*---------------------------------------------------------------------------------*/ /* Data Members */ @@ -108,7 +110,6 @@ namespace SHADE uint8_t debugDrawFlags; SHPhysicsSystem* physicsSystem; - rp3d::DebugRenderer* rp3dDebugRenderer; SHColour debugColours[NUM_FLAGS]; /*---------------------------------------------------------------------------------*/ @@ -117,11 +118,12 @@ namespace SHADE // Generic Draw Functions - static void drawColliders (rp3d::DebugRenderer* debugRenderer) noexcept; - static void drawColliderAABBs (rp3d::DebugRenderer* debugRenderer) noexcept; - static void drawBroadPhaseAABBs (rp3d::DebugRenderer* debugRenderer) noexcept; - static void drawContactPoints (rp3d::DebugRenderer* debugRenderer) noexcept; - static void drawContactNormals (rp3d::DebugRenderer* debugRenderer) noexcept; + static void drawColliders (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; + static void drawColliderAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; + static void drawBroadPhaseAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; + static void drawContactPoints (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; + static void drawContactNormals (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; + static void drawRaycasts (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; // Shape Generation Functions @@ -129,8 +131,8 @@ namespace SHADE // Shape Draw Functions - static void debugDrawBox (const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; - static void debugDrawSphere (const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; + static void debugDrawBox (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; + static void debugDrawSphere (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 50590e04..89be2614 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -14,18 +14,16 @@ #include "SHPhysicsSystem.h" // Project Headers +#include "Assets/SHAssetMacros.h" #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" +#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/SHPhysicsEvents.h" #include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" -/*-------------------------------------------------------------------------------------*/ -/* Local Helper Functions */ -/*-------------------------------------------------------------------------------------*/ - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -94,6 +92,18 @@ namespace SHADE void SHPhysicsSystem::Init() { + // Initialise collision tags + std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; + defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); + SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath); + + // Link Physics Object Manager with System & Raycaster + objectManager.SetFactory(factory); + raycaster.SetObjectManager(&objectManager); + + // Link Collision Listener with System + collisionListener.BindToSystem(this); + // Subscribe to component events const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::addPhysicsComponent) }; const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(ADD_COMPONENT_RECEIVER); @@ -115,16 +125,66 @@ namespace SHADE SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, ON_STOP_RECEIVER_PTR); #endif - // Link Physics Object Manager with System - objectManager.SetFactory(factory); - - // Link Collision Listener with System - collisionListener.BindToSystem(this); + } void SHPhysicsSystem::Exit() { worldState.DestroyWorld(factory); + + // Write collision tag names to file + std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; + defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); + SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath); + } + + void SHPhysicsSystem::BuildScene(SHSceneGraph& sceneGraph) + { + static const auto BUILD_NEW_SCENE_PHYSICS_OBJECT = [&](SHSceneNode* node) + { + const EntityID EID = node->GetEntityID(); + + if (SHComponentManager::HasComponent(EID)) + objectManager.AddRigidBody(EID); + + if (SHComponentManager::HasComponent(EID)) + objectManager.AddCollider(EID); + }; + + //////////////////////////////// + + // Destroy an existing world + if (worldState.world != nullptr) + { + objectManager.RemoveAllObjects(); + objectManager.SetWorld(nullptr); + + collisionListener.ClearContainers(); + raycaster.ClearFrame(); + + worldState.DestroyWorld(factory); + } + + worldState.CreateWorld(factory); + #ifdef _PUBLISH + worldState.world->setIsDebugRenderingEnabled(false); + #else + worldState.world->setIsDebugRenderingEnabled(true); + #endif + + // Link Collision Listener & Raycaster + collisionListener.BindToWorld(worldState.world); + raycaster.BindToWorld(worldState.world); + + // Link with object manager & create all physics objects + objectManager.SetWorld(worldState.world); + + // When building a scene, clear the object manager command queue and build scene objects again. + // This is done to avoid duplicate adds. + while (!objectManager.commandQueue.empty()) + objectManager.commandQueue.pop(); + + sceneGraph.Traverse(BUILD_NEW_SCENE_PHYSICS_OBJECT); } void SHPhysicsSystem::ForceUpdate() @@ -183,6 +243,35 @@ namespace SHADE } } + SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance) noexcept + { + return raycaster.Raycast(ray, distance); + } + + SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end) noexcept + { + return raycaster.Linecast(start, end); + } + + SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept + { + return raycaster.ColliderRaycast(eid, ray, distance); + } + + SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept + { + return raycaster.ColliderRaycast(eid, shapeIndex, ray, distance); + } + + SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept + { + return raycaster.ColliderLinecast(eid, start, end); + } + + SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept + { + return raycaster.ColliderLinecast(eid, shapeIndex, start, end); + } void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex) { @@ -190,10 +279,13 @@ namespace SHADE { objectManager.AddCollisionShape(entityID, index); + auto* colliderComponent = SHComponentManager::GetComponent(entityID); + auto& collisionShape = colliderComponent->GetCollisionShape(index); + const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA { .entityID = entityID - , .colliderType = SHComponentManager::GetComponent(entityID)->GetCollisionShape(index).GetType() + , .colliderType = collisionShape.GetType() , .colliderIndex = index }; @@ -325,16 +417,25 @@ namespace SHADE //////////////////////////////// // Create physics world - worldState.CreateWorld(factory); + if (worldState.world != nullptr) + return onPlayEvent->handle; - // Link Collision Listener + worldState.CreateWorld(factory); + #ifdef _PUBLISH + worldState.world->setIsDebugRenderingEnabled(false); + #else + worldState.world->setIsDebugRenderingEnabled(true); + #endif + + // Link Collision Listener & Raycaster collisionListener.BindToWorld(worldState.world); + raycaster.BindToWorld(worldState.world); // Link with object manager & create all physics objects objectManager.SetWorld(worldState.world); - const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); - SCENE_GRAPH.Traverse(BUILD_PHYSICS_OBJECT); + // Build scene + SHSceneManager::GetCurrentSceneGraph().Traverse(BUILD_PHYSICS_OBJECT); return onPlayEvent->handle; } @@ -348,11 +449,11 @@ namespace SHADE // Clear all collision info // Collision listener is automatically unbound when world is destroyed collisionListener.ClearContainers(); + raycaster.ClearFrame(); // Destroy the world worldState.DestroyWorld(factory); return onStopEvent->handle; } - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index 9638e05c..f7340d31 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -21,13 +21,13 @@ #include "ECS_Base/System/SHFixedSystemRoutine.h" #include "Math/Transform/SHTransformComponent.h" - #include "Physics/Collision/SHCollisionListener.h" +#include "Physics/Collision/SHPhysicsRaycaster.h" #include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/PhysicsObject//SHPhysicsObjectManager.h" +#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" #include "Physics/SHPhysicsWorld.h" - +#include "Scene/SHSceneGraph.h" namespace SHADE { @@ -74,10 +74,96 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void Init () override; - void Exit () override; + void Init () override; + void Exit () override; - void ForceUpdate (); + void BuildScene (SHSceneGraph& sceneGraph); + void ForceUpdate (); + + + /** + * @brief Casts a ray into the world. + * @param ray The ray to cast. + * @param distance The distance to cast the ray. Defaults to infinity. + * @return The result of the raycast. + */ + SHPhysicsRaycastResult Raycast + ( + const SHRay& ray + , float distance = std::numeric_limits::infinity() + ) noexcept; + + /** + * @brief Casts a bounded ray into the world. + * @param start The starting point of the ray. + * @param end The end point of the ray. + * @return The result of the raycast. + */ + SHPhysicsRaycastResult Linecast + ( + const SHVec3& start + , const SHVec3& end + ) noexcept; + + /** + * @brief Casts a ray at a body with colliders. + * @param eid The entity to cast to. + * @param ray The ray to cast. + * @param distance The distance to cast the ray. Defaults to infinity. + * @return The result of the raycast. + */ + SHPhysicsRaycastResult ColliderRaycast + ( + EntityID eid + , const SHRay& ray + , float distance = std::numeric_limits::infinity() + ) noexcept; + + /** + * @brief Casts a ray at a collider. + * @param eid The entity to cast to. + * @param shapeIndex The index of the collision shape. + * @param ray The ray to cast. + * @param distance The distance to cast the ray. Defaults to infinity. + * @return The result of the raycast. + */ + SHPhysicsRaycastResult ColliderRaycast + ( + EntityID eid + , int shapeIndex + , const SHRay& ray + , float distance = std::numeric_limits::infinity() + ) noexcept; + + /** + * @brief Casts a bounded ray at a body with colliders. + * @param eid + * @param start + * @param end + * @return The result of the raycast. + */ + SHPhysicsRaycastResult ColliderLinecast + ( + EntityID eid + , const SHVec3& start + , const SHVec3& end + ) noexcept; + + /** + * @brief + * @param eid + * @param shapeIndex + * @param start + * @param end + * @return The result of the raycast. + */ + SHPhysicsRaycastResult ColliderLinecast + ( + EntityID eid + , int shapeIndex + , const SHVec3& start + , const SHVec3& end + ) noexcept; // Specific Handling for Collision Shapes as they are not under the Component System. // This is done as events need to be sent out. @@ -190,16 +276,17 @@ namespace SHADE SHPhysicsWorldState worldState; SHPhysicsObjectManager objectManager; SHCollisionListener collisionListener; + SHPhysicsRaycaster raycaster; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept; - SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept; - - SHEventHandle onPlay (SHEventPtr onPlayEvent); - SHEventHandle onStop (SHEventPtr onStopEvent); + SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept; + SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept; + SHEventHandle onPlay (SHEventPtr onPlayEvent); + SHEventHandle onStop (SHEventPtr onStopEvent); + SHEventHandle buildScene (SHEventPtr onSceneChangeEvent); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index b142d54c..a028ffb5 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -33,7 +33,7 @@ namespace SHADE return phySystem->GetAllCollisionInfo(); } - SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead."); + SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); return emptyVec; } const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept @@ -46,7 +46,7 @@ namespace SHADE return phySystem->GetAllTriggerInfo(); } - SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead."); + SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); return emptyVec; } @@ -58,7 +58,79 @@ namespace SHADE return phySystem->GetFixedUpdateRate(); } - SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get fixed delta time. 0.0 returned instead."); + SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); return 0.0; } + + SHPhysicsRaycastResult SHPhysicsSystemInterface::Raycast(const SHRay& ray, float distance) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + { + return physicsSystem->Raycast(ray, distance); + } + + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; + } + + SHPhysicsRaycastResult SHPhysicsSystemInterface::Linecast(const SHVec3& start, const SHVec3& end) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + { + return physicsSystem->Linecast(start, end); + } + + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; + } + + SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + { + return physicsSystem->ColliderRaycast(eid, ray, distance); + } + + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; + } + + SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + { + return physicsSystem->ColliderRaycast(eid, shapeIndex, ray, distance); + } + + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; + } + + SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + { + return physicsSystem->ColliderLinecast(eid, start, end); + } + + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; + } + + SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + { + return physicsSystem->ColliderLinecast(eid, shapeIndex, start, end); + } + + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; + } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index bdd04686..0065aee3 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -14,12 +14,21 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" + + namespace SHADE { /*-----------------------------------------------------------------------------------*/ /* Forward Declarations */ /*-----------------------------------------------------------------------------------*/ - class SHCollisionInfo; + + class SHCollisionInfo; + class SHVec3; + struct SHRay; + struct SHPhysicsRaycastResult; + /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -39,8 +48,16 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo() noexcept; - [[nodiscard]] static double GetFixedDT() noexcept; + + [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; + [[nodiscard]] static double GetFixedDT () noexcept; + + [[nodiscard]] static SHPhysicsRaycastResult Raycast (const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; + [[nodiscard]] static SHPhysicsRaycastResult Linecast (const SHVec3& start, const SHVec3& end) noexcept; + [[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; + [[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, int shapeIndex, const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; + [[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, const SHVec3& start, const SHVec3& end) noexcept; + [[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept; }; } diff --git a/SHADE_Engine/src/Resource/SHResourceManager.cpp b/SHADE_Engine/src/Resource/SHResourceManager.cpp index 077835f5..5cb93bb0 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.cpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.cpp @@ -25,7 +25,8 @@ namespace SHADE std::unordered_map> SHResourceManager::typedFreeFuncMap; std::vector SHResourceManager::loadedAssetData; bool SHResourceManager::textureChanged = false; - bool SHResourceManager::meshChanged = false; + bool SHResourceManager::meshChanged = false; + bool SHResourceManager::fontChanged = false; /*-----------------------------------------------------------------------------------*/ /* Function Definitions */ @@ -76,6 +77,11 @@ namespace SHADE gfxSystem->BuildTextures(); textureChanged = false; } + if (fontChanged) + { + gfxSystem->BuildFonts(); + fontChanged = false; + } // Free CPU Resources for (auto assetId : loadedAssetData) diff --git a/SHADE_Engine/src/Resource/SHResourceManager.h b/SHADE_Engine/src/Resource/SHResourceManager.h index dae20f99..6afdf2b0 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.h +++ b/SHADE_Engine/src/Resource/SHResourceManager.h @@ -26,6 +26,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Assets/Asset Types/SHMaterialAsset.h" +#include "Graphics/MiddleEnd/TextRendering/SHFont.h" namespace SHADE { @@ -47,8 +48,8 @@ namespace SHADE template<> struct SHResourceLoader { using AssetType = SHShaderAsset; }; template<> struct SHResourceLoader { using AssetType = SHMaterialAsset; }; template<> struct SHResourceLoader { using AssetType = SHMaterialSpec; }; - - /// + template<> struct SHResourceLoader { using AssetType = SHFontAsset; }; +/// /// Static class responsible for loading and caching runtime resources from their /// serialised Asset IDs. /// @@ -178,6 +179,7 @@ namespace SHADE // Dirty Flags static bool meshChanged; static bool textureChanged; + static bool fontChanged; /*---------------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp index d0488e66..51ee356a 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.hpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -39,6 +39,7 @@ namespace SHADE !std::is_same_v && !std::is_same_v && !std::is_same_v && + !std::is_same_v && !std::is_same_v ) { @@ -337,5 +338,12 @@ namespace SHADE return matHandle; } + else if constexpr (std::is_same_v) + { + loadedAssetData.emplace_back(assetId); + fontChanged = true; + + return gfxSystem->AddFont(assetData); + } } } diff --git a/SHADE_Engine/src/Scene/SHSceneGraphEvents.h b/SHADE_Engine/src/Scene/SHSceneEvents.h similarity index 72% rename from SHADE_Engine/src/Scene/SHSceneGraphEvents.h rename to SHADE_Engine/src/Scene/SHSceneEvents.h index ccdf06be..c0d7dbc1 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraphEvents.h +++ b/SHADE_Engine/src/Scene/SHSceneEvents.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHSceneGraphEvents.h + * \file SHSceneEvents.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for Scene Graph Events. + * \brief Interface for Scene Events. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -21,21 +21,21 @@ namespace SHADE struct SHSceneGraphChangeParentEvent { - SHSceneNode* node; - SHSceneNode* oldParent; - SHSceneNode* newParent; + SHSceneNode* node = nullptr; + SHSceneNode* oldParent = nullptr; + SHSceneNode* newParent = nullptr; }; struct SHSceneGraphAddChildEvent { - SHSceneNode* parent; - SHSceneNode* childAdded; + SHSceneNode* parent = nullptr; + SHSceneNode* childAdded = nullptr; }; struct SHSceneGraphRemoveChildEvent { - SHSceneNode* parent; - SHSceneNode* childRemoved; + SHSceneNode* parent = nullptr; + SHSceneNode* childRemoved = nullptr; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index 5747be7b..37d0e063 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -16,7 +16,7 @@ #include "ECS_Base/Entity/SHEntity.h" #include "SH_API.h" #include "SHSceneNode.h" -#include "SHSceneGraphEvents.h" +#include "SHSceneEvents.h" namespace SHADE { diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index be9c7755..110aaea6 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -85,7 +85,6 @@ namespace SHADE currentScene->Load(); currentScene->Init(); } - } else // restarting scene { diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 84b50373..90121994 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -27,7 +27,7 @@ of DigiPen Institute of Technology is prohibited. #include "Events/SHEventManager.hpp" #include "Physics/System/SHPhysicsSystem.h" #include "Physics/SHPhysicsEvents.h" -#include "Scene/SHSceneGraphEvents.h" +#include "Scene/SHSceneEvents.h" #include "Assets/SHAssetMacros.h" diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 3ed96d7d..be7c9cf0 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -211,6 +211,7 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddConvComponentToComponentNode(components, eid); + AddConvComponentToComponentNode(components, eid); node[ComponentsNode] = components; @@ -262,6 +263,7 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); return componentIDList; } @@ -338,6 +340,7 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index d66a7506..023f0817 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -12,6 +12,9 @@ #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "SHSerializationTools.h" #include "Physics/Interface/SHColliderComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHFont.h" + namespace YAML { using namespace SHADE; @@ -113,6 +116,7 @@ namespace YAML static constexpr const char* Bounciness = "Bounciness"; static constexpr const char* Density = "Density"; static constexpr const char* PositionOffset = "Position Offset"; + static constexpr const char* RotationOffset = "Rotation Offset"; static Node encode(SHCollisionShape& rhs) { @@ -148,6 +152,7 @@ namespace YAML node[Bounciness] = rhs.GetBounciness(); node[Density] = rhs.GetDensity(); node[PositionOffset] = rhs.GetPositionOffset(); + node[RotationOffset] = rhs.GetRotationOffset(); return node; } @@ -188,6 +193,8 @@ namespace YAML rhs.SetDensity(node[Density].as()); if (node[PositionOffset].IsDefined()) rhs.SetPositionOffset(node[PositionOffset].as()); + if (node[RotationOffset].IsDefined()) + rhs.SetRotationOffset(node[RotationOffset].as()); return true; } @@ -322,4 +329,45 @@ namespace YAML return true; } }; + + template<> + struct convert + { + static constexpr std::string_view TEXT_YAML_TAG = "Text"; + static constexpr std::string_view FONT_YAML_TAG = "Font"; + + static YAML::Node encode(SHTextRenderableComponent const& rhs) + { + YAML::Node node; + node[TEXT_YAML_TAG.data()] = rhs.GetText(); + auto font = rhs.GetFont(); + if (font) + { + node[FONT_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetFont()).value_or(0); + } + else + { + node[FONT_YAML_TAG.data()] = 0; + } + return node; + } + static bool decode(YAML::Node const& node, SHTextRenderableComponent& rhs) + { + if (node[TEXT_YAML_TAG.data()].IsDefined()) + { + rhs.SetText(node[TEXT_YAML_TAG.data()].as()); + } + if (node[FONT_YAML_TAG.data()].IsDefined()) + { + + // Temporarily, use default material + auto gfxSystem = SHSystemManager::GetSystem(); + if (!gfxSystem) + return false; + + rhs.SetFont(SHResourceManager::LoadOrGet(node[TEXT_YAML_TAG.data()].as())); + } + return true; + } + }; } diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua index 2384cae8..463e80b8 100644 --- a/SHADE_Managed/premake5.lua +++ b/SHADE_Managed/premake5.lua @@ -33,6 +33,8 @@ project "SHADE_Managed" "%{IncludeDir.imgui}", "%{IncludeDir.imguizmo}", "%{IncludeDir.imnodes}", + "%{IncludeDir.msdf_atlas_gen}", + "%{IncludeDir.msdfgen}", "%{IncludeDir.yamlcpp}", "%{IncludeDir.SDL}\\include", "%{IncludeDir.RTTR}/include", @@ -53,6 +55,8 @@ project "SHADE_Managed" links { "yaml-cpp", + "msdfgen", + "msdf-atlas-gen", "imgui", "SDL2.lib", "SDL2main.lib", @@ -62,7 +66,11 @@ project "SHADE_Managed" disablewarnings { - "4251" + "4251", + "4633", + "4634", + "4635", + "4638" } defines @@ -85,6 +93,8 @@ project "SHADE_Managed" dependson { "yaml-cpp", + "msdfgen", + "msdf-atlas-gen", "imgui", "SHADE_Engine" } diff --git a/SHADE_Managed/src/Assets/Font.cxx b/SHADE_Managed/src/Assets/Font.cxx new file mode 100644 index 00000000..782b0688 --- /dev/null +++ b/SHADE_Managed/src/Assets/Font.cxx @@ -0,0 +1,32 @@ +/************************************************************************************//*! +\file Font.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2022 +\brief Contains the implementation of the functions of the managed Font class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Font.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Explicit Template Instantiation */ + /*---------------------------------------------------------------------------------*/ + template ref class NativeAsset; + + /*---------------------------------------------------------------------------------*/ + /* Constructors/Destructor */ + /*---------------------------------------------------------------------------------*/ + Font::Font(Handle font) + : NativeAsset { font } + {} +} diff --git a/SHADE_Managed/src/Assets/Font.hxx b/SHADE_Managed/src/Assets/Font.hxx new file mode 100644 index 00000000..fd194d1a --- /dev/null +++ b/SHADE_Managed/src/Assets/Font.hxx @@ -0,0 +1,41 @@ +/************************************************************************************//*! +\file Font.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2022 +\brief Contains the definition of the managed Font class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "Resource/SHHandle.h" +#include "Graphics/MiddleEnd/TextRendering/SHFont.h" +// Project Includes +#include "NativeAsset.hxx" +#include "Engine/GenericHandle.hxx" + +namespace SHADE +{ + /// + /// Managed counterpart of the native Font object that can be fed to TextRenderables + /// for rendering. + /// + public ref class Font : public NativeAsset + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors/Destructor */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for the Font. + /// + /// Handle to the font object. + Font(Handle font); + }; +} diff --git a/SHADE_Managed/src/Assets/NativeAsset.cxx b/SHADE_Managed/src/Assets/NativeAsset.cxx index 674207a1..9cdb1840 100644 --- a/SHADE_Managed/src/Assets/NativeAsset.cxx +++ b/SHADE_Managed/src/Assets/NativeAsset.cxx @@ -21,6 +21,17 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { /*---------------------------------------------------------------------------------*/ - /* Explicit Tempalte Instantiations */ + /* Properties */ /*---------------------------------------------------------------------------------*/ + GenericHandle Asset::NativeObjectHandle::get() + { + return nativeObjHandle; + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Asset::Asset(Handle nativeHandle) + : nativeObjHandle { Convert::ToCLI(Handle(nativeHandle)) } + {} } \ No newline at end of file diff --git a/SHADE_Managed/src/Assets/NativeAsset.h++ b/SHADE_Managed/src/Assets/NativeAsset.h++ index a4cd94b4..05be83b4 100644 --- a/SHADE_Managed/src/Assets/NativeAsset.h++ +++ b/SHADE_Managed/src/Assets/NativeAsset.h++ @@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited. // Primary Include #include "NativeAsset.hxx" +#include "Utility/Convert.hxx" namespace SHADE { @@ -23,11 +24,6 @@ namespace SHADE /* Properties */ /*---------------------------------------------------------------------------------*/ template - GenericHandle NativeAsset::NativeObjectHandle::get() - { - return nativeObjHandle; - } - template Handle NativeAsset::NativeObject::get() try { @@ -43,7 +39,6 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ template NativeAsset::NativeAsset(Handle nativeObj) - : nativeObjHandle{ Convert::ToCLI(Handle(nativeObj)) } + : Asset { Handle(nativeObj) } {} - } diff --git a/SHADE_Managed/src/Assets/NativeAsset.hxx b/SHADE_Managed/src/Assets/NativeAsset.hxx index 68addb75..4d53ce6b 100644 --- a/SHADE_Managed/src/Assets/NativeAsset.hxx +++ b/SHADE_Managed/src/Assets/NativeAsset.hxx @@ -19,13 +19,9 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { /// - /// Generalised template class for a managed representation of a native asset + /// Abstract base class that all Native Assets will inherit from. /// - /// - /// The type of the asset's native representation. - /// - template - public ref class NativeAsset + public ref class Asset abstract { internal: /*-----------------------------------------------------------------------------*/ @@ -38,6 +34,36 @@ namespace SHADE { GenericHandle get(); } + + /*-----------------------------------------------------------------------------*/ + /* Constructors/Destructor */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for the asset. + /// + /// Native asset object handle. + Asset(Handle nativeHandle); + + protected: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + GenericHandle nativeObjHandle; + }; + + /// + /// Generalised template class for a managed representation of a native asset + /// + /// + /// The type of the asset's native representation. + /// + template + public ref class NativeAsset abstract : Asset + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ /// /// Copy of the Handle to the native object. /// @@ -52,14 +78,8 @@ namespace SHADE /// /// Constructor for the native asset /// - /// Native asset object. + /// Native asset object handle. NativeAsset(Handle ptr); - - protected: - /*-----------------------------------------------------------------------------*/ - /* Data Members */ - /*-----------------------------------------------------------------------------*/ - GenericHandle nativeObjHandle; }; } diff --git a/SHADE_Managed/src/Components/RigidBody.cxx b/SHADE_Managed/src/Components/RigidBody.cxx index cdaa296a..a564402f 100644 --- a/SHADE_Managed/src/Components/RigidBody.cxx +++ b/SHADE_Managed/src/Components/RigidBody.cxx @@ -58,7 +58,7 @@ namespace SHADE } void RigidBody::Mass::set(float value) { - return GetNativeComponent()->SetMass(value); + /*return GetNativeComponent()->SetMass(value);*/ } float RigidBody::Drag::get() { diff --git a/SHADE_Managed/src/Components/TextRenderable.cxx b/SHADE_Managed/src/Components/TextRenderable.cxx new file mode 100644 index 00000000..c5859854 --- /dev/null +++ b/SHADE_Managed/src/Components/TextRenderable.cxx @@ -0,0 +1,57 @@ +/************************************************************************************//*! +\file TextRenderable.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2022 +\brief Contains the definition of the functions of the managed TextRenderable + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "TextRenderable.hxx" +#include "Assets/NativeAsset.hxx" +#include "Utility/Convert.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + TextRenderable::TextRenderable(Entity entity) + : Component(entity) + {} + + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + System::String^ TextRenderable::Text::get() + { + return Convert::ToCLI(GetNativeComponent()->GetText()); + } + void TextRenderable::Text::set(System::String^ value) + { + GetNativeComponent()->SetText(Convert::ToNative(value)); + } + SHADE::Font^ TextRenderable::Font::get() + { + return gcnew SHADE::Font(GetNativeComponent()->GetFont()); + } + void TextRenderable::Font::set(SHADE::Font^ value) + { + if (value == nullptr) + { + GetNativeComponent()->SetFont(Handle()); + } + else + { + GetNativeComponent()->SetFont(Handle(Convert::ToNative(value->NativeObjectHandle))); + } + } +} diff --git a/SHADE_Managed/src/Components/TextRenderable.hxx b/SHADE_Managed/src/Components/TextRenderable.hxx new file mode 100644 index 00000000..5418b6e5 --- /dev/null +++ b/SHADE_Managed/src/Components/TextRenderable.hxx @@ -0,0 +1,65 @@ +/************************************************************************************//*! +\file TextRenderable.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 21, 2022 +\brief Contains the definition of the managed TextRenderable class with the + declaration of functions for working with it. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" +// Project Includes +#include "Components/Component.hxx" +#include "Math/Vector3.hxx" +#include "Math/Quaternion.hxx" +#include "Assets/Font.hxx" + +namespace SHADE +{ + /// + /// CLR version of the SHADE Engine's SHTextRenderableComponent. + /// + public ref class TextRenderable : public Component + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructs a TextRenderable Component that represents a native TextRenderable + /// component tied to the specified Entity. + /// + /// Entity that this Component will be tied to. + TextRenderable(Entity entity); + + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Text to render using this TextRenderable. + /// + property System::String^ Text + { + System::String^ get(); + void set(System::String^ value); + } + /// + /// Font to use to render using this TextRenderable. + /// + property SHADE::Font^ Font + { + SHADE::Font^ get(); + void set(SHADE::Font^ value); + } + }; +} + diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 7b2e0982..beb667e3 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -117,6 +117,12 @@ namespace SHADE // Header SHEditorUI::PushID(index); + bool enabled = script->Enabled; + if (SHEditorUI::InputCheckbox("", enabled)) + { + script->Enabled = enabled; + } + SHEditorUI::SameLine(); if (SHEditorUI::CollapsingHeader(LABEL)) { SHEditorUI::PushID(LABEL); diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index ffdffd12..c388f0cd 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -28,6 +28,7 @@ of DigiPen Institute of Technology is prohibited. #include "Scene/SHSceneGraph.h" #include "Tools/Logger/SHLog.h" #include "Graphics\MiddleEnd\Interface\SHRenderable.h" +#include "Graphics\MiddleEnd\TextRendering\SHTextRenderableComponent.h" // Project Headers #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" @@ -38,6 +39,7 @@ of DigiPen Institute of Technology is prohibited. #include "Components/CameraArm.hxx" #include "Components/Light.hxx" #include "Components\Renderable.hxx" +#include "Components\TextRenderable.hxx" namespace SHADE { @@ -321,6 +323,7 @@ namespace SHADE componentMap.Add(createComponentSet()); componentMap.Add(createComponentSet()); componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Engine/GameObject.cxx b/SHADE_Managed/src/Engine/GameObject.cxx index 200b2079..3557e8f1 100644 --- a/SHADE_Managed/src/Engine/GameObject.cxx +++ b/SHADE_Managed/src/Engine/GameObject.cxx @@ -54,6 +54,14 @@ namespace SHADE return GameObject(ENTITY_ID); } + /*---------------------------------------------------------------------------------*/ + /* Static Properties */ + /*---------------------------------------------------------------------------------*/ + GameObject GameObject::Null::get() + { + return GameObject(); + } + /*---------------------------------------------------------------------------------*/ /* Properties */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Engine/GameObject.hxx b/SHADE_Managed/src/Engine/GameObject.hxx index 64d1b428..1ebfc250 100644 --- a/SHADE_Managed/src/Engine/GameObject.hxx +++ b/SHADE_Managed/src/Engine/GameObject.hxx @@ -62,6 +62,17 @@ namespace SHADE /// GameObject that has the specified name. Null if not found. static System::Nullable Find(System::String^ name); + /*-----------------------------------------------------------------------------*/ + /* Static Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Default empty GameObject. + /// + static property GameObject Null + { + GameObject get(); + } + /*-----------------------------------------------------------------------------*/ /* Properties */ /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Math/Ray.cxx b/SHADE_Managed/src/Math/Ray.cxx index ee614cbe..bfb99578 100644 --- a/SHADE_Managed/src/Math/Ray.cxx +++ b/SHADE_Managed/src/Math/Ray.cxx @@ -1,28 +1,37 @@ -/************************************************************************************//*! -\file Ray.cxx -\author Tng Kah Wei, kahwei.tng, 390009620 -\par email: kahwei.tng\@digipen.edu -\date Oct 20, 2022 -\brief Contains the definitions of functions of the Vector2 struct. - - Note: This file is written in C++17/CLI. +/**************************************************************************************** + * \file Ray.cxx + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the managed Ray struct. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ -Copyright (C) 2022 DigiPen Institute of Technology. -Reproduction or disclosure of this file or its contents without the prior written consent -of DigiPen Institute of Technology is prohibited. -*//*************************************************************************************/ -// Precompiled Headers #include "SHpch.h" + // Primary Header -#include "Math/Ray.hxx" +#include "Ray.hxx" namespace SHADE { - /*---------------------------------------------------------------------------------*/ - /* Constructors */ - /*---------------------------------------------------------------------------------*/ - Ray::Ray(Vector3 origin, Vector3 direction) - : Origin { origin } - , Direction{ direction } - {} -} \ No newline at end of file + /*-----------------------------------------------------------------------------------*/ + /* Constructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + Ray::Ray(Vector3 position, Vector3 direction) + { + Position = position; + Direction = direction; + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void Ray::LookAt(Vector3 target) + { + Direction = (target - Position).GetNormalised(); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Ray.hxx b/SHADE_Managed/src/Math/Ray.hxx index c50191f8..b684aa91 100644 --- a/SHADE_Managed/src/Math/Ray.hxx +++ b/SHADE_Managed/src/Math/Ray.hxx @@ -1,50 +1,61 @@ -/************************************************************************************//*! -\file Ray.hxx -\author Tng Kah Wei, kahwei.tng, 390009620 -\par email: kahwei.tng\@digipen.edu -\date Oct 20, 2021 -\brief Contains the definitions of Vector2 struct. - - Note: This file is written in C++17/CLI. +/**************************************************************************************** + * \file Ray.hxx + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the managed Ray struct. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ -Copyright (C) 2022 DigiPen Institute of Technology. -Reproduction or disclosure of this file or its contents without the prior written consent -of DigiPen Institute of Technology is prohibited. -*//*************************************************************************************/ #pragma once // Project Includes -#include "Vector3.hxx" +#include "Math/Vector3.hxx" namespace SHADE { - /// - /// CLR version of the the SHADE Engine's Ray class that represents a ray in - /// 3-Dimensional space. - /// - public value struct Ray - { - public: - /*-----------------------------------------------------------------------------*/ - /* Public Members */ - /*-----------------------------------------------------------------------------*/ - /// - /// The start point of the ray. - /// - Vector3 Origin; - /// - /// The direction that a ray travels in. - /// - Vector3 Direction; + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------------*/ - /* Constructors */ - /*-----------------------------------------------------------------------------*/ - /// - /// Creates a ray starting at origin along direction. - /// - /// Source of the ray. - /// Direction the ray travels in. - Ray(Vector3 origin, Vector3 direction); - }; -} + public value struct Ray + { + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + + /// + /// Constructor for a ray. + /// + /// The starting position of the ray. + /// The direction of the ray. + Ray(Vector3 position, Vector3 direction); + + + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + + /// + /// The starting point of the Ray. + /// + property Vector3 Position; + /// + /// The direction of the ray. This should be a normalised vector. + /// + property Vector3 Direction; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + /// + /// Rotates the ray's direction towards a target. + /// + /// The target to direct the ray towards. + void LookAt(Vector3 target); + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Physics/Physics.cxx b/SHADE_Managed/src/Physics/Physics.cxx new file mode 100644 index 00000000..9e2c1413 --- /dev/null +++ b/SHADE_Managed/src/Physics/Physics.cxx @@ -0,0 +1,105 @@ +/**************************************************************************************** + * \file Physics.cxx + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the managed Physics class. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include "SHpch.h" + +// Primary Header +#include "Physics.hxx" +// External Dependencies +#include "Physics/System/SHPhysicsSystemInterface.h" +// Project Header +#include "Engine/GameObject.hxx" +#include "Utility/Convert.hxx" +#include "Utility/Debug.hxx" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Property Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + Vector3 Physics::Gravity::get() + { + // TODO(Diren) + + return Vector3::Zero; + } + + void Physics::Gravity::set(Vector3 value) + { + (void)value; + } + + /*-----------------------------------------------------------------------------------*/ + /* Raycast Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + RaycastHit Physics::Raycast(Ray ray) + { + return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray))); + } + + RaycastHit Physics::Raycast(Ray ray, float distance) + { + return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray), distance)); + } + + RaycastHit Physics::Linecast(Vector3 start, Vector3 end) + { + return Convert::ToCLI(SHPhysicsSystemInterface::Linecast(Convert::ToNative(start), Convert::ToNative(end))); + } + + RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray) + { + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray))); + } + + RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance) + { + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray), distance)); + } + + RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray) + { + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray))); + } + + RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance) + { + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray), distance)); + } + + RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end) + { + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, Convert::ToNative(start), Convert::ToNative(end))); + } + + RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end) + { + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, shapeIndex, Convert::ToNative(start), Convert::ToNative(end))); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + RaycastHit Physics::generateDefaultResult() + { + RaycastHit default; + default.Hit = false; + default.Other = System::Nullable(); + default.Position = Vector3::Zero; + default.Normal = Vector3::Zero; + default.Distance = System::Single::PositiveInfinity; + default.CollisionShapeIndex = -1; + + return default; + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Physics/Physics.hxx b/SHADE_Managed/src/Physics/Physics.hxx new file mode 100644 index 00000000..f13e5952 --- /dev/null +++ b/SHADE_Managed/src/Physics/Physics.hxx @@ -0,0 +1,128 @@ +/**************************************************************************************** + * \file Physics.hxx + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the managed Physics class. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +// Project Includes +#include "Math/Ray.hxx" +#include "RaycastHit.hxx" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + public ref class Physics abstract sealed + { + public: + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + + static property Vector3 Gravity + { + Vector3 get(); + void set(Vector3 value); + } + + // TODO(Diren): Add more properties for physics system settings. + + /*---------------------------------------------------------------------------------*/ + /* Raycast Function Members */ + /*---------------------------------------------------------------------------------*/ + + /// + /// Casts an infinite ray into the world. + /// + /// The ray to cast. + /// The result of the raycast. + static RaycastHit Raycast (Ray ray); + + /// + /// Casts a ray for a given distance into the world. + /// + /// The ray to cast. + /// The distance to cast the ray. + /// The result of the raycast. + static RaycastHit Raycast (Ray ray, float distance); + + /// + /// Casts a bounded ray into the world. + /// + /// The start of the bounded ray. + /// The end of the bounded ray. + /// The result of the raycast. + static RaycastHit Linecast (Vector3 start, Vector3 end); + + /// + /// Casts an infinite ray w.r.t a GameObject. + /// + /// The GameObject to cast the ray to. + /// The ray to cast. + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, Ray ray); + + /// + /// Casts a ray for a given distance w.r.t a GameObject. + /// + /// The GameObject to cast the ray to. + /// The ray to cast. + /// The distance to cast the ray. + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance); + + /// + /// Casts an infinite ray w.r.t a specific collider on a GameObject. + /// + /// The GameObject to cast the ray to. + /// The collision shape index on the collider to cast to. + /// The ray to cast. + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray); + + /// + /// Casts a ray for a given distance w.r.t a specific collider on a GameObject. + /// + /// The GameObject to cast the ray to. + /// The collision shape index on the collider to cast to. + /// The ray to cast. + /// The distance to cast the ray. + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance); + + /// + /// Casts a bounded ray w.r.t a GameObject. + /// + /// The GameObject to cast the ray to. + /// The start of the bounded ray. + /// + /// The result of the raycast. + static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end); + + /// + /// Casts a bounded ray w.r.t a specific collider on a GameObject. + /// + /// The GameObject to cast the ray to. + /// The collision shape index on the collider to cast to. + /// The start of the bounded ray. + /// The end of the bounded ray. + /// The result of the raycast. + static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end); + + private: + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + static RaycastHit generateDefaultResult (); + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Physics/RaycastHit.cxx b/SHADE_Managed/src/Physics/RaycastHit.cxx new file mode 100644 index 00000000..e7ee9b89 --- /dev/null +++ b/SHADE_Managed/src/Physics/RaycastHit.cxx @@ -0,0 +1,19 @@ +/**************************************************************************************** + * \file RaycastHit.cxx + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the managed RaycastHit struct. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include "SHpch.h" + +// Primary Header +#include "RaycastHit.hxx" + +namespace SHADE +{ + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Physics/RaycastHit.hxx b/SHADE_Managed/src/Physics/RaycastHit.hxx new file mode 100644 index 00000000..260da2a1 --- /dev/null +++ b/SHADE_Managed/src/Physics/RaycastHit.hxx @@ -0,0 +1,64 @@ +/**************************************************************************************** + * \file RaycastHit.hxx + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the managed RaycastHit struct. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +// Project Includes +#include "Engine/GameObject.hxx" +#include "Math/Vector3.hxx" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /// + /// Defines a struct that contains the information of a raycast. + /// + public value struct RaycastHit + { + public: + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + + /// + /// Whether or not the raycast hit a collider. + /// + property bool Hit; + + /// + /// The other game object hit. + /// + property System::Nullable Other; + + /// + /// The position where the ray cast hit. Zero if not hit. + /// + property Vector3 Position; + + /// + /// The normal where the ray cast hit. Zero if not hit. + /// + property Vector3 Normal; + + /// + /// The distance the ray was cast. Infinity if not hit. + /// + property float Distance; + + /// + /// The index of the collision shape hit on the collider. -1 if not hit. + /// + property int CollisionShapeIndex; + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Scripts/Script.cxx b/SHADE_Managed/src/Scripts/Script.cxx index a2af38a3..2ee7dbf7 100644 --- a/SHADE_Managed/src/Scripts/Script.cxx +++ b/SHADE_Managed/src/Scripts/Script.cxx @@ -22,6 +22,36 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + GameObject Script::Owner::get() + { + return owner; + } + GameObject Script::GameObject::get() + { + return owner; + } + bool Script::Enabled::get() + { + return enabled; + } + void Script::Enabled::set(bool value) + { + // Same, don't set + if (value == enabled) + return; + + enabled = value; + + // There's a change, so call the appropriate function + if (enabled) + OnEnable(); + else + OnDisable(); + } + /*---------------------------------------------------------------------------------*/ /* Component Access Functions */ /*---------------------------------------------------------------------------------*/ @@ -104,11 +134,10 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* "All-time" Lifecycle Functions */ /*---------------------------------------------------------------------------------*/ - void Script::Initialize(GameObject newOwner) + void Script::Initialize(SHADE::GameObject newOwner) { owner = newOwner; } - void Script::OnAttached() { SAFE_NATIVE_CALL_BEGIN @@ -131,6 +160,12 @@ namespace SHADE awake(); SAFE_NATIVE_CALL_END(this) } + void Script::OnEnable() + { + SAFE_NATIVE_CALL_BEGIN + onEnable(); + SAFE_NATIVE_CALL_END(this) + } void Script::Start() { SAFE_NATIVE_CALL_BEGIN @@ -162,6 +197,12 @@ namespace SHADE onDrawGizmos(); SAFE_NATIVE_CALL_END(this) } + void Script::OnDisable() + { + SAFE_NATIVE_CALL_BEGIN + onDisable(); + SAFE_NATIVE_CALL_END(this) + } void Script::OnDestroy() { SAFE_NATIVE_CALL_BEGIN @@ -228,6 +269,7 @@ namespace SHADE /* Virtual Lifecycle Functions */ /*---------------------------------------------------------------------------------*/ void Script::awake() {} + void Script::onEnable() {} void Script::start() {} void Script::fixedUpdate() {} void Script::update() {} @@ -236,6 +278,7 @@ namespace SHADE { OnGizmosDrawOverriden = false; } + void Script::onDisable() {} void Script::onDestroy() {} /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Scripts/Script.hxx b/SHADE_Managed/src/Scripts/Script.hxx index 46736245..62c5015c 100644 --- a/SHADE_Managed/src/Scripts/Script.hxx +++ b/SHADE_Managed/src/Scripts/Script.hxx @@ -38,11 +38,28 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// + /// GameObject that this Script belongs to. This is a legacy interface, use + /// GameObject instead. + /// + [System::ObsoleteAttribute("Use GameObject instead.", false)] + property SHADE::GameObject Owner + { + SHADE::GameObject get(); + } + /// /// GameObject that this Script belongs to. /// - property GameObject Owner + property SHADE::GameObject GameObject { - GameObject get() { return owner; } + SHADE::GameObject get(); + } + /// + /// Whether or not this Script should have it's update functions be executed. + /// + property bool Enabled + { + bool get(); + void set(bool value); } /*-----------------------------------------------------------------------------*/ @@ -127,7 +144,7 @@ namespace SHADE /// /// /// Type of script to get. - /// This needs to be a default constructable Script. + /// This needs to be a default constructible Script. /// /// Reference to the script added generic where T : ref class, Script @@ -206,7 +223,7 @@ namespace SHADE /// /// Used to initialize a Script with a GameObject. /// - void Initialize(GameObject newOwner); + void Initialize(SHADE::GameObject newOwner); /// /// Used to call onAttached(). This is called immediately when this script is /// attached to a GameObject. @@ -232,6 +249,11 @@ namespace SHADE /// void Start(); /// + /// Used to call onEnable. This should be called right when a script is enabled + /// directly. + /// + void OnEnable(); + /// /// Used to call fixedUpdate(). This should be called in sync with Physics /// update steps and thus in most cases will execute more than Update() will. /// This will be called immediately before a Physics update step. @@ -253,6 +275,11 @@ namespace SHADE /// void OnDrawGizmos(); /// + /// Used to call onDisable. This should be called right when a script is disabled + /// directly. + /// + void OnDisable(); + /// /// Used to call onDestroy(). This should be called at the end of the frame /// where the attached GameObject or this script is destroyed directly or /// indirectly due to destruction of the owner. @@ -329,6 +356,10 @@ namespace SHADE /// virtual void awake(); /// + /// Called when this script is enabled. + /// + virtual void onEnable(); + /// /// Called on the first frame that the attached GameObject is active but always /// after Awake(). /// @@ -353,6 +384,10 @@ namespace SHADE /// virtual void onDrawGizmos(); /// + /// Called when this script is disabled. + /// + virtual void onDisable(); + /// /// Called just before the end of the frame where the attached GameObject or /// this script is destroyed directly or indirectly due to destruction of the /// owner. @@ -403,7 +438,8 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ - GameObject owner; + SHADE::GameObject owner; + bool enabled = true; }; } diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index 29ba6e52..96eb7361 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -528,7 +528,8 @@ namespace SHADE ScriptList^ scripts = entity.Value; for (int i = 0; i < scripts->Count; ++i) { - scripts[i]->FixedUpdate(); + if (scripts[i]->Enabled) + scripts[i]->FixedUpdate(); } } SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") @@ -546,7 +547,8 @@ namespace SHADE ScriptList^ scripts = entity.Value; for (int i = 0; i < scripts->Count; ++i) { - scripts[i]->Update(); + if (scripts[i]->Enabled) + scripts[i]->Update(); } } SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") @@ -564,7 +566,8 @@ namespace SHADE ScriptList^ scripts = entity.Value; for (int i = 0; i < scripts->Count; ++i) { - scripts[i]->LateUpdate(); + if (scripts[i]->Enabled) + scripts[i]->LateUpdate(); } } SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") @@ -583,7 +586,8 @@ namespace SHADE ScriptList^ scripts = entity.Value; for (int i = 0; i < scripts->Count; ++i) { - scripts[i]->OnDrawGizmos(); + if (scripts[i]->Enabled) + scripts[i]->OnDrawGizmos(); } } SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index 3b1f0f38..590a3cf0 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -19,6 +19,8 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include #include "ECS_Base/Managers/SHEntityManager.h" +// Project Headers +#include "Engine/GameObject.hxx" namespace SHADE { @@ -62,14 +64,14 @@ namespace SHADE return Quaternion{ quat.x, quat.y, quat.z, quat.w }; } - SHRay Convert::ToNative(Ray vec) + SHRay Convert::ToNative(Ray ray) { - return SHRay(ToNative(vec.Origin), ToNative(vec.Direction)); + return SHRay(ToNative(ray.Position), ToNative(ray.Direction)); } - Ray Convert::ToCLI(const SHRay& vec) + Ray Convert::ToCLI(const SHRay& ray) { - return Ray(ToCLI(vec.position), ToCLI(vec.direction)); + return Ray(ToCLI(ray.position), ToCLI(ray.direction)); } SHColour Convert::ToNative(Color col) @@ -87,6 +89,8 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ std::string Convert::ToNative(System::String^ str) { + if (str == nullptr) + return ""; return msclr::interop::marshal_as(str); } @@ -95,6 +99,42 @@ namespace SHADE return msclr::interop::marshal_as(str); } + /*---------------------------------------------------------------------------------*/ + /* Physics Conversions */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsRaycastResult Convert::ToNative(RaycastHit cli) + { + // This function shouldn't be used anyway, so we leave the entityHit empty. + + SHPhysicsRaycastResult native; + + native.hit = cli.Hit; + native.position = ToNative(cli.Position); + native.normal = ToNative(cli.Normal); + native.distance = cli.Distance; + native.shapeIndex = cli.CollisionShapeIndex; + + return native; + } + + RaycastHit Convert::ToCLI(const SHPhysicsRaycastResult& native) + { + RaycastHit cli; + + cli.Hit = native.hit; + cli.Position = ToCLI(native.position); + cli.Normal = ToCLI(native.normal); + cli.Distance = native.distance; + cli.CollisionShapeIndex = native.shapeIndex; + + cli.Other = SHEntityManager::IsValidEID(native.entityHit) + ? GameObject(native.entityHit) + : System::Nullable(); + + return cli; + } + /*---------------------------------------------------------------------------------*/ /* Handle Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index 4d0c5b59..04407f77 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -28,9 +28,11 @@ of DigiPen Institute of Technology is prohibited. #include "Math/Vector3.hxx" #include "Math/Quaternion.hxx" #include "Math/Ray.hxx" +#include "Physics/RaycastHit.hxx" #include "Engine/GenericHandle.hxx" #include "Math/SHColour.h" #include "Graphics/Color.hxx" +#include "Physics/Collision/SHPhysicsRaycastResult.h" namespace SHADE { @@ -95,22 +97,22 @@ namespace SHADE /// The native Quaternion to convert from. /// Managed copy of a native Quaternion. static Quaternion ToCLI(const SHQuaternion& quat); - /// Converts from a managed Vector2 to a native Vector2. + /// Converts from a managed Ray to a native Ray. /// - /// The managed Vector2 to convert from. - /// Native copy of a managed Vector2. + /// The managed Ray to convert from. + /// Native copy of a managed Ray. static SHRay ToNative(Ray vec); /// - /// Converts from a native Vector2 to a managed Vector2. + /// Converts from a native Ray to a managed Ray. /// - /// The native Vector2 to convert from. - /// Managed copy of a native Vector2. - static Ray ToCLI(const SHRay& vec); + /// The native Ray to convert from. + /// Managed copy of a native Ray. + static Ray ToCLI(const SHRay& ray); /// Converts from a managed Color to a native Colour. /// /// The managed Color to convert from. /// Native copy of a managed Color. - static SHColour ToNative(Color col); + static SHColour ToNative(Color ray); /// /// Converts from a native Colour to a managed Color. /// @@ -134,9 +136,27 @@ namespace SHADE /// Managed copy of a native std::string. static System::String^ ToCLI(const std::string& str); + /*-----------------------------------------------------------------------------*/ + /* Physics Conversions */ + /*-----------------------------------------------------------------------------*/ + + /// + /// Converts from a managed RaycastHit to a native SHPhysicsRaycastResult + /// + /// The managed RaycastHit to convert from. + /// Native copy of a managed RaycastHit. + static SHPhysicsRaycastResult ToNative(RaycastHit cli); + + /// + /// Converts from native SHPhysicsRaycastResult to a managed RaycastHit. + /// + /// The native SHPhysicsRaycastResult to convert from. + /// Managed copy of a native SHPhysicsRaycastResult. + static RaycastHit ToCLI(const SHPhysicsRaycastResult& native); + /*-----------------------------------------------------------------------------*/ /* Handle Conversions */ - /*-----------------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------------*/ /// /// Converts from a managed GenericHandle to a Handle. /// diff --git a/premake5.lua b/premake5.lua index 2164d649..26f181b5 100644 --- a/premake5.lua +++ b/premake5.lua @@ -25,10 +25,11 @@ workspace "SHADE" include "SHADE_CSharp" group "Dependencies" - include "Dependencies/msdf" + include "Dependencies/FontCompiler/Dependencies/msdf" include "Dependencies/imgui" --include "Dependencies/tracy" include "Dependencies/yamlcpp" include "Dependencies/reactphysics3d" include "Dependencies/ModelCompiler" + include "Dependencies/FontCompiler" group ""