Merge branch 'main' into SP3-6-c-scripting

This commit is contained in:
Kah Wei 2022-10-27 10:12:52 +08:00
commit d2c7630af4
61 changed files with 2489 additions and 1090 deletions

View File

@ -4,13 +4,13 @@ Size=1920,20
Collapsed=0
[Window][SHEditorMenuBar]
Pos=0,24
Size=1920,1036
Pos=0,48
Size=1920,1012
Collapsed=0
[Window][Hierarchy Panel]
Pos=0,120
Size=225,940
Pos=0,197
Size=308,863
Collapsed=0
DockId=0x00000004,0
@ -20,29 +20,96 @@ Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1686,24
Size=234,1036
Pos=1528,48
Size=392,1012
Collapsed=0
DockId=0x00000006,0
[Window][Profiler]
Pos=0,24
Size=225,94
Pos=0,48
Size=308,147
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=227,24
Size=1457,1036
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x00000002,0
DockId=0x0000000B,0
[Window][ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌð‡Žoû]
Pos=60,60
Size=32,64
Collapsed=0
[Window][ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ]
Pos=60,60
Size=999,581
Collapsed=0
[Window][ð‡]
Pos=60,60
Size=32,64
Collapsed=0
[Window][ÌÌÌÌ]
Pos=60,60
Size=553,422
Collapsed=0
[Window][]
Pos=60,60
Size=770,394
Collapsed=0
[Window][ Viewport]
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x0000000B,0
[Window][ Viewport]
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x0000000B,0
[Window][î<> Viewport]
Pos=310,48
Size=1216,715
Collapsed=0
DockId=0x0000000B,0
[Window][V]
Pos=310,722
Size=1501,338
Collapsed=0
DockId=0x00000008,0
[Window][p£€Ê]
Pos=310,750
Size=1501,310
Collapsed=0
DockId=0x0000000A,0
[Window][ Asset Browser]
Pos=310,765
Size=1216,295
Collapsed=0
DockId=0x0000000C,0
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1526,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=308,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1216,1036 Split=Y Selected=0xB41284E7
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=1501,672 Split=Y Selected=0xB41284E7
DockNode ID=0x00000009 Parent=0x00000007 SizeRef=1501,700 Split=Y Selected=0xB41284E7
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=1501,715 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=1501,295 Selected=0xB128252A
DockNode ID=0x0000000A Parent=0x00000007 SizeRef=1501,310 Selected=0xD446F7B6
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1501,338 Selected=0xD9F31532
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=392,1036 Selected=0xE7039252

View File

@ -1,54 +0,0 @@
[Window][MainStatusBar]
Pos=0,1060
Size=1920,20
Collapsed=0
[Window][SHEditorMenuBar]
Pos=0,48
Size=1920,1012
Collapsed=0
[Window][Hierarchy Panel]
Pos=0,142
Size=387,918
Collapsed=0
DockId=0x00000004,0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1649,48
Size=271,1012
Collapsed=0
DockId=0x00000006,0
[Window][Profiler]
Pos=0,48
Size=387,92
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=648,48
Size=2519,1319
Collapsed=0
DockId=0x00000002,0
[Window][ Viewport]
Pos=389,48
Size=1258,1012
Collapsed=0
DockId=0x00000002,0
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=387,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1258,1036 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252

View File

@ -56,8 +56,8 @@ namespace Sandbox
_In_ INT nCmdShow
)
{
// Set working directory
SHFileUtilities::SetWorkDirToExecDir();
// Set working directory
SHFileUtilities::SetWorkDirToExecDir();
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
@ -152,16 +152,16 @@ namespace Sandbox
SHSceneManager::SceneUpdate(0.016f);
#endif
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
//editor->PollPicking();
editor->PollPicking();
}
// Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution();
graphicsSystem->AwaitGraphicsExecution();
}
void SBApplication::Exit(void)
{
#ifdef SHEDITOR
#ifdef SHEDITOR
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
#endif

View File

@ -12,6 +12,7 @@
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h"
#include "Camera/SHCameraComponent.h"
@ -158,6 +159,7 @@ namespace Sandbox
scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase");
SHComponentManager::AddComponent<SHCameraComponent>(0);
SHComponentManager::AddComponent<SHLightComponent>(0);
SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
SHComponentManager::RemoveComponent <SHColliderComponent>(0);
}

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHAssetBrowser.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include "Assets/SHAssetManager.h"
#include "Editor/DragDrop/SHDragDrop.hpp"
namespace SHADE
{
SHAssetBrowser::SHAssetBrowser()
:SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar)
{
}
void SHAssetBrowser::Init()
{
SHEditorWindow::Init();
}
void SHAssetBrowser::Update()
{
SHEditorWindow::Update();
if(Begin())
{
DrawMenuBar();
auto const& assets = SHAssetManager::GetAllAssets();
if(ImGui::BeginTable("AssetBrowserTable", 3))
{
ImGui::TableNextColumn();
ImGui::TableHeader("Asset ID");
ImGui::TableNextColumn();
ImGui::TableHeader("Name");
ImGui::TableNextColumn();
ImGui::TableHeader("Type");
for(SHAsset const& asset : assets)
{
DrawAsset(asset);
}
ImGui::EndTable();
}
}
ImGui::End();
}
void SHAssetBrowser::DrawMenuBar()
{
if(ImGui::BeginMenuBar())
{
ImGui::EndMenuBar();
}
}
void SHAssetBrowser::DrawAsset(SHAsset const& asset)
{
ImGui::PushID(asset.id);
ImGui::BeginGroup();
ImGui::TableNextColumn();
ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns);
if(SHDragDrop::BeginSource())
{
auto id = asset.id;
ImGui::Text("Moving Asset: %zu", id);
SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id);
SHDragDrop::EndSource();
}
ImGui::TableNextColumn();
ImGui::Text("%s", asset.name.c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "Type");
ImGui::EndGroup();
ImGui::PopID();
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "Assets/SHAsset.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHAssetBrowser final : public SHEditorWindow
{
public:
SHAssetBrowser();
void Init();
void Update();
void Refresh();
private:
void DrawMenuBar();
void DrawAsset(SHAsset const& asset);
float idColumnWidth, nameColumnWidth, typeColumnWidth;
};
}

View File

@ -93,8 +93,7 @@ namespace SHADE
{
if (ImGui::BeginMenuBar())
{
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
if(ImGui::SmallButton(ICON_MD_DESELECT))
{
auto editor = SHSystemManager::GetSystem<SHEditor>();

View File

@ -39,6 +39,10 @@ namespace SHADE
{
SHComponentManager::RemoveComponent<T>(component->GetEID());
}
if (ImGui::Selectable(std::format("{} Reset {}", ICON_MD_RESTART_ALT, componentName.data()).data()))
{
*component = T();
}
ImGui::EndPopup();
}
}
@ -48,7 +52,7 @@ namespace SHADE
if (!component)
return;
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
@ -89,7 +93,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax)
{
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMin.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMax.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
}
else
{
@ -115,7 +119,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMin.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMax.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
@ -128,7 +132,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMin.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMax.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
@ -141,7 +145,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMin.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMax.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
@ -152,13 +156,18 @@ namespace SHADE
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
float min{}, max{};
if(metaMin.is_valid())
min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f);
if(metaMax.is_valid())
max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value<float>(), metaMin.template get_value<float>(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
}
else
{
SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, "Test");
}
}
else if (type == rttr::type::get<double>())
@ -167,7 +176,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMin.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMax.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
}
else
{

View File

@ -35,6 +35,23 @@ namespace SHADE
return selected;
}
template <typename ComponentType, typename EnforcedComponent, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true, std::enable_if_t<std::is_base_of_v<SHComponent, EnforcedComponent>, bool> = true>
bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid)
{
bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
{
if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
SHComponentManager::AddComponent<EnforcedComponent>(eid);
SHComponentManager::AddComponent<ComponentType>(eid);
}
}
return selected;
}
SHEditorInspector::SHEditorInspector()
:SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar)
{
@ -84,21 +101,19 @@ namespace SHADE
}
ImGui::Separator();
// Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid);
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid);
ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{
DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid);
DrawAddComponentButton<SHColliderComponent>(eid);
if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
{
if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr)
{
SHComponentManager::AddComponent<SHTransformComponent>(eid);
}
}
// Components that require Transforms
DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
ImGui::EndMenu();
}

View File

@ -3,4 +3,5 @@
#include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel
#include "Inspector/SHEditorInspector.h" //Inspector
#include "Profiling/SHEditorProfiler.h" //Profiler
#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport
#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport
#include "AssetBrowser/SHAssetBrowser.h" //Asset Browser

View File

@ -24,12 +24,13 @@ namespace SHADE
void SHEditorViewport::Init()
{
SHEditorWindow::Init();
transformGizmo.Init();
}
void SHEditorViewport::Update()
{
SHEditorWindow::Update();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
if(Begin())
{
ImGuizmo::SetDrawlist();
@ -55,7 +56,7 @@ namespace SHADE
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
transformGizmo.Draw();
ImGui::End();
ImGui::PopStyleVar();
}
void SHEditorViewport::Exit()

View File

@ -13,6 +13,12 @@
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
namespace SHADE
{
void SHTransformGizmo::Init()
{
auto& style = ImGuizmo::GetStyle();
style.RotationLineThickness = 2.5f;
}
void SHTransformGizmo::Draw()
{
bool justChangedTfm = false;
@ -26,9 +32,12 @@ namespace SHADE
SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
//Invert projection y-axis
proj(1, 1) *= -1;
static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
//ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f);
if (selectedEntityTransformComponent == nullptr)
{
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
@ -55,31 +64,37 @@ namespace SHADE
return;
SHMatrix mat = selectedEntityTransformComponent->GetTRS();
isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11);
if (!justChangedTfm)
useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
if(useSnap)
{
if (ImGui::IsItemClicked())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})));
else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})), true);
switch (operation)
{
case Operation::TRANSLATE: snap = &translationSnap.x; break;
case Operation::ROTATE: snap = &rotationSnap; break;
case Operation::SCALE: snap = &scaleSnap; break;
default: snap = &translationSnap.x;
}
}
ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11, nullptr, useSnap ? snap : nullptr);
static bool startRecording = false;
if (!justChangedTfm && ImGuizmo::IsUsing())
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = (selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})), startRecording);
if(!startRecording)
startRecording = true;
}
isManipulating = ImGuizmo::IsUsing() || startRecording;
if(startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false;
}
}

View File

@ -37,11 +37,17 @@ namespace SHADE
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
};
void Init();
void Draw();
bool isManipulating = false;
bool useSnap = false;
Mode mode = Mode::WORLD;
Operation operation = Operation::TRANSLATE;
private:
float scaleSnap = 0.25f;
float rotationSnap = 1.0f;
SHVec3 translationSnap = SHVec3(0.25f, 0.25f, 0.25f);
float* snap = nullptr;
SHTransformComponent* selectedEntityTransformComponent{nullptr};
SHCameraComponent* editorCamera{nullptr};
};

View File

@ -92,6 +92,7 @@ namespace SHADE
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
io = &ImGui::GetIO();
@ -134,7 +135,7 @@ namespace SHADE
}
}
PollPicking();
//PollPicking();
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{

View File

@ -40,7 +40,6 @@ namespace SHADE
{
ImGui::BeginGroup();
auto cursorPos = ImGui::GetCursorScreenPos();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
@ -158,7 +157,7 @@ namespace SHADE
}
template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
static bool DragN(const std::string& label, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0, bool* isHovered = nullptr)
{
@ -169,13 +168,13 @@ namespace SHADE
const ImGuiContext& g = *GImGui;
bool valueChanged = false;
ImGui::BeginGroup();
ImGui::PushID(fieldLabel.c_str());
ImGui::PushID(label.c_str());
PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(fieldLabel.c_str());
ImGui::Text(label.c_str());
if (isHovered)
*isHovered = ImGui::IsItemHovered();
*isHovered = ImGui::IsItemHovered();
ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i)
{
@ -203,75 +202,91 @@ namespace SHADE
return valueChanged;
}
static bool DragVec2(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
static bool DragVec2(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec2 values = get();
bool changed = false;
if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false;
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
static bool DragVec3(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
static bool DragVec3(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec3 values = get();
bool changed = false;
if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
SHVec3 old = get();
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
static bool DragVec4(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
static bool DragVec4(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec4 values = get();
bool changed = false;
if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
bool const changed = DragN<float, 4>(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
@ -279,173 +294,325 @@ namespace SHADE
//|| Widget Extensions ||
//#==============================================================#
static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
static void TextLabel(std::string_view const& text, bool sameLine = true)
{
const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true);
if(textSize.x > 0.0f)
{
ImGui::Text(text.data());
ImGui::SameLine();
}
}
static bool CheckBox(std::string_view const& label, std::function<bool(void)> get, std::function<void(bool const&)> set, std::string_view const& tooltip = {})
{
bool value = get();
if (ImGui::Checkbox(label.c_str(), &value))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::Checkbox("##", &value))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true;
}
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return false;
}
template<typename T>
static bool RadioButton(std::vector<std::string> const& listLabels, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set)
static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set ,std::string_view const& tooltip = {})
{
T type = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
for (size_t i = 0; i < listTypes.size(); i++)
{
if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
}
ImGui::SameLine();
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return true;
}
static bool InputText(const std::string& label, const std::function<std::string(void)> get,
const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0,
ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
const std::function<void(std::string)> set, std::string_view const& tooltip = {},
ImGuiInputTextFlags flag = 0, ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
{
std::string text = get();
if (ImGui::InputText(label.c_str(), &text, flag, callback, userData))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::InputText("##", &text, flag, callback, userData))
{
if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true;
}
return false;
}
template <typename T>
static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
std::cout << value << " \n";
//bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags))
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
return true;
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return false;
}
static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set,
template <typename T>
static bool DragScalar(const std::string& label, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, ImGuiSliderFlags flags = 0)
{
T value = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragScalar("##", data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
static bool DragFloat(const std::string_view& label, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragFloat("##", &value, speed, p_min, p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
return true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
return false;
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set,
static bool DragInt(const std::string& label, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragInt("##", &value, speed, p_min, p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
return true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
return false;
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
template <typename T>
static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set,
static bool SliderScalar(const std::string& label, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderScalar("##", data_type, &value, &min, &max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
return true;
}
return false;
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float const&)> set,
static bool SliderFloat(const std::string& label, float const& min, float const& max, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderFloat("##", &value, min, max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
return true;
}
return false;
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set,
static bool SliderInt(const std::string& label, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderInt("##", &value, min, max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
return true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
return false;
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set)
static bool ComboBox(const std::string& label, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {})
{
bool edited = false;
int selected = get();
ImGui::PushID(fieldLabel.c_str());
ImGui::Text(fieldLabel.c_str()); ImGui::SameLine();
ImGui::BeginGroup();
ImGui::PushID(label.c_str());
TextLabel(label);
ImGui::SameLine();
if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size())))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false);
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return edited;
}
};

View File

@ -11,3 +11,6 @@ constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 };
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 };
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 };
constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 6 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 };

View File

@ -12,6 +12,7 @@
#include "SHpch.h"
#include "SHEvent.h"
#include "SHEventReceiver.h"
#include "SH_API.h"
/******************************************************************************
INSTRUCTIONS FOR USE:
@ -67,7 +68,7 @@ namespace SHADE
using EventManagerListener = std::function<void(SHEvent)>;
class SHEventManager
class SH_API SHEventManager
{
private:

View File

@ -49,7 +49,7 @@ namespace SHADE
SHVkSampler::~SHVkSampler() noexcept
{
if (vkSampler)
device->GetVkLogicalDevice().destroySampler();
device->GetVkLogicalDevice().destroySampler(vkSampler);
}
/*-----------------------------------------------------------------------------------*/

View File

@ -155,7 +155,7 @@ namespace SHADE
SHVkDebugMessenger::GenMessengerType(SH_DEBUG_MSG_TYPE::T_GENERAL, SH_DEBUG_MSG_TYPE::T_VALIDATION, SH_DEBUG_MSG_TYPE::T_PERFORMANCE));
instanceDbgInfo.pfnUserCallback = SHVulkanDebugUtil::GenericDebugCallback;
instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo);
//instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo);
}
// Finally create the instance

View File

@ -30,200 +30,200 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/
SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
/*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/
SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
: pipeline{ pipeline }
{
if (!pipeline)
throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
{
if (!pipeline)
throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
// Mark all as dirty
setAllDirtyFlags();
// Mark all as dirty
setAllDirtyFlags();
}
void SHBatch::Add(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Create one if not found
if (subBatch == subBatches.end())
{
subBatches.emplace_back(renderable->Mesh);
subBatch = subBatches.end() - 1;
}
void SHBatch::Add(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Add renderable in
subBatch->Renderables.insert(renderable->GetEID());
// Create one if not found
if (subBatch == subBatches.end())
// Also add material instance in
referencedMatInstances.insert(renderable->GetMaterial());
// Mark all as dirty
setAllDirtyFlags();
}
void SHBatch::Remove(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Attempt to remove if it exists
if (subBatch == subBatches.end())
return;
subBatch->Renderables.erase(renderable->GetEID());
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
for (const auto& sb : subBatches)
for (const auto& rendId : sb.Renderables)
{
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend)
{
subBatches.emplace_back(renderable->Mesh);
subBatch = subBatches.end() - 1;
if (rend->GetMaterial() == renderable->GetMaterial())
{
matUnused = false;
break;
}
}
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
}
// Add renderable in
subBatch->Renderables.insert(renderable->GetEID());
// Material is no longer in this library, so we remove it
if (matUnused)
referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
// Also add material instance in
referencedMatInstances.insert(renderable->GetMaterial());
// Mark all as dirty
setAllDirtyFlags();
}
// Mark all as dirty
setAllDirtyFlags();
void SHBatch::Clear()
{
subBatches.clear();
// Clear CPU buffers
drawData.clear();
transformData.clear();
instancedIntegerData.clear();
matPropsData.reset();
matPropsDataSize = 0;
// Clear GPU buffers
for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
instancedIntegerBuffer[i].Free();
matPropsBuffer[i].Free();
}
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
void SHBatch::Remove(const SHRenderable* renderable)
// Check if there are even material properties to update
if (!matPropsData)
return;
// Check if any materials have changed
bool hasChanged = false;
for (const auto& material : referencedMatInstances)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Attempt to remove if it exists
if (subBatch == subBatches.end())
return;
subBatch->Renderables.erase(renderable->GetEID());
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
for (const auto& sb : subBatches)
for (const auto& rendId : sb.Renderables)
{
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend)
{
if (rend->GetMaterial() == renderable->GetMaterial())
{
matUnused = false;
break;
}
}
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
}
// Material is no longer in this library, so we remove it
if (matUnused)
referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
// Mark all as dirty
setAllDirtyFlags();
if (material->HasChanged())
{
hasChanged = true;
break;
}
}
void SHBatch::Clear()
// We need to update all the material buffers if the materials have changed
if (hasChanged)
{
subBatches.clear();
// Clear CPU buffers
drawData.clear();
transformData.clear();
eidData.clear();
matPropsData.reset();
matPropsDataSize = 0;
// Clear GPU buffers
for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
eidBuffer[i].Free();
matPropsBuffer[i].Free();
}
for (auto& dirt : matBufferDirty)
dirt = true;
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Check if this frame's buffer is dirty
if (!matBufferDirty[frameIndex])
return;
// Check if there are even material properties to update
if (!matPropsData)
return;
// Check if any materials have changed
bool hasChanged = false;
for (const auto& material : referencedMatInstances)
// Build CPU Buffer
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (renderable)
{
if (material->HasChanged())
{
hasChanged = true;
break;
}
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
}
// We need to update all the material buffers if the materials have changed
if (hasChanged)
else
{
for (auto& dirt : matBufferDirty)
dirt = true;
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
propsCurrPtr += singleMatPropAlignedSize;
}
// Check if this frame's buffer is dirty
if (!matBufferDirty[frameIndex])
return;
// Transfer to GPU
rebuildMaterialBuffers(frameIndex, descPool);
// Build CPU Buffer
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (renderable)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
}
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
propsCurrPtr += singleMatPropAlignedSize;
}
// Transfer to GPU
rebuildMaterialBuffers(frameIndex, descPool);
// This frame is updated
matBufferDirty[frameIndex] = false;
}
// This frame is updated
matBufferDirty[frameIndex] = false;
}
void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Reset Transform Data
transformData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(rendId);
if (transform)
{
transformData.emplace_back(transform->GetTRS());
}
else
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
}
// Transfer to GPU
if (transformDataBuffer[frameIndex])
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
void SHBatch::UpdateEIDBuffer(uint32_t frameIndex)
// Reset Transform Data
transformData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(rendId);
if (transform)
{
transformData.emplace_back(transform->GetTRS());
}
else
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
}
// Transfer to GPU
if (transformDataBuffer[frameIndex])
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
}
void SHBatch::UpdateInstancedIntegerBuffer(uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -232,233 +232,244 @@ namespace SHADE
}
// Reset Transform Data
eidData.clear();
instancedIntegerData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
eidData.emplace_back(rendId);
}
for (auto rendId : subBatch.Renderables)
{
auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
rendId,
renderable->GetLightLayer()
}
);
}
// Transfer to GPU
if (eidBuffer[frameIndex])
eidBuffer[frameIndex]->WriteToMemory(eidData.data(), static_cast<EntityID>(eidData.size() * sizeof(EntityID)), 0, 0);
if (instancedIntegerBuffer[frameIndex])
instancedIntegerBuffer[frameIndex]->WriteToMemory(instancedIntegerData.data(), static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData)), 0, 0);
}
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
return;
}
// Save logical device
device = _device;
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
// Count number of elements
size_t numTotalElements = 0;
for (const auto& subBatch : subBatches)
{
numTotalElements += subBatch.Renderables.size();
}
// Generate CPU buffers if there are changes
if (isCPUBuffersDirty)
{
// - Draw data
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
eidData.reserve(numTotalElements);
eidData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
matPropsDataSize = matPropTotalBytes;
}
}
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
const uint32_t CURR_INSTANCES = static_cast<uint32_t>(subBatch.Renderables.size());
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = CURR_INSTANCES,
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
});
nextInstanceIndex += CURR_INSTANCES;
// Fill in buffers (CPU)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(rendId);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
eidData.emplace_back(rendId);
// Material Properties
if (!EMPTY_MAT_PROPS)
{
const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (renderable)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
}
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
}
// Send all buffered data to the GPU buffers
using BuffUsage = vk::BufferUsageFlagBits;
// - Draw Data
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(eidData.size() * sizeof(EntityID));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, eidBuffer[frameIndex], eidData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
return;
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
// Save logical device
device = _device;
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset { 0 };
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::EID, eidBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex])
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
// Count number of elements
size_t numTotalElements = 0;
for (const auto& subBatch : subBatches)
{
numTotalElements += subBatch.Renderables.size();
}
// Generate CPU buffers if there are changes
if (isCPUBuffersDirty)
{
// - Draw data
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
instancedIntegerData.reserve(numTotalElements);
instancedIntegerData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
SH_PIPELINE_TYPE::GRAPHICS,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
matPropsData.reset(new char[matPropTotalBytes]);
matPropsDataSize = matPropTotalBytes;
}
}
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
const uint32_t CURR_INSTANCES = static_cast<uint32_t>(subBatch.Renderables.size());
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = CURR_INSTANCES,
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
});
nextInstanceIndex += CURR_INSTANCES;
// Fill in buffers (CPU)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(rendId);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
rendId,
renderable->GetLightLayer()
}
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::setAllDirtyFlags()
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
// Material Properties
if (!EMPTY_MAT_PROPS)
{
if (renderable)
{
matPropsDescSet[frameIndex] = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
}
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] };
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
bufferList,
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
}
// Send all buffered data to the GPU buffers
using BuffUsage = vk::BufferUsageFlagBits;
// - Draw Data
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset{ 0 };
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
SH_PIPELINE_TYPE::GRAPHICS,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::setAllDirtyFlags()
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{
matPropsDescSet[frameIndex] = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
}
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] };
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
bufferList,
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
}
}
}

View File

@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/SHMatrix.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "ECS_Base/SHECSMacros.h"
#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
namespace SHADE
{
@ -79,7 +80,7 @@ namespace SHADE
void Clear();
void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void UpdateTransformBuffer(uint32_t frameIndex);
void UpdateEIDBuffer(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);
@ -111,7 +112,7 @@ namespace SHADE
// CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::vector<EntityID> eidData;
std::vector<SHInstancedIntegerData> instancedIntegerData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0;
@ -120,7 +121,7 @@ namespace SHADE
// GPU Buffers
TripleBuffer drawDataBuffer;
TripleBuffer transformDataBuffer;
TripleBuffer eidBuffer;
TripleBuffer instancedIntegerBuffer;
TripleBuffer matPropsBuffer;
TripleDescSet matPropsDescSet;

View File

@ -85,7 +85,7 @@ namespace SHADE
{
batch.UpdateMaterialBuffer(frameIndex, descPool);
batch.UpdateTransformBuffer(frameIndex);
batch.UpdateEIDBuffer(frameIndex);
batch.UpdateInstancedIntegerBuffer(frameIndex);
}
}

View File

@ -4,6 +4,8 @@
#include "Graphics/Pipeline/SHPipelineState.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/MiddleEnd/Lights/SHLightData.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
@ -45,16 +47,35 @@ namespace SHADE
// For global data (generic data and textures)
Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding });
SHVkDescriptorSetLayout::Binding lightBinding
std::vector<SHVkDescriptorSetLayout::Binding> lightBindings{};
for (uint32_t i = 0; i < SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i)
{
.Type = vk::DescriptorType::eStorageBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eFragment,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::LIGHTS_DATA,
.DescriptorCount = 1,
};
lightBindings.push_back (SHVkDescriptorSetLayout::Binding
{
.Type = vk::DescriptorType::eStorageBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eFragment,
.BindPoint = i,
.DescriptorCount = 1,
});
}
//SHVkDescriptorSetLayout::Binding pointLightBinding
//{
// .Type = vk::DescriptorType::eStorageBufferDynamic,
// .Stage = vk::ShaderStageFlagBits::eFragment,
// .BindPoint = SHGraphicsConstants::DescriptorSetBindings::POINT_LIGHT_DATA,
// .DescriptorCount = 1,
//};
//SHVkDescriptorSetLayout::Binding spotLightBinding
//{
// .Type = vk::DescriptorType::eStorageBufferDynamic,
// .Stage = vk::ShaderStageFlagBits::eFragment,
// .BindPoint = SHGraphicsConstants::DescriptorSetBindings::SPOT_LIGHT_DATA,
// .DescriptorCount = 1,
//};
// For Dynamic global data (lights)
Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, { lightBinding });
Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings);
SHVkDescriptorSetLayout::Binding cameraDataBinding
{
@ -94,7 +115,7 @@ namespace SHADE
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Normals at binding 2
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_1D) }); // EID at binding 8
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8
}
void SHGraphicsGlobalData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept

View File

@ -94,14 +94,32 @@ namespace SHADE
/***************************************************************************/
static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1;
/***************************************************************************/
/*!
\brief
DescriptorSet binding for lights.
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
*/
/***************************************************************************/
static constexpr uint32_t LIGHTS_DATA = 0;
//*/
///***************************************************************************/
//static constexpr uint32_t DIRECTIONAL_LIGHT_DATA = 0;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
//*/
///***************************************************************************/
//static constexpr uint32_t POINT_LIGHT_DATA = 1;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
//*/
///***************************************************************************/
//static constexpr uint32_t SPOT_LIGHT_DATA = 2;
/***************************************************************************/
/*!
@ -164,7 +182,7 @@ namespace SHADE
Vertex buffer bindings for the eid buffer.
*/
/***************************************************************************/
static constexpr uint32_t EID = 5;
static constexpr uint32_t INTEGER_DATA = 5;
};

View File

@ -36,6 +36,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHTextureAsset.h"
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
namespace SHADE
{
@ -124,14 +125,17 @@ namespace SHADE
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
greyscale->Reflect();
pureCopy->Reflect();
}
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -172,21 +176,32 @@ namespace SHADE
// Initialize world render graph
worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors
auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", { "Light Layer Indices", "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors
auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
gBufferSubpass->AddColorOutput("Scene Pre-Process");
gBufferSubpass->AddColorOutput("Entity ID");
gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
//First subpass to write to G-Buffer
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
gBufferWriteSubpass->AddColorOutput("Scene Pre-Process");
gBufferWriteSubpass->AddColorOutput("Entity ID");
gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
//// kirsch
//auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
//gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" });
// copy
auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" });
auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, {"G-Buffer"}); // no predecessors
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass");
dummySubpass->AddInput("Scene");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
node->AddNodeCompute (greyscale, {"Scene Pre-Process", "Scene"});
// Generate world render graph
worldRenderGraph->Generate();
@ -200,7 +215,7 @@ namespace SHADE
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
}
@ -231,11 +246,15 @@ namespace SHADE
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
cmdPools.push_back(renderContext.GetFrameData(i).cmdPoolHdls[0]);
// Mouse picking system for the editor (Will still run with editor disabled)
mousePickSystem->Init(device, cmdPools, worldRenderGraph->GetRenderGraphResource("Entity ID"));
// Register the post offscreen render to the system
postOffscreenRender = resourceManager.Create<SHPostOffscreenRenderSystem>();
postOffscreenRender->Init(device, worldRenderGraph->GetRenderGraphResource("Scene"), descPool);
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool);
}
#ifdef SHEDITOR
@ -353,10 +372,12 @@ namespace SHADE
// Begin recording the command buffer
currentCmdBuffer->BeginRecording();
// set viewport and scissor
uint32_t w = static_cast<uint32_t>(viewports[vpIndex]->GetWidth());
uint32_t h = static_cast<uint32_t>(viewports[vpIndex]->GetHeight());
currentCmdBuffer->SetViewportScissor (static_cast<float>(w), static_cast<float>(h), w, h);
// Force set the pipeline layout
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS);
// Bind all the buffers required for meshes
@ -368,6 +389,8 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0);
}
// Bind the descriptor set for lights
lightingSubSystem->Run(currentCmdBuffer, frameIndex);
// Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
@ -401,7 +424,7 @@ namespace SHADE
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
#endif
// Draw first
// Draw the scene
renderers[renIndex]->Draw(frameIndex, descPool);
// End the command buffer recording

View File

@ -32,6 +32,7 @@ of DigiPen Institute of Technology is prohibited.
#include "../Textures/SHTextureLibrary.h"
#include "../Textures/SHVkSamplerCache.h"
#include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
namespace SHADE
{
@ -351,6 +352,7 @@ namespace SHADE
// Sub systems
Handle<SHMousePickSystem> mousePickSystem;
Handle<SHPostOffscreenRenderSystem> postOffscreenRender;
Handle<SHLightingSubSystem> lightingSubSystem;
uint32_t resizeWidth;
uint32_t resizeHeight;

View File

@ -0,0 +1,12 @@
#pragma once
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
struct SHInstancedIntegerData
{
EntityID eid;
uint32_t lightLayer;
};
}

View File

@ -7,6 +7,7 @@
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/SHVkUtil.h"
#include "Graphics/MiddleEnd/Interface/SHViewport.h"
//#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
namespace SHADE
{
@ -53,7 +54,7 @@ namespace SHADE
// wait for the copy to be done
afterCopyFence->Wait(true, std::numeric_limits<uint64_t>::max());
pickedEID = imageDataDstBuffer->GetDataFromMappedPointer<uint32_t>(static_cast<uint32_t>(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast<uint32_t>(viewportMousePos.x));
pickedEID = imageDataDstBuffer->GetDataFromMappedPointer<EntityID>(static_cast<uint32_t>(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast<uint32_t>(viewportMousePos.x));
}
}

View File

@ -68,7 +68,7 @@ namespace SHADE
{
std::vector combinedImageSampler
{
std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eGeneral),
std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eShaderReadOnlyOptimal),
};
// Register the image view and sampler with the descriptor set. Now whenever rendering to the offscreen image is done, the descriptor set will see the change

View File

@ -27,6 +27,8 @@ namespace SHADE
sharedMaterial = {};
material = {};
oldMaterial = {};
lightLayer = 0;
}
void SHRenderable::OnDestroy()
@ -91,6 +93,11 @@ namespace SHADE
return material;
}
uint8_t SHRenderable::GetLightLayer(void) const noexcept
{
return lightLayer;
}
void SHRenderable::ResetChangedFlag()
{
materialChanged = false;

View File

@ -56,6 +56,7 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/
bool WasMaterialChanged() const noexcept { return materialChanged; }
Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
uint8_t GetLightLayer (void) const noexcept;
/*-------------------------------------------------------------------------------*/
/* Batcher Dispatcher Functions */
@ -75,6 +76,7 @@ namespace SHADE
Handle<SHMaterialInstance> material;
bool materialChanged = true;
Handle<SHMaterialInstance> oldMaterial;
uint8_t lightLayer;
};
}

View File

@ -0,0 +1,123 @@
#include "SHpch.h"
#include "SHLightComponent.h"
namespace SHADE
{
void SHLightComponent::OnCreate(void)
{
lightData.Reset();
SetType(SH_LIGHT_TYPE::DIRECTIONAL);
indexInBuffer = std::numeric_limits<uint32_t>::max();
active = true;
Unbind();
}
void SHLightComponent::OnDestroy(void)
{
}
void SHLightComponent::SetPosition(SHVec3 position) noexcept
{
lightData.position = position;
MakeDirty();
}
void SHLightComponent::SetType(SH_LIGHT_TYPE type) noexcept
{
lightData.type = type;
MakeDirty();
}
void SHLightComponent::SetDirection(SHVec3 direction) noexcept
{
lightData.direction = direction;
MakeDirty();
}
void SHLightComponent::SetDiffuseColor(SHVec4 diffuseColor) noexcept
{
lightData.diffuseColor = diffuseColor;
MakeDirty();
}
void SHLightComponent::ModifyLayer(uint8_t layerIndex, bool value) noexcept
{
if (value)
lightData.cullingMask |= (1u << layerIndex);
else
lightData.cullingMask &= ~(1u << layerIndex);
MakeDirty();
}
void SHLightComponent::SetAllLayers(void) noexcept
{
lightData.cullingMask = std::numeric_limits<uint32_t>::max();
MakeDirty();
}
void SHLightComponent::ClearAllLayers(void) noexcept
{
lightData.cullingMask = 0;
MakeDirty();
}
void SHLightComponent::MakeDirty(void) noexcept
{
dirty = true;
}
void SHLightComponent::ClearDirtyFlag(void) noexcept
{
dirty = false;
}
void SHLightComponent::Unbind(void) noexcept
{
bound = false;
MakeDirty();
}
void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept
{
bound = true;
indexInBuffer = inIndexInBuffer;
}
void SHLightComponent::SetActive(bool flag) noexcept
{
MakeDirty();
active = flag;
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept
{
return lightData;
}
bool SHLightComponent::IsDirty(void) const noexcept
{
return dirty;
}
bool SHLightComponent::GetBound(void) const noexcept
{
return bound;
}
uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept
{
return indexInBuffer;
}
}

View File

@ -0,0 +1,60 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.h"
namespace SHADE
{
class SH_API SHLightComponent final : public SHComponent
{
private:
//! General data for the light. This will purely be CPU bound. Whatever gets sent to the
//! GPU depends on the type of the light.
SHLightData lightData;
//! 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.
uint32_t indexInBuffer;
//! If the light component changed some value we mark this true.
bool dirty;
//! If the light's data is already in the buffers, this will be set to true.
bool bound;
//! If the light is active, this is true.
bool active;
public:
/*-----------------------------------------------------------------------*/
/* LIFECYCLE FUNCTIONS */
/*-----------------------------------------------------------------------*/
void OnCreate (void) override final;
void OnDestroy (void) override final;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
void SetPosition (SHVec3 position) noexcept;
void SetType (SH_LIGHT_TYPE type) noexcept;
void SetDirection (SHVec3 direction) noexcept;
void SetDiffuseColor (SHVec4 diffuseColor) noexcept;
void ModifyLayer (uint8_t layerIndex, bool value) noexcept;
void SetAllLayers (void) noexcept;
void ClearAllLayers (void) noexcept;
void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetActive (bool flag) noexcept;
SHLightData const& GetLightData (void) const noexcept;
bool IsDirty (void) const noexcept;
bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept;
};
}

View File

@ -0,0 +1,21 @@
#include "SHpch.h"
#include "SHLightData.h"
namespace SHADE
{
void SHLightData::Reset(void) noexcept
{
// no culling is done.
cullingMask = std::numeric_limits<uint32_t>::max();
// reset position to 0
position = SHVec3::Zero;
// direction just point in positive z axis
direction = SHVec3::Forward;
// Diffuse color set to 1
diffuseColor = SHVec4::One;
}
}

View File

@ -0,0 +1,55 @@
#pragma once
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
namespace SHADE
{
enum class SH_LIGHT_TYPE : uint32_t
{
DIRECTIONAL = 0,
POINT,
SPOT,
NUM_TYPES
};
/***************************************************************************/
/*!
\class
Every light will essentially be using this struct. However, when passing
light data over to the GPU, the light data will be split according to
type for more optimal cache access.
*/
/***************************************************************************/
struct SHLightData
{
//! position of the light
SHVec3 position;
//! Type of the light
SH_LIGHT_TYPE type;
//! direction of the light
SHVec3 direction;
//! Each bit in this 32 bit field will represent a layer. If the bit is set,
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
//! Diffuse color emitted by the light
SHVec4 diffuseColor;
void Reset (void) noexcept;
//! TODO:
//! - Add cut off. (inner and outer).
//! - Add constant, linear and quadratic for attenuation
//! - Specular color if needed. see below.
//! Specular color
//SHVec4 specularColor;
};
}

View File

@ -0,0 +1,431 @@
#include "SHpch.h"
#include "SHLightingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Tools/SHUtilities.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "SHLightComponent.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "SHLightComponent.h"
namespace SHADE
{
/***************************************************************************/
/*!
\brief
This function takes an address in the CPU container and writes light
component data to it. What gets written depends on the light type.
\param address
The address to write to.
\param lightComp
The light component with the data to write from.
\param lightType
The type of the light
\return
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHLightComponent* lightComp) noexcept
{
auto const& lightData = lightComp->GetLightData();
switch (lightData.type)
{
case SH_LIGHT_TYPE::DIRECTIONAL:
{
SHDirectionalLightData* lightPtr = reinterpret_cast<SHDirectionalLightData*>(address);
lightPtr->cullingMask = lightData.cullingMask;
lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.diffuseColor;
break;
}
case SH_LIGHT_TYPE::POINT:
break;
case SH_LIGHT_TYPE::SPOT:
break;
case SH_LIGHT_TYPE::NUM_TYPES:
break;
default:
break;
}
}
/***************************************************************************/
/*!
\brief
Initializes type, intermediate data and buffer. dirty will be true.
\param lightType
type of the light.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::InitializeData(Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept
{
// initialize the type
lightType = type;
// boilerplate
intermediateData = nullptr;
// initialize alignment
lightDataAlignmentSize = logicalDevice->PadSSBOSize(GetLightTypeSize(type));
// So create some data!
Expand(logicalDevice);
}
/***************************************************************************/
/*!
\brief
Expands both the CPU container and the GPU buffer when the number of
lights have exceeded the capacity.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::Expand(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
if (lightDataAlignmentSize == 0)
{
SHLOG_ERROR ("One of the types of lights have not been accounted for. Make sure lightDataAlignmentSize is not nullptr.");
return;
}
// we want to wait for the command buffers to finish using the buffers first
logicalDevice->WaitIdle();
// First time we are initializing lights
if (intermediateData == nullptr)
{
// max lights should start of at STARTING_NUM_LIGHTS lights
maxLights = STARTING_NUM_LIGHTS;
numLights = 0;
// Initialize the data for lights
intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights);
// We want to initialize 3 times the amount of data required.
dataBuffer = logicalDevice->CreateBuffer(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
}
else
{
// save old number of lights
uint32_t const OLD_MAX_LIGHTS = maxLights;
// before we increase the number of lights, create space to store old data.
std::unique_ptr<uint8_t[]> oldData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * OLD_MAX_LIGHTS);
// copy data over.
std::memcpy (oldData.get(), intermediateData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
// now we start to expand....
// double space for lights
maxLights *= 2;
// destroy old data and initialize container for double the amount of data.
intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights);
// copy old data to new container
std::memcpy(intermediateData.get(), oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
// Resize the GPU buffer. TODO: Replace with Resize no copy here
dataBuffer->ResizeReplace(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
}
}
/***************************************************************************/
/*!
\brief
Gets the size required to store data for a light type.
\param type
Type of a light.
\return
Size required to store a light based on type.
*/
/***************************************************************************/
uint32_t SHLightingSubSystem::PerTypeData::GetLightTypeSize(SH_LIGHT_TYPE type) noexcept
{
switch (type)
{
case SH_LIGHT_TYPE::DIRECTIONAL:
// TOOD: Change after creating point light struct
return sizeof(SHDirectionalLightData);
case SH_LIGHT_TYPE::POINT:
return 4;
case SH_LIGHT_TYPE::SPOT:
// TOOD: Change after creating spot light struct
return 4;
case SH_LIGHT_TYPE::NUM_TYPES:
default:
return 4;
}
}
Handle<SHVkBuffer> SHLightingSubSystem::PerTypeData::GetDataBuffer(void) const noexcept
{
return dataBuffer;
}
uint32_t SHLightingSubSystem::PerTypeData::GetAlignmentSize(void) const noexcept
{
return lightDataAlignmentSize;
}
uint32_t SHLightingSubSystem::PerTypeData::GetNumLights(void) const noexcept
{
return numLights;
}
uint32_t SHLightingSubSystem::PerTypeData::GetMaxLights(void) const noexcept
{
return maxLights;
}
/***************************************************************************/
/*!
\brief
This function takes in a light comp in the event that its data has not
been placed in the buffer yet. It also checks if the size of the buffer
is big enough to hold the new light. If the buffer is too small, expand
it.
\param lightComp
The light component to add.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept
{
if (unboundLight)
{
// capacity is full
if (numLights == maxLights)
{
// expand first
Expand(logicalDevice);
expanded = true;
}
// Now that the container is big enough, bind the new light
// Get address of write location
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * numLights);
// Write the light data to address
WriteLightToAddress(writeLocation, unboundLight);
// Set the light component to be bound to that location
unboundLight->SetBound(numLights);
// Increase light count
++numLights;
}
}
/***************************************************************************/
/*!
\brief
Modify the data at a specific light address.
\param lightComp
The light component to write.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
{
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * lightComp->GetIndexInBuffer());
WriteLightToAddress(writeLocation, lightComp);
}
void SHLightingSubSystem::PerTypeData::WriteToGPU(uint32_t frameIndex) noexcept
{
if (intermediateData)
{
// we want to write to the offset of the current frame
dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignmentSize * numLights, 0, lightDataAlignmentSize * maxLights * frameIndex);
}
}
/***************************************************************************/
/*!
\brief
Update descriptor sets. We want to call this every time we expand buffers.
\param binding
The binding in the set we want to update.
*/
/***************************************************************************/
void SHLightingSubSystem::UpdateDescSet(uint32_t binding) noexcept
{
auto buffer = perTypeData[binding].GetDataBuffer();
// We bind the buffer with the correct desc set binding
lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS,
binding,
{ &buffer, 1 },
0,
perTypeData[binding].GetAlignmentSize() * perTypeData[binding].GetMaxLights());
lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding);
}
/***************************************************************************/
/*!
\brief
Computes dynamic offsets.
*/
/***************************************************************************/
void SHLightingSubSystem::ComputeDynamicOffsets(void) noexcept
{
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
for (uint32_t j = 0; j < dynamicOffsets.size(); ++j)
{
auto const& typeData = perTypeData[j];
{
dynamicOffsets[i][j] = j * typeData.GetAlignmentSize() * typeData.GetMaxLights();
}
}
}
}
/***************************************************************************/
/*!
\brief
Initializes per light type data. This includes buffers and descriptor
sets.
*/
/***************************************************************************/
void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept
{
SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device;
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
std::fill (variableSizes.begin(), variableSizes.end(), 1);
// Create the descriptor set
lightingDataDescSet = descPool->Allocate({SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS]}, variableSizes);
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{
// initialize all the data first. We add more lights here as we add more types.
perTypeData[i].InitializeData(logicalDevice, static_cast<SH_LIGHT_TYPE>(i));
UpdateDescSet(i);
}
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
dynamicOffsets[i].resize(NUM_LIGHT_TYPES);
}
}
/***************************************************************************/
/*!
\brief
Loops through every single light component and checks for dirty light
data. If light data is dirty, rewrite to the CPU container. We also want
to bind the descriptor set for the light data.
*/
/***************************************************************************/
void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false;
for (auto& light : lightComps)
{
auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer.
if (!light.GetBound())
{
perTypeData[enumValue].AddLight(logicalDevice, &light, expanded);
}
// if there was modification to the light data
if (light.IsDirty())
{
// Write the data to the CPU
perTypeData[enumValue].ModifyLight(&light);
// Light is now updated in the container
light.ClearDirtyFlag();
}
}
// Write data to GPU
for (auto& data : perTypeData)
{
data.WriteToGPU(frameIndex);
}
// If any of the buffers got expanded, the descriptor set is invalid because the expanded buffer
// is a new buffer. If some expansion was detected, update descriptor sets.
if (expanded)
{
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{
UpdateDescSet(i);
}
}
// compute dynamic offsets. We don't actually have to compute every frame but its pretty lightweight,
// so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets();
// Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]});
}
/***************************************************************************/
/*!
\brief
Does nothing for now.
*/
/***************************************************************************/
void SHLightingSubSystem::Exit(void) noexcept
{
}
}

View File

@ -0,0 +1,124 @@
#pragma once
#include "Resource/SHHandle.h"
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "SHLightData.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
namespace SHADE
{
class SHVkLogicalDevice;
class SHVkDescriptorPool;
class SHVkDescriptorSetGroup;
class SHVkDescriptorSetLayout;
class SHVkBuffer;
class SHLightComponent;
class SHVkCommandBuffer;
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData
{
//! Direction of the light
SHVec3 direction;
//! Represents if the light is active or not
uint32_t active;
//! Each bit in this 32 bit field will represent a layer. If the bit is set,
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
//! Diffuse color emitted by the light
SHVec4 diffuseColor;
};
class SH_API SHLightingSubSystem
{
private:
class PerTypeData
{
private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
static constexpr uint32_t STARTING_NUM_LIGHTS = 20;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! Capacity of the container.
uint32_t maxLights;
//! SSBOs need to be aligned. This is to pad lighting structs
uint32_t lightDataAlignmentSize;
//! type of the light. Will be used later when we want to expand
SH_LIGHT_TYPE lightType;
//! number of lights currently alive.
uint32_t numLights;
//! GPU buffer required to store GPU data
Handle<SHVkBuffer> dataBuffer;
//! Before data gets copied to the GPU, it goes into here first. Data here is aligned to whatever struct is
//! used to represent data in this container. Note this will store only 1 copy of all the lights, compared
//! to the GPU that stores NUM_FRAME_BUFFERS copies.
std::unique_ptr<uint8_t[]> intermediateData;
void WriteLightToAddress (void* address, SHLightComponent* lightComp) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void InitializeData (Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept;
void Expand (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept;
void ModifyLight (SHLightComponent* lightComp) noexcept;
void WriteToGPU (uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS */
/*-----------------------------------------------------------------------*/
static uint32_t GetLightTypeSize (SH_LIGHT_TYPE type) noexcept;
Handle<SHVkBuffer> GetDataBuffer (void) const noexcept;
uint32_t GetAlignmentSize (void) const noexcept;
uint32_t GetNumLights (void) const noexcept;
uint32_t GetMaxLights (void) const noexcept;
};
private:
//! logical device used for creation
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
std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)> dynamicOffsets;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept;
void Run (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void Exit (void) noexcept;
};
}

View File

@ -142,6 +142,12 @@ namespace SHADE
case SHAttribFormat::UINT32_1D:
return std::make_tuple(1, 4, vk::Format::eR32Uint);
case SHAttribFormat::UINT32_2D:
return std::make_tuple(1, 8, vk::Format::eR32G32Uint);
case SHAttribFormat::UINT32_3D:
return std::make_tuple(1, 12, vk::Format::eR32G32B32Uint);
case SHAttribFormat::UINT32_4D:
return std::make_tuple(1, 16, vk::Format::eR32G32B32A32Uint);
}
return std::make_tuple(0, 0, vk::Format::eR32Sfloat);
}

View File

@ -142,6 +142,9 @@ namespace SHADE
attDesc.loadOp = vk::AttachmentLoadOp::eLoad;
predAttDesc.storeOp = vk::AttachmentStoreOp::eStore;
attDesc.stencilLoadOp = vk::AttachmentLoadOp::eLoad;
attDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore;
// TODO: Stencil load and store
// When an image is done being used in a renderpass, the image layout will end up being the finalLayout

View File

@ -51,6 +51,18 @@ namespace SHADE
case vk::Format::eR32Uint:
case vk::Format::eR32Sfloat:
return 4;
case vk::Format::eR32G32Sint:
case vk::Format::eR32G32Uint:
case vk::Format::eR32G32Sfloat:
return 8;
case vk::Format::eR32G32B32Sint:
case vk::Format::eR32G32B32Uint:
case vk::Format::eR32G32B32Sfloat:
return 12;
case vk::Format::eR32G32B32A32Sint:
case vk::Format::eR32G32B32A32Uint:
case vk::Format::eR32G32B32A32Sfloat:
return 16;
}
return 0;
}

View File

@ -22,6 +22,9 @@ namespace SHADE
// integer formats
UINT32_1D,
UINT32_2D,
UINT32_3D,
UINT32_4D,
};
struct SHVertexAttribute

View File

@ -61,9 +61,9 @@ namespace SHADE
void SHTransformSystem::Init()
{
std::shared_ptr thisReceiver { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) };
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver);
SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, receiver);
const std::shared_ptr CHANGE_PARENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) };
const ReceiverPtr CHANGE_PARENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(CHANGE_PARENT_RECEIVER);
SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, CHANGE_PARENT_RECEIVER_PTR);
}
void SHTransformSystem::Exit()
@ -75,50 +75,6 @@ namespace SHADE
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
{
const auto& eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
auto* node = eventData->data->node;
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
// Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity;
auto* newParent = eventData->data->newParent;
const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
if (PARENT_TF != nullptr) // Not the root
{
localToWorld = PARENT_TF->GetTRS();
worldToLocal = SHMatrix::Inverse(localToWorld);
}
// Maintain World Transform and recompute Local Transform
// Compute Local Position
tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
tf->localRotation = tf->worldRotation;
tf->local.scale = tf->world.scale;
if (PARENT_TF != nullptr)
{
// Compute Local Rotation
tf->localRotation -= PARENT_TF->GetLocalRotation();
// Compute Local Scale
tf->local.scale /= PARENT_TF->GetLocalScale();
}
tf->local.trs = localToWorld;
// Propagate maintaining world transform down the branch
UpdateChildrenLocalTransforms(node);
return eventData->handle;
}
void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node)
{
// Structure is similar to update entity, albeit without a queue to do being a forced update
@ -300,4 +256,49 @@ namespace SHADE
tf.world.ComputeTRS();
}
SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
auto* node = EVENT_DATA->data->node;
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
// Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity;
auto* newParent = EVENT_DATA->data->newParent;
const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
if (PARENT_TF != nullptr) // Not the root
{
localToWorld = PARENT_TF->GetTRS();
worldToLocal = SHMatrix::Inverse(localToWorld);
}
// Maintain World Transform and recompute Local Transform
// Compute Local Position
tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
tf->localRotation = tf->worldRotation;
tf->local.scale = tf->world.scale;
if (PARENT_TF != nullptr)
{
// Compute Local Rotation
tf->localRotation -= PARENT_TF->GetLocalRotation();
// Compute Local Scale
tf->local.scale /= PARENT_TF->GetLocalScale();
}
tf->local.trs = localToWorld;
// Propagate maintaining world transform down the branch
UpdateChildrenLocalTransforms(node);
return EVENT_DATA->handle;
}
} // namespace SHADE

View File

@ -11,9 +11,9 @@
#pragma once
// Project Headers
#include "SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Scene/SHSceneGraph.h"
#include "SHTransformComponent.h"
namespace SHADE
{
@ -53,17 +53,6 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/
TransformPostLogicUpdate ();
~TransformPostLogicUpdate () = default;
TransformPostLogicUpdate (const TransformPostLogicUpdate&) = delete;
TransformPostLogicUpdate (TransformPostLogicUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Operator Overloads */
/*-------------------------------------------------------------------------------*/
TransformPostLogicUpdate& operator= (const TransformPostLogicUpdate&) = delete;
TransformPostLogicUpdate& operator= (TransformPostLogicUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Function Members */
@ -80,17 +69,6 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/
TransformPostPhysicsUpdate ();
~TransformPostPhysicsUpdate () = default;
TransformPostPhysicsUpdate (const TransformPostPhysicsUpdate&) = delete;
TransformPostPhysicsUpdate (TransformPostPhysicsUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Operator Overloads */
/*-------------------------------------------------------------------------------*/
TransformPostPhysicsUpdate& operator= (const TransformPostPhysicsUpdate&) = delete;
TransformPostPhysicsUpdate& operator= (TransformPostPhysicsUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Function Members */
@ -111,11 +89,14 @@ namespace SHADE
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHEventHandle ChangeParent (SHEventPtr changeParentEvent);
static void UpdateChildrenLocalTransforms (SHSceneNode* node);
static void UpdateEntity (const SHSceneNode* node, bool clearDirtyFlag);
static void UpdateTransform (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
// Event Handlers
SHEventHandle ChangeParent (SHEventPtr changeParentEvent);
};

View File

@ -26,7 +26,6 @@ namespace SHADE
SHColliderComponent::SHColliderComponent() noexcept
: system { nullptr }
, colliders {}
{}
/*-----------------------------------------------------------------------------------*/
@ -69,31 +68,24 @@ namespace SHADE
void SHColliderComponent::OnCreate()
{
system = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!system)
{
SHLOG_ERROR("Physics system does not exist, Collider Component not added!")
return;
}
system->AddCollider(GetEID());
}
void SHColliderComponent::OnDestroy()
{
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to remove Collider component!")
return;
}
system->RemoveCollider(GetEID());
}
SHBoundingBox* SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset) noexcept
{
const auto TYPE = SHCollider::Type::BOX;
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
return nullptr;
}
auto boxPair = std::make_pair(SHCollider{TYPE}, true);
static constexpr auto TYPE = SHCollider::Type::BOX;
auto boxPair = std::make_pair(SHCollider{ TYPE }, true);
auto& collider = colliders.emplace_back(boxPair).first;
const auto* tf = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
@ -101,12 +93,6 @@ namespace SHADE
collider.SetPositionOffset(posOffset);
collider.SetAsBoundingBox(tf->GetWorldScale() * halfExtents);
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
return nullptr;
}
// Notify Physics System
system->AddCollisionShape(GetEID(), &collider);
@ -115,7 +101,13 @@ namespace SHADE
SHBoundingSphere* SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept
{
const auto TYPE = SHCollider::Type::SPHERE;
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
return nullptr;
}
static constexpr auto TYPE = SHCollider::Type::SPHERE;
auto spherePair = std::make_pair(SHCollider{ TYPE }, true);
auto& collider = colliders.emplace_back(spherePair).first;
@ -126,13 +118,7 @@ namespace SHADE
const SHVec3 TF_WORLD_SCALE = tf->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
collider.SetAsBoundingSphere(MAX_SCALE * 0.5f);
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
return nullptr;
}
collider.SetAsBoundingSphere(MAX_SCALE * 0.5f * radius);
// Notify Physics System
system->AddCollisionShape(GetEID(), &collider);

View File

@ -44,7 +44,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
using ColliderDirtyPair = std::pair<SHCollider, bool>;
using Colliders = std::vector<ColliderDirtyPair>;
using Colliders = std::vector<ColliderDirtyPair>;
public:
@ -81,10 +81,10 @@ namespace SHADE
/* Function Members */
/*---------------------------------------------------------------------------------*/
void OnCreate () override;
void OnDestroy () override;
void OnCreate () override;
void OnDestroy () override;
void RemoveCollider (int index);
void RemoveCollider (int index);
SHBoundingBox* AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero) noexcept;
SHBoundingSphere* AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept;

View File

@ -28,11 +28,10 @@ namespace SHADE
, flags { 0 }
, dirtyFlags { 0 }
, interpolate { true }
, system { nullptr }
, rp3dBody { nullptr }
, mass { 1.0f }
, drag { 0.01f }
, angularDrag { 0.01f }
{
// Set default flags: Gravity & Sleeping enabled
flags |= 1U << 0;
@ -161,7 +160,13 @@ namespace SHADE
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
{
constexpr int FLAG_POS = 0;
static constexpr int FLAG_POS = 0;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -169,7 +174,13 @@ namespace SHADE
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
{
constexpr int FLAG_POS = 1;
static constexpr int FLAG_POS = 1;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 1;
isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -177,7 +188,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{
constexpr int FLAG_POS = 2;
static constexpr int FLAG_POS = 2;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2;
freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -185,7 +202,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{
constexpr int FLAG_POS = 3;
static constexpr int FLAG_POS = 3;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2;
freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -193,7 +216,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{
constexpr int FLAG_POS = 4;
static constexpr int FLAG_POS = 4;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2;
freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -201,7 +230,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{
constexpr int FLAG_POS = 5;
static constexpr int FLAG_POS = 5;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3;
freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -209,7 +244,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{
constexpr int FLAG_POS = 6;
static constexpr int FLAG_POS = 6;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3;
freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -217,7 +258,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{
constexpr int FLAG_POS = 7;
static constexpr int FLAG_POS = 7;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3;
freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -230,30 +277,60 @@ namespace SHADE
void SHRigidBodyComponent::SetMass(float newMass) noexcept
{
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 5;
mass = newMass;
}
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
{
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 6;
drag = newDrag;
}
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
{
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 7;
angularDrag = newAngularDrag;
}
void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
{
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 8;
linearVelocity = newLinearVelocity;
}
void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
{
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 9;
angularVelocity = newAngularVelocity;
}
@ -262,125 +339,92 @@ namespace SHADE
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHRigidBodyComponent::OnCreate()
{
system = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!system)
{
SHLOG_ERROR("Physics system does not exist, Rigid Body Component not added!")
return;
}
// Notify Physics System
system->AddRigidBody(GetEID());
}
void SHRigidBodyComponent::OnDestroy()
{
// Notify Physics System
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to remove Rigid Body Component!")
return;
}
system->RemoveRigidBody(GetEID());
}
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddForce(GetEID(), force);
rp3dBody->applyWorldForceAtCenterOfMass(force);
}
void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddForceAtLocalPos(GetEID(), force, localPos);
rp3dBody->applyWorldForceAtLocalPosition(force, localPos);
}
void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddForceAtWorldPos(GetEID(), force, worldPos);
rp3dBody->applyWorldForceAtWorldPosition(force, worldPos);
}
void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddRelativeForce(GetEID(), force);
rp3dBody->applyLocalForceAtCenterOfMass(relativeForce);
}
void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddRelativeForceAtLocalPos(GetEID(), force, localPos);
rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos);
}
void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddRelativeForceAtWorldPos(GetEID(), force, worldPos);
rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
}
void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddTorque(GetEID(), torque);
rp3dBody->applyWorldTorque(torque);
}
void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
{
if (!system)
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return;
}
// Notify Physics Systems
system->AddRelativeTorque(GetEID(), relativeTorque);
rp3dBody->applyLocalTorque(relativeTorque);
}
} // namespace SHADE

View File

@ -10,6 +10,7 @@
#pragma once
#include <reactphysics3d/reactphysics3d.h>
#include <rttr/registration>
// Project Headers
@ -125,9 +126,6 @@ namespace SHADE
/* Function Members */
/*---------------------------------------------------------------------------------*/
void OnCreate () override;
void OnDestroy () override;
void AddForce (const SHVec3& force) const noexcept;
void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept;
void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept;
@ -155,7 +153,7 @@ namespace SHADE
uint16_t dirtyFlags;
bool interpolate;
SHPhysicsSystem* system;
rp3d::RigidBody* rp3dBody;
float mass;
float drag;
@ -167,8 +165,6 @@ namespace SHADE
SHVec3 torque;
SHVec3 angularVelocity;
// TODO(Diren): Once quaternions have replaced euler angles in transforms, store it for the rigidbody.
SHVec3 position;
SHQuaternion orientation;

View File

@ -26,8 +26,6 @@ namespace SHADE
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, isRigidBody { false }
, hasColliders{ false }
, factory { physicsFactory }
, world { physicsWorld }
, rp3dBody { nullptr }
@ -130,42 +128,6 @@ namespace SHADE
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::CreateRigidBody(const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c)
{
// If collider already exists, recreate the collision body as a rigid body
if (hasColliders)
world->destroyCollisionBody(rp3dBody);
rp3dBody = world->createRigidBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
isRigidBody = true;
rb->position = tf->GetWorldPosition();
rb->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
if (hasColliders)
{
c->position = tf->GetWorldPosition();
c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
// Get array of colliders and add them back into the rigidbody
for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider);
}
}
void SHPhysicsObject::CreateCollisionBody(const SHTransformComponent* tf, SHColliderComponent* c)
{
if (rp3dBody == nullptr)
rp3dBody = world->createCollisionBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
hasColliders = true;
c->position = tf->GetWorldPosition();
c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider);
}
int SHPhysicsObject::AddCollider(SHCollider* collider)
{
switch (collider->GetType())
@ -193,31 +155,6 @@ namespace SHADE
return static_cast<int>(rp3dBody->getNbColliders()) - 1;
}
void SHPhysicsObject::DestroyRigidBody(SHColliderComponent* c) noexcept
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(rp3dBody));
if (hasColliders)
{
// Preserve colliders as a collision body
rp3dBody = world->createCollisionBody(rp3d::Transform{ c->position, c->orientation });
for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider);
}
isRigidBody = false;
}
void SHPhysicsObject::DestroyCollisionBody() noexcept
{
// Remove all colliders
for (uint32_t i = 0; i < rp3dBody->getNbColliders(); ++i)
{
auto* collider = rp3dBody->getCollider(i);
rp3dBody->removeCollider(collider);
}
}
void SHPhysicsObject::RemoveCollider(int index)
{
const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());

View File

@ -69,13 +69,8 @@ namespace SHADE
/* Function Members */
/*---------------------------------------------------------------------------------*/
void CreateRigidBody (const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c);
void CreateCollisionBody (const SHTransformComponent* tf, SHColliderComponent* c);
int AddCollider (SHCollider* collider);
void DestroyRigidBody (SHColliderComponent* c) noexcept;
void RemoveCollider (int index);
void DestroyCollisionBody () noexcept;
void SyncRigidBody (SHRigidBodyComponent* rb) const noexcept;
void SyncColliders (SHColliderComponent* c) const noexcept;
@ -86,8 +81,6 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
EntityID entityID;
bool isRigidBody;
bool hasColliders;
rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* world;

View File

@ -16,6 +16,8 @@
// Project Headers
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.hpp"
#include "Math/SHMathHelpers.h"
#include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformComponent.h"
@ -175,11 +177,9 @@ namespace SHADE
void SHPhysicsSystem::Init()
{
using namespace rp3d;
// Create a physics world with the default settings
PhysicsWorld::WorldSettings settings;
settings.gravity = Vector3{ 0.0f, -9.81f, 0.0f };
rp3d::PhysicsWorld::WorldSettings settings;
settings.gravity = SHVec3{ 0.0f, -9.81f, 0.0f };
settings.isSleepingEnabled = true;
settings.defaultVelocitySolverNbIterations = 8;
settings.defaultPositionSolverNbIterations = 3;
@ -190,6 +190,16 @@ namespace SHADE
// Set up solvers
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::AddPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::RemovePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
}
void SHPhysicsSystem::Exit()
@ -197,128 +207,87 @@ namespace SHADE
factory.destroyPhysicsWorld(world);
}
void SHPhysicsSystem::AddRigidBody(EntityID entityID) noexcept
{
//#ifdef _DEBUG
// SHLOG_INFO("Adding a Rigidbody to the Physics World.")
//#endif
auto* physicsObject = CreatePhysicsObject(entityID);
physicsObject->CreateRigidBody
(
EnsureTransform(entityID),
SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID),
SHComponentManager::GetComponent_s<SHColliderComponent>(entityID)
);
}
void SHPhysicsSystem::AddCollider(EntityID entityID) noexcept
{
//#ifdef _DEBUG
// SHLOG_INFO("Adding a Collider to the Physics World.")
//#endif
auto* physicsObject = CreatePhysicsObject(entityID);
physicsObject->CreateCollisionBody
(
EnsureTransform(entityID),
SHComponentManager::GetComponent<SHColliderComponent>(entityID)
);
}
void SHPhysicsSystem::RemoveRigidBody(EntityID entityID) noexcept
{
#ifdef _DEBUG
SHLOG_INFO("Removing a Rigidbody from the Physics World.")
#endif
auto* physicsObject = GetPhysicsObject(entityID);
SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
physicsObject->DestroyRigidBody(SHComponentManager::GetComponent_s<SHColliderComponent>(entityID));
if (physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(entityID);
}
void SHPhysicsSystem::RemoveCollider(EntityID entityID) noexcept
{
#ifdef _DEBUG
SHLOG_INFO("Removing a Collider from the Physics World.")
#endif
}
void SHPhysicsSystem::AddForce(EntityID entityID, const SHVec3& force) const noexcept
{
}
void SHPhysicsSystem::AddForceAtLocalPos(EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept
{
}
void SHPhysicsSystem::AddForceAtWorldPos(EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept
{
}
void SHPhysicsSystem::AddRelativeForce(EntityID entityID, const SHVec3& relativeForce) const noexcept
{
}
void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
{
}
void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
{
}
void SHPhysicsSystem::AddTorque(EntityID entityID, const SHVec3& torque) const noexcept
{
}
void SHPhysicsSystem::AddRelativeTorque(EntityID entityID, const SHVec3& relativeTorque) const noexcept
{
}
void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollider* collider)
{
auto* physicsObject = GetPhysicsObject(entityID);
physicsObject->AddCollider(collider);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = collider->GetType()
, .colliderIndex = physicsObject->AddCollider(collider)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
}
void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index)
{
auto* physicsObject = GetPhysicsObject(entityID);
physicsObject->RemoveCollider(index);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = entityID
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
}
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
// Sync transforms
for (auto& [entityID, physicsObject] : system->map)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
// Clear all forces and velocities if editor is not in play
if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
{
if (rigidBodyComponent)
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
}
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent && transformComponent->HasChanged())
{
const auto WORLD_POS = transformComponent->GetWorldPosition();
const auto WORLD_ROT = transformComponent->GetWorldOrientation();
physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT);
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
}
}
}
// Update bodies and colliders if component is dirty
system->SyncRigidBodyComponents(SHComponentManager::GetDense<SHRigidBodyComponent>());
system->SyncColliderComponents(SHComponentManager::GetDense<SHColliderComponent>());
// Sync transforms
for (auto& physicsObject : system->map | std::views::values)
{
const auto* TF = SHComponentManager::GetComponent<SHTransformComponent>(physicsObject.entityID);
if (TF->HasChanged())
{
physicsObject.SetPosition(TF->GetWorldPosition());
physicsObject.SetOrientation(TF->GetWorldOrientation());
}
}
}
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
@ -359,7 +328,7 @@ namespace SHADE
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsSystem::CreatePhysicsObject(EntityID entityID) noexcept
SHPhysicsObject* SHPhysicsSystem::EnsurePhysicsObject(EntityID entityID) noexcept
{
const auto it = map.find(entityID);
if (it == map.end())
@ -451,15 +420,18 @@ namespace SHADE
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
// Check if transform should be interpolated
if (physicsObject.isRigidBody)
if (rigidBodyComponent != nullptr)
{
auto* rbComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
if (rbComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
continue;
if (rbComponent->IsInterpolating())
if (rigidBodyComponent->IsInterpolating())
{
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
@ -474,12 +446,12 @@ namespace SHADE
rp3dRot = CURRENT_TF.getOrientation();
}
rbComponent->position = CURRENT_TF.getPosition();
rbComponent->orientation = CURRENT_TF.getOrientation();
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (physicsObject.hasColliders)
if (colliderComponent != nullptr)
{
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
@ -491,28 +463,148 @@ namespace SHADE
}
// Convert RP3D Transform to SHADE
auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
tfComponent->SetWorldPosition(rp3dPos);
tfComponent->SetWorldOrientation(SHQuaternion{ rp3dRot });
auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
transformComponent->SetWorldPosition(rp3dPos);
transformComponent->SetWorldOrientation(rp3dRot);
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
}
}
SHTransformComponent* SHPhysicsSystem::EnsureTransform(EntityID entityID)
SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
{
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
// Possibly redundant
if (!tf)
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
SHComponentManager::AddComponent<SHTransformComponent>(entityID);
tf = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = EnsurePhysicsObject(ENTITY_ID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(ENTITY_ID);
if (transformComponent == nullptr)
{
SHLOG_ERROR("Entity {} cannot add a Physics Component without a Transform! Component not created!", ENTITY_ID)
return EVENT_DATA->handle;
}
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (ADDED_ID == RIGID_BODY_ID)
{
if (colliderComponent != nullptr)
{
world->destroyCollisionBody(physicsObject->rp3dBody);
physicsObject->rp3dBody = nullptr;
}
rigidBodyComponent->position = transformComponent->GetWorldPosition();
rigidBodyComponent->orientation = transformComponent->GetWorldOrientation();
physicsObject->rp3dBody = world->createRigidBody
(
rp3d::Transform{ rigidBodyComponent->position, rigidBodyComponent->orientation }
);
rigidBodyComponent->rp3dBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody);
// Add collision shapes back into the body
if (colliderComponent != nullptr)
{
for (auto& collider : colliderComponent->colliders | std::views::keys)
physicsObject->AddCollider(&collider);
}
}
if (ADDED_ID == COLLIDER_ID)
{
SHASSERT(colliderComponent != nullptr, "Collider Component was not added to Entity " + std::to_string(ENTITY_ID) + "!");
colliderComponent->position = transformComponent->GetWorldPosition();
colliderComponent->orientation = transformComponent->GetWorldOrientation();
if (physicsObject->rp3dBody == nullptr)
{
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
}
// Add Collision Shapes
for (auto& collider : colliderComponent->colliders | std::views::keys)
physicsObject->AddCollider(&collider);
}
}
return tf;
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::RemovePhysicsComponent(SHEventPtr removeComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = GetPhysicsObject(ENTITY_ID);
SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
if (REMOVED_ID == RIGID_BODY_ID)
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr;
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (colliderComponent != nullptr)
{
// Preserve colliders as a collision body
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
for (auto& collider : colliderComponent->colliders | std::views::keys)
physicsObject->AddCollider(&collider);
}
// Wake up all physics objects
for (auto& [entityID, object] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
}
}
if (REMOVED_ID == COLLIDER_ID)
{
// Remove all colliders
const int NUM_COLLIDERS = static_cast<int>(physicsObject->rp3dBody->getNbColliders());
for (int i = NUM_COLLIDERS - 1; i >= 0; --i)
{
auto* collider = physicsObject->rp3dBody->getCollider(i);
physicsObject->rp3dBody->removeCollider(collider);
}
}
if (physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(ENTITY_ID);
}
return EVENT_DATA->handle;
}
} // namespace SHADE

View File

@ -16,14 +16,14 @@
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "SHPhysicsObject.h"
#include "Components/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "SHPhysicsObject.h"
namespace SHADE
@ -32,7 +32,7 @@ namespace SHADE
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem : public SHSystem
class SH_API SHPhysicsSystem final : public SHSystem
{
public:
/*---------------------------------------------------------------------------------*/
@ -85,21 +85,10 @@ namespace SHADE
void Init () override;
void Exit () override;
void AddRigidBody (EntityID entityID) noexcept;
void AddCollider (EntityID entityID) noexcept;
void RemoveRigidBody (EntityID entityID) noexcept;
void RemoveCollider (EntityID entityID) noexcept;
void AddForce (EntityID entityID, const SHVec3& force) const noexcept;
void AddForceAtLocalPos (EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept;
void AddForceAtWorldPos (EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept;
void AddRelativeForce (EntityID entityID, const SHVec3& relativeForce) const noexcept;
void AddRelativeForceAtLocalPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept;
void AddRelativeForceAtWorldPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept;
void AddTorque (EntityID entityID, const SHVec3& torque) const noexcept;
void AddRelativeTorque (EntityID entityID, const SHVec3& relativeTorque) const noexcept;
//void AddRigidBody (EntityID entityID) noexcept;
//void AddCollider (EntityID entityID) noexcept;
//void RemoveRigidBody (EntityID entityID) noexcept;
//void RemoveCollider (EntityID entityID) noexcept;
void AddCollisionShape (EntityID entityID, SHCollider* collider);
void RemoveCollisionShape (EntityID entityID, int index);
@ -108,10 +97,7 @@ namespace SHADE
/* System Routines */
/*---------------------------------------------------------------------------------*/
/**
* @brief Synchronises RP3D with SHADE
*/
class SH_API PhysicsPreUpdate : public SHSystemRoutine
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
@ -127,7 +113,7 @@ namespace SHADE
void Execute(double dt) noexcept override;
};
class SH_API PhysicsFixedUpdate : public SHFixedSystemRoutine
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
@ -143,7 +129,7 @@ namespace SHADE
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate : public SHSystemRoutine
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
@ -170,15 +156,14 @@ namespace SHADE
/* Data Members */
/*---------------------------------------------------------------------------------*/
// TODO(Diren): Store interpFactor
bool worldUpdated;
double interpolationFactor;
double fixedDT;
rp3d::PhysicsWorld* world;
rp3d::PhysicsWorld* world;
rp3d::PhysicsCommon factory;
EntityObjectMap map;
@ -186,7 +171,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* CreatePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept;
@ -194,11 +179,26 @@ namespace SHADE
void SyncRigidBodyComponents (std::vector<SHRigidBodyComponent>& denseArray) noexcept;
void SyncColliderComponents (std::vector<SHColliderComponent>& denseArray) noexcept;
void SyncTransforms () noexcept;
// TODO(Diren): Trigger handling
// TODO(Diren): Remove when responsibility shifted to editor
SHTransformComponent* EnsureTransform (EntityID entityID);
SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent);
SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent);
};
/*-----------------------------------------------------------------------------------*/
/* Event Data Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHPhysicsColliderAddedEvent
{
EntityID entityID;
SHCollider::Type colliderType;
int colliderIndex;
};
struct SHPhysicsColliderRemovedEvent
{
EntityID entityID;
int colliderIndex;
};
} // namespace SHADE

View File

@ -584,7 +584,7 @@ namespace SHADE
void SHSceneGraph::Traverse (const UnaryFunction& predicate) const
{
TraverseAndInvokePredicate(root, predicate);
TraverseAndInvokeFunction(root, predicate);
}
/*-----------------------------------------------------------------------------------*/
@ -621,12 +621,12 @@ namespace SHADE
delete node;
}
void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate)
void SHSceneGraph::TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function)
{
for (auto* child : node->children)
{
predicate(child);
TraverseAndInvokePredicate(child, predicate);
function(child);
TraverseAndInvokeFunction(child, function);
}
}

View File

@ -158,9 +158,13 @@ namespace SHADE
SHSceneNode* AllocateNode (EntityID entityID);
void ReleaseNode (SHSceneNode* node) noexcept;
static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryFunction& predicate);
static void TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function);
};
/*-----------------------------------------------------------------------------------*/
/* Event Data Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHSceneGraphChangeParentEvent
{
SHSceneNode* node;

View File

@ -42,6 +42,15 @@ namespace SHADE
template <IsEnum InputType, IsIntegral OutputType = int>
static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept;
/**
* @brief Converts an enum class member from it's type to the underlying type.
* @tparam Enum Restricted to an enum class
* @param[in] value A member of the specified enum class.
* @returns The value of the enum class member in the output type.
*/
template<typename Enum>
static constexpr typename std::underlying_type_t<Enum> ToUnderlying (Enum value) noexcept;
};
} // namespace SHADE

View File

@ -25,4 +25,10 @@ namespace SHADE
return static_cast<OutputType>(enumClassMember);
}
template<typename Enum>
constexpr typename std::underlying_type_t<Enum> SHUtilities::ToUnderlying(Enum value) noexcept
{
return static_cast<typename std::underlying_type_t<Enum>>(value);
}
} // namespace SHADE

View File

@ -0,0 +1,67 @@
//#version 450
//
//layout(local_size_x = 16, local_size_y = 16) in;
//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage;
//
//
//void main()
//{
// ivec2 imageSize = imageSize (targetImage);
//
// if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y)
// return;
//
// // load the image
// vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID));
//
// // get the average
// float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
//
// // store result into result image
// imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f));
//
//}
//
//
//
//
/* Start Header *****************************************************************/
/*! \file (e.g. kirsch.comp)
\author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920.
\par william.zheng\@digipen.edu. brandon.hao\@digipen.edu.
\date Sept 20, 2022
\brief Copyright (C) 20xx DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. */
/* End Header *******************************************************************/
#version 450
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba8) uniform image2D inputImage;
layout(set = 4, binding = 1, rgba8) uniform image2D targetImage;
void main()
{
// convenient variables
ivec2 globalThread = ivec2(gl_GlobalInvocationID);
vec3 color = imageLoad (inputImage, globalThread).rgb;
// store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1.0f));
}

Binary file not shown.

View File

@ -23,6 +23,7 @@ layout(location = 2) flat in struct
{
int materialIndex;
uint eid;
uint lightLayerIndex;
} In2;
//layout (set = 0, binding = )
@ -35,6 +36,7 @@ layout (set = 3, binding = 0) buffer MaterialProperties // For materials
layout(location = 0) out vec4 outColor;
layout(location = 1) out uint outEntityID;
layout(location = 2) out uint lightLayerIndices;
void main()
{
@ -42,5 +44,6 @@ void main()
MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
outEntityID = In2.eid;
lightLayerIndices = In2.lightLayerIndex;
//outColor = vec4 (1.0f);
}

Binary file not shown.

View File

@ -3,12 +3,13 @@
//#include "ShaderDescriptorDefinitions.glsl"
layout(location = 0) in vec3 aVertexPos;
layout(location = 1) in vec2 aUV;
layout(location = 2) in vec3 aNormal;
layout(location = 3) in vec3 aTangent;
layout(location = 4) in mat4 worldTransform;
layout(location = 8) in uint eid;
layout(location = 8) in uvec2 integerData;
layout(location = 0) out struct
@ -23,6 +24,7 @@ layout(location = 2) out struct
{
int materialIndex;
uint eid;
uint lightLayerIndex;
} Out2;
@ -36,7 +38,8 @@ void main()
{
Out.uv = aUV;
Out2.materialIndex = gl_InstanceIndex;
Out2.eid = eid;
Out2.eid = integerData[0];
Out2.lightLayerIndex = integerData[1];
gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
Out.vertColor = vec4 (aVertexPos, 1.0f);
}

Binary file not shown.