diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl new file mode 100644 index 00000000..c1caf0aa --- /dev/null +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -0,0 +1,83 @@ +#version 450 + +struct DirectionalLightStruct +{ + vec3 direction; + uint isActive; + uint cullingMask; + vec4 diffuseColor; +}; + +struct AmbientLightStruct +{ + vec4 ambientColor; + float strength; + uint isActive; + uint cullingMask; +}; + +layout(local_size_x = 16, local_size_y = 16) in; +layout(set = 4, binding = 0, rgba32f) uniform image2D positions; +layout(set = 4, binding = 1, rgba32f) uniform image2D normals; +layout(set = 4, binding = 2, rgba8) uniform image2D albedo; +layout(set = 4, binding = 3, r32ui) uniform uimage2D lightLayerData; +layout(set = 4, binding = 4, rgba8) uniform image2D targetImage; + +layout(set = 1, binding = 0) uniform LightCounts +{ + uint directionalLights; + uint pointLights; + uint spotLights; + uint ambientLights; + +} lightCounts; + +layout(std430, set = 1, binding = 1) buffer DirectionalLightData +{ + DirectionalLightStruct dLightData[]; +} DirLightData; + +layout(std430, set = 1, binding = 4) buffer AmbientLightData +{ + AmbientLightStruct aLightData[]; +} AmbLightData; + +void main() +{ + // convenient variables + ivec2 globalThread = ivec2(gl_GlobalInvocationID); + + // Get the diffuse color of the pixel + vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; + + // Get position of fragment in world space + vec3 positionWorld = imageLoad (positions, globalThread).rgb; + + // normal of fragment + vec3 normalWorld = imageLoad(normals, globalThread).rgb; + + vec3 fragColor = vec3 (0.0f); + + for (int i = 0; i < lightCounts.directionalLights; ++i) + { + // get normalized direction of light + vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction); + + // Get diffuse strength + float diffuseStrength = max (0, dot (dLightNormalized, normalWorld)); + + // Calculate the fragment color + fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; + } + + for (int i = 0; i < lightCounts.ambientLights; ++i) + { + // Just do some add + //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); + fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + } + + // store result into result image + imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor, 1.0f)); + +} \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb new file mode 100644 index 00000000..889de5fb Binary files /dev/null and b/Assets/Shaders/DeferredComposite_CS.shshaderb differ diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb.shmeta b/Assets/Shaders/DeferredComposite_CS.shshaderb.shmeta new file mode 100644 index 00000000..8f18b04a --- /dev/null +++ b/Assets/Shaders/DeferredComposite_CS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: DeferredComposite_CS +ID: 42814284 +Type: 2 diff --git a/Assets/Shaders/Kirsch_CS.shshaderb.shmeta b/Assets/Shaders/Kirsch_CS.shshaderb.shmeta index 61c735f3..af092818 100644 --- a/Assets/Shaders/Kirsch_CS.shshaderb.shmeta +++ b/Assets/Shaders/Kirsch_CS.shshaderb.shmeta @@ -1,3 +1,3 @@ Name: Kirsch_CS -ID: 19931255 +ID: 39301863 Type: 2 diff --git a/Assets/Shaders/PureCopy_CS.shshaderb.shmeta b/Assets/Shaders/PureCopy_CS.shshaderb.shmeta index 8cb091d7..8c3d446d 100644 --- a/Assets/Shaders/PureCopy_CS.shshaderb.shmeta +++ b/Assets/Shaders/PureCopy_CS.shshaderb.shmeta @@ -1,3 +1,3 @@ Name: PureCopy_CS -ID: 29659779 +ID: 34987209 Type: 2 diff --git a/Assets/Shaders/TestCube_FS.glsl b/Assets/Shaders/TestCube_FS.glsl index 4dc6deca..c60da6ce 100644 --- a/Assets/Shaders/TestCube_FS.glsl +++ b/Assets/Shaders/TestCube_FS.glsl @@ -13,37 +13,38 @@ struct MatPropData layout(location = 0) in struct { - vec4 vertColor; - vec2 uv; + vec4 vertPos; // location 0 + vec2 uv; // location = 1 + vec4 normal; // location = 2 } In; // material stuff -layout(location = 2) flat in struct +layout(location = 3) flat in struct { int materialIndex; uint eid; uint lightLayerIndex; } In2; -//layout (set = 0, binding = ) - layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global) -layout (set = 3, binding = 0) buffer MaterialProperties // For materials +layout (std430, set = 3, binding = 0) buffer MaterialProperties // For materials { MatPropData data[]; } MatProp; -layout(location = 0) out vec4 outColor; +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() { - outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) + - MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha; + position = In.vertPos; + normals = In.normal; + albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) + MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha; outEntityID = In2.eid; lightLayerIndices = In2.lightLayerIndex; - //outColor = vec4 (1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/TestCube_FS.shshaderb b/Assets/Shaders/TestCube_FS.shshaderb index 863287f6..b0113dc7 100644 Binary files a/Assets/Shaders/TestCube_FS.shshaderb and b/Assets/Shaders/TestCube_FS.shshaderb differ diff --git a/Assets/Shaders/TestCube_FS.shshaderb.shmeta b/Assets/Shaders/TestCube_FS.shshaderb.shmeta index 3a647313..42f270af 100644 --- a/Assets/Shaders/TestCube_FS.shshaderb.shmeta +++ b/Assets/Shaders/TestCube_FS.shshaderb.shmeta @@ -1,3 +1,3 @@ Name: TestCube_FS -ID: 18415057 +ID: 37450402 Type: 2 diff --git a/Assets/Shaders/TestCube_VS.glsl b/Assets/Shaders/TestCube_VS.glsl index 7b58d1cf..49f107dd 100644 --- a/Assets/Shaders/TestCube_VS.glsl +++ b/Assets/Shaders/TestCube_VS.glsl @@ -14,13 +14,14 @@ layout(location = 8) in uvec2 integerData; layout(location = 0) out struct { - vec4 vertColor; // location 0 + vec4 vertPos; // location 0 vec2 uv; // location = 1 + vec4 normal; // location = 2 } Out; // material stuff -layout(location = 2) out struct +layout(location = 3) out struct { int materialIndex; uint eid; @@ -36,10 +37,14 @@ layout(set = 2, binding = 0) uniform CameraData void main() { - Out.uv = aUV; + Out2.materialIndex = gl_InstanceIndex; Out2.eid = integerData[0]; Out2.lightLayerIndex = integerData[1]; + + Out.vertPos = worldTransform * vec4(aVertexPos, 1.0f); + Out.uv = aUV; + Out.normal.rgb = mat3(transpose(inverse(worldTransform))) * aNormal.rgb; + Out.normal.rgb = normalize (Out.normal.rgb); gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); - Out.vertColor = vec4 (aVertexPos, 1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/TestCube_VS.shshaderb b/Assets/Shaders/TestCube_VS.shshaderb index 3d12507b..03e23af3 100644 Binary files a/Assets/Shaders/TestCube_VS.shshaderb and b/Assets/Shaders/TestCube_VS.shshaderb differ diff --git a/Assets/Shaders/TestCube_VS.shshaderb.shmeta b/Assets/Shaders/TestCube_VS.shshaderb.shmeta index 23c5e30d..b133437b 100644 --- a/Assets/Shaders/TestCube_VS.shshaderb.shmeta +++ b/Assets/Shaders/TestCube_VS.shshaderb.shmeta @@ -1,3 +1,3 @@ Name: TestCube_VS -ID: 29315909 +ID: 41688429 Type: 2 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 53393fea..24f0a214 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -4,7 +4,7 @@ //#define SHEDITOR #ifdef SHEDITOR -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" //#include "Scenes/SBEditorScene.h" #endif // SHEDITOR @@ -94,7 +94,7 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); + //SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); #ifdef SHEDITOR @@ -159,7 +159,7 @@ namespace Sandbox SHSceneManager::Exit(); SHSystemManager::Exit(); - SHAssetManager::Unload(); + SHAssetManager::Exit(); } } diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 4cdac9dc..23b57dfc 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -158,12 +158,22 @@ namespace Sandbox SHComponentManager::AddComponent(0); SHComponentManager::RemoveComponent (0); SHComponentManager::RemoveComponent (0); + + auto ambientLight = SHEntityManager::CreateEntity(); + SHComponentManager::GetComponent(ambientLight)->SetColor(SHVec4(1.0f, 1.0f, 1.0f, 1.0f)); + SHComponentManager::GetComponent(ambientLight)->SetStrength(0.25f); + SHComponentManager::GetComponent(ambientLight)->SetType(SH_LIGHT_TYPE::AMBIENT); } void SBTestScene::Update(float dt) { static float rotation = 0.0f; + SHVec3 direction{0.0f, 0.0f, 1.0f}; + direction = SHVec3::RotateY(direction, rotation); + auto* lightComp =SHComponentManager::GetComponent(0); + lightComp->SetDirection (direction); + rotation += 0.005f; //auto& transform = *SHADE::SHComponentManager::GetComponent_s(testObj); //transform.SetWorldPosition({1.0f, 1.0f, -1.0f}); diff --git a/SHADE_CSharp/src/Events/CallbackAction.cs b/SHADE_CSharp/src/Events/CallbackAction.cs index 968302ed..623e4f59 100644 --- a/SHADE_CSharp/src/Events/CallbackAction.cs +++ b/SHADE_CSharp/src/Events/CallbackAction.cs @@ -61,8 +61,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -86,7 +103,7 @@ namespace SHADE /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -103,7 +120,7 @@ namespace SHADE { targetAction.Invoke(t1); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; _ = targetMethod.Invoke(TargetObject, parameters); @@ -138,8 +155,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[2]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -158,12 +192,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[2]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -180,7 +214,7 @@ namespace SHADE { targetAction.Invoke(t1, t2); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -216,8 +250,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[3]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -236,12 +287,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[3]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -258,7 +309,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -295,8 +346,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[4]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -315,12 +383,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[4]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -337,7 +405,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -375,8 +443,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[5]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -395,12 +480,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[5]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -417,7 +502,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4, t5); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -456,8 +541,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[6]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -476,12 +578,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[6]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -498,7 +600,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4, t5, t6); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -538,8 +640,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[7]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -558,12 +677,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[7]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -580,7 +699,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -621,8 +740,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[8]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -641,12 +777,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[8]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -663,7 +799,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -705,8 +841,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[9]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -725,12 +878,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[9]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -747,7 +900,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; @@ -790,8 +943,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[10]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -810,12 +980,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[10]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action action) { targetAction = action; @@ -832,7 +1002,7 @@ namespace SHADE { targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { parameters[0] = t1; parameters[1] = t2; diff --git a/SHADE_CSharp/src/Events/CallbackAction.tt b/SHADE_CSharp/src/Events/CallbackAction.tt index fffd4251..34789b67 100644 --- a/SHADE_CSharp/src/Events/CallbackAction.tt +++ b/SHADE_CSharp/src/Events/CallbackAction.tt @@ -78,8 +78,25 @@ namespace SHADE /// public CallbackAction() {} /// - /// Constructs a CallbackAction that represents a call to the specified method on the - /// specified target. + /// Constructs a CallbackAction that represents a call to the specified static + /// method. + /// + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(MethodInfo method) + { + // No errors, assign + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[<#=i#>]; + } + /// + /// Constructs a CallbackAction that represents a call to a specified member + /// method on the specified target. /// /// Object to call the method on. /// Method to call. @@ -98,12 +115,12 @@ namespace SHADE targetMethod = method; // Create storage for parameters for calling - parameters = new Object[1]; + parameters = new Object[<#=i#>]; } /// /// Constructs a Callback action based on an action. /// - /// + /// Action that wraps a function to be called. public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action) { targetAction = action; @@ -120,7 +137,7 @@ namespace SHADE { targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>); } - else if (TargetObject != null && targetMethod != null) + else if (targetMethod != null) { <# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>; <# } #>_ = targetMethod.Invoke(TargetObject, parameters); diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index 18920194..bc1f6a03 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -8,7 +8,7 @@ project "SHADE_Engine" pchheader "SHpch.h" pchsource "%{prj.location}/src/SHpch.cpp" staticruntime "off" - + buildoptions{"/bigobj"} files { "%{prj.location}/src/**.h", diff --git a/SHADE_Engine/src/Assets/Asset Types/SHMaterialAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHMaterialAsset.h new file mode 100644 index 00000000..a130fc07 --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHMaterialAsset.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * \file SHMaterialAsset.h + * \author Loh Xiao Qi + * \date 29 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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/Asset Types/SHAssetData.h" +#include + +namespace SHADE +{ + struct SHMaterialAsset : SHAssetData + { + std::string name; + std::string data; + }; +} diff --git a/SHADE_Engine/src/Assets/Asset Types/SHPrefabAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHPrefabAsset.h new file mode 100644 index 00000000..0db299b2 --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHPrefabAsset.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * \file SHPrefabAsset.h + * \author Loh Xiao Qi + * \date 28 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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 "SHAssetData.h" +#include + +namespace SHADE +{ + struct SHPrefabAsset : SHAssetData + { + std::string name; + std::string data; + }; +} diff --git a/SHADE_Engine/src/Assets/Asset Types/SHSceneAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHSceneAsset.h new file mode 100644 index 00000000..0f7061b1 --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHSceneAsset.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * \file SHSceneAsset.h + * \author Loh Xiao Qi + * \date 28 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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 "SHAssetData.h" +#include + +namespace SHADE +{ + struct SHSceneAsset : SHAssetData + { + std::string name; + std::string data; + }; +} diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h index 63e081af..b6b7656b 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h @@ -18,5 +18,6 @@ namespace SHADE struct SHAssetLoader { virtual SHAssetData* Load(AssetPath path) = 0; + virtual void Write(SHAssetData const* data, AssetPath path) = 0; }; } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.cpp index 90dd58d4..52134440 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.cpp @@ -22,6 +22,7 @@ namespace SHADE if (!file.is_open()) { SHLOG_ERROR("Unable to open SHMesh File: {}", path.string()); + return; } const std::string name{ path.stem().string() }; @@ -75,4 +76,55 @@ namespace SHADE return result; } + + void SHMeshLoader::Write(SHAssetData const* data, AssetPath path) + { + std::ofstream file{ path, std::ios::out | std::ios::binary | std::ios::trunc }; + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string()); + } + + auto asset = *dynamic_cast(data); + + file.write( + reinterpret_cast(&(asset.header.vertexCount)), + sizeof(uint32_t) + ); + + file.write( + reinterpret_cast(&(asset.header.indexCount)), + sizeof(uint32_t) + ); + + auto const vertexVec3Byte{ sizeof(SHVec3) * asset.header.vertexCount }; + auto const vertexVec2Byte{ sizeof(SHVec2) * asset.header.vertexCount }; + + file.write( + reinterpret_cast(asset.vertexPosition.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexTangent.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexNormal.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.texCoords.data()), + vertexVec2Byte + ); + + file.write( + reinterpret_cast(asset.indices.data()), + sizeof(uint32_t) * asset.header.indexCount + ); + + file.close(); + } } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h index bf65851a..03a111ce 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h @@ -10,7 +10,6 @@ * of DigiPen Institute of Technology is prohibited. *****************************************************************************/ #pragma once -#include "Assets/SHAssetMacros.h" #include "Assets/Asset Types/SHMeshAsset.h" #include "SHAssetLoader.h" @@ -20,5 +19,6 @@ namespace SHADE { void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept; SHAssetData* Load(AssetPath path) override; + void Write(SHAssetData const* data, AssetPath path) override; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp index 824995d6..f0d9a29b 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp @@ -43,4 +43,27 @@ namespace SHADE return result; } + + void SHShaderSourceLoader::Write(SHAssetData const* data, AssetPath path) + { + std::ofstream file{ path, std::ios::binary | std::ios::out | std::ios::trunc }; + + auto asset = *dynamic_cast(data); + + file.write( + reinterpret_cast(&asset.shaderType), sizeof(uint8_t) + ); + + size_t const byteCount = sizeof(uint32_t) * asset.spirvBinary.size(); + + file.write( + reinterpret_cast(&byteCount), sizeof(size_t) + ); + + file.write( + reinterpret_cast(asset.spirvBinary.data()), byteCount + ); + + file.close(); + } } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h index befdade5..0a4b614f 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h @@ -11,12 +11,12 @@ #pragma once #include "Assets/Libraries/Loaders/SHAssetLoader.h" -#include "Assets/SHAssetMacros.h" namespace SHADE { struct SHShaderSourceLoader : SHAssetLoader { SHAssetData* Load(AssetPath path) override; + void Write(SHAssetData const* data, AssetPath path) override; }; } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextBasedLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextBasedLoader.cpp new file mode 100644 index 00000000..b23130f3 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextBasedLoader.cpp @@ -0,0 +1,95 @@ +/****************************************************************************** + * \file SHTextBasedLoader.cpp + * \author Loh Xiao Qi + * \date 28 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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" +#include "SHTextBasedLoader.h" + +#include "Assets/Asset Types/SHSceneAsset.h" +#include "Assets/Asset Types/SHPrefabAsset.h" +#include "Assets/Asset Types/SHMaterialAsset.h" + +#include +#include + +namespace SHADE +{ + SHAssetData* SHTextBasedLoader::Load(AssetPath path) + { + std::ifstream file{ path, std::ios::in }; + + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open text File: {}", path.string()); + return nullptr; + } + std::stringstream stream; + + stream << file.rdbuf(); + + std::string content = stream.str(); + + SHAssetData* result; + + if (path.extension().string() == SCENE_EXTENSION) + { + auto data = new SHSceneAsset(); + data->name = path.stem().string(); + data->data = std::move(content); + result = data; + } + else if (path.extension().string() == PREFAB_EXTENSION) + { + auto data = new SHPrefabAsset(); + data->name = path.stem().string(); + data->data = std::move(content); + result = data; + } + else if (path.extension().string() == MATERIAL_EXTENSION) + { + auto data = new SHMaterialAsset(); + data->name = path.stem().string(); + data->data = std::move(content); + result = data; + } + + file.close(); + + return result; + } + + void SHTextBasedLoader::Write(SHAssetData const* data, AssetPath path) + { + std::ofstream file{ path, std::ios::out | std::ios::trunc }; + + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open text File: {}", path.string()); + return; + } + + if (path.extension().string() == SCENE_EXTENSION) + { + auto scene = dynamic_cast(data); + file << scene->data; + } + else if (path.extension().string() == PREFAB_EXTENSION) + { + auto prefab = dynamic_cast(data); + file << prefab->data; + } + else if (path.extension().string() == MATERIAL_EXTENSION) + { + auto material = dynamic_cast(data); + file << material->data; + } + + file.close(); + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextBasedLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextBasedLoader.h new file mode 100644 index 00000000..80771058 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextBasedLoader.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * \file Header.h + * \author Loh Xiao Qi + * \date 28 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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 "SHAssetLoader.h" + +namespace SHADE +{ + struct SHTextBasedLoader : SHAssetLoader + { + SHAssetData* Load(AssetPath path) override; + void Write(SHAssetData const* data, AssetPath path) override; + }; +} diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp index 74c08230..423301dd 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp @@ -17,42 +17,94 @@ namespace SHADE { - void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept - { - std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; - if (!file.is_open()) - { - SHLOG_ERROR("Error opening SHTexture file: {}", path.string()); - } + void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept + { + std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; + if (!file.is_open()) + { + SHLOG_ERROR("Error opening SHTexture file: {}", path.string()); + } - auto const intBytes{ sizeof(uint32_t) }; - uint32_t mipCount; + auto const intBytes{ sizeof(uint32_t) }; + uint32_t mipCount; - file.read(reinterpret_cast(&asset.numBytes), intBytes); - file.read(reinterpret_cast(&asset.width), intBytes); - file.read(reinterpret_cast(&asset.height), intBytes); - file.read(reinterpret_cast(&asset.format), sizeof(SHTexture::TextureFormat)); + file.read(reinterpret_cast(&asset.numBytes), intBytes); + file.read(reinterpret_cast(&asset.width), intBytes); + file.read(reinterpret_cast(&asset.height), intBytes); + file.read(reinterpret_cast(&asset.format), sizeof(SHTexture::TextureFormat)); - file.read(reinterpret_cast(&mipCount), intBytes); - std::vector mips(mipCount); - file.read(reinterpret_cast(mips.data()), intBytes * mipCount); + file.read(reinterpret_cast(&mipCount), intBytes); + std::vector mips(mipCount); + file.read(reinterpret_cast(mips.data()), intBytes * mipCount); - auto pixel = new SHTexture::PixelChannel[asset.numBytes]; - file.read(reinterpret_cast(pixel), asset.numBytes); + auto pixel = new SHTexture::PixelChannel[asset.numBytes]; + file.read(reinterpret_cast(pixel), asset.numBytes); - asset.mipOffsets = std::move(mips); - asset.pixelData = std::move(pixel); + asset.mipOffsets = std::move(mips); + asset.pixelData = std::move(pixel); - asset.compiled = true; - file.close(); - } + asset.compiled = true; + file.close(); + } - SHAssetData* SHTextureLoader::Load(AssetPath path) - { - auto result = new SHTextureAsset(); + SHAssetData* SHTextureLoader::Load(AssetPath path) + { + auto result = new SHTextureAsset(); - LoadSHTexture(path, *result); + LoadSHTexture(path, *result); - return result; - } + return result; + } + + void SHTextureLoader::Write(SHAssetData const* data, AssetPath path) + { + std::ofstream file{ path, std::ios::out | std::ios::binary }; + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string()); + } + + auto asset = *dynamic_cast(data); + + constexpr auto intBytes{ sizeof(uint32_t) }; + + uint32_t const mipOffsetCount{ static_cast(asset.mipOffsets.size()) }; + + file.write( + reinterpret_cast(&asset.numBytes), + intBytes + ); + + file.write( + reinterpret_cast(&asset.width), + intBytes + ); + + file.write( + reinterpret_cast(&asset.height), + intBytes + ); + + file.write( + reinterpret_cast(&asset.format), + sizeof(SHTexture::TextureFormat) + ); + + file.write( + reinterpret_cast(&mipOffsetCount), + intBytes + ); + + file.write( + reinterpret_cast(asset.mipOffsets.data()), + intBytes * asset.mipOffsets.size() + ); + + file.write( + reinterpret_cast(asset.pixelData), + asset.numBytes + ); + + file.close(); + } } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h index 00b060ec..27f7b844 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h @@ -10,8 +10,6 @@ * of DigiPen Institute of Technology is prohibited. *****************************************************************************/ #pragma once - -#include "Assets/SHAssetMacros.h" #include "Assets/Asset Types/SHTextureAsset.h" #include "SHAssetLoader.h" @@ -21,5 +19,6 @@ namespace SHADE { void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; SHAssetData* Load(AssetPath path) override; + void Write(SHAssetData const* data, AssetPath path) override; }; } diff --git a/SHADE_Engine/src/Assets/SHAsset.h b/SHADE_Engine/src/Assets/SHAsset.h index 86e8a722..a4e9847c 100644 --- a/SHADE_Engine/src/Assets/SHAsset.h +++ b/SHADE_Engine/src/Assets/SHAsset.h @@ -11,7 +11,6 @@ *****************************************************************************/ #pragma once -#include "Filesystem/SHFileSystem.h" #include "Assets/SHAssetMacros.h" #include "SH_API.h" @@ -23,6 +22,5 @@ namespace SHADE AssetID id; AssetType type; AssetPath path; - FolderLocation location; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h index 1df4e30b..a21a9840 100644 --- a/SHADE_Engine/src/Assets/SHAssetMacros.h +++ b/SHADE_Engine/src/Assets/SHAssetMacros.h @@ -47,17 +47,27 @@ enum class AssetType : AssetTypeMeta SHADER_BUILT_IN, TEXTURE, MESH, + SCENE, + PREFAB, + MATERIAL, MAX_COUNT }; constexpr size_t TYPE_COUNT{ static_cast(AssetType::MAX_COUNT) }; //Directory #ifdef _PUBLISH -constexpr std::string_view ASSET_ROOT {"Assets"}; +constexpr std::string_view ASSET_ROOT{ "Assets" }; +constexpr std::string_view BUILT_IN_ASSET_ROOT {"Built_In"}; #else constexpr std::string_view ASSET_ROOT {"../../Assets"}; +constexpr std::string_view BUILT_IN_ASSET_ROOT{ "../../Built_In" }; #endif +// INTERNAL ASSET PATHS +constexpr std::string_view SCENE_FOLDER{ "/Scenes/" }; +constexpr std::string_view PREFAB_FOLDER{ "/Prefabs/" }; +constexpr std::string_view MATERIAL_FOLDER{ "/Materials/" }; + // ASSET EXTENSIONS constexpr std::string_view META_EXTENSION {".shmeta"}; diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 228f3fdc..682eb9ec 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -10,27 +10,33 @@ #include "SHpch.h" #include #include +#include #include "SHAssetManager.h" #include "SHAssetMetaHandler.h" -#include "Filesystem/SHFileSystem.h" #include "Libraries/Loaders/SHMeshLoader.h" #include "Libraries/Loaders/SHTextureLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h" +#include "Libraries/Loaders/SHTextBasedLoader.h" #include "Libraries/Compilers/SHMeshCompiler.h" #include "Libraries/Compilers/SHTextureCompiler.h" #include "Libraries/Compilers/SHShaderSourceCompiler.h" +#include "Filesystem/SHFileSystem.h" + namespace SHADE { + FolderPointer SHAssetManager::folderRoot{ nullptr }; + FMOD::System* SHAssetManager::audioSystem; std::unordered_map* SHAssetManager::audioSoundList; std::vector SHAssetManager::loaders(TYPE_COUNT); - std::vector SHAssetManager::assetCollection; + std::unordered_map SHAssetManager::assetCollection; std::unordered_map SHAssetManager::assetData; + /**************************************************************************** * \brief Static function to generate asset ID. @@ -45,13 +51,7 @@ namespace SHADE result |= unique; - while (result == 0 || - std::ranges::any_of( - assetCollection.begin(), - assetCollection.end(), - [result](SHAsset const& asset) { return asset.id == result; } - ) - ) + while (result == 0 || assetCollection.contains(result)) { result = GenerateAssetID(type); } @@ -61,11 +61,6 @@ namespace SHADE /**************************************************************************** * \brief Deallocate all memory used by asset data ****************************************************************************/ - void SHAssetManager::Unload() noexcept - { - - } - void SHAssetManager::Unload(AssetID assetId) noexcept { // TODO @@ -73,14 +68,14 @@ namespace SHADE void SHAssetManager::Exit() noexcept { - for (auto const& loader : loaders) - { - delete loader; - } + delete loaders[static_cast(AssetType::SHADER)]; + delete loaders[static_cast(AssetType::TEXTURE)]; + delete loaders[static_cast(AssetType::MESH)]; + delete loaders[static_cast(AssetType::SCENE)]; - for (auto const& data : assetData) + for (auto const& data : std::ranges::views::values(assetData)) { - delete data.second; + delete data; } } @@ -113,8 +108,8 @@ namespace SHADE { case AssetType::SHADER: case AssetType::SHADER_BUILT_IN: - folder = "Shaders/"; - break; + folder = "Shaders/"; + break; default: folder = "/"; @@ -133,9 +128,17 @@ namespace SHADE * * \return const& to unordered_map ****************************************************************************/ - std::vector const& SHAssetManager::GetAllAssets() noexcept + std::vector SHAssetManager::GetAllAssets() noexcept { - return assetCollection; + std::vector result; + result.reserve(assetCollection.size()); + + for (auto const& asset : std::ranges::views::values(assetCollection)) + { + result.push_back(asset); + } + + return result; } /**************************************************************************** @@ -148,41 +151,113 @@ namespace SHADE ****************************************************************************/ AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept { - AssetID id{ GenerateAssetID(type) }; - SHAsset meta; - meta.id = id; - meta.type = type; + std::string newPath{ ASSET_ROOT }; + switch (type) + { + case AssetType::PREFAB: + newPath += PREFAB_FOLDER; + break; - std::string folder; - //TODO implement folder choosing - //switch (type) - //{ - //default: - // folder = ""; - // break; - //} - AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) }; + case AssetType::SCENE: + newPath += SCENE_FOLDER; + break; - SHAssetMetaHandler::WriteMetaData(meta); + case AssetType::MATERIAL: + newPath += MATERIAL_FOLDER; + break; - assetCollection.push_back(meta); + default: + SHLOG_ERROR("Asset type of {} not an internal asset type, cannot be created", name); + return 0; + } + + auto id = GenerateAssetID(type); + SHAsset asset{ + name, + id, + type, + newPath + }; + + assetCollection.insert({ + id, + SHAsset( + name, + id, + type, + newPath + ) + }); return id; } - AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept - { - AssetID id = GenerateAssetID(type); + bool SHAssetManager::SaveAsset(AssetID id) noexcept + { + if (assetCollection.contains(id)) + { + auto const& asset = assetCollection[id]; + if ( + asset.type == AssetType::SCENE || + asset.type == AssetType::PREFAB || + asset.type == AssetType::MATERIAL + ) + { + if (assetData.contains(id)) + { + auto const data = assetData.at(id); + loaders[static_cast(asset.type)]->Write(data, asset.path); + SHAssetMetaHandler::WriteMetaData(asset); + + return true; + } + + SHLOG_ERROR("Asset data has not been written into, cannot be saved: {}", + asset.path.filename().string()); + + return false; + } + } + + SHLOG_WARNING("Asset id: {} not an internal asset type, save cannot be triggered", id); + return false; + } + + bool SHAssetManager::DeleteAsset(AssetID id) noexcept + { + + if (assetCollection.contains(id)) + { + auto const& asset = assetCollection[id]; + if ( + asset.type == AssetType::SCENE || + asset.type == AssetType::PREFAB || + asset.type == AssetType::MATERIAL + ) + { + return (DeleteLocalFile(asset.path) && DeleteLocalFile(asset.path.string() + META_EXTENSION.data())); + } + SHLOG_WARNING("Asset id: {} not an internal asset type, file deletion not allowed", id); + } + + SHLOG_WARNING("Asset id does not exist, nothing was deleted: {}", id); + return false; + } + + //AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept + //{ + // AssetID id = GenerateAssetID(type); + + // assetCollection.emplace_back( + // name, + // id, + // type, + // GenerateNewPath(name, type) + // ); + // return id; + //} + - assetCollection.emplace_back( - name, - id, - type, - GenerateNewPath(name, type), - 0 - ); - return id; - } /**************************************************************************** * \brief Import new asset from outside editor window. * @@ -205,7 +280,8 @@ namespace SHADE std::filesystem::copy(path, newPath); - assetCollection.push_back(CreateAssetFromPath(newPath)); + auto asset = CreateAssetFromPath(newPath); + assetCollection.insert({asset.id, asset}); return id; } @@ -235,7 +311,7 @@ namespace SHADE std::vector SHAssetManager::GetAllRecordOfType(AssetType type) noexcept { std::vector result; - for (auto const& asset : assetCollection) + for (auto const& asset : std::ranges::views::values(assetCollection)) { if (asset.type == type) { @@ -246,26 +322,30 @@ namespace SHADE return result; } - AssetID SHAssetManager::CompileAsset(AssetPath path) noexcept + AssetID SHAssetManager::CompileAsset(AssetPath const& path) noexcept + { + SHAsset newAsset + { + .name = path.stem().string() + }; + + auto const ext{ path.extension().string() }; + if (ext == GLSL_EXTENSION.data()) + { + newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); + newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); + newAsset.type = AssetType::SHADER_BUILT_IN; + } + + assetCollection.insert({ newAsset.id, newAsset }); + SHAssetMetaHandler::WriteMetaData(newAsset); + + return newAsset.id; + } + + FolderPointer SHAssetManager::GetRootFolder() noexcept { - SHAsset newAsset - { - .name = path.stem().string(), - .location = 0 - }; - - auto const ext{ path.extension().string() }; - if (ext == GLSL_EXTENSION.data()) - { - newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); - newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); - newAsset.type = AssetType::SHADER_BUILT_IN; - } - - assetCollection.push_back(newAsset); - SHAssetMetaHandler::WriteMetaData(newAsset); - - return newAsset.id; + return folderRoot; } bool SHAssetManager::IsRecognised(char const* ext) noexcept @@ -289,82 +369,88 @@ namespace SHADE result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); result.id = GenerateAssetID(result.type); result.path = path; - result.location = 0; return result; } - void SHAssetManager::CompileAll() noexcept + void SHAssetManager::CompileAll() noexcept + { + std::vector paths; + + for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT }) + { + if (dir.is_regular_file()) + { + for (auto const& ext : EXTERNALS) + { + if (dir.path().extension().string() == ext.data()) + { + paths.push_back(dir.path()); + } + } + } + } + + for (auto const& path : paths) + { + SHAsset newAsset + { + .name = path.stem().string() + }; + + auto const ext{ path.extension().string() }; + if (ext == GLSL_EXTENSION.data()) + { + newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); + newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); + newAsset.type = AssetType::SHADER_BUILT_IN; + } + else if (ext == DDS_EXTENSION.data()) + { + newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value(); + newAsset.id = GenerateAssetID(AssetType::TEXTURE); + newAsset.type = AssetType::TEXTURE; + } + else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data()) + { + std::vector meshes; + std::vector anims; + SHMeshCompiler::LoadFromFile(path, meshes, anims); + + for (auto const& mesh : meshes) + { + SHAsset meshAsset{ + .name = mesh->header.name + }; + meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value(); + meshAsset.id = GenerateAssetID(AssetType::MESH); + meshAsset.type = AssetType::MESH; + assetCollection.insert({ meshAsset.id, meshAsset }); + SHAssetMetaHandler::WriteMetaData(meshAsset); + } + continue; + } + + assetCollection.insert({ newAsset.id, newAsset }); + SHAssetMetaHandler::WriteMetaData(newAsset); + } + } + + bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept { - std::vector paths; - - for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT }) - { - if (dir.is_regular_file()) - { - for (auto const& ext : EXTERNALS) - { - if (dir.path().extension().string() == ext.data()) - { - paths.push_back(dir.path()); - } - } - } - } - - for (auto const& path : paths) - { - SHAsset newAsset - { - .name = path.stem().string(), - .location = 0 - }; - - auto const ext{ path.extension().string() }; - if (ext == GLSL_EXTENSION.data()) - { - newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); - newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); - newAsset.type = AssetType::SHADER_BUILT_IN; - } - else if (ext == DDS_EXTENSION.data()) - { - newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value(); - newAsset.id = GenerateAssetID(AssetType::TEXTURE); - newAsset.type = AssetType::TEXTURE; - } - else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data()) - { - std::vector meshes; - std::vector anims; - SHMeshCompiler::LoadFromFile(path, meshes, anims); - - for (auto const& mesh : meshes) - { - SHAsset meshAsset{ - .name = mesh->header.name, - .location = 0 - }; - meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value(); - meshAsset.id = GenerateAssetID(AssetType::MESH); - meshAsset.type = AssetType::MESH; - assetCollection.push_back(meshAsset); - SHAssetMetaHandler::WriteMetaData(meshAsset); - } - continue; - } - - assetCollection.push_back(newAsset); - SHAssetMetaHandler::WriteMetaData(newAsset); - } + //TODO Move this to dedicated library + return std::filesystem::remove(path); } - void SHAssetManager::InitLoaders() noexcept + void SHAssetManager:: InitLoaders() noexcept { loaders[static_cast(AssetType::SHADER)] = dynamic_cast(new SHShaderSourceLoader()); loaders[static_cast(AssetType::SHADER_BUILT_IN)] = loaders[static_cast(AssetType::SHADER)]; - loaders[static_cast(AssetType::TEXTURE)] = dynamic_cast(new SHTextureLoader()); - loaders[static_cast(AssetType::MESH)] = dynamic_cast(new SHMeshLoader()); + loaders[static_cast(AssetType::TEXTURE)] = dynamic_cast(new SHTextureLoader()); + loaders[static_cast(AssetType::MESH)] = dynamic_cast(new SHMeshLoader()); + loaders[static_cast(AssetType::SCENE)] = dynamic_cast(new SHTextBasedLoader()); + loaders[static_cast(AssetType::PREFAB)] = loaders[static_cast(AssetType::SCENE)]; + loaders[static_cast(AssetType::MATERIAL)] = loaders[static_cast(AssetType::SCENE)]; } /**************************************************************************** @@ -372,9 +458,9 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::Load() noexcept { - //CompileAll(); + //CompileAll(); + BuildAssetCollection(); InitLoaders(); - BuildAssetCollection(); //LoadAllData(); } @@ -383,7 +469,7 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::LoadAllData() noexcept { - for (auto const& asset : assetCollection) + for (auto const& asset : std::ranges::views::values(assetCollection)) { SHAssetData* data = loaders[static_cast(asset.type)]->Load(asset.path); assetData.emplace(asset.id, data); @@ -406,17 +492,8 @@ namespace SHADE return data; } - void SHAssetManager::BuildAssetCollection() noexcept - { - for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT}) - { - if (dir.is_regular_file()) - { - if (dir.path().extension().string() == META_EXTENSION.data()) - { - assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path())); - } - } - } - } + void SHAssetManager::BuildAssetCollection() noexcept + { + SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection); + } } diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h index bc6f8878..64527e01 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.h +++ b/SHADE_Engine/src/Assets/SHAssetManager.h @@ -10,10 +10,12 @@ ******************************************************************************/ #pragma once #include "tinyddsloader.h" + #include "SHAsset.h" #include "Asset Types/SHAssetData.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h" -#include + +#include "Filesystem/SHFolder.h" #include "SH_API.h" @@ -26,19 +28,17 @@ namespace SHADE * \brief Static function to generate resource ID. ****************************************************************************/ static AssetID GenerateAssetID(AssetType type) noexcept; - static AssetPath GenerateLocalPath(AssetPath path) noexcept; - static AssetPath GenerateNewPath(AssetName name, AssetType type); /**************************************************************************** * \brief Deallocate all memory used by resource data ****************************************************************************/ - static void Unload() noexcept; - static void Unload(AssetID assetId) noexcept; - static void Exit() noexcept; + + static void Unload(AssetID assetId) noexcept; + /**************************************************************************** * \brief Load all resources that are in the folder ****************************************************************************/ @@ -49,7 +49,7 @@ namespace SHADE * * \return const& to unordered_map ****************************************************************************/ - static std::vector const& GetAllAssets() noexcept; + static std::vector GetAllAssets() noexcept; /**************************************************************************** * \brief Create record for new resource. CAN ONLY CREATE FOR CUSTOM @@ -59,8 +59,9 @@ namespace SHADE * \param name of resource * \return resource id generated for new asset ****************************************************************************/ - static AssetID CreateNewAsset(AssetType, AssetName) noexcept; - static AssetID CreateAsset(AssetName name, AssetType type) noexcept; + static AssetID CreateNewAsset(AssetType type, AssetName name) noexcept; + static bool SaveAsset(AssetID id) noexcept; + static bool DeleteAsset(AssetID id) noexcept; /**************************************************************************** * \brief Import new resource from outside editor window. @@ -78,12 +79,17 @@ namespace SHADE // -------------------------------------------------------------------------/ template - static std::enable_if_t, T const* const> GetData(AssetID id) noexcept; + static std::enable_if_t, T* const> GetData(AssetID id) noexcept; + + template + static std::enable_if_t, T const* const> GetConstData(AssetID id) noexcept; static std::vector GetAllDataOfType(AssetType type) noexcept; static std::vector GetAllRecordOfType(AssetType type) noexcept; - static AssetID CompileAsset(AssetPath path) noexcept; + static AssetID CompileAsset(AssetPath const& path) noexcept; + + static FolderPointer GetRootFolder() noexcept; private: @@ -98,13 +104,20 @@ namespace SHADE static void CompileAll() noexcept; + static bool DeleteLocalFile(AssetPath path) noexcept; + + //TODO use this function to create asset data internall at all calls to generate id + //static AssetID CreateAsset(AssetName name, AssetType type) noexcept; + + static FolderPointer folderRoot; + static FMOD::System* audioSystem; static std::unordered_map* audioSoundList; static std::vector loaders; // For all resources - static std::vector assetCollection; + static std::unordered_map assetCollection; static std::unordered_map assetData; }; } diff --git a/SHADE_Engine/src/Assets/SHAssetManager.hpp b/SHADE_Engine/src/Assets/SHAssetManager.hpp index 6c420778..4f372938 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.hpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.hpp @@ -4,16 +4,16 @@ namespace SHADE { template - std::enable_if_t, T const* const> SHAssetManager::GetData(AssetID id) noexcept + std::enable_if_t, T* const> SHAssetManager::GetData(AssetID id) noexcept { if (!assetData.contains(id)) { - for (auto const& asset : assetCollection) + for (auto const& asset : std::ranges::views::values(assetCollection)) { if (asset.id == id) { assetData.emplace(id, LoadData(asset)); - return dynamic_cast(assetData[id]); + return dynamic_cast(assetData[id]); } } @@ -21,6 +21,27 @@ namespace SHADE return nullptr; } - return dynamic_cast(assetData[id]); + return dynamic_cast(assetData[id]); } + + template + std::enable_if_t, T const * const> SHAssetManager::GetConstData(AssetID id) noexcept + { + if (!assetData.contains(id)) + { + for (auto const& asset : std::ranges::views::values(assetCollection)) + { + if (asset.id == id) + { + assetData.emplace(id, LoadData(asset)); + return dynamic_cast(assetData[id]); + } + } + + SHLOG_ERROR("Asset ID provided does not exist: {}", id); + return nullptr; + } + + return dynamic_cast(assetData[id]); + } } diff --git a/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp b/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp index f9849d78..ce0615e1 100644 --- a/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp +++ b/SHADE_Engine/src/Editor/DragDrop/SHDragDrop.hpp @@ -6,12 +6,12 @@ namespace SHADE { //TODO: Convert to RTTR? - constexpr auto DRAG_EID = "DragEID"; - constexpr auto DRAG_RESOURCE = "DragResource"; - struct SHDragDrop { + using DragDropTag = std::string_view; + static constexpr DragDropTag DRAG_EID = "DragEID"; + static constexpr DragDropTag DRAG_RESOURCE = "DragResource"; static bool BeginSource(ImGuiDragDropFlags const flags = 0); /** * \brief Ends the DragDrop Source. ONLY CALL IF BeginSource returns true diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp index caad9b10..8c71eb8f 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp @@ -4,14 +4,16 @@ #include "Editor/IconsMaterialDesign.h" #include "Editor/SHImGuiHelpers.hpp" #include +#include #include "Assets/SHAssetManager.h" +#include "Editor/IconsFontAwesome6.h" #include "Editor/DragDrop/SHDragDrop.hpp" namespace SHADE { SHAssetBrowser::SHAssetBrowser() - :SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar) + :SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar), rootFolder(SHAssetManager::GetRootFolder()), prevFolder(rootFolder), currentFolder(rootFolder) { } @@ -23,62 +25,140 @@ namespace SHADE void SHAssetBrowser::Update() { SHEditorWindow::Update(); - if(Begin()) + if (Begin()) { + RecursivelyDrawTree(rootFolder); DrawMenuBar(); - auto const& assets = SHAssetManager::GetAllAssets(); - if(ImGui::BeginTable("AssetBrowserTable", 3)) - { - ImGui::TableNextColumn(); - ImGui::TableHeader("Asset ID"); - ImGui::TableNextColumn(); - ImGui::TableHeader("Name"); - ImGui::TableNextColumn(); - ImGui::TableHeader("Type"); - for(SHAsset const& asset : assets) - { - DrawAsset(asset); - } - ImGui::EndTable(); - } + DrawCurrentFolder(); } ImGui::End(); } void SHAssetBrowser::DrawMenuBar() { - if(ImGui::BeginMenuBar()) + if (ImGui::BeginMenuBar()) { ImGui::EndMenuBar(); } } - void SHAssetBrowser::DrawAsset(SHAsset const& asset) + ImRect SHAssetBrowser::RecursivelyDrawTree(FolderPointer folder) { - ImGui::PushID(asset.id); - ImGui::BeginGroup(); - - ImGui::TableNextColumn(); - ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns); - if(SHDragDrop::BeginSource()) + auto const& subFolders = folder->subFolders; + auto const& files = folder->files; + const bool isSelected = std::ranges::find(selectedFolders, folder) != selectedFolders.end(); + ImGuiTreeNodeFlags flags = (subFolders.empty() && files.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow; + if (isSelected) + flags |= ImGuiTreeNodeFlags_Selected; + if (folder == rootFolder) + flags |= ImGuiTreeNodeFlags_DefaultOpen; + + bool isOpen = ImGui::TreeNodeEx(folder, flags, "%s %s", ICON_MD_FOLDER, folder->name.data()); + const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); + if(ImGui::IsItemClicked()) { - auto id = asset.id; - ImGui::Text("Moving Asset: %zu", id); - SHDragDrop::SetPayload(DRAG_RESOURCE, &id); - SHDragDrop::EndSource(); + selectedFolders.clear(); + selectedFolders.push_back(folder); + } + if (isOpen) + { + const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark); + const float horizontalOffset = 0.0f; + ImDrawList* drawList = ImGui::GetWindowDrawList(); + ImVec2 vertLineStart = ImGui::GetCursorScreenPos(); + vertLineStart.x += horizontalOffset; + ImVec2 vertLineEnd = vertLineStart; + for (auto const& subFolder : subFolders) + { + const float horizontalLineSize = 8.0f; + const ImRect childRect = RecursivelyDrawTree(subFolder); + const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f; + drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1); + vertLineEnd.y = midPoint; + } + for (auto const& file : files) + { + const float horizontalLineSize = 25.0f; + const ImRect childRect = DrawFile(file); + const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f; + drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1); + vertLineEnd.y = midPoint; + } + drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 1); + ImGui::TreePop(); + } + return nodeRect; + } + + void SHAssetBrowser::DrawCurrentFolder() + { + //auto const& subFolders = currentFolder->subFolders; + //ImVec2 initialCursorPos = ImGui::GetCursorPos(); + //ImVec2 initialRegionAvail = ImGui::GetContentRegionAvail(); + //int maxTiles = initialRegionAvail.x / tileWidth; + //float maxX = (maxTiles - 1)*tileWidth; + //ImVec2 tilePos = initialCursorPos; + //for (auto const& subFolder : subFolders) + //{ + // ImGui::SetCursorPos(tilePos); + // ImGui::BeginGroup(); + // ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, {0.0f, 0.0f}); + // ImGui::Button(ICON_MD_FOLDER, {tileWidth}); + // ImGui::Text(subFolder->name.data()); + // ImGui::PopStyleVar(); + // ImGui::EndGroup(); + // if(tilePos.x >= maxX) + // { + // tilePos.x = initialCursorPos.x; + // } + // else + // { + // ImGui::SameLine(); + // tilePos.x += tileWidth; + // } + //} + } + + ImRect SHAssetBrowser::DrawFile(SHFile const& file) noexcept + { + if (file.assetMeta == nullptr) + return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); + const bool isSelected = std::ranges::find(selectedAssets, file.assetMeta->id) != selectedAssets.end(); + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf; + if (isSelected) + flags |= ImGuiTreeNodeFlags_Selected; + std::string icon{}; + + switch(file.assetMeta->type) + { + case AssetType::INVALID: break; + case AssetType::SHADER: icon = ICON_FA_FILE_CODE; break; + case AssetType::SHADER_BUILT_IN: icon = ICON_FA_FILE_CODE; break; + case AssetType::TEXTURE: icon = ICON_FA_IMAGES; break; + case AssetType::MESH: icon = ICON_FA_CUBES; break; + case AssetType::SCENE: icon = ICON_MD_IMAGE; break; + case AssetType::PREFAB: icon = ICON_FA_BOX_OPEN; break; + case AssetType::MATERIAL: break; + case AssetType::MAX_COUNT: break; + default: ; } - ImGui::TableNextColumn(); - ImGui::Text("%s", asset.name.c_str()); - - ImGui::TableNextColumn(); - ImGui::Text("%s", "Type"); - - ImGui::EndGroup(); - ImGui::PopID(); - - - + ImGui::TreeNodeEx(file.assetMeta, flags, "%s %s", icon.data(), file.assetMeta->name.data()); + const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); + if(SHDragDrop::BeginSource()) + { + auto id = file.assetMeta->id; + ImGui::Text("Moving Asset: %s [%zu]", file.name.data(), file.assetMeta->id); + SHDragDrop::SetPayload(SHDragDrop::DRAG_RESOURCE, &id); + SHDragDrop::EndSource(); + } + if(ImGui::IsItemClicked()) + { + selectedAssets.clear(); + selectedAssets.push_back(file.assetMeta->id); + } + ImGui::TreePop(); + return nodeRect; } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h index 0e3053bc..d56fc029 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h @@ -1,7 +1,9 @@ #pragma once +#include "imgui_internal.h" #include "Assets/SHAsset.h" #include "Editor/EditorWindow/SHEditorWindow.h" +#include "Filesystem/SHFolder.h" namespace SHADE { @@ -16,9 +18,14 @@ namespace SHADE void Refresh(); private: void DrawMenuBar(); - void DrawAsset(SHAsset const& asset); + ImRect RecursivelyDrawTree(FolderPointer folder); + void DrawCurrentFolder(); + ImRect DrawFile(SHFile const& file) noexcept; - float idColumnWidth, nameColumnWidth, typeColumnWidth; + FolderPointer rootFolder, prevFolder, currentFolder; + std::vector selectedFolders; + std::vector selectedAssets; + static constexpr float tileWidth = 50.0f; }; -} \ No newline at end of file +} diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp index f2f8d927..55d78421 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp @@ -6,7 +6,7 @@ //#==============================================================# //|| SHADE Includes || //#==============================================================# -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "Editor/SHImGuiHelpers.hpp" #include "Editor/SHEditorWidgets.hpp" #include "SHHierarchyPanel.h" @@ -48,15 +48,28 @@ namespace SHADE if (Begin()) { + if (skipFrame) + { + ImGui::End(); + skipFrame = false; + return; + } DrawMenuBar(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); - if(const auto root = sceneGraph.GetRoot()) + + if (const auto root = sceneGraph.GetRoot()) { auto const& children = root->GetChildren(); - + for (const auto child : children) { - RecursivelyDrawEntityNode(child); + if (child) + RecursivelyDrawEntityNode(child); + if (skipFrame) + { + ImGui::End(); + return; + } } } else @@ -64,12 +77,36 @@ namespace SHADE SHLOG_WARNING("Scene Graph root is null! Unable to render hierarchy.") } - if(ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) + if (ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - if(auto editor = SHSystemManager::GetSystem()) + if (auto editor = SHSystemManager::GetSystem()) editor->selectedEntities.clear(); } ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal); + if (ImGui::IsWindowFocused()) + { + if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_A)) + { + SelectAllEntities(); + } + if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_C)) + { + CopySelectedEntities(); + } + if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && !ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V)) + { + PasteEntities(); + } + if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V)) + { + const auto editor = SHSystemManager::GetSystem(); + if (editor->selectedEntities.size() == 1) + { + PasteEntities(editor->selectedEntities.back()); + } + } + } + } ImGui::End(); } @@ -81,7 +118,7 @@ namespace SHADE void SHHierarchyPanel::SetScrollTo(EntityID eid) { - if(eid == MAX_EID) + if (eid == MAX_EID) return; scrollTo = eid; } @@ -93,8 +130,10 @@ namespace SHADE { if (ImGui::BeginMenuBar()) { - ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f); - if(ImGui::SmallButton(ICON_MD_DESELECT)) + auto size = ImGui::GetWindowSize(); + auto g = ImGui::GetCurrentContext(); + ImGui::SetCursorPosX(size.x - g->Style.FramePadding.x * 15.0f); + if (ImGui::SmallButton(ICON_MD_CLEAR_ALL)) { auto editor = SHSystemManager::GetSystem(); editor->selectedEntities.clear(); @@ -119,15 +158,17 @@ namespace SHADE } } - ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* currentNode) + ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode) { + if (currentNode == nullptr) + return {}; auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); //Get node data (Children, eid, selected) auto& children = currentNode->GetChildren(); EntityID eid = currentNode->GetEntityID(); - if(scrollTo != MAX_EID && eid == scrollTo) + if (scrollTo != MAX_EID && eid == scrollTo) { ImGui::SetScrollHereY(); scrollTo = MAX_EID; @@ -154,23 +195,23 @@ namespace SHADE if (SHDragDrop::BeginSource()) { std::string moveLabel = "Moving EID: "; - if(!isSelected) + if (!isSelected) editor->selectedEntities.push_back(eid); - for(int i = 0; i < static_cast(editor->selectedEntities.size()); ++i) + for (int i = 0; i < static_cast(editor->selectedEntities.size()); ++i) { moveLabel.append(std::to_string(editor->selectedEntities[i])); - if(i + 1 < static_cast(editor->selectedEntities.size())) + if (i + 1 < static_cast(editor->selectedEntities.size())) { moveLabel.append(", "); } } ImGui::Text(moveLabel.c_str()); - SHDragDrop::SetPayload>(DRAG_EID, &editor->selectedEntities); + SHDragDrop::SetPayload>(SHDragDrop::DRAG_EID, &editor->selectedEntities); SHDragDrop::EndSource(); } else if (SHDragDrop::BeginTarget()) //If Received DragDrop { - if (const std::vector* eidPayload = SHDragDrop::AcceptPayload>(DRAG_EID)) //If payload is valid + if (const std::vector* eidPayload = SHDragDrop::AcceptPayload>(SHDragDrop::DRAG_EID)) //If payload is valid { ParentSelectedEntities(eid); SHDragDrop::EndTarget(); @@ -178,37 +219,43 @@ namespace SHADE } //Context menu - if(ImGui::BeginPopupContextItem(std::to_string(eid).c_str())) + if (ImGui::BeginPopupContextItem(std::to_string(eid).c_str())) { - if(!isSelected) + if (!isSelected) { editor->selectedEntities.clear(); editor->selectedEntities.push_back(eid); } - if(ImGui::Selectable("Copy")) + if (ImGui::Selectable("Copy")) { - SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities)); + CopySelectedEntities(); } - if(ImGui::Selectable("Paste")) + if (ImGui::Selectable("Paste")) { - SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard())); + PasteEntities(); + skipFrame = true; + ImGui::EndPopup(); + if (isNodeOpen) + ImGui::TreePop(); + return nodeRect; } - if(ImGui::Selectable("Paste as Child")) + if (ImGui::Selectable("Paste as Child")) { - SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid)); + PasteEntities(eid); + skipFrame = true; } - if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) + if (ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) { SHEntityManager::DestroyEntity(eid); } - - if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) + + if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) { ParentSelectedEntities(MAX_EID); } ImGui::EndPopup(); } - + //Handle node selection if (ImGui::IsItemHovered()) { @@ -216,11 +263,11 @@ namespace SHADE { if (!isSelected) { - if(ImGui::IsKeyDown(ImGuiKey_LeftShift)) + if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - if(editor->selectedEntities.size() >= 1) + if (editor->selectedEntities.size() >= 1) { - SelectRangeOfEntities(editor->selectedEntities[0], eid); + SelectRangeOfEntities(editor->selectedEntities[0], eid); } else editor->selectedEntities.clear(); } @@ -278,12 +325,12 @@ namespace SHADE auto const editor = SHSystemManager::GetSystem(); SHEntityParentCommand::EntityParentData entityParentData; std::vector parentedEIDS; - for(auto const& eid : editor->selectedEntities) + for (auto const& eid : editor->selectedEntities) { - if(sceneGraph.GetChild(eid, parentEID) == nullptr) + if (sceneGraph.GetChild(eid, parentEID) == nullptr) { parentedEIDS.push_back(eid); - if(auto parent = sceneGraph.GetParent(eid)) + if (auto parent = sceneGraph.GetParent(eid)) entityParentData[eid].oldParentEID = parent->GetEntityID(); entityParentData[eid].newParentEID = parentEID; } @@ -298,34 +345,57 @@ namespace SHADE editor->selectedEntities.clear(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); sceneGraph.Traverse([&](SHSceneNode* nodePtr) - { - auto eid = nodePtr->GetEntityID(); - if(!startSelecting) { - if(eid == beginEID || eid == endEID) + auto eid = nodePtr->GetEntityID(); + if (!startSelecting) { - startSelecting = true; - editor->selectedEntities.push_back(eid); - } - } - else - { - if(!endSelecting) - { - editor->selectedEntities.push_back(eid); - if(eid == endEID || eid == beginEID) + if (eid == beginEID || eid == endEID) { - endSelecting = true; + startSelecting = true; + editor->selectedEntities.push_back(eid); } } - } - }); + else + { + if (!endSelecting) + { + editor->selectedEntities.push_back(eid); + if (eid == endEID || eid == beginEID) + { + endSelecting = true; + } + } + } + }); + } + + void SHHierarchyPanel::SelectAllEntities() + { + const auto editor = SHSystemManager::GetSystem(); + editor->selectedEntities.clear(); + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + sceneGraph.Traverse([&](SHSceneNode* nodePtr) + { + auto eid = nodePtr->GetEntityID(); + editor->selectedEntities.push_back(eid); + }); + } + + void SHHierarchyPanel::CopySelectedEntities() + { + const auto editor = SHSystemManager::GetSystem(); + SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities)); + } + + void SHHierarchyPanel::PasteEntities(EntityID parentEID) + { + SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), parentEID)); } void SHCreateEntityCommand::Execute() { EntityID newEID = SHEntityManager::CreateEntity(eid); - if(eid == MAX_EID) + if (eid == MAX_EID) eid = newEID; } @@ -337,9 +407,9 @@ namespace SHADE void SHEntityParentCommand::Execute() { auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); - for(auto const& eid : entities) + for (auto const& eid : entities) { - if(entityParentData[eid].newParentEID == MAX_EID) + if (entityParentData[eid].newParentEID == MAX_EID) sceneGraph.SetParent(eid, nullptr); else sceneGraph.SetParent(eid, entityParentData[eid].newParentEID); @@ -349,9 +419,9 @@ namespace SHADE void SHEntityParentCommand::Undo() { auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); - for(auto const& eid : entities) + for (auto const& eid : entities) { - if(entityParentData[eid].oldParentEID == MAX_EID) + if (entityParentData[eid].oldParentEID == MAX_EID) sceneGraph.SetParent(eid, nullptr); else sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID); diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h index 0cfe6474..9b26e9d6 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h @@ -26,10 +26,14 @@ namespace SHADE void SetScrollTo(EntityID eid); private: void DrawMenuBar() const noexcept; - ImRect RecursivelyDrawEntityNode(SHSceneNode*); + ImRect RecursivelyDrawEntityNode(SHSceneNode* const); void CreateChildEntity(EntityID parentEID) const noexcept; void ParentSelectedEntities(EntityID parentEID) const noexcept; void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID); + void SelectAllEntities(); + void CopySelectedEntities(); + void PasteEntities(EntityID parentEID = MAX_EID); + bool skipFrame = false; std::string filter; bool isAnyNodeSelected = false; EntityID scrollTo = MAX_EID; diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.h b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.h new file mode 100644 index 00000000..69f4c145 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.h @@ -0,0 +1,12 @@ +#pragma once +#include "ECS_Base/Components/SHComponent.h" + +namespace SHADE +{ + template::value, bool> = true> + static void DrawContextMenu(T* component); + template, bool> = true> + static void DrawComponent(T* component); +} + +#include "SHEditorComponentView.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 4645bf52..521e1213 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -13,11 +13,28 @@ #include "Editor/IconsFontAwesome6.h" #include "ECS_Base/Components/SHComponent.h" #include "Editor/SHEditorWidgets.hpp" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Physics/Components/SHColliderComponent.h" #include "Reflection/SHReflectionMetadata.h" +#include "Resource/SHResourceManager.h" + namespace SHADE { - template::value, bool> = true> + template + std::vector GetRTTREnumNames() + { + auto const rttrType = rttr::type::get(); + if (!rttrType.is_enumeration()) + return {}; + auto const enumAlign = rttrType.get_enumeration(); + auto const names = enumAlign.get_names(); + std::vector result; + std::transform(names.begin(), names.end(), std::back_inserter(result), [](rttr::string_view const& name) {return name.data(); }); + return result; + } + + template::value, bool>> static void DrawContextMenu(T* component) { if (!component) @@ -46,13 +63,15 @@ namespace SHADE ImGui::EndPopup(); } } - template, bool> = true> + template, bool>> static void DrawComponent(T* component) { if (!component) return; - const auto componentType = rttr::type::get(*component); + const auto componentType = rttr::type::get(); + ImGui::PushID(SHFamilyID::GetID()); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); + ImGui::PopID(); ImGui::SameLine(); if (ImGui::CollapsingHeader(componentType.get_name().data())) { @@ -61,7 +80,8 @@ namespace SHADE for (auto const& property : properties) { auto const& type = property.get_type(); - + auto tooltip = property.get_metadata(META::tooltip); + bool const& isAngleInRad = property.get_metadata(META::angleInRad).is_valid() ? property.get_metadata(META::angleInRad).template get_value() : false; if (type.is_enumeration()) { auto enumAlign = type.get_enumeration(); @@ -75,29 +95,25 @@ namespace SHADE auto values = enumAlign.get_values(); auto it = std::next(values.begin(), idx); property.set_value(component, *it); - }); + }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } else if (type.is_arithmetic()) { if (type == rttr::type::get()) { - SHEditorWidgets::CheckBox(property.get_name().data(), [component, property] {return property.get_value(component).to_bool(); }, [component, property](bool const& result) {property.set_value(component, result); }); + SHEditorWidgets::CheckBox(property.get_name().data(), [component, property] {return property.get_value(component).to_bool(); }, [component, property](bool const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } - //else if (type == rttr::type::get()) - //{ - // - //} else if (type == rttr::type::get() || type == rttr::type::get() || type == rttr::type::get() || type == rttr::type::get()) { auto metaMin = property.get_metadata(META::min); auto metaMax = property.get_metadata(META::max); if (metaMin && metaMax) { - SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }); + SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } else { - SHEditorWidgets::DragInt(property.get_name().data(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }); + SHEditorWidgets::DragInt(property.get_name().data(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } else if (type == rttr::type::get()) @@ -106,11 +122,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if (metaMin.is_valid() && metaMax.is_valid()) { - SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, "%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string(), "%zu"); } else { - SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U8, [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U8, [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } else if (type == rttr::type::get()) @@ -119,11 +135,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if (metaMin.is_valid() && metaMax.is_valid()) { - SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string(), "%zu"); } else { - SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U16, [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U16, [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } else if (type == rttr::type::get()) @@ -132,11 +148,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if (metaMin.is_valid() && metaMax.is_valid()) { - SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value(), metaMax.template get_value(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value(), metaMax.template get_value(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string(), "%zu"); } else { - SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U32, [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U32, [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } else if (type == rttr::type::get()) @@ -145,11 +161,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if (metaMin.is_valid() && metaMax.is_valid()) { - SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string(), "%zu"); } else { - SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U64, [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U64, [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } else if (type == rttr::type::get()) @@ -157,17 +173,17 @@ namespace SHADE auto metaMin = property.get_metadata(META::min); auto metaMax = property.get_metadata(META::max); float min{}, max{}; - if(metaMin.is_valid()) + if (metaMin.is_valid()) min = std::max(metaMin.template get_value(), -FLT_MAX * 0.5f); - if(metaMax.is_valid()) + if (metaMax.is_valid()) max = std::min(metaMax.template get_value(), FLT_MAX * 0.5f); if (metaMin.is_valid() && metaMax.is_valid()) { - SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }); + SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } else { - SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, "Test"); + SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } else if (type == rttr::type::get()) @@ -176,25 +192,25 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if (metaMin.is_valid() && metaMax.is_valid()) { - SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value(), metaMax.template get_value(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } else { - SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_Double, [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, 0.1f); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_Double, [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, 0.1f, {}, {}, "%.3f", tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } } else if (type == rttr::type::get()) { - SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }); + SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }, isAngleInRad, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } else if (type == rttr::type::get()) { - SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }); + SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }, isAngleInRad, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } else if (type == rttr::type::get()) { - SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); }); + SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); }, isAngleInRad, tooltip.is_valid() ? tooltip.template get_value() : std::string()); } } @@ -209,10 +225,10 @@ namespace SHADE return; // Get transform component for extrapolating relative sizes - auto* transformComponent = SHComponentManager::GetComponent(component->GetEID()); + auto* transformComponent = SHComponentManager::GetComponent_s(component->GetEID()); const auto componentType = rttr::type::get(*component); - SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); + 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())) { @@ -220,8 +236,8 @@ namespace SHADE auto& colliders = component->GetColliders(); int const size = static_cast(colliders.size()); - ImGui::BeginChild("Colliders", {0.0f, colliders.empty() ? 1.0f : 250.0f}, true); - std::optional colliderToDelete{std::nullopt}; + ImGui::BeginChild("Colliders", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true); + std::optional colliderToDelete{ std::nullopt }; for (int i{}; i < size; ++i) { ImGui::PushID(i); @@ -230,12 +246,12 @@ namespace SHADE if (collider->GetType() == SHCollider::Type::BOX) { - SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); + SHEditorWidgets::BeginPanel(std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); auto box = reinterpret_cast(collider->GetShape()); SHEditorWidgets::DragVec3 ( - "Half Extents", { "X", "Y", "Z" }, - [box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); }, + "Half Extents", { "X", "Y", "Z" }, + [box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); }, [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } else if (collider->GetType() == SHCollider::Type::SPHERE) @@ -244,14 +260,14 @@ namespace SHADE auto sphere = reinterpret_cast(collider->GetShape()); SHEditorWidgets::DragFloat ( - "Radius", + "Radius", [sphere, transformComponent] { const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale(); const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); return sphere->GetRadius() / MAX_SCALE; - }, - [collider](float const& value) { collider->SetBoundingSphere(value);}); + }, + [collider](float const& value) { collider->SetBoundingSphere(value); }); } else if (collider->GetType() == SHCollider::Type::CAPSULE) { @@ -262,14 +278,14 @@ namespace SHADE SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); SHEditorWidgets::EndPanel(); } - if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) + if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) { colliderToDelete = i; } SHEditorWidgets::EndPanel(); ImGui::PopID(); } - if(colliderToDelete.has_value()) + if (colliderToDelete.has_value()) { component->RemoveCollider(colliderToDelete.value()); } @@ -277,11 +293,11 @@ namespace SHADE if (ImGui::BeginMenu("Add Collider")) { - if(ImGui::Selectable("Box Collider")) + if (ImGui::Selectable("Box Collider")) { component->AddBoundingBox(); } - if(ImGui::Selectable("Sphere Collider")) + if (ImGui::Selectable("Sphere Collider")) { component->AddBoundingSphere(); } @@ -290,4 +306,63 @@ namespace SHADE } else DrawContextMenu(component); } -} \ No newline at end of file + + template<> + static void DrawComponent(SHLightComponent* component) + { + if (!component) + return; + 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); + + static auto const enumAlign = rttr::type::get().get_enumeration(); + static std::vector list(GetRTTREnumNames()); + + SHEditorWidgets::ComboBox("Type", list, [component] {return static_cast(component->GetType()); }, [component](int const& idx) + { + component->SetType(static_cast(idx)); + }); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component]() {return component->GetPosition(); }, [component](SHVec3 const& vec) {component->SetPosition(vec); }); + SHEditorWidgets::DragVec3("Direction", { "X", "Y", "Z" }, [component]() {return component->GetDirection(); }, [component](SHVec3 const& vec) {component->SetDirection(vec); }); + SHEditorWidgets::ColorPicker("Color", [component]() {return component->GetColor(); }, [component](SHVec4 const& rgba) {component->SetColor(rgba); }); + SHEditorWidgets::DragFloat("Strength", [component]() {return component->GetStrength(); }, [component](float const& value) {component->SetStrength(value); }); + } + else + { + DrawContextMenu(component); + } + } + + template<> + static void DrawComponent(SHRenderable* component) + { + if (!component) + return; + 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& mesh = component->GetMesh(); + + SHEditorWidgets::DragDropReadOnlyField("Mesh", std::to_string(SHResourceManager::GetAssetID(mesh).value_or(0)).data(), [component]() + { + Handle const& mesh = component->GetMesh(); + return SHResourceManager::GetAssetID(mesh).value_or(0); + }, + [component](AssetID const& id) + { + component->SetMesh(SHResourceManager::LoadOrGet(id)); + }, SHDragDrop::DRAG_RESOURCE); + } + else + { + DrawContextMenu(component); + } + } +} diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 42b516aa..c4a86785 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -1,6 +1,6 @@ #include "SHpch.h" -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "SHEditorInspector.h" #include "ECS_Base/SHECSMacros.h" @@ -10,17 +10,14 @@ #include "Editor/SHImGuiHelpers.hpp" #include "Editor/SHEditorWidgets.hpp" -#include "SHEditorComponentView.hpp" -#include "ECS_Base/UnitTesting/SHTestComponents.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Scripting/SHScriptEngine.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "ECS_Base/Managers/SHSystemManager.h" -#include "AudioSystem/SHAudioSystem.h" #include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Components/SHColliderComponent.h" #include "Camera/SHCameraComponent.h" +#include "SHEditorComponentView.h" namespace SHADE { @@ -30,8 +27,17 @@ namespace SHADE bool selected = false; if(!SHComponentManager::HasComponent(eid)) { - if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get().get_name().data()).data()); selected) + const char* componentName = rttr::type::get().get_name().data(); + if(selected = ImGui::Selectable(std::format("Add {}", componentName).data()); selected) SHComponentManager::AddComponent(eid); + if(ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Adds", componentName); ImGui::SameLine(); + ImGui::TextColored(ImGuiColors::green, "%s", componentName); ImGui::SameLine(); + ImGui::Text("to this entity", componentName); + ImGui::EndTooltip(); + } } return selected; } @@ -42,13 +48,26 @@ namespace SHADE bool selected = false; if (!SHComponentManager::HasComponent(eid)) { - if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get().get_name().data()).data()); selected) + const char* componentName = rttr::type::get().get_name().data(); + + if(selected = ImGui::Selectable(std::format("Add {}", componentName).data()); selected) { if(SHComponentManager::GetComponent_s(eid) == nullptr) SHComponentManager::AddComponent(eid); SHComponentManager::AddComponent(eid); } + if(ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Adds", componentName); ImGui::SameLine(); + ImGui::TextColored(ImGuiColors::green, "%s", componentName); ImGui::SameLine(); + ImGui::Text("to this entity", componentName); + ImGui::Text("Adds"); ImGui::SameLine(); + ImGui::TextColored(ImGuiColors::red, "%s", rttr::type::get().get_name().data()); ImGui::SameLine(); + ImGui::Text("if the entity does not already have it"); + ImGui::EndTooltip(); + } } return selected; } @@ -100,6 +119,10 @@ namespace SHADE { DrawComponent(rigidbodyComponent); } + if(auto lightComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(lightComponent); + } if (auto cameraComponent = SHComponentManager::GetComponent_s(eid)) { DrawComponent(cameraComponent); @@ -113,6 +136,7 @@ namespace SHADE { DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); // Components that require Transforms diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index c33f4fb6..50b878a8 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -3,7 +3,7 @@ //#==============================================================# //|| SHADE Includes || //#==============================================================# -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "SHEditorMenuBar.h" #include "Editor/IconsMaterialDesign.h" #include "Editor/Command/SHCommandManager.h" diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp index f5170999..d6ef8d19 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp @@ -5,13 +5,16 @@ #include "ImGuizmo.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/IconsMaterialDesign.h" -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" #include +#include "Camera/SHCameraSystem.h" +#include "FRC/SHFramerateController.h" + constexpr std::string_view windowName = "\xef\x80\x95 Viewport"; namespace SHADE @@ -30,8 +33,15 @@ namespace SHADE void SHEditorViewport::Update() { SHEditorWindow::Update(); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f)); - if(Begin()) + if (shouldUpdateCamera) + { + auto camSystem = SHSystemManager::GetSystem(); + camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime()); + shouldUpdateCamera = false; + } + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + + if (Begin()) { ImGuizmo::SetDrawlist(); DrawMenuBar(); @@ -39,21 +49,38 @@ namespace SHADE auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0]; auto mousePos = ImGui::GetMousePos(); beginCursorPos = ImGui::GetCursorScreenPos(); - viewportMousePos = {mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y}; - gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos); + viewportMousePos = { mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y }; + gfxSystem->GetMousePickSystem()->SetViewportMousePos(viewportMousePos); - ImGui::Image((ImTextureID)descriptorSet, {beginContentRegionAvailable.x, beginContentRegionAvailable.y}); + ImGui::Image((ImTextureID)descriptorSet, { beginContentRegionAvailable.x, beginContentRegionAvailable.y }); - if(ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right)) + if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right)) { ImGui::SetMouseCursor(ImGuiMouseCursor_None); ImGui::SetCursorScreenPos(ImGui::GetMousePos()); ImGui::PushStyleColor(ImGuiCol_Text, ImGuiColors::green); ImGui::Text(ICON_FA_EYE); ImGui::PopStyleColor(); + + shouldUpdateCamera = true; + } + if (ImGui::IsWindowFocused() && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) + { + if (ImGui::IsKeyReleased(ImGuiKey_Q)) + { + transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE; + } + if (ImGui::IsKeyReleased(ImGuiKey_W)) + { + transformGizmo.operation = SHTransformGizmo::Operation::ROTATE; + } + if (ImGui::IsKeyReleased(ImGuiKey_E)) + { + transformGizmo.operation = SHTransformGizmo::Operation::SCALE; + } } } - ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y); + ImGuizmo::SetRect(beginCursorPos.x, beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y); transformGizmo.Draw(); ImGui::End(); ImGui::PopStyleVar(); @@ -72,11 +99,12 @@ namespace SHADE //auto pos = ImGui::GetCursorPos(); //windowCursorPos = {} - if(beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0) + if (beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0) { - beginContentRegionAvailable = windowSize; + beginContentRegionAvailable = windowSize; } gfxSystem->PrepareResize(static_cast(beginContentRegionAvailable.x), static_cast(beginContentRegionAvailable.y)); + shouldUpdateCamera = true; } void SHEditorViewport::OnPosChange() @@ -86,44 +114,63 @@ namespace SHADE void SHEditorViewport::DrawMenuBar() noexcept { - if(ImGui::BeginMenuBar()) + if (ImGui::BeginMenuBar()) { + ImGui::BeginDisabled(ImGui::IsWindowFocused() && ImGui::IsMouseDown(ImGuiMouseButton_Right)); bool const isTranslate = transformGizmo.operation == SHTransformGizmo::Operation::TRANSLATE; ImGui::BeginDisabled(isTranslate); - if(isTranslate) + if (isTranslate) ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]); - if(ImGui::Button(ICON_MD_OPEN_WITH)) + if (ImGui::Button(ICON_MD_OPEN_WITH)) { transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE; } ImGui::EndDisabled(); - if(isTranslate) + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + { + ImGui::BeginTooltip(); + ImGui::Text("Translate [Q]"); + ImGui::EndTooltip(); + } + if (isTranslate) ImGui::PopStyleColor(); bool const isRotate = transformGizmo.operation == SHTransformGizmo::Operation::ROTATE; ImGui::BeginDisabled(isRotate); - if(isRotate) + if (isRotate) ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]); - if(ImGui::Button(ICON_MD_AUTORENEW)) + if (ImGui::Button(ICON_MD_AUTORENEW)) { transformGizmo.operation = SHTransformGizmo::Operation::ROTATE; } ImGui::EndDisabled(); - if(isRotate) + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + { + ImGui::BeginTooltip(); + ImGui::Text("Rotate [W]"); + ImGui::EndTooltip(); + } + if (isRotate) ImGui::PopStyleColor(); bool const isScale = transformGizmo.operation == SHTransformGizmo::Operation::SCALE; ImGui::BeginDisabled(isScale); - if(isScale) + if (isScale) ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]); - if(ImGui::Button(ICON_MD_EXPAND)) + if (ImGui::Button(ICON_MD_EXPAND)) { transformGizmo.operation = SHTransformGizmo::Operation::SCALE; } ImGui::EndDisabled(); - if(isScale) + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + { + ImGui::BeginTooltip(); + ImGui::Text("Scale [E]"); + ImGui::EndTooltip(); + } + if (isScale) ImGui::PopStyleColor(); - + ImGui::EndDisabled(); ImGui::EndMenuBar(); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h index 80b13285..0fae4317 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h +++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h @@ -14,7 +14,7 @@ namespace SHADE { - class SHEditorViewport final : public SHEditorWindow + class SHEditorViewport final : public SHEditorWindow { public: SHEditorViewport(); @@ -28,5 +28,6 @@ namespace SHADE private: void DrawMenuBar() noexcept; SHVec2 beginCursorPos; + bool shouldUpdateCamera = false; };//class SHEditorViewport }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp index 3c984051..e3bbc809 100644 --- a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp +++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp @@ -3,7 +3,7 @@ #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "Editor/SHImGuiHelpers.hpp" #include #include @@ -63,6 +63,9 @@ namespace SHADE if (selectedEntityTransformComponent == nullptr) return; + if(!selectedEntityTransformComponent->isActive) + return; + SHMatrix mat = selectedEntityTransformComponent->GetTRS(); useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl); if(useSnap) diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 06fadfee..cf5056a5 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -21,7 +21,7 @@ #include "Graphics/MiddleEnd/Interface/SHViewport.h" #include "Graphics/MiddleEnd/Interface/SHRenderer.h" -#include "SHEditor.hpp" +#include "SHEditor.h" #include "SHEditorWidgets.hpp" #include "Math/Transform/SHTransformSystem.h" @@ -175,7 +175,7 @@ namespace SHADE ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f; constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path - constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_MD, 0 }; + constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 }; ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path io->Fonts->Build(); } @@ -293,6 +293,7 @@ namespace SHADE //#==============================================================# void SHEditor::InitBackend() { +#ifdef SHEDITOR if(ImGui_ImplSDL2_InitForVulkan(sdlWindow) == false) { SHLOG_CRITICAL("Editor backend initialisation; Failed to perform SDL initialisation for Vulkan") @@ -339,6 +340,7 @@ namespace SHADE renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle& cmd) { ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); }); +#endif } void SHEditor::PollPicking() diff --git a/SHADE_Engine/src/Editor/SHEditor.hpp b/SHADE_Engine/src/Editor/SHEditor.h similarity index 100% rename from SHADE_Engine/src/Editor/SHEditor.hpp rename to SHADE_Engine/src/Editor/SHEditor.h diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index b54a6799..053348d7 100644 --- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp +++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp @@ -22,6 +22,8 @@ #include #include +#include "DragDrop/SHDragDrop.hpp" + namespace SHADE { class SH_API SHEditorWidgets @@ -41,7 +43,7 @@ namespace SHADE ImGui::BeginGroup(); auto itemSpacing = ImGui::GetStyle().ItemSpacing; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.2f)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); auto frameHeight = ImGui::GetFrameHeight(); @@ -86,7 +88,7 @@ namespace SHADE auto itemSpacing = ImGui::GetStyle().ItemSpacing; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.2f)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); auto frameHeight = ImGui::GetFrameHeight(); @@ -127,7 +129,7 @@ namespace SHADE ImGui::GetWindowDrawList()->AddRect( frameRect.Min, frameRect.Max, - ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Button)), + ImColor(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)), halfFrame.x); ImGui::PopClipRect(); @@ -174,15 +176,19 @@ namespace SHADE ImGui::SetColumnWidth(-1, 80.0f); ImGui::Text(label.c_str()); if (isHovered) - *isHovered = ImGui::IsItemHovered(); + *isHovered |= ImGui::IsItemHovered(); ImGui::NextColumn(); for (std::size_t i = 0; i < N; ++i) { ImGui::PushID(static_cast(i)); - ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine(); + ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); + if (isHovered) + *isHovered |= ImGui::IsItemHovered(); + ImGui::SameLine(); ImGui::SetNextItemWidth(80.0f); valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags); - + if (isHovered) + *isHovered |= ImGui::IsItemHovered(); const ImVec2 min = ImGui::GetItemRectMin(); const ImVec2 max = ImGui::GetItemRectMax(); const float spacing = g.Style.FrameRounding; @@ -192,8 +198,8 @@ namespace SHADE ImGuiColors::colors[i], 4); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); ImGui::PopItemWidth(); + ImGui::PopID(); } ImGui::EndColumns(); ImGui::PopID(); @@ -203,23 +209,31 @@ namespace SHADE } static bool DragVec2(const std::string& label, std::vectorconst& componentLabels, std::function get, - std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f, + std::function set, bool const& isAnAngleInRad = false, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, ImGuiSliderFlags flags = 0) { SHVec2 values = get(); + if(isAnAngleInRad) + { + values = {SHMath::RadiansToDegrees(values.x), SHMath::RadiansToDegrees(values.y)}; + } bool const changed = DragN(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags); static bool startRecording = false; if (changed) { + if(isAnAngleInRad) + { + values = {SHMath::DegreesToRadians(values.x), SHMath::DegreesToRadians(values.y)}; + } SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), startRecording); if (!startRecording) startRecording = true; } if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) startRecording = false; - if(!tooltip.empty()) + if (!tooltip.empty()) { - if(ImGui::IsItemHovered()) + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text(tooltip.data()); @@ -230,17 +244,24 @@ namespace SHADE } static bool DragVec3(const std::string& label, std::vectorconst& componentLabels, std::function get, - std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f, + std::function set, bool const& isAnAngleInRad = false, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, ImGuiSliderFlags flags = 0) { SHVec3 values = get(); - bool const changed = DragN(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags); - - + if(isAnAngleInRad) + { + values = {SHMath::RadiansToDegrees(values.x), SHMath::RadiansToDegrees(values.y), SHMath::RadiansToDegrees(values.z)}; + } + bool isHovered = false; + bool const changed = DragN(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags, &isHovered); static bool startRecording = false; if (changed) { SHVec3 old = get(); + if(isAnAngleInRad) + { + values = {SHMath::DegreesToRadians(values.x), SHMath::DegreesToRadians(values.y), SHMath::DegreesToRadians(values.z)}; + } SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(old, values, set)), startRecording); if (!startRecording) startRecording = true; @@ -249,9 +270,9 @@ namespace SHADE { startRecording = false; } - if(!tooltip.empty()) + if (!tooltip.empty()) { - if(ImGui::IsItemHovered()) + if (isHovered) { ImGui::BeginTooltip(); ImGui::Text(tooltip.data()); @@ -262,14 +283,22 @@ namespace SHADE } static bool DragVec4(const std::string& label, std::vectorconst& componentLabels, std::function get, - std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f, + std::function set, bool const& isAnAngleInRad = false, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, ImGuiSliderFlags flags = 0) { SHVec4 values = get(); + if(isAnAngleInRad) + { + values = {SHMath::RadiansToDegrees(values.x), SHMath::RadiansToDegrees(values.y), SHMath::RadiansToDegrees(values.z), SHMath::RadiansToDegrees(values.w)}; + } bool const changed = DragN(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags); static bool startRecording = false; if (changed) { + if(isAnAngleInRad) + { + values = {SHMath::DegreesToRadians(values.x), SHMath::DegreesToRadians(values.y), SHMath::DegreesToRadians(values.z), SHMath::DegreesToRadians(values.w)}; + } SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), startRecording); if (!startRecording) startRecording = true; @@ -278,9 +307,9 @@ namespace SHADE { startRecording = false; } - if(!tooltip.empty()) + if (!tooltip.empty()) { - if(ImGui::IsItemHovered()) + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text(tooltip.data()); @@ -297,7 +326,7 @@ namespace SHADE static void TextLabel(std::string_view const& text, bool sameLine = true) { const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true); - if(textSize.x > 0.0f) + if (textSize.x > 0.0f) { ImGui::Text(text.data()); ImGui::SameLine(); @@ -310,32 +339,32 @@ namespace SHADE ImGui::BeginGroup(); ImGui::PushID(label.data()); TextLabel(label); - if (ImGui::Checkbox("##", &value)) + bool const changed = ImGui::Checkbox("##", &value); + if (changed) { SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - return true; } ImGui::PopID(); ImGui::EndGroup(); - if(!tooltip.empty()) + if (!tooltip.empty()) { - if(ImGui::IsItemHovered()) + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text(tooltip.data()); ImGui::EndTooltip(); } } - return false; + return changed; } template - static bool RadioButton(std::vector const& label, std::vector const& listTypes, std::function get, std::function set ,std::string_view const& tooltip = {}) + static bool RadioButton(std::vector const& label, std::vector const& listTypes, std::function get, std::function set, std::string_view const& tooltip = {}) { T type = get(); ImGui::BeginGroup(); ImGui::PushID(label.data()); - TextLabel(label); + //TextLabel(label); for (size_t i = 0; i < listTypes.size(); i++) { if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i])) @@ -366,12 +395,11 @@ namespace SHADE ImGui::BeginGroup(); ImGui::PushID(label.data()); TextLabel(label); - if (ImGui::InputText("##", &text, flag, callback, userData)) + bool const changed = ImGui::InputText("##", &text, flag, callback, userData); + if (changed) { if (ImGui::IsItemDeactivatedAfterEdit()) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), text, set)), false); - - return true; } ImGui::PopID(); ImGui::EndGroup(); @@ -384,7 +412,37 @@ namespace SHADE ImGui::EndTooltip(); } } - return false; + return changed; + } + + template + static bool DragDropReadOnlyField(std::string const& label, std::string_view const& fieldVTextValue, std::function const& get, std::function const& set, SHDragDrop::DragDropTag const& dragDropTag, std::string_view const& tooltip = {}) + { + std::string text = fieldVTextValue.data(); + ImGui::BeginGroup(); + ImGui::PushID(label.data()); + TextLabel(label); + bool const changed = ImGui::InputText("##", &text, ImGuiInputTextFlags_ReadOnly, nullptr, nullptr); + if(SHDragDrop::BeginTarget()) + { + if(T* payload = SHDragDrop::AcceptPayload(dragDropTag)) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), *payload, set)), false); + SHDragDrop::EndTarget(); + } + } + ImGui::PopID(); + ImGui::EndGroup(); + if (!tooltip.empty()) + { + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text(tooltip.data()); + ImGui::EndTooltip(); + } + } + return changed; } template @@ -442,9 +500,9 @@ namespace SHADE } ImGui::PopID(); ImGui::EndGroup(); - if(!tooltip.empty()) + if (!tooltip.empty()) { - if(ImGui::IsItemHovered()) + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text(tooltip.data()); @@ -615,5 +673,43 @@ namespace SHADE } return edited; } + + static bool ColorPicker(const std::string_view& label, std::function get, std::function set, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, + ImGuiSliderFlags flags = 0) + { + bool changed = false; + ImGui::BeginGroup(); + ImGui::PushID(label.data()); + + SHVec4 values = get(); + //changed |= DragN(label.data(), {"R", "G", "B", "A"}, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags); + //ImGui::SameLine(); + TextLabel(label); + changed = ImGui::ColorEdit4("##Col4", &values.x, ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_DisplayRGB ); + static bool startRecording = false; + if(changed) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), startRecording); + if(!startRecording) + startRecording = true; + } + if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) + { + startRecording = false; + } + ImGui::PopID(); + ImGui::EndGroup(); + if (!tooltip.empty()) + { + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text(tooltip.data()); + ImGui::EndTooltip(); + } + } + return changed; + } }; + }//namespace SHADE diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp index bd34ed71..4c0971e6 100644 --- a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp @@ -1,159 +1,82 @@ +/*************************************************************************//** + * \file SHFileSystem.cpp + * \author Loh Xiao Qi + * \date 30 October 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. + *****************************************************************************/ #include "SHpch.h" #include "SHFileSystem.h" -#include "fileapi.h" #include #include +#include "Assets/SHAssetMetaHandler.h" + namespace SHADE { - char const FOLDER_MAX_COUNT {15}; - - std::unordered_map> SHFileSystem::folders; - FolderPointer SHFileSystem::root {nullptr}; - - SHFolder::SHFolder(FolderHandle id, FolderName name) - :id{ id }, name{ name }, subFolders(0), folded{ false }, path{""} - { - } - - FolderLocation SHFileSystem::CreateNewFolderHere(FolderName name, FolderLocation here) noexcept - { - if (here == 0) - { - if (!folders.contains(0)) - { - folders[0] = std::make_unique(0, "root"); - } - - auto const count = static_cast(folders[here]->subFolders.size()); - - if (count >= FOLDER_MAX_COUNT) - { - SHLOG_ERROR("Max subfolder reached: {}\n", name); - } - - auto const location = static_cast(count); - - CreateFolder(folders[0]->path, here, location, name); - - return location; - } - - if (!folders.contains(here)) - { - SHLOG_ERROR("Folder creation location does not exist/invalid: {}\n", here); - } - - auto const count = static_cast(folders[here]->subFolders.size()); - - FolderHandle location = here; - location <<= FOLDER_BIT_ALLOCATE; - location |= count; - - if (count >= FOLDER_MAX_COUNT) - { - SHLOG_ERROR("Max subfolder reached: {}\n", name); - } - - CreateFolder(folders[0]->path, here, location, name); - - return location; - } bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept { - if (!folders.contains(location->id)) - { - SHLOG_ERROR("Delete target does not exist/invalid: {}\n", location->name); - } - - for (auto const& subFolder : folders[location->id]->subFolders) - { - DeleteFolder(subFolder); - } - - RemoveDirectoryA(folders[location->id]->path.c_str()); + //TODO IMPLEMENT return true; } - void SHFileSystem::StartupFillDirectories(FolderPath path) noexcept + void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map& assetCollection) noexcept { std::queue folderQueue; - - folderQueue.push(RegisterFolder(path, 0, 0, "Root")); + root = new SHFolder("root"); + root->path = path; + folderQueue.push(root); while (!folderQueue.empty()) { - auto folder = folderQueue.front(); + auto const folder = folderQueue.front(); folderQueue.pop(); - FolderCounter count = 0; + + std::vector assets; for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path)) { + auto const& path = dirEntry.path(); if (!dirEntry.is_directory()) { - folder->files.emplace_back( - dirEntry.path().filename().string(), - dirEntry.path().string(), - dirEntry.path().extension().string() - ); - - continue; + if (path.extension().string() == META_EXTENSION) + { + //auto asset = SHAssetMetaHandler::RetrieveMetaData(path); + //assetCollection.insert({ asset.id, asset }); + assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path)); + } + else + { + folder->files.emplace_back( + path.stem().string(), + path.string(), + path.extension().string(), + nullptr + ); + } + continue; } - FolderLocation location = folder->id; - location <<= FOLDER_BIT_ALLOCATE; - location |= ++count; - - std::string name = dirEntry.path().string(); - name = name.substr(name.find_last_of('/') + 1, name.length() - name.find_last_of('/')); - - FolderPointer newFolder{ RegisterFolder( - dirEntry.path().string(), - folder->id, - location, - name) - }; - - folderQueue.push(newFolder); - folder->subFolders.push_back(newFolder); + auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) }; + folderQueue.push(newFolder); } + + for (auto const& asset : assets) + { + assetCollection.emplace(asset.id, asset); + for(auto& file : folder->files) + { + if (file.name == asset.name) + { + file.assetMeta = &assetCollection[asset.id]; + break; + } + } + } } } - - FolderPointer SHFileSystem::GetRoot() noexcept - { - return root; - } - - FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept - { - - if (!CreateDirectoryA(path.c_str(), nullptr)) - { - SHLOG_ERROR("Failed to create folder: {}\n", path); - } - - folders[location] = std::make_unique(location, name); - folders[location]->path = path; - folders[parent]->subFolders.push_back(folders[location].get()); - - return FolderMakeHelper(path, parent, location, name); - } - - FolderPointer SHFileSystem::RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, - FolderName name) noexcept - { - return FolderMakeHelper(path, parent, location, name); - } - - FolderPointer SHFileSystem::FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, - FolderName name) noexcept - { - folders[location] = std::make_unique(location, name); - folders[location]->path = path; - folders[parent]->subFolders.push_back(folders[location].get()); - - return folders[location].get(); - } } diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.h b/SHADE_Engine/src/Filesystem/SHFileSystem.h index 8df794fd..956d3916 100644 --- a/SHADE_Engine/src/Filesystem/SHFileSystem.h +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.h @@ -1,70 +1,28 @@ +/****************************************************************************** + * \file SHFileSystem.h + * \author Loh Xiao Qi + * \date 28 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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 -#include +#include "SHFolder.h" #include namespace SHADE { - class SHFolder; - - typedef unsigned char FolderCounter; - typedef unsigned char FileCounter; - typedef uint64_t FolderLocation; - typedef uint64_t FolderHandle; - typedef std::string FolderName; - typedef std::string FileName; - typedef std::string FolderPath; - typedef std::string FilePath; - typedef std::string FileExt; - typedef SHFolder* FolderPointer; - - constexpr char FOLDER_BIT_ALLOCATE{ 4 }; - constexpr char FOLDER_MAX_DEPTH{ 16 }; - - struct SHFile - { - FileName name; - FilePath path; - FileExt ext; - }; - - class SHFolder - { - public: - SHFolder(FolderHandle id, FolderName name); - - FolderHandle id; - FolderName name; - std::vector subFolders; - std::vector files; - - bool folded; - - private: - FolderPath path; - friend class SHFileSystem; - }; class SHFileSystem { public: - static FolderLocation CreateNewFolderHere(FolderName name, FolderLocation here = 0) noexcept; - - static bool DeleteFolder(FolderPointer location) noexcept; - - static void StartupFillDirectories(FolderPath path) noexcept; - - static FolderPointer GetRoot() noexcept; + static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map& assetCollection) noexcept; private: - static FolderPointer root; - - static std::unordered_map> folders; - - static FolderPointer CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; - static FolderPointer RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; - static FolderPointer FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + static bool DeleteFolder(FolderPointer location) noexcept; + }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Filesystem/SHFolder.cpp b/SHADE_Engine/src/Filesystem/SHFolder.cpp new file mode 100644 index 00000000..716eec4b --- /dev/null +++ b/SHADE_Engine/src/Filesystem/SHFolder.cpp @@ -0,0 +1,38 @@ +/*************************************************************************//** + * \file SHFolder.cpp + * \author Loh Xiao Qi + * \date 30 October 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. + *****************************************************************************/ +#include "SHpch.h" +#include "SHFolder.h" + +namespace SHADE +{ + SHFolder::SHFolder(FolderName name) + :name{ name }, subFolders(0), folded{ false }, path{ "" } + { + } + + FolderPointer SHFolder::CreateSubFolderHere(FolderName name) + { + for (auto const& folder : subFolders) + { + if (name == folder->name) + { + SHLOG_ERROR("Unable to create subfolder {} at {} as it already exists", name, folder->name); + return nullptr; + } + } + + auto result = new SHFolder(name); + result->path = path + "/" + name; + subFolders.push_back(result); + + return result; + } +} diff --git a/SHADE_Engine/src/Filesystem/SHFolder.h b/SHADE_Engine/src/Filesystem/SHFolder.h new file mode 100644 index 00000000..54e95033 --- /dev/null +++ b/SHADE_Engine/src/Filesystem/SHFolder.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * \file SHFolder.h + * \author Loh Xiao Qi + * \date 28 October 2022 + * \brief + * + * \copyright Copyright (c) 2021 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 +#include "Assets/SHAsset.h" + +namespace SHADE +{ + class SHFolder; + + typedef unsigned char FolderCounter; + typedef unsigned char FileCounter; + typedef std::string FolderName; + typedef std::string FileName; + typedef std::string FolderPath; + typedef std::string FilePath; + typedef std::string FileExt; + typedef SHFolder* FolderPointer; + + struct SHFile + { + FileName name; + FilePath path; + FileExt ext; + SHAsset const* assetMeta; + }; + + class SHFolder + { + public: + SHFolder(FolderName name); + + FolderName name; + std::vector subFolders; + std::vector files; + + bool folded; + + FolderPointer CreateSubFolderHere(FolderName name); + FolderPath path; + }; +} diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index a6b415a9..6bf2e731 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -186,9 +186,10 @@ namespace SHADE vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED // point and lines fill mode - features.fillModeNonSolid = true; + features.fillModeNonSolid = VK_TRUE; features.samplerAnisotropy = VK_TRUE; - features.multiDrawIndirect = true; + features.multiDrawIndirect = VK_TRUE; + features.independentBlend = VK_TRUE; // for wide lines features.wideLines = true; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index d07e0f06..1bda7c90 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -194,7 +194,8 @@ namespace SHADE { SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); } - propsCurrPtr += singleMatPropAlignedSize; + //propsCurrPtr += singleMatPropAlignedSize; + propsCurrPtr += singleMatPropSize; } // Transfer to GPU @@ -316,7 +317,7 @@ namespace SHADE { singleMatPropSize = SHADER_INFO->GetBytesRequired(); singleMatPropAlignedSize = device->PadSSBOSize(static_cast(singleMatPropSize)); - matPropTotalBytes = numTotalElements * singleMatPropAlignedSize; + matPropTotalBytes = numTotalElements * singleMatPropSize; if (matPropsDataSize < matPropTotalBytes) { matPropsData.reset(new char[matPropTotalBytes]); @@ -375,7 +376,8 @@ namespace SHADE { SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); } - propsCurrPtr += singleMatPropAlignedSize; + //propsCurrPtr += singleMatPropAlignedSize; + propsCurrPtr += singleMatPropSize; } } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp index 0f1658f3..d5fb81bd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp @@ -47,36 +47,35 @@ namespace SHADE // For global data (generic data and textures) Handle staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding }); + std::vector lightBindings{}; - for (uint32_t i = 0; i < SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i) + + // This is the binding we use to count the lights (binding 0) + lightBindings.push_back(SHVkDescriptorSetLayout::Binding + { + .Type = vk::DescriptorType::eUniformBufferDynamic, + .Stage = vk::ShaderStageFlagBits::eCompute, + .BindPoint = 0, + .DescriptorCount = 1, + + }); + + for (uint32_t i = 1; i <= SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i) { lightBindings.push_back (SHVkDescriptorSetLayout::Binding { .Type = vk::DescriptorType::eStorageBufferDynamic, - .Stage = vk::ShaderStageFlagBits::eFragment, + .Stage = vk::ShaderStageFlagBits::eCompute, .BindPoint = i, .DescriptorCount = 1, }); } - //SHVkDescriptorSetLayout::Binding pointLightBinding - //{ - // .Type = vk::DescriptorType::eStorageBufferDynamic, - // .Stage = vk::ShaderStageFlagBits::eFragment, - // .BindPoint = SHGraphicsConstants::DescriptorSetBindings::POINT_LIGHT_DATA, - // .DescriptorCount = 1, - //}; - //SHVkDescriptorSetLayout::Binding spotLightBinding - //{ - // .Type = vk::DescriptorType::eStorageBufferDynamic, - // .Stage = vk::ShaderStageFlagBits::eFragment, - // .BindPoint = SHGraphicsConstants::DescriptorSetBindings::SPOT_LIGHT_DATA, - // .DescriptorCount = 1, - //}; // For Dynamic global data (lights) Handle dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings); + SHVkDescriptorSetLayout::Binding cameraDataBinding { .Type = vk::DescriptorType::eUniformBufferDynamic, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index 4c3ba7f9..a39ec10e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -94,32 +94,14 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1; - ///***************************************************************************/ - ///*! - // \brief - // DescriptorSet binding for directional lights. + /***************************************************************************/ + /*! + \brief + DescriptorSet binding for combined image sampler data. - //*/ - ///***************************************************************************/ - //static constexpr uint32_t DIRECTIONAL_LIGHT_DATA = 0; - - ///***************************************************************************/ - ///*! - // \brief - // DescriptorSet binding for directional lights. - - //*/ - ///***************************************************************************/ - //static constexpr uint32_t POINT_LIGHT_DATA = 1; - - ///***************************************************************************/ - ///*! - // \brief - // DescriptorSet binding for directional lights. - - //*/ - ///***************************************************************************/ - //static constexpr uint32_t SPOT_LIGHT_DATA = 2; + */ + /***************************************************************************/ + static constexpr uint32_t LIGHTING_COUNT = 0; /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 3330a189..7391da2c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Windowing/Surface/SHVkSurface.h" #include "Graphics/Swapchain/SHVkSwapchain.h" #include "Camera/SHCameraSystem.h" -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "ECS_Base/Managers/SHSystemManager.h" //#include "SHRenderer.h" #include "Graphics/Windowing/SHWindow.h" @@ -73,15 +73,7 @@ namespace SHADE if (width == 0 || height == 0) return; -#ifdef SHEDITOR - - //PrepareResize(1, 1, SHVec2(0, 0)); - -#else - - PrepareResize(resizeWidth, resizeHeight, SHVec2(0, 0)); - -#endif + PrepareResize(resizeWidth, resizeHeight); }); window->RegisterWindowCloseCallback([&](void) @@ -160,26 +152,45 @@ namespace SHADE // Initialize world render graph worldRenderGraph->Init(device, swapchain); - worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - 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("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->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 }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + 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); + + auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", + { + "Position", + "Entity ID", + "Light Layer Indices", + "Normals", + "Albedo", + "Depth Buffer", + "Scene" + }, + {}); // no predecessors - auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", { "Light Layer Indices", "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write"); - gBufferSubpass->AddColorOutput("Scene Pre-Process"); + gBufferSubpass->AddColorOutput("Position"); gBufferSubpass->AddColorOutput("Entity ID"); gBufferSubpass->AddColorOutput("Light Layer Indices"); + gBufferSubpass->AddColorOutput("Normals"); + gBufferSubpass->AddColorOutput("Albedo"); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); //// kirsch - //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs"); - //gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" }); + //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); + //gBufferNode->AddNodeCompute(kirschShader, { "Position", "Scene" }); - // copy - auto pureCopyShader = shaderModuleLibrary.GetBuiltInShaderModule("PureCopy_CS"); - gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" }); + //// copy + //auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl"); + //gBufferNode->AddNodeCompute(pureCopyShader, { "Position", "Scene" }); + + // deferred composite + auto deferredCompositeShader = shaderModuleLibrary.GetBuiltInShaderModule("DeferredComposite_CS"); + gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" }); auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, {"G-Buffer"}); // no predecessors @@ -311,6 +322,12 @@ namespace SHADE void SHGraphicsSystem::Run(double) noexcept { if (window->IsMinimized() || renderContext.GetWindowIsDead()) + { + restoredFromMinimize = true; + return; + } + + if (restoredFromMinimize) return; // Frame data for the current frame @@ -362,6 +379,7 @@ namespace SHADE // Force set the pipeline layout currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS); + currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::COMPUTE); // Bind all the buffers required for meshes for (auto& [buffer, bindingPoint] : MESH_DATA) @@ -444,7 +462,15 @@ namespace SHADE void SHGraphicsSystem::BeginRender() { if (window->IsMinimized() || renderContext.GetWindowIsDead()) + { + restoredFromMinimize = true; return; + } + + if (restoredFromMinimize) + { + return; + } // Finalise all batches for (auto vp : viewports) @@ -493,7 +519,17 @@ namespace SHADE void SHGraphicsSystem::EndRender() { if (window->IsMinimized() || renderContext.GetWindowIsDead()) + { + restoredFromMinimize = true; return; + } + + if (restoredFromMinimize) + { + restoredFromMinimize = false; + return; + } + const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame(); auto& currFrameData = renderContext.GetCurrentFrameData(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index f657965c..0f9d602a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -360,5 +360,7 @@ namespace SHADE uint32_t resizeWidth; uint32_t resizeHeight; + bool restoredFromMinimize = false; + }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp index 22de83b8..57762324 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp @@ -28,7 +28,7 @@ namespace SHADE material = {}; oldMaterial = {}; - lightLayer = 0; + lightLayer = 1; } void SHRenderable::OnDestroy() diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index fd122334..fb8795fa 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -10,7 +10,7 @@ namespace SHADE lightData.Reset(); SetType(SH_LIGHT_TYPE::DIRECTIONAL); indexInBuffer = std::numeric_limits::max(); - active = true; + isActive = true; Unbind(); } @@ -20,7 +20,7 @@ namespace SHADE } - void SHLightComponent::SetPosition(SHVec3 position) noexcept + void SHLightComponent::SetPosition(SHVec3 const& position) noexcept { lightData.position = position; MakeDirty(); @@ -34,20 +34,20 @@ namespace SHADE } - void SHLightComponent::SetDirection(SHVec3 direction) noexcept + void SHLightComponent::SetDirection(SHVec3 const& direction) noexcept { lightData.direction = direction; MakeDirty(); } - void SHLightComponent::SetDiffuseColor(SHVec4 diffuseColor) noexcept + void SHLightComponent::SetColor(SHVec4 const& color) noexcept { - lightData.diffuseColor = diffuseColor; + lightData.color = color; MakeDirty(); } - void SHLightComponent::ModifyLayer(uint8_t layerIndex, bool value) noexcept + void SHLightComponent::ModifyCullingMask(uint8_t layerIndex, bool value) noexcept { if (value) lightData.cullingMask |= (1u << layerIndex); @@ -57,6 +57,10 @@ namespace SHADE MakeDirty(); } + void SHLightComponent::SetCullingMask(uint32_t const& value) noexcept + { + lightData.cullingMask = value; + } void SHLightComponent::SetAllLayers(void) noexcept { @@ -93,11 +97,11 @@ namespace SHADE indexInBuffer = inIndexInBuffer; } - void SHLightComponent::SetActive(bool flag) noexcept - { - MakeDirty(); - active = flag; + void SHLightComponent::SetStrength(float value) noexcept + { + lightData.strength = value; + MakeDirty(); } SHLightData const& SHLightComponent::GetLightData(void) const noexcept @@ -105,6 +109,32 @@ namespace SHADE return lightData; } + SHVec3 const& SHLightComponent::GetPosition(void) const noexcept + { + return lightData.position; + } + + SH_LIGHT_TYPE SHLightComponent::GetType(void) const noexcept + { + return lightData.type; + } + + SHVec3 const& SHLightComponent::GetDirection(void) const noexcept + { + return lightData.direction; + } + + SHVec4 const& SHLightComponent::GetColor(void) const noexcept + { + return lightData.color; + } + + uint32_t const& SHLightComponent::GetCullingMask(void) const noexcept + { + return lightData.cullingMask; + } + + bool SHLightComponent::IsDirty(void) const noexcept { return dirty; @@ -120,4 +150,32 @@ namespace SHADE return indexInBuffer; } + float SHLightComponent::GetStrength(void) const noexcept + { + return lightData.strength; + } + +} + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::enumeration("Light Type") + ( + value("Directional", SH_LIGHT_TYPE::DIRECTIONAL), + value("Point", SH_LIGHT_TYPE::POINT), + value("Spot", SH_LIGHT_TYPE::SPOT), + value("Ambient", SH_LIGHT_TYPE::AMBIENT) + ); + + registration::class_("Light Component") + .property("Position", &SHLightComponent::GetPosition, &SHLightComponent::SetPosition) + .property("Type", &SHLightComponent::GetType, &SHLightComponent::SetType) + .property("Direction", &SHLightComponent::GetDirection, &SHLightComponent::SetDirection) + .property("Color", &SHLightComponent::GetColor, &SHLightComponent::SetColor) + .property("Layer", &SHLightComponent::GetCullingMask, &SHLightComponent::SetCullingMask) + .property("Strength", &SHLightComponent::GetStrength, &SHLightComponent::SetStrength) + ; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index 20ae3892..81eb80f5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -1,5 +1,6 @@ #pragma once +#include #include "ECS_Base/Components/SHComponent.h" #include "SHLightData.h" @@ -24,8 +25,6 @@ namespace SHADE //! If the light's data is already in the buffers, this will be set to true. bool bound; - //! If the light is active, this is true. - bool active; public: /*-----------------------------------------------------------------------*/ @@ -37,24 +36,31 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - void SetPosition (SHVec3 position) noexcept; - void SetType (SH_LIGHT_TYPE type) noexcept; - void SetDirection (SHVec3 direction) noexcept; - void SetDiffuseColor (SHVec4 diffuseColor) noexcept; - void ModifyLayer (uint8_t layerIndex, bool value) noexcept; - void SetAllLayers (void) noexcept; - void ClearAllLayers (void) noexcept; - void MakeDirty (void) noexcept; - void ClearDirtyFlag (void) noexcept; - void Unbind (void) noexcept; - void SetBound (uint32_t inIndexInBuffer) noexcept; - void SetActive (bool flag) noexcept; + void SetPosition (SHVec3 const& position) noexcept; // serialized + void SetType (SH_LIGHT_TYPE type) noexcept; // serialized + void SetDirection (SHVec3 const& direction) noexcept; // serialized + void SetColor (SHVec4 const& color) noexcept; // serialized + void ModifyCullingMask (uint8_t layerIndex, bool value) noexcept; // serialized + void SetCullingMask (uint32_t const& value) noexcept; + void SetAllLayers (void) noexcept; // serialized + void ClearAllLayers (void) noexcept; // serialized + void MakeDirty (void) noexcept; + void ClearDirtyFlag (void) noexcept; + void Unbind (void) noexcept; + void SetBound (uint32_t inIndexInBuffer) noexcept; + void SetStrength (float value) noexcept; // serialized - SHLightData const& GetLightData (void) const noexcept; + SHLightData const& GetLightData (void) const noexcept; + SHVec3 const& GetPosition (void) const noexcept; // serialized + SH_LIGHT_TYPE GetType (void) const noexcept; // serialized + SHVec3 const& GetDirection (void) const noexcept; // serialized + SHVec4 const& GetColor (void) const noexcept; // serialized + uint32_t const& GetCullingMask (void) const noexcept; // serialized bool IsDirty (void) const noexcept; bool GetBound (void) const noexcept; uint32_t GetIndexInBuffer (void) const noexcept; - + float GetStrength (void) const noexcept; + RTTR_ENABLE() }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp index ba910408..8e8f0783 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp @@ -15,7 +15,7 @@ namespace SHADE direction = SHVec3::Forward; // Diffuse color set to 1 - diffuseColor = SHVec4::One; + color = SHVec4::One; } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h index 607978a4..e9a02c1a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h @@ -10,6 +10,7 @@ namespace SHADE DIRECTIONAL = 0, POINT, SPOT, + AMBIENT, NUM_TYPES }; @@ -40,7 +41,11 @@ namespace SHADE uint32_t cullingMask; //! Diffuse color emitted by the light - SHVec4 diffuseColor; + SHVec4 color; + + //! Strength of the light + float strength; + void Reset (void) noexcept; //! TODO: diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 8d9efe54..5ca879c4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -42,13 +42,23 @@ namespace SHADE lightPtr->cullingMask = lightData.cullingMask; lightPtr->direction = lightData.direction; - lightPtr->diffuseColor = lightData.diffuseColor; + lightPtr->diffuseColor = lightData.color; + lightPtr->active = lightComp->isActive; break; } case SH_LIGHT_TYPE::POINT: break; case SH_LIGHT_TYPE::SPOT: break; + case SH_LIGHT_TYPE::AMBIENT: + { + SHAmbientLightData* lightPtr = reinterpret_cast(address); + lightPtr->ambientColor = lightData.color; + lightPtr->strength = lightData.strength; + lightPtr->cullingMask = lightData.cullingMask; + lightPtr->active = lightComp->isActive; + break; + } case SH_LIGHT_TYPE::NUM_TYPES: break; default: @@ -57,6 +67,7 @@ namespace SHADE } } + /***************************************************************************/ /*! @@ -76,8 +87,9 @@ namespace SHADE // boilerplate intermediateData = nullptr; - // initialize alignment - lightDataAlignmentSize = logicalDevice->PadSSBOSize(GetLightTypeSize(type)); + // Get data required for struct + lightDataSize = GetLightTypeSize(type); + lightDataAlignedSize = logicalDevice->PadSSBOSize(lightDataSize); // So create some data! Expand(logicalDevice); @@ -94,7 +106,7 @@ namespace SHADE /***************************************************************************/ void SHLightingSubSystem::PerTypeData::Expand(Handle logicalDevice) noexcept { - if (lightDataAlignmentSize == 0) + if (lightDataSize == 0) { SHLOG_ERROR ("One of the types of lights have not been accounted for. Make sure lightDataAlignmentSize is not nullptr."); return; @@ -111,10 +123,12 @@ namespace SHADE numLights = 0; // Initialize the data for lights - intermediateData = std::make_unique(lightDataAlignmentSize * maxLights); + intermediateData = std::make_unique(lightDataSize * maxLights); + + lightDataTotalAlignedSize = logicalDevice->PadSSBOSize(lightDataAlignedSize * maxLights); // We want to initialize 3 times the amount of data required. - dataBuffer = logicalDevice->CreateBuffer(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + dataBuffer = logicalDevice->CreateBuffer(lightDataTotalAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, lightDataTotalAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); } else { @@ -122,24 +136,27 @@ namespace SHADE uint32_t const OLD_MAX_LIGHTS = maxLights; // before we increase the number of lights, create space to store old data. - std::unique_ptr oldData = std::make_unique(lightDataAlignmentSize * OLD_MAX_LIGHTS); + std::unique_ptr oldData = std::make_unique(lightDataSize * OLD_MAX_LIGHTS); // copy data over. - std::memcpy (oldData.get(), intermediateData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS); + std::memcpy (oldData.get(), intermediateData.get(), lightDataSize * OLD_MAX_LIGHTS); // now we start to expand.... // double space for lights maxLights *= 2; + // calculate total + padding + lightDataTotalAlignedSize = logicalDevice->PadSSBOSize(lightDataAlignedSize * maxLights); + // destroy old data and initialize container for double the amount of data. - intermediateData = std::make_unique(lightDataAlignmentSize * maxLights); + intermediateData = std::make_unique(lightDataSize * maxLights); // copy old data to new container - std::memcpy(intermediateData.get(), oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS); + std::memcpy(intermediateData.get(), oldData.get(), lightDataSize * OLD_MAX_LIGHTS); // Resize the GPU buffer. TODO: Replace with Resize no copy here - dataBuffer->ResizeReplace(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS); + dataBuffer->ResizeReplace(maxLights * lightDataTotalAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataTotalAlignedSize * OLD_MAX_LIGHTS); } @@ -171,6 +188,9 @@ namespace SHADE case SH_LIGHT_TYPE::SPOT: // TOOD: Change after creating spot light struct return 4; + case SH_LIGHT_TYPE::AMBIENT: + return sizeof(SHAmbientLightData); + return 4; case SH_LIGHT_TYPE::NUM_TYPES: default: return 4; @@ -187,7 +207,12 @@ namespace SHADE uint32_t SHLightingSubSystem::PerTypeData::GetAlignmentSize(void) const noexcept { - return lightDataAlignmentSize; + return lightDataTotalAlignedSize; + } + + uint32_t SHLightingSubSystem::PerTypeData::GetDataSize(void) const noexcept + { + return lightDataSize; } uint32_t SHLightingSubSystem::PerTypeData::GetNumLights(void) const noexcept @@ -231,7 +256,7 @@ namespace SHADE // Now that the container is big enough, bind the new light // Get address of write location - void* writeLocation = reinterpret_cast(intermediateData.get()) + (lightDataAlignmentSize * numLights); + void* writeLocation = reinterpret_cast(intermediateData.get()) + (lightDataAlignedSize * numLights); // Write the light data to address WriteLightToAddress(writeLocation, unboundLight); @@ -257,7 +282,7 @@ namespace SHADE /***************************************************************************/ void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept { - void* writeLocation = reinterpret_cast(intermediateData.get()) + (lightDataAlignmentSize * lightComp->GetIndexInBuffer()); + void* writeLocation = reinterpret_cast(intermediateData.get()) + (lightDataAlignedSize * lightComp->GetIndexInBuffer()); WriteLightToAddress(writeLocation, lightComp); } @@ -266,10 +291,15 @@ namespace SHADE if (intermediateData) { // we want to write to the offset of the current frame - dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignmentSize * numLights, 0, lightDataAlignmentSize * maxLights * frameIndex); + dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignedSize * numLights, 0, lightDataAlignedSize * maxLights * frameIndex); } } + void SHLightingSubSystem::PerTypeData::ResetNumLights(void) noexcept + { + numLights = 0; + } + /***************************************************************************/ /*! @@ -287,12 +317,12 @@ namespace SHADE // We bind the buffer with the correct desc set binding lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, - binding, + binding + 1, // we want to +1 here because the first binding is reserved for count { &buffer, 1 }, 0, - perTypeData[binding].GetAlignmentSize() * perTypeData[binding].GetMaxLights()); + perTypeData[binding].GetDataSize() * perTypeData[binding].GetMaxLights()); - lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding); + lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding + 1); // +1 here, same reason. see above } /***************************************************************************/ @@ -307,16 +337,27 @@ namespace SHADE { for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) { - for (uint32_t j = 0; j < dynamicOffsets.size(); ++j) + dynamicOffsets[i][0] = i * lightCountsAlignedSize; + // Even if the first binding is a count, we want to account for that too + for (uint32_t j = 0; j < static_cast(SH_LIGHT_TYPE::NUM_TYPES); ++j) { auto const& typeData = perTypeData[j]; { - dynamicOffsets[i][j] = j * typeData.GetAlignmentSize() * typeData.GetMaxLights(); + // +1 because 1st reserved for count + dynamicOffsets[i][j + 1] = i * typeData.GetAlignmentSize(); } } } } + void SHLightingSubSystem::ResetNumLights(void) noexcept + { + for (auto& data : perTypeData) + { + data.ResetNumLights(); + } + } + /***************************************************************************/ /*! @@ -346,12 +387,26 @@ namespace SHADE // initialize all the data first. We add more lights here as we add more types. perTypeData[i].InitializeData(logicalDevice, static_cast(i)); UpdateDescSet(i); + + // no lights at first + lightCountsData[i] = 0; } + + lightCountsAlignedSize = sizeof (uint32_t) * NUM_LIGHT_TYPES; + lightCountsAlignedSize = logicalDevice->PadUBOSize(lightCountsAlignedSize); + + // Create the GPU buffer to hold light count + lightCountsBuffer = logicalDevice->CreateBuffer(lightCountsAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, lightCountsAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eUniformBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + + lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, SHGraphicsConstants::DescriptorSetBindings::LIGHTING_COUNT, {&lightCountsBuffer, 1}, 0, sizeof (uint32_t) * NUM_LIGHT_TYPES); + lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, SHGraphicsConstants::DescriptorSetBindings::LIGHTING_COUNT); for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) { - dynamicOffsets[i].resize(NUM_LIGHT_TYPES); + dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count } + + numLightComponents = 0; } /***************************************************************************/ @@ -366,17 +421,32 @@ namespace SHADE /***************************************************************************/ void SHLightingSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex) noexcept { + static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); + auto& lightComps = SHComponentManager::GetDense(); bool expanded = false; + bool rewrite = false; + + if (numLightComponents > lightComps.size()) + { + rewrite = true; + ResetNumLights(); + } + + numLightComponents = lightComps.size(); + for (auto& light : lightComps) { auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type); // First we want to make sure the light is already bound to the system. if it // isn't, we write it to the correct buffer. - if (!light.GetBound()) + if (!light.GetBound() || rewrite) { perTypeData[enumValue].AddLight(logicalDevice, &light, expanded); + + //// add to light count + //++lightCountsData[enumValue]; } // if there was modification to the light data @@ -396,6 +466,13 @@ namespace SHADE data.WriteToGPU(frameIndex); } + for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i) + { + lightCountsData[i] = perTypeData[i].GetNumLights(); + } + + lightCountsBuffer->WriteToMemory(lightCountsData.data(), static_cast(lightCountsData.size()) * sizeof (uint32_t), 0, lightCountsAlignedSize * frameIndex); + // If any of the buffers got expanded, the descriptor set is invalid because the expanded buffer // is a new buffer. If some expansion was detected, update descriptor sets. if (expanded) @@ -412,7 +489,7 @@ namespace SHADE ComputeDynamicOffsets(); // Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data). - cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]}); + cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]}); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index e5336b4e..fb7aa2de 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -17,7 +17,7 @@ namespace SHADE class SHVkCommandBuffer; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. - struct SHDirectionalLightData + struct SHDirectionalLightData { //! Direction of the light SHVec3 direction; @@ -31,7 +31,27 @@ namespace SHADE uint32_t cullingMask; //! Diffuse color emitted by the light - SHVec4 diffuseColor; + alignas (16) SHVec4 diffuseColor; + + }; + + // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. + struct SHAmbientLightData + { + //! Diffuse color emitted by the light + SHVec4 ambientColor; + + //! Strength of the ambient light + float strength; + + //! Represents if the light is active or not + uint32_t active; + + //! Each bit in this 32 bit field will represent a layer. If the bit is set, + //! when a fragment is being evaluated, the shader will use the fragment's + //! layer value to AND with the light's. If result is 1, do lighting calculations. + uint32_t cullingMask; + }; @@ -45,7 +65,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t STARTING_NUM_LIGHTS = 20; + static constexpr uint32_t STARTING_NUM_LIGHTS = 50; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -53,8 +73,13 @@ namespace SHADE //! Capacity of the container. uint32_t maxLights; - //! SSBOs need to be aligned. This is to pad lighting structs - uint32_t lightDataAlignmentSize; + //! SSBOs need to be aligned. This is to pad descriptor offset + uint32_t lightDataTotalAlignedSize; + + //! size needed to store 1 struct object + uint32_t lightDataSize; + + uint32_t lightDataAlignedSize; //! type of the light. Will be used later when we want to expand SH_LIGHT_TYPE lightType; @@ -80,6 +105,7 @@ namespace SHADE void AddLight (Handle logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept; void ModifyLight (SHLightComponent* lightComp) noexcept; void WriteToGPU (uint32_t frameIndex) noexcept; + void ResetNumLights (void) noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS */ @@ -87,6 +113,7 @@ namespace SHADE static uint32_t GetLightTypeSize (SH_LIGHT_TYPE type) noexcept; Handle GetDataBuffer (void) const noexcept; uint32_t GetAlignmentSize (void) const noexcept; + uint32_t GetDataSize (void) const noexcept; uint32_t GetNumLights (void) const noexcept; uint32_t GetMaxLights (void) const noexcept; }; @@ -105,11 +132,26 @@ namespace SHADE //! Container to store dynamic offsets for binding descriptor sets std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)> dynamicOffsets; + //! holds the data that represents how many lights are in the scene + std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; + + //! GPU buffer to hold lightCountData + Handle lightCountsBuffer; + + //! For padding in the buffer + uint32_t lightCountsAlignedSize; + + //! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense + //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more, + //! don't do anything. + uint32_t numLightComponents; + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ void UpdateDescSet (uint32_t binding) noexcept; void ComputeDynamicOffsets (void) noexcept; + void ResetNumLights (void) noexcept; public: diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp index 8041adfd..45103819 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp @@ -133,6 +133,7 @@ namespace SHADE { SHLOG_ERROR("Frame index retrieved from vkAcquireNextImageKHR is not the same as currentFrame."); } + currentFrame = frameIndex; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 607c777a..aa9c7944 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -276,7 +276,7 @@ namespace SHADE } // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceManager->Create(graphStorage, computeShaderModule, std::move(nodeComputeResources)); + auto nodeCompute = graphStorage->resourceManager->Create(graphStorage, computeShaderModule, std::move(nodeComputeResources), nodeComputes.empty()); nodeComputes.push_back(nodeCompute); return nodeCompute; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index a5208fcf..5323d706 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -13,12 +13,13 @@ namespace SHADE { - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} , groupSizeX{0} , groupSizeY{0} + , followingEndRenderpass {followingEndRP} , numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)} { SHPipelineLayoutParams pipelineLayoutParams @@ -53,7 +54,6 @@ namespace SHADE descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts); } - HandleResize(); } @@ -68,8 +68,9 @@ namespace SHADE // dispatch compute cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1); - // TODO: barrier - + cmdBuffer->PipelineBarrier((followingEndRenderpass) ? vk::PipelineStageFlagBits::eFragmentShader : vk::PipelineStageFlagBits::eComputeShader, + vk::PipelineStageFlagBits::eFragmentShader, + {}, {}, {}, memoryBarriers[frameIndex]); } void SHRenderGraphNodeCompute::HandleResize(void) noexcept @@ -104,6 +105,36 @@ namespace SHADE groupSizeX = maxWidth / workGroupSizeX; groupSizeY = maxHeight / workGroupSizeY; + + for (uint32_t i = 0; auto& barriers : memoryBarriers) + { + barriers.clear(); + + for (auto& resource : resources) + { + vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); + barriers.push_back(vk::ImageMemoryBarrier + { + .srcAccessMask = srcAccessMask, + .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, + .oldLayout = vk::ImageLayout::eGeneral, + .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(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = resource->imageAspectFlags, + .baseMipLevel = 0, + .levelCount = resource->mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + } + + ++i; + } } } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index ba4cf387..2cd3c948 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -2,6 +2,7 @@ #include "Resource/SHHandle.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/SHVulkanIncludes.h" #include #include #include @@ -44,8 +45,12 @@ namespace SHADE float numWorkGroupScale; + bool followingEndRenderpass; + + std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> memoryBarriers; + public: - SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp index 44a1cb0e..7995e394 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp @@ -54,13 +54,14 @@ namespace SHADE if (wndData.isFullscreen) { - dwExStyle = WS_EX_APPWINDOW | WS_EX_ACCEPTFILES; + dwExStyle = WS_EX_APPWINDOW; dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + dwExStyle |= WS_EX_ACCEPTFILES; } else { - dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_ACCEPTFILES; - + dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwExStyle |= WS_EX_ACCEPTFILES; if (wndData.frameEnabled) { dwStyle = WNDSTYLE::SHWS_WINDOWED; @@ -87,7 +88,7 @@ namespace SHADE } } - //DPI_AWARENESS_CONTEXT prevDPIContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + DPI_AWARENESS_CONTEXT prevDPIContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); RECT windowRect; windowRect.left = wndData.x; //or CW_USEDEFAULT ? @@ -97,13 +98,16 @@ namespace SHADE AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle); //Create window - wndHWND = CreateWindowEx(0, (LPWSTR) wndData.name.c_str(), (LPWSTR)wndData.title.c_str(), dwStyle, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, parent, NULL, hInstance, NULL); - + wndHWND = CreateWindowEx(dwExStyle, (LPWSTR) wndData.name.c_str(), (LPWSTR)wndData.title.c_str(), dwStyle, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, parent, NULL, hInstance, NULL); + if (!wndHWND) { //DWORD err = GetLastError(); return false; } + BOOL help = ChangeWindowMessageFilter (WM_DROPFILES, MSGFLT_ADD); + help &= ChangeWindowMessageFilter (WM_COPYDATA, MSGFLT_ADD); + help &= ChangeWindowMessageFilter (0x0049, MSGFLT_ADD); if (wndData.isVisible) { @@ -318,13 +322,13 @@ namespace SHADE case WM_CREATE: OnCreate(hwnd, reinterpret_cast(wparam)); break; + case WM_QUIT: case WM_CLOSE: - case WM_DESTROY: OnDestroy(); return 0; case WM_DROPFILES: - //OnFileDrop(reinterpret_cast(wparam)); + OnFileDrop(reinterpret_cast(wparam)); break; case WM_ENTERSIZEMOVE: case WM_EXITSIZEMOVE: @@ -386,12 +390,25 @@ namespace SHADE void SHWindow::OnDestroy() { OnClose(); + DragAcceptFiles(wndHWND, false); this->Destroy(); } - //void SHWindow::OnFileDrop(HDROP drop) - //{ - //} + void SHWindow::OnFileDrop(HDROP drop) + { + + int const numFiles = static_cast(DragQueryFile(drop, 0xFFFFFFFF, nullptr, 0)); + for(int i = 0; i < numFiles; ++i) + { + //char fileNameBuffer[MAX_PATH]; + std::wstring fileNameBuffer; + fileNameBuffer.reserve(MAX_PATH); + DragQueryFile(drop, static_cast(i), fileNameBuffer.data(), MAX_PATH); + std::string name(fileNameBuffer.begin(), fileNameBuffer.end()); + SHLOG_INFO("Dropped: {}", name) + } + DragFinish(drop); + } void SHWindow::OnSize([[maybe_unused]] UINT msg,[[maybe_unused]] UINT type, SIZE size) { diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h index 0a180285..8595ce4b 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h @@ -2,6 +2,7 @@ #define SH_WINDOW_H #include +#include #include #include #include "SHWindowMap.h" @@ -10,7 +11,7 @@ namespace SHADE { constexpr uint16_t MAX_BUFFER = 1024; - + enum WNDSTYLE : DWORD { SHWS_WINDOWED = WS_OVERLAPPEDWINDOW, @@ -47,7 +48,7 @@ namespace SHADE //bool canFullscreen = true; - unsigned bgColor = WHITE_BRUSH; + unsigned bgColor = DKGRAY_BRUSH; //bool transparent = false; @@ -168,7 +169,7 @@ namespace SHADE void OnCreate(HWND hwnd, LPCREATESTRUCT create_struct); void OnClose(); void OnDestroy(); - //void OnFileDrop(HDROP drop); + void OnFileDrop(HDROP drop); void OnSize(UINT msg, UINT type, SIZE size); void OnPosChange(LPWINDOWPOS pos); void OnPaint(HDC hdc, LPPAINTSTRUCT paint); diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp index e56cbc8d..43742855 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp @@ -14,6 +14,7 @@ #include "SHTransformComponent.h" // Project Headers #include "Math/SHMathHelpers.h" +#include "Reflection/SHReflectionMetadata.h" namespace SHADE { @@ -184,7 +185,7 @@ RTTR_REGISTRATION using namespace rttr; registration::class_("Transform Component") - .property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition ) - .property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload(&SHTransformComponent::SetLocalRotation) ) - .property("Scale" , &SHTransformComponent::GetLocalScale , &SHTransformComponent::SetLocalScale ); + .property("Translate" ,&SHTransformComponent::GetLocalPosition ,&SHTransformComponent::SetLocalPosition ) (metadata(META::tooltip, "Translate")) + .property("Rotate" ,&SHTransformComponent::GetLocalRotation ,select_overload(&SHTransformComponent::SetLocalRotation) ) (metadata(META::tooltip, "Rotate"), metadata(META::angleInRad, true)) + .property("Scale" ,&SHTransformComponent::GetLocalScale ,&SHTransformComponent::SetLocalScale ) (metadata(META::tooltip, "Scale")); } \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index a2ab6880..156a47cc 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -263,6 +263,9 @@ namespace SHADE auto* node = EVENT_DATA->data->node; auto* tf = SHComponentManager::GetComponent_s(node->GetEntityID()); + if(tf == nullptr) + return EVENT_DATA->handle; + // Recompute local transform and store localToWorld Matrix SHMatrix localToWorld = SHMatrix::Identity; SHMatrix worldToLocal = SHMatrix::Identity; diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp index fb999847..c7e327fa 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp @@ -146,4 +146,12 @@ namespace SHADE system->RemoveCollisionShape(GetEID(), index); } -} // namespace SHADE \ No newline at end of file +} // namespace SHADE + +RTTR_REGISTRATION +{ + using namespace rttr; + using namespace SHADE; + + registration::class_("Collider Component"); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h index af726b51..7ce272a9 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h @@ -100,5 +100,6 @@ namespace SHADE SHQuaternion orientation; Colliders colliders; + RTTR_ENABLE() }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp index 44142aaf..03241dd4 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -17,7 +17,7 @@ #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Editor/SHEditor.hpp" +#include "Editor/SHEditor.h" #include "Math/SHMathHelpers.h" #include "Scene/SHSceneManager.h" #include "Math/Transform/SHTransformComponent.h" diff --git a/SHADE_Engine/src/Reflection/SHReflectionMetadata.h b/SHADE_Engine/src/Reflection/SHReflectionMetadata.h index 0cc6d8a5..b4dc009c 100644 --- a/SHADE_Engine/src/Reflection/SHReflectionMetadata.h +++ b/SHADE_Engine/src/Reflection/SHReflectionMetadata.h @@ -7,5 +7,6 @@ namespace SHADE constexpr const char* min = "MIN"; constexpr const char* max = "MAX"; constexpr const char* tooltip = "tooltip"; + constexpr const char* angleInRad = "angleInRad"; } } diff --git a/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp new file mode 100644 index 00000000..8ab098b8 --- /dev/null +++ b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp @@ -0,0 +1,56 @@ +#include "SHpch.h" +#include "SHPrefabManager.h" + +namespace SHADE +{ + SHPrefabManager::PrefabMap SHPrefabManager::prefabMap{}; + + void SHPrefabManager::AddPrefab(AssetID const& prefabAssetID) noexcept + { + prefabMap.insert({ prefabAssetID, {} }); + } + + void SHPrefabManager::RemovePrefab(AssetID const& prefabAssetID) noexcept + { + prefabMap.erase(prefabAssetID); + } + + void SHPrefabManager::ClearPrefab(AssetID const& prefabAssetID) noexcept + { + if (prefabMap.contains(prefabAssetID)) + { + prefabMap[prefabAssetID].clear(); + } + } + + void SHPrefabManager::UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept + { + //Loop through all entities and deserialize new data + } + + void SHPrefabManager::AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept + { + if (prefabMap.contains(prefabAssetID)) + { + prefabMap[prefabAssetID].insert(eid); + } + } + + void SHPrefabManager::RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept + { + if (prefabMap.contains(prefabAssetID)) + { + prefabMap[prefabAssetID].erase(eid); + } + } + + void SHPrefabManager::Clear() noexcept + { + prefabMap.clear(); + } + + bool SHPrefabManager::Empty() noexcept + { + return prefabMap.empty(); + } +} diff --git a/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h new file mode 100644 index 00000000..37c317ed --- /dev/null +++ b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Assets/SHAssetMacros.h" +#include "ECS_Base/SHECSMacros.h" +#include +#include + + +namespace SHADE +{ + class SHPrefabManager + { + public: + using PrefabMap = std::unordered_map>; + + static void AddPrefab(AssetID const& prefabAssetID) noexcept; + static void RemovePrefab(AssetID const& prefabAssetID) noexcept; + static void ClearPrefab(AssetID const& prefabAssetID) noexcept; + static void UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept; + static void AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept; + static void RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept; + static void Clear() noexcept; + static bool Empty() noexcept; + + private: + static PrefabMap prefabMap; + }; +} diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 79c8308f..03498951 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -10,10 +10,12 @@ #include "Assets/SHAssetManager.h" #include +#include "Camera/SHCameraComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Math/Transform/SHTransformComponent.h" #include "Physics/Components/SHRigidBodyComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" namespace SHADE @@ -57,7 +59,7 @@ namespace SHADE static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector& createdEntities, EntityID parentEID = MAX_EID) { EntityID eid = MAX_EID; - if(!node) + if (!node) return eid; if (node[EIDNode]) eid = node[EIDNode].as(); @@ -70,13 +72,13 @@ namespace SHADE createdEntities.push_back(eid); if (node[NumberOfChildrenNode]) { - if(const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) + if (const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) { ++it; for (int i = 0; i < numOfChildren; ++i) { DeserializeEntity(it, (*it), createdEntities, eid); - if((i + 1) < numOfChildren) + if ((i + 1) < numOfChildren) ++it; } } @@ -84,7 +86,9 @@ namespace SHADE // Deserialise scripts if (node[ScriptsNode]) - SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); + SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); + + return eid; } void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) @@ -119,10 +123,10 @@ namespace SHADE { DeserializeEntity(it, (*it), createdEntities); } - if(createdEntities.empty()) + if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") - return; + return; } //Initialize Entity auto entityVecIt = createdEntities.begin(); @@ -136,7 +140,7 @@ namespace SHADE { out << SerializeEntityToNode(entityNode); auto const& children = entityNode->GetChildren(); - for(auto const& child : children) + for (auto const& child : children) { EmitEntity(child, out); } @@ -161,17 +165,36 @@ namespace SHADE { } + template, bool> = true> + static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) + { + if (const ComponentType* component = SHComponentManager::GetComponent_s(eid)) + { + componentsNode[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component); + } + } + + template, bool> = true> + static void AddConvComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) + { + if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) + { + componentsNode[rttr::type::get().get_name().data()] = YAML::convert::encode(*component); + } + } + + YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) { YAML::Node node; auto eid = sceneNode->GetEntityID(); auto entity = SHEntityManager::GetEntityByID(eid); - if (!sceneNode || !entity) + if (!sceneNode && !entity) { node = YAML::Null; return node; } - node.SetStyle(YAML::EmitterStyle::Block); + node.SetStyle(YAML::EmitterStyle::Block); node[EIDNode] = eid; node[EntityNameNode] = entity->name; node[IsActiveNode] = sceneNode->IsActive(); @@ -180,18 +203,13 @@ namespace SHADE YAML::Node components; - if (const auto transform = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(transform); - } - if (const auto renderable = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = *renderable; - } - if (const auto rigidbody = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody); - } + AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddConvComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddConvComponentToComponentNode(components, eid); + node[ComponentsNode] = components; YAML::Node scripts; @@ -203,22 +221,22 @@ namespace SHADE EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept { - if(data.empty()) + if (data.empty()) return MAX_EID; YAML::Node entities = YAML::Load(data.c_str()); - EntityID eid{MAX_EID}; + EntityID eid{ MAX_EID }; std::vector createdEntities; - for(auto it = entities.begin(); it != entities.end(); ++it) + for (auto it = entities.begin(); it != entities.end(); ++it) { eid = DeserializeEntity(it, *it, createdEntities, parentEID); } - if(createdEntities.empty()) + if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") - return MAX_EID; + return MAX_EID; } auto entityVecIt = createdEntities.begin(); - for(auto it = entities.begin(); it != entities.end(); ++it) + for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, *entityVecIt++); } @@ -226,29 +244,22 @@ namespace SHADE } template, bool> = true> - std::optional GetComponentID(YAML::Node const& componentNode) + static void AddComponentID(std::vector& idList, YAML::Node const& componentNode) { if (componentNode[rttr::type::get().get_name().data()]) - return { SHFamilyID::GetID() }; - else - return std::nullopt; + idList.push_back(SHFamilyID::GetID()); } std::vector SHSerialization::GetComponentIDList(YAML::Node const& componentsNode) { std::vector componentIDList; - - auto id = GetComponentID(componentsNode); - if (id.has_value()) - componentIDList.push_back(id.value()); - - id = GetComponentID(componentsNode); - if (id.has_value()) - componentIDList.push_back(id.value()); - - id = GetComponentID(componentsNode); - if (id.has_value()) - componentIDList.push_back(id.value()); + + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); return componentIDList; } @@ -259,6 +270,10 @@ namespace SHADE if (!componentsNode) return; SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } } diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index a8e46d88..a6f02249 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -13,10 +13,236 @@ #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "SHSerializationTools.h" +#include "Physics/Components/SHColliderComponent.h" namespace YAML { using namespace SHADE; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + static constexpr const char* z = "z"; + static constexpr const char* w = "w"; + + static Node encode(SHVec4 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + node[z] = rhs.z; + node[w] = rhs.w; + return node; + } + static bool decode(Node const& node, SHVec4& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + if (node[z].IsDefined()) + rhs.z = node[z].as(); + if (node[w].IsDefined()) + rhs.w = node[w].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + static constexpr const char* z = "z"; + + static Node encode(SHVec3 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + node[z] = rhs.z; + return node; + } + static bool decode(Node const& node, SHVec3& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + if (node[z].IsDefined()) + rhs.z = node[z].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + + static Node encode(SHVec2 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + return node; + } + static bool decode(Node const& node, SHVec2& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* IsTrigger = "Is Trigger"; + + static constexpr const char* Type = "Type"; + static constexpr const char* HalfExtents = "Half Extents"; + static constexpr const char* Radius = "Radius"; + + static constexpr const char* Friction = "Friction"; + static constexpr const char* Bounciness = "Bounciness"; + static constexpr const char* Density = "Density"; + static constexpr const char* PositionOffset = "Position Offset"; + + static Node encode(SHCollider& rhs) + { + Node node; + + node[IsTrigger] = rhs.IsTrigger(); + + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + SHCollider::Type colliderType = rhs.GetType(); + + node[Type] = enumAlign.value_to_name(colliderType).data(); + + switch (colliderType) + { + case SHCollider::Type::BOX: + { + auto const bb = reinterpret_cast(rhs.GetShape()); + node[HalfExtents] = bb->GetHalfExtents(); + } + break; + case SHCollider::Type::SPHERE: + { + auto const bs = reinterpret_cast(rhs.GetShape()); + node[Radius] = bs->GetRadius(); + } + break; + case SHCollider::Type::CAPSULE: break; + default:; + } + + node[Friction] = rhs.GetFriction(); + node[Bounciness] = rhs.GetBounciness(); + node[Density] = rhs.GetDensity(); + node[PositionOffset] = rhs.GetPositionOffset(); + + return node; + } + static bool decode(Node const& node, SHCollider& rhs) + { + if (node[IsTrigger].IsDefined()) + rhs.SetIsTrigger(node[IsTrigger].as()); + if (!node[Type].IsDefined()) + return false; + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + bool ok; + const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as()).convert(&ok); + if (!ok) + return false; + switch (colliderType) + { + case SHCollider::Type::BOX: + { + if(node[HalfExtents].IsDefined()) + rhs.SetBoundingBox(node[HalfExtents].as()); + } + break; + case SHCollider::Type::SPHERE: + { + if(node[Radius].IsDefined()) + rhs.SetBoundingSphere(node[Radius].as()); + } + break; + case SHCollider::Type::CAPSULE: break; + default:; + } + if (node[Friction].IsDefined()) + rhs.SetFriction(node[Friction].as()); + if (node[Bounciness].IsDefined()) + rhs.SetBounciness(rhs.GetBounciness()); + if (node[Density].IsDefined()) + rhs.SetDensity(node[Density].as()); + if (node[PositionOffset].IsDefined()) + rhs.SetPositionOffset(node[PositionOffset].as()); + + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* Colliders = "Colliders"; + static Node encode(SHColliderComponent& rhs) + { + Node node, collidersNode; + auto const& colliders = rhs.GetColliders(); + int const numColliders = static_cast(colliders.size()); + for (int i = 0; i < numColliders; ++i) + { + auto& collider = rhs.GetCollider(i); + Node colliderNode = convert::encode(collider); + if (colliderNode.IsDefined()) + collidersNode[i] = colliderNode; + } + node[Colliders] = collidersNode; + return node; + } + static bool decode(Node const& node, SHColliderComponent& rhs) + { + if (node[Colliders].IsDefined()) + { + int numColliders{}; + for (auto const& colliderNode : node[Colliders]) + { + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + bool ok = false; + const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert::Type].as()).convert(&ok); + if (!ok) + return false; + + switch (colliderType) + { + case SHCollider::Type::BOX: rhs.AddBoundingBox(); break; + case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break; + case SHCollider::Type::CAPSULE: break; + default:; + } + YAML::convert::decode(colliderNode, rhs.GetCollider(numColliders++)); + } + } + return true; + } + }; + template<> struct convert { @@ -46,13 +272,13 @@ namespace YAML propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: - propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: - propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: - propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: default: @@ -135,7 +361,7 @@ namespace YAML return false; rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline()); - if (node[PROPS_YAML_TAG.data()]) + if (node[PROPS_YAML_TAG.data()].IsDefined()) { // Loop through all properties Handle pipelineProperties = rhs.GetShaderBlockInterface(); @@ -192,11 +418,11 @@ namespace YAML } static bool decode(YAML::Node const& node, SHRenderable& rhs) { - if (node[MESH_YAML_TAG.data()]) + if (node[MESH_YAML_TAG.data()].IsDefined()) { rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); } - if (node[MAT_YAML_TAG.data()]) + if (node[MAT_YAML_TAG.data()].IsDefined()) { // TODO: Convert Asset ID To Material HAndle // Temporarily, use default material @@ -210,46 +436,34 @@ namespace YAML }; } - namespace SHADE { struct SHSerializationHelper { - template , bool> = true> - static std::string SerializeComponentToString(ComponentType* component) - { - return std::string(); - } - template , bool> = true> - static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) - { - } static YAML::Node RTTRToNode(const rttr::variant& var) { YAML::Node node; auto varType = var.get_type(); + if (varType.is_sequential_container()) + { + for (auto const& elem : var.create_sequential_view()) + { + node.push_back(RTTRToNode(elem)); + } + } if (varType == rttr::type::get()) { - node.SetStyle(YAML::EmitterStyle::Flow); - node["X"] = var.convert().x; - node["Y"] = var.convert().y; - node["Z"] = var.convert().z; - node["W"] = var.convert().w; + node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { - node.SetStyle(YAML::EmitterStyle::Flow); - node["X"] = var.convert().x; - node["Y"] = var.convert().y; - node["Z"] = var.convert().z; + node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { - node.SetStyle(YAML::EmitterStyle::Flow); - node["X"] = var.convert().x; - node["Y"] = var.convert().y; + node = YAML::convert::encode(var.convert()); } else if (varType.is_arithmetic()) { @@ -300,7 +514,7 @@ namespace SHADE else { auto properties = var.get_type().get_properties(); - for (auto property : properties) + for (auto const& property : properties) { node[property.get_name().data()] = RTTRToNode(property.get_value(var)); } @@ -308,6 +522,17 @@ namespace SHADE return node; } + template , bool> = true> + static std::string SerializeComponentToString(ComponentType* component) + { + return std::string(); + } + + template , bool> = true> + static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) + { + } + template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { @@ -327,15 +552,18 @@ namespace SHADE auto propType = prop.get_type(); if (propType == rttr::type::get()) { - prop.set_value(component, SHSerializationTools::YAMLToVec4(propertyNode)); + SHVec4 vec = propertyNode.as(); + prop.set_value(component, vec); } else if (propType == rttr::type::get()) { - prop.set_value(component, SHSerializationTools::YAMLToVec3(propertyNode)); + SHVec3 vec = propertyNode.as(); + prop.set_value(component, vec); } else if (propType == rttr::type::get()) { - prop.set_value(component, SHSerializationTools::YAMLToVec2(propertyNode)); + SHVec2 vec = propertyNode.as(); + prop.set_value(component, vec); } else if (propType.is_arithmetic()) { @@ -371,9 +599,10 @@ namespace SHADE else { auto properties = propType.get_properties(); - for (auto property : properties) + for (auto const& property : properties) { - InitializeProperty(component, property, propertyNode[property.get_name().data()]); + if(propertyNode[property.get_name().data()].IsDefined()) + InitializeProperty(component, property, propertyNode[property.get_name().data()]); } } } @@ -381,17 +610,17 @@ namespace SHADE template , bool> = true> static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) { - auto component = SHComponentManager::GetComponent_s(eid); + ComponentType* component = SHComponentManager::GetComponent_s(eid); if (componentsNode.IsNull() && !component) return; auto rttrType = rttr::type::get(); auto componentNode = componentsNode[rttrType.get_name().data()]; - if (componentsNode.IsNull()) + if(!componentNode.IsDefined()) return; auto properties = rttrType.get_properties(); for (auto const& prop : properties) { - if (componentNode[prop.get_name().data()]) + if (componentNode[prop.get_name().data()].IsDefined()) { InitializeProperty(component, prop, componentNode[prop.get_name().data()]); } @@ -406,7 +635,7 @@ namespace SHADE return; auto rttrType = rttr::type::get(); auto componentNode = componentsNode[rttrType.get_name().data()]; - if (componentsNode.IsNull()) + if (!componentNode.IsDefined()) return; YAML::convert::decode(componentNode, *component); } diff --git a/SHADE_Engine/src/Tools/Dialog/SHWinDialog.cpp b/SHADE_Engine/src/Tools/Dialog/SHWinDialog.cpp new file mode 100644 index 00000000..bd13801a --- /dev/null +++ b/SHADE_Engine/src/Tools/Dialog/SHWinDialog.cpp @@ -0,0 +1,71 @@ +#include "SHpch.h" +#include "SHWinDialog.h" +#include +#include + +namespace SHADE +{ + void SHWinDialog::DisplayMessageBox(MessageBoxType const& messageBoxType, std::string const& title, std::string const& text) + { + if(messageBoxType == MessageBoxType::MB_MAX) + return; + + UINT flags = MB_APPLMODAL | MB_SETFOREGROUND | MB_OK; + flags |= static_cast(messageBoxType); + + const std::wstring wTitle(title.begin(), title.end()); + const std::wstring wText(text.begin(), text.end()); + + MessageBox(GetDesktopWindow(), wText.data(), wTitle.data(), flags); + } + + std::vector SHWinDialog::DisplayOpenDialog(OpenSaveConfig const& openSaveConfig) + { + const HWND hwnd = GetDesktopWindow(); + HRESULT hResult = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + if(SUCCEEDED(hResult)) + { + IFileOpenDialog* pFileOpen; + + //Create Dialog object + hResult = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast(pFileOpen)); + + if(SUCCEEDED(hResult)) + { + //Show the open dialog box + hResult = pFileOpen->Show(hwnd); + + //Get file name from the dialoh box + if(SUCCEEDED(hResult)) + { + if(openSaveConfig.openMultiple) + { + IShellItemArray* pItemArray; + hResult = pFileOpen->GetResults(&pItemArray); + if(SUCCEEDED(hResult)) + { + + } + } + else + { + IShellItem* pItem; + hResult = pFileOpen->GetResult(&pItem); + if(SUCCEEDED(hResult)) + { + PWSTR pszFilePath; + hResult = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath); + } + } + + } + } + } + return {}; + } + + std::vector SHWinDialog::DisplaySaveAsDialog(OpenSaveConfig const& openSaveConfig) + { + return{}; + } +} diff --git a/SHADE_Engine/src/Tools/Dialog/SHWinDialog.h b/SHADE_Engine/src/Tools/Dialog/SHWinDialog.h new file mode 100644 index 00000000..02fe07b9 --- /dev/null +++ b/SHADE_Engine/src/Tools/Dialog/SHWinDialog.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include + +namespace SHADE +{ + //https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox + enum class MessageBoxType + { + MB_ERROR = 0x00000010L, + MB_QUESTION = 0x00000020L, + MB_WARNING = 0x00000030L, + MB_INFO = 0x00000040L, + MB_MAX = 0 + }; + + struct OpenSaveConfig + { + using Extension = std::string; + using Extensions = std::vector; + using FileTypeDesc = std::pair; + using FilterList = std::vector; + + std::string title = "Open"; + bool openFolders = false; + bool openMultiple = false; + FilterList filterList{}; + }; + + struct SHWinDialog + { + static void DisplayMessageBox(MessageBoxType const& messageBoxType, std::string const& title, std::string const& text); + static std::vector DisplayOpenDialog(OpenSaveConfig const& openSaveConfig); + static std::vector DisplaySaveAsDialog(OpenSaveConfig const& openSaveConfig); + }; +} diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index 1d1196f5..dc17ae7f 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -194,7 +194,7 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Total number of ColliderBounds in the Collider component. + /// Total number of ColliderShapes in the Collider component. /// property int CollisionShapeCount { diff --git a/TempScriptsFolder/PhysicsTest.cs b/TempScriptsFolder/PhysicsTest.cs index 6f9774c9..add5971d 100644 --- a/TempScriptsFolder/PhysicsTest.cs +++ b/TempScriptsFolder/PhysicsTest.cs @@ -28,7 +28,7 @@ public class PhysicsTest : Script Debug.LogError("Collider is NULL!"); } - var subColider = Collider.ColliderBoundsCount; + var subColider = Collider.CollisionShapeCount; Debug.Log($"There are {subColider} colliders."); } protected override void update() diff --git a/TempShaderFolder/DeferredCompositeCs.glsl b/TempShaderFolder/DeferredCompositeCs.glsl new file mode 100644 index 00000000..c1caf0aa --- /dev/null +++ b/TempShaderFolder/DeferredCompositeCs.glsl @@ -0,0 +1,83 @@ +#version 450 + +struct DirectionalLightStruct +{ + vec3 direction; + uint isActive; + uint cullingMask; + vec4 diffuseColor; +}; + +struct AmbientLightStruct +{ + vec4 ambientColor; + float strength; + uint isActive; + uint cullingMask; +}; + +layout(local_size_x = 16, local_size_y = 16) in; +layout(set = 4, binding = 0, rgba32f) uniform image2D positions; +layout(set = 4, binding = 1, rgba32f) uniform image2D normals; +layout(set = 4, binding = 2, rgba8) uniform image2D albedo; +layout(set = 4, binding = 3, r32ui) uniform uimage2D lightLayerData; +layout(set = 4, binding = 4, rgba8) uniform image2D targetImage; + +layout(set = 1, binding = 0) uniform LightCounts +{ + uint directionalLights; + uint pointLights; + uint spotLights; + uint ambientLights; + +} lightCounts; + +layout(std430, set = 1, binding = 1) buffer DirectionalLightData +{ + DirectionalLightStruct dLightData[]; +} DirLightData; + +layout(std430, set = 1, binding = 4) buffer AmbientLightData +{ + AmbientLightStruct aLightData[]; +} AmbLightData; + +void main() +{ + // convenient variables + ivec2 globalThread = ivec2(gl_GlobalInvocationID); + + // Get the diffuse color of the pixel + vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; + + // Get position of fragment in world space + vec3 positionWorld = imageLoad (positions, globalThread).rgb; + + // normal of fragment + vec3 normalWorld = imageLoad(normals, globalThread).rgb; + + vec3 fragColor = vec3 (0.0f); + + for (int i = 0; i < lightCounts.directionalLights; ++i) + { + // get normalized direction of light + vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction); + + // Get diffuse strength + float diffuseStrength = max (0, dot (dLightNormalized, normalWorld)); + + // Calculate the fragment color + fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; + } + + for (int i = 0; i < lightCounts.ambientLights; ++i) + { + // Just do some add + //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); + fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + } + + // store result into result image + imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor, 1.0f)); + +} \ No newline at end of file diff --git a/TempShaderFolder/DeferredCompositeCs.spv b/TempShaderFolder/DeferredCompositeCs.spv new file mode 100644 index 00000000..03ef7ac5 Binary files /dev/null and b/TempShaderFolder/DeferredCompositeCs.spv differ diff --git a/TempShaderFolder/TestCubeFs.spv b/TempShaderFolder/TestCubeFs.spv new file mode 100644 index 00000000..2381b834 Binary files /dev/null and b/TempShaderFolder/TestCubeFs.spv differ diff --git a/TempShaderFolder/TestCubeVs.spv b/TempShaderFolder/TestCubeVs.spv new file mode 100644 index 00000000..d8c3c3d0 Binary files /dev/null and b/TempShaderFolder/TestCubeVs.spv differ