Merge branch 'main' into SP3-13-Assets-Manager

This commit is contained in:
Xiao Qi 2022-10-26 18:40:10 +08:00
commit f2e2b21d47
84 changed files with 3677 additions and 1485 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
root = true
[*.{c,cpp,h,hpp}]
indent_style = space
indent_size = 2

View File

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

View File

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

View File

@ -56,8 +56,8 @@ namespace Sandbox
_In_ INT nCmdShow
)
{
// Set working directory
SHFileUtilities::SetWorkDirToExecDir();
// Set working directory
SHFileUtilities::SetWorkDirToExecDir();
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
@ -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

View File

@ -12,6 +12,7 @@
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h"
#include "Camera/SHCameraComponent.h"
@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/SHMatrix.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "ECS_Base/SHECSMacros.h"
#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
namespace SHADE
{
@ -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;

View File

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

View File

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

View File

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

View File

@ -36,6 +36,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHTextureAsset.h"
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
namespace SHADE
{
@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -27,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;

View File

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

View File

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

View File

@ -0,0 +1,60 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.h"
namespace SHADE
{
class SH_API SHLightComponent final : public SHComponent
{
private:
//! General data for the light. This will purely be CPU bound. Whatever gets sent to the
//! GPU depends on the type of the light.
SHLightData lightData;
//! Since the lighting system is gonna be self contained and light weight, we store this
//! so that we only write this to the CPU buffer when this light component change, we don't
//! rewrite everything. However we still write to the GPU buffer when everything changes.
uint32_t indexInBuffer;
//! If the light component changed some value we mark this true.
bool dirty;
//! If the light's data is already in the buffers, this will be set to true.
bool bound;
//! If the light is active, this is true.
bool active;
public:
/*-----------------------------------------------------------------------*/
/* LIFECYCLE FUNCTIONS */
/*-----------------------------------------------------------------------*/
void OnCreate (void) override final;
void OnDestroy (void) override final;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
void SetPosition (SHVec3 position) noexcept;
void SetType (SH_LIGHT_TYPE type) noexcept;
void SetDirection (SHVec3 direction) noexcept;
void SetDiffuseColor (SHVec4 diffuseColor) noexcept;
void ModifyLayer (uint8_t layerIndex, bool value) noexcept;
void SetAllLayers (void) noexcept;
void ClearAllLayers (void) noexcept;
void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetActive (bool flag) noexcept;
SHLightData const& GetLightData (void) const noexcept;
bool IsDirty (void) const noexcept;
bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept;
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,9 +11,9 @@
#pragma once
// Project Headers
#include "SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Scene/SHSceneGraph.h"
#include "SHTransformComponent.h"
namespace SHADE
{
@ -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);
};

View File

@ -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 */
/*-----------------------------------------------------------------------------------*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,8 +26,6 @@ namespace SHADE
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, isRigidBody { false }
, hasColliders{ false }
, factory { physicsFactory }
, world { physicsWorld }
, rp3dBody { nullptr }
@ -130,42 +128,6 @@ namespace SHADE
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::CreateRigidBody(const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c)
{
// If collider already exists, recreate the collision body as a rigid body
if (hasColliders)
world->destroyCollisionBody(rp3dBody);
rp3dBody = world->createRigidBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
isRigidBody = true;
rb->position = tf->GetWorldPosition();
rb->orientation = 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());

View File

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

View File

@ -16,6 +16,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

View File

@ -16,14 +16,14 @@
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "SHPhysicsObject.h"
#include "Components/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "SHPhysicsObject.h"
namespace SHADE
@ -32,7 +32,7 @@ namespace SHADE
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem : public SHSystem
class SH_API SHPhysicsSystem final : public SHSystem
{
public:
/*---------------------------------------------------------------------------------*/
@ -85,21 +85,10 @@ namespace SHADE
void Init () override;
void Exit () override;
void AddRigidBody (EntityID entityID) noexcept;
void AddCollider (EntityID entityID) noexcept;
void RemoveRigidBody (EntityID entityID) noexcept;
void RemoveCollider (EntityID entityID) noexcept;
void AddForce (EntityID entityID, const SHVec3& force) const noexcept;
void AddForceAtLocalPos (EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept;
void AddForceAtWorldPos (EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept;
void AddRelativeForce (EntityID entityID, const SHVec3& relativeForce) const noexcept;
void AddRelativeForceAtLocalPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept;
void AddRelativeForceAtWorldPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept;
void AddTorque (EntityID entityID, const SHVec3& torque) const noexcept;
void AddRelativeTorque (EntityID entityID, const SHVec3& relativeTorque) const noexcept;
//void AddRigidBody (EntityID entityID) noexcept;
//void AddCollider (EntityID entityID) noexcept;
//void RemoveRigidBody (EntityID entityID) noexcept;
//void RemoveCollider (EntityID entityID) noexcept;
void AddCollisionShape (EntityID entityID, SHCollider* collider);
void RemoveCollisionShape (EntityID entityID, int index);
@ -108,10 +97,7 @@ namespace SHADE
/* System Routines */
/*---------------------------------------------------------------------------------*/
/**
* @brief Synchronises RP3D with SHADE
*/
class SH_API PhysicsPreUpdate : public SHSystemRoutine
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
@ -127,7 +113,7 @@ namespace SHADE
void Execute(double dt) noexcept override;
};
class SH_API PhysicsFixedUpdate : public SHFixedSystemRoutine
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
@ -143,7 +129,7 @@ namespace SHADE
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate : public SHSystemRoutine
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
@ -170,15 +156,14 @@ namespace SHADE
/* Data Members */
/*---------------------------------------------------------------------------------*/
// TODO(Diren): Store interpFactor
bool worldUpdated;
double interpolationFactor;
double fixedDT;
rp3d::PhysicsWorld* world;
rp3d::PhysicsWorld* world;
rp3d::PhysicsCommon factory;
EntityObjectMap map;
@ -186,7 +171,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* CreatePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept;
@ -194,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);
};

View File

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

View File

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

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */
/*---------------------------------------------------------------------------------*/

View File

@ -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 */

View File

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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

Binary file not shown.