Merge branch 'main' into SP3-6-c-scripting
This commit is contained in:
commit
d2c7630af4
|
@ -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][ð‡–oû]
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
};
|
||||
}
|
|
@ -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>();
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
};
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace SHADE
|
|||
SHVkSampler::~SHVkSampler() noexcept
|
||||
{
|
||||
if (vkSampler)
|
||||
device->GetVkLogicalDevice().destroySampler();
|
||||
device->GetVkLogicalDevice().destroySampler(vkSampler);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace SHADE
|
|||
{
|
||||
batch.UpdateMaterialBuffer(frameIndex, descPool);
|
||||
batch.UpdateTransformBuffer(frameIndex);
|
||||
batch.UpdateEIDBuffer(frameIndex);
|
||||
batch.UpdateInstancedIntegerBuffer(frameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "ECS_Base/SHECSMacros.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
struct SHInstancedIntegerData
|
||||
{
|
||||
EntityID eid;
|
||||
uint32_t lightLayer;
|
||||
};
|
||||
}
|
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ namespace SHADE
|
|||
|
||||
// integer formats
|
||||
UINT32_1D,
|
||||
UINT32_2D,
|
||||
UINT32_3D,
|
||||
UINT32_4D,
|
||||
};
|
||||
|
||||
struct SHVertexAttribute
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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.
|
@ -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.
|
@ -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.
Loading…
Reference in New Issue