diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 5673556d..ee5e42a8 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97158628 +Starting Scene ID: 87244611 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Bindings.SHConfig b/Assets/Bindings.SHConfig index 573541ac..bdc254b5 100644 --- a/Assets/Bindings.SHConfig +++ b/Assets/Bindings.SHConfig @@ -1 +1,96 @@ +7 +Controller Look Horizontal 0 +0 +5 +0.2 +5 +0 +0 +0 +1 +18 +0 +Controller Look Vertical +0 +0 +5 +0.2 +5 +0 +0 +0 +1 +19 +0 +Horizontal +0 +0 +5 +0.2 +5 +1 +2 +39 +68 +2 +37 +65 +2 +3 +16 +1 +2 +Jump +0 +0 +1000 +0.2 +1000 +0 +1 +32 +0 +1 +10 +0 +Mouse Look Horizontal +1 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 +Mouse Look Vertical +2 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 +Vertical +0 +0 +5 +0.2 +5 +1 +2 +38 +87 +2 +40 +83 +2 +0 +17 +1 +1 diff --git a/Assets/Editor/Editor.SHConfig b/Assets/Editor/Editor.SHConfig new file mode 100644 index 00000000..51425027 --- /dev/null +++ b/Assets/Editor/Editor.SHConfig @@ -0,0 +1,4 @@ +Start Maximized: true +Working Scene ID: 97161771 +Window Size: {x: 1920, y: 1080} +Style: 0 \ No newline at end of file diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 2f38a933..de902c55 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -7,6 +7,7 @@ Translate: {x: 0, y: 0.304069757, z: 1.73034382} Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Camera Component: Position: {x: 0, y: 0.304069757, z: 1.73034382} Pitch: 0 @@ -17,6 +18,7 @@ Near: 0.00999999978 Far: 10000 Perspective: true + IsActive: true Scripts: ~ - EID: 1 Name: Raccoon @@ -24,12 +26,14 @@ NumberOfChildren: 1 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: -1.86388135, y: 0.0544953719, z: 0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Renderable Component: Mesh: 149697411 Material: 126974645 + IsActive: true Scripts: ~ - EID: 3 Name: Bag @@ -40,9 +44,11 @@ Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Rotate: {x: -0, y: 2.79945588, z: 0} Scale: {x: 1.0000881, y: 1, z: 1.0000881} + IsActive: true Renderable Component: Mesh: 144838771 Material: 123745521 + IsActive: true Scripts: ~ - EID: 2 Name: DirectionalLight @@ -50,12 +56,13 @@ NumberOfChildren: 0 Components: Light Component: - Position: {x: 0, y: 0, z: 0} + Position: {x: 3, y: 4.5, z: 7} Type: Directional - Direction: {x: 0, y: 0, z: 1} + Direction: {x: -0.298000008, y: 0.522498012, z: 0.798600018} Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0 + IsActive: true Scripts: ~ - EID: 4 Name: AmbientLight @@ -69,4 +76,20 @@ Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0.600000024 + IsActive: true + Scripts: ~ +- EID: 5 + Name: Floor + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0.0810000002, z: 0} + Rotate: {x: -1.57079637, y: 0, z: 0} + Scale: {x: 50, y: 50, z: 50} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 124370424 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Scenes/UI_Test.shade b/Assets/Scenes/UI_Test.shade index e8ee4df2..0026a48b 100644 --- a/Assets/Scenes/UI_Test.shade +++ b/Assets/Scenes/UI_Test.shade @@ -1,7 +1,7 @@ - EID: 0 Name: Canvas IsActive: true - NumberOfChildren: 1 + NumberOfChildren: 2 Components: Canvas Component: Canvas Width: 10 @@ -28,6 +28,26 @@ Clicked Texture: 0 IsActive: true Scripts: ~ +- EID: 5 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: -3.9000001, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 129340704 + IsActive: true + Toggle Button Component: + Non Toggled Texture: 0 + Toggled Texture: 0 + Value: true + IsActive: true + Scripts: ~ - EID: 1 Name: Camera IsActive: true diff --git a/Assets/Scenes/UI_Test.shade.shmeta b/Assets/Scenes/UI_Test.shade.shmeta index 8b8d6f22..77355480 100644 --- a/Assets/Scenes/UI_Test.shade.shmeta +++ b/Assets/Scenes/UI_Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI_Test -ID: 87707373 +ID: 87244611 Type: 5 diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 0a8085b1..d28eaec0 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -6,6 +6,8 @@ struct DirectionalLightStruct uint isActive; uint cullingMask; vec4 diffuseColor; + mat4 pvMatrix; + uint shadowData; }; struct AmbientLightStruct @@ -22,7 +24,10 @@ layout(set = 3, binding = 1, rgba32f) uniform image2D normals; layout(set = 3, binding = 2, rgba8) uniform image2D albedo; layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; -layout(set = 3, binding = 5, rgba8) uniform image2D targetImage; +layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace; +layout(set = 3, binding = 6, rgba8) uniform image2D targetImage; + +layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global) layout(set = 1, binding = 0) uniform LightCounts { @@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData AmbientLightStruct aLightData[]; } AmbLightData; +float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV) +{ + vec4 fragPosLightPOV = lightPV * worldSpaceFragPos; + vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f); + + float sampledDepth = texture(shadowMap, converted.xy).r; + + if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f) + return 1.0f; + + if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f) + { + return 0.0f; + } + else + return 1.0f; + // return step (fragPosLightPOV.z, ); +} + void main() { // convenient variables @@ -52,6 +76,9 @@ void main() vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; // Get position of fragment in world space + vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f); + + // Get position of fragment in view spacee vec3 positionView = imageLoad (positions, globalThread).rgb; // normal of fragment @@ -62,6 +89,18 @@ void main() vec3 fragColor = vec3 (0.0f); + vec4 shadowMapColor = vec4 (1.0f); + + for (int i = 0; i < lightCounts.ambientLights; ++i) + { + if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) + { + // 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); + } + } + for (int i = 0; i < lightCounts.directionalLights; ++i) { if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) @@ -74,16 +113,13 @@ void main() // Calculate the fragment color fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; - } - } - for (int i = 0; i < lightCounts.ambientLights; ++i) - { - if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) - { - // 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); + // If the shadow map is enabled (test the bit) + if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) + { + // calculate shadow map here + fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx; + } } } @@ -92,6 +128,12 @@ void main() // store result into result image imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); - //imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f)); + + // vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f); + // vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords); + // if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f) + // shadowMapVal = vec4(0.0f); + + // imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx); } \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index cabce080..ceca4e13 100644 Binary files a/Assets/Shaders/DeferredComposite_CS.shshaderb and b/Assets/Shaders/DeferredComposite_CS.shshaderb differ diff --git a/Assets/Shaders/ShadowMap_VS.glsl b/Assets/Shaders/ShadowMap_VS.glsl new file mode 100644 index 00000000..e078679e --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.glsl @@ -0,0 +1,22 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + +//#include "ShaderDescriptorDefinitions.glsl" + + +layout(location = 0) in vec3 aVertexPos; +layout(location = 4) in mat4 worldTransform; + +layout(set = 1, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 projMat; +} cameraData; + +void main() +{ + // clip space for rendering + gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb b/Assets/Shaders/ShadowMap_VS.shshaderb new file mode 100644 index 00000000..3a8734c9 Binary files /dev/null and b/Assets/Shaders/ShadowMap_VS.shshaderb differ diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta new file mode 100644 index 00000000..837cec19 --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ShadowMap_VS +ID: 44646107 +Type: 2 diff --git a/Assets/Shaders/TestCube_FS.glsl b/Assets/Shaders/TestCube_FS.glsl index b6a1eab6..cb7bfefd 100644 --- a/Assets/Shaders/TestCube_FS.glsl +++ b/Assets/Shaders/TestCube_FS.glsl @@ -16,11 +16,12 @@ layout(location = 0) in struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } In; // material stuff -layout(location = 3) flat in struct +layout(location = 4) flat in struct { int materialIndex; uint eid; @@ -38,12 +39,14 @@ layout(location = 1) out uint outEntityID; layout(location = 2) out uint lightLayerIndices; layout(location = 3) out vec4 normals; layout(location = 4) out vec4 albedo; +layout(location = 5) out vec4 worldSpacePosition; void main() { position = In.vertPos; normals = In.normal; albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color; + worldSpacePosition = In.worldPos; outEntityID = In2.eid; lightLayerIndices = In2.lightLayerIndex; diff --git a/Assets/Shaders/TestCube_FS.shshaderb b/Assets/Shaders/TestCube_FS.shshaderb index abd90cf7..2974523d 100644 Binary files a/Assets/Shaders/TestCube_FS.shshaderb and b/Assets/Shaders/TestCube_FS.shshaderb differ diff --git a/Assets/Shaders/TestCube_VS.glsl b/Assets/Shaders/TestCube_VS.glsl index 554ce379..041c552f 100644 --- a/Assets/Shaders/TestCube_VS.glsl +++ b/Assets/Shaders/TestCube_VS.glsl @@ -17,11 +17,12 @@ layout(location = 0) out struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } Out; // material stuff -layout(location = 3) out struct +layout(location = 4) out struct { int materialIndex; uint eid; @@ -49,6 +50,8 @@ void main() // gBuffer position will be in view space Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); + Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f); + // uvs for texturing in fragment shader Out.uv = aUV; diff --git a/Assets/Shaders/TestCube_VS.shshaderb b/Assets/Shaders/TestCube_VS.shshaderb index a1138f75..0467a41d 100644 Binary files a/Assets/Shaders/TestCube_VS.shshaderb and b/Assets/Shaders/TestCube_VS.shshaderb differ diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 8ef7ff64..6feece48 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -270,8 +270,12 @@ namespace SHADE camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset); camera.viewMatrix(2, 3) = -view.Dot(camera.position + camera.offset); - - + //SHVec3 target{ 0.0f,0.0f,-1.0f }; + //target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); + //target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw)); + //target += camera.position; + + //camera.viewMatrix = SHMatrix::Transpose(SHMatrix::LookAtLH(camera.position, target, SHVec3(0.0f, -1.0f, 0.0f))); camera.dirtyView = false; } @@ -309,7 +313,9 @@ namespace SHADE camera.orthoProjMatrix(2, 3) = -n / (f-n); camera.orthoProjMatrix(3, 3) = 1.0f; - //camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f); + camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f); //camera.projMatrix.Transpose(); camera.dirtyProj = false; diff --git a/SHADE_Engine/src/Common/SHAllComponents.h b/SHADE_Engine/src/Common/SHAllComponents.h new file mode 100644 index 00000000..9d280677 --- /dev/null +++ b/SHADE_Engine/src/Common/SHAllComponents.h @@ -0,0 +1,15 @@ +#pragma once +#include "Camera/SHCameraComponent.h" +#include "Camera/SHCameraArmComponent.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "UI/SHCanvasComponent.h" +#include "UI/SHButtonComponent.h" +#include "UI/SHUIComponent.h" +#include "UI/SHToggleButtonComponent.h" +#include "UI/SHSliderComponent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp index bd39b38e..a7ba7dc0 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp @@ -239,10 +239,7 @@ namespace SHADE case AssetType::TEXTURE: break; case AssetType::MESH: break; case AssetType::SCENE: - if(auto editor = SHSystemManager::GetSystem()) - { editor->LoadScene(asset->id); - } break; case AssetType::PREFAB: break; case AssetType::MATERIAL: @@ -262,6 +259,13 @@ namespace SHADE } } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("AssetID: %zu | Path: %s", asset->id, asset->path.c_str()); + ImGui::EndTooltip(); + } + //TODO: Combine Draw asset and Draw Folder recursive drawing const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark); const float horizontalOffset = 0.0f; diff --git a/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp new file mode 100644 index 00000000..31e6edde --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp @@ -0,0 +1,33 @@ +#include "SHpch.h" +#include "SHEditorPopups.h" +#include "Editor/SHEditor.h" +#include "misc/cpp/imgui_stdlib.h" + +namespace SHADE +{ + void SHSceneSavePrompt::Draw() + { + if(Begin()) + { + static std::string newSceneName{}; + ImGui::Text("Enter new scene name"); + ImGui::InputText("##name", &newSceneName); + ImGui::BeginDisabled(newSceneName.empty()); + if (ImGui::Button("Save")) + { + editor->SaveScene(newSceneName); + newSceneName.clear(); + isOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndDisabled(); + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + { + isOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h new file mode 100644 index 00000000..9e37a98a --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h @@ -0,0 +1,17 @@ +#pragma once + +#include "SH_API.h" +#include "Editor/EditorWindow/SHPopUpWindow.h" + +namespace SHADE +{ + class SHSceneSavePrompt : public SHPopUpWindow + { + public: + SHSceneSavePrompt():SHPopUpWindow("Save Scene As", true, 0, 0){} + void Draw() override; + + private: + + }; +} \ 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 6ac5933c..ef4ad35e 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp @@ -3,6 +3,11 @@ //#==============================================================# #include "SHpch.h" +//#==============================================================# +//|| Library Includes || +//#==============================================================# +#include + //#==============================================================# //|| SHADE Includes || //#==============================================================# @@ -16,14 +21,11 @@ #include "Tools/SHException.h" #include "Editor/IconsMaterialDesign.h" #include "SHHierarchyPanelCommands.h" - -//#==============================================================# -//|| Library Includes || -//#==============================================================# -#include +#include "Common/SHAllComponents.h" #include "Serialization/SHSerialization.h" #include "Tools/Utilities/SHClipboardUtilities.h" +#include "Tools/Utilities/SHStringUtilities.h" namespace SHADE @@ -80,7 +82,6 @@ namespace SHADE if (ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - if (auto editor = SHSystemManager::GetSystem()) editor->selectedEntities.clear(); } ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal); @@ -99,7 +100,6 @@ namespace SHADE } 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()); @@ -141,16 +141,18 @@ namespace SHADE //#==============================================================# //|| Private Member Functions || //#==============================================================# - void SHHierarchyPanel::DrawMenuBar() const noexcept + void SHHierarchyPanel::DrawMenuBar() noexcept { if (ImGui::BeginMenuBar()) { auto size = ImGui::GetWindowSize(); auto g = ImGui::GetCurrentContext(); + + DrawHierarchyPanelFilter(); + ImGui::SetCursorPosX(size.x - g->Style.FramePadding.x * 15.0f); if (ImGui::SmallButton(ICON_MD_CLEAR_ALL)) { - auto editor = SHSystemManager::GetSystem(); editor->selectedEntities.clear(); } if (ImGui::IsItemHovered()) @@ -173,6 +175,56 @@ namespace SHADE } } + void SHHierarchyPanel::DrawHierarchyPanelFilter() noexcept + { + if(ImGui::InputTextWithHint("##hierarchyPanelFilter", "Filter", &filter)) + { + + } + ImGui::SameLine(); + if(ImGui::Button("x")) + { + filter.clear(); + } + } + + bool SHHierarchyPanel::EntityFilterCheck(SHSceneNode* entityNode) noexcept + { + if(!entityNode || filter.empty()) + return false; + + EntityID const eid = entityNode->GetEntityID(); + SHEntity* entity = SHEntityManager::GetEntityByID(eid); + + bool result = false; + + result |= SHStringUtilities::StringFindInsensitive(entity->name, filter) != std::string::npos; + + if(SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos) + { + result |= SHComponentManager::HasComponent(eid); + } + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + + //std::vector const& children = entityNode->GetChildren(); + + //for (auto const& child : children) + //{ + // result |= EntityFilterCheck(child); + //} + + return result; + } + ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode) { if (currentNode == nullptr) @@ -189,21 +241,39 @@ namespace SHADE scrollTo = MAX_EID; } - auto editor = SHSystemManager::GetSystem(); + auto* entity = SHEntityManager::GetEntityByID(eid); const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end()); - const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow); - - //bool highlighted = false; - //if(highlighted) + bool highlighted = false; + //if(!filter.empty()) //{ - // ImGui::PushStyleColor(ImGuiCol_Text, highlightedColor); + // highlighted = EntityFilterCheck(currentNode); + // if (highlighted) + // { + // ImGui::PushStyleColor(ImGuiCol_Text, highlightedColor); + // + // ImGui::SetNextItemOpen(true); + // + // + // } + // else + // { + // + // } //} - auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID()); + const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow); + + //Draw Node - bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); + bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); + + if (highlighted) + { + ImGui::PopStyleColor(); + } + const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); //Check For Begin Drag @@ -336,6 +406,7 @@ namespace SHADE drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 2); ImGui::TreePop(); } + return nodeRect; } @@ -350,7 +421,6 @@ namespace SHADE std::vector entitiesToParent = CleanUpEIDList(entities); - //auto const editor = SHSystemManager::GetSystem(); SHEntityParentCommand::EntityParentData entityParentData; std::vector parentedEIDS; for (auto const& eid : entitiesToParent) @@ -371,7 +441,7 @@ namespace SHADE void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID) { bool startSelecting = false; bool endSelecting = false; - auto const editor = SHSystemManager::GetSystem(); + editor->selectedEntities.clear(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); sceneGraph.Traverse([&](SHSceneNode* nodePtr) @@ -403,7 +473,6 @@ namespace SHADE void SHHierarchyPanel::SelectAllEntities() { - const auto editor = SHSystemManager::GetSystem(); editor->selectedEntities.clear(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); sceneGraph.Traverse([&](SHSceneNode* nodePtr) @@ -415,7 +484,6 @@ namespace SHADE void SHHierarchyPanel::CopySelectedEntities() { - const auto editor = SHSystemManager::GetSystem(); std::vector entitiesToCopy = CleanUpEIDList(editor->selectedEntities); SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(entitiesToCopy)); } @@ -428,7 +496,6 @@ namespace SHADE void SHHierarchyPanel::DeleteSelectedEntities() { - const auto editor = SHSystemManager::GetSystem(); std::vector entitiesToDelete = CleanUpEIDList(editor->selectedEntities); SHCommandManager::PerformCommand(std::make_shared(entitiesToDelete)); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h index 9278a0a3..c6670948 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h @@ -10,6 +10,8 @@ #include "imgui_internal.h" #include "ECS_Base/SHECSMacros.h" #include "Editor/EditorWindow/SHEditorWindow.h" +#include "ECS_Base/Entity/SHEntity.h" + namespace SHADE { class SHSceneNode; @@ -24,7 +26,11 @@ namespace SHADE void Exit() override; void SetScrollTo(EntityID eid); private: - void DrawMenuBar() const noexcept; + void DrawMenuBar() noexcept; + void DrawHierarchyPanelFilter() noexcept; + + bool EntityFilterCheck(SHSceneNode* entityNode) noexcept; + ImRect RecursivelyDrawEntityNode(SHSceneNode* const); void CreateChildEntity(EntityID parentEID) const noexcept; void ParentSelectedEntities(EntityID parentEID, std::vector const& entities) noexcept; diff --git a/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.cpp new file mode 100644 index 00000000..d3fa33fa --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.cpp @@ -0,0 +1,546 @@ +#include "SHpch.h" +#include "SHInputBindingsPanel.h" +#include "Input/SHInputManager.h" +#include "Editor/SHEditorWidgets.hpp" + +namespace SHADE +{ + //Vectors containing data for elements for different bindings + static std::vector bindingRenames; + + //Flags to prevent unwanted editing of bindings + static size_t positiveKeyListeningFor; + static bool positiveKeyListening; + + static size_t negativeKeyListeningFor; + static bool negativeKeyListening; + + static size_t positiveControllerListeningFor; + static bool positiveControllerListening; + + static size_t negativeControllerListeningFor; + static bool negativeControllerListening; + + //Internal Helper function + void resizeVectors(size_t newSize) + { + bindingRenames.resize(newSize); + for (auto& s : bindingRenames) + s.clear(); + } + + //Internal Helper function + std::string labelConcat(char const* label, size_t entryNumber) + { + std::string concat = label; + concat += std::to_string(entryNumber); + return concat; + } + + void SHInputBindingsPanel::Init() + { + SHEditorWindow::Init(); + } + + void SHInputBindingsPanel::Update() + { + if (SHEditorWindow::Begin()) + { + //ImGui::ShowDemoWindow(); + + //Binding count + ImGui::Text("Binding Count: %d", SHInputManager::CountBindings()); + + //Binding file name + static std::string bindingFileName; + ImGui::InputText("Binding File Path", &bindingFileName); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text(".SHConfig will be appeneded to file name"); + ImGui::Text("If no name is provided, saves to or loads from \"Assets/Bindings.SHConfig\""); + ImGui::EndTooltip(); + } + + //Save bindings to... + if (ImGui::Button("Save Bindings")) + { + if (bindingFileName.empty()) + { + SHInputManager::SaveBindings(); + } + else + { + std::string filePath = std::string(ASSET_ROOT); + filePath += "/"; + filePath += bindingFileName; + filePath += ".SHConfig"; + SHInputManager::SaveBindings(filePath); + } + } + + //Load bindings from... + if (ImGui::Button("Load Bindings")) + { + if (bindingFileName.empty()) + { + SHInputManager::LoadBindings(); + } + else + { + std::string filePath = std::string(ASSET_ROOT); + filePath += "/"; + filePath += bindingFileName; + filePath += ".SHConfig"; + SHInputManager::LoadBindings(filePath); + } + resizeVectors(SHInputManager::CountBindings()); + } + + //Button to add new binding + if (ImGui::Button("Add New Binding")) + { + std::string newBindingName = "Binding" + std::to_string(SHInputManager::CountBindings()); + SHInputManager::AddBinding(newBindingName); + resizeVectors(SHInputManager::CountBindings()); + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Add a new binding to the list"); + ImGui::EndTooltip(); + } + + //Ensure unique label for entries + size_t entryNumber = 0; + + //Listing for each binding + for (auto& binding : SHInputManager::GetBindings()) + { + if (ImGui::CollapsingHeader(binding.first.c_str())) + { + //Modifiable binding name + ImGui::Text("Binding Name: %s", binding.first.c_str()); + ImGui::InputText(labelConcat("##bindingModifyName", entryNumber).c_str(), &bindingRenames[entryNumber]); + ImGui::SameLine(); + if (ImGui::Button(labelConcat("Rename##bindingRename", entryNumber).c_str())) + { + SHInputManager::RenameBinding(binding.first, bindingRenames[entryNumber]); + bindingRenames[entryNumber].clear(); + } + + if (ImGui::Button(labelConcat("Delete Binding##", entryNumber).c_str())) + { + SHInputManager::RemoveBinding(binding.first); + resizeVectors(SHInputManager::CountBindings()); + ImGui::End(); + return; + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Delete this binding from the list"); + ImGui::EndTooltip(); + } + + //Binding value test + ImGui::BeginDisabled(); + float val = SHInputManager::GetBindingAxis(binding.first); + ImGui::SliderFloat(labelConcat("Value##", entryNumber).c_str(), &val, -1.0f, 1.0f); + ImGui::EndDisabled(); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Test the current value of the binding"); + ImGui::Text("For mouse movement/wheel inputs, will be multiplied by Sensitivity, with 0 being neutral (no input detected)"); + ImGui::Text("Between -1 and 1 for other inputs, with 0 still being neutral (no input detected)"); + ImGui::EndTooltip(); + } + ImGui::BeginDisabled(); + float rawVal = SHInputManager::GetBindingAxisRaw(binding.first); + ImGui::SliderFloat(labelConcat("Raw Value##", entryNumber).c_str(), &rawVal, -1.0f, 1.0f); + ImGui::EndDisabled(); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Test the current value of the binding"); + ImGui::Text("Raw value means it will be fixed among -1, 0 and 1 for non-mouse movement/wheel inputs"); + ImGui::Text("No difference between this and Value for mouse movement/wheel inputs"); + ImGui::Text("But for other inputs, does not consider smoothing options such as gravity and sensitivity"); + ImGui::Text("If both positive and negative input is detected, returns neutral 0"); + ImGui::EndTooltip(); + } + + //Binding Type Combo Box + int bindingType = static_cast(SHInputManager::GetBindingType(binding.first)); + if (ImGui::Combo(labelConcat("Input Type##", entryNumber).c_str(), &bindingType, "Keyboard / Mouse Buttons / Controller\0Mouse Horizontal\0Mouse Vertical\0Mouse Scroll Wheel")) + SHInputManager::SetBindingType(binding.first, static_cast(bindingType)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Which of the four types the binding uses"); + ImGui::Text("Keyboard / Mouse Buttons / Controller = Keys, mouse buttons and ALL controller inputs"); + ImGui::Text("Mouse Horizontal = Horizontal movement of the mouse"); + ImGui::Text("Mouse Vertical = Vertical movement of the mouse"); + ImGui::Text("Mouse Scroll Wheel = The scroll wheel found at the middle of most mouses"); + ImGui::EndTooltip(); + } + + //Inversion + bool bindingInvert = SHInputManager::GetBindingInverted(binding.first); + if (ImGui::Checkbox(labelConcat("Inverted##", entryNumber).c_str(), &bindingInvert)) + SHInputManager::SetBindingInverted(binding.first, bindingInvert); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("If inverted:"); + ImGui::Text("Positive inputs mean negative value of the binding"); + ImGui::Text("Negative inputs mean positive value of the binding"); + ImGui::Text("Mouse moving up / right means negative value of the binding"); + ImGui::Text("Scrolling the mouse wheel up means negative value of the binding"); + ImGui::EndTooltip(); + } + + //Sensitivity + double bindingSensitivity = SHInputManager::GetBindingSensitivity(binding.first); + if (ImGui::InputDouble(labelConcat("Sensitivity##", entryNumber).c_str(), &bindingSensitivity)) + SHInputManager::SetBindingSensitivity(binding.first, bindingSensitivity); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Value multiplier for mouse movement and scrolling"); + ImGui::Text("For other digital inputs, serves as a rate of how fast axis value goes to maximum positive/negative"); + //ImGui::Text("For other analog inputs, serves as a multiplier, but axis value magnitude will still be capped at 1"); + ImGui::Text("Irrelevant for other analog inputs"); + ImGui::EndTooltip(); + } + + //Below this section is only for KB/M type bindings + //Not relevant for mouse movement and scrolling + if (SHInputManager::GetBindingType(binding.first) == SHInputManager::SH_BINDINGTYPE::KB_MB_CONTROLLER) + { + //Dead + float bindingDead = static_cast(SHInputManager::GetBindingDead(binding.first)); + if (ImGui::SliderFloat(labelConcat("Deadzone##", entryNumber).c_str(), &bindingDead, 0.0f, 1.0f)) + SHInputManager::SetBindingDead(binding.first, static_cast(bindingDead)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Any positive or negative analog input with magnitude less than this will be registered as neutral"); + ImGui::EndTooltip(); + } + + //Gravity + double bindingGravity = SHInputManager::GetBindingGravity(binding.first); + if (ImGui::InputDouble(labelConcat("Gravity##", entryNumber).c_str(), &bindingGravity)) + SHInputManager::SetBindingGravity(binding.first, static_cast(bindingGravity)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("The rate at which the value moves to neutral if no input in the direction is read"); + ImGui::TextColored(ImVec4{ 1.0f, 0.5f, 0.5f, 1.0f }, "Should be non-negative"); + ImGui::EndTooltip(); + } + + //Snap + bool bindingSnap = SHInputManager::GetBindingSnap(binding.first); + if (ImGui::Checkbox(labelConcat("Snap##", entryNumber).c_str(), &bindingSnap)) + SHInputManager::SetBindingSnap(binding.first, bindingSnap); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("If no other input on the axis is present and a input is made in the opposite direction of the current value,"); + ImGui::Text("the binding's value will jump to neutral 0 before resuming in the input direction"); + ImGui::EndTooltip(); + } + + size_t keycodeIndex = 0; + //Positive key codes + ImGui::Separator(); + ImGui::Text("Positive Key Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this keyboard or mouse button is held, causes the value to go positive, or negative when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!positiveKeyListening) + { + if (ImGui::Button(labelConcat("New##positiveKeyCode", entryNumber).c_str())) + { + positiveKeyListening = true; + positiveKeyListeningFor = entryNumber; + } + } + else + { + if (positiveKeyListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##positiveKeyCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_KEYCODE k; + if (SHInputManager::AnyKey(&k)) + { + positiveKeyListening = false; + SHInputManager::AddBindingPositiveKeyCode(binding.first, k); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##positiveKeyCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& k : binding.second.positiveKeyCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetKeyCodeName(k).c_str()); + ImGui::SameLine(); + std::string labelString = "X##KeyPositive"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingPositiveKeyCode(binding.first, k); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + + + //Negative key codes + ImGui::Separator(); + ImGui::Text("Negative Key Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this keyboard or mouse button is held, causes the value to go negative, or positive when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!negativeKeyListening) + { + if (ImGui::Button(labelConcat("New##negativeKeyCode", entryNumber).c_str())) + { + negativeKeyListening = true; + negativeKeyListeningFor = entryNumber; + } + } + else + { + if (negativeKeyListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##negativeKeyCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_KEYCODE k; + if (SHInputManager::AnyKey(&k)) + { + negativeKeyListening = false; + SHInputManager::AddBindingNegativeKeyCode(binding.first, k); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##negativeKeyCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& k : binding.second.negativeKeyCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetKeyCodeName(k).c_str()); + ImGui::SameLine(); + std::string labelString = "X##KeyNegative"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingNegativeKeyCode(binding.first, k); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + + //Positive controller codes + ImGui::Separator(); + ImGui::Text("Positive Controller Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this controller button is held, causes the value to go positive, or negative when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!positiveControllerListening) + { + if (ImGui::Button(labelConcat("New##positiveControllerCode", entryNumber).c_str())) + { + positiveControllerListening = true; + positiveControllerListeningFor = entryNumber; + } + } + else + { + if (positiveControllerListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##positiveControllerCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_CONTROLLERCODE c; + if (SHInputManager::AnyControllerInput(&c)) + { + positiveControllerListening = false; + SHInputManager::AddBindingPositiveControllerCode(binding.first, c); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##positiveControllerCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& c : binding.second.positiveControllerCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetControllerCodeName(c).c_str()); + ImGui::SameLine(); + std::string labelString = "X##ControllerPositive"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingPositiveControllerCode(binding.first, c); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + + //Negative controller codes + ImGui::Separator(); + ImGui::Text("Negative Controller Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this controller button is pressed, causes the value to go negative, or positive when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!negativeControllerListening) + { + if (ImGui::Button(labelConcat("New##negativeControllerCode", entryNumber).c_str())) + { + negativeControllerListening = true; + negativeControllerListeningFor = entryNumber; + } + } + else + { + if (negativeControllerListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##negativeControllerCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_CONTROLLERCODE c; + if (SHInputManager::AnyControllerInput(&c)) + { + negativeControllerListening = false; + SHInputManager::AddBindingNegativeControllerCode(binding.first, c); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##negativeControllerCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& c : binding.second.negativeControllerCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetControllerCodeName(c).c_str()); + ImGui::SameLine(); + std::string labelString = "X##ControllerNegative"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingNegativeControllerCode(binding.first, c); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + } + } + ++entryNumber; //Next entry + } + } + ImGui::End(); + } + + void SHInputBindingsPanel::Exit() + { + SHEditorWindow::Exit(); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.h b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.h new file mode 100644 index 00000000..db2ec0c8 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Editor/EditorWindow/SHEditorWindow.h" +#include + +namespace SHADE +{ + class SH_API SHInputBindingsPanel final : public SHEditorWindow + { + public: + SHInputBindingsPanel() : SHEditorWindow("Input Bindings Panel", ImGuiWindowFlags_MenuBar) {} + + void Init() override; + void Update() override; + void Exit() override; + }; +} \ 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 45964930..3e1fdc44 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -77,7 +77,7 @@ namespace SHADE ImGui::PushID(SHFamilyID::GetID()); 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())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); auto const& properties = componentType.get_properties(); @@ -234,7 +234,7 @@ namespace SHADE const auto componentType = rttr::type::get(); 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())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); @@ -328,7 +328,7 @@ namespace SHADE 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())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); @@ -446,7 +446,7 @@ namespace SHADE 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())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); @@ -478,7 +478,7 @@ namespace SHADE 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())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); Handle const& mesh = component->GetMesh(); @@ -536,7 +536,7 @@ namespace SHADE 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())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); Handle const& font = component->GetFont(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 83647da7..55de44cc 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -21,6 +21,7 @@ #include "UI/SHUIComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" +#include "UI/SHToggleButtonComponent.h" #include "SHEditorComponentView.h" #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" @@ -93,7 +94,6 @@ namespace SHADE SHEditorWindow::Update(); if (Begin()) { - auto editor = SHSystemManager::GetSystem(); if (editor && !editor->selectedEntities.empty()) { EntityID const& eid = editor->selectedEntities[0]; @@ -154,6 +154,10 @@ namespace SHADE { DrawComponent(buttonComponent); } + if (auto toggleButton = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(toggleButton); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -167,6 +171,7 @@ namespace SHADE DrawAddComponentButton(eid); 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 5014dbdd..3fe9ceb5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -110,7 +110,7 @@ namespace SHADE { ImGui::BeginMenuBar(); ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.5f - 80.f); - const auto editor = SHSystemManager::GetSystem(); + ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY); if(ImGui::SmallButton(ICON_MD_PLAY_ARROW)) { @@ -165,16 +165,18 @@ namespace SHADE { if (ImGui::Selectable("New Scene")) { - SHSystemManager::GetSystem()->NewScene(); + editor->NewScene(); } if (ImGui::Selectable("Save")) { - SHSystemManager::GetSystem()->SaveScene(); + editor->SaveScene(); } + ImGui::BeginDisabled(true); if (ImGui::Selectable("Load")) { //SHSystemManager::GetSystem()->LoadScene() } + ImGui::EndDisabled(); ImGui::EndMenu(); } } @@ -211,7 +213,7 @@ namespace SHADE auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); scriptEngine->OpenSolution(); } - ImGui::BeginDisabled(SHSystemManager::GetSystem()->editorState != SHEditor::State::STOP); + ImGui::BeginDisabled(editor->editorState != SHEditor::State::STOP); if (ImGui::Selectable("Build Scripts - Debug")) { auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -252,7 +254,6 @@ namespace SHADE { if (ImGui::Selectable(style.to_string().c_str())) { - if (auto editor = SHSystemManager::GetSystem()) editor->SetStyle(style.convert()); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp index 5f00cc37..05059336 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp @@ -7,6 +7,8 @@ //|| SHADE Includes || //#==============================================================# #include "SHEditorWindow.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/SHEditor.h" //#==============================================================# //|| Library Includes || @@ -21,6 +23,7 @@ namespace SHADE SHEditorWindow::SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags) :isOpen(true), isWindowHovered(false), windowName(name), windowFlags(inFlags), io(ImGui::GetIO()) { + editor = SHSystemManager::GetSystem(); } void SHEditorWindow::Init() diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h index faacd8f2..9b932827 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h @@ -12,9 +12,9 @@ //#==============================================================# struct ImGuiIO; typedef int ImGuiWindowFlags; - namespace SHADE { + class SHEditor; class SHEditorWindow { public: @@ -38,6 +38,6 @@ namespace SHADE ImGuiWindowFlags windowFlags = 0; ImGuiIO& io; - + SHEditor* editor; };//class SHEditorWindow }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h index 9aad6ede..290ed622 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h @@ -6,4 +6,5 @@ #include "ViewportWindow/SHEditorViewport.h" //Editor Viewport #include "AssetBrowser/SHAssetBrowser.h" //Asset Browser #include "MaterialInspector/SHMaterialInspector.h" //Material Inspector -#include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel \ No newline at end of file +#include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel +#include "InputBindings/SHInputBindingsPanel.h" //Input Bindings \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp index 420b5414..a63e659b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp @@ -4,5 +4,7 @@ namespace SHADE { SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{}; + SHEditorWindowManager::PopupWindowMap SHEditorWindowManager::popupWindows{}; SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{}; + SHEditorWindowManager::EditorWindowID SHEditorWindowManager::popupWindowCount{}; } diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h index 60730f0e..062f864a 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h @@ -3,6 +3,7 @@ #include #include #include "SHEditorWindow.h" +#include "SHPopUpWindow.h" #include "Tools/Logger/SHLog.h" namespace SHADE @@ -16,6 +17,10 @@ namespace SHADE using EditorWindowID = uint8_t; using EditorWindowPtr = std::unique_ptr; using EditorWindowMap = std::unordered_map; + + using PopupWindowPtr = std::unique_ptr; + using PopupWindowMap = std::unordered_map; + /** * @brief Get ID for the Editor Window Type * @@ -67,10 +72,63 @@ namespace SHADE return reinterpret_cast(editorWindows[GetEditorWindowID()].get()); } + /** + * @brief Get ID for the Popup Window Type + * + * @tparam T Type of Popup Window + * @return EditorWindowID ID of Popup Window Type + */ + template , bool> = true> + static EditorWindowID GetPopupWindowID() + { + static EditorWindowID id; + static bool idCreated = false; + if (!idCreated) + { + id = popupWindowCount++; + idCreated = true; + } + return id; + } + + /** + * @brief Create an Popup Window + * + * @tparam T Type of Popup Window to create + */ + template , bool> = true> + static void CreatePopupWindow() + { + static bool isCreated = false; + if (!isCreated) + { + popupWindows[GetPopupWindowID()] = std::make_unique(); + isCreated = true; + } + else + { + SHLog::Warning("Attempt to create duplicate of Popup window type"); + } + } + + /** + * @brief Get pointer to the Editor Window + * + * @tparam T Type of editor window to retrieve + * @return T* Pointer to the editor window + */ + template , bool> = true> + static T* GetPopupWindow() + { + return reinterpret_cast(popupWindows[GetPopupWindowID()].get()); + } + static EditorWindowMap editorWindows; + static PopupWindowMap popupWindows; private: // Number of windows; used for Editor Window ID Generation static EditorWindowID windowCount; + static EditorWindowID popupWindowCount; // Map of Editor Windows friend class SHEditor; }; diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp new file mode 100644 index 00000000..f82a7495 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp @@ -0,0 +1,21 @@ +#include "SHpch.h" +#include "SHPopUpWindow.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/SHEditor.h" + +namespace SHADE +{ + SHPopUpWindow::SHPopUpWindow(std::string_view const& name, bool modal, ImGuiPopupFlags inPopupFlags, ImGuiWindowFlags inWindowFlags) + :editor(nullptr), windowName(name), popupFlags(inPopupFlags), windowFlags(inWindowFlags), isOpen(false), isModal(modal) + { + editor = SHSystemManager::GetSystem(); + } + + bool SHPopUpWindow::Begin() + { + if (isOpen) + ImGui::OpenPopup(windowName.data(), popupFlags); + + return isModal ? ImGui::BeginPopupModal(windowName.data(), &isOpen, windowFlags) : ImGui::BeginPopup(windowName.data(), windowFlags); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h new file mode 100644 index 00000000..b69b3e99 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h @@ -0,0 +1,31 @@ +#pragma once + +//#==============================================================# +//|| STL Includes || +//#==============================================================# +#include +#include +#include "SH_API.h" + +namespace SHADE +{ + class SHEditor; + class SHPopUpWindow + { + public: + SHPopUpWindow(std::string_view const& name, bool modal, ImGuiPopupFlags inPopupFlags, ImGuiWindowFlags inWindowFlags); + virtual ~SHPopUpWindow() = default; + virtual void Draw(){}; + + bool isOpen; + + protected: + virtual bool Begin(); + + SHEditor* editor; + std::string_view windowName; + ImGuiPopupFlags popupFlags; + ImGuiWindowFlags windowFlags; + bool isModal; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp index 93f4a615..8c32b1c5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp @@ -35,7 +35,6 @@ namespace SHADE { SHEditorWindow::Update(); auto camSystem = SHSystemManager::GetSystem(); - SHEditor* editor = SHSystemManager::GetSystem(); if (!editor->selectedEntities.empty()) { diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 2b8ddbb5..2276164f 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -32,6 +32,9 @@ #include "EditorWindow/SHEditorWindowManager.h" #include "EditorWindow/SHEditorWindowIncludes.h" +#include "EditorWindow/SHPopUpWindow.h" +#include "EditorWindow/EditorPopups/SHEditorPopups.h" + //#==============================================================# //|| Library Includes || //#==============================================================# @@ -98,15 +101,19 @@ namespace SHADE //Add editor windows SHEditorWindowManager::CreateEditorWindow(); - SHEditorWindowManager::CreateEditorWindow(); - SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); + //Add popup windows + SHEditorWindowManager::CreatePopupWindow(); + io = &ImGui::GetIO(); io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls @@ -150,7 +157,7 @@ namespace SHADE { (void)dt; NewFrame(); - for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) + for (auto const& window : SHEditorWindowManager::editorWindows | std::views::values) { if(window->isOpen) { @@ -158,7 +165,11 @@ namespace SHADE } } - RenderSceneNamePrompt(); + for(auto const& popupWindow : SHEditorWindowManager::popupWindows | std::views::values) + { + popupWindow->Draw(); + } + RenderUnsavedChangesPrompt(); //PollPicking(); @@ -177,37 +188,6 @@ namespace SHADE } } - void SHEditor::RenderSceneNamePrompt() noexcept - { - if(isSceneNamePromptOpen) - { - ImGui::OpenPopup(sceneNamePromptName.data()); - } - - if(ImGui::BeginPopupModal(sceneNamePromptName.data(), &isSceneNamePromptOpen)) - { - static std::string newSceneName{}; - ImGui::Text("Enter new scene name"); - ImGui::InputText("##name", &newSceneName); - ImGui::BeginDisabled(newSceneName.empty()); - if(ImGui::Button("Save")) - { - SaveScene(newSceneName); - newSceneName.clear(); - isSceneNamePromptOpen = false; - ImGui::CloseCurrentPopup(); - } - ImGui::EndDisabled(); - ImGui::SameLine(); - if(ImGui::Button("Cancel")) - { - isSceneNamePromptOpen = false; - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - } - void SHEditor::RenderUnsavedChangesPrompt() noexcept { if(isUnsavedChangesPromptOpen) @@ -220,12 +200,12 @@ namespace SHADE ImGui::Text("You have unsaved changes!"); if(ImGui::Button("Save")) { - isSceneNamePromptOpen = true; + SHEditorWindowManager::GetPopupWindow()->isOpen = true; } ImGui::SameLine(); if(ImGui::Button("Cancel")) { - isUnsavedChangesPromptOpen = false; + SHEditorWindowManager::GetPopupWindow()->isOpen = true; ImGui::CloseCurrentPopup(); } } @@ -489,7 +469,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass(); + auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) { @@ -508,7 +488,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); @@ -563,7 +543,7 @@ namespace SHADE if (newSceneName.empty()) { //Prompt for scene name - isSceneNamePromptOpen = true; + SHEditorWindowManager::GetPopupWindow()->isOpen = true; return false; } //Else We have a new name @@ -644,7 +624,7 @@ namespace SHADE editorState = SHEditor::State::STOP; SHCommandManager::SwapStacks(); SHEventManager::BroadcastEvent(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT); - LoadScene(SHSceneManager::GetCurrentSceneAssetID()); + LoadScene(editorConfig->workingSceneID); } void SHEditor::ProcessShortcuts() diff --git a/SHADE_Engine/src/Editor/SHEditor.h b/SHADE_Engine/src/Editor/SHEditor.h index 103f834f..d616c096 100644 --- a/SHADE_Engine/src/Editor/SHEditor.h +++ b/SHADE_Engine/src/Editor/SHEditor.h @@ -37,8 +37,6 @@ namespace SHADE class SHVkCommandBuffer; class SHVkCommandPool; - - /** * @brief SHEditor static class contains editor variables and implementation of editor functions. * @@ -144,8 +142,6 @@ namespace SHADE */ void Render(); - void RenderSceneNamePrompt() noexcept; - void RenderUnsavedChangesPrompt() noexcept; void InitLayout() noexcept; @@ -156,8 +152,6 @@ namespace SHADE SHEventHandle onEditorStateChanged(SHEventPtr eventPtr); - bool isSceneNamePromptOpen = false; - bool isUnsavedChangesPromptOpen = false; static constexpr std::string_view sceneNamePromptName = "Save scene as..."; diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index 441f95aa..f3dfe194 100644 --- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp +++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp @@ -13,6 +13,8 @@ #include "Command/SHCommandManager.h" #include "SHImGuiHelpers.hpp" #include "SH_API.h" +#include "Assets/SHAssetMacros.h" +#include "ECS_Base/SHECSMacros.h" //#==============================================================# //|| Library Includes || @@ -454,7 +456,33 @@ namespace SHADE ImGui::BeginGroup(); ImGui::PushID(label.data()); TextLabel(label); - const bool hasChange = ImGui::InputScalar("##dragScalar", data_type, &value); + bool hasChange = ImGui::DragScalar("##dragScalar", data_type, &value); + if constexpr(std::is_same_v) //EID or Resource + { + if (SHDragDrop::BeginTarget()) + { + if(AssetID * payload = SHDragDrop::AcceptPayload(SHDragDrop::DRAG_RESOURCE)) + { + value = *payload; + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + hasChange = true; + SHDragDrop::EndTarget(); + } + else if (std::vector* payload = SHDragDrop::AcceptPayload>(SHDragDrop::DRAG_EID)) + { + value = payload->back(); + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + hasChange = true; + SHDragDrop::EndTarget(); + } + if(hasChange) + { + ImGui::PopID(); + ImGui::EndGroup(); + return true; + } + } + } static bool startRecording = false; if (hasChange) { diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index 8077fcc1..c090cd69 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -23,4 +23,5 @@ constexpr SHEventIdentifier SH_SCENE_INIT_POST { 14 }; constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 }; constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 }; +constexpr SHEventIdentifier SH_BUTTON_CLICK_EVENT { 18 }; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index e77234ca..8143ec0e 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -175,6 +175,27 @@ namespace SHADE writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].imageLayout = layout; } + + // Rest is not used, so it doesn't matter what's in them, we just want to pacify Vulkan + for (uint32_t i = imageViewsAndSamplers.size(); i < writeInfo.descImageInfos.size(); ++i) + { + writeInfo.descImageInfos[i].sampler = std::get>(imageViewsAndSamplers.back())->GetVkSampler(); + } + } + + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept + { + // Find the target writeDescSet + BindingAndSetHash writeHash = binding; + writeHash |= static_cast(set) << 32; + auto& writeInfo = updater.writeInfos[updater.writeHashMap.at(writeHash)]; + + // write sampler and image view + auto& [view, sampler, layout] = imageViewAndSampler; + writeInfo.descImageInfos[descIndex].imageView = view->GetImageView(); + writeInfo.descImageInfos[descIndex].sampler = sampler ? sampler->GetVkSampler() : nullptr; + writeInfo.descImageInfos[descIndex].imageLayout = layout; + } void SHVkDescriptorSetGroup::ModifyWriteDescBuffer(uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept @@ -200,6 +221,28 @@ namespace SHADE } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept + { + vk::WriteDescriptorSet writeDescSet{}; + + // Get binding + set hash + BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); + + // to index a write for a binding + uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; + + // Initialize info for write + writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type; + writeDescSet.dstArrayElement = descArrayIndex; + writeDescSet.dstSet = descSets[set]; + writeDescSet.dstBinding = binding; + + writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex; + writeDescSet.descriptorCount = 1u; + + device->UpdateDescriptorSet(writeDescSet); + } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept { vk::WriteDescriptorSet writeDescSet{}; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index a228bc66..5b65174a 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -63,10 +63,12 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Public member functions */ /*-----------------------------------------------------------------------------*/ + void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept; void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 6a6e385f..5653bbe7 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -183,33 +183,43 @@ namespace SHADE /*if (!extensionsSupported) SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/ - vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED + vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature + { + .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .descriptorBindingPartiallyBound = VK_TRUE, + .descriptorBindingVariableDescriptorCount = VK_TRUE, + .runtimeDescriptorArray = VK_TRUE, + }; + + vk::PhysicalDeviceRobustness2FeaturesEXT robustFeatures + { + .nullDescriptor = VK_TRUE, + }; + + robustFeatures.pNext = &descIndexingFeature; + + vk::PhysicalDeviceFeatures2 features{}; // ADD MORE FEATURES HERE IF NEEDED // point and lines fill mode - features.fillModeNonSolid = VK_TRUE; - features.samplerAnisotropy = VK_TRUE; - features.multiDrawIndirect = VK_TRUE; - features.independentBlend = VK_TRUE; + features.features.fillModeNonSolid = VK_TRUE; + features.features.samplerAnisotropy = VK_TRUE; + features.features.multiDrawIndirect = VK_TRUE; + features.features.independentBlend = VK_TRUE; + features.features.wideLines = VK_TRUE; - // for wide lines - features.wideLines = true; - - vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{}; - descIndexingFeature.descriptorBindingVariableDescriptorCount = true; - descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true; - descIndexingFeature.runtimeDescriptorArray = true; + features.pNext = &robustFeatures; // Prepare to create the device vk::DeviceCreateInfo deviceCreateInfo { - .pNext = &descIndexingFeature, + .pNext = &features, .queueCreateInfoCount = static_cast(queueCreateInfos.size()), .pQueueCreateInfos = queueCreateInfos.data(), .enabledLayerCount = 0, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored .enabledExtensionCount = !extensionsSupported ? 0 : static_cast(requiredExtensions.size()), .ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(), - .pEnabledFeatures = &features + //.pEnabledFeatures = &features }; // Actually create the device diff --git a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h index ab120a1f..06c480ef 100644 --- a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h +++ b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h @@ -10,5 +10,8 @@ namespace SHADE { //! We need to get the light component and initialize the relevant variables. EntityID lightEntity; + + //! Generate a renderer for the light component + bool generateRenderer; }; } diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index 7443b6e2..255fa5e4 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -33,6 +33,7 @@ namespace SHADE .maxAnisotropy = 1.0f, .minLod = params.minLod, .maxLod = params.maxLod, + .borderColor = vk::BorderColor::eFloatOpaqueWhite }; // Create the sampler diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 7e4069f6..fd2ccd3b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -551,7 +551,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* SHBatch - Usage Functions */ /*---------------------------------------------------------------------------------*/ - void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) + void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -566,7 +566,10 @@ namespace SHADE // Bind all required objects before drawing static std::array dynamicOffset{ 0 }; cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); - cmdBuffer->BindPipeline(pipeline); + + if (bindBatchPipeline) + cmdBuffer->BindPipeline(pipeline); + cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); if (matPropsDescSet[frameIndex]) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d4ce068e..6d1f775f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -87,7 +87,7 @@ namespace SHADE void UpdateTransformBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex); void Build(Handle device, Handle descPool, uint32_t frameIndex) ; - void Draw(Handle cmdBuffer, uint32_t frameIndex); + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index 58993026..8006d0be 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -107,12 +107,12 @@ namespace SHADE } } - void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept + void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline /*= true*/) noexcept { // Build all batches for (auto& batch : batches) { - batch.Draw(cmdBuffer, frameIndex); + batch.Draw(cmdBuffer, frameIndex, bindBatchPipeline); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index 75bd1829..4d831b9c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -57,7 +57,7 @@ namespace SHADE void Clear() noexcept; void UpdateBuffers(uint32_t frameIndex, Handle descPool); void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; - void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true) noexcept; /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index ffe29b36..d5f744fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -13,6 +13,8 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ std::vector> SHGraphicsPredefinedData::predefinedLayouts; SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState; + SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState; + std::vector SHGraphicsPredefinedData::perSystemData; //SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData; @@ -150,12 +152,26 @@ namespace SHADE Handle fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding }); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data"); + // descriptor binding for storing shadow maps + SHVkDescriptorSetLayout::Binding shadowMapBinding + { + .Type = vk::DescriptorType::eCombinedImageSampler, + .Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + .DescriptorCount = 200, // we can have up to 200 textures for now + .flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount, + }; + + // For global data (generic data and textures) + Handle shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding }); + SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps"); predefinedLayouts.push_back(staticGlobalLayout); predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(cameraDataGlobalLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(fontDataDescSetLayout); + predefinedLayouts.push_back(shadowMapDescLayout); perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts ( @@ -179,7 +195,7 @@ namespace SHADE ); } - void SHGraphicsPredefinedData::InitDefaultVertexInputState(void) noexcept + void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept { defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 @@ -187,13 +203,16 @@ namespace SHADE defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3 defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots) defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 + + shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)}); + shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots) } void SHGraphicsPredefinedData::Init(Handle logicalDevice) noexcept { perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES)); InitDescSetLayouts(logicalDevice); - InitDefaultVertexInputState(); + InitPredefinedVertexInputState(); InitDescMappings(); InitDummyPipelineLayouts (logicalDevice); } @@ -217,6 +236,11 @@ namespace SHADE } + SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept + { + return shadowMapVertexInputState; + } + SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept { return perSystemData[static_cast(systemType)]; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h index 11bfc469..9331ed01 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h @@ -28,6 +28,7 @@ namespace SHADE CAMERA = 0x04, MATERIALS = 0x08, FONT = 0x10, + SHADOW = 0x20, }; enum class SystemType @@ -57,6 +58,9 @@ namespace SHADE //! Default vertex input state (used by everything). static SHVertexInputState defaultVertexInputState; + //! vertex input state for shadow mapping + static SHVertexInputState shadowMapVertexInputState; + //! Predefined data for each type of system static std::vector perSystemData; @@ -72,7 +76,7 @@ namespace SHADE static void InitDescMappings (void) noexcept; static void InitDummyPipelineLayouts (Handle logicalDevice) noexcept; static void InitDescSetLayouts (Handle logicalDevice) noexcept; - static void InitDefaultVertexInputState (void) noexcept; + static void InitPredefinedVertexInputState (void) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -90,6 +94,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ static std::vector> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept; + static SHVertexInputState const& GetShadowMapViState (void) noexcept; static PerSystem const& GetSystemData (SystemType systemType) noexcept; static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept; //static PerSystem const& GetBatchingSystemData(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h index 931101f4..fc7f6a1b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h @@ -13,7 +13,7 @@ namespace SHADE CAMERA, MATERIALS, FONT, - RENDER_GRAPH_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE, + RENDER_GRAPH_RESOURCE, }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index ae8c62b2..e8868eba 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,9 +101,13 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); + auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { + // Set line width first + cmdBuffer->SetLineWidth(LineWidth); + + // Draw const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); cmdBuffer->BeginLabeledSegment("SHDebugDraw (No Depth Test)"); { @@ -125,9 +129,13 @@ namespace SHADE } cmdBuffer->EndLabeledSegment(); }); - auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); + auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { + // Set line width first + cmdBuffer->SetLineWidth(LineWidth); + + // Draw const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); cmdBuffer->BeginLabeledSegment("SHDebugDraw (Depth Tested)"); { @@ -506,7 +514,6 @@ namespace SHADE if (batch.NumPoints[frameIndex] > 0) { cmdBuffer->BindPipeline(batch.Pipeline); - cmdBuffer->SetLineWidth(LineWidth); cmdBuffer->BindVertexBuffer(0, batch.VertexBuffers[frameIndex], 0); cmdBuffer->DrawArrays(batch.NumPoints[frameIndex], 1, 0, 0); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index c889a321..b3945689 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,68 +31,91 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - //struct DescriptorSetIndex - //{ - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for static global values like generic data, and - // texture samplers - // */ - // /***************************************************************************/ - // static constexpr uint32_t STATIC_GLOBALS = 0; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for dynamic global values like lights. - // */ - // /***************************************************************************/ - // static constexpr uint32_t DYNAMIC_GLOBALS = 1; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for high frequency changing global values like - // camera matrices. - // */ - // /***************************************************************************/ - // static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for per-instance/material changing values. - // */ - // /***************************************************************************/ - // static constexpr uint32_t PER_INSTANCE = 3; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph resources. Unlike the sets from - // 1 to 3 and 6, this set index does not have hard coded bindings and is - // NOT part of the layouts included in the global data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph node compute resources. For data - // that we wish to pass to compute shaders in the render graph, this is - // the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have - // hard coded bindings and is NOT part of the layouts included in the global - // data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5; + struct RenderGraphEntityNames + { + /***************************************************************************/ + /*! + + \brief + Name of G-Buffer render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view GBUFFER_PASS = "G-Buffer"; - // /***************************************************************************/ - // /*! - // \brief - // To store font data. - // - // */ - // /***************************************************************************/ - // static constexpr uint32_t FONT_DATA = 4; - //}; + /***************************************************************************/ + /*! + + \brief + Name of shadow map render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw with Depth render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of screen space pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of ImGui pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view IMGUI_PASS = "ImGui Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite compute. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite"; + + + + }; struct DescriptorSetBindings { @@ -158,6 +181,16 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t FONT_MATRIX_DATA = 1; + /***************************************************************************/ + /*! + \brief + Descriptor set binding for shadow map images. + + */ + /***************************************************************************/ + static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; + + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index f3bcc8f7..c4990153 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" +#include "Events/SHEvent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Input/SHInputManager.h" namespace SHADE { @@ -124,6 +127,13 @@ namespace SHADE SHFreetypeInstance::Init(); + SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false); + // Load Built In Shaders static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet(FS_DEFAULT); @@ -137,6 +147,8 @@ namespace SHADE static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet(TEXT_FS); static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet(RENDER_SC_VS); static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet(RENDER_SC_FS); + static constexpr AssetID SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet(SHADOW_MAP_VS); + } void SHGraphicsSystem::InitRenderGraph(void) noexcept @@ -169,6 +181,8 @@ namespace SHADE // Create Default Viewport worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); + shadowMapViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(SHLightingSubSystem::SHADOW_MAP_WIDTH), static_cast(SHLightingSubSystem::SHADOW_MAP_HEIGHT), 0.0f, 1.0f)); + std::vector> renderContextCmdPools{ swapchain->GetNumImages() }; for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) { @@ -183,22 +197,24 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Initialize world render graph renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); - renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position World Space", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); //worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); - renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second); - renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, true, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); + renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second); /*-----------------------------------------------------------------------*/ /* MAIN NODE */ /*-----------------------------------------------------------------------*/ - auto gBufferNode = renderGraph->AddNode("G-Buffer", + auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), + //auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data() { "Position", "Entity ID", @@ -207,7 +223,8 @@ namespace SHADE "Albedo", "Depth Buffer", "SSAO", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, {}); // no predecessors @@ -220,6 +237,7 @@ namespace SHADE gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Albedo"); + gBufferSubpass->AddColorOutput("Position World Space"); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); @@ -254,53 +272,52 @@ namespace SHADE // Add another pass to blur SSAO Handle ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); - /*-----------------------------------------------------------------------*/ - /* SHADOW MAP PASS */ - /*-----------------------------------------------------------------------*/ - // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. - // It will initially also not have any subpasses since they will be added for each light that casts shadows. - //auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {}); - - /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ /*-----------------------------------------------------------------------*/ // This pass will facilitate both lighting and shadows in 1 single pass. - auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass", + auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), { "Position", "Light Layer Indices", "Normals", "Albedo", "Scene", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, - {"G-Buffer"}); + { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); + /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Position World Space", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); + deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) + { + lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); + }); + /*-----------------------------------------------------------------------*/ /* DEBUG DRAW PASS INIT */ /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - Depth Tested - auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"}); + auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()}); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - No Depth Test - auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" }); + auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()}); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* SCREEN SPACE PASS */ /*-----------------------------------------------------------------------*/ - auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" }); + auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()}); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -315,16 +332,16 @@ namespace SHADE #ifdef SHEDITOR { // Dummy Node to transition scene render graph resource - auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" }); + auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); dummySubpass->AddInput("Scene"); - auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {}); + auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -393,12 +410,16 @@ namespace SHADE postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); lightingSubSystem = resourceManager.Create(); - lightingSubSystem->Init(device, descPool); + lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams + { + .addressMode = vk::SamplerAddressMode::eClampToBorder, + }) + ); textRenderingSubSystem = resourceManager.Create(); // initialize the text renderer - auto uiNode = renderGraph->GetNode("Screen Space Pass"); + auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data()); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -426,7 +447,7 @@ namespace SHADE defaultMaterial = AddMaterial ( defaultVertShader, defaultFragShader, - renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write") + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") ); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); } @@ -451,6 +472,7 @@ namespace SHADE InitMiddleEnd(); InitSubsystems(); InitBuiltInResources(); + InitEvents(); } void SHGraphicsSystem::Exit(void) @@ -546,6 +568,15 @@ namespace SHADE #endif } + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B)) + { + auto& lightComps = SHComponentManager::GetDense(); + for (auto& comp : lightComps) + { + comp.SetEnableShadow(true); + } + } + renderGraph->Begin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); @@ -726,16 +757,61 @@ namespace SHADE renderers.erase(iter); } - SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept + SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept { + // we need to wait for the device to finish using the graph first + device->WaitIdle(); + + auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; + auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); + std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); + + if (EVENT_DATA->generateRenderer) + { + // Create new renderer for the light component and give it to the light component + Handle newRenderer = resourceManager.Create(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); + lightComp->SetRenderer (newRenderer); + + // assign shadow map index to light component + lightComp->SetShadowMapIndex (lightingSubSystem->GetNumShadowMaps()); + } + // Add the shadow map resource to the graph + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. + auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer()); + newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); + + // regenerate the node + shadowMapNode->RuntimeStandaloneRegenerate(); + + // Create pipeline from new renderpass and subpass if it's not created yet + if (!shadowMapPipeline) + { + SHPipelineLibrary tempLibrary{}; + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); + + SHRasterizationState rasterState{}; + rasterState.cull_mode = vk::CullModeFlagBits::eBack; + + tempLibrary.Init(device); + tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState(), rasterState); + shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); + } + newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline - //renderGraph->GetNode (); - return event->handle; + // add the shadow map to the lighting system + uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), EVENT_DATA->lightEntity); + + auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); + nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); + + return eventPtr->handle; } Handle SHGraphicsSystem::AddMaterial(Handle vertShader, Handle fragShader, Handle subpass) @@ -1047,6 +1123,7 @@ namespace SHADE mousePickSubSystem->HandleResize(); postOffscreenRenderSubSystem->HandleResize(); + //lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data())); worldViewport->SetWidth(static_cast(resizeWidth)); worldViewport->SetHeight(static_cast(resizeHeight)); @@ -1079,7 +1156,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 707862f9..c736599f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -178,7 +178,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* Light functions */ /*-----------------------------------------------------------------------*/ - SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; + SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept; /*-----------------------------------------------------------------------------*/ /* Material Functions */ @@ -406,10 +406,6 @@ namespace SHADE SHWindow* GetWindow() noexcept { return window; } private: - /*-----------------------------------------------------------------------------*/ - /* Constants */ - /*-----------------------------------------------------------------------------*/ - static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer"; /*-----------------------------------------------------------------------------*/ /* Data Members */ @@ -446,6 +442,7 @@ namespace SHADE #endif Handle worldViewport; // Whole screen + Handle shadowMapViewport; std::vector> viewports; // Additional viewports // Renderers @@ -469,6 +466,7 @@ namespace SHADE Handle textFS; Handle renderToSwapchainVS; Handle renderToSwapchainFS; + Handle shadowMapVS; // Fonts Handle testFont; @@ -483,6 +481,7 @@ namespace SHADE Handle debugDrawWireMeshDepthPipeline; Handle debugDrawFilledPipeline; Handle debugDrawFilledDepthPipeline; + Handle shadowMapPipeline; // initialized only when a shadow map is needed // Built-In Textures Handle defaultTexture; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index f1d4dc7f..731489fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -122,4 +122,9 @@ namespace SHADE return cameraDirector; } + SHShaderCameraData SHRenderer::GetCPUCameraData(void) const noexcept + { + return cpuCameraData; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index baf76187..867851ee 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -18,9 +18,9 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "SHCamera.h" #include "Resource/SHHandle.h" -#include "Graphics/RenderGraph/SHRenderGraph.h" #include "Math/SHMath.h" #include +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -93,6 +93,7 @@ namespace SHADE /* Setters and Getters */ /*-----------------------------------------------------------------------------*/ Handle GetCameraDirector (void) const noexcept; + SHShaderCameraData GetCPUCameraData (void) const noexcept; private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index 362b0e8f..6943ec09 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -2,6 +2,7 @@ #include "SHLightComponent.h" #include "Graphics/Events/SHGraphicsEvents.h" #include "Events/SHEventManager.hpp" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" namespace SHADE { @@ -14,6 +15,7 @@ namespace SHADE //indexInBuffer = std::numeric_limits::max(); isActive = true; //Unbind(); + renderer = {}; } @@ -116,11 +118,22 @@ namespace SHADE // Create new event and broadcast it SHLightEnableShadowEvent newEvent; newEvent.lightEntity = GetEID(); + newEvent.generateRenderer = static_cast(!renderer); SHEventManager::BroadcastEvent(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); } } + void SHLightComponent::SetRenderer(Handle newRenderer) noexcept + { + renderer = newRenderer; + } + + void SHLightComponent::SetShadowMapIndex(uint32_t index) noexcept + { + lightData.shadowMapIndex = index; + } + SHLightData const& SHLightComponent::GetLightData(void) const noexcept { return lightData; @@ -172,6 +185,11 @@ namespace SHADE return lightData.strength; } + Handle SHLightComponent::GetRenderer(void) const noexcept + { + return renderer; + } + } RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index 1d636595..4974f3f5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -3,9 +3,11 @@ #include #include "ECS_Base/Components/SHComponent.h" #include "SHLightData.h" +#include "Resource/SHHandle.h" namespace SHADE { + class SHRenderer; class SH_API SHLightComponent final : public SHComponent { @@ -14,6 +16,9 @@ namespace SHADE //! GPU depends on the type of the light. SHLightData lightData; + //! Renderer to calculate light world to projection matrix + Handle renderer; + //! Since the lighting system is gonna be self contained and light weight, we store this //! so that we only write this to the CPU buffer when this light component change, we don't //! rewrite everything. However we still write to the GPU buffer when everything changes. @@ -49,6 +54,8 @@ namespace SHADE //void SetBound (uint32_t inIndexInBuffer) noexcept; void SetStrength (float value) noexcept; // serialized void SetEnableShadow (bool flag) noexcept; + void SetRenderer (Handle newRenderer) noexcept; + void SetShadowMapIndex (uint32_t index) noexcept; SHLightData const& GetLightData (void) const noexcept; @@ -61,6 +68,7 @@ namespace SHADE //bool GetBound (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept; float GetStrength (void) const noexcept; + Handle GetRenderer (void) const noexcept; RTTR_ENABLE() }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index ddacf3a7..9acdfed0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -10,6 +10,13 @@ #include "SHLightComponent.h" #include "Math/Vector/SHVec4.h" #include "Math/SHMatrix.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h" +#include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Events/SHGraphicsEvents.h" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" namespace SHADE { @@ -50,6 +57,19 @@ namespace SHADE //lightPtr->direction = lightData.direction; lightPtr->diffuseColor = lightData.color; lightPtr->active = lightComp->isActive; + + // write view projection matrix if renderer is available + auto lightRenderer = lightComp->GetRenderer(); + if (lightRenderer) + { + lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix; + + // Boolean to cast shadows in first 8 bits (1 byte) + lightPtr->shadowData = lightData.castShadows; + + // Next 24 bits for shadow map index + lightPtr->shadowData |= (lightData.shadowMapIndex << 8); + } break; } case SH_LIGHT_TYPE::POINT: @@ -365,6 +385,32 @@ namespace SHADE } } + void SHLightingSubSystem::UpdateShadowMapDesc(void) noexcept + { + + } + + SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept + { + switch (lightComp->GetLightData().type) + { + case SH_LIGHT_TYPE::DIRECTIONAL: + return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, SHVec3::Normalise (lightComp->GetLightData().direction), SHVec3(0.0f, -1.0f, 0.0f))); + //return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); + case SH_LIGHT_TYPE::POINT: + return {}; + case SH_LIGHT_TYPE::SPOT: + return {}; + case SH_LIGHT_TYPE::AMBIENT: + return {}; + case SH_LIGHT_TYPE::NUM_TYPES: + return {}; + default: + return {}; + + } + } + /***************************************************************************/ /*! @@ -375,13 +421,15 @@ namespace SHADE */ /***************************************************************************/ - void SHLightingSubSystem::Init(Handle device, Handle descPool) noexcept + void SHLightingSubSystem::Init(Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept { SHComponentManager::CreateComponentSparseSet(); logicalDevice = device; + resourceHub = rh; uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); +#pragma region LIGHTING std::vector variableSizes{ NUM_LIGHT_TYPES }; std::fill (variableSizes.begin(), variableSizes.end(), 1); @@ -418,7 +466,22 @@ namespace SHADE dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count } +#pragma endregion + +#pragma region SHADOWS + //std::vector shadowDescVariableSizes{ MAX_SHADOWS }; + //shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); + +//#ifdef _DEBUG +// const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); +// for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) +// SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); +//#endif + + shadowMapSampler = inShadowMapSampler; + shadowMaps.clear(); //numLightComponents = 0; +#pragma endregion } /***************************************************************************/ @@ -452,6 +515,12 @@ namespace SHADE for (auto& light : lightComps) { + if (auto renderer = light.GetRenderer()) + { + //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(10.0f, 10.0f, 1.0f, 50.0f)); + } + auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); // First we want to make sure the light is already bound to the system. if it @@ -503,7 +572,6 @@ namespace SHADE // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing. ComputeDynamicOffsets(); - } /***************************************************************************/ @@ -526,9 +594,101 @@ namespace SHADE } + uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept + { + // Add to container of shadow maps + shadowMapIndexing.emplace(lightEntity, static_cast (shadowMaps.size())); + shadowMaps.emplace_back(newShadowMap); + + // Just use the image view stored in the resource + Handle const NEW_IMAGE_VIEW = newShadowMap->GetImageView(); + + // Prepare to write to descriptor + shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); + + // Update descriptor set + //static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; + //uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; + //shadowMapDescriptorSet->ModifyWriteDescImage + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, + // shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], + // SHADOW_MAP_DESC_ARRAY_INDEX + //); + + //// TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array + //shadowMapDescriptorSet->UpdateDescriptorSetImages + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA + //); + + // add to barriers + shadowMapMemoryBarriers.push_back (vk::ImageMemoryBarrier + { + .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .oldLayout = vk::ImageLayout::eDepthAttachmentOptimal, + .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = newShadowMap->GetImage()->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + + // return new index of shadow map + return static_cast(shadowMapImageSamplers.size()) - 1u; + } + + void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept + { + // Issue barrier to transition shadow maps for reading in compute shader + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, shadowMapMemoryBarriers); + } + + //void SHLightingSubSystem::HandleResize(Handle compute) noexcept + //{ + // uint32_t const NUM_SHADOW_MAPS = static_cast(shadowMaps.size()); + // for (uint32_t i = 0; i < NUM_SHADOW_MAPS; ++i) + // { + // // Just use the image view stored in the resource + // Handle const NEW_IMAGE_VIEW = shadowMaps[i]->GetImageView(); + + // // set new image view + // std::get>(shadowMapImageSamplers[i]) = NEW_IMAGE_VIEW; + + // // Set image for barrier + // shadowMapMemoryBarriers[i].image = shadowMaps[i]->GetImage()->GetVkImage(); + // } + + // if (NUM_SHADOW_MAPS > 0) + // { + // // modify descriptors in render graph node compute + // compute->ModifyWriteDescImageComputeResource (SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, shadowMapImageSamplers); + // } + //} + Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept { return lightingDataDescSet; } + std::tuple, Handle, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept + { + return shadowMapImageSamplers[index]; + } + + uint32_t SHLightingSubSystem::GetNumShadowMaps(void) const noexcept + { + return static_cast(shadowMaps.size()); + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index fa103136..7794a2fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -3,9 +3,13 @@ #include "Resource/SHHandle.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" +#include "Math/SHMatrix.h" #include "SHLightData.h" #include #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/RenderGraph/SHRenderGraphResource.h" +#include "ECS_Base/SHECSMacros.h" + namespace SHADE { @@ -16,6 +20,10 @@ namespace SHADE class SHVkBuffer; class SHLightComponent; class SHVkCommandBuffer; + class SHSamplerCache; + class SHVkImageView; + class SHVkSampler; + class SHRenderGraphNodeCompute; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. struct SHDirectionalLightData @@ -34,6 +42,12 @@ namespace SHADE //! Diffuse color emitted by the light alignas (16) SHVec4 diffuseColor; + //! Matrix for world to projection from light's perspective + SHMatrix pvMatrix; + + //! Represents boolean for casting shadows in first byte and shadow map index in the other 3. + uint32_t shadowData; + }; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. @@ -52,24 +66,27 @@ namespace SHADE //! 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; - - }; class SH_API SHLightingSubSystem { public: using DynamicOffsetArray = std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; - + static constexpr uint32_t MAX_SHADOWS = 200; + static constexpr uint32_t SHADOW_MAP_WIDTH = 1024; + static constexpr uint32_t SHADOW_MAP_HEIGHT = 1024; private: class PerTypeData { + public: + + private: /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t STARTING_NUM_LIGHTS = 50; + static constexpr uint32_t STARTING_NUM_LIGHTS = 50; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -123,51 +140,90 @@ namespace SHADE }; private: + /*-----------------------------------------------------------------------*/ + /* STATIC MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + //! logical device used for creation - Handle logicalDevice; + Handle logicalDevice; //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required. - Handle lightingDataDescSet; - - //! Each type will have some data associated with it for processing - std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; - - //! Container to store dynamic offsets for binding descriptor sets - DynamicOffsetArray 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; + Handle lightingDataDescSet; + + //! Each type will have some data associated with it for processing + std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; + + //! Container to store dynamic offsets for binding descriptor sets + DynamicOffsetArray 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; + //! Handle to sampler that all shadow map descriptors will use + Handle shadowMapSampler; + + //! For indexing shadow maps + std::unordered_map shadowMapIndexing; + + //! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it + std::vector> shadowMaps; + + //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. + //! It will also be preallocated. + //Handle shadowMapDescriptorSet; + + //! Combined image samplers for the texture descriptors + std::vector, Handle, vk::ImageLayout>> shadowMapImageSamplers; + + //! Barriers required to transition the resources from whatever layout they are in (probably from VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + //! to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + std::vector shadowMapMemoryBarriers; + + //! Resource hub from Graphics System + SHResourceHub* resourceHub; + + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ void UpdateDescSet (uint32_t binding) noexcept; void ComputeDynamicOffsets (void) noexcept; void ResetNumLights (void) noexcept; + void UpdateShadowMapDesc (void) noexcept; + SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept; public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool) noexcept; - void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; - void Exit (void) noexcept; + void Init (Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept; + void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; + void Exit (void) noexcept; + void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + uint32_t AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; + void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; + //void HandleResize (Handle compute) noexcept; + //void RemoveShadowMap (uint32_t index) noexcept; - void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; + std::tuple, Handle, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept; + uint32_t GetNumShadowMaps (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index baf09a2d..74795034 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -1,18 +1,23 @@ #include "SHpch.h" #include "SHPipelineLibrary.h" #include "Graphics/Devices/SHVkLogicalDevice.h" -#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" #include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/SHVkUtil.h" namespace SHADE { - Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept { + std::vector> modules{}; + if (vsFsPair.first) + modules.push_back(vsFsPair.first); + if (vsFsPair.second) + modules.push_back(vsFsPair.second); + SHPipelineLayoutParams params { - .shaderModules = {vsFsPair.first, vsFsPair.second}, + .shaderModules = std::move(modules), .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts }; @@ -21,7 +26,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(viState); SHColorBlendState colorBlendState{}; colorBlendState.logic_op_enable = VK_FALSE; @@ -30,6 +35,7 @@ namespace SHADE auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); colorBlendState.attachments.reserve(subpassColorReferences.size()); + for (auto& att : subpassColorReferences) { colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState @@ -47,6 +53,8 @@ namespace SHADE } newPipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + newPipeline->GetPipelineState().SetRasterizationState(rasterState); // Actually construct the pipeline newPipeline->ConstructPipeline(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index 5085f21f..ca46c71a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -3,6 +3,7 @@ #include #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" namespace SHADE { @@ -32,7 +33,9 @@ namespace SHADE Handle CreateGraphicsPipelines ( std::pair, Handle> const& vsFsPair, Handle renderpass, - Handle subpass + Handle subpass, + SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(), + SHRasterizationState const& rasterState = SHRasterizationState{} ) noexcept; Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp index c7ada11f..30d81d89 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp @@ -195,7 +195,7 @@ namespace SHADE return *this; } - void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept + void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding /*= static_cast(-1)*/, uint32_t fixedAttributeLocation/* = static_cast(-1)*/) noexcept { // add a binding and get ref to it bindings.emplace_back(); @@ -210,7 +210,7 @@ namespace SHADE // Offset is 0 at first (for first element) uint32_t offset = 0; - binding.binding = static_cast(bindings.size() - 1); + binding.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); // for every attribute passed in for (auto const& attrib : inAttribs) @@ -226,10 +226,11 @@ namespace SHADE auto& vertexAttrib = attributes.back(); // The binding for that attribute description is index of the new binding created earlier in this function - vertexAttrib.binding = static_cast(bindings.size() - 1); + vertexAttrib.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); - // Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously - vertexAttrib.location = static_cast(attributes.size () - 1); + //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously + vertexAttrib.location = (fixedAttributeLocation != static_cast(-1)) ? fixedAttributeLocation + i : static_cast(attributes.size () - 1); + //vertexAttrib.location = static_cast(attributes.size() - 1); // Get the vkFormat associated with the SHAttribFormat vertexAttrib.format = format; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h index 4c8d679a..73eb1ef5 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h @@ -34,7 +34,7 @@ namespace SHADE SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; - void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept; + void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding = static_cast(-1), uint32_t fixedAttributeLocation = static_cast(-1)) noexcept; friend class SHVkPipelineState; friend class SHVkPipeline; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index c2d83052..6a6ef879 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -19,69 +19,71 @@ namespace SHADE for (auto& shaderModule : shaderModules) { - // References for convenience - auto const& reflectedData = shaderModule->GetReflectedData(); - auto const& pcInfo = reflectedData.GetPushConstantInfo(); - - // If a push constant block exists for the shader module - if (pcInfo.memberCount != 0) + if (shaderModule) { - bool exists = false; + // References for convenience + auto const& reflectedData = shaderModule->GetReflectedData(); + auto const& pcInfo = reflectedData.GetPushConstantInfo(); - // Check if push constant block already exists - for (uint32_t i = 0; i < pcInfos.size(); ++i) + // If a push constant block exists for the shader module + if (pcInfo.memberCount != 0) { - // If there is a block with the same name, member count and size - if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + bool exists = false; + + // Check if push constant block already exists + for (uint32_t i = 0; i < pcInfos.size(); ++i) { - // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages - vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); + // If there is a block with the same name, member count and size + if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + { + // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages + vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); - // Set flag and stop checking - exists = true; - break; - } - } - - // If the block doesn't exist yet - if (!exists) - { - // Loop through all member variables of the new push constant block - for (uint32_t i = 0; i < pcInfo.memberCount; ++i) - { - std::string variableName; - variableName.reserve(50); - variableName += pcInfo.name; - variableName += "."; - variableName += pcInfo.members[i].name; - - // Add the variable's offset info to the interface - pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + // Set flag and stop checking + exists = true; + break; + } } - // New push constant range - vk::PushConstantRange newRange; + // If the block doesn't exist yet + if (!exists) + { + // Loop through all member variables of the new push constant block + for (uint32_t i = 0; i < pcInfo.memberCount; ++i) + { + std::string variableName; + variableName.reserve(50); + variableName += pcInfo.name; + variableName += "."; + variableName += pcInfo.members[i].name; - // set offset and size - newRange.offset = startOffset; - newRange.size = pcInfo.size; + // Add the variable's offset info to the interface + pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + } - // Stage flags will be whatever shader stage of the shader that contains the push constant block - newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); + // New push constant range + vk::PushConstantRange newRange; - // Add to the list foe checking later - pcInfos.push_back(&pcInfo); + // set offset and size + newRange.offset = startOffset; + newRange.size = pcInfo.size; - // For pipeline layout to consume - vkPcRanges.push_back(newRange); + // Stage flags will be whatever shader stage of the shader that contains the push constant block + newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); - // Next push constant block will start next to the previous push constant block - startOffset += pcInfo.size; + // Add to the list foe checking later + pcInfos.push_back(&pcInfo); + + // For pipeline layout to consume + vkPcRanges.push_back(newRange); + + // Next push constant block will start next to the previous push constant block + startOffset += pcInfo.size; + } + + stageFlags |= shaderModule->GetShaderStageFlagBits(); } - - stageFlags |= shaderModule->GetShaderStageFlagBits(); } - } // After all the sizes of the push constant blocks have been added, record the size in the interface @@ -132,6 +134,9 @@ namespace SHADE //! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set for (auto& shaderModule : shaderModules) { + if (!shaderModule) + continue; + auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo(); auto const& reflectedSets = descBindingInfo.GetReflectedSets(); @@ -200,10 +205,12 @@ namespace SHADE newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND; // Set the flags for variable bindings - newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; + newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound; } else + { SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. "); + } } setsWithBindings[CURRENT_SET].emplace_back(newBinding); @@ -326,11 +333,10 @@ namespace SHADE { for (auto& mod : shaderModules) { - mod->AddCallback([this]() - { - RecreateIfNeeded(); - } - ); + if (mod) + { + mod->AddCallback([this]() { RecreateIfNeeded(); }); + } } RecreateIfNeeded (); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 74371a64..74ea951a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -54,7 +54,7 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) + void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, bool resizeWithWindow, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) { // If we set to if (w == static_cast(-1) && h == static_cast(-1)) @@ -64,7 +64,7 @@ namespace SHADE format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); + auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags, resizeWithWindow); renderGraphStorage->graphResources->try_emplace(resourceName, resource); } @@ -106,6 +106,9 @@ namespace SHADE for (auto& affectedNode : affectedNodes) nodes[affectedNode]->CreateFramebuffer(); + + renderGraphStorage->graphResources->at(resourceName).Free(); + renderGraphStorage->graphResources->erase (resourceName); /* * IMPORTANT NOTES * @@ -166,68 +169,7 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is final layout. - std::unordered_map resourceAttFinalLayouts; - if (node->subpasses.empty()) - { - SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); - return; - } - - // We first want to take all resources track their layout as undefined at the start of the node/renderpass - auto const resources = node->GetResources(); - for (auto& resource : resources) - { - resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); - } - - // attempt to get all final layouts for all resources - for (auto& subpass : node->subpasses) - { - for (auto& color : subpass->colorReferences) - { - // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass - if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) - resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; - else - resourceAttFinalLayouts[color.attachment] = color.layout; - - node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); - } - - for (auto& depth : subpass->depthReferences) - { - resourceAttFinalLayouts[depth.attachment] = depth.layout; - node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); - } - - for (auto& input : subpass->inputReferences) - { - resourceAttFinalLayouts[input.attachment] = input.layout; - node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); - } - } - - for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) - { - auto& att = node->attachmentDescriptions[j]; - auto& resource = node->attResources[j]; - - // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. - // We also want to load the attachment, not "don't care". - if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && - renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) - { - att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at (resource.GetId().Raw); - att.loadOp = vk::AttachmentLoadOp::eLoad; - att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; - } - else - att.initialLayout = vk::ImageLayout::eUndefined; - - att.finalLayout = resourceAttFinalLayouts[j]; - resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); - } + node->StandaloneConfigureAttDesc(i == nodes.size() - 1); ++i; } @@ -333,6 +275,17 @@ namespace SHADE } } + void SHRenderGraph::ReindexNodes(void) noexcept + { + nodeIndexing.clear(); + uint32_t i = 0; + for (auto& node : nodes) + { + nodeIndexing.emplace (node->name, i); + ++i; + } + } + /***************************************************************************/ /*! @@ -473,6 +426,65 @@ namespace SHADE return node; } + /***************************************************************************/ + /*! + + \brief + This function is purely used for dynamic nodes (if such a thing were to + exist in our architecture). In other words, don't use this function unless + the new node is fully standalone and does not rely or is a prereq of + other nodes. + + \param nodeName + Name of new node + + \param resourceInstruction + Resources for the node + + \param nodeToAddAfter + The node to add the new node after. + + \return + + */ + /***************************************************************************/ + Handle SHRenderGraph::AddNodeAfter(std::string nodeName, std::initializer_list resourceInstruction, std::string nodeToAddAfter) noexcept + { + if (nodeIndexing.contains(nodeName)) + { + SHLOG_ERROR("Node already exists, cannot add node. "); + return {}; + } + + std::vector descInitParams; + for (auto const& instruction : resourceInstruction) + { + // If the resource that the new node is requesting for exists, allow the graph to reference it + if (renderGraphStorage->graphResources->contains(instruction.resourceName)) + { + descInitParams.push_back( + { + .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName), + .dontClearOnLoad = instruction.dontClearOnLoad, + } + ); + } + else + { + SHLOG_ERROR("Resource doesn't exist in graph yet. Cannot create new node."); + return{}; + } + } + + // get target node + auto targetNode = nodes.begin() + nodeIndexing.at(nodeToAddAfter); + + auto node = nodes.insert(targetNode, renderGraphStorage->resourceHub->Create(nodeName, renderGraphStorage, std::move(descInitParams), std::vector>())); + ReindexNodes (); + return *node; + + } + void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list predecessorNodes, std::pair, Handle> shaderModules) noexcept { for (auto& node : predecessorNodes) @@ -532,10 +544,6 @@ namespace SHADE ConfigureSubSystems(); } - void SHRenderGraph::Regenerate(void) noexcept - { - - } /***************************************************************************/ /*! @@ -572,10 +580,13 @@ namespace SHADE for (auto& node : nodes) { - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + if (node->renderpass) + { + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - node->Execute(cmdBuffer, descPool, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); + } } cmdBuffer->EndLabeledSegment(); @@ -605,8 +616,11 @@ namespace SHADE // resize resources for (auto& [name, resource] : *renderGraphStorage->graphResources) { - if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) - resource->HandleResize(newWidth, newHeight); + if (resource->resizeWithWindow) + { + if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) + resource->HandleResize(newWidth, newHeight); + } } for (auto& node : nodes) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index c7fe221b..5abcd6b6 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -55,6 +55,7 @@ namespace SHADE void ConfigureRenderpasses (void) noexcept; void ConfigureSubSystems (void) noexcept; void ConfigureFramebuffers (void) noexcept; + void ReindexNodes (void) noexcept; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -101,6 +102,7 @@ namespace SHADE ( std::string resourceName, std::initializer_list typeFlags, + bool resizeWithWindow = true, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, @@ -123,6 +125,12 @@ namespace SHADE std::initializer_list resourceInstruction, std::initializer_list predecessorNodes ) noexcept; + Handle AddNodeAfter + ( + std::string nodeName, + std::initializer_list resourceInstruction, + std::string nodeToAddAfter + ) noexcept; void AddRenderToSwapchainNode ( @@ -134,7 +142,6 @@ namespace SHADE ) noexcept; void Generate (void) noexcept; - void Regenerate (void) noexcept; void CheckForNodeComputes (void) noexcept; void Execute (uint32_t frameIndex, Handle descPool) noexcept; void Begin (uint32_t frameIndex) noexcept; @@ -165,7 +172,14 @@ namespace SHADE * that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph, * but different matrices (SHRenderer) can be used in different nodes. * - There are also way too many hash maps created for ease of access. This definitely can be cut down. - * - + * - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted + * for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses + * while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other + * than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as + * whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later + * be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as + * if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any + * other node. * */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 3c412645..ff540ce1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -32,8 +32,11 @@ namespace SHADE renderpass.Free(); } - renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + if (!spDescs.empty()) + { + renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + } } /***************************************************************************/ @@ -46,91 +49,105 @@ namespace SHADE /***************************************************************************/ void SHRenderGraphNode::CreateFramebuffer(void) noexcept { - if (!framebuffers.empty()) + if (renderpass) { - for (auto fbo : framebuffers) + if (!framebuffers.empty()) { - if (fbo) - fbo.Free(); - } - } - - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (auto fbo : framebuffers) + { + if (fbo) + fbo.Free(); + } } + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + } } } void SHRenderGraphNode::HandleResize(void) noexcept { - renderpass->HandleResize(); - - for (uint32_t i = 0; i < framebuffers.size(); ++i) + if (renderpass) { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); + renderpass->HandleResize(); - for (uint32_t j = 0; j < attResources.size(); ++j) + for (uint32_t i = 0; i < framebuffers.size(); ++i) { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } - framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); - } + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } - for (auto& subpass : subpasses) - { - subpass->HandleResize(); - } - - for (auto& nodeCompute : nodeComputes) - { - nodeCompute->HandleResize(); + for (auto& nodeCompute : nodeComputes) + { + nodeCompute->HandleResize(); + } } } void SHRenderGraphNode::ConfigureSubpasses(void) noexcept { + if (subpasses.empty()) + return; + + uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle subpass) {return !subpass->HasNoAttachments();}); + // Create subpass description and dependencies based on number of subpasses - spDescs.resize(subpasses.size()); - spDeps.resize(subpasses.size()); + spDescs.resize(numValidSubpasses); + spDeps.resize(numValidSubpasses); // Now we want to loop through all attachments in all subpasses in the node and query // the resources being used. For each resource we want to query the type and record it // in bit fields (1 bit for each subpass). uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0; - uint32_t i = 0; // For all subpasses (see above description about bit field for this). - for (auto& subpass : subpasses) + for (uint32_t i = 0; auto& subpass : subpasses) { + // skip if subpass is not valid + if (subpass->HasNoAttachments()) + continue; + // Configure subpass description auto& desc = spDescs[i]; desc.pColorAttachments = subpass->colorReferences.data(); @@ -186,8 +203,11 @@ namespace SHADE // Loop through all subpasses again but this time we use the bit field to initialize // the dependencies. - for (i = 0; i < subpasses.size(); ++i) + for (uint32_t i = 0; auto & subpass : subpasses) { + if (subpass->HasNoAttachments()) + continue; + vk::PipelineStageFlags srcStage; vk::PipelineStageFlags dstStage; vk::AccessFlags srcAccess; @@ -245,6 +265,8 @@ namespace SHADE // initialize input descriptors subpasses[i]->CreateInputDescriptors(); + + ++i; } } @@ -343,6 +365,7 @@ namespace SHADE , spDeps{ std::move(rhs.spDeps) } , nodeComputes{ std::move(rhs.nodeComputes) } , name { std::move(rhs.name) } + , ISelfHandle{std::move(rhs)} { rhs.renderpass = {}; @@ -419,7 +442,7 @@ namespace SHADE return subpass; } - Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept + Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept { // Look for the required resources in the graph std::vector> nodeComputeResources{}; @@ -435,7 +458,7 @@ namespace SHADE std::vector> temp (nodeComputeResources); // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount); nodeComputes.push_back(nodeCompute); for (auto& resource : temp) @@ -483,6 +506,68 @@ namespace SHADE } } + void SHRenderGraphNode::StandaloneConfigureAttDesc(bool isLastNode) noexcept + { + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; + if (!subpasses.empty()) + { + // We first want to take all resources track their layout as undefined at the start of the node/renderpass + for (auto& resource : attResources) + { + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, vk::ImageLayout::eUndefined); + } + + // attempt to get all final layouts for all resources + for (auto& subpass : subpasses) + { + for (auto& color : subpass->colorReferences) + { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass + if (isLastNode && (attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + else + resourceAttFinalLayouts[color.attachment] = color.layout; + + attResources[color.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, color.layout); + } + + for (auto& depth : subpass->depthReferences) + { + resourceAttFinalLayouts[depth.attachment] = depth.layout; + attResources[depth.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, depth.layout); + } + + for (auto& input : subpass->inputReferences) + { + resourceAttFinalLayouts[input.attachment] = input.layout; + attResources[input.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, input.layout); + } + } + + for (uint32_t j = 0; j < attachmentDescriptions.size(); ++j) + { + auto& att = attachmentDescriptions[j]; + auto& resource = attResources[j]; + + // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. + // We also want to load the attachment, not "don't care". + if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && + graphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) + { + att.initialLayout = graphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw); + att.loadOp = vk::AttachmentLoadOp::eLoad; + att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; + } + else + att.initialLayout = vk::ImageLayout::eUndefined; + + att.finalLayout = resourceAttFinalLayouts[j]; + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, att.finalLayout); + } + } + } + /***************************************************************************/ /*! @@ -509,14 +594,14 @@ namespace SHADE // remove attachment reference attachmentDescriptions.erase (attachmentDescriptions.begin() + index); + // erase from mapping as well + resourceAttachmentMapping->erase(resourceHandleID); + // Remove footprint of attachment from all subpasses as well for (auto it = subpasses.begin(); it != subpasses.end(); ++it) { - // attempt to detach resource from subpass - (*it)->DetachResource(resourceName, index); - - // If the subpass ends up having no attachments after, erase it from the node - if ((*it)->HasNoAttachments()) + // If the subpass uses the resource, just remove the subpass since the subpass will be invalid + if ((*it)->UsesResource(index)) { // erase from indexing subpassIndexing.erase((*it)->GetName()); @@ -530,6 +615,24 @@ namespace SHADE for (uint32_t i = 0; i < subpasses.size(); ++i) subpasses[i]->SetIndex(i); + // remove node computes using the resource + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if ((*it)->UsesResource(resourceHandleID)) + { + it = nodeComputes.erase(it); + } + } + + // recompute the barriers for the other computes + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if (it == nodeComputes.begin()) + (*it)->SetFollowingEndRenderpass(true); + + (*it)->InitializeBarriers(); + } + return true; } return false; @@ -537,37 +640,40 @@ namespace SHADE void SHRenderGraphNode::Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { - uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) + if (renderpass) { - subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - // Go to next subpass if not last subpass - if (i != static_cast(subpasses.size()) - 1u) - commandBuffer->NextSubpass(); + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + + // Go to next subpass if not last subpass + if (i != static_cast(subpasses.size()) - 1u && !subpasses[i]->HasNoAttachments()) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); + + // We bind these 2 descriptor sets here because they apply to all node computes + if (!nodeComputes.empty()) + { + commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); + + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + + // bind lighting data + SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); + } + + // Execute all subpass computes + for (auto& sbCompute : nodeComputes) + sbCompute->Execute(commandBuffer, frameIndex); } - - commandBuffer->EndRenderpass(); - - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); - - // We bind these 2 descriptor sets here because they apply to all node computes - if (!nodeComputes.empty()) - { - commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); - - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - - // bind lighting data - SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); - } - - // Execute all subpass computes - for (auto& sbCompute : nodeComputes) - sbCompute->Execute(commandBuffer, frameIndex); } Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept @@ -599,6 +705,77 @@ namespace SHADE batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); } + /***************************************************************************/ + /*! + + \brief + This function simply appends to the container of VkAttachmentDescription + and attResources. It will assume the resource is used standalone in the + node and will not account for its usage in other nodes. As such its + initialLayout will always be UNDEFINED and its finalLayout will be + whatever is calculated if the node is regenerated using + StandaloneRegnerate. This function also does not affect the render graph + while its running since the 2 containers above have already been copied + to the GPU. + + \param resourceName + The name of the resource for getting the resource. + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeLinkResource(std::string resourceName) noexcept + { + // Get new resource + Handle newResource = graphStorage->graphResources->at(resourceName); + + // append new resource to container + attResources.push_back(newResource); + + attachmentDescriptions.push_back(vk::AttachmentDescription + { + .format = newResource->GetResourceFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eClear, + .stencilStoreOp = vk::AttachmentStoreOp::eStore, + }); + + resourceAttachmentMapping->try_emplace(newResource.GetId().Raw, attachmentDescriptions.size() - 1); + } + + Handle SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept + { + return AddSubpass(std::move (subpassName), viewport, renderer); + } + + /***************************************************************************/ + /*! + + \brief + USE WITH CAUTION because the function does not reevaluate resource + layouts in attachment descriptions. All resources here will start at + UNDEFINED and end at whatever the last subpass using the attachment + specifies. It will also not support render graph node computes given its + complexity if it has to be accounted for. + + IN SHORT, IT GENERATES A RENDERPASS AS IF ITS THE ONLY NODE + IN THE RENDER GRAPH. SEE NOTES IN SHRenderGraph.h + + This function is mainly meant for nodes that are dynamic (in hindsight, + there really should have been a distinction between static and dynamic + nodes). + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeStandaloneRegenerate(void) noexcept + { + StandaloneConfigureAttDesc(false); + ConfigureSubpasses(); + CreateRenderpass(); + CreateFramebuffer(); + } + /***************************************************************************/ /*! @@ -633,4 +810,15 @@ namespace SHADE return attResources; } + Handle SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept + { + for (auto nc : nodeComputes) + { + if (nc->name == nodeComputeName) + return nc; + } + + return {}; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index a581d21c..b070b8fa 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -93,6 +93,9 @@ namespace SHADE void CreateFramebuffer(void) noexcept; void HandleResize (void) noexcept; void ConfigureSubpasses (void) noexcept; + bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept; + void AddDummySubpassIfNeeded(void) noexcept; + void StandaloneConfigureAttDesc (bool isLastNode) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -105,15 +108,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; - Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; - void AddDummySubpassIfNeeded (void) noexcept; - bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept; + Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; + + void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); - // TODO: RemoveSubpass() - void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex, Handle descPool); + // Runtime functions that don't affect the renderpass + void RuntimeLinkResource(std::string resourceName) noexcept; + Handle RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + void RuntimeStandaloneRegenerate (void) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ @@ -122,6 +127,7 @@ namespace SHADE Handle GetSubpass(std::string_view subpassName) const noexcept; Handle GetResource (uint32_t resourceIndex) const noexcept; std::vector> const& GetResources (void) const noexcept; + Handle GetNodeCompute (std::string nodeComputeName) const noexcept; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index cfc8443c..ef1b6b03 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -14,7 +14,56 @@ namespace SHADE { - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept + + bool SHRenderGraphNodeCompute::UsesResource(uint64_t resourceHandleID) const noexcept + { + for (auto& resource : resources) + { + if (resource.GetId().Raw == resourceHandleID) + return true; + } + return false; + } + + void SHRenderGraphNodeCompute::InitializeBarriers(void) noexcept + { + 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_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = resource->imageAspectFlags, + .baseMipLevel = 0, + .levelCount = resource->mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + } + ++i; + } + } + + void SHRenderGraphNodeCompute::SetFollowingEndRenderpass(uint32_t flag) noexcept + { + followingEndRenderpass = flag; + } + + + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} @@ -68,10 +117,12 @@ namespace SHADE // check if all layouts are there if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) { + Handle computeResourceLayout = {}; + computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; + // create compute resources computeResource = graphStorage->resourceHub->Create(); - auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; - computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 }); + computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount}); #ifdef _DEBUG for (auto set : computeResource->descSet->GetVkHandle()) SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); @@ -91,6 +142,11 @@ namespace SHADE void SHRenderGraphNodeCompute::Execute(Handle cmdBuffer, uint32_t frameIndex) noexcept { + for (auto& fn : preComputeFunctions) + { + fn (cmdBuffer, frameIndex); + } + // bind the compute pipeline cmdBuffer->BindPipeline(computePipeline); @@ -157,35 +213,7 @@ 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_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), - .subresourceRange = vk::ImageSubresourceRange - { - .aspectMask = resource->imageAspectFlags, - .baseMipLevel = 0, - .levelCount = resource->mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - } - }); - } - - ++i; - } + InitializeBarriers(); } void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span perFrameSizes) noexcept @@ -219,4 +247,17 @@ namespace SHADE } + void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept + { + static constexpr uint32_t COMPUTE_RESOURCE_SET_INDEX = 0; + computeResource->descSet->ModifyWriteDescImage(COMPUTE_RESOURCE_SET_INDEX, binding, viewSamplerLayout, descArrayIndex); + computeResource->descSet->UpdateDescriptorSetImage(COMPUTE_RESOURCE_SET_INDEX, binding, descArrayIndex); + + } + + void SHRenderGraphNodeCompute::AddPreComputeFunction(PreComputeFunction const& fn) noexcept + { + preComputeFunctions.push_back(fn); + } + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index dc3ca886..83bc5d33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -25,6 +25,10 @@ namespace SHADE class SHRenderGraphNodeCompute { + public: + using PreComputeFunction = std::function, uint32_t)>; + + private: // Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE struct ComputeResource @@ -73,8 +77,23 @@ namespace SHADE //! Name of this node std::string name; + std::vector preComputeFunctions; + + + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource (uint64_t resourceHandleID) const noexcept; + void InitializeBarriers (void) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetFollowingEndRenderpass (uint32_t flag) noexcept; + public: - SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; @@ -84,7 +103,9 @@ namespace SHADE void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span const& viewSamplerLayouts) noexcept; + void ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept; + void AddPreComputeFunction (PreComputeFunction const& fn) noexcept; friend class SHRenderGraph; friend class SHRenderGraphNode; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index 5a34fa04..d0a88e86 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -78,7 +78,7 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } @@ -88,6 +88,7 @@ namespace SHADE , height{ h } , mipLevels{ levels } , resourceName{ name } + , resizeWithWindow { inResizeWithWindow } { // If the resource type is an arbitrary image and not swapchain image if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT) @@ -210,6 +211,7 @@ namespace SHADE , imageAspectFlags{ rhs.imageAspectFlags } , graphStorage{rhs.graphStorage} , infoTracker {std::move (rhs.infoTracker)} + , resizeWithWindow{rhs.resizeWithWindow} { } @@ -242,7 +244,8 @@ namespace SHADE mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; graphStorage = rhs.graphStorage; - infoTracker = std::move(infoTracker); + infoTracker = std::move(rhs.infoTracker); + resizeWithWindow = rhs.resizeWithWindow; return *this; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index 7ac2b824..b9fe219e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -96,11 +96,14 @@ namespace SHADE //! For tracking resource states in stages of the render graphs Handle infoTracker; + //! Whether or not to resize (recreate vulkan image) when window resizes + bool resizeWithWindow; + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 3d2b1699..5205b44d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -77,6 +77,7 @@ namespace SHADE , name { rhs.name } , viewport {rhs.viewport} , renderer {rhs.renderer} + , companionSubpass {rhs.companionSubpass} { } @@ -113,6 +114,7 @@ namespace SHADE name = std::move(rhs.name); renderer = rhs.renderer; viewport = rhs.viewport; + companionSubpass = rhs.companionSubpass; return *this; @@ -162,7 +164,7 @@ namespace SHADE switch (attachmentDescriptionType) { case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; break; case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; @@ -211,25 +213,38 @@ namespace SHADE { commandBuffer->BeginLabeledSegment(name); - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex, descPool); - - if (viewport) + if (!HasNoAttachments()) { - // set viewport and scissor - uint32_t w = static_cast(viewport->GetWidth()); - uint32_t h = static_cast(viewport->GetHeight()); - commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + if (viewport) + { + // set viewport and scissor + uint32_t w = static_cast(viewport->GetWidth()); + uint32_t h = static_cast(viewport->GetHeight()); + commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + } + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); + + if (renderer) + renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); + + // If companion subpass is not a valid handle, render super batch normally + if (!companionSubpass.companion) + { + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + } + else + { + // if not bind pipeline for companion and and execute draw command + commandBuffer->BindPipeline(companionSubpass.pipeline); + companionSubpass.companion->superBatch->Draw(commandBuffer, frameIndex, false); + } } - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); - - if (renderer) - renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - // Draw all the exterior draw calls for (auto& drawCall : exteriorDrawCalls) { @@ -265,43 +280,27 @@ namespace SHADE */ /***************************************************************************/ - void SHSubpass::DetachResource(std::string const& resourceName, uint32_t attachmentIndex) noexcept + bool SHSubpass::UsesResource(uint32_t attachmentIndex) noexcept { for (uint32_t i = 0; i < colorReferences.size(); ++i) { if (colorReferences[i].attachment == attachmentIndex) - { - colorReferences.erase (colorReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < depthReferences.size(); ++i) { if (depthReferences[i].attachment == attachmentIndex) - { - depthReferences.erase(depthReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < inputReferences.size(); ++i) { if (inputReferences[i].attachment == attachmentIndex) - { - inputReferences.erase(inputReferences.begin() + i); - break; - } + return true; } - for (uint32_t i = 0; i < inputNames.size(); ++i) - { - if (inputNames[i] == resourceName) - { - inputNames.erase(inputNames.begin() + i); - break; - } - } + return false; } bool SHSubpass::HasNoAttachments(void) const noexcept @@ -458,6 +457,12 @@ namespace SHADE subpassIndex = index; } + void SHSubpass::SetCompanionSubpass(Handle companion, Handle pipeline) noexcept + { + companionSubpass.companion = companion; + companionSubpass.pipeline = pipeline; + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 6c582aa6..f84d4dee 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -21,12 +21,23 @@ namespace SHADE class SHVkSampler; class SHRenderer; class SHViewport; + class SHVkPipeline; class SH_API SHSubpass : public ISelfHandle { public: using ExteriorDrawCallFunction = std::function, Handle, uint32_t)>; + // Allows for subpasses to run using a companions data + struct CompanionSubpass + { + // subpass whose data will be borrowed to draw + Handle companion; + + // Pipeline that will be used for all the draw calls from all batches of the companion subpass + Handle pipeline; + }; + private: /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -94,6 +105,15 @@ namespace SHADE // For identifying subpasses std::string name; + //! Optional component to a companion subpass. If the subpass handle of this object + //! is valid, the subpass will be drawn using this companion's data. + CompanionSubpass companionSubpass; + + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource(uint32_t attachmentIndex) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -119,7 +139,6 @@ namespace SHADE void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; void BindInputDescriptorSets (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; - void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept; bool HasNoAttachments (void) const noexcept; void Init(SHResourceHub& resourceManager) noexcept; @@ -128,19 +147,24 @@ namespace SHADE void CreateInputDescriptors (void) noexcept; void UpdateWriteDescriptors (void) noexcept; - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ void SetIndex (uint32_t index) noexcept; public: - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch(void) const noexcept; + /*-----------------------------------------------------------------------*/ + /* PUBLIC SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetCompanionSubpass (Handle companion, Handle pipeline) noexcept; + + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; std::vector const& GetColorAttachmentReferences (void) const noexcept; - vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; - const std::string& GetName() const; + vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; + const std::string& GetName() const; friend class SHRenderGraphNode; friend class SHRenderGraph; diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index b8f329b9..2f0ab6d6 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -100,6 +100,475 @@ namespace SHADE } } + std::string SHInputManager::GetKeyCodeName(SH_KEYCODE k) noexcept + { + int kInt = static_cast(k); + //Numbers + if (kInt >= static_cast(SH_KEYCODE::NUMBER_0) && kInt <= static_cast(SH_KEYCODE::NUMBER_9)) + { + return std::to_string(kInt - 48); + } + //Letters + if (kInt >= static_cast(SH_KEYCODE::A) && kInt <= static_cast(SH_KEYCODE::Z)) + { + return std::string(1, static_cast(kInt)); + } + //Numpads + if (kInt >= static_cast(SH_KEYCODE::NUMPAD_0) && kInt <= static_cast(SH_KEYCODE::NUMPAD_9)) + { + return "Numpad " + std::to_string(kInt - 96); + } + //Function keys + if (kInt >= static_cast(SH_KEYCODE::F1) && kInt <= static_cast(SH_KEYCODE::F24)) + { + return "F" + std::to_string(kInt - 111); + } + + //Other keys + switch (k) + { + case SH_KEYCODE::LMB: + return "Left Mouse Button"; + break; + case SH_KEYCODE::RMB: + return "Right Mouse Button"; + break; + case SH_KEYCODE::CANCEL: + return "Cancel"; + break; + case SH_KEYCODE::MMB: + return "Middle Mouse Button"; + break; + case SH_KEYCODE::XMB1: + return "X1 Mouse Button"; + break; + case SH_KEYCODE::XMB2: + return "X2 Mouse Button"; + break; + case SH_KEYCODE::BACKSPACE: + return "Backspace"; + break; + case SH_KEYCODE::TAB: + return "Tab"; + break; + case SH_KEYCODE::CLEAR: + return "Clear"; + break; + case SH_KEYCODE::ENTER: + return "Enter"; + break; + case SH_KEYCODE::SHIFT: + return "Shift"; + break; + case SH_KEYCODE::CTRL: + return "Ctrl"; + break; + case SH_KEYCODE::ALT: + return "Alt"; + break; + case SH_KEYCODE::PAUSE: + return "Pause"; + break; + case SH_KEYCODE::CAPS_LOCK: + return "Caps Lock"; + break; + case SH_KEYCODE::IME_KANA: + return "IME Kana / Hangul Mode"; + break; + case SH_KEYCODE::IME_ON: + return "IME On"; + break; + case SH_KEYCODE::IME_JUNJA: + return "IME Junja Mode"; + break; + case SH_KEYCODE::IME_FINAL: + return "IME Final Mode"; + break; + case SH_KEYCODE::IME_HANJA: + return "IME Kanji / Hanja Mode"; + break; + case SH_KEYCODE::IME_OFF: + return "IME Off"; + break; + case SH_KEYCODE::ESCAPE: + return "Esc"; + break; + case SH_KEYCODE::IME_CONVERT: + return "IME Convert"; + break; + case SH_KEYCODE::IME_NONCONVERT: + return "IME Nonconvert"; + break; + case SH_KEYCODE::IME_ACCEPT: + return "IME Accept"; + break; + case SH_KEYCODE::IME_MODECHANGE: + return "IME Mode Change Request"; + break; + case SH_KEYCODE::SPACE: + return "Spacebar"; + break; + case SH_KEYCODE::PAGE_UP: + return "Page Up"; + break; + case SH_KEYCODE::PAGE_DOWN: + return "Page Down"; + break; + case SH_KEYCODE::END: + return "End"; + break; + case SH_KEYCODE::HOME: + return "Home"; + break; + case SH_KEYCODE::LEFT_ARROW: + return "Left Arrow"; + break; + case SH_KEYCODE::UP_ARROW: + return "Up Arrow"; + break; + case SH_KEYCODE::RIGHT_ARROW: + return "Right Arrow"; + break; + case SH_KEYCODE::DOWN_ARROW: + return "Down Arrow"; + break; + case SH_KEYCODE::SELECT: + return "Select"; + break; + case SH_KEYCODE::PRINT: + return "Print"; + break; + case SH_KEYCODE::EXECUTE: + return "Execute"; + break; + case SH_KEYCODE::PRINT_SCREEN: + return "Print Screen"; + break; + case SH_KEYCODE::INSERT: + return "Insert"; + break; + case SH_KEYCODE::DEL: + return "Delete"; + break; + case SH_KEYCODE::HELP: + return "Help"; + break; + case SH_KEYCODE::LEFT_WINDOWS: + return "Left Windows"; + break; + case SH_KEYCODE::RIGHT_WINDOWS: + return "Right Windows"; + break; + case SH_KEYCODE::APPS: + return "Applications"; + break; + case SH_KEYCODE::SLEEP: + return "Sleep"; + break; + case SH_KEYCODE::MULTIPLY: + return "Numpad *"; + break; + case SH_KEYCODE::ADD: + return "Numpad +"; + break; + case SH_KEYCODE::SEPARATOR: + return "Separator"; + break; + case SH_KEYCODE::SUBTRACT: + return "Numpad -"; + break; + case SH_KEYCODE::DECIMAL: + return "Numpad ."; + break; + case SH_KEYCODE::DIVIDE: + return "Numpad /"; + break; + case SH_KEYCODE::NUM_LOCK: + return "Num Lock"; + break; + case SH_KEYCODE::SCROLL_LOCK: + return "Scroll Lock"; + break; + case SH_KEYCODE::OEM_PC98_NUMPAD_EQUAL: + return "OEM PC98 Numpad Equal / Fujitsu Dictionary"; + break; + case SH_KEYCODE::OEM_FUJITSU_UNREGISTER: + return "OEM Fujitsu Unregister"; + break; + case SH_KEYCODE::OEM_FUJITSU_REGISTER: + return "OEM Fujitsu Register"; + break; + case SH_KEYCODE::OEM_FUJITSU_LEFT_THUMB: + return "OEM Fujitsu Left Thumb"; + break; + case SH_KEYCODE::OEM_FUJITSU_RIGHT_THUMB: + return "OEM Fujitsu Right Thumb"; + break; + case SH_KEYCODE::LEFT_SHIFT: + return "Left Shift"; + break; + case SH_KEYCODE::RIGHT_SHIFT: + return "Right Shift"; + break; + case SH_KEYCODE::LEFT_CTRL: + return "Left Ctrl"; + break; + case SH_KEYCODE::RIGHT_CTRL: + return "Right Ctrl"; + break; + case SH_KEYCODE::LEFT_ALT: + return "Left Alt"; + break; + case SH_KEYCODE::RIGHT_ALT: + return "Right Alt"; + break; + case SH_KEYCODE::BROWSER_BACK: + return "Browser Back"; + break; + case SH_KEYCODE::BROWSER_FORWARD: + return "Browser Forward"; + break; + case SH_KEYCODE::BROWSER_REFRESH: + return "Browser Refresh"; + break; + case SH_KEYCODE::BROWSER_STOP: + return "Browser Stop"; + break; + case SH_KEYCODE::BROWSER_SEARCH: + return "Browser Search"; + break; + case SH_KEYCODE::BROWSER_FAVOURITES: + return "Browser Favourites"; + break; + case SH_KEYCODE::BROWSER_HOME: + return "Browser Start and Home"; + break; + case SH_KEYCODE::VOLUME_MUTE: + return "Volume Mute"; + break; + case SH_KEYCODE::VOLUME_DOWN: + return "Volume Down"; + break; + case SH_KEYCODE::VOLUME_UP: + return "Volume Up"; + break; + case SH_KEYCODE::MEDIA_NEXT_TRACK: + return "Media Next Track"; + break; + case SH_KEYCODE::MEDIA_PREVIOUS_TRACK: + return "Media Previous Track"; + break; + case SH_KEYCODE::MEDIA_STOP: + return "Media Stop"; + break; + case SH_KEYCODE::MEDIA_PLAY_PAUSE: + return "Media Play/Pause"; + break; + case SH_KEYCODE::LAUNCH_MAIL: + return "Launch Mail"; + break; + case SH_KEYCODE::LAUNCH_MEDIA_SELECT: + return "Select Media"; + break; + case SH_KEYCODE::LAUNCH_APP_1: + return "Launch App 1"; + break; + case SH_KEYCODE::LAUNCH_APP_2: + return "Launch App 2"; + break; + case SH_KEYCODE::OEM_1: + return "; or :"; + break; + case SH_KEYCODE::OEM_PLUS: + return "= or +"; + break; + case SH_KEYCODE::OEM_COMMA: + return ", or <"; + break; + case SH_KEYCODE::OEM_MINUS: + return "- or _"; + break; + case SH_KEYCODE::OEM_PERIOD: + return ". or >"; + break; + case SH_KEYCODE::OEM_2: + return "/ or ?"; + break; + case SH_KEYCODE::OEM_3: + return "` or ~"; + break; + case SH_KEYCODE::OEM_4: + return "[ or {"; + break; + case SH_KEYCODE::OEM_5: + return "\\ or |"; + break; + case SH_KEYCODE::OEM_6: + return "] or }"; + break; + case SH_KEYCODE::OEM_7: + return "\' or \""; + break; + case SH_KEYCODE::OEM_8: + return "OEM 8"; + break; + case SH_KEYCODE::OEM_AX: + return "OEM AX"; + break; + case SH_KEYCODE::OEM_102: + return "< or > or \\ or |"; + break; + case SH_KEYCODE::OEM_ICO_HELP: + return "ICO Help"; + break; + case SH_KEYCODE::OEM_ICO_00: + return "ICO 00"; + break; + case SH_KEYCODE::IME_PROCESS: + return "IME Process"; + break; + case SH_KEYCODE::OEM_ICO_CLEAR: + return "ICO Clear"; + break; + case SH_KEYCODE::PACKET: + return "Packet"; + break; + case SH_KEYCODE::OEM_RESET: + return "OEM Reset"; + break; + case SH_KEYCODE::OEM_JUMP: + return "OEM Jump"; + break; + case SH_KEYCODE::OEM_PA1: + return "OEM PA1"; + break; + case SH_KEYCODE::OEM_PA2: + return "OEM PA2"; + break; + case SH_KEYCODE::OEM_PA3: + return "OEM PA3"; + break; + case SH_KEYCODE::OEM_WSCTRL: + return "OEM WSCTRL"; + break; + case SH_KEYCODE::OEM_CUSEL: + return "OEM CuSel"; + break; + case SH_KEYCODE::OEM_ATTN: + return "OEM Attn"; + break; + case SH_KEYCODE::OEM_FINISH: + return "OEM Finish"; + break; + case SH_KEYCODE::OEM_COPY: + return "OEM Copy"; + break; + case SH_KEYCODE::OEM_AUTO: + return "OEM Auto"; + break; + case SH_KEYCODE::OEM_ENLW: + return "OEM ENLW"; + break; + case SH_KEYCODE::OEM_BACKTAB: + return "OEM Backtab"; + break; + case SH_KEYCODE::ATTN: + return "Attn"; + break; + case SH_KEYCODE::CRSEL: + return "CrSel"; + break; + case SH_KEYCODE::EXSEL: + return "ExSel"; + break; + case SH_KEYCODE::EREOF: + return "Erase EOF"; + break; + case SH_KEYCODE::PLAY: + return "Play"; + break; + case SH_KEYCODE::ZOOM: + return "Zoom"; + break; + case SH_KEYCODE::NONAME: + return "No Name Key"; + break; + case SH_KEYCODE::PA_1: + return "PA1"; + break; + case SH_KEYCODE::OEM_CLEAR: + return "OEM Clear"; + break; + } + } + + std::string SHInputManager::GetControllerCodeName(SH_CONTROLLERCODE c) noexcept + { + switch (c) + { + case SH_CONTROLLERCODE::DPAD_UP: + return "D-Pad Up"; + break; + case SH_CONTROLLERCODE::DPAD_DOWN: + return "D-Pad Down"; + break; + case SH_CONTROLLERCODE::DPAD_LEFT: + return "D-Pad Left"; + break; + case SH_CONTROLLERCODE::DPAD_RIGHT: + return "D-Pad Right"; + break; + case SH_CONTROLLERCODE::START: + return "Start Button"; + break; + case SH_CONTROLLERCODE::BACK: + return "Back Button"; + break; + case SH_CONTROLLERCODE::LEFT_THUMBSTICK: + return "Left Thumbstick Button"; + break; + case SH_CONTROLLERCODE::RIGHT_THUMBSTICK: + return "Right Thumbstick Button"; + break; + case SH_CONTROLLERCODE::LEFT_SHOULDER: + return "Left Shoulder Button"; + break; + case SH_CONTROLLERCODE::RIGHT_SHOULDER: + return "Right Shoulder Button"; + break; + case SH_CONTROLLERCODE::A: + return "A Button"; + break; + case SH_CONTROLLERCODE::B: + return "B Button"; + break; + case SH_CONTROLLERCODE::X: + return "X Button"; + break; + case SH_CONTROLLERCODE::Y: + return "Y Button"; + break; + case SH_CONTROLLERCODE::LEFT_TRIGGER: + return "Left Trigger"; + break; + case SH_CONTROLLERCODE::RIGHT_TRIGGER: + return "Right Trigger"; + break; + case SH_CONTROLLERCODE::LEFT_THUMBSTICK_X: + return "Left Thumbstick Horizontal"; + break; + case SH_CONTROLLERCODE::LEFT_THUMBSTICK_Y: + return "Left Thumbstick Vertical"; + break; + case SH_CONTROLLERCODE::RIGHT_THUMBSTICK_X: + return "Right Thumbstick Horizontal"; + break; + case SH_CONTROLLERCODE::RIGHT_THUMBSTICK_Y: + return "Right Thumbstick Vertical"; + break; + } + } + //The Binding File format presently goes as such: /* * Binding count @@ -680,7 +1149,7 @@ namespace SHADE digitalInput = true; } if (std::abs(newValue) > std::abs(largestMagnitude)) - largestMagnitude = newValue * data.sensitivity * (data.inverted ? -1.0 : 1.0); + largestMagnitude = newValue * (data.inverted ? -1.0 : 1.0); } } @@ -696,7 +1165,7 @@ namespace SHADE digitalInput = true; } if (std::abs(newValue) > std::abs(largestMagnitude)) - largestMagnitude = -newValue * data.sensitivity * (data.inverted ? -1.0 : 1.0); + largestMagnitude = -newValue * (data.inverted ? -1.0 : 1.0); } } @@ -740,21 +1209,23 @@ namespace SHADE if (data.value > 1.0) data.value = 1.0; else if (data.value < -1.0) data.value = -1.0; } - //If analog input was in, - //sensitivity is instead used as a multiplier + //If analog input was in, raw value taken else { - data.value = largestMagnitude * data.sensitivity; + data.value = largestMagnitude; if (data.value > 1.0) data.value = 1.0; else if (data.value < -1.0) data.value = -1.0; } if (data.snap) //Snapping { - if (data.value > 0.0 && data.negativeInputHeld) - data.value = 0.0; - if (data.value < 0.0 && data.positiveInputHeld) - data.value = 0.0; + if (digitalInput) //Only for digital inputs + { + if (data.value > 0.0 && data.negativeInputHeld) + data.value = 0.0; + if (data.value < 0.0 && data.positiveInputHeld) + data.value = 0.0; + } } } } @@ -936,11 +1407,11 @@ namespace SHADE { return 0.0; } - else if (bindings[bindingName].positiveInputHeld) + else if (GetBindingAxis(bindingName, cNum) > 0.0) { return 1.0; } - else if (bindings[bindingName].negativeInputHeld) + else if (GetBindingAxis(bindingName, cNum) < 0.0) { return -1.0; } diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 680035c3..1bcafa7d 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -363,6 +363,7 @@ namespace SHADE //Speed in units per second that the axis will move toward target value for digital //For mouse movement / scrolling, serves as multiplier + //Irrelevant for other analog inputs double sensitivity = 1.0; //If enabled, axis value will reset to zero when pressing a button @@ -415,6 +416,12 @@ namespace SHADE return controllerInUse; } + //Get the name of key code + static std::string GetKeyCodeName(SH_KEYCODE const keyCode) noexcept; + + //Get the name of controller code + static std::string GetControllerCodeName(SH_CONTROLLERCODE const controllerCode) noexcept; + //For testing purposes //static void PrintCurrentState() noexcept; @@ -738,6 +745,16 @@ namespace SHADE return bindings.erase(bindingName); } + //Rename a binding + static inline void RenameBinding(std::string const& oldBindingName, std::string const& newBindingName) noexcept + { + //https://stackoverflow.com/a/44883472 + //https://en.cppreference.com/w/cpp/container/map/extract + auto nodeHandler = bindings.extract(oldBindingName); + nodeHandler.key() = newBindingName; + bindings.insert(std::move(nodeHandler)); + } + //Clears all bindings from the list static inline void ClearBindings() noexcept { @@ -809,7 +826,7 @@ namespace SHADE //Get the sensitivity of the binding //Serves as a multiplier for mouse movement/scrolling //For other digital inputs, serves as a rate of how fast axis value goes to maximum positive/negative - //For other analog inputs, serves as a multiplier, but axis value magnitude will still be capped at 1 + //Irrelevant for other analog inputs static inline double GetBindingSensitivity(std::string const& bindingName) { return bindings[bindingName].sensitivity; @@ -818,7 +835,7 @@ namespace SHADE //Set the sensitivity of the binding //Serves as a multiplier for mouse movement/scrolling //For other digital inputs, serves as a rate of how fast axis value goes to maximum positive/negative - //For other analog inputs, serves as a multiplier, but axis value magnitude will still be capped at 1 + //Irrelevant for other analog inputs static inline void SetBindingSensitivity(std::string const& bindingName, double const newValue) { bindings[bindingName].sensitivity = newValue; @@ -984,8 +1001,6 @@ namespace SHADE //Get the axis value of binding, between -1 and 1 for non-mouse movement/wheel //For mouse movement/wheel, it won't be between -1 and 1. It will also be multiplied by sensitivity - //To avoid interference between mouse movement/wheel and keyboard/mouse/controller input, - //Set mouseXBound, mouseYBound and mouseScrollBound to false //controllerNumber is not used static double GetBindingAxis(std::string const& bindingName, size_t controllerNumber = 0) noexcept; diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index a0b961a3..6af13b17 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -11,15 +11,8 @@ #include #include "Assets/Asset Types/SHSceneAsset.h" -#include "Camera/SHCameraComponent.h" -#include "Camera/SHCameraArmComponent.h" -#include "Math/Transform/SHTransformComponent.h" -#include "Graphics/MiddleEnd/Interface/SHRenderable.h" -#include "Physics/Interface/SHRigidBodyComponent.h" -#include "UI/SHCanvasComponent.h" -#include "UI/SHButtonComponent.h" +#include "Common/SHAllComponents.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" #include "Tools/FileIO/SHFileIO.h" @@ -208,6 +201,7 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); @@ -265,6 +259,7 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); return componentIDList; @@ -346,6 +341,7 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 58268b57..2e2d45f4 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -1,5 +1,7 @@ #pragma once #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Math/Geometry/SHBox.h" #include "Math/Geometry/SHSphere.h" @@ -11,8 +13,6 @@ #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "SHSerializationTools.h" -#include "Physics/Interface/SHColliderComponent.h" -#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Physics/Collision/SHCollisionTagMatrix.h" diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.h b/SHADE_Engine/src/Tools/SHDebugDraw.h index 3d7bee2f..c775a514 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.h +++ b/SHADE_Engine/src/Tools/SHDebugDraw.h @@ -205,7 +205,7 @@ namespace SHADE /// /// Colour to draw with. /// Whether or not drawn object will be occluded. - void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Function Class "Folder" */ @@ -388,7 +388,7 @@ namespace SHADE /// /// Colour to draw with. /// Whether or not drawn object will be occluded. - void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /// /// Clears any persistent drawn debug primitives. /// diff --git a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp index b9698071..f547da6c 100644 --- a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp +++ b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp @@ -13,6 +13,7 @@ of DigiPen Institute of Technology is prohibited. #include // Primary Header #include "SHStringUtilities.h" +#include namespace SHADE { @@ -50,5 +51,12 @@ namespace SHADE { return std::system_category().message(errorCode); } + + size_t SHStringUtilities::StringFindInsensitive(std::string str, std::string search, size_t pos) + { + std::transform(str.begin(), str.end(), str.begin(), [](char c) {return static_cast(std::tolower(c)); }); + std::transform(search.begin(), search.end(), search.begin(), [](char c) {return static_cast(std::tolower(c)); }); + return str.find(search, pos); + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h index bac83b07..697e19f2 100644 --- a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h +++ b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h @@ -4,9 +4,9 @@ \par email: kahwei.tng\@digipen.edu \date Nov 29, 2021 \brief Contains the declaration of functions for working with files and folders. - + Copyright (C) 2021 DigiPen Institute of Technology. -Reproduction or disclosure of this file or its contents without the prior written consent +Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ #pragma once @@ -16,66 +16,68 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /// - /// Contains useful functions for operating on strings. - /// - class SHStringUtilities - { - public: - /*-----------------------------------------------------------------------------*/ - /* Utility Functions */ - /*-----------------------------------------------------------------------------*/ - - /// - /// Splits a string separated by a specified delimiter into a vector of strings. - /// - /// Internal type of each element in the string. - /// Read only reference to the string to split. - /// Read only reference to the delimiter. - /// Vector of strings that have been split. - template - static std::vector> Split(const std::basic_string& str, const T& delim); - /// - /// Splits a string separated by a specified delimiter into a vector of strings. - /// Overload of Split() to allow for string literals to be accepted. - /// - /// Read only reference to the string to split. - /// Read only reference to the delimiter. - /// Vector of strings that have been split. - static std::vector Split(const std::string& str, const char& delim); - /// - /// Splits a string separated by a specified delimiter into a vector of strings. - /// Overload of Split() to allow for wide string literals to be accepted. - /// - /// Read only reference to the string to split. - /// Read only reference to the delimiter. - /// Vector of strings that have been split. - static std::vector Split(const std::wstring& str, const wchar_t& delim); - /// - /// Converts a wstring to a string. - /// - /// wstring to convert. - /// The converted wstring in string form. - static std::string WstrToStr(const std::wstring& wstr); - /// - /// Converts a string to a wstring. - /// - /// string to convert. - /// The converted string in wstring form. - static std::wstring StrToWstr(const std::string& str); - /// - /// Retrieves the error message associated with a Win32 error code. - /// - /// Win32 error code to decode. - /// String that represents the Win32 error. - static std::string GetWin32ErrorMessage(unsigned long errorCode); + /// + /// Contains useful functions for operating on strings. + /// + class SHStringUtilities + { + public: + /*-----------------------------------------------------------------------------*/ + /* Utility Functions */ + /*-----------------------------------------------------------------------------*/ - private: - /*-------------------------------------------------------------------------------*/ - /* Constructors/Destructors */ - /*-------------------------------------------------------------------------------*/ - SHStringUtilities() = delete; - }; + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// + /// Internal type of each element in the string. + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + template + static std::vector> Split(const std::basic_string& str, const T& delim); + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// Overload of Split() to allow for string literals to be accepted. + /// + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + static std::vector Split(const std::string& str, const char& delim); + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// Overload of Split() to allow for wide string literals to be accepted. + /// + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + static std::vector Split(const std::wstring& str, const wchar_t& delim); + /// + /// Converts a wstring to a string. + /// + /// wstring to convert. + /// The converted wstring in string form. + static std::string WstrToStr(const std::wstring& wstr); + /// + /// Converts a string to a wstring. + /// + /// string to convert. + /// The converted string in wstring form. + static std::wstring StrToWstr(const std::string& str); + /// + /// Retrieves the error message associated with a Win32 error code. + /// + /// Win32 error code to decode. + /// String that represents the Win32 error. + static std::string GetWin32ErrorMessage(unsigned long errorCode); + + static size_t StringFindInsensitive(std::string str, std::string search, size_t pos = 0); + + private: + /*-------------------------------------------------------------------------------*/ + /* Constructors/Destructors */ + /*-------------------------------------------------------------------------------*/ + SHStringUtilities() = delete; + }; } #include "SHStringUtilities.hpp" diff --git a/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h b/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h new file mode 100644 index 00000000..35bcdc61 --- /dev/null +++ b/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h @@ -0,0 +1,16 @@ +#pragma once + + +#include "ECS_Base/SHECSMacros.h" + +namespace SHADE +{ + struct SHButtonClickEvent + { + EntityID EID; + // value of the toggle button, default to false if its a button and not a toggle button + bool value{false}; + }; + + +} diff --git a/SHADE_Engine/src/UI/SHButtonComponent.cpp b/SHADE_Engine/src/UI/SHButtonComponent.cpp index 7b275128..8e87b10e 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.cpp +++ b/SHADE_Engine/src/UI/SHButtonComponent.cpp @@ -5,7 +5,7 @@ namespace SHADE { SHButtonComponent::SHButtonComponent() - :size(1.0f), offset(0.0f), isHovered(false), isClicked(false), + :size(1.0f), isHovered(false), isClicked(false), defaultTexture(0), hoveredTexture(0), clickedTexture(0) { } diff --git a/SHADE_Engine/src/UI/SHButtonComponent.h b/SHADE_Engine/src/UI/SHButtonComponent.h index 39790b6a..3aac09e6 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.h +++ b/SHADE_Engine/src/UI/SHButtonComponent.h @@ -18,7 +18,6 @@ namespace SHADE virtual ~SHButtonComponent() = default; SHVec2 size; - SHVec2 offset; AssetID GetClickedTexture() const noexcept; AssetID GetDefaultTexture() const noexcept; @@ -33,8 +32,10 @@ namespace SHADE friend class SHUISystem; private: - + //Set to true when mouse is hovering over the button. bool isHovered; + //This is set to true when the mouse clicks down, and set back to false when mouse releases. + //The event for the button click will be broadcasted when mouse release. bool isClicked; AssetID defaultTexture; AssetID hoveredTexture; diff --git a/SHADE_Engine/src/UI/SHSliderComponent.cpp b/SHADE_Engine/src/UI/SHSliderComponent.cpp new file mode 100644 index 00000000..56d1d89b --- /dev/null +++ b/SHADE_Engine/src/UI/SHSliderComponent.cpp @@ -0,0 +1,39 @@ +#include "SHpch.h" +#include "SHSliderComponent.h" + +namespace SHADE +{ + SHSliderComponent::SHSliderComponent() + :size(1.0f), isHovered(false), isClicked(false), value(0.0f) + { + + } + + + float SHSliderComponent::GetValue() const noexcept + { + return value; + } + + void SHSliderComponent::SetValue(float value) noexcept + { + this->value = value; + } + + + +} + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Slider Component") + .property("Slider Value", &SHSliderComponent::GetValue, &SHSliderComponent::SetValue) + + ; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHSliderComponent.h b/SHADE_Engine/src/UI/SHSliderComponent.h new file mode 100644 index 00000000..bdc57c7e --- /dev/null +++ b/SHADE_Engine/src/UI/SHSliderComponent.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "SH_API.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec2.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + + class SH_API SHSliderComponent final: public SHComponent + { + public: + SHSliderComponent(); + virtual ~SHSliderComponent() = default; + + SHVec2 size; + + + float GetValue() const noexcept; + + + void SetValue(float value) noexcept; + + + friend class SHUISystem; + private: + + bool isHovered; + bool isClicked; + + float value; + + RTTR_ENABLE() + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp b/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp new file mode 100644 index 00000000..527323ea --- /dev/null +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp @@ -0,0 +1,59 @@ +#include "SHpch.h" +#include "SHToggleButtonComponent.h" + + +namespace SHADE +{ + SHToggleButtonComponent::SHToggleButtonComponent() + :size(1.0f), isHovered(false), isClicked(false), value(false), + defaultTexture(0), toggledTexture(0) + { + } + + AssetID SHToggleButtonComponent::GetDefaultTexture() const noexcept + { + return defaultTexture; + } + + AssetID SHToggleButtonComponent::GetToggledTexture() const noexcept + { + return toggledTexture; + } + + bool SHToggleButtonComponent::GetValue() const noexcept + { + return value; + } + + + void SHToggleButtonComponent::SetDefaultTexture(AssetID texture) noexcept + { + defaultTexture = texture; + } + + void SHToggleButtonComponent::SetToggledTexture(AssetID texture) noexcept + { + toggledTexture = texture; + } + + void SHToggleButtonComponent::SetValue(bool value) noexcept + { + this->value = value; + } + +} + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Toggle Button Component") + .property("Non Toggled Texture", &SHToggleButtonComponent::GetDefaultTexture, &SHToggleButtonComponent::SetDefaultTexture) + .property("Toggled Texture", &SHToggleButtonComponent::GetToggledTexture, &SHToggleButtonComponent::SetToggledTexture) + .property("Value", &SHToggleButtonComponent::GetValue, &SHToggleButtonComponent::SetValue) + ; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.h b/SHADE_Engine/src/UI/SHToggleButtonComponent.h new file mode 100644 index 00000000..2c77f3ba --- /dev/null +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "SH_API.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec2.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + + class SH_API SHToggleButtonComponent final: public SHComponent + { + public: + SHToggleButtonComponent(); + virtual ~SHToggleButtonComponent() = default; + + SHVec2 size; + + AssetID GetToggledTexture() const noexcept; + AssetID GetDefaultTexture() const noexcept; + bool GetValue() const noexcept; + + + void SetDefaultTexture(AssetID texture) noexcept; + void SetToggledTexture(AssetID texture) noexcept; + void SetValue(bool value) noexcept; + + + + friend class SHUISystem; + private: + + //Set to true when mouse is hovering over the button. + bool isHovered; + //This is set to true when the mouse clicks down, and set back to false when mouse releases. + //The event for the button click will be broadcasted when mouse release. + bool isClicked; + bool value; + AssetID defaultTexture; + AssetID toggledTexture; + + + + RTTR_ENABLE() + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 1387bc6b..c75af66f 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -9,7 +9,15 @@ #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/SHEditor.h" #include "Resource/SHResourceManager.h" +#include "Assets/SHAssetManager.h" #include "Input/SHInputManager.h" +#include "SHUIComponent.h" +#include "SHButtonComponent.h" +#include "SHToggleButtonComponent.h" +#include "SHSliderComponent.h" +#include "SHCanvasComponent.h" +#include "Events/SHEventManager.hpp" +#include "Events/SHButtonClickEvent.h" namespace SHADE { @@ -103,7 +111,7 @@ namespace SHADE { auto transform = SHComponentManager::GetComponent(comp.GetEID()); if (canvasComp != nullptr) - comp.localToCanvasMatrix = canvasComp->GetMatrix()* transform->GetTRS(); + comp.localToCanvasMatrix = transform->GetTRS() * canvasComp->GetMatrix(); else comp.localToCanvasMatrix = transform->GetTRS(); } @@ -139,77 +147,235 @@ namespace SHADE void SHUISystem::UpdateButtonComponent(SHButtonComponent& comp) noexcept { - if (!SHComponentManager::HasComponent(comp.GetEID()) || !SHComponentManager::HasComponent(comp.GetEID())) + if (!SHComponentManager::HasComponent(comp.GetEID())) + { + return; + } + auto cameraSystem = SHSystemManager::GetSystem(); + auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); + //auto canvasComp = SHComponentManager::GetComponent_s(uiComp->canvasID); + + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); + + + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; + SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; + + + SHVec2 mousePos; + SHVec2 windowSize; +#ifdef SHEDITOR + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; + mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; + //mousePos.y = windowSize.y - mousePos.y; + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + mousePos /= windowSize; + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + + + +#else + + int x, y; + SHInputManager::GetMouseScreenPosition(&x, &y); + mousePos.x = x; + mousePos.y = y; + auto ws = SHSystemManager::GetSystem()->GetWindow()->GetWindowSize(); + windowSize = { ws.first,ws.second }; + mousePos /= windowSize; +#endif + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; + //SHLOG_INFO("TopExtent: {}, {}", topExtent.x, topExtent.y) + + topExtent = CanvasToScreenPoint(topExtent,true); + btmExtent = CanvasToScreenPoint(btmExtent,true); + //SHLOG_INFO("TopExtent: {}, {} Btm Extent: {}, {}", topExtent.x, topExtent.y, btmExtent.x, btmExtent.y) + + + //comp.isClicked = false; + if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x + && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) + { + comp.isHovered = true; + #ifdef SHEDITOR + //if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + } + #else + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + #endif + + //SHLOG_INFO("HOVERED") + } + else + { + comp.isHovered = false; + //SHLOG_INFO("NOT HOVERED") + } + if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = false; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + + if (SHComponentManager::HasComponent(comp.GetEID())) + { + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); + + auto material = renderable->GetModifiableMaterial(); + if(!comp.isHovered && !comp.isClicked) + if (comp.GetDefaultTexture() != 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + else if (comp.isClicked) + { + if (comp.GetClickedTexture() != 0 && SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetClickedTexture()); + //SHLOG_INFO("SETTING CLICKED TEXTURE") + } + } + else + { + if (comp.GetHoveredTexture() != 0 && SHAssetManager::GetType(comp.GetHoveredTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetHoveredTexture()); + //SHLOG_INFO("SETTING HOVERED TEXTURE") + } + } + + + + } + } + + + void SHUISystem::UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept + { + if (!SHComponentManager::HasComponent(comp.GetEID())) { return; } auto cameraSystem = SHSystemManager::GetSystem(); auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); - SHVec4 topExtent4 = uiComp->GetMatrix() * SHVec4(-comp.size.x * 0.5f, comp.size.y * 0.5f , 0.0f,1.0f); - SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f); + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); - SHVec2 topExtent{ topExtent4.x,-topExtent4.y }; - SHVec2 btmExtent{ btmExtent4.x,-btmExtent4.y }; - + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; + SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; - SHVec2 windowSize; SHVec2 mousePos; + SHVec2 windowSize; + #ifdef SHEDITOR - - windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; + //mousePos.y = windowSize.y - mousePos.y; + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + mousePos /= windowSize; + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) -#endif - - - - SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0).x , cameraSystem->GetCameraWidthHeight(0).y }; - - topExtent += camSize * 0.5f; - btmExtent += camSize * 0.5f; - - //Convert everything to using ratios - topExtent /= camSize; - btmExtent /= camSize; +#else + int x, y; + SHInputManager::GetMouseScreenPosition(&x, &y); + mousePos.x = x; + mousePos.y = y; + auto ws = SHSystemManager::GetSystem()->GetWindow()->GetWindowSize(); + windowSize = { ws.first,ws.second }; mousePos /= windowSize; +#endif + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; + + + + topExtent = CanvasToScreenPoint(topExtent,true); + btmExtent = CanvasToScreenPoint(btmExtent, true); + + - //SHLOG_INFO("mousePos: {} , {}", mousePos.x, mousePos.y); comp.isClicked = false; if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) { comp.isHovered = true; - if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) +#ifdef SHEDITOR + if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + } +#else + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; } - //SHLOG_INFO("BUTTON HOVERED"); - - +#endif } else { comp.isHovered = false; - - //SHLOG_INFO("BUTTON NOT HOVERED") } - - + + + if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = false; + comp.value = !comp.value; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + clickEvent.value = comp.value; + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + if (SHComponentManager::HasComponent(comp.GetEID())) { - //auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); - //auto material = renderable->GetModifiableMaterial(); - //material->SetProperty("texture", comp.GetDefaultTexture()); + auto material = renderable->GetModifiableMaterial(); + if (comp.GetValue() == false) + { + if (comp.GetDefaultTexture()!= 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + } + else + { + if (comp.GetToggledTexture() != 0 && SHAssetManager::GetType(comp.GetToggledTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetToggledTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + } + } } + void SHUISystem::UpdateButtonsRoutine::Execute(double dt) noexcept { SHUISystem* system = (SHUISystem*)GetSystem(); @@ -219,6 +385,34 @@ namespace SHADE if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) system->UpdateButtonComponent(comp); } + + auto& toggleButtonDense = SHComponentManager::GetDense(); + for (auto& comp : toggleButtonDense) + { + if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) + system->UpdateToggleButtonComponent(comp); + } } + SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept + { + SHVec2 result{canvasPoint}; + + auto cameraSystem = SHSystemManager::GetSystem(); + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; + //camSize.y *= -1.0f; + + result.y *= -1.0f; + result += camSize * 0.5f; + + if (normalized) + return result / camSize; + else + return result; + } + + + + }//end namespace diff --git a/SHADE_Engine/src/UI/SHUISystem.h b/SHADE_Engine/src/UI/SHUISystem.h index 04e057ad..ae1091ec 100644 --- a/SHADE_Engine/src/UI/SHUISystem.h +++ b/SHADE_Engine/src/UI/SHUISystem.h @@ -3,14 +3,20 @@ #include "SH_API.h" #include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystemRoutine.h" -#include "SHUIComponent.h" -#include "SHButtonComponent.h" -#include "SHCanvasComponent.h" + #include "Scene/SHSceneGraph.h" #include "Scene/SHSceneManager.h" +#include "Math/Vector/SHVec2.h" namespace SHADE { + + class SHButtonComponent; + class SHUIComponent; + class SHToggleButtonComponent; + class SHSliderComponent; + class SHCanvasComponent; + class SH_API SHUISystem final: public SHSystem { public: @@ -64,7 +70,11 @@ namespace SHADE private: void UpdateUIComponent(SHUIComponent& comp) noexcept; void UpdateButtonComponent(SHButtonComponent& comp) noexcept; + void UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept; void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept; + + SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept; + };