Added open by default for component inspector toggle headers, Added drag/drop receiving for all uint32_t fields #315

Merged
srishamharan merged 6 commits from SP3-4-Editor into main 2023-01-18 04:05:49 +08:00
80 changed files with 2339 additions and 554 deletions
Showing only changes of commit 3cb1e5c7fc - Show all commits

View File

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

1
Assets/Bindings.SHConfig Normal file
View File

@ -0,0 +1 @@
0

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

View File

@ -1,7 +1,7 @@
- EID: 0
Name: Canvas
IsActive: true
NumberOfChildren: 1
NumberOfChildren: 2
Components:
Canvas Component:
Canvas Width: 10
@ -28,6 +28,26 @@
Clicked Texture: 0
IsActive: true
Scripts: ~
- EID: 5
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -3.9000001, z: 0}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
Renderable Component:
Mesh: 141771688
Material: 129340704
IsActive: true
Toggle Button Component:
Non Toggled Texture: 0
Toggled Texture: 0
Value: true
IsActive: true
Scripts: ~
- EID: 1
Name: Camera
IsActive: true

View File

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

View File

@ -6,6 +6,8 @@ struct DirectionalLightStruct
uint isActive;
uint cullingMask;
vec4 diffuseColor;
mat4 pvMatrix;
uint shadowData;
};
struct AmbientLightStruct
@ -22,7 +24,10 @@ layout(set = 3, binding = 1, rgba32f) uniform image2D normals;
layout(set = 3, binding = 2, rgba8) uniform image2D albedo;
layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage;
layout(set = 3, binding = 5, rgba8) uniform image2D targetImage;
layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace;
layout(set = 3, binding = 6, rgba8) uniform image2D targetImage;
layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global)
layout(set = 1, binding = 0) uniform LightCounts
{
@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData
AmbientLightStruct aLightData[];
} AmbLightData;
float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV)
{
vec4 fragPosLightPOV = lightPV * worldSpaceFragPos;
vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f);
float sampledDepth = texture(shadowMap, converted.xy).r;
if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f)
return 1.0f;
if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f)
{
return 0.0f;
}
else
return 1.0f;
// return step (fragPosLightPOV.z, );
}
void main()
{
// convenient variables
@ -52,6 +76,9 @@ void main()
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space
vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f);
// Get position of fragment in view spacee
vec3 positionView = imageLoad (positions, globalThread).rgb;
// normal of fragment
@ -62,6 +89,18 @@ void main()
vec3 fragColor = vec3 (0.0f);
vec4 shadowMapColor = vec4 (1.0f);
for (int i = 0; i < lightCounts.ambientLights; ++i)
{
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
{
// Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
}
}
for (int i = 0; i < lightCounts.directionalLights; ++i)
{
if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
@ -74,16 +113,13 @@ void main()
// Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
}
for (int i = 0; i < lightCounts.ambientLights; ++i)
{
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
{
// Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
// If the shadow map is enabled (test the bit)
if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1)
{
// calculate shadow map here
fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx;
}
}
}
@ -92,6 +128,12 @@ void main()
// store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f));
//imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f));
// vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f);
// vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords);
// if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f)
// shadowMapVal = vec4(0.0f);
// imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx);
}

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

Binary file not shown.

View File

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

Binary file not shown.

View File

@ -270,8 +270,12 @@ namespace SHADE
camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset);
camera.viewMatrix(2, 3) = -view.Dot(camera.position + camera.offset);
//SHVec3 target{ 0.0f,0.0f,-1.0f };
//target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
//target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
//target += camera.position;
//camera.viewMatrix = SHMatrix::Transpose(SHMatrix::LookAtLH(camera.position, target, SHVec3(0.0f, -1.0f, 0.0f)));
camera.dirtyView = false;
}
@ -309,7 +313,9 @@ namespace SHADE
camera.orthoProjMatrix(2, 3) = -n / (f-n);
camera.orthoProjMatrix(3, 3) = 1.0f;
//camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar());
//camera.perspProjMatrix = SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f);
camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar());
//camera.perspProjMatrix = SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f);
//camera.projMatrix.Transpose();
camera.dirtyProj = false;

View File

@ -7,6 +7,8 @@
#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"

View File

@ -23,7 +23,7 @@
#include "SH_API.h"
#include "Events/SHEventManager.hpp"
#include <tuple>
#include <cassert>
namespace SHADE
@ -151,6 +151,32 @@ namespace SHADE
return (componentSet.GetSparseSet<T>()->GetElement_s(EntityHandleGenerator::GetIndex(entityID)));
}
/*!*************************************************************************
* \brief
* Gets the Component of the entity with the specified entityID
*
* This is the safe version of GetComponent_s which does a HasComponent to make
* sure that the entity has such a component and returns nullptr if it doesn't
*
* This safe version also checks if the sparse set of this component type
* has been created in SHComponentManager and creates one if it doesn't
*
* @tparam T...
* Pack of Types for all the Components to get.
* \param entityID
* EntityID of the entity that we are trying to get the component of.
* \return
* A tuple of pointers to all the components specified.
* Returns nullptr if the entity does not contain such a component.
***************************************************************************/
template<typename ...T>
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, T>), std::tuple<T*...>> GetComponents(EntityID entityID) noexcept
{
return std::make_tuple<T*...>(GetComponent_s<T>(entityID)...);
}
/*!*************************************************************************
* \brief
* Gets the Component of the entity with the specified entityID

View File

@ -259,6 +259,13 @@ namespace SHADE
}
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("AssetID: %zu | Path: %s", asset->id, asset->path.c_str());
ImGui::EndTooltip();
}
//TODO: Combine Draw asset and Draw Folder recursive drawing
const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark);
const float horizontalOffset = 0.0f;

View File

@ -21,6 +21,7 @@
#include "UI/SHUIComponent.h"
#include "UI/SHCanvasComponent.h"
#include "UI/SHButtonComponent.h"
#include "UI/SHToggleButtonComponent.h"
#include "SHEditorComponentView.h"
#include "AudioSystem/SHAudioListenerComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
@ -153,6 +154,10 @@ namespace SHADE
{
DrawComponent(buttonComponent);
}
if (auto toggleButton = SHComponentManager::GetComponent_s<SHToggleButtonComponent>(eid))
{
DrawComponent(toggleButton);
}
ImGui::Separator();
// Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
@ -166,6 +171,7 @@ namespace SHADE
DrawAddComponentButton<SHLightComponent>(eid);
DrawAddComponentButton<SHCanvasComponent>(eid);
DrawAddComponentButton<SHButtonComponent>(eid);
DrawAddComponentButton<SHToggleButtonComponent>(eid);
// Components that require Transforms

View File

@ -468,7 +468,7 @@ namespace SHADE
//auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph();
auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass();
auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass();
if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false)
{
@ -487,7 +487,7 @@ namespace SHADE
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");
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());

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_POST { 16 };
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].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
@ -200,6 +221,28 @@ namespace SHADE
}
void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept
{
vk::WriteDescriptorSet writeDescSet{};
// Get binding + set hash
BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding);
// to index a write for a binding
uint32_t writeInfoIndex = updater.writeHashMap[bsHash];
// Initialize info for write
writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type;
writeDescSet.dstArrayElement = descArrayIndex;
writeDescSet.dstSet = descSets[set];
writeDescSet.dstBinding = binding;
writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex;
writeDescSet.descriptorCount = 1u;
device->UpdateDescriptorSet(writeDescSet);
}
void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept
{
vk::WriteDescriptorSet writeDescSet{};

View File

@ -63,10 +63,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Public member functions */
/*-----------------------------------------------------------------------------*/
void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept;
void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<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;

View File

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

View File

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

View File

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

View File

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

View File

@ -87,7 +87,7 @@ namespace SHADE
void UpdateTransformBuffer(uint32_t frameIndex);
void UpdateInstancedIntegerBuffer(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 */

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
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 UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
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 */

View File

@ -13,6 +13,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsPredefinedData::predefinedLayouts;
SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState;
SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState;
std::vector<SHGraphicsPredefinedData::PerSystem> SHGraphicsPredefinedData::perSystemData;
//SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData;
@ -150,12 +152,26 @@ namespace SHADE
Handle<SHVkDescriptorSetLayout> fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data");
// descriptor binding for storing shadow maps
SHVkDescriptorSetLayout::Binding shadowMapBinding
{
.Type = vk::DescriptorType::eCombinedImageSampler,
.Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA,
.DescriptorCount = 200, // we can have up to 200 textures for now
.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount,
};
// For global data (generic data and textures)
Handle<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(lightDataDescSetLayout);
predefinedLayouts.push_back(cameraDataGlobalLayout);
predefinedLayouts.push_back(materialDataPerInstanceLayout);
predefinedLayouts.push_back(fontDataDescSetLayout);
predefinedLayouts.push_back(shadowMapDescLayout);
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts
(
@ -179,7 +195,7 @@ namespace SHADE
);
}
void SHGraphicsPredefinedData::InitDefaultVertexInputState(void) noexcept
void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept
{
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1
@ -187,13 +203,16 @@ namespace SHADE
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots)
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8
shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)});
shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots)
}
void SHGraphicsPredefinedData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES));
InitDescSetLayouts(logicalDevice);
InitDefaultVertexInputState();
InitPredefinedVertexInputState();
InitDescMappings();
InitDummyPipelineLayouts (logicalDevice);
}
@ -217,6 +236,11 @@ namespace SHADE
}
SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept
{
return shadowMapVertexInputState;
}
SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept
{
return perSystemData[static_cast<uint32_t>(systemType)];

View File

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

View File

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

View File

@ -101,9 +101,13 @@ namespace SHADE
// Register function for subpass
//auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph();
auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw");
auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw");
subPass->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{
// Set line width first
cmdBuffer->SetLineWidth(LineWidth);
// Draw
const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex();
cmdBuffer->BeginLabeledSegment("SHDebugDraw (No Depth Test)");
{
@ -125,9 +129,13 @@ namespace SHADE
}
cmdBuffer->EndLabeledSegment();
});
auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth");
auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth");
subPassWithDepth->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{
// Set line width first
cmdBuffer->SetLineWidth(LineWidth);
// Draw
const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex();
cmdBuffer->BeginLabeledSegment("SHDebugDraw (Depth Tested)");
{
@ -207,6 +215,11 @@ namespace SHADE
drawSphere(getMeshBatch(true, depthTested), matrix, color);
}
void SHDebugDrawSystem::DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested)
{
drawWireCapsule(getLineBatch(depthTested), getMeshBatch(false, depthTested), position, rotation, height, radius, color);
}
/*-----------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*-----------------------------------------------------------------------------------*/
@ -264,6 +277,12 @@ namespace SHADE
markPersistentDrawsDirty();
}
void SHDebugDrawSystem::DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested)
{
drawWireCapsule(getPersistentLineBatch(depthTested), getPersistentMeshBatch(false, depthTested), position, rotation, height, radius, color);
markPersistentDrawsDirty();
}
void SHDebugDrawSystem::ClearPersistentDraws()
{
for (auto& batch : persistentLineBatches)
@ -348,6 +367,53 @@ namespace SHADE
);
}
void SHDebugDrawSystem::drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color)
{
// Get local axis vectors
const SHVec3 LOCAL_UP = SHVec3::Rotate(SHVec3::Up, rotation);
const SHVec3 LOCAL_RIGHT = SHVec3::Rotate(SHVec3::Right, rotation);
const SHVec3 LOCAL_FORWARD = SHVec3::Rotate(SHVec3::Forward, rotation);
// Rotate the circle
SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)) * rotation;
// Compute top and bottom of the cylinder
const SHVec3 HALF_UP = LOCAL_UP * (height * 0.5f - radius);
const SHVec3 TOP_POS = position + HALF_UP;
const SHVec3 BOT_POS = position - HALF_UP;
// Render circles
const SHVec3 CIRCLE_SCALE = SHVec3(radius * 2.0f, radius * 2.0, radius * 2.0);
drawCircle(meshBatch, SHMatrix::Transform(TOP_POS, circleOrientation, CIRCLE_SCALE), color);
drawCircle(meshBatch, SHMatrix::Transform(BOT_POS, circleOrientation, CIRCLE_SCALE), color);
// Render connecting lines
drawLine(lineBatch, TOP_POS + LOCAL_RIGHT * radius, BOT_POS + LOCAL_RIGHT * radius, color);
drawLine(lineBatch, TOP_POS - LOCAL_RIGHT * radius, BOT_POS - LOCAL_RIGHT * radius, color);
drawLine(lineBatch, TOP_POS + LOCAL_FORWARD * radius, BOT_POS + LOCAL_FORWARD * radius, color);
drawLine(lineBatch, TOP_POS - LOCAL_FORWARD * radius, BOT_POS - LOCAL_FORWARD * radius, color);
// Render caps
const SHVec3 RADIUS_SCALE = SHVec3(radius * 2.0, radius * 2.0f, radius * 2.0);
const SHMatrix TOP_CAP_MAT = SHMatrix::Transform(TOP_POS, rotation, RADIUS_SCALE);
drawMesh
(
gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap),
meshBatch, TOP_CAP_MAT, color
);
const SHMatrix BOT_CAP_MAT = SHMatrix::Transform
(
BOT_POS,
SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)) * rotation,
RADIUS_SCALE
);
drawMesh
(
gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap),
meshBatch, BOT_CAP_MAT, color
);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Batch Functions - Lines */
/*-----------------------------------------------------------------------------------*/
@ -448,7 +514,6 @@ namespace SHADE
if (batch.NumPoints[frameIndex] > 0)
{
cmdBuffer->BindPipeline(batch.Pipeline);
cmdBuffer->SetLineWidth(LineWidth);
cmdBuffer->BindVertexBuffer(0, batch.VertexBuffers[frameIndex], 0);
cmdBuffer->DrawArrays(batch.NumPoints[frameIndex], 1, 0, 0);
}

View File

@ -163,6 +163,17 @@ namespace SHADE
/// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
void DrawSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false);
/// <summary>
/// Draws the outline of a capsule.
/// </summary>
/// <param name="position">Position of the wireframe capsule.</param>
/// <param name="rotation">Rotation of the capsule.</param>
/// <param name="height">Height of the overall capsule.</param>
/// <param name="radius">Radius of the capsule.</param>
/// <param name="color"></param>
/// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
void DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false);
/*---------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
@ -269,6 +280,17 @@ namespace SHADE
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
void DrawPersistentSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false);
/// <summary>
/// Draws a persistent outline of a capsule.
/// </summary>
/// <param name="position">Position of the wireframe capsule.</param>
/// <param name="rotation">Rotation of the capsule.</param>
/// <param name="height">Height of the overall capsule.</param>
/// <param name="radius">Radius of the capsule.</param>
/// <param name="color"></param>
/// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
void DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false);
/// <summary>
/// Clears any persistent drawn debug primitives.
/// </summary>
void ClearPersistentDraws();
@ -386,6 +408,7 @@ namespace SHADE
void drawCube(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color);
void drawSphere(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color);
void drawCircle(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color);
void drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color);
/*---------------------------------------------------------------------------------*/
/* Helper Batch Functions - Lines */

View File

@ -31,68 +31,91 @@ namespace SHADE
static constexpr uint32_t EDITOR = 0;
};
//struct DescriptorSetIndex
//{
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for static global values like generic data, and
// texture samplers
// */
// /***************************************************************************/
// static constexpr uint32_t STATIC_GLOBALS = 0;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for dynamic global values like lights.
// */
// /***************************************************************************/
// static constexpr uint32_t DYNAMIC_GLOBALS = 1;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for high frequency changing global values like
// camera matrices.
// */
// /***************************************************************************/
// static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for per-instance/material changing values.
// */
// /***************************************************************************/
// static constexpr uint32_t PER_INSTANCE = 3;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for render graph resources. Unlike the sets from
// 1 to 3 and 6, this set index does not have hard coded bindings and is
// NOT part of the layouts included in the global data.
// */
// /***************************************************************************/
// static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for render graph node compute resources. For data
// that we wish to pass to compute shaders in the render graph, this is
// the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have
// hard coded bindings and is NOT part of the layouts included in the global
// data.
// */
// /***************************************************************************/
// static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5;
struct RenderGraphEntityNames
{
/***************************************************************************/
/*!
\brief
Name of G-Buffer render graph node.
*/
/***************************************************************************/
static constexpr std::string_view GBUFFER_PASS = "G-Buffer";
// /***************************************************************************/
// /*!
// \brief
// To store font data.
//
// */
// /***************************************************************************/
// static constexpr uint32_t FONT_DATA = 4;
//};
/***************************************************************************/
/*!
\brief
Name of shadow map render graph node.
*/
/***************************************************************************/
static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass";
/***************************************************************************/
/*!
\brief
Name of deferred composite render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass";
/***************************************************************************/
/*!
\brief
Name of Debug Draw with Depth render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass";
/***************************************************************************/
/*!
\brief
Name of Debug Draw render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass";
/***************************************************************************/
/*!
\brief
Name of screen space pass render graph node.
*/
/***************************************************************************/
static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass";
/***************************************************************************/
/*!
\brief
Name of ImGui pass render graph node.
*/
/***************************************************************************/
static constexpr std::string_view IMGUI_PASS = "ImGui Pass";
/***************************************************************************/
/*!
\brief
Name of deferred composite compute.
*/
/***************************************************************************/
static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite";
};
struct DescriptorSetBindings
{
@ -158,6 +181,16 @@ namespace SHADE
/***************************************************************************/
static constexpr uint32_t FONT_MATRIX_DATA = 1;
/***************************************************************************/
/*!
\brief
Descriptor set binding for shadow map images.
*/
/***************************************************************************/
static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0;
};
struct VertexBufferBindings

View File

@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Events/SHEvent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Input/SHInputManager.h"
namespace SHADE
{
@ -124,6 +127,13 @@ namespace SHADE
SHFreetypeInstance::Init();
SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false);
// Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_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 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 SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_MAP_VS);
}
void SHGraphicsSystem::InitRenderGraph(void) noexcept
@ -169,6 +181,8 @@ namespace SHADE
// Create Default Viewport
worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<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() };
for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i)
{
@ -183,22 +197,24 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
// Initialize world render graph
renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools);
renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Position World Space", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
//worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second);
renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second);
renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second);
renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, true, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second);
renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second);
/*-----------------------------------------------------------------------*/
/* MAIN NODE */
/*-----------------------------------------------------------------------*/
auto gBufferNode = renderGraph->AddNode("G-Buffer",
auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(),
//auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()
{
"Position",
"Entity ID",
@ -207,7 +223,8 @@ namespace SHADE
"Albedo",
"Depth Buffer",
"SSAO",
"SSAO Blur"
"SSAO Blur",
"Position World Space"
},
{}); // no predecessors
@ -220,6 +237,7 @@ namespace SHADE
gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals");
gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddColorOutput("Position World Space");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL);
@ -254,53 +272,52 @@ namespace SHADE
// Add another pass to blur SSAO
Handle<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 */
/*-----------------------------------------------------------------------*/
// This pass will facilitate both lighting and shadows in 1 single pass.
auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass",
auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(),
{
"Position",
"Light Layer Indices",
"Normals",
"Albedo",
"Scene",
"SSAO Blur"
"SSAO Blur",
"Position World Space"
},
{"G-Buffer"});
{ SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()});
/*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */
/*-----------------------------------------------------------------------*/
deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" });
auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Position World Space", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS);
deferredCompositeCompute->AddPreComputeFunction([=](Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer);
});
/*-----------------------------------------------------------------------*/
/* DEBUG DRAW PASS INIT */
/*-----------------------------------------------------------------------*/
// Set up Debug Draw Passes
// - Depth Tested
auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"});
auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()});
auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer);
debugDrawDepthSubpass->AddColorOutput("Scene");
debugDrawDepthSubpass->AddDepthOutput("Depth Buffer");
// - No Depth Test
auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" });
auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()});
auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer);
debugDrawSubpass->AddColorOutput("Scene");
/*-----------------------------------------------------------------------*/
/* SCREEN SPACE PASS */
/*-----------------------------------------------------------------------*/
auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" });
auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()});
auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer);
uiSubpass->AddColorOutput("Scene");
uiSubpass->AddColorOutput("Entity ID");
@ -315,16 +332,16 @@ namespace SHADE
#ifdef SHEDITOR
{
// Dummy Node to transition scene render graph resource
auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" });
auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()});
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {});
dummySubpass->AddInput("Scene");
auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {});
auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {});
auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {});
imGuiSubpass->AddColorOutput("Present");
}
#else
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS });
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS});
#endif
@ -393,12 +410,16 @@ namespace SHADE
postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool);
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool);
lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams
{
.addressMode = vk::SamplerAddressMode::eClampToBorder,
})
);
textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>();
// initialize the text renderer
auto uiNode = renderGraph->GetNode("Screen Space Pass");
auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data());
textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS);
SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem);
@ -419,13 +440,14 @@ namespace SHADE
primitiveMeshes[static_cast<int>(PrimitiveType::Sphere)] = SHPrimitiveGenerator::Sphere(meshLibrary);
primitiveMeshes[static_cast<int>(PrimitiveType::LineCube)] = SHPrimitiveGenerator::LineCube(meshLibrary);
primitiveMeshes[static_cast<int>(PrimitiveType::LineCircle)] = SHPrimitiveGenerator::LineCircle(meshLibrary);
primitiveMeshes[static_cast<int>(PrimitiveType::LineCapsuleCap)] = SHPrimitiveGenerator::LineCapsuleCap(meshLibrary);
BuildMeshBuffers();
// Create default materials
defaultMaterial = AddMaterial
(
defaultVertShader, defaultFragShader,
renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write")
renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write")
);
defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
}
@ -450,6 +472,7 @@ namespace SHADE
InitMiddleEnd();
InitSubsystems();
InitBuiltInResources();
InitEvents();
}
void SHGraphicsSystem::Exit(void)
@ -545,6 +568,15 @@ namespace SHADE
#endif
}
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B))
{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
for (auto& comp : lightComps)
{
comp.SetEnableShadow(true);
}
}
renderGraph->Begin(frameIndex);
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
@ -725,16 +757,61 @@ namespace SHADE
renderers.erase(iter);
}
SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept
SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept
{
// we need to wait for the device to finish using the graph first
device->WaitIdle();
auto const& EVENT_DATA = reinterpret_cast<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
renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat);
// link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer.
auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data());
// Add a subpass to render to that shadow map
auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer());
newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH);
// regenerate the node
shadowMapNode->RuntimeStandaloneRegenerate();
// Create pipeline from new renderpass and subpass if it's not created yet
if (!shadowMapPipeline)
{
SHPipelineLibrary tempLibrary{};
Handle<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
//renderGraph->GetNode ();
return event->handle;
// add the shadow map to the lighting system
uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), EVENT_DATA->lightEntity);
auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data());
nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX);
return eventPtr->handle;
}
Handle<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass)
@ -819,6 +896,7 @@ namespace SHADE
case PrimitiveType::Sphere:
case PrimitiveType::LineCube:
case PrimitiveType::LineCircle:
case PrimitiveType::LineCapsuleCap:
return primitiveMeshes[static_cast<int>(type)];
default:
return {};
@ -1045,6 +1123,7 @@ namespace SHADE
mousePickSubSystem->HandleResize();
postOffscreenRenderSubSystem->HandleResize();
//lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()));
worldViewport->SetWidth(static_cast<float>(resizeWidth));
worldViewport->SetHeight(static_cast<float>(resizeHeight));
@ -1077,7 +1156,7 @@ namespace SHADE
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

View File

@ -72,9 +72,10 @@ namespace SHADE
Cube,
Sphere,
LineCube,
LineCircle
LineCircle,
LineCapsuleCap
};
static constexpr int MAX_PRIMITIVE_TYPES = 4;
static constexpr int MAX_PRIMITIVE_TYPES = 5;
enum class DebugDrawPipelineType
{
LineNoDepthTest,
@ -177,7 +178,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* Light functions */
/*-----------------------------------------------------------------------*/
SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept;
SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept;
/*-----------------------------------------------------------------------------*/
/* Material Functions */
@ -405,10 +406,6 @@ namespace SHADE
SHWindow* GetWindow() noexcept { return window; }
private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/
/* Data Members */
@ -445,6 +442,7 @@ namespace SHADE
#endif
Handle<SHViewport> worldViewport; // Whole screen
Handle<SHViewport> shadowMapViewport;
std::vector<Handle<SHViewport>> viewports; // Additional viewports
// Renderers
@ -468,6 +466,7 @@ namespace SHADE
Handle<SHVkShaderModule> textFS;
Handle<SHVkShaderModule> renderToSwapchainVS;
Handle<SHVkShaderModule> renderToSwapchainFS;
Handle<SHVkShaderModule> shadowMapVS;
// Fonts
Handle<SHFont> testFont;
@ -482,6 +481,7 @@ namespace SHADE
Handle<SHVkPipeline> debugDrawWireMeshDepthPipeline;
Handle<SHVkPipeline> debugDrawFilledPipeline;
Handle<SHVkPipeline> debugDrawFilledDepthPipeline;
Handle<SHVkPipeline> shadowMapPipeline; // initialized only when a shadow map is needed
// Built-In Textures
Handle<SHTexture> defaultTexture;

View File

@ -122,4 +122,9 @@ namespace SHADE
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
#include "SHCamera.h"
#include "Resource/SHHandle.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Math/SHMath.h"
#include <vector>
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE
{
@ -93,6 +93,7 @@ namespace SHADE
/* Setters and Getters */
/*-----------------------------------------------------------------------------*/
Handle<SHCameraDirector> GetCameraDirector (void) const noexcept;
SHShaderCameraData GetCPUCameraData (void) const noexcept;
private:
/*-----------------------------------------------------------------------------*/

View File

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

View File

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

View File

@ -10,6 +10,13 @@
#include "SHLightComponent.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
#include "Graphics/Images/SHVkImageView.h"
#include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h"
#include "Graphics/Images/SHVkSampler.h"
#include "Graphics/Events/SHGraphicsEvents.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
namespace SHADE
{
@ -50,6 +57,19 @@ namespace SHADE
//lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive;
// write view projection matrix if renderer is available
auto lightRenderer = lightComp->GetRenderer();
if (lightRenderer)
{
lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix;
// Boolean to cast shadows in first 8 bits (1 byte)
lightPtr->shadowData = lightData.castShadows;
// Next 24 bits for shadow map index
lightPtr->shadowData |= (lightData.shadowMapIndex << 8);
}
break;
}
case SH_LIGHT_TYPE::POINT:
@ -365,6 +385,32 @@ namespace SHADE
}
}
void SHLightingSubSystem::UpdateShadowMapDesc(void) noexcept
{
}
SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept
{
switch (lightComp->GetLightData().type)
{
case SH_LIGHT_TYPE::DIRECTIONAL:
return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, SHVec3::Normalise (lightComp->GetLightData().direction), SHVec3(0.0f, -1.0f, 0.0f)));
//return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f)));
case SH_LIGHT_TYPE::POINT:
return {};
case SH_LIGHT_TYPE::SPOT:
return {};
case SH_LIGHT_TYPE::AMBIENT:
return {};
case SH_LIGHT_TYPE::NUM_TYPES:
return {};
default:
return {};
}
}
/***************************************************************************/
/*!
@ -375,13 +421,15 @@ namespace SHADE
*/
/***************************************************************************/
void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept
void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, SHResourceHub* rh, Handle<SHVkSampler> inShadowMapSampler) noexcept
{
SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device;
resourceHub = rh;
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::fill (variableSizes.begin(), variableSizes.end(), 1);
@ -418,7 +466,22 @@ namespace SHADE
dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
}
#pragma endregion
#pragma region SHADOWS
//std::vector<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;
#pragma endregion
}
/***************************************************************************/
@ -452,6 +515,12 @@ namespace SHADE
for (auto& light : lightComps)
{
if (auto renderer = light.GetRenderer())
{
//SHMatrix orthoMatrix = SHMatrix::OrthographicRH()
renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(10.0f, 10.0f, 1.0f, 50.0f));
}
auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it
@ -503,7 +572,6 @@ namespace SHADE
// so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets();
}
/***************************************************************************/
@ -526,9 +594,101 @@ namespace SHADE
}
uint32_t SHLightingSubSystem::AddShadowMap(Handle<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
{
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 "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
#include "SHLightData.h"
#include <array>
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/RenderGraph/SHRenderGraphResource.h"
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
@ -16,6 +20,10 @@ namespace SHADE
class SHVkBuffer;
class SHLightComponent;
class SHVkCommandBuffer;
class SHSamplerCache;
class SHVkImageView;
class SHVkSampler;
class SHRenderGraphNodeCompute;
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData
@ -34,6 +42,12 @@ namespace SHADE
//! Diffuse color emitted by the light
alignas (16) SHVec4 diffuseColor;
//! Matrix for world to projection from light's perspective
SHMatrix pvMatrix;
//! Represents boolean for casting shadows in first byte and shadow map index in the other 3.
uint32_t shadowData;
};
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
@ -52,24 +66,27 @@ namespace SHADE
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
};
class SH_API SHLightingSubSystem
{
public:
using DynamicOffsetArray = std::array<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:
class PerTypeData
{
public:
private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
static constexpr uint32_t STARTING_NUM_LIGHTS = 50;
static constexpr uint32_t STARTING_NUM_LIGHTS = 50;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
@ -123,51 +140,90 @@ namespace SHADE
};
private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! logical device used for creation
Handle<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.
Handle<SHVkDescriptorSetGroup> lightingDataDescSet;
//! Each type will have some data associated with it for processing
std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData;
//! Container to store dynamic offsets for binding descriptor sets
DynamicOffsetArray dynamicOffsets;
//! holds the data that represents how many lights are in the scene
std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData;
//! GPU buffer to hold lightCountData
Handle<SHVkBuffer> lightCountsBuffer;
//! For padding in the buffer
uint32_t lightCountsAlignedSize;
Handle<SHVkDescriptorSetGroup> lightingDataDescSet;
//! Each type will have some data associated with it for processing
std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData;
//! Container to store dynamic offsets for binding descriptor sets
DynamicOffsetArray dynamicOffsets;
//! holds the data that represents how many lights are in the scene
std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData;
//! GPU buffer to hold lightCountData
Handle<SHVkBuffer> lightCountsBuffer;
//! For padding in the buffer
uint32_t lightCountsAlignedSize;
//! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense
//! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more,
//! don't do anything.
//uint32_t numLightComponents;
//! Handle to sampler that all shadow map descriptors will use
Handle<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 */
/*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept;
void ResetNumLights (void) noexcept;
void UpdateShadowMapDesc (void) noexcept;
SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept;
void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept;
void Exit (void) 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 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;
std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept;
uint32_t GetNumShadowMaps (void) const noexcept;
};
}

View File

@ -29,6 +29,7 @@ namespace SHADE
SHMeshData SHPrimitiveGenerator::sphereMesh;
SHMeshData SHPrimitiveGenerator::lineCubeMesh;
SHMeshData SHPrimitiveGenerator::lineCircleMesh;
SHMeshData SHPrimitiveGenerator::lineCapsuleCapMesh;
/*-----------------------------------------------------------------------------------*/
/* Primitive Generation Functions */
@ -392,6 +393,64 @@ namespace SHADE
return addMeshDataTo(lineCircleMesh, gfxSystem);
}
SHADE::SHMeshData SHPrimitiveGenerator::LineCapsuleCap() noexcept
{
SHMeshData mesh;
// Have multiple semi-circles for the cap
static constexpr int SPLITS = 36;
static constexpr float ANGLE_INCREMENTS = (std::numbers::pi_v<float> * 2.0f) / static_cast<float>(SPLITS);
/* X-Axis */
// Generate points of the circle
for (int i = 0; i <= SPLITS / 2; ++i)
{
const float ANGLE = ANGLE_INCREMENTS * i;
mesh.VertexPositions.emplace_back(cos(ANGLE) * 0.5f, sin(ANGLE) * 0.5f, 0.0f);
}
// Generate lines of the circle
for (int i = 1; i <= SPLITS / 2; ++i)
{
mesh.Indices.emplace_back(static_cast<uint32_t>(i - 1));
mesh.Indices.emplace_back(static_cast<uint32_t>(i));
}
/* Z-Axis */
// Generate points of the circle
for (int i = 0; i <= SPLITS / 2; ++i)
{
const float ANGLE = ANGLE_INCREMENTS * i;
mesh.VertexPositions.emplace_back(0.0f, sin(ANGLE) * 0.5f, cos(ANGLE) * 0.5f);
}
// Generate lines of the circle
for (int i = 2 + SPLITS / 2; i <= SPLITS + 1; ++i)
{
mesh.Indices.emplace_back(static_cast<uint32_t>(i - 1));
mesh.Indices.emplace_back(static_cast<uint32_t>(i));
}
mesh.VertexNormals.resize(mesh.VertexPositions.size());
mesh.VertexTangents.resize(mesh.VertexPositions.size());
mesh.VertexTexCoords.resize(mesh.VertexPositions.size());
return mesh;
}
Handle<SHADE::SHMesh> SHPrimitiveGenerator::LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept
{
if (lineCapsuleCapMesh.VertexPositions.empty())
lineCapsuleCapMesh = LineCapsuleCap();
return addMeshDataTo(lineCapsuleCapMesh, meshLibrary);
}
Handle<SHADE::SHMesh> SHPrimitiveGenerator::LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept
{
if (lineCapsuleCapMesh.VertexPositions.empty())
lineCapsuleCapMesh = LineCapsuleCap();
return addMeshDataTo(lineCapsuleCapMesh, gfxSystem);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/

View File

@ -194,6 +194,46 @@ namespace SHADE
*/
/***********************************************************************************/
[[nodiscard]] static Handle<SHMesh> LineCircle(SHGraphicsSystem& gfxSystem) noexcept;
/***********************************************************************************/
/*!
\brief
Produces a cap of a wireframe capsule that is comprised only of lines and
store the data in a SHMeshData object.
\return
SHMeshData object containing vertex data for the line circle.
*/
/***********************************************************************************/
[[nodiscard]] static SHMeshData LineCapsuleCap() noexcept;
/***********************************************************************************/
/*!
\brief
Produces a cap of a wireframe capsule that is comprised only of lines and
constructs a SHMesh using the SHGraphicsSystem provided.
\param meshLibrary
Reference to the SHMeshLibrary to produce and store a line circle mesh in.
\return
SHMesh object that points to the generated line circle mesh in the SHMeshLibrary.
*/
/***********************************************************************************/
[[nodiscard]] static Handle<SHMesh> LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept;
/***********************************************************************************/
/*!
\brief
Produces a cap of a wireframe capsule that is comprised only of lines and
constructs a SHMesh using the SHGraphicsSystem provided.
\param gfxSystem
Reference to the SHGraphicsSystem to produce and store a line circle mesh in.
\return
SHMesh object that points to the generated line circle mesh in the
SHGraphicsSystem.
*/
/***********************************************************************************/
[[nodiscard]] static Handle<SHMesh> LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept;
private:
/*---------------------------------------------------------------------------------*/
@ -209,5 +249,6 @@ namespace SHADE
static SHMeshData sphereMesh;
static SHMeshData lineCubeMesh;
static SHMeshData lineCircleMesh;
static SHMeshData lineCapsuleCapMesh;
};
}

View File

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

View File

@ -3,6 +3,7 @@
#include <unordered_map>
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h"
namespace SHADE
{
@ -32,7 +33,9 @@ namespace SHADE
Handle<SHVkPipeline> CreateGraphicsPipelines (
std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair,
Handle<SHVkRenderpass> renderpass,
Handle<SHSubpass> subpass
Handle<SHSubpass> subpass,
SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(),
SHRasterizationState const& rasterState = SHRasterizationState{}
) noexcept;
Handle<SHVkPipeline> GetGraphicsPipeline (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;
}
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
bindings.emplace_back();
@ -210,7 +210,7 @@ namespace SHADE
// Offset is 0 at first (for first element)
uint32_t offset = 0;
binding.binding = static_cast<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 (auto const& attrib : inAttribs)
@ -226,10 +226,11 @@ namespace SHADE
auto& vertexAttrib = attributes.back();
// The binding for that attribute description is index of the new binding created earlier in this function
vertexAttrib.binding = static_cast<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
vertexAttrib.location = static_cast<uint32_t>(attributes.size () - 1);
//Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously
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
vertexAttrib.format = format;

View File

@ -34,7 +34,7 @@ namespace SHADE
SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept;
SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept;
void AddBinding(bool instanced, bool calcOffset, std::initializer_list<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 SHVkPipeline;

View File

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

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 (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
@ -64,7 +64,7 @@ namespace SHADE
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);
}
@ -106,6 +106,9 @@ namespace SHADE
for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->CreateFramebuffer();
renderGraphStorage->graphResources->at(resourceName).Free();
renderGraphStorage->graphResources->erase (resourceName);
/*
* IMPORTANT NOTES
*
@ -166,68 +169,7 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes)
{
// key is handle ID, value is final layout.
std::unordered_map<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);
}
node->StandaloneConfigureAttDesc(i == nodes.size() - 1);
++i;
}
@ -333,6 +275,17 @@ namespace SHADE
}
}
void SHRenderGraph::ReindexNodes(void) noexcept
{
nodeIndexing.clear();
uint32_t i = 0;
for (auto& node : nodes)
{
nodeIndexing.emplace (node->name, i);
++i;
}
}
/***************************************************************************/
/*!
@ -473,6 +426,65 @@ namespace SHADE
return node;
}
/***************************************************************************/
/*!
\brief
This function is purely used for dynamic nodes (if such a thing were to
exist in our architecture). In other words, don't use this function unless
the new node is fully standalone and does not rely or is a prereq of
other nodes.
\param nodeName
Name of new node
\param resourceInstruction
Resources for the node
\param nodeToAddAfter
The node to add the new node after.
\return
*/
/***************************************************************************/
Handle<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
{
for (auto& node : predecessorNodes)
@ -532,10 +544,6 @@ namespace SHADE
ConfigureSubSystems();
}
void SHRenderGraph::Regenerate(void) noexcept
{
}
/***************************************************************************/
/*!
@ -572,10 +580,13 @@ namespace SHADE
for (auto& node : nodes)
{
// bind static global data
SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA));
if (node->renderpass)
{
// bind static global data
SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA));
node->Execute(cmdBuffer, descPool, frameIndex);
node->Execute(cmdBuffer, descPool, frameIndex);
}
}
cmdBuffer->EndLabeledSegment();
@ -605,8 +616,11 @@ namespace SHADE
// resize resources
for (auto& [name, resource] : *renderGraphStorage->graphResources)
{
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw))
resource->HandleResize(newWidth, newHeight);
if (resource->resizeWithWindow)
{
if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw))
resource->HandleResize(newWidth, newHeight);
}
}
for (auto& node : nodes)

View File

@ -55,6 +55,7 @@ namespace SHADE
void ConfigureRenderpasses (void) noexcept;
void ConfigureSubSystems (void) noexcept;
void ConfigureFramebuffers (void) noexcept;
void ReindexNodes (void) noexcept;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
@ -101,6 +102,7 @@ namespace SHADE
(
std::string resourceName,
std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags,
bool resizeWithWindow = true,
uint32_t w = static_cast<uint32_t>(-1),
uint32_t h = static_cast<uint32_t>(-1),
vk::Format format = vk::Format::eB8G8R8A8Unorm,
@ -123,6 +125,12 @@ namespace SHADE
std::initializer_list<ResourceInstruction> resourceInstruction,
std::initializer_list<std::string> predecessorNodes
) noexcept;
Handle<SHRenderGraphNode> AddNodeAfter
(
std::string nodeName,
std::initializer_list<ResourceInstruction> resourceInstruction,
std::string nodeToAddAfter
) noexcept;
void AddRenderToSwapchainNode
(
@ -134,7 +142,6 @@ namespace SHADE
) noexcept;
void Generate (void) noexcept;
void Regenerate (void) noexcept;
void CheckForNodeComputes (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void Begin (uint32_t frameIndex) noexcept;
@ -165,7 +172,14 @@ namespace SHADE
* that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph,
* but different matrices (SHRenderer) can be used in different nodes.
* - There are also way too many hash maps created for ease of access. This definitely can be cut down.
* -
* - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted
* for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses
* while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other
* than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as
* whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later
* be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as
* if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any
* other node.
*
*/

View File

@ -32,8 +32,11 @@ namespace SHADE
renderpass.Free();
}
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name);
if (!spDescs.empty())
{
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name);
}
}
/***************************************************************************/
@ -46,91 +49,105 @@ namespace SHADE
/***************************************************************************/
void SHRenderGraphNode::CreateFramebuffer(void) noexcept
{
if (!framebuffers.empty())
if (renderpass)
{
for (auto fbo : framebuffers)
if (!framebuffers.empty())
{
if (fbo)
fbo.Free();
}
}
for (uint32_t i = 0; i < framebuffers.size(); ++i)
{
std::vector<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 (auto fbo : framebuffers)
{
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();
framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i));
for (uint32_t j = 0; j < attResources.size(); ++j)
{
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<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
{
renderpass->HandleResize();
for (uint32_t i = 0; i < framebuffers.size(); ++i)
if (renderpass)
{
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();
renderpass->HandleResize();
for (uint32_t j = 0; j < attResources.size(); ++j)
for (uint32_t i = 0; i < framebuffers.size(); ++i)
{
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0;
imageViews[j] = attResources[j]->imageViews[imageViewIndex];
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();
// We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's
if (fbWidth > attResources[j]->width)
fbWidth = attResources[j]->width;
if (fbHeight > attResources[j]->height)
fbHeight = attResources[j]->height;
for (uint32_t j = 0; j < attResources.size(); ++j)
{
uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast<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]->HandleResize(renderpass, imageViews, fbWidth, fbHeight);
}
framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight);
}
for (auto& subpass : subpasses)
{
subpass->HandleResize();
}
for (auto& subpass : subpasses)
{
subpass->HandleResize();
}
for (auto& nodeCompute : nodeComputes)
{
nodeCompute->HandleResize();
for (auto& nodeCompute : nodeComputes)
{
nodeCompute->HandleResize();
}
}
}
void SHRenderGraphNode::ConfigureSubpasses(void) noexcept
{
if (subpasses.empty())
return;
uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle<SHSubpass> subpass) {return !subpass->HasNoAttachments();});
// Create subpass description and dependencies based on number of subpasses
spDescs.resize(subpasses.size());
spDeps.resize(subpasses.size());
spDescs.resize(numValidSubpasses);
spDeps.resize(numValidSubpasses);
// Now we want to loop through all attachments in all subpasses in the node and query
// the resources being used. For each resource we want to query the type and record it
// in bit fields (1 bit for each subpass).
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0;
uint32_t i = 0;
// For all subpasses (see above description about bit field for this).
for (auto& subpass : subpasses)
for (uint32_t i = 0; auto& subpass : subpasses)
{
// skip if subpass is not valid
if (subpass->HasNoAttachments())
continue;
// Configure subpass description
auto& desc = spDescs[i];
desc.pColorAttachments = subpass->colorReferences.data();
@ -186,8 +203,11 @@ namespace SHADE
// Loop through all subpasses again but this time we use the bit field to initialize
// the dependencies.
for (i = 0; i < subpasses.size(); ++i)
for (uint32_t i = 0; auto & subpass : subpasses)
{
if (subpass->HasNoAttachments())
continue;
vk::PipelineStageFlags srcStage;
vk::PipelineStageFlags dstStage;
vk::AccessFlags srcAccess;
@ -245,6 +265,8 @@ namespace SHADE
// initialize input descriptors
subpasses[i]->CreateInputDescriptors();
++i;
}
}
@ -343,6 +365,7 @@ namespace SHADE
, spDeps{ std::move(rhs.spDeps) }
, nodeComputes{ std::move(rhs.nodeComputes) }
, name { std::move(rhs.name) }
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
{
rhs.renderpass = {};
@ -419,7 +442,7 @@ namespace SHADE
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
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
@ -435,7 +458,7 @@ namespace SHADE
std::vector<Handle<SHRenderGraphResource>> temp (nodeComputeResources);
// 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);
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
attachmentDescriptions.erase (attachmentDescriptions.begin() + index);
// erase from mapping as well
resourceAttachmentMapping->erase(resourceHandleID);
// Remove footprint of attachment from all subpasses as well
for (auto it = subpasses.begin(); it != subpasses.end(); ++it)
{
// attempt to detach resource from subpass
(*it)->DetachResource(resourceName, index);
// If the subpass ends up having no attachments after, erase it from the node
if ((*it)->HasNoAttachments())
// If the subpass uses the resource, just remove the subpass since the subpass will be invalid
if ((*it)->UsesResource(index))
{
// erase from indexing
subpassIndexing.erase((*it)->GetName());
@ -530,6 +615,24 @@ namespace SHADE
for (uint32_t i = 0; i < subpasses.size(); ++i)
subpasses[i]->SetIndex(i);
// remove node computes using the resource
for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it)
{
if ((*it)->UsesResource(resourceHandleID))
{
it = nodeComputes.erase(it);
}
}
// recompute the barriers for the other computes
for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it)
{
if (it == nodeComputes.begin())
(*it)->SetFollowingEndRenderpass(true);
(*it)->InitializeBarriers();
}
return true;
}
return false;
@ -537,37 +640,40 @@ namespace SHADE
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
for (uint32_t i = 0; i < subpasses.size(); ++i)
if (renderpass)
{
subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
// Go to next subpass if not last subpass
if (i != static_cast<uint32_t>(subpasses.size()) - 1u)
commandBuffer->NextSubpass();
for (uint32_t i = 0; i < subpasses.size(); ++i)
{
subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
// Go to next subpass if not last subpass
if (i != static_cast<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
@ -599,6 +705,77 @@ namespace SHADE
batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex);
}
/***************************************************************************/
/*!
\brief
This function simply appends to the container of VkAttachmentDescription
and attResources. It will assume the resource is used standalone in the
node and will not account for its usage in other nodes. As such its
initialLayout will always be UNDEFINED and its finalLayout will be
whatever is calculated if the node is regenerated using
StandaloneRegnerate. This function also does not affect the render graph
while its running since the 2 containers above have already been copied
to the GPU.
\param resourceName
The name of the resource for getting the resource.
*/
/***************************************************************************/
void SHRenderGraphNode::RuntimeLinkResource(std::string resourceName) noexcept
{
// Get new resource
Handle<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;
}
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 HandleResize (void) noexcept;
void ConfigureSubpasses (void) noexcept;
bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept;
void AddDummySubpassIfNeeded(void) noexcept;
void StandaloneConfigureAttDesc (bool isLastNode) noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -105,15 +108,17 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<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;
void AddDummySubpassIfNeeded (void) noexcept;
bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) 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 = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) 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;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
// TODO: RemoveSubpass()
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;
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 */
@ -122,6 +127,7 @@ namespace SHADE
Handle<SHSubpass> GetSubpass(std::string_view subpassName) const noexcept;
Handle<SHRenderGraphResource> GetResource (uint32_t resourceIndex) const noexcept;
std::vector<Handle<SHRenderGraphResource>> const& GetResources (void) const noexcept;
Handle<SHRenderGraphNodeCompute> GetNodeCompute (std::string nodeComputeName) const noexcept;
friend class SHRenderGraph;
};

View File

@ -14,7 +14,56 @@
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{}
, pipelineLayout{}
, resources{}
@ -68,10 +117,12 @@ namespace SHADE
// check if all layouts are there
if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1)
{
Handle<SHVkDescriptorSetLayout> computeResourceLayout = {};
computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
// create compute resources
computeResource = graphStorage->resourceHub->Create<ComputeResource>();
auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 });
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount});
#ifdef _DEBUG
for (auto set : computeResource->descSet->GetVkHandle())
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources");
@ -91,6 +142,11 @@ namespace SHADE
void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
for (auto& fn : preComputeFunctions)
{
fn (cmdBuffer, frameIndex);
}
// bind the compute pipeline
cmdBuffer->BindPipeline(computePipeline);
@ -157,35 +213,7 @@ namespace SHADE
groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY;
for (uint32_t i = 0; auto& barriers : memoryBarriers)
{
barriers.clear();
for (auto& resource : resources)
{
vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite);
barriers.push_back(vk::ImageMemoryBarrier
{
.srcAccessMask = srcAccessMask,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = resource->GetImage((resource->resourceTypeFlags & static_cast<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;
}
InitializeBarriers();
}
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
{
public:
using PreComputeFunction = std::function<void(Handle<SHVkCommandBuffer>, uint32_t)>;
private:
// Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE
struct ComputeResource
@ -73,8 +77,23 @@ namespace SHADE
//! Name of this node
std::string name;
std::vector<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:
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 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 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 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}
, resourceTypeFlags{ }
, resourceFormat{ format }
@ -88,6 +88,7 @@ namespace SHADE
, height{ h }
, mipLevels{ levels }
, resourceName{ name }
, resizeWithWindow { inResizeWithWindow }
{
// If the resource type is an arbitrary image and not swapchain image
if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)
@ -210,6 +211,7 @@ namespace SHADE
, imageAspectFlags{ rhs.imageAspectFlags }
, graphStorage{rhs.graphStorage}
, infoTracker {std::move (rhs.infoTracker)}
, resizeWithWindow{rhs.resizeWithWindow}
{
}
@ -242,7 +244,8 @@ namespace SHADE
mipLevels = rhs.mipLevels;
imageAspectFlags = rhs.imageAspectFlags;
graphStorage = rhs.graphStorage;
infoTracker = std::move(infoTracker);
infoTracker = std::move(rhs.infoTracker);
resizeWithWindow = rhs.resizeWithWindow;
return *this;
}

View File

@ -96,11 +96,14 @@ namespace SHADE
//! For tracking resource states in stages of the render graphs
Handle<InfoTracker> infoTracker;
//! Whether or not to resize (recreate vulkan image) when window resizes
bool resizeWithWindow;
public:
/*-----------------------------------------------------------------------*/
/* 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& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept;

View File

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

View File

@ -21,12 +21,23 @@ namespace SHADE
class SHVkSampler;
class SHRenderer;
class SHViewport;
class SHVkPipeline;
class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{
public:
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 MEMBER VARIABLES */
@ -94,6 +105,15 @@ namespace SHADE
// For identifying subpasses
std::string name;
//! Optional component to a companion subpass. If the subpass handle of this object
//! is valid, the subpass will be drawn using this companion's data.
CompanionSubpass companionSubpass;
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
bool UsesResource(uint32_t attachmentIndex) noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -119,7 +139,6 @@ namespace SHADE
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void HandleResize (void) 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;
void Init(SHResourceHub& resourceManager) noexcept;
@ -128,19 +147,24 @@ namespace SHADE
void CreateInputDescriptors (void) noexcept;
void UpdateWriteDescriptors (void) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
void SetIndex (uint32_t index) noexcept;
public:
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
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;
vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept;
const std::string& GetName() const;
vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept;
const std::string& GetName() const;
friend class SHRenderGraphNode;
friend class SHRenderGraph;

View File

@ -11,6 +11,7 @@
#pragma once
#include <SHpch.h>
#include <fstream>
#include "SHInputManager.h"
#include "../Tools/SHException.h"
@ -99,6 +100,161 @@ namespace SHADE
}
}
//The Binding File format presently goes as such:
/*
* Binding count
* (For each binding:)
* Name
Binding Type Enum
Inverted Bool
Gravity Double
Dead Double
Sensitivity Double
Snap Bool
PositiveKeyCode count
PositiveKeyCodes
NegativeKeyCode count
NegativeKeyCodes
PositiveControllerCode Count
PositiveControllerCodes
NegativeControllerCode Count
NegativeControllerCodes
*/
void SHInputManager::SaveBindings(std::string const& targetFile) noexcept
{
std::ofstream file;
file.open(targetFile);
//File cannot be written to
if (!file) return;
//First write the number of bindings
file << bindings.size() << std::endl;
for (auto& b : bindings)
{
//Name
file << b.first << std::endl;
//Data
auto& lbd = b.second;
file << static_cast<int>(lbd.bindingType) << std::endl;
file << static_cast<int>(lbd.inverted) << std::endl;
file << lbd.gravity << std::endl;
file << lbd.dead << std::endl;
file << lbd.sensitivity << std::endl;
file << static_cast<int>(lbd.snap) << std::endl;
//Bindings
file << lbd.positiveKeyCodes.size() << std::endl;
for (auto kc : lbd.positiveKeyCodes)
file << static_cast<int>(kc) << std::endl;
file << lbd.negativeKeyCodes.size() << std::endl;
for (auto kc : lbd.negativeKeyCodes)
file << static_cast<int>(kc) << std::endl;
file << lbd.positiveControllerCodes.size() << std::endl;
for (auto cc : lbd.positiveControllerCodes)
file << static_cast<int>(cc) << std::endl;
file << lbd.negativeControllerCodes.size() << std::endl;
for (auto cc : lbd.negativeControllerCodes)
file << static_cast<int>(cc) << std::endl;
}
file.close();
}
void SHInputManager::LoadBindings(std::string const& sourceFile) noexcept
{
std::ifstream file;
file.open(sourceFile);
//Check
if (!file) return;
//Erase
ClearBindings();
//Read
std::string read;
int count = 0;
std::getline(file, read);
count = std::stoi(read);
std::string bindingName;
for (int b = 0; b < count; ++b)
{
//Name
std::getline(file, read);
bindingName = read;
AddBinding(bindingName);
//Type
std::getline(file, read);
SetBindingType(bindingName, static_cast<SH_BINDINGTYPE>(std::stoi(read)));
//Inversion
std::getline(file, read);
SetBindingInverted(bindingName, static_cast<bool>(std::stoi(read)));
//Gravity
std::getline(file, read);
SetBindingGravity(bindingName, std::stod(read));
//Dead
std::getline(file, read);
SetBindingDead(bindingName, std::stod(read));
//Sensitivity
std::getline(file, read);
SetBindingSensitivity(bindingName, std::stod(read));
//Snap
std::getline(file, read);
SetBindingSnap(bindingName, static_cast<bool>(std::stoi(read)));
int count = 0;
//Positive Key Codes
std::getline(file, read);
count = std::stoi(read);
for (int i = 0; i < count; ++i)
{
std::getline(file, read);
AddBindingPositiveKeyCode(bindingName, static_cast<SH_KEYCODE>(std::stoi(read)));
}
//Negative Key Codes
std::getline(file, read);
count = std::stoi(read);
for (int i = 0; i < count; ++i)
{
std::getline(file, read);
AddBindingNegativeKeyCode(bindingName, static_cast<SH_KEYCODE>(std::stoi(read)));
}
//Positive Controller Codes
std::getline(file, read);
count = std::stoi(read);
for (int i = 0; i < count; ++i)
{
std::getline(file, read);
AddBindingPositiveControllerCode(bindingName, static_cast<SH_CONTROLLERCODE>(std::stoi(read)));
}
//Negative Controller Codes
std::getline(file, read);
count = std::stoi(read);
for (int i = 0; i < count; ++i)
{
std::getline(file, read);
AddBindingNegativeControllerCode(bindingName, static_cast<SH_CONTROLLERCODE>(std::stoi(read)));
}
}
file.close();
}
void SHInputManager::UpdateInput(double dt) noexcept
{
//Keyboard and Mouse Buttons////////////////////////////////////////////////

View File

@ -14,6 +14,7 @@
#include <map>
#include <set>
#include "../../SHADE_Managed/src/SHpch.h"
#include "../../SHADE_Engine/src/Assets/SHAssetMacros.h"
#include "SH_API.h"
#pragma comment(lib, "xinput.lib")
@ -681,6 +682,17 @@ namespace SHADE
return controllersReleasedTime[controllerNum][static_cast<size_t>(code)];
}
/*------------------------------------------------------------------------*/
/* Binding I/O */
/*------------------------------------------------------------------------*/
//Save bindings registered into a file
static void SaveBindings(std::string const& targetFile = std::string(ASSET_ROOT) + "/Bindings.SHConfig") noexcept;
//Load and register bindings from a file
//If specified file exists, the current list of bindings will be overwritten, so save them somewhere else before loading
static void LoadBindings(std::string const& sourceFile = std::string(ASSET_ROOT) + "/Bindings.SHConfig") noexcept;
/*------------------------------------------------------------------------*/
/* Binding Functions */
/*------------------------------------------------------------------------*/

View File

@ -35,7 +35,17 @@ namespace SHADE
: position { pos }
, orientation { SHQuaternion::FromEuler(rot) }
, scale { scl }
{}
{
ComputeTRS();
}
SHTransform::SHTransform(const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl) noexcept
: position { pos }
, orientation { quat }
, scale { scl }
{
ComputeTRS();
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */

View File

@ -201,6 +201,7 @@ namespace SHADE
AddComponentToComponentNode<SHCanvasComponent>(components, eid);
AddComponentToComponentNode<SHButtonComponent>(components, eid);
AddComponentToComponentNode<SHToggleButtonComponent>(components, eid);
AddComponentToComponentNode<SHTextRenderableComponent>(components, eid);
@ -258,6 +259,7 @@ namespace SHADE
AddComponentID<SHCanvasComponent>(componentIDList, componentsNode);
AddComponentID<SHButtonComponent>(componentIDList, componentsNode);
AddComponentID<SHToggleButtonComponent>(componentIDList, componentsNode);
AddComponentID<SHTextRenderableComponent>(componentIDList, componentsNode);
return componentIDList;
@ -339,6 +341,7 @@ namespace SHADE
SHSerializationHelper::InitializeComponentFromNode<SHCanvasComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHButtonComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHToggleButtonComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHTextRenderableComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid);
}

View File

@ -128,6 +128,10 @@ namespace SHADE
dbgDrawSys->DrawWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested);
}
void SHDebugDraw::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested)
{
dbgDrawSys->DrawWireCapsule(position, rotation, height, radius, color, depthTested);
}
/*-----------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*-----------------------------------------------------------------------------------*/
@ -216,6 +220,10 @@ namespace SHADE
dbgDrawSys->DrawPersistentWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested);
}
void SHDebugDraw::Persistent::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested)
{
dbgDrawSys->DrawPersistentWireCapsule(position, rotation, height, radius, color, depthTested);
}
void SHDebugDraw::Persistent::ClearDraws()
{
dbgDrawSys->ClearPersistentDraws();

View File

@ -194,6 +194,18 @@ namespace SHADE
/// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false);
/// <summary>
/// Draws the outline of a capsule.
/// This will remain drawn until ClearDraws() is called.
/// </summary>
/// <param name="position">Position of the wireframe capsule.</param>
/// <param name="rotation">Rotation of the capsule.</param>
/// <param name="height">Height of the overall capsule.</param>
/// <param name="radius">Radius of the capsule.</param>
/// <param name="color"></param>
/// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
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" */
@ -366,6 +378,18 @@ namespace SHADE
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false);
/// <summary>
/// Draws the outline of a capsule.
/// This will remain drawn until ClearDraws() is called.
/// </summary>
/// <param name="position">Position of the wireframe capsule.</param>
/// <param name="rotation">Rotation of the capsule.</param>
/// <param name="height">Height of the overall capsule.</param>
/// <param name="radius">Radius of the capsule.</param>
/// <param name="color"></param>
/// <param name="color">Colour to draw with.</param>
/// <param name="depthTested">Whether or not drawn object will be occluded.</param>
static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false);
/// <summary>
/// Clears any persistent drawn debug primitives.
/// </summary>
static void ClearDraws();

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
{
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)
{
}

View File

@ -18,7 +18,6 @@ namespace SHADE
virtual ~SHButtonComponent() = default;
SHVec2 size;
SHVec2 offset;
AssetID GetClickedTexture() const noexcept;
AssetID GetDefaultTexture() const noexcept;
@ -33,8 +32,10 @@ namespace SHADE
friend class SHUISystem;
private:
//Set to true when mouse is hovering over the button.
bool isHovered;
//This is set to true when the mouse clicks down, and set back to false when mouse releases.
//The event for the button click will be broadcasted when mouse release.
bool isClicked;
AssetID defaultTexture;
AssetID hoveredTexture;

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/SHEditor.h"
#include "Resource/SHResourceManager.h"
#include "Assets/SHAssetManager.h"
#include "Input/SHInputManager.h"
#include "SHUIComponent.h"
#include "SHButtonComponent.h"
#include "SHToggleButtonComponent.h"
#include "SHSliderComponent.h"
#include "SHCanvasComponent.h"
#include "Events/SHEventManager.hpp"
#include "Events/SHButtonClickEvent.h"
namespace SHADE
{
@ -103,7 +111,7 @@ namespace SHADE
{
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(comp.GetEID());
if (canvasComp != nullptr)
comp.localToCanvasMatrix = canvasComp->GetMatrix()* transform->GetTRS();
comp.localToCanvasMatrix = transform->GetTRS() * canvasComp->GetMatrix();
else
comp.localToCanvasMatrix = transform->GetTRS();
}
@ -139,77 +147,235 @@ namespace SHADE
void SHUISystem::UpdateButtonComponent(SHButtonComponent& comp) noexcept
{
if (!SHComponentManager::HasComponent<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;
}
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
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 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f);
SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f);
SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f);
SHVec2 topExtent{ topExtent4.x,-topExtent4.y };
SHVec2 btmExtent{ btmExtent4.x,-btmExtent4.y };
SHVec2 topExtent{ topExtent4.x,topExtent4.y };
SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y };
SHVec2 windowSize;
SHVec2 mousePos;
SHVec2 windowSize;
#ifdef SHEDITOR
windowSize = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>()->windowSize;
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)
#endif
SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0).x , cameraSystem->GetCameraWidthHeight(0).y };
topExtent += camSize * 0.5f;
btmExtent += camSize * 0.5f;
//Convert everything to using ratios
topExtent /= camSize;
btmExtent /= camSize;
#else
int x, y;
SHInputManager::GetMouseScreenPosition(&x, &y);
mousePos.x = x;
mousePos.y = y;
auto ws = SHSystemManager::GetSystem<SHGraphicsSystem>()->GetWindow()->GetWindowSize();
windowSize = { ws.first,ws.second };
mousePos /= windowSize;
#endif
SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) };
topExtent = CanvasToScreenPoint(topExtent,true);
btmExtent = CanvasToScreenPoint(btmExtent, true);
//SHLOG_INFO("mousePos: {} , {}", mousePos.x, mousePos.y);
comp.isClicked = false;
if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x
&& mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y)
{
comp.isHovered = true;
if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB))
#ifdef SHEDITOR
if (SHSystemManager::GetSystem<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;
}
//SHLOG_INFO("BUTTON HOVERED");
#endif
}
else
{
comp.isHovered = false;
//SHLOG_INFO("BUTTON NOT HOVERED")
}
if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB))
{
comp.isClicked = false;
comp.value = !comp.value;
SHButtonClickEvent clickEvent;
clickEvent.EID = comp.GetEID();
clickEvent.value = comp.value;
SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT);
}
if (SHComponentManager::HasComponent<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 material = renderable->GetModifiableMaterial();
//material->SetProperty("texture", comp.GetDefaultTexture());
auto material = renderable->GetModifiableMaterial();
if (comp.GetValue() == false)
{
if (comp.GetDefaultTexture()!= 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE)
{
material->SetProperty("data.textureIndex", comp.GetDefaultTexture());
//SHLOG_INFO("SETTING DEFAULT TEXTURE")
}
}
else
{
if (comp.GetToggledTexture() != 0 && SHAssetManager::GetType(comp.GetToggledTexture()) == AssetType::TEXTURE)
{
material->SetProperty("data.textureIndex", comp.GetToggledTexture());
//SHLOG_INFO("SETTING DEFAULT TEXTURE")
}
}
}
}
void SHUISystem::UpdateButtonsRoutine::Execute(double dt) noexcept
{
SHUISystem* system = (SHUISystem*)GetSystem();
@ -219,6 +385,34 @@ namespace SHADE
if (SHSceneManager::CheckNodeAndComponentsActive<SHButtonComponent>(comp.GetEID()))
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

View File

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

View File

@ -107,8 +107,7 @@ namespace SHADE
Vector3 Transform::Forward::get()
{
const SHVec3 DIRECTION = SHVec3::Rotate(-SHVec3::UnitZ, Convert::ToNative(GlobalRotation));
return Convert::ToCLI(DIRECTION);
return Vector3::Rotate(Vector3::Forward, GlobalRotation);
}
/*-----------------------------------------------------------------------------------*/

View File

@ -167,6 +167,10 @@ namespace SHADE
{
return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(axis), radians));
}
Vector3 Vector3::Rotate(Vector3 vec, Quaternion quat)
{
return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(quat)));
}
Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
{
float lx = lhs.x, rx = rhs.x;

View File

@ -19,10 +19,17 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes
#include "Vector2.hxx"
value struct Quaternion;
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-------------------------------------------------------------------------- --- */
value struct Quaternion;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------- --- */
///<summary>
/// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector.
/// Designed to closely match Unity's Vector3 struct.
@ -308,6 +315,12 @@ namespace SHADE
/// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 Rotate(Vector3 vec, Vector3 axis, float radians);
/// <summary>
/// Rotates a Vector3 using a Quaternion.
/// </summary>
/// <param name="vec">A Vector3 to rotate.</param>
/// <param name="quat">A Quaternion to rotate the vector with.</param>
static Vector3 Rotate(Vector3 vec, Quaternion quat);
/// <summary>
/// Computes and returns a Vector3 that is made from the smallest components of
/// the two specified Vector3s.
/// </summary>