Merge branch 'main' into SP3-13-Assets-Manager
This commit is contained in:
commit
f2e2b21d47
|
@ -0,0 +1,5 @@
|
|||
root = true
|
||||
|
||||
[*.{c,cpp,h,hpp}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -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);
|
||||
|
||||
|
@ -83,11 +83,13 @@ namespace Sandbox
|
|||
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
|
||||
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
|
||||
|
||||
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
|
||||
|
||||
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
|
||||
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
|
||||
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
|
||||
|
||||
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>();
|
||||
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
|
||||
|
||||
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
|
||||
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
|
||||
|
@ -150,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"
|
||||
|
@ -67,9 +68,9 @@ namespace Sandbox
|
|||
customMat->SetProperty("data.alpha", 0.1f);
|
||||
|
||||
// Create Stress Test Objects
|
||||
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f;
|
||||
constexpr int NUM_ROWS = 0;
|
||||
constexpr int NUM_COLS = 0;
|
||||
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One;
|
||||
constexpr int NUM_ROWS = 3;
|
||||
constexpr int NUM_COLS = 1;
|
||||
static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f };
|
||||
static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f };
|
||||
|
||||
|
@ -91,13 +92,13 @@ namespace Sandbox
|
|||
//Set initial positions
|
||||
transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, y * TEST_OBJ_SPACING.y, SHMath::GenerateRandomNumber(-3.5f, -5.0f) });
|
||||
//transform.SetWorldPosition({-1.0f, -1.0f, -1.0f});
|
||||
transform.SetWorldRotation(SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber());
|
||||
transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
|
||||
transform.SetWorldScale(TEST_OBJ_SCALE);
|
||||
|
||||
if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
|
||||
//if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
|
||||
collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
|
||||
else
|
||||
collider.AddBoundingSphere(0.5f, SHVec3::Zero);
|
||||
//else
|
||||
// collider.AddBoundingSphere(0.5f, SHVec3::Zero);
|
||||
|
||||
stressTestObjects.emplace_back(entity);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,8 +5,9 @@ typedef uint32_t SHEventIdentifier;
|
|||
typedef uint32_t SHEventHandle;
|
||||
|
||||
//Add your event identifiers here:
|
||||
constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0};
|
||||
constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 };
|
||||
constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 };
|
||||
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT{ 3 };
|
||||
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 };
|
||||
constexpr SHEventIdentifier SH_EXAMPLE_EVENT { 0 };
|
||||
constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT { 1 };
|
||||
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 };
|
||||
|
|
|
@ -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,185 +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);
|
||||
// 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);
|
||||
|
||||
// Check if other renderables in subBatches contain the same material instance
|
||||
bool matUnused = true;
|
||||
for (const auto& sb : subBatches)
|
||||
for (const auto& rend : sb.Renderables)
|
||||
{
|
||||
if (rend->GetMaterial() == renderable->GetMaterial())
|
||||
{
|
||||
matUnused = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Material is no longer in this library, so we remove it
|
||||
if (matUnused)
|
||||
referencedMatInstances.erase(renderable->GetMaterial());
|
||||
|
||||
// Mark all as dirty
|
||||
for (bool& dirt : isDirty)
|
||||
dirt = true;
|
||||
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 (const SHRenderable* renderable : subBatch.Renderables)
|
||||
{
|
||||
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
|
||||
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 (const SHRenderable* renderable : subBatch.Renderables)
|
||||
{
|
||||
// Transform
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(renderable->GetEID());
|
||||
if (!transform)
|
||||
{
|
||||
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
|
||||
transformData.emplace_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
transformData.emplace_back(transform->GetTRS());
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -217,224 +232,244 @@ namespace SHADE
|
|||
}
|
||||
|
||||
// Reset Transform Data
|
||||
eidData.clear();
|
||||
instancedIntegerData.clear();
|
||||
|
||||
// Populate on the CPU
|
||||
for (auto& subBatch : subBatches)
|
||||
for (const SHRenderable* renderable : subBatch.Renderables)
|
||||
for (auto rendId : subBatch.Renderables)
|
||||
{
|
||||
eidData.emplace_back(renderable->GetEID());
|
||||
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
|
||||
drawData.emplace_back(vk::DrawIndexedIndirectCommand
|
||||
{
|
||||
.indexCount = subBatch.Mesh->IndexCount,
|
||||
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
|
||||
.firstIndex = subBatch.Mesh->FirstIndex,
|
||||
.vertexOffset = subBatch.Mesh->FirstVertex,
|
||||
.firstInstance = nextInstanceIndex++
|
||||
});
|
||||
|
||||
// Fill in buffers (CPU)
|
||||
for (const SHRenderable* renderable : subBatch.Renderables)
|
||||
{
|
||||
// Transform
|
||||
EntityID eid = renderable->GetEID();
|
||||
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
|
||||
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(eid);
|
||||
|
||||
// Material Properties
|
||||
if (!EMPTY_MAT_PROPS)
|
||||
{
|
||||
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
|
||||
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
|
||||
{
|
||||
|
@ -55,7 +56,7 @@ namespace SHADE
|
|||
/* Data Members */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
Handle<SHMesh> Mesh;
|
||||
std::unordered_set<const SHRenderable*> Renderables;
|
||||
std::unordered_set<EntityID> Renderables;
|
||||
};
|
||||
/***********************************************************************************/
|
||||
/*!
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -116,8 +117,25 @@ namespace SHADE
|
|||
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
|
||||
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
|
||||
|
||||
shaderModuleLibrary.ImportAllShaderSource(device);
|
||||
shaderModuleLibrary.ReflectAllShaderModules();
|
||||
|
||||
// TODO: This is VERY temporarily here until a more solid resource management system is implemented
|
||||
shaderSourceLibrary.Init("../../TempShaderFolder/");
|
||||
|
||||
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
|
||||
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
|
||||
|
@ -158,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();
|
||||
|
@ -186,7 +215,7 @@ namespace SHADE
|
|||
auto cubeVS = shaderModuleLibrary.GetBuiltInShaderModule("TestCubeVs.glsl");
|
||||
auto cubeFS = shaderModuleLibrary.GetBuiltInShaderModule("TestCubeFs.glsl");
|
||||
|
||||
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
|
||||
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
|
||||
|
||||
}
|
||||
|
||||
|
@ -217,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
|
||||
|
@ -339,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
|
||||
|
@ -354,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();
|
||||
|
@ -387,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
|
||||
|
@ -663,10 +700,10 @@ namespace SHADE
|
|||
continue;
|
||||
|
||||
// Remove from old material's SuperBatch
|
||||
Handle<SHMaterial> prevMaterial = renderable.GetPrevMaterial();
|
||||
Handle<SHMaterialInstance> prevMaterial = renderable.GetPrevMaterial();
|
||||
if (prevMaterial)
|
||||
{
|
||||
Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
|
||||
Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
|
||||
oldSuperBatch->Remove(&renderable);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,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
|
||||
{
|
||||
|
@ -348,6 +349,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,19 +27,22 @@ namespace SHADE
|
|||
sharedMaterial = {};
|
||||
material = {};
|
||||
oldMaterial = {};
|
||||
|
||||
lightLayer = 0;
|
||||
}
|
||||
|
||||
void SHRenderable::OnDestroy()
|
||||
{
|
||||
// Remove from SuperBatch
|
||||
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
|
||||
superBatch->Remove(this);
|
||||
|
||||
// Free resources
|
||||
if (material)
|
||||
{
|
||||
material.Free();
|
||||
material = {};
|
||||
}
|
||||
|
||||
// Remove from SuperBatch
|
||||
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
|
||||
superBatch->Remove(this);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -51,20 +54,23 @@ namespace SHADE
|
|||
if (!material && sharedMaterial == materialInstance)
|
||||
return;
|
||||
|
||||
// Flag that material was changed
|
||||
materialChanged = true;
|
||||
|
||||
// Free copies of materials if any
|
||||
if (material)
|
||||
{
|
||||
oldMaterial = material;
|
||||
material.Free();
|
||||
material = {};
|
||||
}
|
||||
|
||||
// Flag that material was changed
|
||||
materialChanged = true;
|
||||
if (sharedMaterial)
|
||||
oldMaterial = sharedMaterial->GetBaseMaterial();
|
||||
else if (sharedMaterial)
|
||||
{
|
||||
oldMaterial = sharedMaterial;
|
||||
}
|
||||
|
||||
// Update the material
|
||||
sharedMaterial = materialInstance;
|
||||
sharedMaterial = materialInstance;
|
||||
}
|
||||
|
||||
Handle<SHMaterialInstance> SHRenderable::GetMaterial() const
|
||||
|
@ -87,6 +93,11 @@ namespace SHADE
|
|||
return material;
|
||||
}
|
||||
|
||||
uint8_t SHRenderable::GetLightLayer(void) const noexcept
|
||||
{
|
||||
return lightLayer;
|
||||
}
|
||||
|
||||
void SHRenderable::ResetChangedFlag()
|
||||
{
|
||||
materialChanged = false;
|
||||
|
|
|
@ -55,7 +55,8 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
bool WasMaterialChanged() const noexcept { return materialChanged; }
|
||||
Handle<SHMaterial> GetPrevMaterial() const noexcept { return oldMaterial; }
|
||||
Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
|
||||
uint8_t GetLightLayer (void) const noexcept;
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Batcher Dispatcher Functions */
|
||||
|
@ -74,7 +75,8 @@ namespace SHADE
|
|||
Handle<SHMaterialInstance> sharedMaterial;
|
||||
Handle<SHMaterialInstance> material;
|
||||
bool materialChanged = true;
|
||||
Handle<SHMaterial> oldMaterial;
|
||||
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
|
||||
|
|
|
@ -295,32 +295,33 @@ namespace SHADE
|
|||
) != 0;
|
||||
}
|
||||
|
||||
SHMatrix::operator XMMATRIX() const noexcept
|
||||
{
|
||||
return XMLoadFloat4x4(this);
|
||||
}
|
||||
|
||||
SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHMatrix::Transpose() noexcept
|
||||
{
|
||||
const XMMATRIX M = XMLoadFloat4x4(this);
|
||||
XMStoreFloat4x4(this, XMMatrixTranspose(M));
|
||||
XMStoreFloat4x4(this, XMMatrixTranspose(*this));
|
||||
}
|
||||
|
||||
void SHMatrix::Invert() noexcept
|
||||
{
|
||||
const XMMATRIX M = XMLoadFloat4x4(this);
|
||||
XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M));
|
||||
XMStoreFloat4x4(this, XMMatrixInverse(nullptr, *this));
|
||||
}
|
||||
|
||||
float SHMatrix::Determinant() const noexcept
|
||||
{
|
||||
const XMMATRIX M = XMLoadFloat4x4(this);
|
||||
return XMVectorGetX(XMMatrixDeterminant(M));
|
||||
return XMVectorGetX(XMMatrixDeterminant(*this));
|
||||
}
|
||||
|
||||
std::string SHMatrix::ToString() const noexcept
|
||||
|
@ -337,9 +338,8 @@ namespace SHADE
|
|||
bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept
|
||||
{
|
||||
XMVECTOR s, r, t;
|
||||
const XMMATRIX M = XMLoadFloat4x4(this);
|
||||
|
||||
if (!XMMatrixDecompose(&s, &r, &t, M))
|
||||
if (!XMMatrixDecompose(&s, &r, &t, *this))
|
||||
return false;
|
||||
|
||||
SHQuaternion orientation;
|
||||
|
@ -356,9 +356,8 @@ namespace SHADE
|
|||
bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept
|
||||
{
|
||||
XMVECTOR s, r, t;
|
||||
const XMMATRIX M = XMLoadFloat4x4(this);
|
||||
|
||||
if (!XMMatrixDecompose(&s, &r, &t, M))
|
||||
if (!XMMatrixDecompose(&s, &r, &t, *this))
|
||||
return false;
|
||||
|
||||
XMStoreFloat3(&scale, s);
|
||||
|
@ -376,8 +375,7 @@ namespace SHADE
|
|||
{
|
||||
SHMatrix result;
|
||||
|
||||
const XMMATRIX M = XMLoadFloat4x4(&matrix);
|
||||
XMStoreFloat4x4(&result, XMMatrixTranspose(M));
|
||||
XMStoreFloat4x4(&result, XMMatrixTranspose(matrix));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -385,8 +383,7 @@ namespace SHADE
|
|||
{
|
||||
SHMatrix result;
|
||||
|
||||
const XMMATRIX M = XMLoadFloat4x4(&matrix);
|
||||
XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M));
|
||||
XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, matrix));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -401,8 +398,8 @@ namespace SHADE
|
|||
SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -410,25 +407,23 @@ namespace SHADE
|
|||
{
|
||||
SHMatrix result;
|
||||
|
||||
const XMVECTOR A = XMLoadFloat3(&axis);
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationAxis(axis, angleInRad));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYawFromVector(eulerAngles));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -436,57 +431,55 @@ namespace SHADE
|
|||
{
|
||||
SHMatrix result;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(&q);
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(q));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::RotateX(float angleInRad) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::RotateY(float angleInRad) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept
|
||||
{
|
||||
SHMatrix result;
|
||||
XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixScalingFromVector(scale));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -494,12 +487,7 @@ namespace SHADE
|
|||
{
|
||||
SHMatrix result;
|
||||
|
||||
const XMVECTOR EYE = XMLoadFloat3(&eye);
|
||||
const XMVECTOR TGT = XMLoadFloat3(&target);
|
||||
const XMVECTOR UP = XMLoadFloat3(&up);
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixLookAtRH(eye, target, up));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -507,12 +495,7 @@ namespace SHADE
|
|||
{
|
||||
SHMatrix result;
|
||||
|
||||
const XMVECTOR EYE = XMLoadFloat3(&eye);
|
||||
const XMVECTOR TGT = XMLoadFloat3(&target);
|
||||
const XMVECTOR UP = XMLoadFloat3(&up);
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP));
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixLookAtLH(eye, target, up));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -522,8 +505,8 @@ namespace SHADE
|
|||
|
||||
const SHVec3 FWD_HAT = SHVec3::Normalise(-forward);
|
||||
|
||||
const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT));
|
||||
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT));
|
||||
const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT);
|
||||
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
|
||||
const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT);
|
||||
|
||||
XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
|
||||
|
@ -543,8 +526,8 @@ namespace SHADE
|
|||
|
||||
const SHVec3 FWD_HAT = SHVec3::Normalise(forward);
|
||||
|
||||
const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT));
|
||||
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT));
|
||||
const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT);
|
||||
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
|
||||
const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT);
|
||||
|
||||
XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
|
||||
|
@ -563,7 +546,6 @@ namespace SHADE
|
|||
SHMatrix result;
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -572,7 +554,6 @@ namespace SHADE
|
|||
SHMatrix result;
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -581,7 +562,6 @@ namespace SHADE
|
|||
SHMatrix result;
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -590,7 +570,6 @@ namespace SHADE
|
|||
SHMatrix result;
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -599,7 +578,6 @@ namespace SHADE
|
|||
SHMatrix result;
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -608,7 +586,6 @@ namespace SHADE
|
|||
SHMatrix result;
|
||||
|
||||
XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@ namespace SHADE
|
|||
SHMatrix& operator= (const SHMatrix& rhs) = default;
|
||||
SHMatrix& operator= (SHMatrix&& rhs) = default;
|
||||
|
||||
operator DirectX::XMMATRIX () const noexcept;
|
||||
|
||||
SHMatrix& operator+= (const SHMatrix& rhs) noexcept;
|
||||
SHMatrix& operator-= (const SHMatrix& rhs) noexcept;
|
||||
SHMatrix& operator*= (const SHMatrix& rhs) noexcept;
|
||||
|
|
|
@ -36,44 +36,18 @@ namespace SHADE
|
|||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
|
||||
{}
|
||||
|
||||
SHQuaternion::SHQuaternion(const SHVec4& vec4) noexcept
|
||||
: XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w )
|
||||
{}
|
||||
|
||||
SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept
|
||||
: XMFLOAT4( _x, _y, _z, _w )
|
||||
{}
|
||||
|
||||
SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept
|
||||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
|
||||
{
|
||||
XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
|
||||
}
|
||||
|
||||
SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept
|
||||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
|
||||
{
|
||||
const XMVECTOR V = XMLoadFloat3(&eulerAngles);
|
||||
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
|
||||
}
|
||||
|
||||
SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept
|
||||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
|
||||
{
|
||||
const XMVECTOR AXIS = XMLoadFloat3(&axis);
|
||||
XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad));
|
||||
}
|
||||
|
||||
SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept
|
||||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
|
||||
{
|
||||
const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix);
|
||||
XMStoreFloat4(this, XMQuaternionRotationMatrix(M));
|
||||
}
|
||||
|
||||
SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept
|
||||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
|
||||
{
|
||||
const SHVec3& SHADE_VEC{ rp3dEuler };
|
||||
|
||||
const XMVECTOR V = XMLoadFloat3(&SHADE_VEC);
|
||||
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
|
||||
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler }));
|
||||
}
|
||||
|
||||
SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept
|
||||
|
@ -113,10 +87,7 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
|
||||
|
||||
XMStoreFloat4(&result, XMVectorAdd(Q1, Q2));
|
||||
XMStoreFloat4(&result, XMVectorAdd(*this, rhs));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -124,10 +95,7 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
|
||||
|
||||
XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2));
|
||||
XMStoreFloat4(&result, XMVectorSubtract(*this, rhs));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -135,9 +103,7 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
|
||||
XMStoreFloat4(&result, XMVectorNegate(Q));
|
||||
XMStoreFloat4(&result, XMVectorNegate(*this));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -145,10 +111,7 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
|
||||
XMStoreFloat4(&result, XMQuaternionMultiply(*this, rhs));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -156,9 +119,7 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
|
||||
XMStoreFloat4(&result, XMVectorScale(Q, rhs));
|
||||
XMStoreFloat4(&result, XMVectorScale(*this, rhs));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -166,27 +127,18 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs));
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
|
||||
XMStoreFloat4(&result, XMQuaternionMultiply(*this, XMQuaternionInverse(rhs)));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept
|
||||
{
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
|
||||
|
||||
return XMQuaternionEqual(Q1, Q2);
|
||||
return XMQuaternionEqual(*this, rhs);
|
||||
}
|
||||
|
||||
bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept
|
||||
{
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
|
||||
|
||||
return XMQuaternionNotEqual(Q1, Q2);
|
||||
return XMQuaternionNotEqual(*this, rhs);
|
||||
}
|
||||
|
||||
SHQuaternion::operator reactphysics3d::Quaternion() const noexcept
|
||||
|
@ -199,6 +151,11 @@ namespace SHADE
|
|||
return reactphysics3d::Vector3{ ToEuler() };
|
||||
}
|
||||
|
||||
SHQuaternion::operator XMVECTOR() const noexcept
|
||||
{
|
||||
return XMLoadFloat4(this);
|
||||
}
|
||||
|
||||
SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept
|
||||
{
|
||||
return rhs * lhs;
|
||||
|
@ -213,8 +170,7 @@ namespace SHADE
|
|||
XMVECTOR axis;
|
||||
float angle;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
XMQuaternionToAxisAngle(&axis, &angle, Q);
|
||||
XMQuaternionToAxisAngle(&axis, &angle, *this);
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
@ -223,8 +179,7 @@ namespace SHADE
|
|||
XMVECTOR axis;
|
||||
float angle;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
XMQuaternionToAxisAngle(&axis, &angle, Q);
|
||||
XMQuaternionToAxisAngle(&axis, &angle, *this);
|
||||
|
||||
|
||||
return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle};
|
||||
|
@ -238,64 +193,49 @@ namespace SHADE
|
|||
|
||||
void SHQuaternion::Invert() noexcept
|
||||
{
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
XMStoreFloat4(this, XMQuaternionInverse(Q));
|
||||
XMStoreFloat4(this, XMQuaternionInverse(*this));
|
||||
}
|
||||
|
||||
float SHQuaternion::Length() const noexcept
|
||||
{
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
return XMVectorGetX(XMQuaternionLength(Q));
|
||||
return XMVectorGetX(XMQuaternionLength(*this));
|
||||
}
|
||||
|
||||
float SHQuaternion::LengthSquared() const noexcept
|
||||
{
|
||||
const XMVECTOR Q = XMLoadFloat4(this);
|
||||
return XMVectorGetX(XMQuaternionLengthSq(Q));
|
||||
return XMVectorGetX(XMQuaternionLengthSq(*this));
|
||||
}
|
||||
|
||||
float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept
|
||||
{
|
||||
const XMVECTOR Q1 = XMLoadFloat4(this);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
|
||||
|
||||
return XMVectorGetX(XMQuaternionDot(Q1, Q2));
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
// TODO (Diren)
|
||||
|
||||
return result;
|
||||
return XMVectorGetX(XMQuaternionDot(*this, rhs));
|
||||
}
|
||||
|
||||
SHVec3 SHQuaternion::ToEuler() const noexcept
|
||||
{
|
||||
const float xx = x * x;
|
||||
const float yy = y * y;
|
||||
const float zz = z * z;
|
||||
const float XX = x * x;
|
||||
const float YY = y * y;
|
||||
const float ZZ = z * z;
|
||||
|
||||
const float m31 = 2.f * x * z + 2.f * y * w;
|
||||
const float m32 = 2.f * y * z - 2.f * x * w;
|
||||
const float m33 = 1.f - 2.f * xx - 2.f * yy;
|
||||
const float M_31 = 2.f * x * z + 2.f * y * w;
|
||||
const float M_32 = 2.f * y * z - 2.f * x * w;
|
||||
const float M_33 = 1.f - 2.f * XX - 2.f * YY;
|
||||
|
||||
const float cy = sqrtf(m33 * m33 + m31 * m31);
|
||||
const float cx = atan2f(-m32, cy);
|
||||
if (cy > 16.0f * SHMath::EPSILON)
|
||||
const float CY = sqrtf(M_33 * M_33 + M_31 * M_31);
|
||||
const float CX = atan2f(-M_32, CY);
|
||||
if (CY > 16.0f * SHMath::EPSILON)
|
||||
{
|
||||
const float m12 = 2.f * x * y + 2.f * z * w;
|
||||
const float m22 = 1.f - 2.f * xx - 2.f * zz;
|
||||
const float M_12 = 2.f * x * y + 2.f * z * w;
|
||||
const float M_22 = 1.f - 2.f * XX - 2.f * ZZ;
|
||||
|
||||
return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22));
|
||||
return SHVec3(CX, atan2f(M_31, M_33), atan2f(M_12, M_22));
|
||||
}
|
||||
else
|
||||
{
|
||||
const float m11 = 1.f - 2.f * yy - 2.f * zz;
|
||||
const float m21 = 2.f * x * y - 2.f * z * w;
|
||||
const float m11 = 1.f - 2.f * YY - 2.f * ZZ;
|
||||
const float m21 = 2.f * x * y - 2.f * z * w;
|
||||
|
||||
return SHVec3(cx, 0.f, atan2f(-m21, m11));
|
||||
return SHVec3(CX, 0.f, atan2f(-m21, m11));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -311,13 +251,43 @@ namespace SHADE
|
|||
/* Static Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHQuaternion SHQuaternion::FromEuler(const SHVec3& eulerAngles) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionRotationRollPitchYawFromVector(eulerAngles));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::FromPitchYawRoll(float pitch, float yaw, float roll) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::FromAxisAngle(const SHVec3& axis, float angle) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionRotationAxis(axis, angle));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionRotationMatrix(rotationMatrix));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(&q);
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionNormalize(Q));
|
||||
XMStoreFloat4(&result, XMQuaternionNormalize(q));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -325,9 +295,7 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(&q);
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionConjugate(Q));
|
||||
XMStoreFloat4(&result, XMQuaternionConjugate(q));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -335,26 +303,37 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q = XMLoadFloat4(&q);
|
||||
XMStoreFloat4(&result, XMQuaternionInverse(Q));
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionInverse(q));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept
|
||||
float SHQuaternion::Angle(const SHQuaternion& q1, const SHQuaternion& q2) noexcept
|
||||
{
|
||||
// TODO (Diren)
|
||||
XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(q1), q2);
|
||||
|
||||
return 0.0f;
|
||||
const float RS = XMVectorGetW(R);
|
||||
R = XMVector3Length(R);
|
||||
return 2.0f * atan2f(XMVectorGetX(R), RS);
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept
|
||||
SHQuaternion SHQuaternion::Lerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
// TODO (Diren)
|
||||
XMVECTOR R = XMVectorZero();
|
||||
if (XMVector4GreaterOrEqual(XMVector4Dot(q1, q2), R))
|
||||
{
|
||||
R = XMVectorLerp(q1, q2, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
const XMVECTOR X0 = XMVectorMultiply(q1, XMVectorReplicate(1.f - t));
|
||||
const XMVECTOR X1 = XMVectorMultiply(q2, XMVectorReplicate(t));
|
||||
R = XMVectorSubtract(X0, X1);
|
||||
}
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionNormalize(R));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -362,19 +341,105 @@ namespace SHADE
|
|||
{
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR Q1 = XMLoadFloat4(&q1);
|
||||
const XMVECTOR Q2 = XMLoadFloat4(&q2);
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t));
|
||||
XMStoreFloat4(&result, XMQuaternionSlerp(q1, q2, t));
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept
|
||||
SHQuaternion SHQuaternion::ClampedLerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
|
||||
{
|
||||
return Lerp(q1, q2, std::clamp(t, tMin, tMax));
|
||||
}
|
||||
|
||||
|
||||
SHQuaternion SHQuaternion::ClampedSlerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
|
||||
{
|
||||
return Slerp(q1, q2, std::clamp(t, tMin, tMax));
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::FromToRotation(const SHVec3& from, const SHVec3& to) noexcept
|
||||
{
|
||||
// Melax, "The Shortest Arc Quaternion", Game Programming Gems
|
||||
|
||||
SHQuaternion result;
|
||||
|
||||
const XMVECTOR F = XMVector3Normalize(from);
|
||||
const XMVECTOR T = XMVector3Normalize(to);
|
||||
|
||||
const float dot = XMVectorGetX(XMVector3Dot(F, T));
|
||||
if (dot >= 1.f)
|
||||
{
|
||||
result = Identity;
|
||||
}
|
||||
else if (dot <= -1.f)
|
||||
{
|
||||
XMVECTOR axis = XMVector3Cross(F, SHVec3::Right);
|
||||
if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon))
|
||||
{
|
||||
axis = XMVector3Cross(F, SHVec3::Up);
|
||||
}
|
||||
|
||||
const XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI);
|
||||
XMStoreFloat4(&result, Q);
|
||||
}
|
||||
else
|
||||
{
|
||||
const XMVECTOR C = XMVector3Cross(F, T);
|
||||
XMStoreFloat4(&result, C);
|
||||
|
||||
const float s = sqrtf((1.f + dot) * 2.f);
|
||||
result.x /= s;
|
||||
result.y /= s;
|
||||
result.z /= s;
|
||||
result.w = s * 0.5f;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::LookRotation(const SHVec3& forward, const SHVec3& up) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
// TODO (Diren)
|
||||
const SHQuaternion Q1 = FromToRotation(SHVec3::Forward, forward);
|
||||
|
||||
const XMVECTOR C = XMVector3Cross(forward, up);
|
||||
if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon))
|
||||
{
|
||||
// forward and up are co-linear
|
||||
return Q1;
|
||||
}
|
||||
|
||||
SHVec3 qU;
|
||||
XMStoreFloat3(&qU, XMQuaternionMultiply(Q1, SHVec3::Up));
|
||||
|
||||
const SHQuaternion Q2 = FromToRotation(qU, up);
|
||||
|
||||
XMStoreFloat4(&result, XMQuaternionMultiply(Q2, Q1));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept
|
||||
{
|
||||
SHQuaternion result;
|
||||
|
||||
// We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
|
||||
const XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(from), to);
|
||||
|
||||
const float RS = XMVectorGetW(R);
|
||||
const XMVECTOR L = XMVector3Length(R);
|
||||
const float angle = 2.f * atan2f(XMVectorGetX(L), RS);
|
||||
if (angle > maxAngleInRad)
|
||||
{
|
||||
const XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngleInRad);
|
||||
const XMVECTOR Q = XMQuaternionMultiply(delta, from);
|
||||
XMStoreFloat4(&result, Q);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't overshoot.
|
||||
result = to;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,8 @@ namespace SHADE
|
|||
SHQuaternion (SHQuaternion&& rhs) = default;
|
||||
|
||||
SHQuaternion () noexcept;
|
||||
SHQuaternion (const SHVec4& vec4) noexcept;
|
||||
SHQuaternion (float x, float y, float z, float w) noexcept;
|
||||
SHQuaternion (float yaw, float pitch, float roll) noexcept;
|
||||
SHQuaternion (const SHVec3& eulerAngles) noexcept;
|
||||
SHQuaternion (const SHVec3& axis, float angleInRad) noexcept;
|
||||
SHQuaternion (const SHMatrix& rotationMatrix) noexcept;
|
||||
|
||||
// Conversion from other math types
|
||||
|
||||
|
@ -87,6 +84,7 @@ namespace SHADE
|
|||
|
||||
operator reactphysics3d::Quaternion () const noexcept;
|
||||
operator reactphysics3d::Vector3 () const noexcept;
|
||||
operator DirectX::XMVECTOR () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
|
@ -99,29 +97,37 @@ namespace SHADE
|
|||
/* Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void Invert () noexcept;
|
||||
void Invert () noexcept;
|
||||
|
||||
[[nodiscard]] float Length () const noexcept;
|
||||
[[nodiscard]] float LengthSquared () const noexcept;
|
||||
[[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept;
|
||||
[[nodiscard]] SHQuaternion RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept;
|
||||
[[nodiscard]] float Length () const noexcept;
|
||||
[[nodiscard]] float LengthSquared () const noexcept;
|
||||
[[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept;
|
||||
|
||||
[[nodiscard]] SHVec3 ToEuler () const noexcept;
|
||||
[[nodiscard]] std::string ToString () const noexcept;
|
||||
[[nodiscard]] SHVec3 ToEuler () const noexcept;
|
||||
[[nodiscard]] std::string ToString () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Static Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept;
|
||||
[[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept;
|
||||
[[nodiscard]] static SHQuaternion FromEuler (const SHVec3& eulerAngles) noexcept;
|
||||
[[nodiscard]] static SHQuaternion FromPitchYawRoll (float pitch, float yaw, float roll) noexcept;
|
||||
[[nodiscard]] static SHQuaternion FromAxisAngle (const SHVec3& axis, float angle) noexcept;
|
||||
[[nodiscard]] static SHQuaternion FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept;
|
||||
|
||||
[[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept;
|
||||
[[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept;
|
||||
|
||||
[[nodiscard]] static SHQuaternion Rotate (const SHVec3& from, const SHVec3& to) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
|
||||
[[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
|
||||
[[nodiscard]] static SHQuaternion ClampedLerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
|
||||
[[nodiscard]] static SHQuaternion ClampedSlerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
|
||||
|
||||
[[nodiscard]] static SHQuaternion FromToRotation (const SHVec3& from, const SHVec3& to) noexcept;
|
||||
[[nodiscard]] static SHQuaternion LookRotation (const SHVec3& forward, const SHVec3& up) noexcept;
|
||||
[[nodiscard]] static SHQuaternion RotateTowards (const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept;
|
||||
};
|
||||
|
||||
SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept;
|
||||
|
|
|
@ -26,15 +26,15 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHTransform::SHTransform() noexcept
|
||||
: position { SHVec3::Zero }
|
||||
, rotation { SHVec3::Zero }
|
||||
, scale { SHVec3::One }
|
||||
: position { SHVec3::Zero }
|
||||
, orientation { SHQuaternion::Identity }
|
||||
, scale { SHVec3::One }
|
||||
{}
|
||||
|
||||
SHTransform::SHTransform(const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept
|
||||
: position { pos }
|
||||
, rotation { rot }
|
||||
, scale { scl }
|
||||
: position { pos }
|
||||
, orientation { SHQuaternion::FromEuler(rot) }
|
||||
, scale { scl }
|
||||
{}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -43,12 +43,12 @@ namespace SHADE
|
|||
|
||||
bool SHTransform::operator==(const SHTransform& rhs) const noexcept
|
||||
{
|
||||
return !(position != rhs.position || rotation != rhs.rotation || scale != rhs.scale);
|
||||
return !(position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
|
||||
}
|
||||
|
||||
bool SHTransform::operator!=(const SHTransform& rhs) const noexcept
|
||||
{
|
||||
return (position != rhs.position || rotation != rhs.rotation || scale != rhs.scale);
|
||||
return (position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -59,7 +59,7 @@ namespace SHADE
|
|||
{
|
||||
|
||||
const SHMatrix T = SHMatrix::Translate(position);
|
||||
const SHMatrix R = SHMatrix::Rotate(rotation);
|
||||
const SHMatrix R = SHMatrix::Rotate(orientation);
|
||||
const SHMatrix S = SHMatrix::Scale(scale);
|
||||
|
||||
trs = S * R * T;
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
// Project Headers
|
||||
#include "SH_API.h"
|
||||
#include "Math/Vector/SHVec2.h"
|
||||
#include "Math/Vector/SHVec3.h"
|
||||
#include "Math/SHQuaternion.h"
|
||||
#include "Math/SHMatrix.h"
|
||||
|
||||
namespace SHADE
|
||||
|
@ -31,22 +31,23 @@ namespace SHADE
|
|||
|
||||
static const SHTransform Identity;
|
||||
|
||||
SHVec3 position;
|
||||
SHVec3 rotation;
|
||||
SHVec3 scale;
|
||||
SHVec3 position;
|
||||
SHQuaternion orientation;
|
||||
SHVec3 scale;
|
||||
|
||||
SHMatrix trs;
|
||||
SHMatrix trs;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHTransform (const SHTransform&) = default;
|
||||
SHTransform (SHTransform&&) = default;
|
||||
~SHTransform () = default;
|
||||
SHTransform (const SHTransform&) = default;
|
||||
SHTransform (SHTransform&&) = default;
|
||||
~SHTransform () = default;
|
||||
|
||||
SHTransform () noexcept;
|
||||
SHTransform (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept;
|
||||
SHTransform () noexcept;
|
||||
SHTransform (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept;
|
||||
SHTransform (const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
|
@ -63,7 +64,6 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
const SHMatrix& ComputeTRS();
|
||||
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
// Primary Header
|
||||
#include "SHTransformComponent.h"
|
||||
// Project Headers
|
||||
#include "Math/SHMathHelpers.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -40,7 +42,12 @@ namespace SHADE
|
|||
|
||||
const SHVec3& SHTransformComponent::GetLocalRotation() const noexcept
|
||||
{
|
||||
return local.rotation;
|
||||
return localRotation;
|
||||
}
|
||||
|
||||
const SHQuaternion& SHTransformComponent::GetLocalOrientation() const noexcept
|
||||
{
|
||||
return local.orientation;
|
||||
}
|
||||
|
||||
const SHVec3& SHTransformComponent::GetLocalScale() const noexcept
|
||||
|
@ -55,7 +62,12 @@ namespace SHADE
|
|||
|
||||
const SHVec3& SHTransformComponent::GetWorldRotation() const noexcept
|
||||
{
|
||||
return world.rotation;
|
||||
return worldRotation;
|
||||
}
|
||||
|
||||
const SHQuaternion& SHTransformComponent::GetWorldOrientation() const noexcept
|
||||
{
|
||||
return world.orientation;
|
||||
}
|
||||
|
||||
const SHVec3& SHTransformComponent::GetWorldScale() const noexcept
|
||||
|
@ -91,16 +103,28 @@ namespace SHADE
|
|||
void SHTransformComponent::SetLocalRotation(const SHVec3& newLocalRotation) noexcept
|
||||
{
|
||||
dirty = true;
|
||||
local.rotation = newLocalRotation;
|
||||
|
||||
localRotation = newLocalRotation;
|
||||
updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, newLocalRotation });
|
||||
}
|
||||
|
||||
void SHTransformComponent::SetLocalRotation(float pitch, float yaw, float roll) noexcept
|
||||
{
|
||||
dirty = true;
|
||||
|
||||
local.rotation.x = pitch;
|
||||
local.rotation.y = yaw;
|
||||
local.rotation.z = roll;
|
||||
localRotation.x = pitch;
|
||||
localRotation.y = yaw;
|
||||
localRotation.z = roll;
|
||||
|
||||
updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, SHVec3{pitch, yaw, roll} });
|
||||
}
|
||||
|
||||
void SHTransformComponent::SetLocalOrientation(const SHQuaternion& newLocalOrientation) noexcept
|
||||
{
|
||||
dirty = true;
|
||||
|
||||
local.orientation = newLocalOrientation;
|
||||
updateQueue.push({ UpdateCommandType::LOCAL_ORIENTATION, newLocalOrientation });
|
||||
}
|
||||
|
||||
void SHTransformComponent::SetLocalScale(const SHVec3& newLocalScale) noexcept
|
||||
|
@ -121,7 +145,7 @@ namespace SHADE
|
|||
{
|
||||
dirty = true;
|
||||
|
||||
world.rotation = newWorldRotation;
|
||||
worldRotation = newWorldRotation;
|
||||
updateQueue.push({ UpdateCommandType::WORLD_ROTATION, newWorldRotation });
|
||||
}
|
||||
|
||||
|
@ -129,13 +153,21 @@ namespace SHADE
|
|||
{
|
||||
dirty = true;
|
||||
|
||||
world.rotation.x = pitch;
|
||||
world.rotation.y = yaw;
|
||||
world.rotation.z = roll;
|
||||
worldRotation.x = pitch;
|
||||
worldRotation.y = yaw;
|
||||
worldRotation.z = roll;
|
||||
|
||||
updateQueue.push({ UpdateCommandType::WORLD_ROTATION, SHVec3{ pitch, yaw, roll} });
|
||||
}
|
||||
|
||||
void SHTransformComponent::SetWorldOrientation(const SHQuaternion& newWorldOrientation) noexcept
|
||||
{
|
||||
dirty = true;
|
||||
|
||||
world.orientation = newWorldOrientation;
|
||||
updateQueue.push({ UpdateCommandType::WORLD_ORIENTATION, newWorldOrientation });
|
||||
}
|
||||
|
||||
void SHTransformComponent::SetWorldScale(const SHVec3& newWorldScale) noexcept
|
||||
{
|
||||
dirty = true;
|
||||
|
@ -153,6 +185,6 @@ RTTR_REGISTRATION
|
|||
|
||||
registration::class_<SHTransformComponent>("Transform Component")
|
||||
.property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition )
|
||||
.property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload<void(SHVec3 const&)>(&SHTransformComponent::SetLocalRotation) )
|
||||
.property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) )
|
||||
.property("Scale" , &SHTransformComponent::GetLocalScale , &SHTransformComponent::SetLocalScale );
|
||||
}
|
|
@ -56,42 +56,52 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] bool HasChanged () const noexcept;
|
||||
[[nodiscard]] bool HasChanged () const noexcept;
|
||||
|
||||
[[nodiscard]] const SHVec3& GetLocalPosition () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetLocalRotation () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetLocalScale () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetWorldPosition () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetWorldRotation () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetWorldScale () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetLocalPosition () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetLocalRotation () const noexcept;
|
||||
[[nodiscard]] const SHQuaternion& GetLocalOrientation () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetLocalScale () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetWorldPosition () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetWorldRotation () const noexcept;
|
||||
[[nodiscard]] const SHQuaternion& GetWorldOrientation () const noexcept;
|
||||
[[nodiscard]] const SHVec3& GetWorldScale () const noexcept;
|
||||
|
||||
[[nodiscard]] const SHMatrix& GetLocalToWorld () const noexcept;
|
||||
[[nodiscard]] SHMatrix GetWorldToLocal () const noexcept;
|
||||
[[nodiscard]] const SHMatrix& GetLocalToWorld () const noexcept;
|
||||
[[nodiscard]] SHMatrix GetWorldToLocal () const noexcept;
|
||||
|
||||
[[nodiscard]] const SHMatrix& GetTRS () const noexcept;
|
||||
[[nodiscard]] const SHMatrix& GetTRS () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Setter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void SetLocalPosition (const SHVec3& newLocalPosition) noexcept;
|
||||
void SetLocalRotation (const SHVec3& newLocalRotation) noexcept;
|
||||
void SetLocalRotation (float pitch, float yaw, float roll) noexcept;
|
||||
void SetLocalScale (const SHVec3& newLocalScale) noexcept;
|
||||
void SetWorldPosition (const SHVec3& newWorldPosition) noexcept;
|
||||
void SetWorldRotation (const SHVec3& newWorldRotation) noexcept;
|
||||
void SetWorldRotation (float pitch, float yaw, float roll) noexcept;
|
||||
void SetWorldScale (const SHVec3& newWorldScale) noexcept;
|
||||
void SetLocalPosition (const SHVec3& newLocalPosition) noexcept;
|
||||
void SetLocalRotation (const SHVec3& newLocalRotation) noexcept;
|
||||
void SetLocalRotation (float pitch, float yaw, float roll) noexcept;
|
||||
void SetLocalOrientation (const SHQuaternion& newLocalOrientation) noexcept;
|
||||
void SetLocalScale (const SHVec3& newLocalScale) noexcept;
|
||||
void SetWorldPosition (const SHVec3& newWorldPosition) noexcept;
|
||||
void SetWorldRotation (const SHVec3& newWorldRotation) noexcept;
|
||||
void SetWorldRotation (float pitch, float yaw, float roll) noexcept;
|
||||
void SetWorldOrientation (const SHQuaternion& newWorldOrientation) noexcept;
|
||||
void SetWorldScale (const SHVec3& newWorldScale) noexcept;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
// Differentiate between rotation and orientation for setters
|
||||
// Setting a quaternion directly is different from using euler angle rotations.
|
||||
|
||||
enum class UpdateCommandType
|
||||
{
|
||||
WORLD_POSITION
|
||||
LOCAL_ROTATION
|
||||
, LOCAL_ORIENTATION
|
||||
, WORLD_POSITION
|
||||
, WORLD_ROTATION
|
||||
, WORLD_ORIENTATION
|
||||
, WORLD_SCALE
|
||||
};
|
||||
|
||||
|
@ -103,7 +113,7 @@ namespace SHADE
|
|||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
UpdateCommandType type;
|
||||
SHVec3 data;
|
||||
SHVec4 data;
|
||||
};
|
||||
|
||||
using UpdateQueue = std::queue<UpdateCommand>;
|
||||
|
@ -114,6 +124,12 @@ namespace SHADE
|
|||
|
||||
bool dirty;
|
||||
|
||||
// We store euler angle rotations separately to interface with transform quaternions.
|
||||
// Reading quaternions are unreliable.
|
||||
|
||||
SHVec3 localRotation; // Stored in Radians
|
||||
SHVec3 worldRotation; // Stored in Radians
|
||||
|
||||
SHTransform local; // Local TRS holds Local To World Transform
|
||||
SHTransform world;
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#include "Scene/SHSceneManager.h"
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
#include "ECS_Base/Managers/SHEntityManager.h"
|
||||
#include "Tools/SHException.h"
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Math/SHMathHelpers.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -29,8 +30,12 @@ namespace SHADE
|
|||
/* Constructors & Destructor Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHTransformSystem::TransformUpdateRoutine::TransformUpdateRoutine()
|
||||
: SHSystemRoutine { "Transform Update", true }
|
||||
SHTransformSystem::TransformPostLogicUpdate::TransformPostLogicUpdate()
|
||||
: SHSystemRoutine { "Transform Post-Logic Update", true }
|
||||
{}
|
||||
|
||||
SHTransformSystem::TransformPostPhysicsUpdate::TransformPostPhysicsUpdate()
|
||||
: SHSystemRoutine { "Transform Post-Physics Update", false }
|
||||
{}
|
||||
|
||||
|
||||
|
@ -38,16 +43,27 @@ namespace SHADE
|
|||
/* Public Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHTransformSystem::TransformUpdateRoutine::Execute(double) noexcept
|
||||
void SHTransformSystem::TransformPostLogicUpdate::Execute(double) noexcept
|
||||
{
|
||||
// Get the current scene graph to traverse and update
|
||||
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
|
||||
UpdateEntity(SCENE_GRAPH.GetRoot());
|
||||
|
||||
// TODO(Diren): Consider how to clear dirty in pause / stop mode and update physics, but do not clear in play mode.
|
||||
UpdateEntity(SCENE_GRAPH.GetRoot(), false);
|
||||
}
|
||||
|
||||
void SHTransformSystem::TransformPostPhysicsUpdate::Execute(double) noexcept
|
||||
{
|
||||
// Get the current scene graph to traverse and update
|
||||
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
|
||||
UpdateEntity(SCENE_GRAPH.GetRoot(), true);
|
||||
}
|
||||
|
||||
void SHTransformSystem::Init()
|
||||
{
|
||||
|
||||
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()
|
||||
|
@ -59,7 +75,53 @@ namespace SHADE
|
|||
/* Private Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHTransformSystem::UpdateEntity(const SHSceneNode* node)
|
||||
void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node)
|
||||
{
|
||||
// Structure is similar to update entity, albeit without a queue to do being a forced update
|
||||
for (const auto* child : node->GetChildren())
|
||||
{
|
||||
if (auto* childTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(child->GetEntityID()); childTransform)
|
||||
{
|
||||
const bool IS_NODE_ACTIVE = child->IsActive();
|
||||
if (IS_NODE_ACTIVE && childTransform->isActive)
|
||||
{
|
||||
// Recompute local transform and store localToWorld Matrix
|
||||
SHMatrix localToWorld = SHMatrix::Identity;
|
||||
SHMatrix worldToLocal = SHMatrix::Identity;
|
||||
|
||||
const auto* parent = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
|
||||
|
||||
if (parent != nullptr) // Not the root
|
||||
{
|
||||
localToWorld = parent->GetTRS();
|
||||
worldToLocal = SHMatrix::Inverse(localToWorld);
|
||||
}
|
||||
|
||||
// Maintain World Transform and recompute Local Transform
|
||||
|
||||
// Compute Local Position
|
||||
childTransform->local.position = SHVec3::Transform(childTransform->world.position, worldToLocal);
|
||||
|
||||
|
||||
childTransform->localRotation = childTransform->worldRotation;
|
||||
childTransform->local.scale = childTransform->world.scale;
|
||||
|
||||
if (parent)
|
||||
{
|
||||
// Compute Local Rotation
|
||||
childTransform->localRotation -= parent->GetLocalRotation();
|
||||
|
||||
// Compute Local Scale
|
||||
childTransform->local.scale /= parent->GetLocalScale();
|
||||
}
|
||||
|
||||
childTransform->local.trs = localToWorld;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHTransformSystem::UpdateEntity(const SHSceneNode* node, bool clearDirtyFlag)
|
||||
{
|
||||
const auto* NODE_TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
|
||||
const bool HAS_PARENT_CHANGED = NODE_TRANSFORM && NODE_TRANSFORM->dirty;
|
||||
|
@ -74,14 +136,17 @@ namespace SHADE
|
|||
if (IS_NODE_ACTIVE && childTransform->isActive)
|
||||
{
|
||||
if (childTransform->dirty || HAS_PARENT_CHANGED)
|
||||
{
|
||||
UpdateTransform(*childTransform, NODE_TRANSFORM);
|
||||
childTransform->dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateEntity(child);
|
||||
UpdateEntity(child, clearDirtyFlag);
|
||||
|
||||
// Clear dirty flag after all children are updated
|
||||
if (childTransform)
|
||||
if (childTransform && clearDirtyFlag)
|
||||
childTransform->dirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +156,8 @@ namespace SHADE
|
|||
SHMatrix localToWorld = SHMatrix::Identity;
|
||||
SHMatrix worldToLocal = SHMatrix::Identity;
|
||||
|
||||
bool convertRotation = true;
|
||||
|
||||
if (parent)
|
||||
{
|
||||
localToWorld = parent->GetTRS();
|
||||
|
@ -103,22 +170,44 @@ namespace SHADE
|
|||
|
||||
switch (UPDATE_COMMAND.type)
|
||||
{
|
||||
case SHTransformComponent::UpdateCommandType::LOCAL_ROTATION:
|
||||
{
|
||||
convertRotation = true;
|
||||
break;
|
||||
}
|
||||
case SHTransformComponent::UpdateCommandType::LOCAL_ORIENTATION:
|
||||
{
|
||||
convertRotation = false;
|
||||
break;
|
||||
}
|
||||
case SHTransformComponent::UpdateCommandType::WORLD_POSITION:
|
||||
{
|
||||
tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data, worldToLocal);
|
||||
tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data.ToVec3(), worldToLocal);
|
||||
break;
|
||||
}
|
||||
case SHTransformComponent::UpdateCommandType::WORLD_ROTATION:
|
||||
{
|
||||
tf.local.rotation = tf.world.rotation;
|
||||
tf.localRotation = UPDATE_COMMAND.data.ToVec3();
|
||||
if (parent)
|
||||
tf.local.rotation -= parent->GetLocalRotation();
|
||||
tf.localRotation -= parent->GetLocalRotation();
|
||||
|
||||
convertRotation = true;
|
||||
|
||||
break;
|
||||
}
|
||||
case SHTransformComponent::UpdateCommandType::WORLD_ORIENTATION:
|
||||
{
|
||||
tf.local.orientation = UPDATE_COMMAND.data;
|
||||
if (parent)
|
||||
tf.local.orientation /= parent->GetLocalOrientation();
|
||||
|
||||
convertRotation = false;
|
||||
|
||||
break;
|
||||
}
|
||||
case SHTransformComponent::UpdateCommandType::WORLD_SCALE:
|
||||
{
|
||||
tf.local.scale = tf.world.scale;
|
||||
tf.local.scale = UPDATE_COMMAND.data.ToVec3();
|
||||
if (parent)
|
||||
tf.local.scale /= parent->GetLocalScale();
|
||||
|
||||
|
@ -133,15 +222,83 @@ namespace SHADE
|
|||
|
||||
tf.local.trs = localToWorld;
|
||||
|
||||
// Compute world transforms
|
||||
tf.world.position = SHVec3::Transform(tf.local.position, localToWorld);
|
||||
tf.world.rotation = tf.local.rotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
|
||||
tf.world.scale = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One);
|
||||
|
||||
tf.world.ComputeTRS();
|
||||
|
||||
|
||||
// Transpose TRS to column major
|
||||
//tf.local.trs.Transpose();
|
||||
//tf.world.trs.Transpose();
|
||||
if (convertRotation)
|
||||
{
|
||||
tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
|
||||
|
||||
// Set the orientation
|
||||
// Wrap rotations between -360 and 360 and convert to radians
|
||||
SHVec3 worldRotRad, localRotRad;
|
||||
for (size_t i = 0; i < SHVec3::SIZE; ++i)
|
||||
{
|
||||
worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
|
||||
localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
|
||||
}
|
||||
|
||||
tf.world.orientation = SHQuaternion::FromEuler(worldRotRad);
|
||||
tf.local.orientation = SHQuaternion::FromEuler(localRotRad);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf.world.orientation = (parent ? parent->GetLocalOrientation() : SHQuaternion::Identity) * tf.local.orientation;
|
||||
|
||||
// Set the euler angle rotations
|
||||
tf.worldRotation = tf.world.orientation.ToEuler();
|
||||
tf.localRotation = tf.local.orientation.ToEuler();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -45,25 +45,30 @@ namespace SHADE
|
|||
/* System Routines */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
class SH_API TransformUpdateRoutine final: public SHSystemRoutine
|
||||
class SH_API TransformPostLogicUpdate final: public SHSystemRoutine
|
||||
{
|
||||
public:
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
TransformUpdateRoutine ();
|
||||
~TransformUpdateRoutine () = default;
|
||||
|
||||
TransformUpdateRoutine (const TransformUpdateRoutine&) = delete;
|
||||
TransformUpdateRoutine (TransformUpdateRoutine&&) = delete;
|
||||
TransformPostLogicUpdate ();
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/* Function Members */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
TransformUpdateRoutine& operator= (const TransformUpdateRoutine&) = delete;
|
||||
TransformUpdateRoutine& operator= (TransformUpdateRoutine&&) = delete;
|
||||
void Execute(double dt) noexcept override;
|
||||
};
|
||||
|
||||
class SH_API TransformPostPhysicsUpdate final: public SHSystemRoutine
|
||||
{
|
||||
public:
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
TransformPostPhysicsUpdate ();
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Function Members */
|
||||
|
@ -84,8 +89,14 @@ namespace SHADE
|
|||
/* Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
static void UpdateEntity (const SHSceneNode* node);
|
||||
static void UpdateTransform(SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,10 @@ namespace SHADE
|
|||
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f )
|
||||
{}
|
||||
|
||||
SHVec4::SHVec4(const SHVec3& vec3) noexcept
|
||||
: XMFLOAT4( vec3.x, vec3.y, vec3.z, 1.0f )
|
||||
{}
|
||||
|
||||
SHVec4::SHVec4(const XMFLOAT4& xmfloat4) noexcept
|
||||
: XMFLOAT4( xmfloat4.x, xmfloat4.y, xmfloat4.z, xmfloat4.w )
|
||||
{}
|
||||
|
@ -271,6 +275,11 @@ namespace SHADE
|
|||
return result;
|
||||
}
|
||||
|
||||
SHVec3 SHVec4::ToVec3() const noexcept
|
||||
{
|
||||
return SHVec3{ x, y, z };
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Static Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
// Project Headers
|
||||
#include "SH_API.h"
|
||||
#include "SHVec3.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -53,6 +54,7 @@ namespace SHADE
|
|||
~SHVec4 () = default;
|
||||
|
||||
SHVec4 () noexcept;
|
||||
SHVec4 (const SHVec3& vec3) noexcept;
|
||||
SHVec4 (const XMFLOAT4& xmfloat4) noexcept;
|
||||
SHVec4 (float x, float y, float z, float w) noexcept;
|
||||
|
||||
|
@ -102,16 +104,18 @@ namespace SHADE
|
|||
[[nodiscard]] float Dot3D (const SHVec4& rhs) const noexcept;
|
||||
[[nodiscard]] SHVec4 Cross3D (const SHVec4& rhs) const noexcept;
|
||||
[[nodiscard]] SHVec4 Cross (const SHVec4& v1, const SHVec4& v2) const noexcept;
|
||||
|
||||
[[nodiscard]] SHVec3 ToVec3 () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Static Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept;
|
||||
[[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept;
|
||||
[[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept;
|
||||
[[nodiscard]] static SHVec4 Min (const std::initializer_list<SHVec4>& vs) noexcept;
|
||||
[[nodiscard]] static SHVec4 Max (const std::initializer_list<SHVec4>& vs) noexcept;
|
||||
[[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept;
|
||||
[[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept;
|
||||
[[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept;
|
||||
[[nodiscard]] static SHVec4 Min (const std::initializer_list<SHVec4>& vs) noexcept;
|
||||
[[nodiscard]] static SHVec4 Max (const std::initializer_list<SHVec4>& vs) noexcept;
|
||||
[[nodiscard]] static SHVec4 Clamp (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax) noexcept;
|
||||
[[nodiscard]] static SHVec4 Lerp (const SHVec4& a, const SHVec4& b, float t) noexcept;
|
||||
[[nodiscard]] static SHVec4 ClampedLerp (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
|
||||
|
|
|
@ -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 = tf->GetWorldRotation();
|
||||
|
||||
if (hasColliders)
|
||||
{
|
||||
c->position = tf->GetWorldPosition();
|
||||
c->orientation = 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 = 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,9 @@
|
|||
// 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"
|
||||
|
||||
|
@ -174,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;
|
||||
|
@ -189,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()
|
||||
|
@ -196,99 +207,6 @@ 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);
|
||||
|
@ -297,27 +215,63 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index)
|
||||
{
|
||||
|
||||
auto* physicsObject = GetPhysicsObject(entityID);
|
||||
physicsObject->RemoveCollider(index);
|
||||
}
|
||||
|
||||
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.SetRotation(TF->GetWorldRotation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
|
||||
|
@ -358,7 +312,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())
|
||||
|
@ -450,15 +404,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));
|
||||
|
@ -473,12 +430,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();
|
||||
}
|
||||
|
@ -490,29 +447,146 @@ namespace SHADE
|
|||
}
|
||||
|
||||
// Convert RP3D Transform to SHADE
|
||||
auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
|
||||
tfComponent->SetWorldPosition(rp3dPos);
|
||||
tfComponent->SetWorldRotation(SHQuaternion{ rp3dRot }.ToEuler());
|
||||
|
||||
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
|
||||
for (uint32_t i = 0; i < physicsObject->rp3dBody->getNbColliders(); ++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,10 +179,9 @@ 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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
// Project Headers
|
||||
#include "ECS_Base/Managers/SHEntityManager.h"
|
||||
#include "Events/SHEventManager.hpp"
|
||||
#include "Tools/SHLogger.h"
|
||||
#include "Tools/SHException.h"
|
||||
|
||||
|
@ -317,6 +318,11 @@ namespace SHADE
|
|||
if (parentNode == nullptr)
|
||||
{
|
||||
SHLOG_WARNING("Removing Entity {}'s parent", entityID)
|
||||
|
||||
if (parent)
|
||||
parent->RemoveChild(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle self assignment
|
||||
|
@ -359,10 +365,19 @@ namespace SHADE
|
|||
}
|
||||
////////////////////////////////////////
|
||||
|
||||
const SHSceneGraphChangeParentEvent EVENT_DATA
|
||||
{
|
||||
.node = NODE_ITER->second
|
||||
, .oldParent = NODE_ITER->second->GetParent()
|
||||
, .newParent = parent ? parent : root
|
||||
};
|
||||
|
||||
if (parent == nullptr)
|
||||
parent = root;
|
||||
|
||||
NODE_ITER->second->SetParent(parent);
|
||||
|
||||
SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
|
||||
}
|
||||
|
||||
void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept
|
||||
|
@ -396,8 +411,17 @@ namespace SHADE
|
|||
}
|
||||
////////////////////////////////////////
|
||||
|
||||
const SHSceneGraphChangeParentEvent EVENT_DATA
|
||||
{
|
||||
.node = NODE_ITER->second
|
||||
, .oldParent = NODE_ITER->second->GetParent()
|
||||
, .newParent = PARENT_ITER->second
|
||||
};
|
||||
|
||||
SHSceneNode* currentNode = NODE_ITER->second;
|
||||
currentNode->SetParent(PARENT_ITER->second);
|
||||
|
||||
SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -558,7 +582,7 @@ namespace SHADE
|
|||
ReleaseNode(node);
|
||||
}
|
||||
|
||||
void SHSceneGraph::Traverse (const UnaryPredicate& predicate) const
|
||||
void SHSceneGraph::Traverse (const UnaryFunction& predicate) const
|
||||
{
|
||||
TraverseAndInvokePredicate(root, predicate);
|
||||
}
|
||||
|
@ -597,7 +621,7 @@ namespace SHADE
|
|||
delete node;
|
||||
}
|
||||
|
||||
void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryPredicate& predicate)
|
||||
void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate)
|
||||
{
|
||||
for (auto* child : node->children)
|
||||
{
|
||||
|
|
|
@ -97,9 +97,8 @@ namespace SHADE
|
|||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
using EntityNodeMap = std::unordered_map<EntityID, SHSceneNode*>;
|
||||
|
||||
using UnaryPredicate = std::function<void(SHSceneNode*)>;
|
||||
using EntityNodeMap = std::unordered_map<EntityID, SHSceneNode*>;
|
||||
using UnaryFunction = std::function<void(SHSceneNode*)>;
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -143,8 +142,7 @@ namespace SHADE
|
|||
bool RemoveNode (SHSceneNode* nodeToRemove) noexcept;
|
||||
void Reset () noexcept;
|
||||
|
||||
void Traverse (const UnaryPredicate& predicate) const;
|
||||
|
||||
void Traverse (const UnaryFunction& predicate) const;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -160,8 +158,14 @@ namespace SHADE
|
|||
|
||||
SHSceneNode* AllocateNode (EntityID entityID);
|
||||
void ReleaseNode (SHSceneNode* node) noexcept;
|
||||
static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryPredicate& predicate);
|
||||
static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryFunction& predicate);
|
||||
};
|
||||
|
||||
struct SHSceneGraphChangeParentEvent
|
||||
{
|
||||
SHSceneNode* node;
|
||||
SHSceneNode* oldParent;
|
||||
SHSceneNode* newParent;
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
|
@ -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
|
|
@ -29,13 +29,21 @@ namespace SHADE
|
|||
{
|
||||
GetNativeComponent()->SetLocalPosition(Convert::ToNative(val));
|
||||
}
|
||||
Vector3 Transform::LocalRotation::get()
|
||||
Quaternion Transform::LocalRotation::get()
|
||||
{
|
||||
return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
|
||||
return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
|
||||
}
|
||||
void Transform::LocalRotation::set(Vector3 val)
|
||||
void Transform::LocalRotation::set(Quaternion val)
|
||||
{
|
||||
GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
|
||||
GetNativeComponent()->SetLocalOrientation(Convert::ToNative(val));
|
||||
}
|
||||
Vector3 Transform::LocalEulerAngles::get()
|
||||
{
|
||||
return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
|
||||
}
|
||||
void Transform::LocalEulerAngles::set(Vector3 val)
|
||||
{
|
||||
GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
|
||||
}
|
||||
Vector3 Transform::LocalScale::get()
|
||||
{
|
||||
|
@ -54,13 +62,21 @@ namespace SHADE
|
|||
{
|
||||
GetNativeComponent()->SetWorldPosition(Convert::ToNative(val));
|
||||
}
|
||||
Vector3 Transform::GlobalRotation::get()
|
||||
Quaternion Transform::GlobalRotation::get()
|
||||
{
|
||||
return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
|
||||
return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
|
||||
}
|
||||
void Transform::GlobalRotation::set(Vector3 val)
|
||||
void Transform::GlobalRotation::set(Quaternion val)
|
||||
{
|
||||
GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
|
||||
GetNativeComponent()->SetWorldOrientation(Convert::ToNative(val));
|
||||
}
|
||||
Vector3 Transform::GlobalEulerAngles::get()
|
||||
{
|
||||
return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
|
||||
}
|
||||
void Transform::GlobalEulerAngles::set(Vector3 val)
|
||||
{
|
||||
GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
|
||||
}
|
||||
Vector3 Transform::GlobalScale::get()
|
||||
{
|
||||
|
|
|
@ -17,14 +17,14 @@ of DigiPen Institute of Technology is prohibited.
|
|||
// Project Includes
|
||||
#include "Components/Component.hxx"
|
||||
#include "Math/Vector3.hxx"
|
||||
#include "Utility/Convert.hxx"
|
||||
#include "Math/Quaternion.hxx"
|
||||
// External Dependencies
|
||||
#include "Math/Transform/SHTransformComponent.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/// <summary>
|
||||
/// CLR version of the the SHADE Engine's TransformComponent.
|
||||
/// CLR version of the SHADE Engine's TransformComponent.
|
||||
/// </summary>
|
||||
public ref class Transform : public Component<SHTransformComponent>
|
||||
{
|
||||
|
@ -52,9 +52,17 @@ namespace SHADE
|
|||
void set(Vector3 val);
|
||||
}
|
||||
/// <summary>
|
||||
/// Local Z-axis rotation angle stored by this Transform in Radians.
|
||||
/// Local rotation quaternion stored by this Transform.
|
||||
/// </summary>
|
||||
property Vector3 LocalRotation
|
||||
property Quaternion LocalRotation
|
||||
{
|
||||
Quaternion get();
|
||||
void set(Quaternion val);
|
||||
}
|
||||
/// <summary>
|
||||
/// Local euler angle rotations stored by this Transform.
|
||||
/// </summary>
|
||||
property Vector3 LocalEulerAngles
|
||||
{
|
||||
Vector3 get();
|
||||
void set(Vector3 val);
|
||||
|
@ -76,16 +84,23 @@ namespace SHADE
|
|||
void set(Vector3 val);
|
||||
}
|
||||
/// <summary>
|
||||
/// Global Z-axis rotation angle stored by this Transform in Radians.
|
||||
/// Global rotation quaternion stored by this Transform.
|
||||
/// </summary>
|
||||
property Vector3 GlobalRotation
|
||||
property Quaternion GlobalRotation
|
||||
{
|
||||
Quaternion get();
|
||||
void set(Quaternion val);
|
||||
}
|
||||
/// <summary>
|
||||
/// Global euler angle rotations stored by this Transform.
|
||||
/// </summary>
|
||||
property Vector3 GlobalEulerAngles
|
||||
{
|
||||
Vector3 get();
|
||||
void set(Vector3 val);
|
||||
}
|
||||
/// <summary>
|
||||
/// Global scale stored by this Transform.
|
||||
/// Note that this operation is expensive.
|
||||
/// </summary>
|
||||
property Vector3 GlobalScale
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* Utility Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
double Math::Wrap(double value, double min, double max)
|
||||
float Math::Wrap(float value, float min, float max)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
|
@ -33,24 +33,24 @@ namespace SHADE
|
|||
}
|
||||
return value;
|
||||
}
|
||||
double Math::DegreesToRadians(double degrees)
|
||||
float Math::DegreesToRadians(float degrees)
|
||||
{
|
||||
return degrees * Deg2Rad;
|
||||
}
|
||||
double Math::RadiansToDegrees(double radians)
|
||||
float Math::RadiansToDegrees(float radians)
|
||||
{
|
||||
return radians * Rad2Deg;
|
||||
}
|
||||
double Math::Lerp(double a, double b, double t)
|
||||
float Math::Lerp(float a, float b, float t)
|
||||
{
|
||||
return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0, 1.0));
|
||||
return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0f, 1.0f));
|
||||
}
|
||||
double Math::LerpUnclamped(double a, double b, double t)
|
||||
float Math::LerpUnclamped(float a, float b, float t)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
double Math::InverseLerp(double a, double b, double value)
|
||||
float Math::InverseLerp(float a, float b, float value)
|
||||
{
|
||||
return (value - a) / (b - a);
|
||||
}
|
||||
|
|
|
@ -27,11 +27,11 @@ namespace SHADE
|
|||
/// <summary>
|
||||
/// Degrees-to-radians conversion constant
|
||||
/// </summary>
|
||||
static constexpr double Deg2Rad = System::Math::PI / 180.0;
|
||||
static constexpr float Deg2Rad = System::Math::PI / 180.0f;
|
||||
/// <summary>
|
||||
/// Radians-to-degrees conversion constant
|
||||
/// </summary>
|
||||
static constexpr double Rad2Deg = 180.0 / System::Math::PI;
|
||||
static constexpr float Rad2Deg = 180.0f / System::Math::PI;
|
||||
/// <summary>
|
||||
/// Small value used for single precision floating point comparisons.
|
||||
/// </summary>
|
||||
|
@ -47,28 +47,28 @@ namespace SHADE
|
|||
/// <param name="min">Minimum value to wrap at.</param>
|
||||
/// <param name="max">Maximum value to wrap at.</param>
|
||||
/// <returns>Wrapped value.</returns>
|
||||
static double Wrap(double value, double min, double max);
|
||||
static float Wrap(float value, float min, float max);
|
||||
/// <summary>
|
||||
/// Converts an angle from degree representation to radian representation.
|
||||
/// </summary>
|
||||
/// <param name="degrees">Degree-based angle to convert.</param>
|
||||
/// <returns>The specified angle in radians.</returns>
|
||||
static double DegreesToRadians(double degrees);
|
||||
static float DegreesToRadians(float degrees);
|
||||
/// <summary>
|
||||
/// Converts an angle from radian representation to degree representation.
|
||||
/// </summary>
|
||||
/// <param name="radians">Radian-based angle to convert.</param>
|
||||
/// <returns>The specified angle in degrees.</returns>
|
||||
static double RadiansToDegrees(double radians);
|
||||
static float RadiansToDegrees(float radians);
|
||||
/// <summary>
|
||||
/// Linearly interpolates between a and b by t.
|
||||
/// The parameter t is clamped to the range [0, 1].
|
||||
/// </summary>
|
||||
/// <param name="a">The start value.</param>
|
||||
/// <param name="b">The end value.</param>
|
||||
/// <param name="t">The interpolation value between the two double.</param>
|
||||
/// <returns>The interpolated double result between the two double values.</returns>
|
||||
static double Lerp(double a, double b, double t);
|
||||
/// <param name="t">The interpolation value between the two float.</param>
|
||||
/// <returns>The interpolated float result between the two float values.</returns>
|
||||
static float Lerp(float a, float b, float t);
|
||||
/// <summary>
|
||||
/// Linearly interpolates between a and b by t.
|
||||
/// The parameter t is not clamped and a value based on a and b is supported.
|
||||
|
@ -77,9 +77,9 @@ namespace SHADE
|
|||
/// </summary>
|
||||
/// <param name="a">The start value.</param>
|
||||
/// <param name="b">The end value.</param>
|
||||
/// <param name="t">The interpolation value between the two double.</param>
|
||||
/// <returns>The interpolated double result between the two double values.</returns>
|
||||
static double LerpUnclamped(double a, double b, double t);
|
||||
/// <param name="t">The interpolation value between the two float.</param>
|
||||
/// <returns>The interpolated float result between the two float values.</returns>
|
||||
static float LerpUnclamped(float a, float b, float t);
|
||||
/// <summary>
|
||||
/// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
|
||||
/// </summary>
|
||||
|
@ -87,6 +87,6 @@ namespace SHADE
|
|||
/// <param name="b">End value.</param>
|
||||
/// <param name="value">Value between start and end.</param>
|
||||
/// <returns>Percentage of value between start and end.</returns>
|
||||
static double InverseLerp(double a, double b, double value);
|
||||
static float InverseLerp(float a, float b, float value);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/************************************************************************************//*!
|
||||
\file Quaternion.cxx
|
||||
\author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
\par email: diren.dbharwani\@digipen.edu
|
||||
\date Oct 23, 2022
|
||||
\brief Contains the definitions of functions in the Quaternion struct.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2021 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.
|
||||
*//*************************************************************************************/
|
||||
|
||||
// Precompiled Headers
|
||||
#include "SHpch.h"
|
||||
// Primary Header
|
||||
#include "Quaternion.hxx"
|
||||
// External Dependencies
|
||||
#include "Math/SHQuaternion.h"
|
||||
#include "Math/Vector/SHVec4.h"
|
||||
// Project Headers
|
||||
#include "Utility/Convert.hxx"
|
||||
#include "Math.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
Quaternion::Quaternion(float _x, float _y, float _z, float _w)
|
||||
: x { _x }
|
||||
, y { _y }
|
||||
, z { _z }
|
||||
, w { _w }
|
||||
{}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Usage Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void Quaternion::SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
|
||||
{
|
||||
const SHQuaternion R = SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection));
|
||||
*this = Convert::ToCLI(R);
|
||||
}
|
||||
|
||||
void Quaternion::SetLookRotation(Vector3 view, Vector3 up)
|
||||
{
|
||||
const SHQuaternion R = SHQuaternion::LookRotation(Convert::ToNative(view), Convert::ToNative(up));
|
||||
*this = Convert::ToCLI(R);
|
||||
}
|
||||
|
||||
void Quaternion::ToAngleAxis(float^% angle, Vector3^% axis)
|
||||
{
|
||||
const SHVec4 NATIVE_AXIS_ANGLE = Convert::ToNative(*this).GetAxisAngle();
|
||||
axis = Convert::ToCLI(NATIVE_AXIS_ANGLE.ToVec3());
|
||||
angle = NATIVE_AXIS_ANGLE.w;
|
||||
}
|
||||
|
||||
System::String^ Quaternion::ToString()
|
||||
{
|
||||
return ValueType::ToString();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* IEquatable */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
bool Quaternion::Equals(Quaternion other)
|
||||
{
|
||||
const float DOT = Dot(*this, other);
|
||||
return fabs(1.0f - DOT) <= Math::Epsilon;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Object Overrides */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
bool Quaternion::Equals(Object^ o)
|
||||
{
|
||||
return ValueType::Equals(o);
|
||||
}
|
||||
|
||||
int Quaternion::GetHashCode()
|
||||
{
|
||||
return ValueType::GetHashCode();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Static Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
float Quaternion::Angle(Quaternion a, Quaternion b)
|
||||
{
|
||||
return SHQuaternion::Angle(Convert::ToNative(a), Convert::ToNative(b));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::AngleAxis(float angle, Vector3 axis)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::FromAxisAngle(Convert::ToNative(axis), angle));
|
||||
}
|
||||
|
||||
float Quaternion::Dot(Quaternion a, Quaternion b)
|
||||
{
|
||||
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Euler(float _x, float _y, float _z)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::FromPitchYawRoll(_x, _y, _z));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::FromToRotation(Vector3 fromDirection, Vector3 toDirection)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection)));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Inverse(Quaternion rotation)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::Inverse(Convert::ToNative(rotation)));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Lerp(Quaternion a, Quaternion b, float t)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::ClampedLerp(Convert::ToNative(a), Convert::ToNative(b), t));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::LerpUnclamped(Quaternion a, Quaternion b, float t)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::Lerp(Convert::ToNative(a), Convert::ToNative(b), t));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::LookRotation(Vector3 forward, Vector3 upwards)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::LookRotation(Convert::ToNative(forward), Convert::ToNative(upwards)));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Normalize(Quaternion q)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::Normalise(Convert::ToNative(q)));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::RotateTowards(Convert::ToNative(from), Convert::ToNative(to), Math::DegreesToRadians(maxDegreesDelta)));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Slerp(Quaternion a, Quaternion b, float t)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::ClampedSlerp(Convert::ToNative(a), Convert::ToNative(b), t));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::SlerpUnclamped(Quaternion a, Quaternion b, float t)
|
||||
{
|
||||
return Convert::ToCLI(SHQuaternion::Slerp(Convert::ToNative(a), Convert::ToNative(b), t));
|
||||
}
|
||||
|
||||
|
||||
Quaternion Quaternion::operator*(Quaternion lhs, Quaternion rhs)
|
||||
{
|
||||
return Convert::ToCLI(Convert::ToNative(lhs) * Convert::ToNative(rhs));
|
||||
}
|
||||
|
||||
bool Quaternion::operator==(Quaternion lhs, Quaternion rhs)
|
||||
{
|
||||
return lhs.Equals(rhs);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/************************************************************************************//*!
|
||||
\file Quaternion.hxx
|
||||
\author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
\par email: diren.dbharwani\@digipen.edu
|
||||
\date Oct 23, 2022
|
||||
\brief Contains the definitions of Quaternion struct.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2021 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.
|
||||
*//*************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Standard Libraries
|
||||
#include <limits>
|
||||
// Project Includes
|
||||
#include "Vector3.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
///<summary>
|
||||
/// CLR version of SHADE's Quaternion class that represents an orientation.
|
||||
/// Designed to closely match Unity's Quaternion struct.
|
||||
/// </summary>
|
||||
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
|
||||
public value struct Quaternion : public System::IEquatable<Quaternion>
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constants */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
#pragma region Constants
|
||||
|
||||
///<summary>
|
||||
/// Shorthand for writing Quaternion(0, 0, 0, 1).
|
||||
///</summary>
|
||||
static initonly Quaternion Identity = Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Public Members */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
///<summary>
|
||||
/// X-component of the Quaternion.
|
||||
/// Don't modify this directly unless you know quaternions inside out.
|
||||
///</summary>
|
||||
float x;
|
||||
///<summary>
|
||||
/// Y-component of the Quaternion.
|
||||
/// Don't modify this directly unless you know quaternions inside out.
|
||||
///</summary>
|
||||
float y;
|
||||
///<summary>
|
||||
/// Z-component of the Quaternion.
|
||||
/// Don't modify this directly unless you know quaternions inside out.
|
||||
///</summary>
|
||||
float z;
|
||||
///<summary>
|
||||
/// W-component of the Quaternion. Do not directly modify quaternions.
|
||||
///</summary>
|
||||
float w;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to construct a Quaternion with the specified components.
|
||||
/// </summary>
|
||||
/// <param name="_x">X-coordinate to set.</param>
|
||||
/// <param name="_y">Y-coordinate to set.</param>
|
||||
/// <param name="_z">Z-coordinate to set.</param>
|
||||
/// <param name="_z">W-coordinate to set.</param>
|
||||
Quaternion(float _x, float _y, float _z, float _w);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Usage Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rotation which rotates from fromDirection to toDirection. <br/>
|
||||
/// Use this to create a rotation which starts at the first Vector (fromDirection) and rotates to the second Vector (toDirection).
|
||||
/// These Vectors must be set up in a script.
|
||||
/// </summary>
|
||||
void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rotation with the specified forward and upwards directions. <br/>
|
||||
/// The result is applied to this quaternion.
|
||||
/// If used to orient a Transform, the Z axis will be aligned with forward and the Y axis with upwards, assuming these vectors are orthogonal.
|
||||
/// Logs an error if the forward direction is zero.
|
||||
/// </summary>
|
||||
/// <param name="view">The direction to look in.</param>
|
||||
/// <param name="up">The vector that defines in which direction up is.</param>
|
||||
void SetLookRotation(Vector3 view, Vector3 up);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a rotation to angle-axis representation (angles in degrees).
|
||||
/// </summary>
|
||||
void ToAngleAxis(float^% angle, Vector3^% axis);
|
||||
|
||||
System::String^ ToString() override;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* IEquatable */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
/// <summary>
|
||||
/// Compares equality with an object of the same type.
|
||||
/// </summary>
|
||||
/// <param name="other">The object to compare with.</param>
|
||||
/// <returns>True if both objects are the same.</returns>
|
||||
virtual bool Equals(Quaternion other);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Object */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
/// <summary>
|
||||
/// Compares equality with another unboxed object.
|
||||
/// </summary>
|
||||
/// <param name="o">The unboxed object to compare with.</param>
|
||||
/// <returns>True if both objects are the same.</returns>
|
||||
bool Equals(Object^ o) override;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a unique hash for this object.
|
||||
/// </summary>
|
||||
/// <returns>Unique hash for this object.</returns>
|
||||
int GetHashCode() override;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Static Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
/// <summary>
|
||||
/// Returns the angle in degrees between two rotations a and b.<br/>
|
||||
/// </summary>
|
||||
/// <returns>The angle in degrees between the two vectors. </returns>
|
||||
static float Angle(Quaternion a, Quaternion b);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rotation which rotates angle degrees around axis.
|
||||
/// </summary>
|
||||
static Quaternion AngleAxis(float angle, Vector3 axis);
|
||||
|
||||
/// <summary>
|
||||
/// The dot product between two rotations.
|
||||
/// </summary>
|
||||
static float Dot(Quaternion a, Quaternion b);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a rotation that rotates y degrees around the y axis, x degrees around the x axis, and z degrees around the z axis; applied in that order.
|
||||
/// </summary>
|
||||
static Quaternion Euler(float _x, float _y, float _z);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rotation which rotates from fromDirection to toDirection.
|
||||
/// </summary>
|
||||
static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Inverse of rotation.
|
||||
/// </summary>
|
||||
static Quaternion Inverse(Quaternion rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is clamped to the range [0, 1].
|
||||
/// </summary>
|
||||
/// <param name="a">Start value, returned when t = 0.</param>
|
||||
/// <param name="b">End value, returned when t = 1.</param>
|
||||
/// <param name="t">Interpolation ratio.</param>
|
||||
/// <returns> A quaternion interpolated between quaternions a and b.</returns>
|
||||
static Quaternion Lerp(Quaternion a, Quaternion b, float t);
|
||||
|
||||
/// <summary>
|
||||
/// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is not clamped.
|
||||
/// </summary>
|
||||
static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rotation with the specified forward and upwards directions. <br/>
|
||||
/// Z axis will be aligned with forward, X axis aligned with cross product between forward and upwards, and Y axis aligned with cross product between Z and X.
|
||||
/// </summary>
|
||||
static Quaternion LookRotation(Vector3 forward, Vector3 upwards);
|
||||
|
||||
/// <summary>
|
||||
/// Converts this quaternion to one with the same orientation but with a magnitude of 1.
|
||||
/// </summary>
|
||||
static Quaternion Normalize(Quaternion q);
|
||||
|
||||
/// <summary>
|
||||
/// Rotates a rotation from towards to. <br/>
|
||||
/// The from quaternion is rotated towards to by an angular step of maxDegreesDelta (but note that the rotation will not overshoot).
|
||||
/// Negative values of maxDegreesDelta will move away from to until the rotation is exactly the opposite direction.
|
||||
/// </summary>
|
||||
static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
|
||||
|
||||
/// <summary>
|
||||
/// Spherically interpolates between quaternions a and b by ratio t. The parameter t is clamped to the range [0, 1].
|
||||
/// </summary>
|
||||
/// <param name="a">Start value, returned when t = 0.</param>
|
||||
/// <param name="b">End value, returned when t = 1.</param>
|
||||
/// <param name="t">Interpolation ratio.</param>
|
||||
/// <returns> A quaternion spherically interpolated between quaternions a and b.</returns>
|
||||
static Quaternion Slerp(Quaternion a, Quaternion b, float t);
|
||||
|
||||
/// <summary>
|
||||
/// Spherically interpolates between a and b by t. The parameter t is not clamped.
|
||||
/// </summary>
|
||||
static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Overloaded Operators */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
/// <summary>
|
||||
/// Combines rotations lhs and rhs.
|
||||
/// </summary>
|
||||
/// <param name="lhs">Left-hand side quaternion.</param>
|
||||
/// <param name="rhs">Right-hand side quaternion.</param>
|
||||
static Quaternion operator*(Quaternion lhs, Quaternion rhs);
|
||||
|
||||
/// <summary>
|
||||
/// Are two quaternions equal to each other?
|
||||
/// </summary>
|
||||
/// <param name="lhs">Left-hand side quaternion.</param>
|
||||
/// <param name="rhs">Right-hand side quaternion.</param>
|
||||
static bool operator==(Quaternion lhs, Quaternion rhs);
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
|
@ -26,10 +26,10 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
Vector2::Vector2(double _x)
|
||||
: Vector2 { _x, 0.0 }
|
||||
Vector2::Vector2(float _x)
|
||||
: Vector2 { _x, 0.0f }
|
||||
{}
|
||||
Vector2::Vector2(double _x, double _y)
|
||||
Vector2::Vector2(float _x, float _y)
|
||||
: x { _x }
|
||||
, y { _y }
|
||||
{}
|
||||
|
@ -47,22 +47,22 @@ namespace SHADE
|
|||
return *this / GetMagnitude();
|
||||
}
|
||||
|
||||
double Vector2::GetMagnitude()
|
||||
float Vector2::GetMagnitude()
|
||||
{
|
||||
return sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
double Vector2::GetSqrMagnitude()
|
||||
float Vector2::GetSqrMagnitude()
|
||||
{
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
double Vector2::AngleFromRightRadians()
|
||||
float Vector2::AngleFromRightRadians()
|
||||
{
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
double Vector2::AngleFromRightDegrees()
|
||||
float Vector2::AngleFromRightDegrees()
|
||||
{
|
||||
return Math::RadiansToDegrees(AngleFromRightRadians());
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ namespace SHADE
|
|||
return IsNearPoint(point, Math::Epsilon);
|
||||
}
|
||||
|
||||
bool Vector2::IsNearPoint(Vector2 point, double tolerance)
|
||||
bool Vector2::IsNearPoint(Vector2 point, float tolerance)
|
||||
{
|
||||
return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
|
||||
}
|
||||
|
@ -113,13 +113,13 @@ namespace SHADE
|
|||
{
|
||||
return IsNear(lhs, rhs, Math::Epsilon);
|
||||
}
|
||||
bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, double tolerance)
|
||||
bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, float tolerance)
|
||||
{
|
||||
return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
|
||||
&&
|
||||
(std::abs(lhs.y) - std::abs(rhs.y)) < tolerance;
|
||||
}
|
||||
double Vector2::Dot(Vector2 lhs, Vector2 rhs)
|
||||
float Vector2::Dot(Vector2 lhs, Vector2 rhs)
|
||||
{
|
||||
return lhs.x * rhs.x + lhs.y * rhs.y;
|
||||
}
|
||||
|
@ -153,12 +153,12 @@ namespace SHADE
|
|||
}
|
||||
Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal)
|
||||
{
|
||||
return vec - (Project(vec, normal.GetNormalised()) * 2.0);
|
||||
return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
|
||||
}
|
||||
Vector2 Vector2::RotateRadians(Vector2 vec, double radians)
|
||||
Vector2 Vector2::RotateRadians(Vector2 vec, float radians)
|
||||
{
|
||||
const double SINE = sin(radians);
|
||||
const double COSINE = cos(radians);
|
||||
const float SINE = sin(radians);
|
||||
const float COSINE = cos(radians);
|
||||
|
||||
return Vector2
|
||||
(
|
||||
|
@ -166,35 +166,35 @@ namespace SHADE
|
|||
vec.x * SINE + vec.y * COSINE
|
||||
);
|
||||
}
|
||||
Vector2 Vector2::RotateDegrees(Vector2 vec, double degrees)
|
||||
Vector2 Vector2::RotateDegrees(Vector2 vec, float degrees)
|
||||
{
|
||||
return RotateRadians(vec, Math::DegreesToRadians(degrees));
|
||||
}
|
||||
Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs)
|
||||
{
|
||||
double lx = lhs.x, rx = rhs.x;
|
||||
double ly = lhs.y, ry = rhs.y;
|
||||
float lx = lhs.x, rx = rhs.x;
|
||||
float ly = lhs.y, ry = rhs.y;
|
||||
|
||||
return Vector2(std::min(lx, rx),
|
||||
std::min(ly, ry));
|
||||
}
|
||||
Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs)
|
||||
{
|
||||
double lx = lhs.x, rx = rhs.x;
|
||||
double ly = lhs.y, ry = rhs.y;
|
||||
float lx = lhs.x, rx = rhs.x;
|
||||
float ly = lhs.y, ry = rhs.y;
|
||||
|
||||
return Vector2(std::max(lx, rx),
|
||||
std::max(ly, ry));
|
||||
}
|
||||
Vector2 Vector2::Lerp(Vector2 a, Vector2 b, double t)
|
||||
Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t)
|
||||
{
|
||||
return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
|
||||
return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
|
||||
}
|
||||
Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, double t)
|
||||
Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t)
|
||||
{
|
||||
return a + ((b - a) * t);
|
||||
}
|
||||
Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta)
|
||||
Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta)
|
||||
{
|
||||
// Ignore if it is exactly on the same point
|
||||
if (current == target)
|
||||
|
@ -206,7 +206,7 @@ namespace SHADE
|
|||
|
||||
// Check if check if is behind or ahead of target
|
||||
Vector2 DIFF = target - newPos;
|
||||
if (Dot(DELTA, DIFF) < 0.0)
|
||||
if (Dot(DELTA, DIFF) < 0.0f)
|
||||
{
|
||||
newPos = target;
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ namespace SHADE
|
|||
lhs.y * rhs.y
|
||||
);
|
||||
}
|
||||
Vector2 Vector2::operator*(Vector2 lhs, double rhs)
|
||||
Vector2 Vector2::operator*(Vector2 lhs, float rhs)
|
||||
{
|
||||
return Vector2
|
||||
(
|
||||
|
@ -244,7 +244,7 @@ namespace SHADE
|
|||
lhs.y * rhs
|
||||
);
|
||||
}
|
||||
Vector2 Vector2::operator/(Vector2 lhs, double rhs)
|
||||
Vector2 Vector2::operator/(Vector2 lhs, float rhs)
|
||||
{
|
||||
return Vector2
|
||||
(
|
||||
|
|
|
@ -19,8 +19,8 @@ of DigiPen Institute of Technology is prohibited.
|
|||
namespace SHADE
|
||||
{
|
||||
///<summary>
|
||||
/// CLR version of the the SHADE Engine's Vector2 class that represents a
|
||||
/// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct.
|
||||
/// CLR version of SHADE Engine's Vector2 class that represents a 2-Dimensional Vector.
|
||||
/// Designed to closely match Unity's Vector2 struct.
|
||||
/// </summary>
|
||||
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
|
||||
public value struct Vector2 : public System::IEquatable<Vector2>
|
||||
|
@ -33,37 +33,37 @@ namespace SHADE
|
|||
///<summary>
|
||||
/// Shorthand for writing Vector2(0, -1).
|
||||
///</summary>
|
||||
static initonly Vector2 Down = Vector2(0.0, -1.0);
|
||||
static initonly Vector2 Down = Vector2(0.0f, -1.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(-1, 0).
|
||||
///</summary>
|
||||
static initonly Vector2 Left = Vector2(-1.0, 0.0);
|
||||
static initonly Vector2 Left = Vector2(-1.0f, 0.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(double.NegativeInfinity,
|
||||
/// double.NegativeInfinity).
|
||||
/// Shorthand for writing Vector2(float.NegativeInfinity,
|
||||
/// float.NegativeInfinity).
|
||||
///</summary>
|
||||
static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
|
||||
static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest());
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(1, 1).
|
||||
///</summary>
|
||||
static initonly Vector2 One = Vector2(1.0, 1.0);
|
||||
static initonly Vector2 One = Vector2(1.0f, 1.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(double.PositiveInfinity,
|
||||
/// double.PositiveInfinity).
|
||||
/// Shorthand for writing Vector2(float.PositiveInfinity,
|
||||
/// float.PositiveInfinity).
|
||||
///</summary>
|
||||
static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(1, 0).
|
||||
///</summary>
|
||||
static initonly Vector2 Right = Vector2(1.0, 0.0);
|
||||
static initonly Vector2 Right = Vector2(1.0f, 0.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(0, 1).
|
||||
///</summary>
|
||||
static initonly Vector2 Up = Vector2(0.0, 1.0);
|
||||
static initonly Vector2 Up = Vector2(0.0f, 1.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector2(0, 0).
|
||||
///</summary>
|
||||
static initonly Vector2 Zero = Vector2(0.0, 0.0);
|
||||
static initonly Vector2 Zero = Vector2(0.0f, 0.0f);
|
||||
#pragma endregion
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
@ -72,27 +72,27 @@ namespace SHADE
|
|||
///<summary>
|
||||
/// X-component of the Vector2.
|
||||
///</summary>
|
||||
double x;
|
||||
float x;
|
||||
///<summary>
|
||||
/// Y-component of the Vector2.
|
||||
///</summary>
|
||||
double y;
|
||||
float y;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Constructor to construct a Vector2 with the specified components with the
|
||||
/// Y-component set to 0.0.
|
||||
/// Y-component set to 0.0f.
|
||||
/// </summary>
|
||||
/// <param name="_x">X-coordinate to set.</param>
|
||||
Vector2(double _x);
|
||||
Vector2(float _x);
|
||||
/// <summary>
|
||||
/// Constructor to construct a Vector2 with the specified components..
|
||||
/// </summary>
|
||||
/// <param name="_x">X-coordinate to set.</param>
|
||||
/// <param name="_y">Y-coordinate to set.</param>
|
||||
Vector2(double _x, double _y);
|
||||
Vector2(float _x, float _y);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Usage Functions */
|
||||
|
@ -117,24 +117,24 @@ namespace SHADE
|
|||
/// need the precise magnitude, consider using GetSqrMagnitude() instead.
|
||||
/// </summary>
|
||||
/// <returns>Returns the length of this Vector2.</returns>
|
||||
double GetMagnitude();
|
||||
float GetMagnitude();
|
||||
/// <summary>
|
||||
/// Calculates and returns the squared magnitude of this Vector2.
|
||||
/// </summary>
|
||||
/// <returns>Returns the squared length of this Vector2.</returns>
|
||||
double GetSqrMagnitude();
|
||||
float GetSqrMagnitude();
|
||||
/// <summary>
|
||||
/// Calculates and returns the angle of this vector from the right vector. This
|
||||
/// function returns values between -Math.PI and Math.PI.
|
||||
/// </summary>
|
||||
/// <returns>Returns the angle of this vector from the right vector in radians.</returns>
|
||||
double AngleFromRightRadians();
|
||||
float AngleFromRightRadians();
|
||||
/// <summary>
|
||||
/// Calculates and returns the angle of this vector from the right vector. This
|
||||
/// function returns values between -180.0 and 180.0.
|
||||
/// function returns values between -180.0f and 180.0f.
|
||||
/// </summary>
|
||||
/// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
|
||||
double AngleFromRightDegrees();
|
||||
float AngleFromRightDegrees();
|
||||
/// <summary>
|
||||
/// Checks if a specified point is near this Vector2 that represents a point with
|
||||
/// a tolerance value of PLS_EPSILON.
|
||||
|
@ -156,7 +156,7 @@ namespace SHADE
|
|||
/// True if this Vector2 representing a point and the specified point are within
|
||||
/// the range of the specified tolerance. False otherwise.
|
||||
/// </returns>
|
||||
bool IsNearPoint(Vector2 point, double tolerance);
|
||||
bool IsNearPoint(Vector2 point, float tolerance);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* IEquatable */
|
||||
|
@ -206,7 +206,7 @@ namespace SHADE
|
|||
/// <returns>
|
||||
/// True if the two Vector2s are within the tolerance value specified
|
||||
/// </returns>
|
||||
static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance);
|
||||
static bool IsNear(Vector2 lhs, Vector2 rhs, float tolerance);
|
||||
/// <summary>
|
||||
/// Computes and returns the dot product of 2 specified Vector2s.
|
||||
/// </summary>
|
||||
|
@ -215,7 +215,7 @@ namespace SHADE
|
|||
/// <returns>
|
||||
/// Scalar value representing the dot product of the two Vector2s.
|
||||
/// </returns>
|
||||
static double Dot(Vector2 lhs, Vector2 rhs);
|
||||
static float Dot(Vector2 lhs, Vector2 rhs);
|
||||
/// <summary>
|
||||
/// Computes the inward perpendicular Vector2 to the specified Vector2.
|
||||
/// Equivalent to calling Perpendicular(lhs, true). This means, the
|
||||
|
@ -260,7 +260,7 @@ namespace SHADE
|
|||
/// Angle to rotate the vector by in an anti-clockwise direction in radians.
|
||||
/// </param>
|
||||
/// <returns>The Vector2 that represents the rotated vector.</returns>
|
||||
static Vector2 RotateRadians(Vector2 vec, double radians);
|
||||
static Vector2 RotateRadians(Vector2 vec, float radians);
|
||||
/// <summary>
|
||||
/// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise
|
||||
/// direction.
|
||||
|
@ -270,7 +270,7 @@ namespace SHADE
|
|||
/// Angle to rotate the vector by in an anti-clockwise direction in degrees.
|
||||
/// </param>
|
||||
/// <returns>The Vector2 that represents the rotated vector.</returns>
|
||||
static Vector2 RotateDegrees(Vector2 vec, double degrees);
|
||||
static Vector2 RotateDegrees(Vector2 vec, float degrees);
|
||||
/// <summary>
|
||||
/// Computes and returns a Vector2 that is made from the smallest components of
|
||||
/// the two specified Vector2s.
|
||||
|
@ -298,25 +298,25 @@ namespace SHADE
|
|||
/// This is most commonly used to find a point some fraction of the way along a
|
||||
/// line between two endpoints.
|
||||
/// </summary>
|
||||
/// <param name="a">The start Vector2, returned when t = 0.0.</param>
|
||||
/// <param name="b">The end Vector2, returned when t = 1.0.</param>
|
||||
/// <param name="a">The start Vector2, returned when t = 0.0f.</param>
|
||||
/// <param name="b">The end Vector2, returned when t = 1.0f.</param>
|
||||
/// <param name="t">
|
||||
/// Value used to interpolate between a and b which is clamped to
|
||||
/// the range[0, 1].
|
||||
/// </param>
|
||||
/// <returns>The interpolated Vector2.</returns>
|
||||
static Vector2 Lerp(Vector2 a, Vector2 b, double t);
|
||||
static Vector2 Lerp(Vector2 a, Vector2 b, float t);
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two specified points.
|
||||
/// This is most commonly used to find a point some fraction of the way along a
|
||||
/// line between two endpoints.
|
||||
/// Unlike Lerp(), t is not clamped to a range at all.
|
||||
/// </summary>
|
||||
/// <param name="a">The start Vector2, returned when t = 0.0.</param>
|
||||
/// <param name="b">The end Vector2, returned when t = 1.0.</param>
|
||||
/// <param name="a">The start Vector2, returned when t = 0.0f.</param>
|
||||
/// <param name="b">The end Vector2, returned when t = 1.0f.</param>
|
||||
/// <param name="t">Value used to interpolate between a and b.</param>
|
||||
/// <returns>The interpolated Vector2.</returns>
|
||||
static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t);
|
||||
static Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t);
|
||||
/// <summary>
|
||||
/// Moves a point current towards target.
|
||||
/// Similar to Lerp(), however, the function will ensure that the distance never
|
||||
|
@ -327,7 +327,7 @@ namespace SHADE
|
|||
/// <param name="target">The target position to move to.</param>
|
||||
/// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
|
||||
/// <returns>Vector representing the moved point.</returns>
|
||||
static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta);
|
||||
static Vector2 MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Overloaded Operators */
|
||||
|
@ -361,7 +361,7 @@ namespace SHADE
|
|||
/// <param name="lhs">Vector2 to multiply with.</param>
|
||||
/// <param name="rhs">Scalar to multiply with.</param>
|
||||
/// <returns>The result of the scalar multiplication.</returns>
|
||||
static Vector2 operator*(Vector2 lhs, double rhs);
|
||||
static Vector2 operator*(Vector2 lhs, float rhs);
|
||||
/// <summary>
|
||||
/// Calculates the division of a Vector2 with a scalar value and returns
|
||||
/// the result.
|
||||
|
@ -369,7 +369,7 @@ namespace SHADE
|
|||
/// <param name="lhs">Scalar to divide with.</param>
|
||||
/// <param name="rhs">Vector2 to divide with.</param>
|
||||
/// <returns>The result of the scalar division.</returns>
|
||||
static Vector2 operator/(Vector2 lhs, double rhs);
|
||||
static Vector2 operator/(Vector2 lhs, float rhs);
|
||||
/// <summary>
|
||||
/// Checks if two Vector2s are approximately equal. This is equivalent to
|
||||
/// calling Vector2.IsNear() with default tolerance values.
|
||||
|
|
|
@ -11,6 +11,7 @@ Copyright (C) 2021 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.
|
||||
*//*************************************************************************************/
|
||||
|
||||
// Precompiled Headers
|
||||
#include "SHpch.h"
|
||||
// Primary Header
|
||||
|
@ -26,13 +27,13 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
Vector3::Vector3(double _x)
|
||||
: Vector3 {_x, 0.0, 0.0}
|
||||
Vector3::Vector3(float _x)
|
||||
: Vector3 {_x, 0.0f, 0.0f}
|
||||
{}
|
||||
Vector3::Vector3(double _x, double _y)
|
||||
: Vector3 {_x, _y, 0.0}
|
||||
Vector3::Vector3(float _x, float _y)
|
||||
: Vector3 {_x, _y, 0.0f}
|
||||
{}
|
||||
Vector3::Vector3(double _x, double _y, double _z)
|
||||
Vector3::Vector3(float _x, float _y, float _z)
|
||||
: x { _x }
|
||||
, y { _y }
|
||||
, z { _z }
|
||||
|
@ -54,22 +55,22 @@ namespace SHADE
|
|||
return *this / GetSqrMagnitude();
|
||||
}
|
||||
|
||||
double Vector3::GetMagnitude()
|
||||
float Vector3::GetMagnitude()
|
||||
{
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
double Vector3::GetSqrMagnitude()
|
||||
float Vector3::GetSqrMagnitude()
|
||||
{
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
double Vector3::Angle2DFromRightRadians()
|
||||
float Vector3::Angle2DFromRightRadians()
|
||||
{
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
double Vector3::Angle2DFromRightDegrees()
|
||||
float Vector3::Angle2DFromRightDegrees()
|
||||
{
|
||||
return Math::RadiansToDegrees(Angle2DFromRightRadians());
|
||||
}
|
||||
|
@ -79,7 +80,7 @@ namespace SHADE
|
|||
return IsNearPoint(point, Math::Epsilon);
|
||||
}
|
||||
|
||||
bool Vector3::IsNearPoint(Vector3 point, double tolerance)
|
||||
bool Vector3::IsNearPoint(Vector3 point, float tolerance)
|
||||
{
|
||||
return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
|
||||
}
|
||||
|
@ -121,7 +122,7 @@ namespace SHADE
|
|||
{
|
||||
return IsNear(lhs, rhs, Math::Epsilon);
|
||||
}
|
||||
bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, double tolerance)
|
||||
bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, float tolerance)
|
||||
{
|
||||
return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
|
||||
&&
|
||||
|
@ -129,7 +130,7 @@ namespace SHADE
|
|||
&&
|
||||
(std::abs(lhs.z) - std::abs(rhs.z)) < tolerance;
|
||||
}
|
||||
double Vector3::Dot(Vector3 lhs, Vector3 rhs)
|
||||
float Vector3::Dot(Vector3 lhs, Vector3 rhs)
|
||||
{
|
||||
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
|
||||
}
|
||||
|
@ -145,12 +146,12 @@ namespace SHADE
|
|||
}
|
||||
Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal)
|
||||
{
|
||||
return vec - (Project(vec, normal.GetNormalised()) * 2.0);
|
||||
return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
|
||||
}
|
||||
Vector3 Vector3::RotateRadians(Vector3 vec, double radians)
|
||||
Vector3 Vector3::RotateRadians(Vector3 vec, float radians)
|
||||
{
|
||||
const double SINE = sin(radians);
|
||||
const double COSINE = cos(radians);
|
||||
const float SINE = sin(radians);
|
||||
const float COSINE = cos(radians);
|
||||
|
||||
return Vector3
|
||||
(
|
||||
|
@ -159,15 +160,15 @@ namespace SHADE
|
|||
vec.z
|
||||
);
|
||||
}
|
||||
Vector3 Vector3::RotateDegrees(Vector3 vec, double degrees)
|
||||
Vector3 Vector3::RotateDegrees(Vector3 vec, float degrees)
|
||||
{
|
||||
return RotateRadians(vec, Math::DegreesToRadians(degrees));
|
||||
}
|
||||
Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
|
||||
{
|
||||
double lx = lhs.x, rx = rhs.x;
|
||||
double ly = lhs.y, ry = rhs.y;
|
||||
double lz = lhs.z, rz = rhs.z;
|
||||
float lx = lhs.x, rx = rhs.x;
|
||||
float ly = lhs.y, ry = rhs.y;
|
||||
float lz = lhs.z, rz = rhs.z;
|
||||
|
||||
return Vector3(std::min(lx, rx),
|
||||
std::min(ly, ry),
|
||||
|
@ -175,23 +176,23 @@ namespace SHADE
|
|||
}
|
||||
Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs)
|
||||
{
|
||||
double lx = lhs.x, rx = rhs.x;
|
||||
double ly = lhs.y, ry = rhs.y;
|
||||
double lz = lhs.z, rz = rhs.z;
|
||||
float lx = lhs.x, rx = rhs.x;
|
||||
float ly = lhs.y, ry = rhs.y;
|
||||
float lz = lhs.z, rz = rhs.z;
|
||||
|
||||
return Vector3(std::max(lx, rx),
|
||||
std::max(ly, ry),
|
||||
std::max(lz, rz));
|
||||
}
|
||||
Vector3 Vector3::Lerp(Vector3 a, Vector3 b, double t)
|
||||
Vector3 Vector3::Lerp(Vector3 a, Vector3 b, float t)
|
||||
{
|
||||
return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
|
||||
return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
|
||||
}
|
||||
Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, double t)
|
||||
Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, float t)
|
||||
{
|
||||
return a + ((b - a) * t);
|
||||
}
|
||||
Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta)
|
||||
Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
|
||||
{
|
||||
// Ignore if it is exactly on the same point
|
||||
if (current == target)
|
||||
|
@ -203,7 +204,7 @@ namespace SHADE
|
|||
|
||||
// Check if check if is behind or ahead of target
|
||||
Vector3 DIFF = target - newPos;
|
||||
if (Dot(DELTA, DIFF) < 0.0)
|
||||
if (Dot(DELTA, DIFF) < 0.0f)
|
||||
{
|
||||
newPos = target;
|
||||
}
|
||||
|
@ -236,7 +237,7 @@ namespace SHADE
|
|||
lhs.z * rhs.z
|
||||
);
|
||||
}
|
||||
Vector3 Vector3::operator*(Vector3 lhs, double rhs)
|
||||
Vector3 Vector3::operator*(Vector3 lhs, float rhs)
|
||||
{
|
||||
return Vector3
|
||||
(
|
||||
|
@ -245,7 +246,7 @@ namespace SHADE
|
|||
lhs.z * rhs
|
||||
);
|
||||
}
|
||||
Vector3 Vector3::operator/(Vector3 lhs, double rhs)
|
||||
Vector3 Vector3::operator/(Vector3 lhs, float rhs)
|
||||
{
|
||||
return Vector3
|
||||
(
|
||||
|
|
|
@ -11,6 +11,7 @@ Copyright (C) 2021 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.
|
||||
*//*************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Standard Libraries
|
||||
|
@ -21,8 +22,8 @@ of DigiPen Institute of Technology is prohibited.
|
|||
namespace SHADE
|
||||
{
|
||||
///<summary>
|
||||
/// CLR version of the the PlushieEngine's Vector3 class that represents a
|
||||
/// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct.
|
||||
/// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector.
|
||||
/// Designed to closely match Unity's Vector3 struct.
|
||||
/// </summary>
|
||||
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
|
||||
public value struct Vector3 : public System::IEquatable<Vector3>
|
||||
|
@ -35,49 +36,49 @@ namespace SHADE
|
|||
///<summary>
|
||||
/// Shorthand for writing Vector3(0, 0, -1).
|
||||
///</summary>
|
||||
static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0);
|
||||
static initonly Vector3 Back = Vector3(0.0f, 0.0f, -1.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(0, -1, 0).
|
||||
///</summary>
|
||||
static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0);
|
||||
static initonly Vector3 Down = Vector3(0.0f, -1.0f, 0.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(0, 0, 1).
|
||||
///</summary>
|
||||
static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0);
|
||||
static initonly Vector3 Forward = Vector3(0.0f, 0.0f, 1.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(-1, 0, 0).
|
||||
///</summary>
|
||||
static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0);
|
||||
static initonly Vector3 Left = Vector3(-1.0f, 0.0f, 0.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(double.NegativeInfinity,
|
||||
/// double.NegativeInfinity, double.NegativeInfinity).
|
||||
/// Shorthand for writing Vector3(float.NegativeInfinity,
|
||||
/// float.NegativeInfinity, float.NegativeInfinity).
|
||||
///</summary>
|
||||
static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<double>::lowest(),
|
||||
std::numeric_limits<double>::lowest(),
|
||||
std::numeric_limits<double>::lowest());
|
||||
static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<float>::lowest(),
|
||||
std::numeric_limits<float>::lowest(),
|
||||
std::numeric_limits<float>::lowest());
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(1, 1, 1).
|
||||
///</summary>
|
||||
static initonly Vector3 One = Vector3(1.0, 1.0, 1.0);
|
||||
static initonly Vector3 One = Vector3(1.0f, 1.0f, 1.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(double.PositiveInfinity,
|
||||
/// double.PositiveInfinity, double.PositiveInfinity).
|
||||
/// Shorthand for writing Vector3(float.PositiveInfinity,
|
||||
/// float.PositiveInfinity, float.PositiveInfinity).
|
||||
///</summary>
|
||||
static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<double>::max(),
|
||||
std::numeric_limits<double>::max(),
|
||||
std::numeric_limits<double>::max());
|
||||
static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max());
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(1, 0, 0).
|
||||
///</summary>
|
||||
static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0);
|
||||
static initonly Vector3 Right = Vector3(1.0f, 0.0f, 0.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(0, 1, 0).
|
||||
///</summary>
|
||||
static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0);
|
||||
static initonly Vector3 Up = Vector3(0.0f, 1.0f, 0.0f);
|
||||
///<summary>
|
||||
/// Shorthand for writing Vector3(0, 0, 0).
|
||||
///</summary>
|
||||
static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0);
|
||||
static initonly Vector3 Zero = Vector3(0.0f, 0.0f, 0.0f);
|
||||
#pragma endregion
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
@ -86,39 +87,39 @@ namespace SHADE
|
|||
///<summary>
|
||||
/// X-component of the Vector3.
|
||||
///</summary>
|
||||
double x;
|
||||
float x;
|
||||
///<summary>
|
||||
/// Y-component of the Vector3.
|
||||
///</summary>
|
||||
double y;
|
||||
float y;
|
||||
///<summary>
|
||||
/// Z-component of the Vector3.
|
||||
///</summary>
|
||||
double z;
|
||||
float z;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Constructor to construct a Vector3 with the specified components with the
|
||||
/// Y and Z-component set to 0.0.
|
||||
/// Y and Z-component set to 0.0f.
|
||||
/// </summary>
|
||||
/// <param name="_x">X-coordinate to set.</param>
|
||||
Vector3(double _x);
|
||||
Vector3(float _x);
|
||||
/// <summary>
|
||||
/// Constructor to construct a Vector3 with the specified components with the
|
||||
/// Z-component set to 0.0.
|
||||
/// Z-component set to 0.0f.
|
||||
/// </summary>
|
||||
/// <param name="_x">X-coordinate to set.</param>
|
||||
/// <param name="_y">Y-coordinate to set.</param>
|
||||
Vector3(double _x, double _y);
|
||||
Vector3(float _x, float _y);
|
||||
/// <summary>
|
||||
/// Constructor to construct a Vector3 with the specified components.
|
||||
/// </summary>
|
||||
/// <param name="_x">X-coordinate to set.</param>
|
||||
/// <param name="_y">Y-coordinate to set.</param>
|
||||
/// <param name="_z">Z-coordinate to set.</param>
|
||||
Vector3(double _x, double _y, double _z);
|
||||
Vector3(float _x, float _y, float _z);
|
||||
/// <summary>
|
||||
/// Conversion constructor to construct a Vector3 using a Vector2.
|
||||
/// </summary>
|
||||
|
@ -148,24 +149,24 @@ namespace SHADE
|
|||
/// need the precise magnitude, consider using GetSqrMagnitude() instead.
|
||||
/// </summary>
|
||||
/// <returns>Returns the length of this Vector3.</returns>
|
||||
double GetMagnitude();
|
||||
float GetMagnitude();
|
||||
/// <summary>
|
||||
/// Calculates and returns the squared magnitude of this Vector3.
|
||||
/// </summary>
|
||||
/// <returns>Returns the squared length of this Vector3.</returns>
|
||||
double GetSqrMagnitude();
|
||||
float GetSqrMagnitude();
|
||||
/// <summary>
|
||||
/// Calculates and returns the angle of this vector from the right vector. This
|
||||
/// function returns values between -Math.PI and Math.PI.
|
||||
/// </summary>
|
||||
/// <returns>Returns the angle of this vector from the right vector in radians.</returns>
|
||||
double Angle2DFromRightRadians();
|
||||
float Angle2DFromRightRadians();
|
||||
/// <summary>
|
||||
/// Calculates and returns the angle of this vector from the right vector. This
|
||||
/// function returns values between -180.0 and 180.0.
|
||||
/// function returns values between -180.0f and 180.0f.
|
||||
/// </summary>
|
||||
/// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
|
||||
double Angle2DFromRightDegrees();
|
||||
float Angle2DFromRightDegrees();
|
||||
/// <summary>
|
||||
/// Checks if a specified point is near this Vector3 that represents a point with
|
||||
/// a tolerance value of PLS_EPSILON.
|
||||
|
@ -187,7 +188,7 @@ namespace SHADE
|
|||
/// True if this Vector3 representing a point and the specified point are within
|
||||
/// the range of the specified tolerance. False otherwise.
|
||||
/// </returns>
|
||||
bool IsNearPoint(Vector3 point, double tolerance);
|
||||
bool IsNearPoint(Vector3 point, float tolerance);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* IEquatable */
|
||||
|
@ -207,12 +208,12 @@ namespace SHADE
|
|||
/// </summary>
|
||||
/// <param name="o">The unboxed object to compare with.</param>
|
||||
/// <returns>True if both objects are the same.</returns>
|
||||
bool Equals(Object^ o) override;
|
||||
bool Equals(Object^ o) override;
|
||||
/// <summary>
|
||||
/// Gets a unique hash for this object.
|
||||
/// </summary>
|
||||
/// <returns>Unique hash for this object.</returns>
|
||||
int GetHashCode() override;
|
||||
int GetHashCode() override;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Static Functions */
|
||||
|
@ -235,14 +236,14 @@ namespace SHADE
|
|||
/// <returns>
|
||||
/// True if the two Vector3s are within the tolerance value specified
|
||||
/// </returns>
|
||||
static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance);
|
||||
static bool IsNear(Vector3 lhs, Vector3 rhs, float tolerance);
|
||||
/// <summary>
|
||||
/// Computes and returns the dot product of 2 specified Vector3s.
|
||||
/// </summary>
|
||||
/// <param name="lhs">Vector3 to calculate dot product with.</param>
|
||||
/// <param name="rhs">Another Vector3 to calculate dot product with.</param>
|
||||
/// <returns>Scalar value representing the dot product of the two Vector3s.</returns>
|
||||
static double Dot(Vector3 lhs, Vector3 rhs);
|
||||
static float Dot(Vector3 lhs, Vector3 rhs);
|
||||
/// <summary>
|
||||
/// Computes and returns the cross product of 2 specified Vector3s.
|
||||
/// </summary>
|
||||
|
@ -273,7 +274,7 @@ namespace SHADE
|
|||
/// Angle to rotate the vector by in an anti-clockwise direction in radians.
|
||||
/// </param>
|
||||
/// <returns>The Vector3 that represents the rotated vector.</returns>
|
||||
static Vector3 RotateRadians(Vector3 vec, double radians);
|
||||
static Vector3 RotateRadians(Vector3 vec, float radians);
|
||||
/// <summary>
|
||||
/// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise
|
||||
/// direction.
|
||||
|
@ -283,7 +284,7 @@ namespace SHADE
|
|||
/// Angle to rotate the vector by in an anti-clockwise direction in degrees.
|
||||
/// </param>
|
||||
/// <returns>The Vector3 that represents the rotated vector.</returns>
|
||||
static Vector3 RotateDegrees(Vector3 vec, double degrees);
|
||||
static Vector3 RotateDegrees(Vector3 vec, float degrees);
|
||||
/// <summary>
|
||||
/// Computes and returns a Vector3 that is made from the smallest components of
|
||||
/// the two specified Vector3s.
|
||||
|
@ -311,25 +312,25 @@ namespace SHADE
|
|||
/// This is most commonly used to find a point some fraction of the way along a
|
||||
/// line between two endpoints.
|
||||
/// </summary>
|
||||
/// <param name="a">The start Vector3, returned when t = 0.0.</param>
|
||||
/// <param name="b">The end Vector3, returned when t = 1.0.</param>
|
||||
/// <param name="a">The start Vector3, returned when t = 0.0f.</param>
|
||||
/// <param name="b">The end Vector3, returned when t = 1.0f.</param>
|
||||
/// <param name="t">
|
||||
/// Value used to interpolate between a and b which is clamped to
|
||||
/// the range[0, 1].
|
||||
/// </param>
|
||||
/// <returns>The interpolated Vector3.</returns>
|
||||
static Vector3 Lerp(Vector3 a, Vector3 b, double t);
|
||||
static Vector3 Lerp(Vector3 a, Vector3 b, float t);
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two specified points.
|
||||
/// This is most commonly used to find a point some fraction of the way along a
|
||||
/// line between two endpoints.
|
||||
/// Unlike Lerp(), t is not clamped to a range at all.
|
||||
/// </summary>
|
||||
/// <param name="a">The start Vector3, returned when t = 0.0.</param>
|
||||
/// <param name="b">The end Vector3, returned when t = 1.0.</param>
|
||||
/// <param name="a">The start Vector3, returned when t = 0.0f.</param>
|
||||
/// <param name="b">The end Vector3, returned when t = 1.0f.</param>
|
||||
/// <param name="t">Value used to interpolate between a and b.</param>
|
||||
/// <returns>The interpolated Vector3.</returns>
|
||||
static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t);
|
||||
static Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t);
|
||||
/// <summary>
|
||||
/// Moves a point current towards target.
|
||||
/// Similar to Lerp(), however, the function will ensure that the distance never
|
||||
|
@ -340,7 +341,7 @@ namespace SHADE
|
|||
/// <param name="target">The target position to move to.</param>
|
||||
/// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
|
||||
/// <returns>Vector representing the moved point.</returns>
|
||||
static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta);
|
||||
static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Overloaded Operators */
|
||||
|
@ -374,7 +375,7 @@ namespace SHADE
|
|||
/// <param name="lhs">Vector3 to multiply with.</param>
|
||||
/// <param name="rhs">Scalar to multiply with.</param>
|
||||
/// <returns>The result of the scalar multiplication.</returns>
|
||||
static Vector3 operator*(Vector3 lhs, double rhs);
|
||||
static Vector3 operator*(Vector3 lhs, float rhs);
|
||||
/// <summary>
|
||||
/// Calculates the division of a Vector3 with a scalar value and returns
|
||||
/// the result.
|
||||
|
@ -382,7 +383,7 @@ namespace SHADE
|
|||
/// <param name="lhs">Scalar to divide with.</param>
|
||||
/// <param name="rhs">Vector3 to divide with.</param>
|
||||
/// <returns>The result of the scalar division.</returns>
|
||||
static Vector3 operator/(Vector3 lhs, double rhs);
|
||||
static Vector3 operator/(Vector3 lhs, float rhs);
|
||||
/// <summary>
|
||||
/// Checks if two Vector3s are approximately equal. This is equivalent to
|
||||
/// calling Vector3.IsNear() with default tolerance values.
|
||||
|
|
|
@ -35,10 +35,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
SHVec3 Convert::ToNative(Vector3 vec)
|
||||
{
|
||||
const double X = vec.x;
|
||||
const double Y = vec.y;
|
||||
const double Z = vec.z;
|
||||
return SHVec3(X, Y, Z);
|
||||
return SHVec3(vec.x, vec.y, vec.z);
|
||||
}
|
||||
Vector3 Convert::ToCLI(const SHVec3& vec)
|
||||
{
|
||||
|
@ -46,9 +43,7 @@ namespace SHADE
|
|||
}
|
||||
SHVec2 Convert::ToNative(Vector2 vec)
|
||||
{
|
||||
const double X = vec.x;
|
||||
const double Y = vec.y;
|
||||
return SHVec2(X, Y);
|
||||
return SHVec2(vec.x, vec.y);
|
||||
}
|
||||
|
||||
Vector2 Convert::ToCLI(const SHVec2& vec)
|
||||
|
@ -56,6 +51,16 @@ namespace SHADE
|
|||
return Vector2(vec.x, vec.y);
|
||||
}
|
||||
|
||||
SHQuaternion Convert::ToNative(Quaternion quat)
|
||||
{
|
||||
return SHQuaternion{ quat.x, quat.y, quat.z, quat.w };
|
||||
}
|
||||
|
||||
Quaternion Convert::ToCLI(const SHQuaternion& quat)
|
||||
{
|
||||
return Quaternion{ quat.x, quat.y, quat.z, quat.w };
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* String Conversions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -18,10 +18,12 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "ECS_Base/Entity/SHEntity.h"
|
||||
#include "Math/Vector/SHVec2.h"
|
||||
#include "Math/Vector/SHVec3.h"
|
||||
#include "Math/SHQuaternion.h"
|
||||
// Project Includes
|
||||
#include "Engine/Entity.hxx"
|
||||
#include "Math/Vector2.hxx"
|
||||
#include "Math/Vector3.hxx"
|
||||
#include "Math/Quaternion.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -74,6 +76,18 @@ namespace SHADE
|
|||
/// <param name="vec">The native Vector2 to convert from.</param>
|
||||
/// <returns>Managed copy of a native Vector2.</returns>
|
||||
static Vector2 ToCLI(const SHVec2& vec);
|
||||
/// <summary>
|
||||
/// Converts from a managed Quaternion to a native Quaternion.
|
||||
/// </summary>
|
||||
/// <param name="quat">The managed Quaternion to convert from.</param>
|
||||
/// <returns>Native copy of a managed Quaternion.</returns>
|
||||
static SHQuaternion ToNative(Quaternion quat);
|
||||
/// <summary>
|
||||
/// Converts from a native Quaternion to a managed Quaternion.
|
||||
/// </summary>
|
||||
/// <param name="quat">The native Quaternion to convert from.</param>
|
||||
/// <returns>Managed copy of a native Quaternion.</returns>
|
||||
static Quaternion ToCLI(const SHQuaternion& quat);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* String Conversions */
|
||||
|
|
|
@ -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