Merge branch 'main' into AudioScripting

This commit is contained in:
SHAM-DP 2023-01-30 16:47:46 +08:00
commit 59ef28baf1
92 changed files with 3467 additions and 722 deletions

View File

@ -1,4 +1,4 @@
Start in Fullscreen: false Start in Fullscreen: false
Starting Scene ID: 97158628 Starting Scene ID: 87244611
Window Size: {x: 1920, y: 1080} Window Size: {x: 1920, y: 1080}
Window Title: SHADE Engine Window Title: SHADE Engine

View File

@ -1 +1,96 @@
7
Controller Look Horizontal
0 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

View File

@ -0,0 +1,4 @@
Start Maximized: true
Working Scene ID: 97161771
Window Size: {x: 1920, y: 1080}
Style: 0

View File

@ -7,6 +7,7 @@
Translate: {x: 0, y: 0.304069757, z: 1.73034382} Translate: {x: 0, y: 0.304069757, z: 1.73034382}
Rotate: {x: 0, y: 0, z: 0} Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true
Camera Component: Camera Component:
Position: {x: 0, y: 0.304069757, z: 1.73034382} Position: {x: 0, y: 0.304069757, z: 1.73034382}
Pitch: 0 Pitch: 0
@ -17,6 +18,7 @@
Near: 0.00999999978 Near: 0.00999999978
Far: 10000 Far: 10000
Perspective: true Perspective: true
IsActive: true
Scripts: ~ Scripts: ~
- EID: 1 - EID: 1
Name: Raccoon Name: Raccoon
@ -24,12 +26,14 @@
NumberOfChildren: 1 NumberOfChildren: 1
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0, y: 0, z: 0} Translate: {x: -1.86388135, y: 0.0544953719, z: 0}
Rotate: {x: 0, y: 0, z: 0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true
Renderable Component: Renderable Component:
Mesh: 149697411 Mesh: 149697411
Material: 126974645 Material: 126974645
IsActive: true
Scripts: ~ Scripts: ~
- EID: 3 - EID: 3
Name: Bag Name: Bag
@ -40,9 +44,11 @@
Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Translate: {x: 0.006237939, y: -0.000393368304, z: 0}
Rotate: {x: -0, y: 2.79945588, z: 0} Rotate: {x: -0, y: 2.79945588, z: 0}
Scale: {x: 1.0000881, y: 1, z: 1.0000881} Scale: {x: 1.0000881, y: 1, z: 1.0000881}
IsActive: true
Renderable Component: Renderable Component:
Mesh: 144838771 Mesh: 144838771
Material: 123745521 Material: 123745521
IsActive: true
Scripts: ~ Scripts: ~
- EID: 2 - EID: 2
Name: DirectionalLight Name: DirectionalLight
@ -50,12 +56,13 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Light Component: Light Component:
Position: {x: 0, y: 0, z: 0} Position: {x: 3, y: 4.5, z: 7}
Type: Directional 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} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0 Strength: 0
IsActive: true
Scripts: ~ Scripts: ~
- EID: 4 - EID: 4
Name: AmbientLight Name: AmbientLight
@ -69,4 +76,20 @@
Color: {x: 1, y: 1, z: 1, w: 1} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0.600000024 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: ~ Scripts: ~

View File

@ -1,7 +1,7 @@
- EID: 0 - EID: 0
Name: Canvas Name: Canvas
IsActive: true IsActive: true
NumberOfChildren: 1 NumberOfChildren: 2
Components: Components:
Canvas Component: Canvas Component:
Canvas Width: 10 Canvas Width: 10
@ -28,6 +28,26 @@
Clicked Texture: 0 Clicked Texture: 0
IsActive: true IsActive: true
Scripts: ~ 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 - EID: 1
Name: Camera Name: Camera
IsActive: true IsActive: true

View File

@ -1,3 +1,3 @@
Name: UI_Test Name: UI_Test
ID: 87707373 ID: 87244611
Type: 5 Type: 5

View File

@ -6,6 +6,8 @@ struct DirectionalLightStruct
uint isActive; uint isActive;
uint cullingMask; uint cullingMask;
vec4 diffuseColor; vec4 diffuseColor;
mat4 pvMatrix;
uint shadowData;
}; };
struct AmbientLightStruct 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 = 2, rgba8) uniform image2D albedo;
layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; 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 layout(set = 1, binding = 0) uniform LightCounts
{ {
@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData
AmbientLightStruct aLightData[]; AmbientLightStruct aLightData[];
} AmbLightData; } 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() void main()
{ {
// convenient variables // convenient variables
@ -52,6 +76,9 @@ void main()
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space // 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; vec3 positionView = imageLoad (positions, globalThread).rgb;
// normal of fragment // normal of fragment
@ -62,6 +89,18 @@ void main()
vec3 fragColor = vec3 (0.0f); 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) for (int i = 0; i < lightCounts.directionalLights; ++i)
{ {
if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
@ -74,16 +113,13 @@ void main()
// Calculate the fragment color // Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
}
for (int i = 0; i < lightCounts.ambientLights; ++i) // If the shadow map is enabled (test the bit)
{ if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1)
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) {
{ // calculate shadow map here
// Just do some add fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx;
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); }
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
} }
} }
@ -92,6 +128,12 @@ void main()
// store result into result image // store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); 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);
} }

View File

@ -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);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: ShadowMap_VS
ID: 44646107
Type: 2

View File

@ -16,11 +16,12 @@ layout(location = 0) in struct
vec4 vertPos; // location 0 vec4 vertPos; // location 0
vec2 uv; // location = 1 vec2 uv; // location = 1
vec4 normal; // location = 2 vec4 normal; // location = 2
vec4 worldPos; // location = 3
} In; } In;
// material stuff // material stuff
layout(location = 3) flat in struct layout(location = 4) flat in struct
{ {
int materialIndex; int materialIndex;
uint eid; uint eid;
@ -38,12 +39,14 @@ layout(location = 1) out uint outEntityID;
layout(location = 2) out uint lightLayerIndices; layout(location = 2) out uint lightLayerIndices;
layout(location = 3) out vec4 normals; layout(location = 3) out vec4 normals;
layout(location = 4) out vec4 albedo; layout(location = 4) out vec4 albedo;
layout(location = 5) out vec4 worldSpacePosition;
void main() void main()
{ {
position = In.vertPos; position = In.vertPos;
normals = In.normal; normals = In.normal;
albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color; albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color;
worldSpacePosition = In.worldPos;
outEntityID = In2.eid; outEntityID = In2.eid;
lightLayerIndices = In2.lightLayerIndex; lightLayerIndices = In2.lightLayerIndex;

Binary file not shown.

View File

@ -17,11 +17,12 @@ layout(location = 0) out struct
vec4 vertPos; // location 0 vec4 vertPos; // location 0
vec2 uv; // location = 1 vec2 uv; // location = 1
vec4 normal; // location = 2 vec4 normal; // location = 2
vec4 worldPos; // location = 3
} Out; } Out;
// material stuff // material stuff
layout(location = 3) out struct layout(location = 4) out struct
{ {
int materialIndex; int materialIndex;
uint eid; uint eid;
@ -49,6 +50,8 @@ void main()
// gBuffer position will be in view space // gBuffer position will be in view space
Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f);
Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f);
// uvs for texturing in fragment shader // uvs for texturing in fragment shader
Out.uv = aUV; Out.uv = aUV;

Binary file not shown.

View File

@ -270,8 +270,12 @@ namespace SHADE
camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset); camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset);
camera.viewMatrix(2, 3) = -view.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; camera.dirtyView = false;
} }
@ -309,7 +313,9 @@ namespace SHADE
camera.orthoProjMatrix(2, 3) = -n / (f-n); camera.orthoProjMatrix(2, 3) = -n / (f-n);
camera.orthoProjMatrix(3, 3) = 1.0f; 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.projMatrix.Transpose();
camera.dirtyProj = false; camera.dirtyProj = false;

View File

@ -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"

View File

@ -239,10 +239,7 @@ namespace SHADE
case AssetType::TEXTURE: break; case AssetType::TEXTURE: break;
case AssetType::MESH: break; case AssetType::MESH: break;
case AssetType::SCENE: case AssetType::SCENE:
if(auto editor = SHSystemManager::GetSystem<SHEditor>())
{
editor->LoadScene(asset->id); editor->LoadScene(asset->id);
}
break; break;
case AssetType::PREFAB: break; case AssetType::PREFAB: break;
case AssetType::MATERIAL: 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 //TODO: Combine Draw asset and Draw Folder recursive drawing
const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark); const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark);
const float horizontalOffset = 0.0f; const float horizontalOffset = 0.0f;

View File

@ -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();
}
}
}

View File

@ -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:
};
}

View File

@ -3,6 +3,11 @@
//#==============================================================# //#==============================================================#
#include "SHpch.h" #include "SHpch.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
//#==============================================================# //#==============================================================#
//|| SHADE Includes || //|| SHADE Includes ||
//#==============================================================# //#==============================================================#
@ -16,14 +21,11 @@
#include "Tools/SHException.h" #include "Tools/SHException.h"
#include "Editor/IconsMaterialDesign.h" #include "Editor/IconsMaterialDesign.h"
#include "SHHierarchyPanelCommands.h" #include "SHHierarchyPanelCommands.h"
#include "Common/SHAllComponents.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Tools/Utilities/SHClipboardUtilities.h" #include "Tools/Utilities/SHClipboardUtilities.h"
#include "Tools/Utilities/SHStringUtilities.h"
namespace SHADE namespace SHADE
@ -80,7 +82,6 @@ namespace SHADE
if (ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) if (ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{ {
if (auto editor = SHSystemManager::GetSystem<SHEditor>())
editor->selectedEntities.clear(); editor->selectedEntities.clear();
} }
ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal); ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal);
@ -99,7 +100,6 @@ namespace SHADE
} }
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V)) if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V))
{ {
const auto editor = SHSystemManager::GetSystem<SHEditor>();
if (editor->selectedEntities.size() == 1) if (editor->selectedEntities.size() == 1)
{ {
PasteEntities(editor->selectedEntities.back()); PasteEntities(editor->selectedEntities.back());
@ -141,16 +141,18 @@ namespace SHADE
//#==============================================================# //#==============================================================#
//|| Private Member Functions || //|| Private Member Functions ||
//#==============================================================# //#==============================================================#
void SHHierarchyPanel::DrawMenuBar() const noexcept void SHHierarchyPanel::DrawMenuBar() noexcept
{ {
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
auto size = ImGui::GetWindowSize(); auto size = ImGui::GetWindowSize();
auto g = ImGui::GetCurrentContext(); auto g = ImGui::GetCurrentContext();
DrawHierarchyPanelFilter();
ImGui::SetCursorPosX(size.x - g->Style.FramePadding.x * 15.0f); ImGui::SetCursorPosX(size.x - g->Style.FramePadding.x * 15.0f);
if (ImGui::SmallButton(ICON_MD_CLEAR_ALL)) if (ImGui::SmallButton(ICON_MD_CLEAR_ALL))
{ {
auto editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear(); editor->selectedEntities.clear();
} }
if (ImGui::IsItemHovered()) 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<SHTransformComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHTransformComponent>(eid);
}
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHColliderComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHRigidBodyComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCameraComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCameraArmComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHRenderable>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHLightComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHTextRenderableComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHUIComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHButtonComponent>().get_name().data(), filter) != std::string::npos;
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCanvasComponent>().get_name().data(), filter) != std::string::npos;
//std::vector<SHSceneNode*> const& children = entityNode->GetChildren();
//for (auto const& child : children)
//{
// result |= EntityFilterCheck(child);
//}
return result;
}
ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode) ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode)
{ {
if (currentNode == nullptr) if (currentNode == nullptr)
@ -189,21 +241,39 @@ namespace SHADE
scrollTo = MAX_EID; scrollTo = MAX_EID;
} }
auto editor = SHSystemManager::GetSystem<SHEditor>(); auto* entity = SHEntityManager::GetEntityByID(eid);
const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end()); 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(!filter.empty())
//bool highlighted = false;
//if(highlighted)
//{ //{
// 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 //Draw Node
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
if (highlighted)
{
ImGui::PopStyleColor();
}
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
//Check For Begin Drag //Check For Begin Drag
@ -336,6 +406,7 @@ namespace SHADE
drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 2); drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 2);
ImGui::TreePop(); ImGui::TreePop();
} }
return nodeRect; return nodeRect;
} }
@ -350,7 +421,6 @@ namespace SHADE
std::vector<EntityID> entitiesToParent = CleanUpEIDList(entities); std::vector<EntityID> entitiesToParent = CleanUpEIDList(entities);
//auto const editor = SHSystemManager::GetSystem<SHEditor>();
SHEntityParentCommand::EntityParentData entityParentData; SHEntityParentCommand::EntityParentData entityParentData;
std::vector<EntityID> parentedEIDS; std::vector<EntityID> parentedEIDS;
for (auto const& eid : entitiesToParent) for (auto const& eid : entitiesToParent)
@ -371,7 +441,7 @@ namespace SHADE
void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID) void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID)
{ {
bool startSelecting = false; bool endSelecting = false; bool startSelecting = false; bool endSelecting = false;
auto const editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear(); editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr) sceneGraph.Traverse([&](SHSceneNode* nodePtr)
@ -403,7 +473,6 @@ namespace SHADE
void SHHierarchyPanel::SelectAllEntities() void SHHierarchyPanel::SelectAllEntities()
{ {
const auto editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear(); editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr) sceneGraph.Traverse([&](SHSceneNode* nodePtr)
@ -415,7 +484,6 @@ namespace SHADE
void SHHierarchyPanel::CopySelectedEntities() void SHHierarchyPanel::CopySelectedEntities()
{ {
const auto editor = SHSystemManager::GetSystem<SHEditor>();
std::vector<EntityID> entitiesToCopy = CleanUpEIDList(editor->selectedEntities); std::vector<EntityID> entitiesToCopy = CleanUpEIDList(editor->selectedEntities);
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(entitiesToCopy)); SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(entitiesToCopy));
} }
@ -428,7 +496,6 @@ namespace SHADE
void SHHierarchyPanel::DeleteSelectedEntities() void SHHierarchyPanel::DeleteSelectedEntities()
{ {
const auto editor = SHSystemManager::GetSystem<SHEditor>();
std::vector<EntityID> entitiesToDelete = CleanUpEIDList(editor->selectedEntities); std::vector<EntityID> entitiesToDelete = CleanUpEIDList(editor->selectedEntities);
SHCommandManager::PerformCommand(std::make_shared<SHDeleteEntitiesCommand>(entitiesToDelete)); SHCommandManager::PerformCommand(std::make_shared<SHDeleteEntitiesCommand>(entitiesToDelete));
} }

View File

@ -10,6 +10,8 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h" #include "Editor/EditorWindow/SHEditorWindow.h"
#include "ECS_Base/Entity/SHEntity.h"
namespace SHADE namespace SHADE
{ {
class SHSceneNode; class SHSceneNode;
@ -24,7 +26,11 @@ namespace SHADE
void Exit() override; void Exit() override;
void SetScrollTo(EntityID eid); void SetScrollTo(EntityID eid);
private: private:
void DrawMenuBar() const noexcept; void DrawMenuBar() noexcept;
void DrawHierarchyPanelFilter() noexcept;
bool EntityFilterCheck(SHSceneNode* entityNode) noexcept;
ImRect RecursivelyDrawEntityNode(SHSceneNode* const); ImRect RecursivelyDrawEntityNode(SHSceneNode* const);
void CreateChildEntity(EntityID parentEID) const noexcept; void CreateChildEntity(EntityID parentEID) const noexcept;
void ParentSelectedEntities(EntityID parentEID, std::vector<EntityID> const& entities) noexcept; void ParentSelectedEntities(EntityID parentEID, std::vector<EntityID> const& entities) noexcept;

View File

@ -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<std::string> 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<int>(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<SHInputManager::SH_BINDINGTYPE>(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<float>(SHInputManager::GetBindingDead(binding.first));
if (ImGui::SliderFloat(labelConcat("Deadzone##", entryNumber).c_str(), &bindingDead, 0.0f, 1.0f))
SHInputManager::SetBindingDead(binding.first, static_cast<double>(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<double>(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<int>(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<int>(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<int>(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<int>(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();
}
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "Editor/EditorWindow/SHEditorWindow.h"
#include <imgui.h>
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;
};
}

View File

@ -77,7 +77,7 @@ namespace SHADE
ImGui::PushID(SHFamilyID<SHComponent>::GetID<T>()); ImGui::PushID(SHFamilyID<SHComponent>::GetID<T>());
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
{ {
DrawContextMenu(component); DrawContextMenu(component);
auto const& properties = componentType.get_properties(); auto const& properties = componentType.get_properties();
@ -234,7 +234,7 @@ namespace SHADE
const auto componentType = rttr::type::get<SHRigidBodyComponent>(); const auto componentType = rttr::type::get<SHRigidBodyComponent>();
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
{ {
DrawContextMenu(component); DrawContextMenu(component);
@ -328,7 +328,7 @@ namespace SHADE
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
{ {
DrawContextMenu(component); DrawContextMenu(component);
@ -446,7 +446,7 @@ namespace SHADE
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
{ {
DrawContextMenu(component); DrawContextMenu(component);
@ -478,7 +478,7 @@ namespace SHADE
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
{ {
DrawContextMenu(component); DrawContextMenu(component);
Handle<SHMesh> const& mesh = component->GetMesh(); Handle<SHMesh> const& mesh = component->GetMesh();
@ -536,7 +536,7 @@ namespace SHADE
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
{ {
DrawContextMenu(component); DrawContextMenu(component);
Handle<SHFont> const& font = component->GetFont(); Handle<SHFont> const& font = component->GetFont();

View File

@ -21,6 +21,7 @@
#include "UI/SHUIComponent.h" #include "UI/SHUIComponent.h"
#include "UI/SHCanvasComponent.h" #include "UI/SHCanvasComponent.h"
#include "UI/SHButtonComponent.h" #include "UI/SHButtonComponent.h"
#include "UI/SHToggleButtonComponent.h"
#include "SHEditorComponentView.h" #include "SHEditorComponentView.h"
#include "AudioSystem/SHAudioListenerComponent.h" #include "AudioSystem/SHAudioListenerComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
@ -93,7 +94,6 @@ namespace SHADE
SHEditorWindow::Update(); SHEditorWindow::Update();
if (Begin()) if (Begin())
{ {
auto editor = SHSystemManager::GetSystem<SHEditor>();
if (editor && !editor->selectedEntities.empty()) if (editor && !editor->selectedEntities.empty())
{ {
EntityID const& eid = editor->selectedEntities[0]; EntityID const& eid = editor->selectedEntities[0];
@ -154,6 +154,10 @@ namespace SHADE
{ {
DrawComponent(buttonComponent); DrawComponent(buttonComponent);
} }
if (auto toggleButton = SHComponentManager::GetComponent_s<SHToggleButtonComponent>(eid))
{
DrawComponent(toggleButton);
}
ImGui::Separator(); ImGui::Separator();
// Render Scripts // Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
@ -167,6 +171,7 @@ namespace SHADE
DrawAddComponentButton<SHLightComponent>(eid); DrawAddComponentButton<SHLightComponent>(eid);
DrawAddComponentButton<SHCanvasComponent>(eid); DrawAddComponentButton<SHCanvasComponent>(eid);
DrawAddComponentButton<SHButtonComponent>(eid); DrawAddComponentButton<SHButtonComponent>(eid);
DrawAddComponentButton<SHToggleButtonComponent>(eid);
// Components that require Transforms // Components that require Transforms

View File

@ -110,7 +110,7 @@ namespace SHADE
{ {
ImGui::BeginMenuBar(); ImGui::BeginMenuBar();
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.5f - 80.f); ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.5f - 80.f);
const auto editor = SHSystemManager::GetSystem<SHEditor>();
ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY); ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY);
if(ImGui::SmallButton(ICON_MD_PLAY_ARROW)) if(ImGui::SmallButton(ICON_MD_PLAY_ARROW))
{ {
@ -165,16 +165,18 @@ namespace SHADE
{ {
if (ImGui::Selectable("New Scene")) if (ImGui::Selectable("New Scene"))
{ {
SHSystemManager::GetSystem<SHEditor>()->NewScene(); editor->NewScene();
} }
if (ImGui::Selectable("Save")) if (ImGui::Selectable("Save"))
{ {
SHSystemManager::GetSystem<SHEditor>()->SaveScene(); editor->SaveScene();
} }
ImGui::BeginDisabled(true);
if (ImGui::Selectable("Load")) if (ImGui::Selectable("Load"))
{ {
//SHSystemManager::GetSystem<SHEditor>()->LoadScene() //SHSystemManager::GetSystem<SHEditor>()->LoadScene()
} }
ImGui::EndDisabled();
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
@ -211,7 +213,7 @@ namespace SHADE
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->OpenSolution(); scriptEngine->OpenSolution();
} }
ImGui::BeginDisabled(SHSystemManager::GetSystem<SHEditor>()->editorState != SHEditor::State::STOP); ImGui::BeginDisabled(editor->editorState != SHEditor::State::STOP);
if (ImGui::Selectable("Build Scripts - Debug")) if (ImGui::Selectable("Build Scripts - Debug"))
{ {
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
@ -252,7 +254,6 @@ namespace SHADE
{ {
if (ImGui::Selectable(style.to_string().c_str())) if (ImGui::Selectable(style.to_string().c_str()))
{ {
if (auto editor = SHSystemManager::GetSystem<SHEditor>())
editor->SetStyle(style.convert<SHEditor::Style>()); editor->SetStyle(style.convert<SHEditor::Style>());
} }
} }

View File

@ -7,6 +7,8 @@
//|| SHADE Includes || //|| SHADE Includes ||
//#==============================================================# //#==============================================================#
#include "SHEditorWindow.h" #include "SHEditorWindow.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
//#==============================================================# //#==============================================================#
//|| Library Includes || //|| Library Includes ||
@ -21,6 +23,7 @@ namespace SHADE
SHEditorWindow::SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags) SHEditorWindow::SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags)
:isOpen(true), isWindowHovered(false), windowName(name), windowFlags(inFlags), io(ImGui::GetIO()) :isOpen(true), isWindowHovered(false), windowName(name), windowFlags(inFlags), io(ImGui::GetIO())
{ {
editor = SHSystemManager::GetSystem<SHEditor>();
} }
void SHEditorWindow::Init() void SHEditorWindow::Init()

View File

@ -12,9 +12,9 @@
//#==============================================================# //#==============================================================#
struct ImGuiIO; struct ImGuiIO;
typedef int ImGuiWindowFlags; typedef int ImGuiWindowFlags;
namespace SHADE namespace SHADE
{ {
class SHEditor;
class SHEditorWindow class SHEditorWindow
{ {
public: public:
@ -38,6 +38,6 @@ namespace SHADE
ImGuiWindowFlags windowFlags = 0; ImGuiWindowFlags windowFlags = 0;
ImGuiIO& io; ImGuiIO& io;
SHEditor* editor;
};//class SHEditorWindow };//class SHEditorWindow
}//namespace SHADE }//namespace SHADE

View File

@ -7,3 +7,4 @@
#include "AssetBrowser/SHAssetBrowser.h" //Asset Browser #include "AssetBrowser/SHAssetBrowser.h" //Asset Browser
#include "MaterialInspector/SHMaterialInspector.h" //Material Inspector #include "MaterialInspector/SHMaterialInspector.h" //Material Inspector
#include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel #include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel
#include "InputBindings/SHInputBindingsPanel.h" //Input Bindings

View File

@ -4,5 +4,7 @@
namespace SHADE namespace SHADE
{ {
SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{}; SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{};
SHEditorWindowManager::PopupWindowMap SHEditorWindowManager::popupWindows{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{}; SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::popupWindowCount{};
} }

View File

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include "SHEditorWindow.h" #include "SHEditorWindow.h"
#include "SHPopUpWindow.h"
#include "Tools/Logger/SHLog.h" #include "Tools/Logger/SHLog.h"
namespace SHADE namespace SHADE
@ -16,6 +17,10 @@ namespace SHADE
using EditorWindowID = uint8_t; using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>; using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>; using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
using PopupWindowPtr = std::unique_ptr<SHPopUpWindow>;
using PopupWindowMap = std::unordered_map<EditorWindowID, PopupWindowPtr>;
/** /**
* @brief Get ID for the Editor Window Type * @brief Get ID for the Editor Window Type
* *
@ -67,10 +72,63 @@ namespace SHADE
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get()); return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
} }
/**
* @brief Get ID for the Popup Window Type
*
* @tparam T Type of Popup Window
* @return EditorWindowID ID of Popup Window Type
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHPopUpWindow, T>, 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 <typename T, std::enable_if_t<std::is_base_of_v<SHPopUpWindow, T>, bool> = true>
static void CreatePopupWindow()
{
static bool isCreated = false;
if (!isCreated)
{
popupWindows[GetPopupWindowID<T>()] = std::make_unique<T>();
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 <typename T, std::enable_if_t<std::is_base_of_v<SHPopUpWindow, T>, bool> = true>
static T* GetPopupWindow()
{
return reinterpret_cast<T*>(popupWindows[GetPopupWindowID<T>()].get());
}
static EditorWindowMap editorWindows; static EditorWindowMap editorWindows;
static PopupWindowMap popupWindows;
private: private:
// Number of windows; used for Editor Window ID Generation // Number of windows; used for Editor Window ID Generation
static EditorWindowID windowCount; static EditorWindowID windowCount;
static EditorWindowID popupWindowCount;
// Map of Editor Windows // Map of Editor Windows
friend class SHEditor; friend class SHEditor;
}; };

View File

@ -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<SHEditor>();
}
bool SHPopUpWindow::Begin()
{
if (isOpen)
ImGui::OpenPopup(windowName.data(), popupFlags);
return isModal ? ImGui::BeginPopupModal(windowName.data(), &isOpen, windowFlags) : ImGui::BeginPopup(windowName.data(), windowFlags);
}
}

View File

@ -0,0 +1,31 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <string>
#include <imgui.h>
#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;
};
}

View File

@ -35,7 +35,6 @@ namespace SHADE
{ {
SHEditorWindow::Update(); SHEditorWindow::Update();
auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>();
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (!editor->selectedEntities.empty()) if (!editor->selectedEntities.empty())
{ {

View File

@ -32,6 +32,9 @@
#include "EditorWindow/SHEditorWindowManager.h" #include "EditorWindow/SHEditorWindowManager.h"
#include "EditorWindow/SHEditorWindowIncludes.h" #include "EditorWindow/SHEditorWindowIncludes.h"
#include "EditorWindow/SHPopUpWindow.h"
#include "EditorWindow/EditorPopups/SHEditorPopups.h"
//#==============================================================# //#==============================================================#
//|| Library Includes || //|| Library Includes ||
//#==============================================================# //#==============================================================#
@ -98,15 +101,19 @@ namespace SHADE
//Add editor windows //Add editor windows
SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>(); SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>(); SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>(); SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
SHEditorWindowManager::CreateEditorWindow<SHMaterialInspector>(); SHEditorWindowManager::CreateEditorWindow<SHMaterialInspector>();
SHEditorWindowManager::CreateEditorWindow<SHColliderTagPanel>(); SHEditorWindowManager::CreateEditorWindow<SHColliderTagPanel>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHInputBindingsPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>(); SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
//Add popup windows
SHEditorWindowManager::CreatePopupWindow<SHSceneSavePrompt>();
io = &ImGui::GetIO(); io = &ImGui::GetIO();
io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
@ -150,7 +157,7 @@ namespace SHADE
{ {
(void)dt; (void)dt;
NewFrame(); NewFrame();
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) for (auto const& window : SHEditorWindowManager::editorWindows | std::views::values)
{ {
if(window->isOpen) if(window->isOpen)
{ {
@ -158,7 +165,11 @@ namespace SHADE
} }
} }
RenderSceneNamePrompt(); for(auto const& popupWindow : SHEditorWindowManager::popupWindows | std::views::values)
{
popupWindow->Draw();
}
RenderUnsavedChangesPrompt(); RenderUnsavedChangesPrompt();
//PollPicking(); //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 void SHEditor::RenderUnsavedChangesPrompt() noexcept
{ {
if(isUnsavedChangesPromptOpen) if(isUnsavedChangesPromptOpen)
@ -220,12 +200,12 @@ namespace SHADE
ImGui::Text("You have unsaved changes!"); ImGui::Text("You have unsaved changes!");
if(ImGui::Button("Save")) if(ImGui::Button("Save"))
{ {
isSceneNamePromptOpen = true; SHEditorWindowManager::GetPopupWindow<SHSceneSavePrompt>()->isOpen = true;
} }
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Cancel")) if(ImGui::Button("Cancel"))
{ {
isUnsavedChangesPromptOpen = false; SHEditorWindowManager::GetPopupWindow<SHSceneSavePrompt>()->isOpen = true;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
} }
@ -489,7 +469,7 @@ namespace SHADE
//auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph(); 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) if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false)
{ {
@ -508,7 +488,7 @@ namespace SHADE
ImGui_ImplVulkan_DestroyFontUploadObjects(); ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer> cmd, Handle<SHRenderer> renderer, uint32_t frameIndex) renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer> cmd, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
cmd->BeginLabeledSegment("ImGui Draw"); cmd->BeginLabeledSegment("ImGui Draw");
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());
@ -563,7 +543,7 @@ namespace SHADE
if (newSceneName.empty()) if (newSceneName.empty())
{ {
//Prompt for scene name //Prompt for scene name
isSceneNamePromptOpen = true; SHEditorWindowManager::GetPopupWindow<SHSceneSavePrompt>()->isOpen = true;
return false; return false;
} }
//Else We have a new name //Else We have a new name
@ -644,7 +624,7 @@ namespace SHADE
editorState = SHEditor::State::STOP; editorState = SHEditor::State::STOP;
SHCommandManager::SwapStacks(); SHCommandManager::SwapStacks();
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT); SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT);
LoadScene(SHSceneManager::GetCurrentSceneAssetID()); LoadScene(editorConfig->workingSceneID);
} }
void SHEditor::ProcessShortcuts() void SHEditor::ProcessShortcuts()

View File

@ -37,8 +37,6 @@ namespace SHADE
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkCommandPool; class SHVkCommandPool;
/** /**
* @brief SHEditor static class contains editor variables and implementation of editor functions. * @brief SHEditor static class contains editor variables and implementation of editor functions.
* *
@ -144,8 +142,6 @@ namespace SHADE
*/ */
void Render(); void Render();
void RenderSceneNamePrompt() noexcept;
void RenderUnsavedChangesPrompt() noexcept; void RenderUnsavedChangesPrompt() noexcept;
void InitLayout() noexcept; void InitLayout() noexcept;
@ -156,8 +152,6 @@ namespace SHADE
SHEventHandle onEditorStateChanged(SHEventPtr eventPtr); SHEventHandle onEditorStateChanged(SHEventPtr eventPtr);
bool isSceneNamePromptOpen = false;
bool isUnsavedChangesPromptOpen = false; bool isUnsavedChangesPromptOpen = false;
static constexpr std::string_view sceneNamePromptName = "Save scene as..."; static constexpr std::string_view sceneNamePromptName = "Save scene as...";

View File

@ -13,6 +13,8 @@
#include "Command/SHCommandManager.h" #include "Command/SHCommandManager.h"
#include "SHImGuiHelpers.hpp" #include "SHImGuiHelpers.hpp"
#include "SH_API.h" #include "SH_API.h"
#include "Assets/SHAssetMacros.h"
#include "ECS_Base/SHECSMacros.h"
//#==============================================================# //#==============================================================#
//|| Library Includes || //|| Library Includes ||
@ -454,7 +456,33 @@ namespace SHADE
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushID(label.data()); ImGui::PushID(label.data());
TextLabel(label); 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<T, uint32_t>) //EID or Resource
{
if (SHDragDrop::BeginTarget())
{
if(AssetID * payload = SHDragDrop::AcceptPayload<T>(SHDragDrop::DRAG_RESOURCE))
{
value = *payload;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
hasChange = true;
SHDragDrop::EndTarget();
}
else if (std::vector<EntityID>* payload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(SHDragDrop::DRAG_EID))
{
value = payload->back();
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
hasChange = true;
SHDragDrop::EndTarget();
}
if(hasChange)
{
ImGui::PopID();
ImGui::EndGroup();
return true;
}
}
}
static bool startRecording = false; static bool startRecording = false;
if (hasChange) if (hasChange)
{ {

View File

@ -23,4 +23,5 @@ constexpr SHEventIdentifier SH_SCENE_INIT_POST { 14 };
constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 }; constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 };
constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 };
constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 }; constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 };
constexpr SHEventIdentifier SH_BUTTON_CLICK_EVENT { 18 };

View File

@ -175,6 +175,27 @@ namespace SHADE
writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr;
writeInfo.descImageInfos[i].imageLayout = layout; 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<Handle<SHVkSampler>>(imageViewsAndSamplers.back())->GetVkSampler();
}
}
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept
{
// Find the target writeDescSet
BindingAndSetHash writeHash = binding;
writeHash |= static_cast<uint64_t>(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<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept void SHVkDescriptorSetGroup::ModifyWriteDescBuffer(uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> 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 void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept
{ {
vk::WriteDescriptorSet writeDescSet{}; vk::WriteDescriptorSet writeDescSet{};

View File

@ -63,10 +63,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Public member functions */ /* 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 UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(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<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept;
void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;

View File

@ -183,33 +183,43 @@ namespace SHADE
/*if (!extensionsSupported) /*if (!extensionsSupported)
SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/ 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 // point and lines fill mode
features.fillModeNonSolid = VK_TRUE; features.features.fillModeNonSolid = VK_TRUE;
features.samplerAnisotropy = VK_TRUE; features.features.samplerAnisotropy = VK_TRUE;
features.multiDrawIndirect = VK_TRUE; features.features.multiDrawIndirect = VK_TRUE;
features.independentBlend = VK_TRUE; features.features.independentBlend = VK_TRUE;
features.features.wideLines = VK_TRUE;
// for wide lines features.pNext = &robustFeatures;
features.wideLines = true;
vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{};
descIndexingFeature.descriptorBindingVariableDescriptorCount = true;
descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true;
descIndexingFeature.runtimeDescriptorArray = true;
// Prepare to create the device // Prepare to create the device
vk::DeviceCreateInfo deviceCreateInfo vk::DeviceCreateInfo deviceCreateInfo
{ {
.pNext = &descIndexingFeature, .pNext = &features,
.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()), .queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()),
.pQueueCreateInfos = queueCreateInfos.data(), .pQueueCreateInfos = queueCreateInfos.data(),
.enabledLayerCount = 0, // deprecated and ignored .enabledLayerCount = 0, // deprecated and ignored
.ppEnabledLayerNames = nullptr, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored
.enabledExtensionCount = !extensionsSupported ? 0 : static_cast<uint32_t>(requiredExtensions.size()), .enabledExtensionCount = !extensionsSupported ? 0 : static_cast<uint32_t>(requiredExtensions.size()),
.ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(), .ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(),
.pEnabledFeatures = &features //.pEnabledFeatures = &features
}; };
// Actually create the device // Actually create the device

View File

@ -10,5 +10,8 @@ namespace SHADE
{ {
//! We need to get the light component and initialize the relevant variables. //! We need to get the light component and initialize the relevant variables.
EntityID lightEntity; EntityID lightEntity;
//! Generate a renderer for the light component
bool generateRenderer;
}; };
} }

View File

@ -33,6 +33,7 @@ namespace SHADE
.maxAnisotropy = 1.0f, .maxAnisotropy = 1.0f,
.minLod = params.minLod, .minLod = params.minLod,
.maxLod = params.maxLod, .maxLod = params.maxLod,
.borderColor = vk::BorderColor::eFloatOpaqueWhite
}; };
// Create the sampler // Create the sampler

View File

@ -551,7 +551,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
@ -566,7 +566,10 @@ namespace SHADE
// Bind all required objects before drawing // Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset{ 0 }; static std::array<uint32_t, 1> dynamicOffset{ 0 };
cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); 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::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex]) if (matPropsDescSet[frameIndex])

View File

@ -87,7 +87,7 @@ namespace SHADE
void UpdateTransformBuffer(uint32_t frameIndex); void UpdateTransformBuffer(uint32_t frameIndex);
void UpdateInstancedIntegerBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ; void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex); void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */

View File

@ -107,12 +107,12 @@ namespace SHADE
} }
} }
void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline /*= true*/) noexcept
{ {
// Build all batches // Build all batches
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.Draw(cmdBuffer, frameIndex); batch.Draw(cmdBuffer, frameIndex, bindBatchPipeline);
} }
} }

View File

@ -57,7 +57,7 @@ namespace SHADE
void Clear() noexcept; void Clear() noexcept;
void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */

View File

@ -13,6 +13,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsPredefinedData::predefinedLayouts; std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsPredefinedData::predefinedLayouts;
SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState; SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState;
SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState;
std::vector<SHGraphicsPredefinedData::PerSystem> SHGraphicsPredefinedData::perSystemData; std::vector<SHGraphicsPredefinedData::PerSystem> SHGraphicsPredefinedData::perSystemData;
//SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData; //SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData;
@ -150,12 +152,26 @@ namespace SHADE
Handle<SHVkDescriptorSetLayout> fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding }); Handle<SHVkDescriptorSetLayout> fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data"); 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<SHVkDescriptorSetLayout> 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(staticGlobalLayout);
predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(lightDataDescSetLayout);
predefinedLayouts.push_back(cameraDataGlobalLayout); predefinedLayouts.push_back(cameraDataGlobalLayout);
predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout);
predefinedLayouts.push_back(fontDataDescSetLayout); predefinedLayouts.push_back(fontDataDescSetLayout);
predefinedLayouts.push_back(shadowMapDescLayout);
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts 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_3D) }); // positions at binding 0
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 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(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::MAT_4D) }); // Transform at binding 4 - 7 (4 slots)
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 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<SHVkLogicalDevice> logicalDevice) noexcept void SHGraphicsPredefinedData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{ {
perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES)); perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES));
InitDescSetLayouts(logicalDevice); InitDescSetLayouts(logicalDevice);
InitDefaultVertexInputState(); InitPredefinedVertexInputState();
InitDescMappings(); InitDescMappings();
InitDummyPipelineLayouts (logicalDevice); InitDummyPipelineLayouts (logicalDevice);
} }
@ -217,6 +236,11 @@ namespace SHADE
} }
SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept
{
return shadowMapVertexInputState;
}
SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept
{ {
return perSystemData[static_cast<uint32_t>(systemType)]; return perSystemData[static_cast<uint32_t>(systemType)];

View File

@ -28,6 +28,7 @@ namespace SHADE
CAMERA = 0x04, CAMERA = 0x04,
MATERIALS = 0x08, MATERIALS = 0x08,
FONT = 0x10, FONT = 0x10,
SHADOW = 0x20,
}; };
enum class SystemType enum class SystemType
@ -57,6 +58,9 @@ namespace SHADE
//! Default vertex input state (used by everything). //! Default vertex input state (used by everything).
static SHVertexInputState defaultVertexInputState; static SHVertexInputState defaultVertexInputState;
//! vertex input state for shadow mapping
static SHVertexInputState shadowMapVertexInputState;
//! Predefined data for each type of system //! Predefined data for each type of system
static std::vector<PerSystem> perSystemData; static std::vector<PerSystem> perSystemData;
@ -72,7 +76,7 @@ namespace SHADE
static void InitDescMappings (void) noexcept; static void InitDescMappings (void) noexcept;
static void InitDummyPipelineLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept; static void InitDummyPipelineLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept; static void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void InitDefaultVertexInputState (void) noexcept; static void InitPredefinedVertexInputState (void) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -90,6 +94,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static std::vector<Handle<SHVkDescriptorSetLayout>> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept; static std::vector<Handle<SHVkDescriptorSetLayout>> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept;
static SHVertexInputState const& GetDefaultViState (void) noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept;
static SHVertexInputState const& GetShadowMapViState (void) noexcept;
static PerSystem const& GetSystemData (SystemType systemType) noexcept; static PerSystem const& GetSystemData (SystemType systemType) noexcept;
static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept; static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept;
//static PerSystem const& GetBatchingSystemData(void) noexcept; //static PerSystem const& GetBatchingSystemData(void) noexcept;

View File

@ -13,7 +13,7 @@ namespace SHADE
CAMERA, CAMERA,
MATERIALS, MATERIALS,
FONT, FONT,
RENDER_GRAPH_RESOURCE,
RENDER_GRAPH_NODE_COMPUTE_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE,
RENDER_GRAPH_RESOURCE,
}; };
} }

View File

@ -101,9 +101,13 @@ namespace SHADE
// Register function for subpass // Register function for subpass
//auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph(); 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<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) subPass->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
// Set line width first
cmdBuffer->SetLineWidth(LineWidth);
// Draw
const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex();
cmdBuffer->BeginLabeledSegment("SHDebugDraw (No Depth Test)"); cmdBuffer->BeginLabeledSegment("SHDebugDraw (No Depth Test)");
{ {
@ -125,9 +129,13 @@ namespace SHADE
} }
cmdBuffer->EndLabeledSegment(); 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<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) subPassWithDepth->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
// Set line width first
cmdBuffer->SetLineWidth(LineWidth);
// Draw
const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex();
cmdBuffer->BeginLabeledSegment("SHDebugDraw (Depth Tested)"); cmdBuffer->BeginLabeledSegment("SHDebugDraw (Depth Tested)");
{ {
@ -506,7 +514,6 @@ namespace SHADE
if (batch.NumPoints[frameIndex] > 0) if (batch.NumPoints[frameIndex] > 0)
{ {
cmdBuffer->BindPipeline(batch.Pipeline); cmdBuffer->BindPipeline(batch.Pipeline);
cmdBuffer->SetLineWidth(LineWidth);
cmdBuffer->BindVertexBuffer(0, batch.VertexBuffers[frameIndex], 0); cmdBuffer->BindVertexBuffer(0, batch.VertexBuffers[frameIndex], 0);
cmdBuffer->DrawArrays(batch.NumPoints[frameIndex], 1, 0, 0); cmdBuffer->DrawArrays(batch.NumPoints[frameIndex], 1, 0, 0);
} }

View File

@ -31,68 +31,91 @@ namespace SHADE
static constexpr uint32_t EDITOR = 0; static constexpr uint32_t EDITOR = 0;
}; };
//struct DescriptorSetIndex struct RenderGraphEntityNames
//{ {
// /***************************************************************************/ /***************************************************************************/
// /*! /*!
// \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;
// /***************************************************************************/ \brief
// /*! Name of G-Buffer render graph node.
// \brief
// To store font data. */
// /***************************************************************************/
// */ static constexpr std::string_view GBUFFER_PASS = "G-Buffer";
// /***************************************************************************/
// 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 struct DescriptorSetBindings
{ {
@ -158,6 +181,16 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t FONT_MATRIX_DATA = 1; 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 struct VertexBufferBindings

View File

@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Events/SHEvent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Input/SHInputManager.h"
namespace SHADE namespace SHADE
{ {
@ -124,6 +127,13 @@ namespace SHADE
SHFreetypeInstance::Init(); 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 // Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT); static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEFAULT);
@ -137,6 +147,8 @@ namespace SHADE
static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_FS); static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_FS);
static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_VS); static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_VS);
static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_FS); static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(RENDER_SC_FS);
static constexpr AssetID SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_MAP_VS);
} }
void SHGraphicsSystem::InitRenderGraph(void) noexcept void SHGraphicsSystem::InitRenderGraph(void) noexcept
@ -169,6 +181,8 @@ namespace SHADE
// Create Default Viewport // Create Default Viewport
worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(window->GetWindowSize().first), static_cast<float>(window->GetWindowSize().second), 0.0f, 1.0f)); worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(window->GetWindowSize().first), static_cast<float>(window->GetWindowSize().second), 0.0f, 1.0f));
shadowMapViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(SHLightingSubSystem::SHADOW_MAP_WIDTH), static_cast<float>(SHLightingSubSystem::SHADOW_MAP_HEIGHT), 0.0f, 1.0f));
std::vector<Handle<SHVkCommandPool>> renderContextCmdPools{ swapchain->GetNumImages() }; std::vector<Handle<SHVkCommandPool>> renderContextCmdPools{ swapchain->GetNumImages() };
for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i)
{ {
@ -183,22 +197,24 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Initialize world render graph // Initialize world render graph
renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); 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("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("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 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); //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("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 }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); 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 }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); 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 }, 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 }, windowDims.first, windowDims.second); 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 }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); 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 }, 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 }, windowDims.first, windowDims.second); renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* MAIN NODE */ /* 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", "Position",
"Entity ID", "Entity ID",
@ -207,7 +223,8 @@ namespace SHADE
"Albedo", "Albedo",
"Depth Buffer", "Depth Buffer",
"SSAO", "SSAO",
"SSAO Blur" "SSAO Blur",
"Position World Space"
}, },
{}); // no predecessors {}); // no predecessors
@ -220,6 +237,7 @@ namespace SHADE
gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Normals");
gBufferSubpass->AddColorOutput("Albedo"); gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddColorOutput("Position World Space");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL);
@ -254,53 +272,52 @@ namespace SHADE
// Add another pass to blur SSAO // Add another pass to blur SSAO
Handle<SHRenderGraphNodeCompute> ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); Handle<SHRenderGraphNodeCompute> 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 */ /* DEFERRED COMPOSITE NODE */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// This pass will facilitate both lighting and shadows in 1 single pass. // 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", "Position",
"Light Layer Indices", "Light Layer Indices",
"Normals", "Normals",
"Albedo", "Albedo",
"Scene", "Scene",
"SSAO Blur" "SSAO Blur",
"Position World Space"
}, },
{"G-Buffer"}); { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */ /* 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<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer);
});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEBUG DRAW PASS INIT */ /* DEBUG DRAW PASS INIT */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Set up Debug Draw Passes // Set up Debug Draw Passes
// - Depth Tested // - 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); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer);
debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddColorOutput("Scene");
debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer");
// - No Depth Test // - 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); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer);
debugDrawSubpass->AddColorOutput("Scene"); debugDrawSubpass->AddColorOutput("Scene");
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SCREEN SPACE PASS */ /* 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); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer);
uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Scene");
uiSubpass->AddColorOutput("Entity ID"); uiSubpass->AddColorOutput("Entity ID");
@ -315,16 +332,16 @@ namespace SHADE
#ifdef SHEDITOR #ifdef SHEDITOR
{ {
// Dummy Node to transition scene render graph resource // 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", {}, {}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {});
dummySubpass->AddInput("Scene"); 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", {}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {});
imGuiSubpass->AddColorOutput("Present"); imGuiSubpass->AddColorOutput("Present");
} }
#else #else
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS});
#endif #endif
@ -393,12 +410,16 @@ namespace SHADE
postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool);
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>(); lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool); lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams
{
.addressMode = vk::SamplerAddressMode::eClampToBorder,
})
);
textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>(); textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>();
// initialize the text renderer // 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); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS);
SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem);
@ -426,7 +447,7 @@ namespace SHADE
defaultMaterial = AddMaterial defaultMaterial = AddMaterial
( (
defaultVertShader, defaultFragShader, 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); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
} }
@ -451,6 +472,7 @@ namespace SHADE
InitMiddleEnd(); InitMiddleEnd();
InitSubsystems(); InitSubsystems();
InitBuiltInResources(); InitBuiltInResources();
InitEvents();
} }
void SHGraphicsSystem::Exit(void) void SHGraphicsSystem::Exit(void)
@ -546,6 +568,15 @@ namespace SHADE
#endif #endif
} }
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B))
{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
for (auto& comp : lightComps)
{
comp.SetEnableShadow(true);
}
}
renderGraph->Begin(frameIndex); renderGraph->Begin(frameIndex);
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
@ -726,16 +757,61 @@ namespace SHADE
renderers.erase(iter); 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<const SHEventSpec<SHLightEnableShadowEvent>*>(eventPtr.get())->data;
auto* lightComp = SHComponentManager::GetComponent<SHLightComponent>(EVENT_DATA->lightEntity);
std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity);
Handle<SHSubpass> 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<SHRenderer> newRenderer = resourceManager.Create<SHRenderer>(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 // 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. // 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 // 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);
//renderGraph->GetNode (); // regenerate the node
return event->handle; shadowMapNode->RuntimeStandaloneRegenerate();
// Create pipeline from new renderpass and subpass if it's not created yet
if (!shadowMapPipeline)
{
SHPipelineLibrary tempLibrary{};
Handle<SHRenderGraphNode> 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
// 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<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass) Handle<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass)
@ -1047,6 +1123,7 @@ namespace SHADE
mousePickSubSystem->HandleResize(); mousePickSubSystem->HandleResize();
postOffscreenRenderSubSystem->HandleResize(); postOffscreenRenderSubSystem->HandleResize();
//lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()));
worldViewport->SetWidth(static_cast<float>(resizeWidth)); worldViewport->SetWidth(static_cast<float>(resizeWidth));
worldViewport->SetHeight(static_cast<float>(resizeHeight)); worldViewport->SetHeight(static_cast<float>(resizeHeight));
@ -1079,7 +1156,7 @@ namespace SHADE
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{ {
return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data());
} }
Handle<SHVkPipeline> SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept Handle<SHVkPipeline> SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept

View File

@ -178,7 +178,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Light functions */ /* Light functions */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Material Functions */ /* Material Functions */
@ -406,10 +406,6 @@ namespace SHADE
SHWindow* GetWindow() noexcept { return window; } SHWindow* GetWindow() noexcept { return window; }
private: private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
@ -446,6 +442,7 @@ namespace SHADE
#endif #endif
Handle<SHViewport> worldViewport; // Whole screen Handle<SHViewport> worldViewport; // Whole screen
Handle<SHViewport> shadowMapViewport;
std::vector<Handle<SHViewport>> viewports; // Additional viewports std::vector<Handle<SHViewport>> viewports; // Additional viewports
// Renderers // Renderers
@ -469,6 +466,7 @@ namespace SHADE
Handle<SHVkShaderModule> textFS; Handle<SHVkShaderModule> textFS;
Handle<SHVkShaderModule> renderToSwapchainVS; Handle<SHVkShaderModule> renderToSwapchainVS;
Handle<SHVkShaderModule> renderToSwapchainFS; Handle<SHVkShaderModule> renderToSwapchainFS;
Handle<SHVkShaderModule> shadowMapVS;
// Fonts // Fonts
Handle<SHFont> testFont; Handle<SHFont> testFont;
@ -483,6 +481,7 @@ namespace SHADE
Handle<SHVkPipeline> debugDrawWireMeshDepthPipeline; Handle<SHVkPipeline> debugDrawWireMeshDepthPipeline;
Handle<SHVkPipeline> debugDrawFilledPipeline; Handle<SHVkPipeline> debugDrawFilledPipeline;
Handle<SHVkPipeline> debugDrawFilledDepthPipeline; Handle<SHVkPipeline> debugDrawFilledDepthPipeline;
Handle<SHVkPipeline> shadowMapPipeline; // initialized only when a shadow map is needed
// Built-In Textures // Built-In Textures
Handle<SHTexture> defaultTexture; Handle<SHTexture> defaultTexture;

View File

@ -122,4 +122,9 @@ namespace SHADE
return cameraDirector; return cameraDirector;
} }
SHShaderCameraData SHRenderer::GetCPUCameraData(void) const noexcept
{
return cpuCameraData;
}
} }

View File

@ -18,9 +18,9 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "SHCamera.h" #include "SHCamera.h"
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Math/SHMath.h" #include "Math/SHMath.h"
#include <vector> #include <vector>
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE namespace SHADE
{ {
@ -93,6 +93,7 @@ namespace SHADE
/* Setters and Getters */ /* Setters and Getters */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHCameraDirector> GetCameraDirector (void) const noexcept; Handle<SHCameraDirector> GetCameraDirector (void) const noexcept;
SHShaderCameraData GetCPUCameraData (void) const noexcept;
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -2,6 +2,7 @@
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "Graphics/Events/SHGraphicsEvents.h" #include "Graphics/Events/SHGraphicsEvents.h"
#include "Events/SHEventManager.hpp" #include "Events/SHEventManager.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
namespace SHADE namespace SHADE
{ {
@ -14,6 +15,7 @@ namespace SHADE
//indexInBuffer = std::numeric_limits<uint32_t>::max(); //indexInBuffer = std::numeric_limits<uint32_t>::max();
isActive = true; isActive = true;
//Unbind(); //Unbind();
renderer = {};
} }
@ -116,11 +118,22 @@ namespace SHADE
// Create new event and broadcast it // Create new event and broadcast it
SHLightEnableShadowEvent newEvent; SHLightEnableShadowEvent newEvent;
newEvent.lightEntity = GetEID(); newEvent.lightEntity = GetEID();
newEvent.generateRenderer = static_cast<bool>(!renderer);
SHEventManager::BroadcastEvent<SHLightEnableShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); SHEventManager::BroadcastEvent<SHLightEnableShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT);
} }
} }
void SHLightComponent::SetRenderer(Handle<SHRenderer> newRenderer) noexcept
{
renderer = newRenderer;
}
void SHLightComponent::SetShadowMapIndex(uint32_t index) noexcept
{
lightData.shadowMapIndex = index;
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept SHLightData const& SHLightComponent::GetLightData(void) const noexcept
{ {
return lightData; return lightData;
@ -172,6 +185,11 @@ namespace SHADE
return lightData.strength; return lightData.strength;
} }
Handle<SHRenderer> SHLightComponent::GetRenderer(void) const noexcept
{
return renderer;
}
} }
RTTR_REGISTRATION RTTR_REGISTRATION

View File

@ -3,9 +3,11 @@
#include <rttr/registration> #include <rttr/registration>
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.h" #include "SHLightData.h"
#include "Resource/SHHandle.h"
namespace SHADE namespace SHADE
{ {
class SHRenderer;
class SH_API SHLightComponent final : public SHComponent class SH_API SHLightComponent final : public SHComponent
{ {
@ -14,6 +16,9 @@ namespace SHADE
//! GPU depends on the type of the light. //! GPU depends on the type of the light.
SHLightData lightData; SHLightData lightData;
//! Renderer to calculate light world to projection matrix
Handle<SHRenderer> renderer;
//! Since the lighting system is gonna be self contained and light weight, we store this //! 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 //! 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. //! 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 SetBound (uint32_t inIndexInBuffer) noexcept;
void SetStrength (float value) noexcept; // serialized void SetStrength (float value) noexcept; // serialized
void SetEnableShadow (bool flag) noexcept; void SetEnableShadow (bool flag) noexcept;
void SetRenderer (Handle<SHRenderer> newRenderer) noexcept;
void SetShadowMapIndex (uint32_t index) noexcept;
SHLightData const& GetLightData (void) const noexcept; SHLightData const& GetLightData (void) const noexcept;
@ -61,6 +68,7 @@ namespace SHADE
//bool GetBound (void) const noexcept; //bool GetBound (void) const noexcept;
//uint32_t GetIndexInBuffer (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept; float GetStrength (void) const noexcept;
Handle<SHRenderer> GetRenderer (void) const noexcept;
RTTR_ENABLE() RTTR_ENABLE()
}; };
} }

View File

@ -10,6 +10,13 @@
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "Math/Vector/SHVec4.h" #include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.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 namespace SHADE
{ {
@ -50,6 +57,19 @@ namespace SHADE
//lightPtr->direction = lightData.direction; //lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.color; lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive; 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; break;
} }
case SH_LIGHT_TYPE::POINT: 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<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, SHResourceHub* rh, Handle<SHVkSampler> inShadowMapSampler) noexcept
{ {
SHComponentManager::CreateComponentSparseSet<SHLightComponent>(); SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device; logicalDevice = device;
resourceHub = rh;
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
#pragma region LIGHTING
std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES }; std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
std::fill (variableSizes.begin(), variableSizes.end(), 1); std::fill (variableSizes.begin(), variableSizes.end(), 1);
@ -418,7 +466,22 @@ namespace SHADE
dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
} }
#pragma endregion
#pragma region SHADOWS
//std::vector<uint32_t> 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<int>(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; //numLightComponents = 0;
#pragma endregion
} }
/***************************************************************************/ /***************************************************************************/
@ -452,6 +515,12 @@ namespace SHADE
for (auto& light : lightComps) 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); auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it // 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. // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets(); ComputeDynamicOffsets();
} }
/***************************************************************************/ /***************************************************************************/
@ -526,9 +594,101 @@ namespace SHADE
} }
uint32_t SHLightingSubSystem::AddShadowMap(Handle<SHRenderGraphResource> newShadowMap, EntityID lightEntity) noexcept
{
// Add to container of shadow maps
shadowMapIndexing.emplace(lightEntity, static_cast<uint32_t> (shadowMaps.size()));
shadowMaps.emplace_back(newShadowMap);
// Just use the image view stored in the resource
Handle<SHVkImageView> 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<uint32_t>(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<uint32_t>(shadowMapImageSamplers.size()) - 1u;
}
void SHLightingSubSystem::PrepareShadowMapsForRead(Handle<SHVkCommandBuffer> 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<SHRenderGraphNodeCompute> compute) noexcept
//{
// uint32_t const NUM_SHADOW_MAPS = static_cast<uint32_t>(shadowMaps.size());
// for (uint32_t i = 0; i < NUM_SHADOW_MAPS; ++i)
// {
// // Just use the image view stored in the resource
// Handle<SHVkImageView> const NEW_IMAGE_VIEW = shadowMaps[i]->GetImageView();
// // set new image view
// std::get<Handle<SHVkImageView>>(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<SHVkDescriptorSetGroup> SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept Handle<SHVkDescriptorSetGroup> SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept
{ {
return lightingDataDescSet; return lightingDataDescSet;
} }
std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept
{
return shadowMapImageSamplers[index];
}
uint32_t SHLightingSubSystem::GetNumShadowMaps(void) const noexcept
{
return static_cast<uint32_t>(shadowMaps.size());
}
} }

View File

@ -3,9 +3,13 @@
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h" #include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
#include "SHLightData.h" #include "SHLightData.h"
#include <array> #include <array>
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/RenderGraph/SHRenderGraphResource.h"
#include "ECS_Base/SHECSMacros.h"
namespace SHADE namespace SHADE
{ {
@ -16,6 +20,10 @@ namespace SHADE
class SHVkBuffer; class SHVkBuffer;
class SHLightComponent; class SHLightComponent;
class SHVkCommandBuffer; 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. // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData struct SHDirectionalLightData
@ -34,6 +42,12 @@ namespace SHADE
//! Diffuse color emitted by the light //! Diffuse color emitted by the light
alignas (16) SHVec4 diffuseColor; 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. // 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 //! 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. //! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask; uint32_t cullingMask;
}; };
class SH_API SHLightingSubSystem class SH_API SHLightingSubSystem
{ {
public: public:
using DynamicOffsetArray = std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; using DynamicOffsetArray = std::array<std::vector<uint32_t>, static_cast<uint32_t>(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: private:
class PerTypeData class PerTypeData
{ {
public:
private: private:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */ /* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static constexpr uint32_t STARTING_NUM_LIGHTS = 50; static constexpr uint32_t STARTING_NUM_LIGHTS = 50;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -123,51 +140,90 @@ namespace SHADE
}; };
private: private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! logical device used for creation //! logical device used for creation
Handle<SHVkLogicalDevice> logicalDevice; Handle<SHVkLogicalDevice> logicalDevice;
//! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required. //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required.
Handle<SHVkDescriptorSetGroup> lightingDataDescSet; Handle<SHVkDescriptorSetGroup> lightingDataDescSet;
//! Each type will have some data associated with it for processing //! Each type will have some data associated with it for processing
std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData;
//! Container to store dynamic offsets for binding descriptor sets //! Container to store dynamic offsets for binding descriptor sets
DynamicOffsetArray dynamicOffsets; DynamicOffsetArray dynamicOffsets;
//! holds the data that represents how many lights are in the scene //! holds the data that represents how many lights are in the scene
std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData;
//! GPU buffer to hold lightCountData //! GPU buffer to hold lightCountData
Handle<SHVkBuffer> lightCountsBuffer; Handle<SHVkBuffer> lightCountsBuffer;
//! For padding in the buffer //! For padding in the buffer
uint32_t lightCountsAlignedSize; uint32_t lightCountsAlignedSize;
//! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense //! 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, //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more,
//! don't do anything. //! don't do anything.
//uint32_t numLightComponents; //uint32_t numLightComponents;
//! Handle to sampler that all shadow map descriptors will use
Handle<SHVkSampler> shadowMapSampler;
//! For indexing shadow maps
std::unordered_map<EntityID, uint32_t> shadowMapIndexing;
//! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it
std::vector<Handle<SHRenderGraphResource>> 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<SHVkDescriptorSetGroup> shadowMapDescriptorSet;
//! Combined image samplers for the texture descriptors
std::vector<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, 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<vk::ImageMemoryBarrier> shadowMapMemoryBarriers;
//! Resource hub from Graphics System
SHResourceHub* resourceHub;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept; void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept; void ComputeDynamicOffsets (void) noexcept;
void ResetNumLights (void) noexcept; void ResetNumLights (void) noexcept;
void UpdateShadowMapDesc (void) noexcept;
SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept; void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, SHResourceHub* rh, Handle<SHVkSampler> inShadowMapSampler) noexcept;
void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept;
void Exit (void) noexcept; void Exit (void) noexcept;
void BindDescSet (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept;
uint32_t AddShadowMap (Handle<SHRenderGraphResource> newShadowMap, EntityID lightEntity) noexcept;
void PrepareShadowMapsForRead (Handle<SHVkCommandBuffer> cmdBuffer) noexcept;
//void HandleResize (Handle<SHRenderGraphNodeCompute> compute) noexcept;
//void RemoveShadowMap (uint32_t index) noexcept;
void BindDescSet (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHVkDescriptorSetGroup> GetLightDataDescriptorSet (void) const noexcept; Handle<SHVkDescriptorSetGroup> GetLightDataDescriptorSet (void) const noexcept;
std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept;
uint32_t GetNumShadowMaps (void) const noexcept;
}; };
} }

View File

@ -1,18 +1,23 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHPipelineLibrary.h" #include "SHPipelineLibrary.h"
#include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h"
#include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/RenderGraph/SHSubpass.h"
#include "Graphics/SHVkUtil.h" #include "Graphics/SHVkUtil.h"
namespace SHADE namespace SHADE
{ {
Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept
{ {
std::vector<Handle<SHVkShaderModule>> modules{};
if (vsFsPair.first)
modules.push_back(vsFsPair.first);
if (vsFsPair.second)
modules.push_back(vsFsPair.second);
SHPipelineLayoutParams params SHPipelineLayoutParams params
{ {
.shaderModules = {vsFsPair.first, vsFsPair.second}, .shaderModules = std::move(modules),
.predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts
}; };
@ -21,7 +26,7 @@ namespace SHADE
// Create the pipeline and configure the default vertex input state // Create the pipeline and configure the default vertex input state
auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass);
newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState()); newPipeline->GetPipelineState().SetVertexInputState(viState);
SHColorBlendState colorBlendState{}; SHColorBlendState colorBlendState{};
colorBlendState.logic_op_enable = VK_FALSE; colorBlendState.logic_op_enable = VK_FALSE;
@ -30,6 +35,7 @@ namespace SHADE
auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); auto const& subpassColorReferences = subpass->GetColorAttachmentReferences();
colorBlendState.attachments.reserve(subpassColorReferences.size()); colorBlendState.attachments.reserve(subpassColorReferences.size());
for (auto& att : subpassColorReferences) for (auto& att : subpassColorReferences)
{ {
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
@ -48,6 +54,8 @@ namespace SHADE
newPipeline->GetPipelineState().SetColorBlenState(colorBlendState); newPipeline->GetPipelineState().SetColorBlenState(colorBlendState);
newPipeline->GetPipelineState().SetRasterizationState(rasterState);
// Actually construct the pipeline // Actually construct the pipeline
newPipeline->ConstructPipeline(); newPipeline->ConstructPipeline();

View File

@ -3,6 +3,7 @@
#include <unordered_map> #include <unordered_map>
#include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h"
namespace SHADE namespace SHADE
{ {
@ -32,7 +33,9 @@ namespace SHADE
Handle<SHVkPipeline> CreateGraphicsPipelines ( Handle<SHVkPipeline> CreateGraphicsPipelines (
std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair,
Handle<SHVkRenderpass> renderpass, Handle<SHVkRenderpass> renderpass,
Handle<SHSubpass> subpass Handle<SHSubpass> subpass,
SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(),
SHRasterizationState const& rasterState = SHRasterizationState{}
) noexcept; ) noexcept;
Handle<SHVkPipeline> GetGraphicsPipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept; Handle<SHVkPipeline> GetGraphicsPipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
bool CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;

View File

@ -195,7 +195,7 @@ namespace SHADE
return *this; return *this;
} }
void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs) noexcept void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs, uint32_t fixedBinding /*= static_cast<uint32_t>(-1)*/, uint32_t fixedAttributeLocation/* = static_cast<uint32_t>(-1)*/) noexcept
{ {
// add a binding and get ref to it // add a binding and get ref to it
bindings.emplace_back(); bindings.emplace_back();
@ -210,7 +210,7 @@ namespace SHADE
// Offset is 0 at first (for first element) // Offset is 0 at first (for first element)
uint32_t offset = 0; uint32_t offset = 0;
binding.binding = static_cast<uint32_t>(bindings.size() - 1); binding.binding = (fixedBinding != static_cast<uint32_t>(-1)) ? fixedBinding : static_cast<uint32_t>(bindings.size() - 1);
// for every attribute passed in // for every attribute passed in
for (auto const& attrib : inAttribs) for (auto const& attrib : inAttribs)
@ -226,10 +226,11 @@ namespace SHADE
auto& vertexAttrib = attributes.back(); auto& vertexAttrib = attributes.back();
// The binding for that attribute description is index of the new binding created earlier in this function // The binding for that attribute description is index of the new binding created earlier in this function
vertexAttrib.binding = static_cast<uint32_t>(bindings.size() - 1); vertexAttrib.binding = (fixedBinding != static_cast<uint32_t>(-1)) ? fixedBinding : static_cast<uint32_t>(bindings.size() - 1);
// Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously
vertexAttrib.location = static_cast<uint32_t>(attributes.size () - 1); vertexAttrib.location = (fixedAttributeLocation != static_cast<uint32_t>(-1)) ? fixedAttributeLocation + i : static_cast<uint32_t>(attributes.size () - 1);
//vertexAttrib.location = static_cast<uint32_t>(attributes.size() - 1);
// Get the vkFormat associated with the SHAttribFormat // Get the vkFormat associated with the SHAttribFormat
vertexAttrib.format = format; vertexAttrib.format = format;

View File

@ -34,7 +34,7 @@ namespace SHADE
SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept;
SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept;
void AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs) noexcept; void AddBinding(bool instanced, bool calcOffset, std::initializer_list<SHVertexAttribute> inAttribs, uint32_t fixedBinding = static_cast<uint32_t>(-1), uint32_t fixedAttributeLocation = static_cast<uint32_t>(-1)) noexcept;
friend class SHVkPipelineState; friend class SHVkPipelineState;
friend class SHVkPipeline; friend class SHVkPipeline;

View File

@ -19,69 +19,71 @@ namespace SHADE
for (auto& shaderModule : shaderModules) for (auto& shaderModule : shaderModules)
{ {
// References for convenience if (shaderModule)
auto const& reflectedData = shaderModule->GetReflectedData();
auto const& pcInfo = reflectedData.GetPushConstantInfo();
// If a push constant block exists for the shader module
if (pcInfo.memberCount != 0)
{ {
bool exists = false; // References for convenience
auto const& reflectedData = shaderModule->GetReflectedData();
auto const& pcInfo = reflectedData.GetPushConstantInfo();
// Check if push constant block already exists // If a push constant block exists for the shader module
for (uint32_t i = 0; i < pcInfos.size(); ++i) if (pcInfo.memberCount != 0)
{ {
// If there is a block with the same name, member count and size bool exists = false;
if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size)
// 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 // If there is a block with the same name, member count and size
vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); 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 // Set flag and stop checking
exists = true; exists = true;
break; 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);
} }
// New push constant range // If the block doesn't exist yet
vk::PushConstantRange newRange; 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 // Add the variable's offset info to the interface
newRange.offset = startOffset; pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset);
newRange.size = pcInfo.size; }
// Stage flags will be whatever shader stage of the shader that contains the push constant block // New push constant range
newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); vk::PushConstantRange newRange;
// Add to the list foe checking later // set offset and size
pcInfos.push_back(&pcInfo); newRange.offset = startOffset;
newRange.size = pcInfo.size;
// For pipeline layout to consume // Stage flags will be whatever shader stage of the shader that contains the push constant block
vkPcRanges.push_back(newRange); newRange.stageFlags = shaderModule->GetShaderStageFlagBits();
// Next push constant block will start next to the previous push constant block // Add to the list foe checking later
startOffset += pcInfo.size; 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 // 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 //! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set
for (auto& shaderModule : shaderModules) for (auto& shaderModule : shaderModules)
{ {
if (!shaderModule)
continue;
auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo(); auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo();
auto const& reflectedSets = descBindingInfo.GetReflectedSets(); auto const& reflectedSets = descBindingInfo.GetReflectedSets();
@ -200,10 +205,12 @@ namespace SHADE
newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND; newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND;
// Set the flags for variable bindings // Set the flags for variable bindings
newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound;
} }
else else
{
SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. "); 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); setsWithBindings[CURRENT_SET].emplace_back(newBinding);
@ -326,11 +333,10 @@ namespace SHADE
{ {
for (auto& mod : shaderModules) for (auto& mod : shaderModules)
{ {
mod->AddCallback([this]() if (mod)
{ {
RecreateIfNeeded(); mod->AddCallback([this]() { RecreateIfNeeded(); });
} }
);
} }
RecreateIfNeeded (); RecreateIfNeeded ();

View File

@ -54,7 +54,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-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<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, bool resizeWithWindow, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/)
{ {
// If we set to // If we set to
if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1)) if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
@ -64,7 +64,7 @@ namespace SHADE
format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format;
} }
auto resource = renderGraphStorage->resourceHub->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); auto resource = renderGraphStorage->resourceHub->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags, resizeWithWindow);
renderGraphStorage->graphResources->try_emplace(resourceName, resource); renderGraphStorage->graphResources->try_emplace(resourceName, resource);
} }
@ -106,6 +106,9 @@ namespace SHADE
for (auto& affectedNode : affectedNodes) for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->CreateFramebuffer(); nodes[affectedNode]->CreateFramebuffer();
renderGraphStorage->graphResources->at(resourceName).Free();
renderGraphStorage->graphResources->erase (resourceName);
/* /*
* IMPORTANT NOTES * IMPORTANT NOTES
* *
@ -166,68 +169,7 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes) for (uint32_t i = 0; auto& node : nodes)
{ {
// key is handle ID, value is final layout. node->StandaloneConfigureAttDesc(i == nodes.size() - 1);
std::unordered_map<uint32_t, vk::ImageLayout> 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<uint32_t>(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);
}
++i; ++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; 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<SHRenderGraphNode> SHRenderGraph::AddNodeAfter(std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::string nodeToAddAfter) noexcept
{
if (nodeIndexing.contains(nodeName))
{
SHLOG_ERROR("Node already exists, cannot add node. ");
return {};
}
std::vector<SHAttachmentDescInitParams> 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<SHRenderGraphNode>(nodeName, renderGraphStorage, std::move(descInitParams), std::vector<Handle<SHRenderGraphNode>>()));
ReindexNodes ();
return *node;
}
void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list<std::string> predecessorNodes, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> shaderModules) noexcept void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list<std::string> predecessorNodes, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> shaderModules) noexcept
{ {
for (auto& node : predecessorNodes) for (auto& node : predecessorNodes)
@ -532,10 +544,6 @@ namespace SHADE
ConfigureSubSystems(); ConfigureSubSystems();
} }
void SHRenderGraph::Regenerate(void) noexcept
{
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -572,10 +580,13 @@ namespace SHADE
for (auto& node : nodes) for (auto& node : nodes)
{ {
// bind static global data if (node->renderpass)
SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); {
// 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(); cmdBuffer->EndLabeledSegment();
@ -605,8 +616,11 @@ namespace SHADE
// resize resources // resize resources
for (auto& [name, resource] : *renderGraphStorage->graphResources) for (auto& [name, resource] : *renderGraphStorage->graphResources)
{ {
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) if (resource->resizeWithWindow)
resource->HandleResize(newWidth, newHeight); {
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw))
resource->HandleResize(newWidth, newHeight);
}
} }
for (auto& node : nodes) for (auto& node : nodes)

View File

@ -55,6 +55,7 @@ namespace SHADE
void ConfigureRenderpasses (void) noexcept; void ConfigureRenderpasses (void) noexcept;
void ConfigureSubSystems (void) noexcept; void ConfigureSubSystems (void) noexcept;
void ConfigureFramebuffers (void) noexcept; void ConfigureFramebuffers (void) noexcept;
void ReindexNodes (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -101,6 +102,7 @@ namespace SHADE
( (
std::string resourceName, std::string resourceName,
std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags,
bool resizeWithWindow = true,
uint32_t w = static_cast<uint32_t>(-1), uint32_t w = static_cast<uint32_t>(-1),
uint32_t h = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1),
vk::Format format = vk::Format::eB8G8R8A8Unorm, vk::Format format = vk::Format::eB8G8R8A8Unorm,
@ -123,6 +125,12 @@ namespace SHADE
std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<ResourceInstruction> resourceInstruction,
std::initializer_list<std::string> predecessorNodes std::initializer_list<std::string> predecessorNodes
) noexcept; ) noexcept;
Handle<SHRenderGraphNode> AddNodeAfter
(
std::string nodeName,
std::initializer_list<ResourceInstruction> resourceInstruction,
std::string nodeToAddAfter
) noexcept;
void AddRenderToSwapchainNode void AddRenderToSwapchainNode
( (
@ -134,7 +142,6 @@ namespace SHADE
) noexcept; ) noexcept;
void Generate (void) noexcept; void Generate (void) noexcept;
void Regenerate (void) noexcept;
void CheckForNodeComputes (void) noexcept; void CheckForNodeComputes (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept; void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void Begin (uint32_t frameIndex) 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, * 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. * 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. * - 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.
* *
*/ */

View File

@ -32,8 +32,11 @@ namespace SHADE
renderpass.Free(); renderpass.Free();
} }
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); if (!spDescs.empty())
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); {
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 void SHRenderGraphNode::CreateFramebuffer(void) noexcept
{ {
if (!framebuffers.empty()) if (renderpass)
{ {
for (auto fbo : framebuffers) if (!framebuffers.empty())
{ {
if (fbo) for (auto fbo : framebuffers)
fbo.Free(); {
} if (fbo)
} fbo.Free();
}
for (uint32_t i = 0; i < framebuffers.size(); ++i)
{
std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
for (uint32_t j = 0; j < attResources.size(); ++j)
{
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(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 (uint32_t i = 0; i < framebuffers.size(); ++i)
{
std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); for (uint32_t j = 0; j < attResources.size(); ++j)
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); {
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(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 void SHRenderGraphNode::HandleResize(void) noexcept
{ {
renderpass->HandleResize(); if (renderpass)
for (uint32_t i = 0; i < framebuffers.size(); ++i)
{ {
std::vector<Handle<SHVkImageView>> imageViews(attResources.size()); renderpass->HandleResize();
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
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<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
imageViews[j] = attResources[j]->imageViews[imageViewIndex]; uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::max();
// We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's for (uint32_t j = 0; j < attResources.size(); ++j)
if (fbWidth > attResources[j]->width) {
fbWidth = attResources[j]->width; uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0;
if (fbHeight > attResources[j]->height) imageViews[j] = attResources[j]->imageViews[imageViewIndex];
fbHeight = attResources[j]->height;
// 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) for (auto& nodeCompute : nodeComputes)
{ {
subpass->HandleResize(); nodeCompute->HandleResize();
} }
for (auto& nodeCompute : nodeComputes)
{
nodeCompute->HandleResize();
} }
} }
void SHRenderGraphNode::ConfigureSubpasses(void) noexcept void SHRenderGraphNode::ConfigureSubpasses(void) noexcept
{ {
if (subpasses.empty())
return;
uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle<SHSubpass> subpass) {return !subpass->HasNoAttachments();});
// Create subpass description and dependencies based on number of subpasses // Create subpass description and dependencies based on number of subpasses
spDescs.resize(subpasses.size()); spDescs.resize(numValidSubpasses);
spDeps.resize(subpasses.size()); spDeps.resize(numValidSubpasses);
// Now we want to loop through all attachments in all subpasses in the node and query // 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 // the resources being used. For each resource we want to query the type and record it
// in bit fields (1 bit for each subpass). // in bit fields (1 bit for each subpass).
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0; 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 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 // Configure subpass description
auto& desc = spDescs[i]; auto& desc = spDescs[i];
desc.pColorAttachments = subpass->colorReferences.data(); 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 // Loop through all subpasses again but this time we use the bit field to initialize
// the dependencies. // 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 srcStage;
vk::PipelineStageFlags dstStage; vk::PipelineStageFlags dstStage;
vk::AccessFlags srcAccess; vk::AccessFlags srcAccess;
@ -245,6 +265,8 @@ namespace SHADE
// initialize input descriptors // initialize input descriptors
subpasses[i]->CreateInputDescriptors(); subpasses[i]->CreateInputDescriptors();
++i;
} }
} }
@ -343,6 +365,7 @@ namespace SHADE
, spDeps{ std::move(rhs.spDeps) } , spDeps{ std::move(rhs.spDeps) }
, nodeComputes{ std::move(rhs.nodeComputes) } , nodeComputes{ std::move(rhs.nodeComputes) }
, name { std::move(rhs.name) } , name { std::move(rhs.name) }
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
{ {
rhs.renderpass = {}; rhs.renderpass = {};
@ -419,7 +442,7 @@ namespace SHADE
return subpass; return subpass;
} }
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept
{ {
// Look for the required resources in the graph // Look for the required resources in the graph
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{}; std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
@ -435,7 +458,7 @@ namespace SHADE
std::vector<Handle<SHRenderGraphResource>> temp (nodeComputeResources); std::vector<Handle<SHRenderGraphResource>> temp (nodeComputeResources);
// Create the subpass compute with the resources // Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceHub->Create<SHRenderGraphNodeCompute>(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); auto nodeCompute = graphStorage->resourceHub->Create<SHRenderGraphNodeCompute>(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount);
nodeComputes.push_back(nodeCompute); nodeComputes.push_back(nodeCompute);
for (auto& resource : temp) 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<uint32_t, vk::ImageLayout> 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<uint32_t>(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 // remove attachment reference
attachmentDescriptions.erase (attachmentDescriptions.begin() + index); attachmentDescriptions.erase (attachmentDescriptions.begin() + index);
// erase from mapping as well
resourceAttachmentMapping->erase(resourceHandleID);
// Remove footprint of attachment from all subpasses as well // Remove footprint of attachment from all subpasses as well
for (auto it = subpasses.begin(); it != subpasses.end(); ++it) for (auto it = subpasses.begin(); it != subpasses.end(); ++it)
{ {
// attempt to detach resource from subpass // If the subpass uses the resource, just remove the subpass since the subpass will be invalid
(*it)->DetachResource(resourceName, index); if ((*it)->UsesResource(index))
// If the subpass ends up having no attachments after, erase it from the node
if ((*it)->HasNoAttachments())
{ {
// erase from indexing // erase from indexing
subpassIndexing.erase((*it)->GetName()); subpassIndexing.erase((*it)->GetName());
@ -530,6 +615,24 @@ namespace SHADE
for (uint32_t i = 0; i < subpasses.size(); ++i) for (uint32_t i = 0; i < subpasses.size(); ++i)
subpasses[i]->SetIndex(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 true;
} }
return false; return false;
@ -537,37 +640,40 @@ namespace SHADE
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{ {
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; if (renderpass)
commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
for (uint32_t i = 0; i < subpasses.size(); ++i)
{ {
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 for (uint32_t i = 0; i < subpasses.size(); ++i)
if (i != static_cast<uint32_t>(subpasses.size()) - 1u) {
commandBuffer->NextSubpass(); subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
// Go to next subpass if not last subpass
if (i != static_cast<uint32_t>(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<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept Handle<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept
@ -599,6 +705,77 @@ namespace SHADE
batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); 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<SHRenderGraphResource> 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<SHSubpass> SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> 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; return attResources;
} }
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept
{
for (auto nc : nodeComputes)
{
if (nc->name == nodeComputeName)
return nc;
}
return {};
}
} }

View File

@ -93,6 +93,9 @@ namespace SHADE
void CreateFramebuffer(void) noexcept; void CreateFramebuffer(void) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void ConfigureSubpasses (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: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -105,15 +108,17 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept; Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) noexcept;
bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept;
// TODO: RemoveSubpass() void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept; void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
// Runtime functions that don't affect the renderpass
void RuntimeLinkResource(std::string resourceName) noexcept;
Handle<SHSubpass> RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
void RuntimeStandaloneRegenerate (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
@ -122,6 +127,7 @@ namespace SHADE
Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept; Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept;
Handle<SHRenderGraphResource> GetResource (uint32_t resourceIndex) const noexcept; Handle<SHRenderGraphResource> GetResource (uint32_t resourceIndex) const noexcept;
std::vector<Handle<SHRenderGraphResource>> const& GetResources (void) const noexcept; std::vector<Handle<SHRenderGraphResource>> const& GetResources (void) const noexcept;
Handle<SHRenderGraphNodeCompute> GetNodeCompute (std::string nodeComputeName) const noexcept;
friend class SHRenderGraph; friend class SHRenderGraph;
}; };

View File

@ -14,7 +14,56 @@
namespace SHADE namespace SHADE
{ {
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& 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<uint32_t>(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<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{} : computePipeline{}
, pipelineLayout{} , pipelineLayout{}
, resources{} , resources{}
@ -68,10 +117,12 @@ namespace SHADE
// check if all layouts are there // check if all layouts are there
if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1)
{ {
Handle<SHVkDescriptorSetLayout> computeResourceLayout = {};
computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
// create compute resources // create compute resources
computeResource = graphStorage->resourceHub->Create<ComputeResource>(); computeResource = graphStorage->resourceHub->Create<ComputeResource>();
auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount});
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 });
#ifdef _DEBUG #ifdef _DEBUG
for (auto set : computeResource->descSet->GetVkHandle()) for (auto set : computeResource->descSet->GetVkHandle())
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources");
@ -91,6 +142,11 @@ namespace SHADE
void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{ {
for (auto& fn : preComputeFunctions)
{
fn (cmdBuffer, frameIndex);
}
// bind the compute pipeline // bind the compute pipeline
cmdBuffer->BindPipeline(computePipeline); cmdBuffer->BindPipeline(computePipeline);
@ -157,35 +213,7 @@ namespace SHADE
groupSizeX = maxWidth / workGroupSizeX; groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY; groupSizeY = maxHeight / workGroupSizeY;
for (uint32_t i = 0; auto& barriers : memoryBarriers) InitializeBarriers();
{
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<uint32_t>(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::SetDynamicOffsets(std::span<uint32_t> perFrameSizes) noexcept void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span<uint32_t> 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);
}
} }

View File

@ -25,6 +25,10 @@ namespace SHADE
class SHRenderGraphNodeCompute class SHRenderGraphNodeCompute
{ {
public:
using PreComputeFunction = std::function<void(Handle<SHVkCommandBuffer>, uint32_t)>;
private: private:
// Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE // Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE
struct ComputeResource struct ComputeResource
@ -73,8 +77,23 @@ namespace SHADE
//! Name of this node //! Name of this node
std::string name; std::string name;
std::vector<PreComputeFunction> 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: public:
SHRenderGraphNodeCompute(std::string nodeName, Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; SHRenderGraphNodeCompute(std::string nodeName, Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
@ -84,7 +103,9 @@ namespace SHADE
void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;
void ModifyWriteDescImageComputeResource(uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> const& viewSamplerLayouts) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> 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 SHRenderGraph;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;

View File

@ -78,7 +78,7 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept
: graphStorage{renderGraphStorage} : graphStorage{renderGraphStorage}
, resourceTypeFlags{ } , resourceTypeFlags{ }
, resourceFormat{ format } , resourceFormat{ format }
@ -88,6 +88,7 @@ namespace SHADE
, height{ h } , height{ h }
, mipLevels{ levels } , mipLevels{ levels }
, resourceName{ name } , resourceName{ name }
, resizeWithWindow { inResizeWithWindow }
{ {
// If the resource type is an arbitrary image and not swapchain image // 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) if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)
@ -210,6 +211,7 @@ namespace SHADE
, imageAspectFlags{ rhs.imageAspectFlags } , imageAspectFlags{ rhs.imageAspectFlags }
, graphStorage{rhs.graphStorage} , graphStorage{rhs.graphStorage}
, infoTracker {std::move (rhs.infoTracker)} , infoTracker {std::move (rhs.infoTracker)}
, resizeWithWindow{rhs.resizeWithWindow}
{ {
} }
@ -242,7 +244,8 @@ namespace SHADE
mipLevels = rhs.mipLevels; mipLevels = rhs.mipLevels;
imageAspectFlags = rhs.imageAspectFlags; imageAspectFlags = rhs.imageAspectFlags;
graphStorage = rhs.graphStorage; graphStorage = rhs.graphStorage;
infoTracker = std::move(infoTracker); infoTracker = std::move(rhs.infoTracker);
resizeWithWindow = rhs.resizeWithWindow;
return *this; return *this;
} }

View File

@ -96,11 +96,14 @@ namespace SHADE
//! For tracking resource states in stages of the render graphs //! For tracking resource states in stages of the render graphs
Handle<InfoTracker> infoTracker; Handle<InfoTracker> infoTracker;
//! Whether or not to resize (recreate vulkan image) when window resizes
bool resizeWithWindow;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> 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(SHRenderGraphResource&& rhs) noexcept;
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept; ~SHRenderGraphResource(void) noexcept;

View File

@ -77,6 +77,7 @@ namespace SHADE
, name { rhs.name } , name { rhs.name }
, viewport {rhs.viewport} , viewport {rhs.viewport}
, renderer {rhs.renderer} , renderer {rhs.renderer}
, companionSubpass {rhs.companionSubpass}
{ {
} }
@ -113,6 +114,7 @@ namespace SHADE
name = std::move(rhs.name); name = std::move(rhs.name);
renderer = rhs.renderer; renderer = rhs.renderer;
viewport = rhs.viewport; viewport = rhs.viewport;
companionSubpass = rhs.companionSubpass;
return *this; return *this;
@ -162,7 +164,7 @@ namespace SHADE
switch (attachmentDescriptionType) switch (attachmentDescriptionType)
{ {
case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH:
imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
break; break;
case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL:
imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; imageLayout = vk::ImageLayout::eStencilAttachmentOptimal;
@ -211,25 +213,38 @@ namespace SHADE
{ {
commandBuffer->BeginLabeledSegment(name); commandBuffer->BeginLabeledSegment(name);
// Ensure correct transforms are provided if (!HasNoAttachments())
superBatch->UpdateBuffers(frameIndex, descPool);
if (viewport)
{ {
// set viewport and scissor // Ensure correct transforms are provided
uint32_t w = static_cast<uint32_t>(viewport->GetWidth()); superBatch->UpdateBuffers(frameIndex, descPool);
uint32_t h = static_cast<uint32_t>(viewport->GetHeight());
commandBuffer->SetViewportScissor(static_cast<float>(w), static_cast<float>(h), w, h); if (viewport)
{
// set viewport and scissor
uint32_t w = static_cast<uint32_t>(viewport->GetWidth());
uint32_t h = static_cast<uint32_t>(viewport->GetHeight());
commandBuffer->SetViewportScissor(static_cast<float>(w), static_cast<float>(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 // Draw all the exterior draw calls
for (auto& drawCall : exteriorDrawCalls) 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) for (uint32_t i = 0; i < colorReferences.size(); ++i)
{ {
if (colorReferences[i].attachment == attachmentIndex) if (colorReferences[i].attachment == attachmentIndex)
{ return true;
colorReferences.erase (colorReferences.begin() + i);
break;
}
} }
for (uint32_t i = 0; i < depthReferences.size(); ++i) for (uint32_t i = 0; i < depthReferences.size(); ++i)
{ {
if (depthReferences[i].attachment == attachmentIndex) if (depthReferences[i].attachment == attachmentIndex)
{ return true;
depthReferences.erase(depthReferences.begin() + i);
break;
}
} }
for (uint32_t i = 0; i < inputReferences.size(); ++i) for (uint32_t i = 0; i < inputReferences.size(); ++i)
{ {
if (inputReferences[i].attachment == attachmentIndex) if (inputReferences[i].attachment == attachmentIndex)
{ return true;
inputReferences.erase(inputReferences.begin() + i);
break;
}
} }
for (uint32_t i = 0; i < inputNames.size(); ++i) return false;
{
if (inputNames[i] == resourceName)
{
inputNames.erase(inputNames.begin() + i);
break;
}
}
} }
bool SHSubpass::HasNoAttachments(void) const noexcept bool SHSubpass::HasNoAttachments(void) const noexcept
@ -458,6 +457,12 @@ namespace SHADE
subpassIndex = index; subpassIndex = index;
} }
void SHSubpass::SetCompanionSubpass(Handle<SHSubpass> companion, Handle<SHVkPipeline> pipeline) noexcept
{
companionSubpass.companion = companion;
companionSubpass.pipeline = pipeline;
}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -21,12 +21,23 @@ namespace SHADE
class SHVkSampler; class SHVkSampler;
class SHRenderer; class SHRenderer;
class SHViewport; class SHViewport;
class SHVkPipeline;
class SH_API SHSubpass : public ISelfHandle<SHSubpass> class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{ {
public: public:
using ExteriorDrawCallFunction = std::function<void(Handle<SHVkCommandBuffer>, Handle<SHRenderer>, uint32_t)>; using ExteriorDrawCallFunction = std::function<void(Handle<SHVkCommandBuffer>, Handle<SHRenderer>, uint32_t)>;
// Allows for subpasses to run using a companions data
struct CompanionSubpass
{
// subpass whose data will be borrowed to draw
Handle<SHSubpass> companion;
// Pipeline that will be used for all the draw calls from all batches of the companion subpass
Handle<SHVkPipeline> pipeline;
};
private: private:
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -94,6 +105,15 @@ namespace SHADE
// For identifying subpasses // For identifying subpasses
std::string name; 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: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -119,7 +139,6 @@ namespace SHADE
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void BindInputDescriptorSets (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; void BindInputDescriptorSets (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept;
void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept;
bool HasNoAttachments (void) const noexcept; bool HasNoAttachments (void) const noexcept;
void Init(SHResourceHub& resourceManager) noexcept; void Init(SHResourceHub& resourceManager) noexcept;
@ -128,19 +147,24 @@ namespace SHADE
void CreateInputDescriptors (void) noexcept; void CreateInputDescriptors (void) noexcept;
void UpdateWriteDescriptors (void) noexcept; void UpdateWriteDescriptors (void) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
private: private:
/*-----------------------------------------------------------------------*/
/* PRIVATE GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
void SetIndex (uint32_t index) noexcept; void SetIndex (uint32_t index) noexcept;
public: public:
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept; /*-----------------------------------------------------------------------*/
SHSubPassIndex GetIndex() const noexcept; /* PUBLIC SETTERS AND GETTERS */
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept; /*-----------------------------------------------------------------------*/
void SetCompanionSubpass (Handle<SHSubpass> companion, Handle<SHVkPipeline> pipeline) noexcept;
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept; std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept;
vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept;
const std::string& GetName() const; const std::string& GetName() const;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;
friend class SHRenderGraph; friend class SHRenderGraph;

View File

@ -100,6 +100,475 @@ namespace SHADE
} }
} }
std::string SHInputManager::GetKeyCodeName(SH_KEYCODE k) noexcept
{
int kInt = static_cast<int>(k);
//Numbers
if (kInt >= static_cast<int>(SH_KEYCODE::NUMBER_0) && kInt <= static_cast<int>(SH_KEYCODE::NUMBER_9))
{
return std::to_string(kInt - 48);
}
//Letters
if (kInt >= static_cast<int>(SH_KEYCODE::A) && kInt <= static_cast<int>(SH_KEYCODE::Z))
{
return std::string(1, static_cast<char>(kInt));
}
//Numpads
if (kInt >= static_cast<int>(SH_KEYCODE::NUMPAD_0) && kInt <= static_cast<int>(SH_KEYCODE::NUMPAD_9))
{
return "Numpad " + std::to_string(kInt - 96);
}
//Function keys
if (kInt >= static_cast<int>(SH_KEYCODE::F1) && kInt <= static_cast<int>(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: //The Binding File format presently goes as such:
/* /*
* Binding count * Binding count
@ -680,7 +1149,7 @@ namespace SHADE
digitalInput = true; digitalInput = true;
} }
if (std::abs(newValue) > std::abs(largestMagnitude)) 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; digitalInput = true;
} }
if (std::abs(newValue) > std::abs(largestMagnitude)) 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; if (data.value > 1.0) data.value = 1.0;
else if (data.value < -1.0) data.value = -1.0; else if (data.value < -1.0) data.value = -1.0;
} }
//If analog input was in, //If analog input was in, raw value taken
//sensitivity is instead used as a multiplier
else else
{ {
data.value = largestMagnitude * data.sensitivity; data.value = largestMagnitude;
if (data.value > 1.0) data.value = 1.0; if (data.value > 1.0) data.value = 1.0;
else 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.snap) //Snapping
{ {
if (data.value > 0.0 && data.negativeInputHeld) if (digitalInput) //Only for digital inputs
data.value = 0.0; {
if (data.value < 0.0 && data.positiveInputHeld) if (data.value > 0.0 && data.negativeInputHeld)
data.value = 0.0; data.value = 0.0;
if (data.value < 0.0 && data.positiveInputHeld)
data.value = 0.0;
}
} }
} }
} }
@ -936,11 +1407,11 @@ namespace SHADE
{ {
return 0.0; return 0.0;
} }
else if (bindings[bindingName].positiveInputHeld) else if (GetBindingAxis(bindingName, cNum) > 0.0)
{ {
return 1.0; return 1.0;
} }
else if (bindings[bindingName].negativeInputHeld) else if (GetBindingAxis(bindingName, cNum) < 0.0)
{ {
return -1.0; return -1.0;
} }

View File

@ -363,6 +363,7 @@ namespace SHADE
//Speed in units per second that the axis will move toward target value for digital //Speed in units per second that the axis will move toward target value for digital
//For mouse movement / scrolling, serves as multiplier //For mouse movement / scrolling, serves as multiplier
//Irrelevant for other analog inputs
double sensitivity = 1.0; double sensitivity = 1.0;
//If enabled, axis value will reset to zero when pressing a button //If enabled, axis value will reset to zero when pressing a button
@ -415,6 +416,12 @@ namespace SHADE
return controllerInUse; 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 //For testing purposes
//static void PrintCurrentState() noexcept; //static void PrintCurrentState() noexcept;
@ -738,6 +745,16 @@ namespace SHADE
return bindings.erase(bindingName); 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 //Clears all bindings from the list
static inline void ClearBindings() noexcept static inline void ClearBindings() noexcept
{ {
@ -809,7 +826,7 @@ namespace SHADE
//Get the sensitivity of the binding //Get the sensitivity of the binding
//Serves as a multiplier for mouse movement/scrolling //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 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) static inline double GetBindingSensitivity(std::string const& bindingName)
{ {
return bindings[bindingName].sensitivity; return bindings[bindingName].sensitivity;
@ -818,7 +835,7 @@ namespace SHADE
//Set the sensitivity of the binding //Set the sensitivity of the binding
//Serves as a multiplier for mouse movement/scrolling //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 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) static inline void SetBindingSensitivity(std::string const& bindingName, double const newValue)
{ {
bindings[bindingName].sensitivity = 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 //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 //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 //controllerNumber is not used
static double GetBindingAxis(std::string const& bindingName, size_t controllerNumber = 0) noexcept; static double GetBindingAxis(std::string const& bindingName, size_t controllerNumber = 0) noexcept;

View File

@ -11,15 +11,8 @@
#include <fstream> #include <fstream>
#include "Assets/Asset Types/SHSceneAsset.h" #include "Assets/Asset Types/SHSceneAsset.h"
#include "Camera/SHCameraComponent.h" #include "Common/SHAllComponents.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 "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Tools/FileIO/SHFileIO.h" #include "Tools/FileIO/SHFileIO.h"
@ -208,6 +201,7 @@ namespace SHADE
AddComponentToComponentNode<SHCanvasComponent>(components, eid); AddComponentToComponentNode<SHCanvasComponent>(components, eid);
AddComponentToComponentNode<SHButtonComponent>(components, eid); AddComponentToComponentNode<SHButtonComponent>(components, eid);
AddComponentToComponentNode<SHToggleButtonComponent>(components, eid);
AddComponentToComponentNode<SHTextRenderableComponent>(components, eid); AddComponentToComponentNode<SHTextRenderableComponent>(components, eid);
@ -265,6 +259,7 @@ namespace SHADE
AddComponentID<SHCanvasComponent>(componentIDList, componentsNode); AddComponentID<SHCanvasComponent>(componentIDList, componentsNode);
AddComponentID<SHButtonComponent>(componentIDList, componentsNode); AddComponentID<SHButtonComponent>(componentIDList, componentsNode);
AddComponentID<SHToggleButtonComponent>(componentIDList, componentsNode);
AddComponentID<SHTextRenderableComponent>(componentIDList, componentsNode); AddComponentID<SHTextRenderableComponent>(componentIDList, componentsNode);
return componentIDList; return componentIDList;
@ -346,6 +341,7 @@ namespace SHADE
SHSerializationHelper::InitializeComponentFromNode<SHCanvasComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHCanvasComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHButtonComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHButtonComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHToggleButtonComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHTextRenderableComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHTextRenderableComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid);
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Math/Geometry/SHBox.h" #include "Math/Geometry/SHBox.h"
#include "Math/Geometry/SHSphere.h" #include "Math/Geometry/SHSphere.h"
@ -11,8 +13,6 @@
#include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/SHCollisionTagMatrix.h"

View File

@ -205,7 +205,7 @@ namespace SHADE
/// <param name="color"></param> /// <param name="color"></param>
/// <param name="color">Colour to draw with.</param> /// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param> /// <param name="depthTested">Whether or not drawn object will be occluded.</param>
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" */ /* Persistent Draw Function Class "Folder" */
@ -388,7 +388,7 @@ namespace SHADE
/// <param name="color"></param> /// <param name="color"></param>
/// <param name="color">Colour to draw with.</param> /// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param> /// <param name="depthTested">Whether or not drawn object will be occluded.</param>
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);
/// <summary> /// <summary>
/// Clears any persistent drawn debug primitives. /// Clears any persistent drawn debug primitives.
/// </summary> /// </summary>

View File

@ -13,6 +13,7 @@ of DigiPen Institute of Technology is prohibited.
#include <SHpch.h> #include <SHpch.h>
// Primary Header // Primary Header
#include "SHStringUtilities.h" #include "SHStringUtilities.h"
#include <algorithm>
namespace SHADE namespace SHADE
{ {
@ -51,4 +52,11 @@ namespace SHADE
return std::system_category().message(errorCode); 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<char>(std::tolower(c)); });
std::transform(search.begin(), search.end(), search.begin(), [](char c) {return static_cast<char>(std::tolower(c)); });
return str.find(search, pos);
}
} }

View File

@ -16,66 +16,68 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
/// <summary>
/// Contains useful functions for operating on strings.
/// </summary>
class SHStringUtilities
{
public:
/*-----------------------------------------------------------------------------*/
/* Utility Functions */
/*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Contains useful functions for operating on strings. /// Splits a string separated by a specified delimiter into a vector of strings.
/// </summary> /// </summary>
class SHStringUtilities /// <typeparam name="T">Internal type of each element in the string.</typeparam>
{ /// <param name="str">Read only reference to the string to split.</param>
public: /// <param name="delim">Read only reference to the delimiter.</param>
/*-----------------------------------------------------------------------------*/ /// <returns>Vector of strings that have been split.</returns>
/* Utility Functions */ template<typename T>
/*-----------------------------------------------------------------------------*/ static std::vector<std::basic_string<T>> Split(const std::basic_string<T>& str, const T& delim);
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// Overload of Split<T>() to allow for string literals to be accepted.
/// </summary>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
static std::vector<std::string> Split(const std::string& str, const char& delim);
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// Overload of Split<T>() to allow for wide string literals to be accepted.
/// </summary>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
static std::vector<std::wstring> Split(const std::wstring& str, const wchar_t& delim);
/// <summary>
/// Converts a wstring to a string.
/// </summary>
/// <param name="wstr">wstring to convert.</param>
/// <returns>The converted wstring in string form.</returns>
static std::string WstrToStr(const std::wstring& wstr);
/// <summary>
/// Converts a string to a wstring.
/// </summary>
/// <param name="str">string to convert.</param>
/// <returns>The converted string in wstring form.</returns>
static std::wstring StrToWstr(const std::string& str);
/// <summary>
/// Retrieves the error message associated with a Win32 error code.
/// </summary>
/// <param name="errorCode">Win32 error code to decode.</param>
/// <returns>String that represents the Win32 error.</returns>
static std::string GetWin32ErrorMessage(unsigned long errorCode);
/// <summary> static size_t StringFindInsensitive(std::string str, std::string search, size_t pos = 0);
/// Splits a string separated by a specified delimiter into a vector of strings.
/// </summary>
/// <typeparam name="T">Internal type of each element in the string.</typeparam>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
template<typename T>
static std::vector<std::basic_string<T>> Split(const std::basic_string<T>& str, const T& delim);
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// Overload of Split<T>() to allow for string literals to be accepted.
/// </summary>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
static std::vector<std::string> Split(const std::string& str, const char& delim);
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// Overload of Split<T>() to allow for wide string literals to be accepted.
/// </summary>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
static std::vector<std::wstring> Split(const std::wstring& str, const wchar_t& delim);
/// <summary>
/// Converts a wstring to a string.
/// </summary>
/// <param name="wstr">wstring to convert.</param>
/// <returns>The converted wstring in string form.</returns>
static std::string WstrToStr(const std::wstring& wstr);
/// <summary>
/// Converts a string to a wstring.
/// </summary>
/// <param name="str">string to convert.</param>
/// <returns>The converted string in wstring form.</returns>
static std::wstring StrToWstr(const std::string& str);
/// <summary>
/// Retrieves the error message associated with a Win32 error code.
/// </summary>
/// <param name="errorCode">Win32 error code to decode.</param>
/// <returns>String that represents the Win32 error.</returns>
static std::string GetWin32ErrorMessage(unsigned long errorCode);
private: private:
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Constructors/Destructors */ /* Constructors/Destructors */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
SHStringUtilities() = delete; SHStringUtilities() = delete;
}; };
} }
#include "SHStringUtilities.hpp" #include "SHStringUtilities.hpp"

View File

@ -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};
};
}

View File

@ -5,7 +5,7 @@
namespace SHADE namespace SHADE
{ {
SHButtonComponent::SHButtonComponent() 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) defaultTexture(0), hoveredTexture(0), clickedTexture(0)
{ {
} }

View File

@ -18,7 +18,6 @@ namespace SHADE
virtual ~SHButtonComponent() = default; virtual ~SHButtonComponent() = default;
SHVec2 size; SHVec2 size;
SHVec2 offset;
AssetID GetClickedTexture() const noexcept; AssetID GetClickedTexture() const noexcept;
AssetID GetDefaultTexture() const noexcept; AssetID GetDefaultTexture() const noexcept;
@ -33,8 +32,10 @@ namespace SHADE
friend class SHUISystem; friend class SHUISystem;
private: private:
//Set to true when mouse is hovering over the button.
bool isHovered; 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 isClicked;
AssetID defaultTexture; AssetID defaultTexture;
AssetID hoveredTexture; AssetID hoveredTexture;

View File

@ -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_<SHSliderComponent>("Slider Component")
.property("Slider Value", &SHSliderComponent::GetValue, &SHSliderComponent::SetValue)
;
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <rttr/registration>
#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()
};
}

View File

@ -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_<SHToggleButtonComponent>("Toggle Button Component")
.property("Non Toggled Texture", &SHToggleButtonComponent::GetDefaultTexture, &SHToggleButtonComponent::SetDefaultTexture)
.property("Toggled Texture", &SHToggleButtonComponent::GetToggledTexture, &SHToggleButtonComponent::SetToggledTexture)
.property("Value", &SHToggleButtonComponent::GetValue, &SHToggleButtonComponent::SetValue)
;
}

View File

@ -0,0 +1,51 @@
#pragma once
#include <rttr/registration>
#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()
};
}

View File

@ -9,7 +9,15 @@
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
#include "Editor/SHEditor.h" #include "Editor/SHEditor.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
#include "Assets/SHAssetManager.h"
#include "Input/SHInputManager.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 namespace SHADE
{ {
@ -103,7 +111,7 @@ namespace SHADE
{ {
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(comp.GetEID()); auto transform = SHComponentManager::GetComponent<SHTransformComponent>(comp.GetEID());
if (canvasComp != nullptr) if (canvasComp != nullptr)
comp.localToCanvasMatrix = canvasComp->GetMatrix()* transform->GetTRS(); comp.localToCanvasMatrix = transform->GetTRS() * canvasComp->GetMatrix();
else else
comp.localToCanvasMatrix = transform->GetTRS(); comp.localToCanvasMatrix = transform->GetTRS();
} }
@ -139,77 +147,235 @@ namespace SHADE
void SHUISystem::UpdateButtonComponent(SHButtonComponent& comp) noexcept void SHUISystem::UpdateButtonComponent(SHButtonComponent& comp) noexcept
{ {
if (!SHComponentManager::HasComponent<SHTransformComponent>(comp.GetEID()) || !SHComponentManager::HasComponent<SHUIComponent>(comp.GetEID())) if (!SHComponentManager::HasComponent<SHUIComponent>(comp.GetEID()))
{
return;
}
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
auto uiComp = SHComponentManager::GetComponent<SHUIComponent>(comp.GetEID());
//auto canvasComp = SHComponentManager::GetComponent_s<SHCanvasComponent>(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<SHEditorViewport>()->beginContentRegionAvailable;
mousePos = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>()->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<SHGraphicsSystem>()->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<SHEditor>()->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<SHRenderable>(comp.GetEID()))
{
auto renderable = SHComponentManager::GetComponent_s<SHRenderable>(comp.GetEID());
//auto texture = SHResourceManager::Get<SHTexture>(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<SHUIComponent>(comp.GetEID()))
{ {
return; return;
} }
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
auto uiComp = SHComponentManager::GetComponent<SHUIComponent>(comp.GetEID()); auto uiComp = SHComponentManager::GetComponent<SHUIComponent>(comp.GetEID());
SHVec4 topExtent4 = 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 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 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 mousePos;
SHVec2 windowSize;
#ifdef SHEDITOR #ifdef SHEDITOR
windowSize = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>()->beginContentRegionAvailable;
windowSize = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>()->windowSize;
mousePos = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>()->viewportMousePos; mousePos = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>()->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<SHGraphicsSystem>()->GetWindow()->GetWindowSize();
windowSize = { ws.first,ws.second };
mousePos /= windowSize;
#endif #endif
SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) };
SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0).x , cameraSystem->GetCameraWidthHeight(0).y };
topExtent += camSize * 0.5f; topExtent = CanvasToScreenPoint(topExtent,true);
btmExtent += camSize * 0.5f; btmExtent = CanvasToScreenPoint(btmExtent, true);
//Convert everything to using ratios
topExtent /= camSize;
btmExtent /= camSize;
mousePos /= windowSize;
//SHLOG_INFO("mousePos: {} , {}", mousePos.x, mousePos.y);
comp.isClicked = false; comp.isClicked = false;
if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x
&& mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y)
{ {
comp.isHovered = true; comp.isHovered = true;
if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) #ifdef SHEDITOR
if (SHSystemManager::GetSystem<SHEditor>()->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; comp.isClicked = true;
} }
//SHLOG_INFO("BUTTON HOVERED"); #endif
} }
else else
{ {
comp.isHovered = false; 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<SHRenderable>(comp.GetEID())) if (SHComponentManager::HasComponent<SHRenderable>(comp.GetEID()))
{ {
//auto renderable = SHComponentManager::GetComponent_s<SHRenderable>(comp.GetEID()); auto renderable = SHComponentManager::GetComponent_s<SHRenderable>(comp.GetEID());
//auto texture = SHResourceManager::Get<SHTexture>(comp.GetDefaultTexture()); //auto texture = SHResourceManager::Get<SHTexture>(comp.GetDefaultTexture());
//auto material = renderable->GetModifiableMaterial(); auto material = renderable->GetModifiableMaterial();
//material->SetProperty("texture", comp.GetDefaultTexture()); 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 void SHUISystem::UpdateButtonsRoutine::Execute(double dt) noexcept
{ {
SHUISystem* system = (SHUISystem*)GetSystem(); SHUISystem* system = (SHUISystem*)GetSystem();
@ -219,6 +385,34 @@ namespace SHADE
if (SHSceneManager::CheckNodeAndComponentsActive<SHButtonComponent>(comp.GetEID())) if (SHSceneManager::CheckNodeAndComponentsActive<SHButtonComponent>(comp.GetEID()))
system->UpdateButtonComponent(comp); system->UpdateButtonComponent(comp);
} }
auto& toggleButtonDense = SHComponentManager::GetDense<SHToggleButtonComponent>();
for (auto& comp : toggleButtonDense)
{
if (SHSceneManager::CheckNodeAndComponentsActive<SHToggleButtonComponent>(comp.GetEID()))
system->UpdateToggleButtonComponent(comp);
}
} }
SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept
{
SHVec2 result{canvasPoint};
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
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 }//end namespace

View File

@ -3,14 +3,20 @@
#include "SH_API.h" #include "SH_API.h"
#include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "SHUIComponent.h"
#include "SHButtonComponent.h"
#include "SHCanvasComponent.h"
#include "Scene/SHSceneGraph.h" #include "Scene/SHSceneGraph.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Math/Vector/SHVec2.h"
namespace SHADE namespace SHADE
{ {
class SHButtonComponent;
class SHUIComponent;
class SHToggleButtonComponent;
class SHSliderComponent;
class SHCanvasComponent;
class SH_API SHUISystem final: public SHSystem class SH_API SHUISystem final: public SHSystem
{ {
public: public:
@ -64,8 +70,12 @@ namespace SHADE
private: private:
void UpdateUIComponent(SHUIComponent& comp) noexcept; void UpdateUIComponent(SHUIComponent& comp) noexcept;
void UpdateButtonComponent(SHButtonComponent& comp) noexcept; void UpdateButtonComponent(SHButtonComponent& comp) noexcept;
void UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept;
void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept; void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept;
SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept;
}; };