Merge branch 'main' into PlayerController

This commit is contained in:
Glence 2022-11-11 09:21:36 +08:00
commit 4f9015995c
76 changed files with 1984 additions and 872 deletions

View File

@ -50,7 +50,7 @@
Colliders: Colliders:
- Is Trigger: false - Is Trigger: false
Type: Box Type: Box
Half Extents: {x: 24.7399445, y: 0.25, z: 8.75} Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006 Friction: 0.400000006
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1
@ -90,23 +90,7 @@
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1
Position Offset: {x: 0, y: 0.5, z: 0} Position Offset: {x: 0, y: 0.5, z: 0}
Scripts: Scripts: ~
- Type: PlayerController
drag: 2
currentState: 0
maxMoveVel: 2
moveForce: 50
sprintMultiplier: 2
rotationFactorPerFrame: 1
maxJumpHeight: 4
maxJumpTime: 0.75
fallMultipler: 2
lightMultiper: 0.75
mediumMultiper: 0.5
heavyMultiper: 0.25
- Type: PickAndThrow
throwForce: [200, 300, 200]
item: 5
- EID: 3 - EID: 3
Name: Default Name: Default
IsActive: true IsActive: true
@ -126,12 +110,7 @@
Translate: {x: 0, y: 0, z: 0} Translate: {x: 0, y: 0, z: 0}
Rotate: {x: 0, y: 0, z: 0} Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
Scripts: Scripts: ~
- Type: SHADE_Scripting.ThirdPersonCamera
armLength: 2
turnSpeedPitch: 0.300000012
turnSpeedYaw: 0.5
pitchClamp: 45
- EID: 9 - EID: 9
Name: Default Name: Default
IsActive: true IsActive: true
@ -145,6 +124,67 @@
Mesh: 144838771 Mesh: 144838771
Material: 123745521 Material: 123745521
Scripts: ~ Scripts: ~
- EID: 6
Name: AI
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -8, y: -2, z: 2.5}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
Renderable Component:
Mesh: 149697411
Material: 126974645
RigidBody Component:
Type: Dynamic
Mass: 1
Drag: 0
Angular Drag: 0
Use Gravity: true
Interpolate: false
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: true
Freeze Rotation Y: true
Freeze Rotation Z: true
Collider Component:
Colliders:
- Is Trigger: false
Type: Box
Half Extents: {x: 0.5, y: 0.5, z: 0.5}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0.5, z: 0}
Scripts: ~
- EID: 7
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -16.8647861, z: -14.039052}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 28.1434975, y: 28.1434975, z: 28.1434975}
Renderable Component:
Mesh: 149697411
Material: 126974645
Scripts: ~
- EID: 8
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Light Component:
Position: {x: 0, y: 0, z: 0}
Type: Ambient
Direction: {x: 0, y: 0, z: 1}
Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295
Strength: 0.25
Scripts: ~
- EID: 5 - EID: 5
Name: item Name: item
IsActive: true IsActive: true
@ -186,77 +226,4 @@
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1
Position Offset: {x: 0, y: 0.5, z: 0} Position Offset: {x: 0, y: 0.5, z: 0}
Scripts:
- Type: Item
currCategory: 0
- EID: 6
Name: AI
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -8, y: -2, z: 2.5}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
Renderable Component:
Mesh: 149697411
Material: 126974645
RigidBody Component:
Type: Dynamic
Mass: 1
Drag: 0
Angular Drag: 0
Use Gravity: true
Interpolate: false
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: true
Freeze Rotation Y: true
Freeze Rotation Z: true
Collider Component:
Colliders:
- Is Trigger: false
Type: Box
Half Extents: {x: 0.5, y: 0.5, z: 0.5}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0.5, z: 0}
Scripts:
- Type: AIPrototype
movementForceMultiplier: 100
patrolSpeed: 0.400000006
chaseSpeed: 0.800000012
distanceToCapture: 1.20000005
distanceToStartChase: 2
distanceToEndChase: 2.5
- EID: 7
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -16.8647861, z: -14.039052}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 28.1434975, y: 28.1434975, z: 28.1434975}
Renderable Component:
Mesh: 149697411
Material: 126974645
Scripts: ~ Scripts: ~
- EID: 8
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Light Component:
Position: {x: 0, y: 0, z: 0}
Type: Ambient
Direction: {x: 0, y: 0, z: 1}
Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295
Strength: 0.25
Scripts:
- Type: PickAndThrow
throwForce: [100, 200, 100]
item: 1

View File

@ -27,6 +27,11 @@ public class RaccoonShowcase : Script
Debug.LogError("Transform is NULL!"); Debug.LogError("Transform is NULL!");
} }
foreach (var child in Owner)
{
Debug.Log(child.Name);
}
originalScale = Transform.LocalScale.z; originalScale = Transform.LocalScale.z;
} }
protected override void update() protected override void update()
@ -36,4 +41,10 @@ public class RaccoonShowcase : Script
//Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); //Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f);
//Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); //Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale);
} }
protected override void onDrawGizmos()
{
Gizmos.DrawLine(new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
Gizmos.DrawLine(new Vector3(-1.0f, 1.0f, 0.0f), new Vector3(1.0f, 1.0f, 0.0f), Color.Red);
}
} }

View File

@ -106,6 +106,7 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>(); SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::GizmosDrawRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();

View File

@ -92,7 +92,7 @@ namespace Sandbox
floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC); floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC);
auto* floorBox = floorCollider.AddBoundingBox(); floorCollider.AddBoundingBox();
// Create blank entity with a script // Create blank entity with a script
//testObj = SHADE::SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>(); //testObj = SHADE::SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
@ -114,8 +114,8 @@ namespace Sandbox
racoonTransform.SetWorldPosition({ -3.0f, -2.0f, -5.0f }); racoonTransform.SetWorldPosition({ -3.0f, -2.0f, -5.0f });
racoonCollider.AddBoundingBox(); racoonCollider.AddBoundingBox();
racoonCollider.GetCollider(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f)); racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f));
racoonCollider.GetCollider(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
auto racoonItemLocation = SHEntityManager::CreateEntity<SHTransformComponent>(); auto racoonItemLocation = SHEntityManager::CreateEntity<SHTransformComponent>();
auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s<SHTransformComponent>(racoonItemLocation); auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s<SHTransformComponent>(racoonItemLocation);
@ -140,13 +140,13 @@ namespace Sandbox
itemCollider.AddBoundingBox(); itemCollider.AddBoundingBox();
itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f)); itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f));
itemCollider.GetCollider(1).SetIsTrigger(true); itemCollider.GetCollisionShape(1).SetIsTrigger(true);
itemCollider.GetCollider(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); itemCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
itemCollider.GetCollider(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
itemCollider.GetCollider(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); itemCollider.GetCollisionShape(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
itemCollider.GetCollider(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f)); itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f));
itemRigidBody.SetInterpolate(false); itemRigidBody.SetInterpolate(false);
itemRigidBody.SetFreezeRotationX(true); itemRigidBody.SetFreezeRotationX(true);
@ -168,8 +168,8 @@ namespace Sandbox
AITransform.SetWorldPosition({ -8.0f, -2.0f, 2.5f }); AITransform.SetWorldPosition({ -8.0f, -2.0f, 2.5f });
AICollider.AddBoundingBox(); AICollider.AddBoundingBox();
AICollider.GetCollider(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
AICollider.GetCollider(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
AIRigidBody.SetInterpolate(false); AIRigidBody.SetInterpolate(false);
AIRigidBody.SetFreezeRotationX(true); AIRigidBody.SetFreezeRotationX(true);

View File

@ -51,6 +51,7 @@ enum class AssetType : AssetTypeMeta
SCENE, SCENE,
PREFAB, PREFAB,
MATERIAL, MATERIAL,
SCRIPT,
MESH, MESH,
MAX_COUNT MAX_COUNT
}; };
@ -91,12 +92,12 @@ constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION, AUDIO_EXTENSION,
SHADER_EXTENSION, SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION, SHADER_BUILT_IN_EXTENSION,
MATERIAL_EXTENSION,
TEXTURE_EXTENSION, TEXTURE_EXTENSION,
MODEL_EXTENSION, MODEL_EXTENSION,
SCRIPT_EXTENSION,
SCENE_EXTENSION, SCENE_EXTENSION,
PREFAB_EXTENSION, PREFAB_EXTENSION,
MATERIAL_EXTENSION,
SCRIPT_EXTENSION,
AUDIO_WAV_EXTENSION, AUDIO_WAV_EXTENSION,
}; };

View File

@ -338,7 +338,7 @@ namespace SHADE
return result; return result;
} }
void SHAssetManager::CompileAsset(AssetPath const& path) noexcept void SHAssetManager::CompileAsset(AssetPath const& path, bool genMeta) noexcept
{ {
if (!std::filesystem::exists(path)) if (!std::filesystem::exists(path))
{ {
@ -360,10 +360,12 @@ namespace SHADE
std::string modelPath = path.string().substr(0, path.string().find_last_of('.')); std::string modelPath = path.string().substr(0, path.string().find_last_of('.'));
modelPath += MODEL_EXTENSION; modelPath += MODEL_EXTENSION;
newPath = modelPath; newPath = modelPath;
GenerateNewMeta(newPath);
} }
if (genMeta)
{
GenerateNewMeta(newPath);
}
} }
FolderPointer SHAssetManager::GetRootFolder() noexcept FolderPointer SHAssetManager::GetRootFolder() noexcept
@ -371,6 +373,13 @@ namespace SHADE
return folderRoot; return folderRoot;
} }
void SHAssetManager::RefreshDirectory() noexcept
{
SHFileSystem::DestroyDirectory(folderRoot);
assetCollection.clear();
BuildAssetCollection();
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept bool SHAssetManager::IsRecognised(char const* ext) noexcept
{ {
for (auto const& e : EXTENSIONS) for (auto const& e : EXTENSIONS)

View File

@ -87,9 +87,10 @@ namespace SHADE
static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept; static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept; static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static void CompileAsset(AssetPath const& path) noexcept; static void CompileAsset(AssetPath const& path, bool genMeta) noexcept;
static FolderPointer GetRootFolder() noexcept; static FolderPointer GetRootFolder() noexcept;
static void RefreshDirectory() noexcept;
private: private:

View File

@ -17,6 +17,8 @@
#include <FMOD/fmod_studio.hpp> #include <FMOD/fmod_studio.hpp>
#include <SDL_keyboard.h> #include <SDL_keyboard.h>
const std::string AUDIO_FOLDER_PATH{ std::string(ASSET_ROOT)+ "/Audio/" };
namespace SHADE namespace SHADE
{ {
SHAudioSystem::SHAudioSystem() SHAudioSystem::SHAudioSystem()
@ -79,10 +81,10 @@ namespace SHADE
//SHResourceManager::LoadAllAudio(system, soundList); //SHResourceManager::LoadAllAudio(system, soundList);
LoadBank("../../Assets/Audio/Master.bank"); LoadBank((AUDIO_FOLDER_PATH + "Master.bank").data());
LoadBank("../../Assets/Audio/Master.strings.bank"); LoadBank((AUDIO_FOLDER_PATH + "Master.strings.bank").data());
//LoadBank("../../Assets/Audio/Music.bank"); //LoadBank((AUDIO_FOLDER_PATH + "Music.bank").data());
LoadBank("../../Assets/Audio/footsteps.bank"); LoadBank((AUDIO_FOLDER_PATH + "footsteps.bank").data());
//auto clip = CreateAudioClip("event:/Characters/sfx_footsteps_human"); //auto clip = CreateAudioClip("event:/Characters/sfx_footsteps_human");
//clip->Play(); //clip->Play();

View File

@ -419,7 +419,7 @@ namespace SHADE
void SHEntityParentCommand::Execute() void SHEntityParentCommand::Execute()
{ {
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities) for (auto const& eid : entities)
{ {
if (entityParentData[eid].newParentEID == MAX_EID) if (entityParentData[eid].newParentEID == MAX_EID)
@ -431,7 +431,7 @@ namespace SHADE
void SHEntityParentCommand::Undo() void SHEntityParentCommand::Undo()
{ {
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities) for (auto const& eid : entities)
{ {
if (entityParentData[eid].oldParentEID == MAX_EID) if (entityParentData[eid].oldParentEID == MAX_EID)

View File

@ -224,9 +224,6 @@ namespace SHADE
if (!component) if (!component)
return; return;
// Get transform component for extrapolating relative sizes
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(component->GetEID());
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
@ -234,46 +231,39 @@ namespace SHADE
{ {
DrawContextMenu(component); DrawContextMenu(component);
auto& colliders = component->GetColliders(); auto& colliders = component->GetCollisionShapes();
int const size = static_cast<int>(colliders.size()); int const size = static_cast<int>(colliders.size());
ImGui::BeginChild("Colliders", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true); ImGui::BeginChild("Collision Shapes", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true);
std::optional<int> colliderToDelete{ std::nullopt }; std::optional<int> colliderToDelete{ std::nullopt };
for (int i{}; i < size; ++i) for (int i{}; i < size; ++i)
{ {
ImGui::PushID(i); ImGui::PushID(i);
SHCollider* collider = &component->GetCollider(i); SHCollisionShape* collider = &component->GetCollisionShape(i);
auto cursorPos = ImGui::GetCursorPos(); auto cursorPos = ImGui::GetCursorPos();
//collider->IsTrigger //collider->IsTrigger
if (collider->GetType() == SHCollider::Type::BOX) if (collider->GetType() == SHCollisionShape::Type::BOX)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
SHEditorWidgets::CheckBox("Is Trigger", [collider]() {return collider->IsTrigger(); }, [collider](bool const& value) {collider->SetIsTrigger(value); }, "Is Trigger");
auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape()); auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3 SHEditorWidgets::DragVec3
( (
"Half Extents", { "X", "Y", "Z" }, "Half Extents", { "X", "Y", "Z" },
[box, transformComponent] { return (box->GetHalfExtents() * 2.0f) / transformComponent->GetWorldScale(); }, [box] { return box->GetRelativeExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
} }
else if (collider->GetType() == SHCollider::Type::SPHERE) else if (collider->GetType() == SHCollisionShape::Type::SPHERE)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
SHEditorWidgets::CheckBox("Is Trigger", [collider]() {return collider->IsTrigger(); }, [collider](bool const& value) {collider->SetIsTrigger(value); }, "Is Trigger");
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape()); auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat SHEditorWidgets::DragFloat
( (
"Radius", "Radius",
[sphere, transformComponent] [sphere] { return sphere->GetRelativeRadius(); },
{
const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
return (sphere->GetRadius() / MAX_SCALE) * 2.0f;
},
[collider](float const& value) { collider->SetBoundingSphere(value); }); [collider](float const& value) { collider->SetBoundingSphere(value); });
} }
else if (collider->GetType() == SHCollider::Type::CAPSULE) else if (collider->GetType() == SHCollisionShape::Type::CAPSULE)
{ {
} }

View File

@ -24,6 +24,9 @@
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Serialization/Configurations/SHConfigurationManager.h" #include "Serialization/Configurations/SHConfigurationManager.h"
const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" };
namespace SHADE namespace SHADE
{ {
constexpr ImGuiWindowFlags editorMenuBarFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | constexpr ImGuiWindowFlags editorMenuBarFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
@ -43,8 +46,7 @@ namespace SHADE
void SHEditorMenuBar::Init() void SHEditorMenuBar::Init()
{ {
SHEditorWindow::Init(); SHEditorWindow::Init();
constexpr std::string_view path = "../../Assets/Editor/Layouts"; for(auto const& entry : std::filesystem::directory_iterator(LAYOUT_FOLDER_PATH))
for(auto const& entry : std::filesystem::directory_iterator(path))
{ {
layoutPaths.push_back(entry.path()); layoutPaths.push_back(entry.path());
} }

View File

@ -65,6 +65,10 @@ RTTR_REGISTRATION
); );
} }
const std::string USER_LAYOUT_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts/UserLayout.ini" };
const std::string DEFAULT_LAYOUT_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts/Default.ini" };
const std::string FONT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Fonts/"};
namespace SHADE namespace SHADE
{ {
@ -106,7 +110,7 @@ namespace SHADE
io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking
io->IniFilename = "../../Assets/Editor/Layouts/UserLayout.ini"; io->IniFilename = USER_LAYOUT_PATH.data();
io->ConfigWindowsMoveFromTitleBarOnly = true; io->ConfigWindowsMoveFromTitleBarOnly = true;
InitLayout(); InitLayout();
@ -236,20 +240,20 @@ namespace SHADE
{ {
if(!std::filesystem::exists(io->IniFilename)) if(!std::filesystem::exists(io->IniFilename))
{ {
std::filesystem::copy_file("../../Assets/Editor/Layouts/Default.ini", io->IniFilename); std::filesystem::copy_file(DEFAULT_LAYOUT_PATH.data(), io->IniFilename);
} }
//eventually load preferred layout here //eventually load preferred layout here
} }
void SHEditor::InitFonts() noexcept void SHEditor::InitFonts() noexcept
{ {
ImFont* mainFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path ImFont* mainFont = io->Fonts->AddFontFromFileTTF(std::string(FONT_FOLDER_PATH + "Segoe UI.ttf").data(), 20.f);//TODO: Change to config based assets path
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f; ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f;
constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF(std::string(FONT_FOLDER_PATH + "fa-solid-900.ttf").data(), 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path
constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 }; constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF(std::string(FONT_FOLDER_PATH + "MaterialIcons-Regular.ttf").data(), 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path
io->Fonts->Build(); io->Fonts->Build();
} }

View File

@ -11,9 +11,11 @@ constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 };
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 }; constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 };
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 }; constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 };
constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 }; constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 6 }; constexpr SHEventIdentifier SH_SCENEGRAPH_ADD_CHILD_EVENT { 6 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 }; constexpr SHEventIdentifier SH_SCENEGRAPH_REMOVE_CHILD_EVENT { 7 };
constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 8 }; constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 8 };
constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 9 }; constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 9 };
constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 10 }; constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 10 };
constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 11 };
constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 12 };

View File

@ -12,6 +12,7 @@
#include "SHFileSystem.h" #include "SHFileSystem.h"
#include <filesystem> #include <filesystem>
#include <queue> #include <queue>
#include <stack>
#include "Assets/SHAssetMetaHandler.h" #include "Assets/SHAssetMetaHandler.h"
@ -24,23 +25,37 @@ namespace SHADE
return true; return true;
} }
bool SHFileSystem::IsCompilable(std::string ext) noexcept
{
for (auto const& external : EXTERNALS)
{
if (ext == external)
{
return true;
}
}
return false;
}
void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept
{ {
std::queue<FolderPointer> folderQueue; std::stack<FolderPointer> folderStack;
root = new SHFolder("root"); root = new SHFolder("root");
root->path = path; root->path = path;
folderQueue.push(root); folderStack.push(root);
while (!folderQueue.empty()) while (!folderStack.empty())
{ {
auto const folder = folderQueue.front(); auto const folder = folderStack.top();
folderQueue.pop(); folderStack.pop();
std::vector<SHAsset> assets; std::vector<SHAsset> assets;
for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path)) for (auto& dirEntry : std::filesystem::directory_iterator(folder->path))
{ {
auto const& path = dirEntry.path(); auto path = dirEntry.path();
path.make_preferred();
if (!dirEntry.is_directory()) if (!dirEntry.is_directory())
{ {
if (path.extension().string() == META_EXTENSION) if (path.extension().string() == META_EXTENSION)
@ -55,14 +70,15 @@ namespace SHADE
path.stem().string(), path.stem().string(),
path.string(), path.string(),
path.extension().string(), path.extension().string(),
nullptr nullptr,
IsCompilable(path.extension().string())
); );
} }
continue; continue;
} }
auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) }; auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
folderQueue.push(newFolder); folderStack.push(newFolder);
} }
for (auto const& asset : assets) for (auto const& asset : assets)
@ -71,6 +87,9 @@ namespace SHADE
for(auto& file : folder->files) for(auto& file : folder->files)
{ {
if (file.name == asset.name) if (file.name == asset.name)
{
AssetPath path{ file.path };
if (SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()) == asset.type)
{ {
file.assetMeta = &assetCollection[asset.id]; file.assetMeta = &assetCollection[asset.id];
break; break;
@ -80,3 +99,23 @@ namespace SHADE
} }
} }
} }
void SHFileSystem::DestroyDirectory(FolderPointer root) noexcept
{
std::stack<FolderPointer> folderStack;
folderStack.push(root);
while(!folderStack.empty())
{
auto const folder = folderStack.top();
folderStack.pop();
for (auto const& ptr : folder->subFolders)
{
folderStack.push(ptr);
}
delete folder;
}
}
}

View File

@ -20,9 +20,9 @@ namespace SHADE
{ {
public: public:
static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept; static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept;
static void DestroyDirectory(FolderPointer root) noexcept;
private: private:
static bool DeleteFolder(FolderPointer location) noexcept; static bool DeleteFolder(FolderPointer location) noexcept;
static bool IsCompilable(std::string ext) noexcept;
}; };
} }

View File

@ -33,6 +33,7 @@ namespace SHADE
FilePath path; FilePath path;
FileExt ext; FileExt ext;
SHAsset const* assetMeta; SHAsset const* assetMeta;
bool compilable;
}; };
class SHFolder class SHFolder

View File

@ -323,7 +323,7 @@ namespace SHADE
static const SHMeshData SPHERE = SHPrimitiveGenerator::Sphere(); static const SHMeshData SPHERE = SHPrimitiveGenerator::Sphere();
for (const auto& idx : SPHERE.Indices) for (const auto& idx : SPHERE.Indices)
{ {
spherePoints.emplace_back(SPHERE.VertexPositions[idx]); spherePoints.emplace_back(SPHERE.VertexPositions[idx] * radius);
} }
} }
drawLineSet(storage, color, spherePoints.begin(), spherePoints.end()); drawLineSet(storage, color, spherePoints.begin(), spherePoints.end());

View File

@ -25,11 +25,13 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHBoundingBox::SHBoundingBox() noexcept SHBoundingBox::SHBoundingBox() noexcept
: RelativeExtents { SHVec3::One }
{ {
type = Type::BOX; type = Type::BOX;
} }
SHBoundingBox::SHBoundingBox(const SHVec3& c, const SHVec3& hE) noexcept SHBoundingBox::SHBoundingBox(const SHVec3& c, const SHVec3& hE) noexcept
: RelativeExtents { SHVec3::One }
{ {
type = Type::BOX; type = Type::BOX;
@ -47,6 +49,7 @@ namespace SHADE
Center = rhs.Center; Center = rhs.Center;
Extents = rhs.Extents; Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
} }
SHBoundingBox::SHBoundingBox(SHBoundingBox&& rhs) noexcept SHBoundingBox::SHBoundingBox(SHBoundingBox&& rhs) noexcept
@ -55,6 +58,7 @@ namespace SHADE
Center = rhs.Center; Center = rhs.Center;
Extents = rhs.Extents; Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -71,6 +75,7 @@ namespace SHADE
{ {
Center = rhs.Center; Center = rhs.Center;
Extents = rhs.Extents; Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
} }
return *this; return *this;
@ -86,6 +91,7 @@ namespace SHADE
{ {
Center = rhs.Center; Center = rhs.Center;
Extents = rhs.Extents; Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
} }
return *this; return *this;
@ -100,11 +106,16 @@ namespace SHADE
return Center; return Center;
} }
SHVec3 SHBoundingBox::GetHalfExtents() const noexcept SHVec3 SHBoundingBox::GetWorldExtents() const noexcept
{ {
return Extents; return Extents;
} }
const SHVec3& SHBoundingBox::GetRelativeExtents() const noexcept
{
return RelativeExtents;
}
SHVec3 SHBoundingBox::GetMin() const noexcept SHVec3 SHBoundingBox::GetMin() const noexcept
{ {
return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z }; return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z };
@ -124,9 +135,14 @@ namespace SHADE
Center = newCenter; Center = newCenter;
} }
void SHBoundingBox::SetHalfExtents(const SHVec3& newHalfExtents) noexcept void SHBoundingBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
{ {
Extents = newHalfExtents; Extents = newWorldExtents;
}
void SHBoundingBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
{
RelativeExtents = newRelativeExtents;
} }
void SHBoundingBox::SetMin(const SHVec3& min) noexcept void SHBoundingBox::SetMin(const SHVec3& min) noexcept

View File

@ -55,7 +55,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetCenter () const noexcept; [[nodiscard]] SHVec3 GetCenter () const noexcept;
[[nodiscard]] SHVec3 GetHalfExtents() const noexcept; [[nodiscard]] SHVec3 GetWorldExtents () const noexcept;
[[nodiscard]] const SHVec3& GetRelativeExtents () const noexcept;
[[nodiscard]] SHVec3 GetMin () const noexcept; [[nodiscard]] SHVec3 GetMin () const noexcept;
[[nodiscard]] SHVec3 GetMax () const noexcept; [[nodiscard]] SHVec3 GetMax () const noexcept;
[[nodiscard]] std::vector<SHVec3> GetVertices () const noexcept; [[nodiscard]] std::vector<SHVec3> GetVertices () const noexcept;
@ -65,7 +66,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetCenter (const SHVec3& newCenter) noexcept; void SetCenter (const SHVec3& newCenter) noexcept;
void SetHalfExtents (const SHVec3& newHalfExtents) noexcept; void SetWorldExtents (const SHVec3& newWorldExtents) noexcept;
void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept;
void SetMin (const SHVec3& min) noexcept; void SetMin (const SHVec3& min) noexcept;
void SetMax (const SHVec3& max) noexcept; void SetMax (const SHVec3& max) noexcept;
void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept;
@ -89,6 +91,13 @@ namespace SHADE
[[nodiscard]] static bool Intersect (const SHBoundingBox& lhs, const SHBoundingBox& rhs) noexcept; [[nodiscard]] static bool Intersect (const SHBoundingBox& lhs, const SHBoundingBox& rhs) noexcept;
[[nodiscard]] static SHBoundingBox BuildFromBoxes (const SHBoundingBox* boxes, size_t numBoxes) noexcept; [[nodiscard]] static SHBoundingBox BuildFromBoxes (const SHBoundingBox* boxes, size_t numBoxes) noexcept;
[[nodiscard]] static SHBoundingBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; [[nodiscard]] static SHBoundingBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHVec3 RelativeExtents;
}; };

View File

@ -25,11 +25,13 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHBoundingSphere::SHBoundingSphere() noexcept SHBoundingSphere::SHBoundingSphere() noexcept
: RelativeRadius { 1.0f }
{ {
type = Type::SPHERE; type = Type::SPHERE;
} }
SHBoundingSphere::SHBoundingSphere(const SHVec3& center, float radius) noexcept SHBoundingSphere::SHBoundingSphere(const SHVec3& center, float radius) noexcept
: RelativeRadius { 1.0f }
{ {
type = Type::SPHERE; type = Type::SPHERE;
@ -46,6 +48,7 @@ namespace SHADE
Center = rhs.Center; Center = rhs.Center;
Radius = rhs.Radius; Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
} }
SHBoundingSphere::SHBoundingSphere(SHBoundingSphere&& rhs) noexcept SHBoundingSphere::SHBoundingSphere(SHBoundingSphere&& rhs) noexcept
@ -54,6 +57,7 @@ namespace SHADE
Center = rhs.Center; Center = rhs.Center;
Radius = rhs.Radius; Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -70,6 +74,7 @@ namespace SHADE
{ {
Center = rhs.Center; Center = rhs.Center;
Radius = rhs.Radius; Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
} }
return *this; return *this;
@ -85,6 +90,7 @@ namespace SHADE
{ {
Center = rhs.Center; Center = rhs.Center;
Radius = rhs.Radius; Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
} }
return *this; return *this;
@ -99,11 +105,16 @@ namespace SHADE
return Center; return Center;
} }
float SHBoundingSphere::GetRadius() const noexcept float SHBoundingSphere::GetWorldRadius() const noexcept
{ {
return Radius; return Radius;
} }
float SHBoundingSphere::GetRelativeRadius() const noexcept
{
return RelativeRadius;
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */ /* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -113,9 +124,14 @@ namespace SHADE
Center = center; Center = center;
} }
void SHBoundingSphere::SetRadius(float radius) noexcept void SHBoundingSphere::SetWorldRadius(float newWorldRadius) noexcept
{ {
Radius = radius; Radius = newWorldRadius;
}
void SHBoundingSphere::SetRelativeRadius(float newRelativeRadius) noexcept
{
RelativeRadius = newRelativeRadius;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -49,14 +49,16 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetCenter () const noexcept; [[nodiscard]] SHVec3 GetCenter () const noexcept;
[[nodiscard]] float GetRadius () const noexcept; [[nodiscard]] float GetWorldRadius () const noexcept;
[[nodiscard]] float GetRelativeRadius () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetCenter (const SHVec3& center) noexcept; void SetCenter (const SHVec3& center) noexcept;
void SetRadius (float radius) noexcept; void SetWorldRadius (float newWorldRadius) noexcept;
void SetRelativeRadius (float newRelativeRadius) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -79,5 +81,12 @@ namespace SHADE
[[nodiscard]] static SHBoundingSphere BuildFromSpheres (const SHBoundingSphere* spheres, size_t numSpheres) noexcept; [[nodiscard]] static SHBoundingSphere BuildFromSpheres (const SHBoundingSphere* spheres, size_t numSpheres) noexcept;
[[nodiscard]] static SHBoundingSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; [[nodiscard]] static SHBoundingSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
float RelativeRadius;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -231,12 +231,12 @@ namespace SHADE
tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero); tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
// Set the orientation // Set the orientation
// Wrap rotations between -360 and 360 and convert to radians // Wrap rotations between -720 and 720 and convert to radians
SHVec3 worldRotRad, localRotRad; SHVec3 worldRotRad, localRotRad;
for (size_t i = 0; i < SHVec3::SIZE; ++i) for (size_t i = 0; i < SHVec3::SIZE; ++i)
{ {
worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI); worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -2.0f * SHMath::TWO_PI, 2.0f * SHMath::TWO_PI);
localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI); localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -2.0f * SHMath::TWO_PI, 2.0f * SHMath::TWO_PI);
} }
tf.world.orientation = SHQuaternion::FromEuler(worldRotRad); tf.world.orientation = SHQuaternion::FromEuler(worldRotRad);

View File

@ -48,17 +48,22 @@ namespace SHADE
return orientation.ToEuler(); return orientation.ToEuler();
} }
const SHColliderComponent::Colliders& SHColliderComponent::GetColliders() const noexcept const SHVec3& SHColliderComponent::GetScale() const noexcept
{ {
return colliders; return scale;
} }
SHCollider& SHColliderComponent::GetCollider(int index) const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept
{ {
if (index < 0 || static_cast<size_t>(index) >= colliders.size()) return collisionShapes;
}
SHCollisionShape& SHColliderComponent::GetCollisionShape(int index)
{
if (index < 0 || static_cast<size_t>(index) >= collisionShapes.size())
throw std::invalid_argument("Out-of-range access!"); throw std::invalid_argument("Out-of-range access!");
return colliders[index]; return collisionShapes[index];
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -75,39 +80,74 @@ namespace SHADE
} }
SHBoundingBox* SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset) noexcept void SHColliderComponent::RecomputeCollisionShapes() noexcept
{
for (auto& collisionShape : collisionShapes)
{
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX:
{
auto* box = reinterpret_cast<SHBoundingBox*>(collisionShape.GetShape());
const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents();
// Recompute world extents based on new scale and fixed relative extents
const SHVec3 WORLD_EXTENTS = RELATIVE_EXTENTS * (scale * 0.5f);
box->SetWorldExtents(WORLD_EXTENTS);
continue;
}
case SHCollisionShape::Type::SPHERE:
{
auto* sphere = reinterpret_cast<SHBoundingSphere*>(collisionShape.GetShape());
const float RELATIVE_RADIUS = sphere->GetRelativeRadius();
// Recompute world radius based on new scale and fixed radius
const float MAX_SCALE = SHMath::Max({ scale.x, scale.y, scale.z });
const float WORLD_RADIUS = RELATIVE_RADIUS * MAX_SCALE * 0.5f;
sphere->SetWorldRadius(WORLD_RADIUS);
continue;
}
default: continue;
}
}
}
int SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset, const SHVec3& rotOffset) noexcept
{ {
if (!system) if (!system)
{ {
SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!") SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
return nullptr; return -1;
} }
static constexpr auto TYPE = SHCollider::Type::BOX; static constexpr auto TYPE = SHCollisionShape::Type::BOX;
auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE }); auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE });
collider.entityID = GetEID(); collider.entityID = GetEID();
collider.SetPositionOffset(posOffset); collider.SetPositionOffset(posOffset);
collider.SetRotationOffset(rotOffset);
collider.SetBoundingBox(halfExtents); collider.SetBoundingBox(halfExtents);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); system->AddCollisionShape(GetEID(), &collider);
return reinterpret_cast<SHBoundingBox*>(collider.GetShape()); return static_cast<int>(collisionShapes.size()) - 1;
} }
SHBoundingSphere* SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept
{ {
if (!system) if (!system)
{ {
SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!") SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
return nullptr; return -1;
} }
static constexpr auto TYPE = SHCollider::Type::SPHERE; static constexpr auto TYPE = SHCollisionShape::Type::SPHERE;
auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE }); auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE });
collider.entityID = GetEID(); collider.entityID = GetEID();
collider.SetPositionOffset(posOffset); collider.SetPositionOffset(posOffset);
@ -116,17 +156,17 @@ namespace SHADE
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); system->AddCollisionShape(GetEID(), &collider);
return reinterpret_cast<SHBoundingSphere*>(collider.GetShape()); return static_cast<int>(collisionShapes.size()) - 1;
} }
void SHColliderComponent::RemoveCollider(int index) void SHColliderComponent::RemoveCollider(int index)
{ {
if (index < 0 || static_cast<size_t>(index) >= colliders.size()) if (index < 0 || static_cast<size_t>(index) >= collisionShapes.size())
throw std::invalid_argument("Out-of-range access!"); throw std::invalid_argument("Out-of-range access!");
int idx = 0; int idx = 0;
auto it = colliders.begin(); auto it = collisionShapes.begin();
for (; it != colliders.end(); ++it) for (; it != collisionShapes.end(); ++it)
{ {
if (idx == index) if (idx == index)
break; break;
@ -134,7 +174,7 @@ namespace SHADE
++idx; ++idx;
} }
it = colliders.erase(it); it = collisionShapes.erase(it);
// Notify Physics System // Notify Physics System
if (!system) if (!system)

View File

@ -14,7 +14,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Physics/SHCollider.h" #include "Physics/SHCollisionShape.h"
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
@ -43,7 +43,7 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
using Colliders = std::vector<SHCollider>; using CollisionShapes = std::vector<SHCollisionShape>;
public: public:
@ -72,9 +72,10 @@ namespace SHADE
[[nodiscard]] const SHVec3& GetPosition () const noexcept; [[nodiscard]] const SHVec3& GetPosition () const noexcept;
[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept; [[nodiscard]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] const SHVec3& GetScale () const noexcept;
[[nodiscard]] const Colliders& GetColliders () const noexcept; [[nodiscard]] const CollisionShapes& GetCollisionShapes() const noexcept;
[[nodiscard]] SHCollider& GetCollider (int index); [[nodiscard]] SHCollisionShape& GetCollisionShape (int index);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -83,10 +84,12 @@ namespace SHADE
void OnCreate () override; void OnCreate () override;
void OnDestroy () override; void OnDestroy () override;
void RecomputeCollisionShapes () noexcept;
void RemoveCollider (int index); void RemoveCollider (int index);
SHBoundingBox* AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero) noexcept; int AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero) noexcept;
SHBoundingSphere* AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept; int AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept;
private: private:
@ -98,7 +101,8 @@ namespace SHADE
SHVec3 position; SHVec3 position;
SHQuaternion orientation; SHQuaternion orientation;
Colliders colliders; SHVec3 scale;
CollisionShapes collisionShapes;
RTTR_ENABLE() RTTR_ENABLE()
}; };

View File

@ -11,12 +11,12 @@
#include <SHpch.h> #include <SHpch.h>
// Primary Header // Primary Header
#include "SHCollider.h" #include "SHCollisionShape.h"
// Project Headers // Project Headers
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
namespace SHADE namespace SHADE
@ -25,7 +25,7 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHCollider::SHCollider(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial) SHCollisionShape::SHCollisionShape(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial)
: type { colliderType } : type { colliderType }
, entityID { eid } , entityID { eid }
, isTrigger { false } , isTrigger { false }
@ -49,7 +49,7 @@ namespace SHADE
} }
} }
SHCollider::SHCollider(const SHCollider& rhs) noexcept SHCollisionShape::SHCollisionShape(const SHCollisionShape& rhs) noexcept
: type { rhs.type} : type { rhs.type}
, entityID { rhs.entityID } , entityID { rhs.entityID }
, isTrigger { rhs.isTrigger } , isTrigger { rhs.isTrigger }
@ -61,7 +61,7 @@ namespace SHADE
CopyShape(rhs.shape); CopyShape(rhs.shape);
} }
SHCollider::SHCollider(SHCollider&& rhs) noexcept SHCollisionShape::SHCollisionShape(SHCollisionShape&& rhs) noexcept
: type { rhs.type} : type { rhs.type}
, entityID { rhs.entityID } , entityID { rhs.entityID }
, isTrigger { rhs.isTrigger } , isTrigger { rhs.isTrigger }
@ -73,7 +73,7 @@ namespace SHADE
CopyShape(rhs.shape); CopyShape(rhs.shape);
} }
SHCollider::~SHCollider() noexcept SHCollisionShape::~SHCollisionShape() noexcept
{ {
shape = nullptr; shape = nullptr;
} }
@ -82,7 +82,7 @@ namespace SHADE
/* Operator Overload Definitions */ /* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHCollider& SHCollider::operator=(const SHCollider& rhs) noexcept SHCollisionShape& SHCollisionShape::operator=(const SHCollisionShape& rhs) noexcept
{ {
if (this == &rhs) if (this == &rhs)
return *this; return *this;
@ -100,7 +100,7 @@ namespace SHADE
return *this; return *this;
} }
SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept SHCollisionShape& SHCollisionShape::operator=(SHCollisionShape&& rhs) noexcept
{ {
type = rhs.type; type = rhs.type;
entityID = rhs.entityID; entityID = rhs.entityID;
@ -119,52 +119,52 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHCollider::HasChanged() const noexcept bool SHCollisionShape::HasChanged() const noexcept
{ {
return dirty; return dirty;
} }
bool SHCollider::IsTrigger() const noexcept bool SHCollisionShape::IsTrigger() const noexcept
{ {
return isTrigger; return isTrigger;
} }
SHCollider::Type SHCollider::GetType() const noexcept SHCollisionShape::Type SHCollisionShape::GetType() const noexcept
{ {
return type; return type;
} }
float SHCollider::GetFriction() const noexcept float SHCollisionShape::GetFriction() const noexcept
{ {
return material.GetFriction(); return material.GetFriction();
} }
float SHCollider::GetBounciness() const noexcept float SHCollisionShape::GetBounciness() const noexcept
{ {
return material.GetBounciness(); return material.GetBounciness();
} }
float SHCollider::GetDensity() const noexcept float SHCollisionShape::GetDensity() const noexcept
{ {
return material.GetDensity(); return material.GetDensity();
} }
const SHPhysicsMaterial& SHCollider::GetMaterial() const noexcept const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept
{ {
return material; return material;
} }
const SHVec3& SHCollider::GetPositionOffset() const noexcept const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept
{ {
return positionOffset; return positionOffset;
} }
const SHVec3& SHCollider::GetRotationOffset() const noexcept const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept
{ {
return rotationOffset; return rotationOffset;
} }
SHShape* SHCollider::GetShape() noexcept SHShape* SHCollisionShape::GetShape() noexcept
{ {
dirty = true; dirty = true;
return shape; return shape;
@ -174,93 +174,80 @@ namespace SHADE
/* Setter Function Definitions */ /* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHCollider::SetBoundingBox(const SHVec3& halfExtents) void SHCollisionShape::SetBoundingBox(const SHVec3& halfExtents)
{ {
dirty = true; dirty = true;
// Set the half extents relative to transform const auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
SHVec3 worldHalfExtents = halfExtents; // Set the half extents relative to world scale
const SHVec3 WORLD_EXTENTS = halfExtents * colliderComponent->GetScale() * 0.5f;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID); if (type != Type::BOX)
if (transformComponent != nullptr)
worldHalfExtents *= (transformComponent->GetWorldScale() * 0.5f);
if (type == Type::BOX)
{
auto* box = reinterpret_cast<SHBoundingBox*>(shape);
box->SetHalfExtents(worldHalfExtents);
}
else
{ {
type = Type::BOX; type = Type::BOX;
delete shape; delete shape;
shape = new SHBoundingBox{ positionOffset, worldHalfExtents }; shape = new SHBoundingBox{ positionOffset, WORLD_EXTENTS };
}
} }
void SHCollider::SetBoundingSphere(float radius) auto* box = reinterpret_cast<SHBoundingBox*>(shape);
box->SetWorldExtents(WORLD_EXTENTS);
box->SetRelativeExtents(halfExtents);
}
void SHCollisionShape::SetBoundingSphere(float radius)
{ {
dirty = true; dirty = true;
// Set the radius relative to transform const auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
float worldRadius = radius; // Set the radius relative to world scale
const SHVec3 WORLD_SCALE = colliderComponent->GetScale();
const float MAX_SCALE = SHMath::Max({ WORLD_SCALE.x, WORLD_SCALE.y, WORLD_SCALE.z });
const float WORLD_RADIUS = radius * MAX_SCALE * 0.5f;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID); if (type != Type::SPHERE)
if (transformComponent != nullptr)
{
const SHVec3 TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
worldRadius *= MAX_SCALE * 0.5f;
}
if (type == Type::SPHERE)
{
auto* sphere = reinterpret_cast<SHBoundingSphere*>(shape);
sphere->SetRadius(worldRadius);
}
else
{ {
type = Type::SPHERE; type = Type::SPHERE;
delete shape; delete shape;
shape = new SHBoundingSphere{ positionOffset, worldRadius }; shape = new SHBoundingSphere{ positionOffset, WORLD_RADIUS };
} }
auto* sphere = reinterpret_cast<SHBoundingSphere*>(shape);
sphere->SetWorldRadius(WORLD_RADIUS);
} }
void SHCollider::SetIsTrigger(bool trigger) noexcept void SHCollisionShape::SetIsTrigger(bool trigger) noexcept
{ {
dirty = true; dirty = true;
isTrigger = trigger; isTrigger = trigger;
} }
void SHCollider::SetFriction(float friction) noexcept void SHCollisionShape::SetFriction(float friction) noexcept
{ {
dirty = true; dirty = true;
material.SetFriction(friction); material.SetFriction(friction);
} }
void SHCollider::SetBounciness(float bounciness) noexcept void SHCollisionShape::SetBounciness(float bounciness) noexcept
{ {
dirty = true; dirty = true;
material.SetBounciness(bounciness); material.SetBounciness(bounciness);
} }
void SHCollider::SetDensity(float density) noexcept void SHCollisionShape::SetDensity(float density) noexcept
{ {
dirty = true; dirty = true;
material.SetDensity(density); material.SetDensity(density);
} }
void SHCollider::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept
{ {
dirty = true; dirty = true;
material = newMaterial; material = newMaterial;
} }
void SHCollider::SetPositionOffset(const SHVec3& posOffset) noexcept void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept
{ {
dirty = true; dirty = true;
positionOffset = posOffset; positionOffset = posOffset;
@ -281,7 +268,7 @@ namespace SHADE
} }
} }
void SHCollider::SetRotationOffset(const SHVec3& rotOffset) noexcept void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept
{ {
dirty = true; dirty = true;
rotationOffset = rotOffset; rotationOffset = rotOffset;
@ -291,7 +278,7 @@ namespace SHADE
/* Private Function Member Definitions */ /* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHCollider::CopyShape(const SHShape* rhs) void SHCollisionShape::CopyShape(const SHShape* rhs)
{ {
switch (type) switch (type)
{ {
@ -299,14 +286,14 @@ namespace SHADE
{ {
const auto* RHS_BOX = reinterpret_cast<const SHBoundingBox*>(rhs); const auto* RHS_BOX = reinterpret_cast<const SHBoundingBox*>(rhs);
shape = new SHBoundingBox{ positionOffset, RHS_BOX->GetHalfExtents() }; shape = new SHBoundingBox{ positionOffset, RHS_BOX->GetWorldExtents() };
break; break;
} }
case Type::SPHERE: case Type::SPHERE:
{ {
const auto* RHS_SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs); const auto* RHS_SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs);
shape = new SHBoundingSphere{ positionOffset, RHS_SPHERE->GetRadius() }; shape = new SHBoundingSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() };
break; break;
} }
default: break; default: break;
@ -320,14 +307,14 @@ RTTR_REGISTRATION
using namespace SHADE; using namespace SHADE;
using namespace rttr; using namespace rttr;
registration::enumeration<SHCollider::Type>("Collider Type") registration::enumeration<SHCollisionShape::Type>("Collider Type")
( (
value("Box", SHCollider::Type::BOX), value("Box", SHCollisionShape::Type::BOX),
value("Sphere", SHCollider::Type::SPHERE) value("Sphere", SHCollisionShape::Type::SPHERE)
// TODO(Diren): Add More Shapes // TODO(Diren): Add More Shapes
); );
registration::class_<SHCollider>("Collider") registration::class_<SHCollisionShape>("Collider")
.property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset) .property("Position Offset", &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset)
.property("Rotation Offset", &SHCollider::GetRotationOffset, &SHCollider::SetRotationOffset) (metadata(META::angleInRad, true)); .property("Rotation Offset", &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true));
} }

View File

@ -24,7 +24,7 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SH_API SHCollider class SH_API SHCollisionShape
{ {
private: private:
@ -51,18 +51,18 @@ namespace SHADE
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHCollider (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT); SHCollisionShape (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT);
SHCollider (const SHCollider& rhs) noexcept; SHCollisionShape (const SHCollisionShape& rhs) noexcept;
SHCollider (SHCollider&& rhs) noexcept; SHCollisionShape (SHCollisionShape&& rhs) noexcept;
~SHCollider () noexcept; ~SHCollisionShape () noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Operator Overloads */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHCollider& operator=(const SHCollider& rhs) noexcept; SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept;
SHCollider& operator=(SHCollider&& rhs) noexcept; SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */

View File

@ -128,24 +128,24 @@ namespace SHADE
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
int SHPhysicsObject::AddCollider(SHCollider* collider) int SHPhysicsObject::AddCollider(SHCollisionShape* collider)
{ {
const rp3d::Transform OFFSETS{ collider->GetPositionOffset(), collider->GetRotationOffset() }; const rp3d::Transform OFFSETS{ collider->GetPositionOffset(), collider->GetRotationOffset() };
switch (collider->GetType()) switch (collider->GetType())
{ {
case SHCollider::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
const auto* box = reinterpret_cast<SHBoundingBox*>(collider->GetShape()); const auto* box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(box->GetHalfExtents()); rp3d::BoxShape* newBox = factory->createBoxShape(box->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS); rp3dBody->addCollider(newBox, OFFSETS);
break; break;
} }
case SHCollider::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape()); const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(sphere->GetRadius()); rp3d::SphereShape* newSphere = factory->createSphereShape(sphere->GetWorldRadius());
rp3dBody->addCollider(newSphere, OFFSETS); rp3dBody->addCollider(newSphere, OFFSETS);
break; break;
@ -173,7 +173,7 @@ namespace SHADE
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept
{ {
int index = 0; int index = 0;
for (auto& collider : c->colliders) for (auto& collider : c->collisionShapes)
{ {
if (!collider.dirty) if (!collider.dirty)
continue; continue;
@ -188,21 +188,21 @@ namespace SHADE
switch (collider.GetType()) switch (collider.GetType())
{ {
case SHCollider::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
const auto* box = reinterpret_cast<SHBoundingBox*>(collider.GetShape()); const auto* box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
auto* rp3dBoxShape = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape()); auto* rp3dBoxShape = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape());
rp3dBoxShape->setHalfExtents(box->GetHalfExtents()); rp3dBoxShape->setHalfExtents(box->GetWorldExtents());
break; break;
} }
case SHCollider::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape()); const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape());
auto* rp3dSphereShape = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape()); auto* rp3dSphereShape = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
rp3dSphereShape->setRadius(sphere->GetRadius()); rp3dSphereShape->setRadius(sphere->GetWorldRadius());
break; break;
} }

View File

@ -69,7 +69,7 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
int AddCollider (SHCollider* collider); int AddCollider (SHCollisionShape* collider);
void RemoveCollider (int index); void RemoveCollider (int index);
void SyncColliders (SHColliderComponent* c) const noexcept; void SyncColliders (SHColliderComponent* c) const noexcept;

View File

@ -348,7 +348,7 @@ namespace SHADE
factory.destroyPhysicsWorld(world); factory.destroyPhysicsWorld(world);
} }
void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollider* collider) void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollisionShape* collider)
{ {
auto* physicsObject = GetPhysicsObject(entityID); auto* physicsObject = GetPhysicsObject(entityID);
@ -395,6 +395,7 @@ namespace SHADE
{ {
const auto WORLD_POS = transformComponent->GetWorldPosition(); const auto WORLD_POS = transformComponent->GetWorldPosition();
const auto WORLD_ROT = transformComponent->GetWorldOrientation(); const auto WORLD_ROT = transformComponent->GetWorldOrientation();
const auto WORLD_SCL = transformComponent->GetWorldScale();
physicsObject.SetPosition(WORLD_POS); physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT); physicsObject.SetOrientation(WORLD_ROT);
@ -411,6 +412,9 @@ namespace SHADE
{ {
colliderComponent->position = WORLD_POS; colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT; colliderComponent->orientation = WORLD_ROT;
colliderComponent->scale = WORLD_SCL;
colliderComponent->RecomputeCollisionShapes();
} }
} }
@ -605,7 +609,6 @@ namespace SHADE
if (rigidBodyComponent != nullptr) if (rigidBodyComponent != nullptr)
{ {
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC) if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
continue; continue;
@ -658,8 +661,10 @@ namespace SHADE
{ {
const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionEvent& e) const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionEvent& e)
{ {
const bool ENTITY_MATCH = e.value[0] == collisionEvent.value[0]; const bool ENTITY_MATCH = (e.ids[0] == collisionEvent.ids[0] && e.ids[1] == collisionEvent.ids[1])
const bool COLLIDERS_MATCH = e.value[1] == collisionEvent.value[1]; || (e.ids[0] == collisionEvent.ids[1] && e.ids[1] == collisionEvent.ids[0]);
const bool COLLIDERS_MATCH = (e.ids[2] == collisionEvent.ids[2] && e.ids[3] == collisionEvent.ids[3])
|| (e.ids[2] == collisionEvent.ids[3] && e.ids[3] == collisionEvent.ids[2]);
return ENTITY_MATCH && COLLIDERS_MATCH; return ENTITY_MATCH && COLLIDERS_MATCH;
}); });
@ -734,7 +739,7 @@ namespace SHADE
// Add collision shapes back into the body // Add collision shapes back into the body
if (colliderComponent != nullptr) if (colliderComponent != nullptr)
{ {
for (auto& collider : colliderComponent->colliders) for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider); physicsObject->AddCollider(&collider);
} }
} }
@ -745,6 +750,7 @@ namespace SHADE
colliderComponent->position = transformComponent->GetWorldPosition(); colliderComponent->position = transformComponent->GetWorldPosition();
colliderComponent->orientation = transformComponent->GetWorldOrientation(); colliderComponent->orientation = transformComponent->GetWorldOrientation();
colliderComponent->scale = transformComponent->GetWorldScale();
if (physicsObject->rp3dBody == nullptr) if (physicsObject->rp3dBody == nullptr)
{ {
@ -755,7 +761,7 @@ namespace SHADE
} }
// Add Collision Shapes // Add Collision Shapes
for (auto& collider : colliderComponent->colliders) for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider); physicsObject->AddCollider(&collider);
} }
} }
@ -800,7 +806,7 @@ namespace SHADE
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation } rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
); );
for (auto& collider : colliderComponent->colliders) for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider); physicsObject->AddCollider(&collider);
} }
} }

View File

@ -114,7 +114,7 @@ namespace SHADE
void Init () override; void Init () override;
void Exit () override; void Exit () override;
void AddCollisionShape (EntityID entityID, SHCollider* collider); void AddCollisionShape (EntityID entityID, SHCollisionShape* collider);
void RemoveCollisionShape (EntityID entityID, int index); void RemoveCollisionShape (EntityID entityID, int index);
void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override; void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override;

View File

@ -75,14 +75,14 @@ namespace SHADE
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]); return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]);
} }
const SHCollider* SHCollisionEvent::GetColliderA() const noexcept const SHCollisionShape* SHCollisionEvent::GetColliderA() const noexcept
{ {
return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A])->GetCollider(ids[COLLIDER_A]); return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]);
} }
const SHCollider* SHCollisionEvent::GetColliderB() const noexcept const SHCollisionShape* SHCollisionEvent::GetColliderB() const noexcept
{ {
return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B])->GetCollider(ids[COLLIDER_B]); return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]);
} }
SHCollisionEvent::State SHCollisionEvent::GetCollisionState() const noexcept SHCollisionEvent::State SHCollisionEvent::GetCollisionState() const noexcept

View File

@ -24,7 +24,7 @@ namespace SHADE
struct SHPhysicsColliderAddedEvent struct SHPhysicsColliderAddedEvent
{ {
EntityID entityID; EntityID entityID;
SHCollider::Type colliderType; SHCollisionShape::Type colliderType;
int colliderIndex; int colliderIndex;
}; };
@ -88,8 +88,8 @@ namespace SHADE
[[nodiscard]] EntityID GetEntityB () const noexcept; [[nodiscard]] EntityID GetEntityB () const noexcept;
[[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept; [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept;
[[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept; [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept;
[[nodiscard]] const SHCollider* GetColliderA () const noexcept; [[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept;
[[nodiscard]] const SHCollider* GetColliderB () const noexcept; [[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept;
[[nodiscard]] State GetCollisionState () const noexcept; [[nodiscard]] State GetCollisionState () const noexcept;
private: private:

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHSceneGraph.cpp * \file SHSceneGraph.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Scene Graph & Scene Nodes. * \brief Implementation for a Scene Graph.
* *
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent * disclosure of this file or its contents without the prior written consent
@ -16,8 +16,6 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Events/SHEventManager.hpp" #include "Events/SHEventManager.hpp"
#include "Tools/SHLogger.h"
#include "Tools/SHException.h"
namespace SHADE namespace SHADE
{ {
@ -25,56 +23,6 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHSceneNode::SHSceneNode(EntityID eid, SHSceneNode* parent) noexcept
: active { true }
, entityID { eid }
, parent { parent }
{}
SHSceneNode::SHSceneNode(const SHSceneNode& rhs) noexcept
: active { rhs.active }
, entityID { rhs.entityID }
, parent { rhs.parent }
{
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
}
SHSceneNode::SHSceneNode(SHSceneNode&& rhs) noexcept
: active { rhs.active }
, entityID { rhs.entityID }
, parent { rhs.parent }
{
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
}
SHSceneNode& SHSceneNode::operator=(const SHSceneNode& rhs) noexcept
{
if (this == &rhs)
return *this;
active = rhs.active;
entityID = rhs.entityID;
parent = rhs.parent;
children.clear();
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
return *this;
}
SHSceneNode& SHSceneNode::operator=(SHSceneNode&& rhs) noexcept
{
active = rhs.active;
entityID = rhs.entityID;
parent = rhs.parent;
children.clear();
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
return *this;
}
SHSceneGraph::SHSceneGraph() noexcept SHSceneGraph::SHSceneGraph() noexcept
: root { nullptr } : root { nullptr }
{ {
@ -110,56 +58,6 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHSceneNode::IsActive() const noexcept
{
return active;
}
EntityID SHSceneNode::GetEntityID() const noexcept
{
return entityID;
}
SHSceneNode* SHSceneNode::GetParent() const noexcept
{
return parent;
}
const std::vector<SHSceneNode*>& SHSceneNode::GetChildren() const noexcept
{
return children;
}
SHSceneNode* SHSceneNode::GetChild(EntityID childID) const noexcept
{
////////////////////////////////////////
// Error handling
if (!SHEntityManager::IsValidEID(childID))
{
SHLOG_ERROR("Child Entity {} is invalid! Unable to get child from Entity {}", childID, entityID)
return nullptr;
}
if (children.empty())
{
SHLOG_WARNING("Entity {} has no children!", entityID)
return nullptr;
}
////////////////////////////////////////
// Find child
const auto ENTITY_MATCH = [&](const SHSceneNode* node) { return node->GetEntityID() == childID; };
const auto CHILD_ITER = std::ranges::find_if(children.begin(), children.end(),ENTITY_MATCH);
if (CHILD_ITER == children.end())
{
SHLOG_WARNING("Entity {} is not a child of Entity {}! Unable to retrieve child node!", childID, entityID)
return nullptr;
}
return *CHILD_ITER;
}
const SHSceneNode* SHSceneGraph::GetRoot() const noexcept const SHSceneNode* SHSceneGraph::GetRoot() const noexcept
{ {
if (root != nullptr) if (root != nullptr)
@ -313,41 +211,7 @@ namespace SHADE
/* Setter Function Definitions */ /* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHSceneNode::SetParent(SHSceneNode* parentNode) noexcept void SHSceneGraph::SetParent(EntityID entityID, SHSceneNode* newParent) noexcept
{
if (parentNode == nullptr)
{
SHLOG_WARNING("Removing Entity {}'s parent", entityID)
if (parent)
parent->RemoveChild(this);
return;
}
// Handle self assignment
if (parent && parentNode->entityID == parent->entityID)
return;
if (parent)
parent->RemoveChild(this);
parent = parentNode;
// Update parent's children
parent->AddChild(this);
}
void SHSceneNode::SetActive(bool newActiveState) noexcept
{
active = newActiveState;
for (auto* child : children)
{
SetActive(newActiveState);
}
}
void SHSceneGraph::SetParent(EntityID entityID, SHSceneNode* parent) const noexcept
{ {
//////////////////////////////////////// ////////////////////////////////////////
// Error Handling // Error Handling
@ -369,30 +233,31 @@ namespace SHADE
{ {
.node = NODE_ITER->second .node = NODE_ITER->second
, .oldParent = NODE_ITER->second->GetParent() , .oldParent = NODE_ITER->second->GetParent()
, .newParent = parent ? parent : root , .newParent = newParent ? newParent : root
}; };
if (parent == nullptr) if (newParent == nullptr)
parent = root; newParent = root;
NODE_ITER->second->SetParent(parent); ChangeParent(NODE_ITER->second, newParent);
SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT); SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
} }
void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept void SHSceneGraph::SetParent(EntityID entityID, EntityID newParent) noexcept
{ {
//////////////////////////////////////// ////////////////////////////////////////
// Error Handling // Error Handling
if (!SHEntityManager::IsValidEID(entityID)) if (!SHEntityManager::IsValidEID(entityID))
{ {
SHLOG_ERROR("Entity {} is invalid! Unable to set parent of an invalid entity!", entityID) SHLOG_ERROR("Entity {} is invalid! Unable to set parent of an invalid entity!", entityID)
return; return;
} }
if (!SHEntityManager::IsValidEID(parent)) if (!SHEntityManager::IsValidEID(newParent))
{ {
SHLOG_ERROR("Parent Entity {} is invalid! Unable to set Entity {}'s parent!", parent, entityID) SHLOG_ERROR("Parent Entity {} is invalid! Unable to set Entity {}'s parent!", newParent, entityID)
return; return;
} }
@ -403,10 +268,10 @@ namespace SHADE
return; return;
} }
auto PARENT_ITER = entityNodeMap.find(parent); auto PARENT_ITER = entityNodeMap.find(newParent);
if (PARENT_ITER == entityNodeMap.end()) if (PARENT_ITER == entityNodeMap.end())
{ {
SHLOG_ERROR("Entity {} cannot be found in the scene! Unable to parent to Entity {}", parent, entityID) SHLOG_ERROR("Entity {} cannot be found in the scene! Unable to parent to Entity {}", newParent, entityID)
return; return;
} }
//////////////////////////////////////// ////////////////////////////////////////
@ -419,7 +284,7 @@ namespace SHADE
}; };
SHSceneNode* currentNode = NODE_ITER->second; SHSceneNode* currentNode = NODE_ITER->second;
currentNode->SetParent(PARENT_ITER->second); ChangeParent(currentNode, PARENT_ITER->second);
SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT); SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
} }
@ -428,84 +293,6 @@ namespace SHADE
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHSceneNode::AddChild(SHSceneNode* newChild) noexcept
{
////////////////////////////////////////
// Error Handling
if (newChild == nullptr)
{
SHLOG_WARNING("Attempting to add a non-existent child to an entity!")
return;
}
////////////////////////////////////////
if (newChild->parent)
newChild->parent->RemoveChild(newChild);
newChild->parent = this;
children.emplace_back(newChild);
}
bool SHSceneNode::RemoveChild(EntityID childID) noexcept
{
////////////////////////////////////////
// Error Handling
if (!SHEntityManager::IsValidEID(childID))
{
SHLOG_ERROR("Entity {} is invalid!", childID)
return false;
}
////////////////////////////////////////
auto childIter = std::find_if(children.begin(), children.end(), [&](SHSceneNode* node)
{
return node->GetEntityID() == childID;
});
if (childIter == children.end())
{
SHLOG_WARNING("Unable to remove Entity {} from Entity {} since it is not it's child!", childID, entityID)
return false;
}
(*childIter)->parent = nullptr;
childIter = children.erase(childIter);
return true;
}
bool SHSceneNode::RemoveChild(SHSceneNode* childToRemove) noexcept
{
////////////////////////////////////////
// Error Handling
if (childToRemove == nullptr)
{
SHLOG_WARNING("Attempting to remove non-existent child from Entity {}", entityID)
return false;
}
////////////////////////////////////////
auto childIter = std::find(children.begin(), children.end(), childToRemove);
if (childIter == children.end())
{
SHLOG_WARNING("Unable to remove Entity {} from Entity {} since it is not it's child!", childToRemove->entityID, entityID)
return false;
}
childIter = children.erase(childIter);
childToRemove->parent = nullptr;
return true;
}
void SHSceneNode::RemoveAllChildren() noexcept
{
for (const auto child : children)
child->parent = nullptr;
children.clear();
}
SHSceneNode* SHSceneGraph::AddNode(EntityID entityID, SHSceneNode* parent) SHSceneNode* SHSceneGraph::AddNode(EntityID entityID, SHSceneNode* parent)
{ {
//////////////////////////////////////// ////////////////////////////////////////
@ -528,13 +315,12 @@ namespace SHADE
if (parent == nullptr) if (parent == nullptr)
{ {
// Specific handling for root to avoid a warning when removing a non-existent child // Specific handling for root to avoid a warning when removing a non-existent child
parent = root;
newNode->parent = root; newNode->parent = root;
root->children.emplace_back(newNode); root->children.emplace_back(newNode);
} }
else else
{ {
newNode->SetParent(parent); ChangeParent(newNode, parent);
} }
return newNode; return newNode;
@ -542,6 +328,8 @@ namespace SHADE
bool SHSceneGraph::RemoveNode(EntityID entityID) noexcept bool SHSceneGraph::RemoveNode(EntityID entityID) noexcept
{ {
////////////////////////////////////////
// Error Handling
if (!SHEntityManager::IsValidEID(entityID)) if (!SHEntityManager::IsValidEID(entityID))
{ {
SHLOG_ERROR("Entity {} is invalid!", entityID) SHLOG_ERROR("Entity {} is invalid!", entityID)
@ -554,12 +342,12 @@ namespace SHADE
SHLOG_ERROR("Entity {} does not exist in the scene!", entityID) SHLOG_ERROR("Entity {} does not exist in the scene!", entityID)
return false; return false;
} }
////////////////////////////////////////
// Remove reference of current node from parent // Remove reference of current node from parent
SHSceneNode* currentNode = NODE_ITER->second; SHSceneNode* currentNode = NODE_ITER->second;
SHSceneNode* parent = currentNode->GetParent(); if (currentNode->parent != nullptr)
if (parent != nullptr) RemoveChild(currentNode->parent, currentNode);
parent->RemoveChild(currentNode);
ReleaseNode(currentNode); ReleaseNode(currentNode);
return true; return true;
@ -568,9 +356,8 @@ namespace SHADE
bool SHSceneGraph::RemoveNode(SHSceneNode* nodeToRemove) noexcept bool SHSceneGraph::RemoveNode(SHSceneNode* nodeToRemove) noexcept
{ {
// Remove reference of current node from parent // Remove reference of current node from parent
SHSceneNode* parent = nodeToRemove->GetParent(); if (nodeToRemove->parent != nullptr)
if (parent != nullptr) RemoveChild(nodeToRemove->parent, nodeToRemove);
parent->RemoveChild(nodeToRemove);
ReleaseNode(nodeToRemove); ReleaseNode(nodeToRemove);
return true; return true;
@ -582,6 +369,91 @@ namespace SHADE
ReleaseNode(node); ReleaseNode(node);
} }
bool SHSceneGraph::IsChildOf(EntityID entityID, SHSceneNode* targetNode) noexcept
{
////////////////////////////////////////
// Error Handling
if (!SHEntityManager::IsValidEID(entityID))
{
SHLOG_ERROR("Entity {} is invalid!", entityID)
return false;
}
auto NODE_ITER = entityNodeMap.find(entityID);
if (NODE_ITER == entityNodeMap.end())
{
SHLOG_ERROR("Entity {} cannot be found in the scene! Unable to check child!", entityID)
return false;
}
////////////////////////////////////////
// Handle self-checks
if (NODE_ITER->second == targetNode)
{
SHLOG_WARNING("Entity {} cannot be a child of itself!", entityID)
return false;
}
// Search for a matching target until the root
const SHSceneNode* CURRENT_TARGET = NODE_ITER->second->parent;
while (CURRENT_TARGET != root)
{
if (CURRENT_TARGET == targetNode)
return true;
CURRENT_TARGET = CURRENT_TARGET->parent;
}
return false;
}
bool SHSceneGraph::IsChildOf(EntityID entityID, EntityID targetID) noexcept
{
////////////////////////////////////////
// Error Handling
if (!SHEntityManager::IsValidEID(entityID))
{
SHLOG_ERROR("Entity {} is invalid!", entityID)
return false;
}
if (!SHEntityManager::IsValidEID(targetID))
{
SHLOG_ERROR("Entity {} is invalid!", targetID)
return false;
}
auto NODE_ITER = entityNodeMap.find(entityID);
if (NODE_ITER == entityNodeMap.end())
{
SHLOG_ERROR("Entity {} cannot be found in the scene! Unable to check child!", entityID)
return false;
}
auto TARGET_ITER = entityNodeMap.find(targetID);
if (TARGET_ITER == entityNodeMap.end())
{
SHLOG_ERROR("Entity {} cannot be found in the scene! Unable to check child!", targetID)
return false;
}
////////////////////////////////////////
const SHSceneNode* CURRENT_TARGET = NODE_ITER->second->parent;
while (CURRENT_TARGET != root)
{
if (CURRENT_TARGET == TARGET_ITER->second)
return true;
CURRENT_TARGET = CURRENT_TARGET->parent;
}
return false;
}
void SHSceneGraph::Traverse (const UnaryFunction& function) const void SHSceneGraph::Traverse (const UnaryFunction& function) const
{ {
TraverseAndInvokeFunction(root, function); TraverseAndInvokeFunction(root, function);
@ -594,11 +466,6 @@ namespace SHADE
SHSceneNode* SHSceneGraph::AllocateNode(EntityID entityID) SHSceneNode* SHSceneGraph::AllocateNode(EntityID entityID)
{ {
SHSceneNode* newNode = new SHSceneNode{entityID}; SHSceneNode* newNode = new SHSceneNode{entityID};
//#ifdef _DEBUG
// SHLOG_INFO("Allocated a new Scene Node for Entity {}!", entityID)
//#endif
entityNodeMap.emplace(entityID, newNode); entityNodeMap.emplace(entityID, newNode);
return newNode; return newNode;
} }
@ -608,19 +475,81 @@ namespace SHADE
SHASSERT(node != nullptr, "Attempting to release Invalid Node!") SHASSERT(node != nullptr, "Attempting to release Invalid Node!")
// Remove parent's reference to this node if there is a parent // Remove parent's reference to this node if there is a parent
if (node->GetParent() != nullptr) if (node->parent != nullptr)
node->GetParent()->RemoveChild(node); RemoveChild(node->parent, node);
// Remove child's references to this node. Children end up as floating nodes. // Remove child's references to this node. Children end up as floating nodes.
for (auto* child : node->GetChildren()) for (auto* child : node->GetChildren())
{ {
child->SetParent(nullptr); ChangeParent(child, nullptr);
} }
entityNodeMap.erase(node->GetEntityID()); entityNodeMap.erase(node->GetEntityID());
delete node; delete node;
} }
void SHSceneGraph::ChangeParent(SHSceneNode* node, SHSceneNode* newParent)
{
// Handle self assignment
if (node->parent != nullptr && newParent != nullptr && node->parent->entityID == newParent->entityID)
return;
// Remove child
if (node->parent)
RemoveChild(node->parent, node);
if (newParent == nullptr)
{
SHLOG_WARNING("Removing Entity {}'s parent", node->entityID)
return;
}
node->parent = newParent;
// Update parent's children
AddChild(newParent, node);
}
void SHSceneGraph::AddChild(SHSceneNode* node, SHSceneNode* newChild)
{
SHASSERT(node != nullptr, "Attempting to modify a non-existent scene node!")
SHASSERT(newChild != nullptr, "Attempting to add a non-existent child to a SceneNode!")
if (newChild->parent)
RemoveChild(newChild->parent, newChild);
newChild->parent = node;
node->children.emplace_back(newChild);
const SHSceneGraphAddChildEvent EVENT_DATA
{
.parent = node
, .childAdded = newChild
};
SHEventManager::BroadcastEvent<SHSceneGraphAddChildEvent>(EVENT_DATA, SH_SCENEGRAPH_ADD_CHILD_EVENT);
}
void SHSceneGraph::RemoveChild(SHSceneNode* node, SHSceneNode* childToRemove)
{
SHASSERT(node != nullptr, "Attempting to modify a non-existent scene node!")
SHASSERT(childToRemove != nullptr, "Attempting to remove a non-existent child from a SceneNode!")
auto childIter = std::find(node->children.begin(), node->children.end(), childToRemove);
if (childIter == node->children.end())
return;
childIter = node->children.erase(childIter);
childToRemove->parent = nullptr;
const SHSceneGraphRemoveChildEvent EVENT_DATA
{
.parent = node
, .childRemoved = childToRemove
};
SHEventManager::BroadcastEvent<SHSceneGraphRemoveChildEvent>(EVENT_DATA, SH_SCENEGRAPH_REMOVE_CHILD_EVENT);
}
void SHSceneGraph::TraverseAndInvokeFunction(const SHSceneNode* node, const UnaryFunction& function) void SHSceneGraph::TraverseAndInvokeFunction(const SHSceneNode* node, const UnaryFunction& function)
{ {
for (auto* child : node->children) for (auto* child : node->children)

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHSceneGraph.h * \file SHSceneGraph.h
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Scene Graph & Scene Nodes. * \brief Interface for a Scene Graph.
* *
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent * disclosure of this file or its contents without the prior written consent
@ -15,81 +15,15 @@
// Project Headers // Project Headers
#include "ECS_Base/Entity/SHEntity.h" #include "ECS_Base/Entity/SHEntity.h"
#include "SH_API.h" #include "SH_API.h"
#include "SHSceneNode.h"
#include "SHSceneGraphEvents.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHSceneGraph;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SH_API SHSceneNode
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHSceneGraph;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
~SHSceneNode () = default;
SHSceneNode (EntityID eid, SHSceneNode* parent = nullptr) noexcept;
SHSceneNode (const SHSceneNode& rhs) noexcept;
SHSceneNode (SHSceneNode&& rhs) noexcept;
SHSceneNode& operator= (const SHSceneNode& rhs) noexcept;
SHSceneNode& operator= (SHSceneNode&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool IsActive () const noexcept;
[[nodiscard]] EntityID GetEntityID () const noexcept;
[[nodiscard]] SHSceneNode* GetParent () const noexcept;
[[nodiscard]] const std::vector<SHSceneNode*>& GetChildren () const noexcept;
[[nodiscard]] SHSceneNode* GetChild (EntityID childID) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetParent (SHSceneNode* parentNode) noexcept;
void SetActive (bool newActiveState) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void AddChild (SHSceneNode* newChild) noexcept;
bool RemoveChild (EntityID childID) noexcept;
bool RemoveChild (SHSceneNode* childToRemove) noexcept;
void RemoveAllChildren () noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool active;
EntityID entityID;
SHSceneNode* parent;
std::vector<SHSceneNode*> children;
};
class SH_API SHSceneGraph class SH_API SHSceneGraph
{ {
public: public:
@ -130,8 +64,8 @@ namespace SHADE
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetParent (EntityID entityID, SHSceneNode* parent) const noexcept; void SetParent (EntityID entityID, SHSceneNode* newParent) noexcept;
void SetParent (EntityID entityID, EntityID parent) const noexcept; void SetParent (EntityID entityID, EntityID newParent) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -142,6 +76,9 @@ namespace SHADE
bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; bool RemoveNode (SHSceneNode* nodeToRemove) noexcept;
void Reset () noexcept; void Reset () noexcept;
bool IsChildOf (EntityID entityID, SHSceneNode* targetNode) noexcept;
bool IsChildOf (EntityID entityID, EntityID targetID) noexcept;
void Traverse (const UnaryFunction& function) const; void Traverse (const UnaryFunction& function) const;
private: private:
@ -158,18 +95,12 @@ namespace SHADE
SHSceneNode* AllocateNode (EntityID entityID); SHSceneNode* AllocateNode (EntityID entityID);
void ReleaseNode (SHSceneNode* node) noexcept; void ReleaseNode (SHSceneNode* node) noexcept;
void ChangeParent (SHSceneNode* node, SHSceneNode* newParent);
void AddChild (SHSceneNode* node, SHSceneNode* newChild);
void RemoveChild (SHSceneNode* node, SHSceneNode* childToRemove);
static void TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function); static void TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function);
}; };
/*-----------------------------------------------------------------------------------*/
/* Event Data Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHSceneGraphChangeParentEvent
{
SHSceneNode* node;
SHSceneNode* oldParent;
SHSceneNode* newParent;
};
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,41 @@
/****************************************************************************************
* \file SHSceneGraphEvents.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for Scene Graph Events.
*
* \copyright Copyright (C) 2022 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
// Project Headers
#include "SHSceneNode.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Event Data Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHSceneGraphChangeParentEvent
{
SHSceneNode* node;
SHSceneNode* oldParent;
SHSceneNode* newParent;
};
struct SHSceneGraphAddChildEvent
{
SHSceneNode* parent;
SHSceneNode* childAdded;
};
struct SHSceneGraphRemoveChildEvent
{
SHSceneNode* parent;
SHSceneNode* childRemoved;
};
} // namespace SHADE

View File

@ -0,0 +1,143 @@
/****************************************************************************************
* \file SHSceneNode.c[[
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Scene Node.
*
* \copyright Copyright (C) 2022 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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHSceneNode.h"
// Project Headers
#include "ECS_Base/Managers/SHEntityManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHSceneNode::SHSceneNode(EntityID eid, SHSceneNode* parent) noexcept
: active { true }
, entityID { eid }
, parent { parent }
{}
SHSceneNode::SHSceneNode(const SHSceneNode& rhs) noexcept
: active { rhs.active }
, entityID { rhs.entityID }
, parent { rhs.parent }
{
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
}
SHSceneNode::SHSceneNode(SHSceneNode&& rhs) noexcept
: active { rhs.active }
, entityID { rhs.entityID }
, parent { rhs.parent }
{
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
}
SHSceneNode& SHSceneNode::operator=(const SHSceneNode& rhs) noexcept
{
if (this == &rhs)
return *this;
active = rhs.active;
entityID = rhs.entityID;
parent = rhs.parent;
children.clear();
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
return *this;
}
SHSceneNode& SHSceneNode::operator=(SHSceneNode&& rhs) noexcept
{
active = rhs.active;
entityID = rhs.entityID;
parent = rhs.parent;
children.clear();
std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children));
return *this;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHSceneNode::IsActive() const noexcept
{
return active;
}
EntityID SHSceneNode::GetEntityID() const noexcept
{
return entityID;
}
SHSceneNode* SHSceneNode::GetParent() const noexcept
{
return parent;
}
const std::vector<SHSceneNode*>& SHSceneNode::GetChildren() const noexcept
{
return children;
}
SHSceneNode* SHSceneNode::GetChild(EntityID childID) const noexcept
{
////////////////////////////////////////
// Error handling
if (!SHEntityManager::IsValidEID(childID))
{
SHLOG_ERROR("Child Entity {} is invalid! Unable to get child from Entity {}", childID, entityID)
return nullptr;
}
if (children.empty())
{
SHLOG_WARNING("Entity {} has no children!", entityID)
return nullptr;
}
////////////////////////////////////////
// Find child
const auto ENTITY_MATCH = [&](const SHSceneNode* node) { return node->GetEntityID() == childID; };
const auto CHILD_ITER = std::ranges::find_if(children.begin(), children.end(),ENTITY_MATCH);
if (CHILD_ITER == children.end())
{
SHLOG_WARNING("Entity {} is not a child of Entity {}! Unable to retrieve child node!", childID, entityID)
return nullptr;
}
return *CHILD_ITER;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHSceneNode::SetActive(bool newActiveState) noexcept
{
active = newActiveState;
for (auto* child : children)
{
SetActive(newActiveState);
}
}
} // namespace SHADE

View File

@ -0,0 +1,82 @@
/****************************************************************************************
* \file SHSceneNode.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Scene Node.
*
* \copyright Copyright (C) 2022 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
#include <vector>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "SH_API.h"
#include "SHSceneGraph.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHSceneGraph;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHSceneNode
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHSceneGraph;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
~SHSceneNode () = default;
SHSceneNode (EntityID eid, SHSceneNode* parent = nullptr) noexcept;
SHSceneNode (const SHSceneNode& rhs) noexcept;
SHSceneNode (SHSceneNode&& rhs) noexcept;
SHSceneNode& operator= (const SHSceneNode& rhs) noexcept;
SHSceneNode& operator= (SHSceneNode&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool IsActive () const noexcept;
[[nodiscard]] EntityID GetEntityID () const noexcept;
[[nodiscard]] SHSceneNode* GetParent () const noexcept;
[[nodiscard]] const std::vector<SHSceneNode*>& GetChildren () const noexcept;
[[nodiscard]] SHSceneNode* GetChild (EntityID childID) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetActive (bool newActiveState) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool active;
EntityID entityID;
SHSceneNode* parent;
std::vector<SHSceneNode*> children;
};
} // namespace SHADE

View File

@ -26,13 +26,15 @@ of DigiPen Institute of Technology is prohibited.
#include "Events/SHEventManager.hpp" #include "Events/SHEventManager.hpp"
#include "Physics/SHPhysicsSystem.h" #include "Physics/SHPhysicsSystem.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Static Definitions */ /* Static Definitions */
/*----------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------*/
const std::string SHScriptEngine::DEFAULT_CSHARP_NAMESPACE = std::string("SHADE"); const std::string SHScriptEngine::DEFAULT_CSHARP_NAMESPACE = std::string("SHADE");
const std::string SHScriptEngine::CSPROJ_DIR = "..\\..\\TempScriptsFolder"; const std::string SHScriptEngine::CSPROJ_DIR = std::string(ASSET_ROOT) + "/Scripts";
const std::string SHScriptEngine::CSPROJ_PATH = std::string(CSPROJ_DIR) + "\\SHADE_Scripting.csproj"; const std::string SHScriptEngine::CSPROJ_PATH = std::string(CSPROJ_DIR) + "\\SHADE_Scripting.csproj";
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -262,18 +264,18 @@ namespace SHADE
</ItemGroup>\n\ </ItemGroup>\n\
<ItemGroup>\n\ <ItemGroup>\n\
<Reference Include=\"SHADE_Managed\">\n\ <Reference Include=\"SHADE_Managed\">\n\
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_Managed.dll</HintPath>\n\ <HintPath Condition=\"Exists('..\\..\\bin\\Debug\\SHADE_Managed.dll')\">..\\..\\bin\\Debug\\SHADE_Managed.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_Managed.dll</HintPath>\n\ <HintPath Condition=\"Exists('..\\..\\bin\\Release\\SHADE_Managed.dll')\">..\\..\\bin\\Release\\SHADE_Managed.dll</HintPath>\n\
</Reference>\n\ </Reference>\n\
<Reference Include=\"SHADE_CSharp\">\n\ <Reference Include=\"SHADE_CSharp\">\n\
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\ <HintPath Condition=\"Exists('..\\..\\bin\\Debug\\SHADE_Managed.dll')\">..\\..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\ <HintPath Condition=\"Exists('..\\..\\bin\\Release\\SHADE_Managed.dll')\">..\\..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\
</Reference>\n\ </Reference>\n\
</ItemGroup>\n\ </ItemGroup>\n\
</Project>"; </Project>";
// Attempt to create the file // Attempt to create the file
std::ofstream file(path); std::ofstream file(path, std::ios::out | std::ios::trunc);
if (!file.is_open()) if (!file.is_open())
throw std::runtime_error("Unable to create CsProj file!"); throw std::runtime_error("Unable to create CsProj file!");
@ -316,6 +318,20 @@ namespace SHADE
return eventData->handle; return eventData->handle;
} }
SHEventHandle SHScriptEngine::onSceneNodeChildrenAdded(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphAddChildEvent>*>(eventPtr.get());
csSceneNodeChildrenChanged(eventData->data->parent->GetEntityID());
return eventData->handle;
}
SHEventHandle SHScriptEngine::onSceneNodeChildrenRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphRemoveChildEvent>*>(eventPtr.get());
csSceneNodeChildrenChanged(eventData->data->parent->GetEntityID());
return eventData->handle;
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -380,6 +396,12 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteLateUpdate" "ExecuteLateUpdate"
); );
csScriptsExecuteDrawGizmos = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteOnDrawGizmos"
);
csScriptsExecutePhysicsEvents = dotNet.GetFunctionPtr<CsFuncPtr> csScriptsExecutePhysicsEvents = dotNet.GetFunctionPtr<CsFuncPtr>
( (
DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_LIB_NAME,
@ -434,6 +456,12 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".Collider", DEFAULT_CSHARP_NAMESPACE + ".Collider",
"OnCollisionShapeRemoved" "OnCollisionShapeRemoved"
); );
csSceneNodeChildrenChanged = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ChildListCache",
"OnChildrenChanged"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr> csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
( (
DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_LIB_NAME,
@ -456,6 +484,7 @@ namespace SHADE
void SHScriptEngine::registerEvents() void SHScriptEngine::registerEvents()
{ {
/* Entity */
// Register for entity destroyed event // Register for entity destroyed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> destroyedEventReceiver std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> destroyedEventReceiver
{ {
@ -463,26 +492,39 @@ namespace SHADE
}; };
SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver)); SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver));
/* Colliders */
// Register for collider added event // Register for collider added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addedColliderEventReceiver std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addedColliderEventReceiver
{ {
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderAdded) std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderAdded)
}; };
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addedColliderEventReceiver)); SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addedColliderEventReceiver));
// Register for collider removed event // Register for collider removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderEventReceiver std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderEventReceiver
{ {
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderRemoved) std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderRemoved)
}; };
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderEventReceiver)); SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderEventReceiver));
// Register for collider component removed event // Register for collider component removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderComponentEventReceiver std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderComponentEventReceiver
{ {
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderComponentRemoved) std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderComponentRemoved)
}; };
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderComponentEventReceiver)); SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderComponentEventReceiver));
/* SceneGraph */
// Register for SceneNode child added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addChildEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onSceneNodeChildrenAdded)
};
SHEventManager::SubscribeTo(SH_SCENEGRAPH_ADD_CHILD_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addChildEventReceiver));
// Register for SceneNode child removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removeChildEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onSceneNodeChildrenRemoved)
};
SHEventManager::SubscribeTo(SH_SCENEGRAPH_REMOVE_CHILD_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removeChildEventReceiver));
} }
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath) void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)

View File

@ -55,6 +55,12 @@ namespace SHADE
LateUpdateRoutine(); LateUpdateRoutine();
void Execute(double dt) noexcept override final; void Execute(double dt) noexcept override final;
}; };
class SH_API GizmosDrawRoutine final : public SHSystemRoutine
{
public:
GizmosDrawRoutine();
void Execute(double dt) noexcept override final;
};
class SH_API FrameCleanUpRoutine final : public SHSystemRoutine class SH_API FrameCleanUpRoutine final : public SHSystemRoutine
{ {
public: public:
@ -250,6 +256,7 @@ namespace SHADE
CsFuncPtr csScriptsExecuteFixedUpdate = nullptr; CsFuncPtr csScriptsExecuteFixedUpdate = nullptr;
CsFuncPtr csScriptsExecuteUpdate = nullptr; CsFuncPtr csScriptsExecuteUpdate = nullptr;
CsFuncPtr csScriptsExecuteLateUpdate = nullptr; CsFuncPtr csScriptsExecuteLateUpdate = nullptr;
CsFuncPtr csScriptsExecuteDrawGizmos = nullptr;
CsFuncPtr csScriptsExecutePhysicsEvents = nullptr; CsFuncPtr csScriptsExecutePhysicsEvents = nullptr;
CsFuncPtr csScriptsFrameCleanUp = nullptr; CsFuncPtr csScriptsFrameCleanUp = nullptr;
CsScriptManipFuncPtr csScriptsAdd = nullptr; CsScriptManipFuncPtr csScriptsAdd = nullptr;
@ -260,6 +267,7 @@ namespace SHADE
// - Events // - Events
CsEventRelayFuncPtr csColliderOnListChanged = nullptr; CsEventRelayFuncPtr csColliderOnListChanged = nullptr;
CsEventRelayFuncPtr csColliderOnRemoved = nullptr; CsEventRelayFuncPtr csColliderOnRemoved = nullptr;
CsEventRelayFuncPtr csSceneNodeChildrenChanged = nullptr;
// - Editor // - Editor
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
CsFuncPtr csEditorUndo = nullptr; CsFuncPtr csEditorUndo = nullptr;
@ -272,6 +280,8 @@ namespace SHADE
SHEventHandle onColliderAdded(SHEventPtr eventPtr); SHEventHandle onColliderAdded(SHEventPtr eventPtr);
SHEventHandle onColliderRemoved(SHEventPtr eventPtr); SHEventHandle onColliderRemoved(SHEventPtr eventPtr);
SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr); SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr);
SHEventHandle onSceneNodeChildrenAdded(SHEventPtr eventPtr);
SHEventHandle onSceneNodeChildrenRemoved(SHEventPtr eventPtr);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */

View File

@ -50,6 +50,17 @@ namespace SHADE
reinterpret_cast<SHScriptEngine*>(system)->csScriptsExecuteLateUpdate(); reinterpret_cast<SHScriptEngine*>(system)->csScriptsExecuteLateUpdate();
} }
/*-----------------------------------------------------------------------------------*/
/* System Routine Functions - GizmosDrawRoutine */
/*-----------------------------------------------------------------------------------*/
SHScriptEngine::GizmosDrawRoutine::GizmosDrawRoutine()
: SHSystemRoutine("Script Engine Gizmos Draw", true)
{}
void SHScriptEngine::GizmosDrawRoutine::Execute(double dt) noexcept
{
reinterpret_cast<SHScriptEngine*>(system)->csScriptsExecuteDrawGizmos();
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* System Routine Functions - FrameCleanUpRoutine */ /* System Routine Functions - FrameCleanUpRoutine */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -25,8 +25,8 @@ namespace SHADE
class SH_API SHConfigurationManager class SH_API SHConfigurationManager
{ {
public: public:
static constexpr std::string_view applicationConfigPath{"../../Assets/Application.SHConfig"}; static inline std::string applicationConfigPath{ std::string(ASSET_ROOT) + "/Application.SHConfig"};
static constexpr std::string_view editorConfigPath{"../../Assets/Editor/Editor.SHConfig"}; static inline std::string editorConfigPath{ std::string(ASSET_ROOT) + "/Editor/Editor.SHConfig"};
static void SaveApplicationConfig(); static void SaveApplicationConfig();
static SHApplicationConfig& LoadApplicationConfig(WindowData* wndData = nullptr); static SHApplicationConfig& LoadApplicationConfig(WindowData* wndData = nullptr);

View File

@ -3,7 +3,7 @@
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "Physics/SHCollider.h" #include "Physics/SHCollisionShape.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
@ -101,7 +101,7 @@ namespace YAML
}; };
template<> template<>
struct convert<SHCollider> struct convert<SHCollisionShape>
{ {
static constexpr const char* IsTrigger = "Is Trigger"; static constexpr const char* IsTrigger = "Is Trigger";
@ -114,33 +114,33 @@ namespace YAML
static constexpr const char* Density = "Density"; static constexpr const char* Density = "Density";
static constexpr const char* PositionOffset = "Position Offset"; static constexpr const char* PositionOffset = "Position Offset";
static Node encode(SHCollider& rhs) static Node encode(SHCollisionShape& rhs)
{ {
Node node; Node node;
node[IsTrigger] = rhs.IsTrigger(); node[IsTrigger] = rhs.IsTrigger();
rttr::type const shapeRttrType = rttr::type::get<SHCollider::Type>(); rttr::type const shapeRttrType = rttr::type::get<SHCollisionShape::Type>();
rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); rttr::enumeration const enumAlign = shapeRttrType.get_enumeration();
SHCollider::Type colliderType = rhs.GetType(); SHCollisionShape::Type colliderType = rhs.GetType();
node[Type] = enumAlign.value_to_name(colliderType).data(); node[Type] = enumAlign.value_to_name(colliderType).data();
switch (colliderType) switch (colliderType)
{ {
case SHCollider::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
auto const bb = reinterpret_cast<SHBoundingBox*>(rhs.GetShape()); auto const bb = reinterpret_cast<SHBoundingBox*>(rhs.GetShape());
node[HalfExtents] = bb->GetHalfExtents(); node[HalfExtents] = bb->GetRelativeExtents();
} }
break; break;
case SHCollider::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
auto const bs = reinterpret_cast<SHBoundingSphere*>(rhs.GetShape()); auto const bs = reinterpret_cast<SHBoundingSphere*>(rhs.GetShape());
node[Radius] = bs->GetRadius(); node[Radius] = bs->GetRelativeRadius();
} }
break; break;
case SHCollider::Type::CAPSULE: break; case SHCollisionShape::Type::CAPSULE: break;
default:; default:;
} }
@ -151,33 +151,33 @@ namespace YAML
return node; return node;
} }
static bool decode(Node const& node, SHCollider& rhs) static bool decode(Node const& node, SHCollisionShape& rhs)
{ {
if (node[IsTrigger].IsDefined()) if (node[IsTrigger].IsDefined())
rhs.SetIsTrigger(node[IsTrigger].as<bool>()); rhs.SetIsTrigger(node[IsTrigger].as<bool>());
if (!node[Type].IsDefined()) if (!node[Type].IsDefined())
return false; return false;
rttr::type const shapeRttrType = rttr::type::get<SHCollider::Type>(); rttr::type const shapeRttrType = rttr::type::get<SHCollisionShape::Type>();
rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); rttr::enumeration const enumAlign = shapeRttrType.get_enumeration();
bool ok; bool ok;
const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as<std::string>()).convert<SHCollider::Type>(&ok); const SHCollisionShape::Type colliderType = enumAlign.name_to_value(node[Type].as<std::string>()).convert<SHCollisionShape::Type>(&ok);
if (!ok) if (!ok)
return false; return false;
switch (colliderType) switch (colliderType)
{ {
case SHCollider::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
if (node[HalfExtents].IsDefined()) if (node[HalfExtents].IsDefined())
rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>() * 2.0f); rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>());
} }
break; break;
case SHCollider::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
if (node[Radius].IsDefined()) if (node[Radius].IsDefined())
rhs.SetBoundingSphere(node[Radius].as<float>()); rhs.SetBoundingSphere(node[Radius].as<float>());
} }
break; break;
case SHCollider::Type::CAPSULE: break; case SHCollisionShape::Type::CAPSULE: break;
default:; default:;
} }
if (node[Friction].IsDefined()) if (node[Friction].IsDefined())
@ -200,12 +200,12 @@ namespace YAML
static Node encode(SHColliderComponent& rhs) static Node encode(SHColliderComponent& rhs)
{ {
Node node, collidersNode; Node node, collidersNode;
auto const& colliders = rhs.GetColliders(); auto const& colliders = rhs.GetCollisionShapes();
int const numColliders = static_cast<int>(colliders.size()); int const numColliders = static_cast<int>(colliders.size());
for (int i = 0; i < numColliders; ++i) for (int i = 0; i < numColliders; ++i)
{ {
auto& collider = rhs.GetCollider(i); auto& collider = rhs.GetCollisionShape(i);
Node colliderNode = convert<SHCollider>::encode(collider); Node colliderNode = convert<SHCollisionShape>::encode(collider);
if (colliderNode.IsDefined()) if (colliderNode.IsDefined())
collidersNode[i] = colliderNode; collidersNode[i] = colliderNode;
} }
@ -219,21 +219,21 @@ namespace YAML
int numColliders{}; int numColliders{};
for (auto const& colliderNode : node[Colliders]) for (auto const& colliderNode : node[Colliders])
{ {
rttr::type const shapeRttrType = rttr::type::get<SHCollider::Type>(); rttr::type const shapeRttrType = rttr::type::get<SHCollisionShape::Type>();
rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); rttr::enumeration const enumAlign = shapeRttrType.get_enumeration();
bool ok = false; bool ok = false;
const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert<SHCollider>::Type].as<std::string>()).convert<SHCollider::Type>(&ok); const SHCollisionShape::Type colliderType = enumAlign.name_to_value(colliderNode[convert<SHCollisionShape>::Type].as<std::string>()).convert<SHCollisionShape::Type>(&ok);
if (!ok) if (!ok)
return false; return false;
switch (colliderType) switch (colliderType)
{ {
case SHCollider::Type::BOX: rhs.AddBoundingBox(); break; case SHCollisionShape::Type::BOX: rhs.AddBoundingBox(); break;
case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break; case SHCollisionShape::Type::SPHERE: rhs.AddBoundingSphere(); break;
case SHCollider::Type::CAPSULE: break; case SHCollisionShape::Type::CAPSULE: break;
default:; default:;
} }
YAML::convert<SHCollider>::decode(colliderNode, rhs.GetCollider(numColliders++)); YAML::convert<SHCollisionShape>::decode(colliderNode, rhs.GetCollisionShape(numColliders++));
} }
} }
return true; return true;

View File

@ -55,11 +55,11 @@ namespace SHADE
} }
Vector3 BoxCollider::HalfExtents::get() Vector3 BoxCollider::HalfExtents::get()
{ {
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetHalfExtents()); return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetWorldExtents());
} }
void BoxCollider::HalfExtents::set(Vector3 value) void BoxCollider::HalfExtents::set(Vector3 value)
{ {
getNativeBoundObject<SHBoundingBox>().SetHalfExtents(Convert::ToNative(value)); getNativeBoundObject<SHBoundingBox>().SetWorldExtents(Convert::ToNative(value));
} }
Vector3 BoxCollider::Min::get() Vector3 BoxCollider::Min::get()
{ {
@ -103,11 +103,11 @@ namespace SHADE
} }
float SphereCollider::Radius::get() float SphereCollider::Radius::get()
{ {
return getNativeBoundObject<SHBoundingSphere>().GetRadius(); return getNativeBoundObject<SHBoundingSphere>().GetWorldRadius();
} }
void SphereCollider::Radius::set(float value) void SphereCollider::Radius::set(float value)
{ {
getNativeBoundObject<SHBoundingSphere>().SetRadius(value); getNativeBoundObject<SHBoundingSphere>().SetWorldRadius(value);
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -150,7 +150,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
int Collider::CollisionShapeCount::get() int Collider::CollisionShapeCount::get()
{ {
return static_cast<int>(GetNativeComponent()->GetColliders().size()); return static_cast<int>(GetNativeComponent()->GetCollisionShapes().size());
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -230,18 +230,18 @@ namespace SHADE
// Populate the list // Populate the list
int i = 0; int i = 0;
for (const auto& collider : GetNativeComponent()->GetColliders()) for (const auto& collider : GetNativeComponent()->GetCollisionShapes())
{ {
CollisionShape^ bound = nullptr; CollisionShape^ bound = nullptr;
switch (collider.GetType()) switch (collider.GetType())
{ {
case SHCollider::Type::BOX: case SHCollisionShape::Type::BOX:
bound = gcnew BoxCollider(i, Owner.GetEntity()); bound = gcnew BoxCollider(i, Owner.GetEntity());
break; break;
case SHCollider::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
bound = gcnew SphereCollider(i, Owner.GetEntity()); bound = gcnew SphereCollider(i, Owner.GetEntity());
break; break;
case SHCollider::Type::CAPSULE: case SHCollisionShape::Type::CAPSULE:
// TODO // TODO
break; break;
default: default:

View File

@ -27,11 +27,11 @@ namespace SHADE
try try
{ {
auto& bounds = collider->GetCollider(arrayIndex); auto& shape = collider->GetCollisionShape(arrayIndex);
if (bounds.GetType() != SHCollider::Type::BOX) if (shape.GetType() != SHCollisionShape::Type::BOX)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid ColliderBound."); throw gcnew System::InvalidOperationException("Attempted to retrieve invalid ColliderBound.");
return reinterpret_cast<CollisionShapeType&>(bounds); return reinterpret_cast<CollisionShapeType&>(shape);
} }
catch (std::invalid_argument&) catch (std::invalid_argument&)
{ {

View File

@ -97,7 +97,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Removes all Scripts of the specified type from this GameObject. /// Removes all Scripts of the specified type from this GameObject.
/// </summary> /// </summary>
/// <typeparam name="T">Type of PLushieScripts to remove.</typeparam> /// <typeparam name="T">Type of Scripts to remove.</typeparam>
generic<typename T> where T : ref class, Script generic<typename T> where T : ref class, Script
void RemoveScript(); void RemoveScript();

View File

@ -0,0 +1,79 @@
/************************************************************************************//*!
\file Light.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 8, 2022
\brief Contains the definition of the functions of the managed Light class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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 "Light.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
Light::Light(Entity entity)
: Component(entity)
{}
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
Vector3 Light::Position::get()
{
return Convert::ToCLI(GetNativeComponent()->GetPosition());
}
void Light::Position::set(Vector3 value)
{
GetNativeComponent()->SetPosition(Convert::ToNative(value));
}
Light::Type Light::LightType::get()
{
return static_cast<Type>(GetNativeComponent()->GetType());
}
void Light::LightType::set(Light::Type value)
{
GetNativeComponent()->SetType(static_cast<SH_LIGHT_TYPE>(value));
}
Vector3 Light::Direction::get()
{
return Convert::ToCLI(GetNativeComponent()->GetDirection());
}
void Light::Direction::set(Vector3 value)
{
GetNativeComponent()->SetDirection(Convert::ToNative(value));
}
Color Light::Color::get()
{
return Convert::ToCLI(SHColour(GetNativeComponent()->GetColor()));
}
void Light::Color::set(SHADE::Color value)
{
GetNativeComponent()->SetColor(Convert::ToNative(value));
}
System::UInt32 Light::CullingMask::get()
{
return GetNativeComponent()->GetCullingMask();
}
void Light::CullingMask::set(System::UInt32 value)
{
GetNativeComponent()->SetCullingMask(value);
}
float Light::Strength::get()
{
return GetNativeComponent()->GetStrength();
}
void Light::Strength::set(float value)
{
GetNativeComponent()->SetStrength(value);
}
}

View File

@ -0,0 +1,125 @@
/************************************************************************************//*!
\file Light.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 8, 2022
\brief Contains the definition of the managed Light class with the declaration
of functions for working with it.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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
// Project Includes
#include "Components/Component.hxx"
#include "Math/Vector3.hxx"
// External Dependencies
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
namespace SHADE
{
/// <summary>
/// CLR version of the SHADE Engine's SHLightComponent.
/// </summary>
public ref class Light : public Component<SHLightComponent>
{
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructs a Light Component that represents a native Light component tied to
/// the specified Entity.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
Light(Entity entity);
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Supported types of the Light Component.
/// </summary>
enum class Type
{
/// <summary>
/// Light applied uniformly across the scene at a specified direction.
/// </summary>
Directional,
/// <summary>
/// Light that originates from a certain point in all directions.
/// Not implemented yet.
/// </summary>
Point,
/// <summary>
/// Light that originates from a certain point within a angle.
/// Not implemented yet.
/// </summary>
Spot,
/// <summary>
/// Light applied to all objects. Has no source point.
/// </summary>
Ambient
};
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Position of the light. Only works for Point Light (unimplemented).
/// </summary>
[System::ObsoleteAttribute("Not implemented yet.", true)]
property Vector3 Position
{
Vector3 get();
void set(Vector3 val);
}
/// <summary>
/// Type of lighting that this Light component will apply onto the scene.
/// </summary>
property Type LightType
{
Type get();
void set(Type val);
}
/// <summary>
/// Direction of the light. Only applicable for Directional Lights.
/// </summary>
property Vector3 Direction
{
Vector3 get();
void set(Vector3 val);
}
/// <summary>
/// Colour of the Light.
/// </summary>
property SHADE::Color Color
{
SHADE::Color get();
void set(SHADE::Color val);
}
/// <summary>
/// Culling mask that is used to control what types of Materials would be
/// affected by this Light.
/// </summary>
property System::UInt32 CullingMask
{
System::UInt32 get();
void set(System::UInt32 val);
}
/// <summary>
/// Intensity of the Light
/// </summary>
property float Strength
{
float get();
void set(float val);
}
};
}

View File

@ -414,19 +414,10 @@ namespace SHADE
generic<typename Attribute> generic<typename Attribute>
Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field) Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field)
{ {
array<System::Object^>^ attributes = field->GetCustomAttributes(true); array<System::Object^>^ attributes = field->GetCustomAttributes(Attribute::typeid, false);
for each (System::Object^ attrib in attributes) if (attributes->Length > 0)
{ {
try return safe_cast<Attribute>(attributes[0]);
{
Attribute attribute = safe_cast<Attribute>(attrib);
if (attribute != nullptr)
return attribute;
}
catch (System::InvalidCastException^)
{
continue;
}
} }
// Failed to find // Failed to find
return Attribute{}; return Attribute{};

View File

@ -39,10 +39,10 @@ namespace SHADE
/// <param name="entity">The Entity to render the Scripts of.</param> /// <param name="entity">The Entity to render the Scripts of.</param>
static void RenderScriptsInInspector(Entity entity); static void RenderScriptsInInspector(Entity entity);
/// <summary> /// <summary>
/// Renders a dropdown button that allows for the addition of PlushieScripts /// Renders a dropdown button that allows for the addition of Scripts onto the
/// onto the specified Entity. /// specified Entity.
/// </summary> /// </summary>
/// <param name="entity">The Entity to add PlushieScripts to.</param> /// <param name="entity">The Entity to add Scripts to.</param>
static void RenderScriptAddButton(Entity entity); static void RenderScriptAddButton(Entity entity);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -0,0 +1,89 @@
/************************************************************************************//*!
\file ChildListCache.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 11, 2022
\brief Contains the definition of the functions for the ChildListCache managed
class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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 "ChildListCache.hxx"
// External Dependencies
#include "Scene/SHSceneManager.h"
// Project Headers
#include "Utility/Debug.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Static Usage Functions */
/*---------------------------------------------------------------------------------*/
ChildListCache::ChildEnumerable^ ChildListCache::GetChildList(Entity entity)
{
// Ignore if invalid
if (entity == MAX_EID)
return nullptr;
// Check if in cache
if (cachedLists->ContainsKey(entity))
return cachedLists[entity];
// Grab the native child list
auto node = GameObject(entity).GetSceneNode();
if (!node || node->GetChildren().empty())
return nullptr;
// Otherwise
// - Create the list
ChildList^ list = gcnew ChildList();
updateChildList(list, node);
// - Cache it
cachedLists[entity] = list;
return list;
}
void ChildListCache::UpdateChildList(Entity entity)
{
// Ignore if invalid
if (entity == MAX_EID)
return;
// Check if in cache
if (!cachedLists->ContainsKey(entity))
return;
// Update
updateChildList(cachedLists[entity], GameObject(entity).GetSceneNode());
}
/*---------------------------------------------------------------------------------*/
/* Event Handling Functions */
/*---------------------------------------------------------------------------------*/
void ChildListCache::OnChildrenChanged(EntityID entity)
{
SAFE_NATIVE_CALL_BEGIN
UpdateChildList(entity);
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ChildListCache")
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void ChildListCache::updateChildList(ChildList^ list, const SHSceneNode* sceneNode)
{
list->Clear();
for (auto node : sceneNode->GetChildren())
{
list->Add(GameObject(node->GetEntityID()));
}
}
}

View File

@ -0,0 +1,80 @@
/************************************************************************************//*!
\file ChildListCache.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 11, 2022
\brief Contains the definition of the ChildListCache managed class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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
// Project Includes
#include "GameObject.hxx"
namespace SHADE { }
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
class SHSceneNode;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Static class that caches all the lists of children for GameObjects.
/// </summary>
private ref class ChildListCache abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using ChildList = System::Collections::Generic::List<GameObject>;
using ChildEnumerable = System::Collections::Generic::IEnumerable<GameObject>;
using ListMap = System::Collections::Generic::Dictionary<Entity, ChildList^>;
internal:
/*-----------------------------------------------------------------------------*/
/* Static Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves the children list for the specified Entity.
/// </summary>
/// <returns>
/// Enumerable read only list of an Entity's children. Null if entity is invalid
/// or there are no children.
/// </returns>
static ChildEnumerable^ GetChildList(Entity entity);
/// <summary>
/// Updates the children list for the specified Entity if it exists.
/// </summary>
static void UpdateChildList(Entity entity);
/*-----------------------------------------------------------------------------*/
/* Event Handling Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// To be
/// </summary>
static void OnChildrenChanged(EntityID entity);
private:
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
static ListMap^ cachedLists = gcnew ListMap();
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
static void updateChildList(ChildList^ list, const SHSceneNode* sceneNode);
};
}

View File

@ -22,8 +22,8 @@ of DigiPen Institute of Technology is prohibited.
// External Dependencies // External Dependencies
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics\Components\SHColliderComponent.h" #include "Physics/Components/SHColliderComponent.h"
#include "Physics\Components\SHRigidBodyComponent.h" #include "Physics/Components/SHRigidBodyComponent.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Scene/SHSceneGraph.h" #include "Scene/SHSceneGraph.h"
#include "Tools/SHLog.h" #include "Tools/SHLog.h"
@ -31,10 +31,11 @@ of DigiPen Institute of Technology is prohibited.
#include "Utility/Convert.hxx" #include "Utility/Convert.hxx"
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
#include "Components/Transform.hxx" #include "Components/Transform.hxx"
#include "Components\RigidBody.hxx" #include "Components/RigidBody.hxx"
#include "Components\Collider.hxx" #include "Components/Collider.hxx"
#include "Components/Camera.hxx" #include "Components/Camera.hxx"
#include "Components/CameraArm.hxx" #include "Components/CameraArm.hxx"
#include "Components/Light.hxx"
namespace SHADE namespace SHADE
{ {
@ -252,6 +253,7 @@ namespace SHADE
componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>()); componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>());
componentMap.Add(createComponentSet<SHCameraComponent, Camera>()); componentMap.Add(createComponentSet<SHCameraComponent, Camera>());
componentMap.Add(createComponentSet<SHCameraArmComponent, CameraArm>()); componentMap.Add(createComponentSet<SHCameraArmComponent, CameraArm>());
componentMap.Add(createComponentSet<SHLightComponent, Light>());
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -20,7 +20,7 @@ namespace SHADE
{ {
/// <summary> /// <summary>
/// Static class that contains the functions for interfacing with the core /// Static class that contains the functions for interfacing with the core
/// PlushieEngine written in C++ for managing the lifecycle of managed code. /// SHADE Engine written in C++ for managing the lifecycle of managed code.
/// </summary> /// </summary>
private ref class EngineInterface abstract sealed private ref class EngineInterface abstract sealed
{ {

View File

@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Utility/Convert.hxx" #include "Utility/Convert.hxx"
#include "Scripts/ScriptStore.hxx" #include "Scripts/ScriptStore.hxx"
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
#include "ChildListCache.hxx"
namespace SHADE namespace SHADE
{ {
@ -87,30 +88,43 @@ namespace SHADE
throw gcnew System::NullReferenceException(); throw gcnew System::NullReferenceException();
return entity; return entity;
} }
GameObject^ GameObject::Parent::get() GameObject GameObject::Parent::get()
{ {
if (!valid) if (!valid)
throw gcnew System::NullReferenceException(); throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot(); const auto* ROOT = SCENE_GRAPH.GetRoot();
const auto* NODE = SCENE_GRAPH.GetNode(entity); const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr) if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString()); throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
const auto* PARENT = NODE->GetParent(); const auto* PARENT = NODE->GetParent();
return PARENT != ROOT ? gcnew GameObject(PARENT->GetEntityID()) : nullptr; return PARENT != ROOT ? GameObject(PARENT->GetEntityID()) : GameObject();
} }
void GameObject::Parent::set(GameObject^ newParent) void GameObject::Parent::set(GameObject newParent)
{ {
if (!valid) if (!valid)
throw gcnew System::NullReferenceException(); throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (newParent == nullptr) if (newParent)
SCENE_GRAPH.SetParent(entity, nullptr); SCENE_GRAPH.SetParent(entity, newParent.EntityId);
else else
SCENE_GRAPH.SetParent(entity, newParent->EntityId); SCENE_GRAPH.SetParent(entity, nullptr);
}
int GameObject::ChildCount::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
return static_cast<int>(NODE->GetChildren().size());
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -215,6 +229,90 @@ namespace SHADE
ScriptStore::RemoveScript<T>(entity); ScriptStore::RemoveScript<T>(entity);
} }
/*---------------------------------------------------------------------------------*/
/* Scene Graph Functions */
/*---------------------------------------------------------------------------------*/
void GameObject::DetachChildren()
{
// Validity Checks
if (!valid)
throw gcnew System::NullReferenceException();
auto node = GetSceneNode();
if (!node)
throw gcnew System::NullReferenceException();
// Unparent all children to the root
for (auto child : node->GetChildren())
{
SHSceneManager::GetCurrentSceneGraph().SetParent(child->GetEntityID(), nullptr);
}
ChildListCache::UpdateChildList(entity);
}
GameObject GameObject::GetChild(int index)
{
// Validity Checks
if (!valid)
throw gcnew System::NullReferenceException();
auto node = GetSceneNode();
if (!node)
throw gcnew System::NullReferenceException();
auto child = node->GetChild(index);
return child ? GameObject(child->GetEntityID()) : GameObject();
}
System::Collections::Generic::IEnumerable<GameObject>^ GameObject::GetChildren()
{
// Validity Checks
if (!valid)
throw gcnew System::NullReferenceException();
return ChildListCache::GetChildList(entity);
}
int GameObject::GetSiblingIndex()
{
throw gcnew System::NotImplementedException();
}
bool GameObject::IsChildOf(GameObject gameObj)
{
// Search parents recursively
auto node = GetSceneNode();
while (node != nullptr)
{
if (node->GetEntityID() == gameObj.entity)
return true;
// Go up higher
node = node->GetParent();
}
return false;
}
void GameObject::SetAsFirstSibling()
{
throw gcnew System::NotImplementedException();
}
void GameObject::SetAsLastSibling()
{
throw gcnew System::NotImplementedException();
}
void GameObject::SetSiblingIndex(int index)
{
throw gcnew System::NotImplementedException();
}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
GameObject::operator bool(GameObject gameObj)
{
return gameObj.valid;
}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -245,11 +343,15 @@ namespace SHADE
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
GameObject::operator bool(GameObject gameObj) SHSceneNode* GameObject::GetSceneNode()
{ {
return gameObj.valid; const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
if (!ROOT)
return nullptr;
return SCENE_GRAPH.GetNode(entity);
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -290,4 +392,21 @@ namespace SHADE
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/*---------------------------------------------------------------------------------*/
/* IEnummerable */
/*---------------------------------------------------------------------------------*/
System::Collections::Generic::IEnumerator<GameObject>^ GameObject::GetEnumerator()
{
System::Collections::Generic::IEnumerable<GameObject>^ childList = GetChildren();
if (childList == nullptr)
return System::Linq::Enumerable::Empty<GameObject>()->GetEnumerator();
else
return childList->GetEnumerator();
}
System::Collections::IEnumerator^ GameObject::GetEnumeratorNonGeneric()
{
return GetEnumerator();
}
} }

View File

@ -32,8 +32,9 @@ namespace SHADE
/// Lightweight object for an Entity that allows for easy access to Component and /// Lightweight object for an Entity that allows for easy access to Component and
/// Script operations. /// Script operations.
/// Can be set to a invalid/null GameObject by default construction. /// Can be set to a invalid/null GameObject by default construction.
/// Can also be iterated to access children.
/// </summary> /// </summary>
public value class GameObject : public System::IEquatable<GameObject> public value class GameObject : public System::IEquatable<GameObject>, public System::Collections::Generic::IEnumerable<GameObject>
{ {
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -97,10 +98,17 @@ namespace SHADE
/// <summary> /// <summary>
/// The parent entity for this GameObject. /// The parent entity for this GameObject.
/// </summary> /// </summary>
property GameObject^ Parent property GameObject Parent
{ {
GameObject^ get(); GameObject get();
void set(GameObject^); void set(GameObject);
}
/// <summary>
/// Number of Children held by this GameObject
/// </summary>
property int ChildCount
{
int get();
} }
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -122,7 +130,6 @@ namespace SHADE
/// </param> /// </param>
void SetActive(bool active); void SetActive(bool active);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Component Access Functions */ /* Component Access Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -210,10 +217,86 @@ namespace SHADE
/// <summary> /// <summary>
/// Removes all Scripts of the specified type from this GameObject. /// Removes all Scripts of the specified type from this GameObject.
/// </summary> /// </summary>
/// <typeparam name="T">Type of PLushieScripts to remove.</typeparam> /// <typeparam name="T">Type of Scripts to remove.</typeparam>
generic<typename T> where T : ref class, Script generic<typename T> where T : ref class, Script
void RemoveScript(); void RemoveScript();
/*-----------------------------------------------------------------------------*/
/* Scene Graph Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Unparents all children. Useful if you want to destroy the root of a hierarchy
/// without destroying the children.
/// </summary>
void DetachChildren();
/// <summary>
/// Returns a child by index.
/// </summary>
/// <param name="index">Index of the child GameObject to retrieve.</param>
/// <returns>
/// Handle to the GameObject if the index is valid. Invalid GameObject otherwise.
/// </returns>
GameObject GetChild(int index);
/// <summary>
/// Returns a cached enumerable container of child GameObjects of this
/// GameObject.
/// </summary>
/// <returns>
/// Enumerable container of child GameObjects of this GameObject. Null if
/// ChildCount is 0.
/// </returns>
System::Collections::Generic::IEnumerable<GameObject>^ GetChildren();
/// <summary>
/// Gets the sibling index. Use GetSiblingIndex to find out the GameObjects
/// place in this hierarchy. When the sibling index of a GameObject is changed,
/// its order in the Hierarchy window will also change.
/// </summary>
/// <returns>
/// Index of this GameObject among the parent GameObject's children.
/// </returns>
[System::ObsoleteAttribute("Not yet implemented.", true)]
int GetSiblingIndex();
/// <summary>
/// Checks if this GameObject a direct or indirect child of the specified
/// GameObject.
/// </summary>
/// <returns>
/// True if this GameObject is a child, deep child (child of a child) or
/// identical to this GameObject, otherwise false.
/// </returns>
bool IsChildOf(GameObject gameObj);
/// <summary>
/// Move the GameObject to the start of the parent GameObject's children list.
/// </summary>
[System::ObsoleteAttribute("Not yet implemented.", true)]
void SetAsFirstSibling();
/// <summary>
/// Move the GameObject to the end of the parent GameObject's children list.
/// </summary>
[System::ObsoleteAttribute("Not yet implemented.", true)]
void SetAsLastSibling();
/// <summary>
/// Move the GameObject to the specified position in the parent GameObject's
/// children list. An existing object at that position if any, will be pushed
/// to the next index (existing element will be at index + 1).
/// </summary>
/// <param name="index">
/// Position to place this GameObject at in the hierarchy. Clamped to between
/// [0, parent.ChildCount].
/// </param>
[System::ObsoleteAttribute("Not yet implemented.", true)]
void SetSiblingIndex(int index);
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a GameObject is valid.
/// </summary>
/// <param name="gameObj">GameObjects to check.</param>
/// <returns>True if the GameObject is valid.</returns>
static operator bool(GameObject gameObj);
internal: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
@ -249,13 +332,13 @@ namespace SHADE
SHEntity& GetNativeEntity(); SHEntity& GetNativeEntity();
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Operator Overloads */ /* Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Implicit conversion operator to enable checking if a GameObject is valid. /// Retrieves the SceneNode for this GameObject's referenced entity.
/// </summary> /// </summary>
/// <param name="gameObj">GameObjects to check.</param> /// <returns>Pointer to the SceneNode for this GameObject..</returns>
static operator bool(GameObject gameObj); SHSceneNode* GetSceneNode();
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -304,6 +387,14 @@ namespace SHADE
/// <param name="rhs">Another GameObject to check with.</param> /// <param name="rhs">Another GameObject to check with.</param>
/// <returns>True if both Components are different.</returns> /// <returns>True if both Components are different.</returns>
static bool operator!=(GameObject lhs, GameObject rhs); static bool operator!=(GameObject lhs, GameObject rhs);
/*-----------------------------------------------------------------------------*/
/* IEnummerable */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
System::Collections::Generic::IEnumerator<GameObject>^ GetEnumerator() override;
/// <inheritdoc/>
System::Collections::IEnumerator^ GetEnumeratorNonGeneric() override = System::Collections::IEnumerable::GetEnumerator;
}; };
} }

View File

@ -25,17 +25,8 @@ namespace SHADE
{ {
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// A static class that contains a set of default Colors.
/// </summary>
ref class Defaults abstract sealed
{
public:
/*-------------------------------------------------------------------------*/
/* Properties */ /* Properties */
/*-------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Pure black. /// Pure black.
/// </summary> /// </summary>
@ -113,7 +104,6 @@ namespace SHADE
{ {
Color get() { return Color(1.0f, 1.0f, 0.0f); } Color get() { return Color(1.0f, 1.0f, 0.0f); }
} }
};
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */

View File

@ -276,4 +276,4 @@ namespace SHADE
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
} // namespace PlushieAPI::Mathematics }

View File

@ -294,4 +294,4 @@ namespace SHADE
{ {
return Vector3(vec); return Vector3(vec);
} }
} // namespace PlushieAPI::Mathematics }

View File

@ -439,4 +439,5 @@ namespace SHADE
/// <param name="vec">Vector2 to convert from.</param> /// <param name="vec">Vector2 to convert from.</param>
static explicit operator Vector3(Vector2 vec); static explicit operator Vector3(Vector2 vec);
}; };
} // namespace PlushieAPI::Mathematics }

View File

@ -3,8 +3,7 @@
\author Tng Kah Wei, kahwei.tng, 390009620 \author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu \par email: kahwei.tng\@digipen.edu
\date Oct 28, 2021 \date Oct 28, 2021
\brief Contains the definition of the functions for the PlushieScript managed \brief Contains the definition of the functions for the Script managed class.
class.
Note: This file is written in C++17/CLI. Note: This file is written in C++17/CLI.
@ -140,6 +139,13 @@ namespace SHADE
lateUpdate(); lateUpdate();
SAFE_NATIVE_CALL_END(this) SAFE_NATIVE_CALL_END(this)
} }
void Script::OnDrawGizmos()
{
SAFE_NATIVE_CALL_BEGIN
OnGizmosDrawOverriden = true;
onDrawGizmos();
SAFE_NATIVE_CALL_END(this)
}
void Script::OnDestroy() void Script::OnDestroy()
{ {
SAFE_NATIVE_CALL_BEGIN SAFE_NATIVE_CALL_BEGIN
@ -194,6 +200,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Script::Script(GameObject gameObj) Script::Script(GameObject gameObj)
: owner { gameObj } : owner { gameObj }
, OnGizmosDrawOverriden { false }
{} {}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -210,6 +217,10 @@ namespace SHADE
void Script::fixedUpdate() {} void Script::fixedUpdate() {}
void Script::update() {} void Script::update() {}
void Script::lateUpdate() {} void Script::lateUpdate() {}
void Script::onDrawGizmos()
{
OnGizmosDrawOverriden = false;
}
void Script::onDestroy() {} void Script::onDestroy() {}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -164,6 +164,14 @@ namespace SHADE
static operator bool(Script^ s); static operator bool(Script^ s);
internal: internal:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// If true, the OnGizmosDraw function was overridden.
/// </summary>
bool OnGizmosDrawOverriden;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* "All-Time" Lifecycle Functions */ /* "All-Time" Lifecycle Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -208,6 +216,11 @@ namespace SHADE
/// </summary> /// </summary>
void LateUpdate(); void LateUpdate();
/// <summary> /// <summary>
/// Used to call onDrawGizmos(). This should be called just before rendering
/// the scene. This will only be called when working in the editor.
/// </summary>
void OnDrawGizmos();
/// <summary>
/// Used to call onDestroy(). This should be called at the end of the frame /// Used to call onDestroy(). This should be called at the end of the frame
/// where the attached GameObject or this script is destroyed directly or /// where the attached GameObject or this script is destroyed directly or
/// indirectly due to destruction of the owner. /// indirectly due to destruction of the owner.
@ -308,6 +321,10 @@ namespace SHADE
/// </summary> /// </summary>
virtual void lateUpdate(); virtual void lateUpdate();
/// <summary> /// <summary>
/// Called every frame just before rendering but only if working in the editor.
/// </summary>
virtual void onDrawGizmos();
/// <summary>
/// Called just before the end of the frame where the attached GameObject or /// Called just before the end of the frame where the attached GameObject or
/// this script is destroyed directly or indirectly due to destruction of the /// this script is destroyed directly or indirectly due to destruction of the
/// owner. /// owner.

View File

@ -478,6 +478,24 @@ namespace SHADE
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
} }
void ScriptStore::ExecuteOnDrawGizmos()
{
SAFE_NATIVE_CALL_BEGIN
for each (System::Collections::Generic::KeyValuePair<Entity, ScriptList^> entity in scripts)
{
// Check active state
if (!isEntityActive(entity.Key))
continue;
// Update each script
for each (Script^ script in entity.Value)
{
script->OnDrawGizmos();
}
}
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::ExecuteCollisionFunctions() void ScriptStore::ExecuteCollisionFunctions()
{ {
SAFE_NATIVE_CALL_BEGIN SAFE_NATIVE_CALL_BEGIN

View File

@ -36,7 +36,7 @@ namespace SHADE
/// </summary> /// </summary>
/// <typeparam name="T"> /// <typeparam name="T">
/// Type of script to add. /// Type of script to add.
/// This needs to be a default constructable PlushieScript. /// This needs to be a default constructable Script.
/// </typeparam> /// </typeparam>
/// <param name="entity">The entity to add a script to.</param> /// <param name="entity">The entity to add a script to.</param>
/// <returns>Reference to the script added.</returns> /// <returns>Reference to the script added.</returns>
@ -234,6 +234,10 @@ namespace SHADE
/// </summary> /// </summary>
static void ExecuteLateUpdate(); static void ExecuteLateUpdate();
/// <summary> /// <summary>
/// Executes OnDrawGizmos() for all scripts.
/// </summary>
static void ExecuteOnDrawGizmos();
/// <summary>
/// Executes OnCollision*() and OnTrigger*() for all scripts. /// Executes OnCollision*() and OnTrigger*() for all scripts.
/// </summary> /// </summary>
static void ExecuteCollisionFunctions(); static void ExecuteCollisionFunctions();

View File

@ -72,6 +72,16 @@ namespace SHADE
return Ray(ToCLI(vec.position), ToCLI(vec.direction)); return Ray(ToCLI(vec.position), ToCLI(vec.direction));
} }
SHColour Convert::ToNative(Color col)
{
return SHColour(col.r, col.g, col.b, col.a);
}
Color Convert::ToCLI(const SHColour& vec)
{
return Color(vec.x, vec.y, vec.z, vec.w);
}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* String Conversions */ /* String Conversions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/Quaternion.hxx" #include "Math/Quaternion.hxx"
#include "Math/Ray.hxx" #include "Math/Ray.hxx"
#include "Engine/GenericHandle.hxx" #include "Engine/GenericHandle.hxx"
#include "Math/SHColour.h"
#include "Graphics/Color.hxx"
namespace SHADE namespace SHADE
{ {
@ -104,6 +106,17 @@ namespace SHADE
/// <param name="vec">The native Vector2 to convert from.</param> /// <param name="vec">The native Vector2 to convert from.</param>
/// <returns>Managed copy of a native Vector2.</returns> /// <returns>Managed copy of a native Vector2.</returns>
static Ray ToCLI(const SHRay& vec); static Ray ToCLI(const SHRay& vec);
/// Converts from a managed Color to a native Colour.
/// </summary>
/// <param name="vec">The managed Color to convert from.</param>
/// <returns>Native copy of a managed Color.</returns>
static SHColour ToNative(Color col);
/// <summary>
/// Converts from a native Colour to a managed Color.
/// </summary>
/// <param name="vec">The native Colour to convert from.</param>
/// <returns>Managed copy of a native Colour.</returns>
static Color ToCLI(const SHColour& vec);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* String Conversions */ /* String Conversions */

View File

@ -33,4 +33,4 @@ namespace SHADE
{ {
return nullptr; return nullptr;
} }
} // namespace PlushieAPI }

View File

@ -36,4 +36,4 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
System::Reflection::Assembly^ Load(System::Reflection::AssemblyName^ assemblyName) override; System::Reflection::Assembly^ Load(System::Reflection::AssemblyName^ assemblyName) override;
}; };
} // namespace PlushieAPI }

View File

@ -0,0 +1,69 @@
/************************************************************************************//*!
\file Gizmos.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 8, 2022
\brief Contains the definition of the functions for the Convert managed static
class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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 "Gizmos.hxx"
#include "Convert.hxx"
#include "Tools/SHDebugDraw.h"
// External Dependencies
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Public Properties */
/*---------------------------------------------------------------------------------*/
Color Gizmos::Color::get()
{
return defaultColor;
}
void Gizmos::Color::set(SHADE::Color color)
{
defaultColor = color;
}
/*---------------------------------------------------------------------------------*/
/* Debug Draw Functions */
/*---------------------------------------------------------------------------------*/
void Gizmos::DrawLine(Vector3 from, Vector3 to)
{
DrawLine(from, to, defaultColor);
}
void Gizmos::DrawLine(Vector3 from, Vector3 to, SHADE::Color color)
{
SHDebugDraw::Line(Convert::ToNative(color), Convert::ToNative(from), Convert::ToNative(to));
}
void Gizmos::DrawWireCube(Vector3 center, Vector3 extents)
{
DrawWireCube(center, extents, defaultColor);
}
void Gizmos::DrawWireCube(Vector3 center, Vector3 extents, SHADE::Color color)
{
SHDebugDraw::Cube(Convert::ToNative(color), Convert::ToNative(center), Convert::ToNative(extents));
}
void Gizmos::DrawWireSphere(Vector3 center, float radius)
{
DrawWireSphere(center, radius, defaultColor);
}
void Gizmos::DrawWireSphere(Vector3 center, float radius, SHADE::Color color)
{
SHDebugDraw::Sphere(Convert::ToNative(color), Convert::ToNative(center), radius);
}
}

View File

@ -0,0 +1,97 @@
/************************************************************************************//*!
\file Gizmos.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 8, 2022
\brief Contains the definition of the Gizmos static class and the
declaration of its functions.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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
// Project Includes
#include "Math/Vector3.hxx"
#include "Graphics/Color.hxx"
namespace SHADE
{
/// <summary>
/// Provides functions for implementing debug drawing.
/// </summary>
public value class Gizmos abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Public Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Default colour that will be used for drawing debug primitives if the color
/// parameter is not specified.
/// </summary>
static property Color Color
{
SHADE::Color get();
void set(SHADE::Color color);
}
/*-----------------------------------------------------------------------------*/
/* Debug Draw Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Renders a line between two points in world space.
/// Uses <see cref="Gizmos.Color">Color</see> to render.
/// </summary>
/// <param name="from">First point of the line.</param>
/// <param name="to">Second point of the line.</param>
static void DrawLine(Vector3 from, Vector3 to);
/// <summary>
/// Renders a line between two points in world space.
/// </summary>
/// <param name="from">First point of the line.</param>
/// <param name="to">Second point of the line.</param>
/// <param name="color">Colour of the line.</param>
static void DrawLine(Vector3 from, Vector3 to, SHADE::Color color);
/// <summary>
/// Renders a wireframe cube centered around the position specified in world
/// space.
/// Uses <see cref="Gizmos.Color">Color</see> to render.
/// </summary>
/// <param name="center">Position where the cube wil be centered at.</param>
/// <param name="extents">Size of the rendered cube.</param>
static void DrawWireCube(Vector3 center, Vector3 extents);
/// <summary>
/// Renders a wireframe cube centered around the position specified in world
/// space.
/// </summary>
/// <param name="center">Position where the cube wil be centered at.</param>
/// <param name="extents">Size of the rendered cube.</param>
/// <param name="color">Colour of the cube.</param>
static void DrawWireCube(Vector3 center, Vector3 extents, SHADE::Color color);
/// <summary>
/// Renders a wireframe sphere centered around the position specified in world
/// space.
/// Uses <see cref="Gizmos.Color">Color</see> to render.
/// </summary>
/// <param name="center">Position where the sphere wil be centered at.</param>
/// <param name="radius">Radius of the rendered sphere.</param>
static void DrawWireSphere(Vector3 center, float radius);
/// <summary>
/// Renders a wireframe sphere centered around the position specified in world
/// space.
/// </summary>
/// <param name="center">Position where the sphere wil be centered at.</param>
/// <param name="radius">Radius of the rendered sphere.</param>
/// <param name="color">Colour of the sphere.</param>
static void DrawWireSphere(Vector3 center, float radius, SHADE::Color color);
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
static SHADE::Color defaultColor = SHADE::Color::White;
};
}