Merge branch 'main' into PlayerController

This commit is contained in:
Glence 2022-11-14 15:03:04 +08:00
commit 04273620a6
124 changed files with 6989 additions and 7921 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,55 @@
Name: HouseModular
ID: 75328301
Type: 4
Sub Assets:
Name: FloorLarge
ID: 142812576
Type: 8
Name: FloorSmall
ID: 139921228
Type: 8
Name: FloorLong
ID: 136991843
Type: 8
Name: Pillar
ID: 150352316
Type: 8
Name: WallEnd
ID: 139594893
Type: 8
Name: WallCorner
ID: 134714737
Type: 8
Name: WallDefault
ID: 140834166
Type: 8
Name: WallLarge
ID: 142689599
Type: 8
Name: WallDiagonal
ID: 144002377
Type: 8
Name: WallTBlock
ID: 149359798
Type: 8
Name: WindowLarge
ID: 148351779
Type: 8
Name: WindowSmallOpened
ID: 149786048
Type: 8
Name: WindowSmallClosed
ID: 147863396
Type: 8
Name: WindowLargeOpen
ID: 138781993
Type: 8
Name: WallDoorHole
ID: 150924328
Type: 8
Name: Door
ID: 147152385
Type: 8
Name: DoorFrame
ID: 146862321
Type: 8

View File

@ -1,10 +1,10 @@
- EID: 0 - EID: 0
Name: Default Name: Camera
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Camera Component: Camera Component:
Position: {x: 0, y: 0, z: 0} Position: {x: 0, y: 0, z: 8}
Pitch: 0 Pitch: 0
Yaw: 0 Yaw: 0
Roll: 0 Roll: 0
@ -22,7 +22,7 @@
Strength: 0 Strength: 0
Scripts: ~ Scripts: ~
- EID: 1 - EID: 1
Name: Default Name: Floor
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -36,8 +36,8 @@
RigidBody Component: RigidBody Component:
Type: Static Type: Static
Mass: 1 Mass: 1
Drag: 0 Drag: 0.00999999978
Angular Drag: 0 Angular Drag: 0.00999999978
Use Gravity: true Use Gravity: true
Interpolate: true Interpolate: true
Freeze Position X: false Freeze Position X: false
@ -56,18 +56,15 @@
Density: 1 Density: 1
Position Offset: {x: 0, y: 0, z: 0} Position Offset: {x: 0, y: 0, z: 0}
Scripts: ~ Scripts: ~
- EID: 2 - EID: 10
Name: Player Name: Default
IsActive: true IsActive: true
NumberOfChildren: 3 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: -3.06177855, y: -2, z: -5} Translate: {x: -4.40482807, y: 2.57871056, z: -5.21213436}
Rotate: {x: -0, y: 0, z: -0} Rotate: {x: -0.361265004, y: 1.11661232, z: -0.626627684}
Scale: {x: 2, y: 2, z: 2} Scale: {x: 0.999982238, y: 0.999987125, z: 0.999981165}
Renderable Component:
Mesh: 149697411
Material: 126974645
RigidBody Component: RigidBody Component:
Type: Dynamic Type: Dynamic
Mass: 1 Mass: 1
@ -89,10 +86,10 @@
Friction: 0.400000006 Friction: 0.400000006
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1
Position Offset: {x: 0, y: 0.5, z: 0} Position Offset: {x: 0, y: 0, z: 0}
Scripts: ~ Scripts: ~
- EID: 3 - EID: 3
Name: Default Name: Empty
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -102,7 +99,7 @@
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
Scripts: ~ Scripts: ~
- EID: 4 - EID: 4
Name: Default Name: Empty2
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -112,7 +109,7 @@
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
Scripts: ~ Scripts: ~
- EID: 9 - EID: 9
Name: Default Name: Bag
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -160,7 +157,7 @@
Position Offset: {x: 0, y: 0.5, z: 0} Position Offset: {x: 0, y: 0.5, z: 0}
Scripts: ~ Scripts: ~
- EID: 7 - EID: 7
Name: Default Name: BigBoi
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -173,7 +170,7 @@
Material: 126974645 Material: 126974645
Scripts: ~ Scripts: ~
- EID: 8 - EID: 8
Name: Default Name: AmbientLight
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -226,4 +223,9 @@
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: Item
currCategory: 0
- Type: PickAndThrow
throwForce: [100, 200, 100]
item: 51000

View File

@ -51,7 +51,6 @@ public class AIPrototype : Script
private GameObject? player; private GameObject? player;
public AIPrototype(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -0,0 +1,3 @@
Name: AIPrototype
ID: 163215061
Type: 9

View File

@ -7,7 +7,6 @@ namespace SHADE_Scripting
{ {
public float turnSpeed = 0.5f; public float turnSpeed = 0.5f;
public CameraControl(GameObject go) : base(go) { }
protected override void update() protected override void update()
{ {
//Camera //Camera

View File

@ -0,0 +1,3 @@
Name: CameraControl
ID: 158782344
Type: 9

View File

@ -3,7 +3,6 @@ using System;
public class CameraFix : Script public class CameraFix : Script
{ {
public CameraFix(GameObject gameObj) : base(gameObj) { }
private Transform tranform; private Transform tranform;
public Vector3 pos = Vector3.Zero; public Vector3 pos = Vector3.Zero;

View File

@ -0,0 +1,3 @@
Name: CameraFix
ID: 162231964
Type: 9

View File

@ -0,0 +1,3 @@
Name: Item
ID: 163145289
Type: 9

View File

@ -8,7 +8,6 @@ public class PhysicsTest : Script
private Transform Transform; private Transform Transform;
private RigidBody RigidBody; private RigidBody RigidBody;
private Collider Collider; private Collider Collider;
public PhysicsTest(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -0,0 +1,3 @@
Name: PhysicsTest
ID: 159771801
Type: 9

View File

@ -0,0 +1,3 @@
Name: PickAndThrow
ID: 165331952
Type: 9

View File

@ -0,0 +1,3 @@
Name: PlayerController
ID: 164563088
Type: 9

View File

@ -2,8 +2,6 @@
public class PrintWhenActive : Script public class PrintWhenActive : Script
{ {
public PrintWhenActive(GameObject gameObj) : base(gameObj) { }
protected override void update() protected override void update()
{ {
Debug.Log("Active!"); Debug.Log("Active!");

View File

@ -0,0 +1,3 @@
Name: PrintWhenActive
ID: 162536221
Type: 9

View File

@ -1,5 +1,6 @@
using SHADE; using SHADE;
using System; using System;
using System.Collections.Generic;
public class RaccoonShowcase : Script public class RaccoonShowcase : Script
{ {
@ -17,7 +18,11 @@ public class RaccoonShowcase : Script
private double rotation = 0.0; private double rotation = 0.0;
private Vector3 scale = Vector3.Zero; private Vector3 scale = Vector3.Zero;
private double originalScale = 1.0f; private double originalScale = 1.0f;
public RaccoonShowcase(GameObject gameObj) : base(gameObj) {} [Tooltip("Sample list of Vector3s.")]
public List<Vector3> vecList = new List<Vector3>(new Vector3[] { new Vector3(1, 2, 3), new Vector3(4, 5, 6) });
[Range(-5, 5)]
public List<int> intList = new List<int>(new int[] { 2, 8, 2, 6, 8, 0, 1 });
public List<Light.Type> enumList = new List<Light.Type>(new Light.Type[] { Light.Type.Point, Light.Type.Directional, Light.Type.Ambient });
protected override void awake() protected override void awake()
{ {

View File

@ -0,0 +1,3 @@
Name: RaccoonShowcase
ID: 159969631
Type: 9

View File

@ -14,8 +14,6 @@ public class RaccoonSpin : Script
[SerializeField] [SerializeField]
private CallbackEvent<int, double, Vector3> testEvent3 = new CallbackEvent<int, double, Vector3>(); private CallbackEvent<int, double, Vector3> testEvent3 = new CallbackEvent<int, double, Vector3>();
private Transform Transform; private Transform Transform;
public RaccoonSpin(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -0,0 +1,3 @@
Name: RaccoonSpin
ID: 157367824
Type: 9

View File

@ -11,7 +11,6 @@ public class Item : Script
public int Score = 1; public int Score = 1;
public ItemCategory currCategory; public ItemCategory currCategory;
public Item(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -15,7 +15,6 @@ public class PickAndThrow : Script
private float lastXDir; private float lastXDir;
private float lastZDir; private float lastZDir;
private bool inRange = false; private bool inRange = false;
public PickAndThrow(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -15,7 +15,6 @@ namespace SHADE_Scripting
public float turnSpeedPitch = 0.3f; public float turnSpeedPitch = 0.3f;
public float turnSpeedYaw = 0.5f; public float turnSpeedYaw = 0.5f;
public float pitchClamp = 45.0f; public float pitchClamp = 45.0f;
public ThirdPersonCamera(GameObject go) : base(go) { }
protected override void awake() protected override void awake()
{ {

View File

@ -0,0 +1,3 @@
Name: ThirdPersonCamera
ID: 154161201
Type: 9

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -24,14 +24,15 @@
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
// Systems // Systems
#include "Scripting/SHScriptEngine.h"
#include "Physics/SHPhysicsSystem.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Input/SHInputManager.h"
#include "FRC/SHFramerateController.h"
#include "AudioSystem/SHAudioSystem.h" #include "AudioSystem/SHAudioSystem.h"
#include "Camera/SHCameraSystem.h" #include "Camera/SHCameraSystem.h"
#include "FRC/SHFramerateController.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Input/SHInputManager.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Physics/System/SHPhysicsDebugDrawSystem.h"
#include "Scripting/SHScriptEngine.h"
// Components // Components
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
@ -39,7 +40,6 @@
#include "Scenes/SBTestScene.h" #include "Scenes/SBTestScene.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include "Scenes/SBMainScene.h" #include "Scenes/SBMainScene.h"
#include "Serialization/Configurations/SHConfigurationManager.h" #include "Serialization/Configurations/SHConfigurationManager.h"
@ -67,16 +67,21 @@ namespace Sandbox
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow, wndData); window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow, wndData);
// Create Systems // Create Systems
SHSystemManager::CreateSystem<SHGraphicsSystem>();
SHSystemManager::CreateSystem<SHScriptEngine>(); SHSystemManager::CreateSystem<SHScriptEngine>();
SHSystemManager::CreateSystem<SHPhysicsSystem>();
SHSystemManager::CreateSystem<SHTransformSystem>(); SHSystemManager::CreateSystem<SHTransformSystem>();
SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>()); SHSystemManager::CreateSystem<SHPhysicsSystem>();
SHSystemManager::CreateSystem<SHPhysicsDebugDrawSystem>();
SHSystemManager::CreateSystem<SHAudioSystem>(); SHSystemManager::CreateSystem<SHAudioSystem>();
SHSystemManager::CreateSystem<SHCameraSystem>(); SHSystemManager::CreateSystem<SHCameraSystem>();
SHSystemManager::CreateSystem<SHDebugDrawSystem>();
SHSystemManager::CreateSystem<SHGraphicsSystem>();
SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>());
// Link up SHDebugDraw // Link up SHDebugDraw
SHSystemManager::CreateSystem<SHDebugDrawSystem>();
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>()); SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
#ifdef SHEDITOR #ifdef SHEDITOR
@ -101,7 +106,8 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsDebugDraw>();
SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>(); SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>();
@ -165,7 +171,7 @@ namespace Sandbox
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10))
{ {
drawColliders = !drawColliders; drawColliders = !drawColliders;
SHSystemManager::GetSystem<SHPhysicsSystem>()->SetDrawColliders(drawColliders); SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders);
} }
} }
// Finish all graphics jobs first // Finish all graphics jobs first

View File

@ -10,8 +10,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"

View File

@ -10,8 +10,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"

View File

@ -51,8 +51,9 @@ enum class AssetType : AssetTypeMeta
SCENE, SCENE,
PREFAB, PREFAB,
MATERIAL, MATERIAL,
SCRIPT,
MESH, MESH,
SCRIPT,
FONT,
MAX_COUNT MAX_COUNT
}; };
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) }; constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
@ -86,7 +87,8 @@ constexpr std::string_view SCENE_EXTENSION {".shade"};
constexpr std::string_view PREFAB_EXTENSION {".shprefab"}; constexpr std::string_view PREFAB_EXTENSION {".shprefab"};
constexpr std::string_view MATERIAL_EXTENSION {".shmat"}; constexpr std::string_view MATERIAL_EXTENSION {".shmat"};
constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
constexpr std::string_view MODEL_EXTENSION {".shmodel"}; constexpr std::string_view MODEL_EXTENSION{ ".shmodel" };
constexpr std::string_view FONT_EXTENSION{ ".shfont" };
constexpr std::string_view EXTENSIONS[] = { constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION, AUDIO_EXTENSION,
@ -97,21 +99,27 @@ constexpr std::string_view EXTENSIONS[] = {
SCENE_EXTENSION, SCENE_EXTENSION,
PREFAB_EXTENSION, PREFAB_EXTENSION,
MATERIAL_EXTENSION, MATERIAL_EXTENSION,
"dummy",
SCRIPT_EXTENSION, SCRIPT_EXTENSION,
FONT_EXTENSION,
AUDIO_WAV_EXTENSION, AUDIO_WAV_EXTENSION,
}; };
constexpr size_t EXTENSIONS_COUNT{ 11 };
// EXTERNAL EXTENSIONS // EXTERNAL EXTENSIONS
constexpr std::string_view GLSL_EXTENSION{ ".glsl" }; constexpr std::string_view GLSL_EXTENSION{ ".glsl" };
constexpr std::string_view DDS_EXTENSION{ ".dds" }; constexpr std::string_view DDS_EXTENSION{ ".dds" };
constexpr std::string_view FBX_EXTENSION{ ".fbx" }; constexpr std::string_view FBX_EXTENSION{ ".fbx" };
constexpr std::string_view GLTF_EXTENSION{ ".gltf" }; constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view TTF_EXTENSION{ ".ttf" };
constexpr std::string_view EXTERNALS[] = { constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION, GLSL_EXTENSION,
DDS_EXTENSION, DDS_EXTENSION,
FBX_EXTENSION, FBX_EXTENSION,
GLTF_EXTENSION GLTF_EXTENSION,
TTF_EXTENSION
}; };
// SHADER IDENTIFIERS // SHADER IDENTIFIERS
@ -126,11 +134,4 @@ constexpr std::pair<std::string_view, SHADE::SH_SHADER_TYPE> SHADER_IDENTIFIERS[
}; };
constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 }; constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 };
// Error flags
constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
#endif // !SH_ASSET_MACROS_H #endif // !SH_ASSET_MACROS_H

View File

@ -83,7 +83,7 @@ namespace SHADE
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{ {
if (!IsRecognised(path.extension().string().c_str())) if (!SHFileSystem::IsRecognised(path.extension().string().c_str()))
{ {
//TODO:ASSERT UNRECOGNISED FILE TYPE //TODO:ASSERT UNRECOGNISED FILE TYPE
return std::filesystem::path(); return std::filesystem::path();
@ -380,19 +380,6 @@ namespace SHADE
BuildAssetCollection(); BuildAssetCollection();
} }
bool SHAssetManager::IsRecognised(char const* ext) noexcept
{
for (auto const& e : EXTENSIONS)
{
if (strcmp(ext, e.data()) == 0)
{
return true;
}
}
return false;
}
SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept
{ {
SHAsset result; SHAsset result;
@ -405,51 +392,6 @@ namespace SHADE
return result; return result;
} }
void SHAssetManager::CompileAll() noexcept
{
std::vector<AssetPath> paths;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
AssetPath newPath;
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newPath = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
}
else if (ext == DDS_EXTENSION.data())
{
newPath = SHTextureCompiler::CompileTextureAsset(path).value();
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::string command = MODEL_COMPILER_EXE.data();
command += " " + path.string();
std::system(command.c_str());
std::string modelPath = path.string().substr(0, path.string().find_last_of('.'));
modelPath += MODEL_EXTENSION;
newPath = modelPath;
}
GenerateNewMeta(newPath);
}
}
bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept
{ {
//TODO Move this to dedicated library //TODO Move this to dedicated library
@ -545,7 +487,7 @@ namespace SHADE
{ {
} }
void SHAssetManager::GenerateNewMeta(AssetPath path) noexcept std::optional<AssetID> SHAssetManager::GenerateNewMeta(AssetPath path) noexcept
{ {
auto const ext = path.extension().string(); auto const ext = path.extension().string();
if (ext == SHADER_BUILT_IN_EXTENSION.data()) if (ext == SHADER_BUILT_IN_EXTENSION.data())
@ -606,11 +548,32 @@ namespace SHADE
SHAssetMetaHandler::WriteMetaData(assetCollection[newAsset.id]); SHAssetMetaHandler::WriteMetaData(assetCollection[newAsset.id]);
} }
else if (ext == SCRIPT_EXTENSION)
{
SHAsset newAsset{
path.stem().string(),
GenerateAssetID(AssetType::SCRIPT),
AssetType::SCRIPT,
path,
false
};
assetCollection.emplace(newAsset.id, newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
} }
void SHAssetManager::BuildAssetCollection() noexcept void SHAssetManager::BuildAssetCollection() noexcept
{ {
SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection); std::vector<SHFile*> toGenNew;
SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection, toGenNew);
for (auto& file : toGenNew)
{
auto newID{ GenerateNewMeta(file->path).value() };
file->assetMeta = &assetCollection[newID];
}
for (auto& asset : std::ranges::views::values(assetCollection)) for (auto& asset : std::ranges::views::values(assetCollection))
{ {

View File

@ -99,16 +99,12 @@ namespace SHADE
static SHAssetData* LoadData(SHAsset const& asset) noexcept; static SHAssetData* LoadData(SHAsset const& asset) noexcept;
static SHAssetData* LoadSubData(SHAsset const& asset) noexcept; static SHAssetData* LoadSubData(SHAsset const& asset) noexcept;
static void LoadNewData(AssetPath path) noexcept; static void LoadNewData(AssetPath path) noexcept;
static void GenerateNewMeta(AssetPath path) noexcept; static std::optional<AssetID> GenerateNewMeta(AssetPath path) noexcept;
inline static void BuildAssetCollection() noexcept; inline static void BuildAssetCollection() noexcept;
static bool IsRecognised(char const*) noexcept;
static SHAsset CreateAssetFromPath(AssetPath path) noexcept; static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
static void CompileAll() noexcept;
static bool DeleteLocalFile(AssetPath path) noexcept; static bool DeleteLocalFile(AssetPath path) noexcept;
//TODO use this function to create asset data internall at all calls to generate id //TODO use this function to create asset data internall at all calls to generate id

View File

@ -38,7 +38,7 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetType SHAssetMetaHandler::GetTypeFromExtension(AssetExtension ext) noexcept AssetType SHAssetMetaHandler::GetTypeFromExtension(AssetExtension ext) noexcept
{ {
for (int i{0}; i < EXTENSIONS->size(); ++i) for (auto i{0}; i < EXTENSIONS_COUNT; ++i)
{ {
if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0) if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0)
{ {
@ -98,6 +98,7 @@ namespace SHADE
meta.type = static_cast<AssetType>(type); meta.type = static_cast<AssetType>(type);
meta.isSubAsset = false; meta.isSubAsset = false;
meta.parent = 0;
// Burn Line // Burn Line
if (std::getline(metaFile, line)) if (std::getline(metaFile, line))

View File

@ -7,13 +7,15 @@
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include <math.h> #include <math.h>
#include "Scene/SHSceneManager.h"
namespace SHADE namespace SHADE
{ {
void SHCameraSystem::UpdateEditorCamera(double dt) noexcept void SHCameraSystem::UpdateEditorCamera(double dt) noexcept
{ {
auto& camera = editorCamera; auto& camera = editorCamera;
SHVec3 view, right, UP; SHVec3 view, right, UP;
GetCameraAxis(camera, view, right, UP); GetCameraAxis(camera, view, right, UP);
@ -61,63 +63,43 @@ namespace SHADE
} }
UpdateCameraComponent(editorCamera); UpdateCameraComponent(editorCamera);
}
} void SHCameraSystem::UpdateEditorArm(double dt,bool active ,SHVec3 const& targetPos) noexcept
void SHCameraSystem::EditorCameraUpdate::Execute(double dt) noexcept
{ {
SHCameraSystem* system = static_cast<SHCameraSystem*>(GetSystem()); if (active == false)
auto& camera = system->editorCamera; {
SHVec3 view, right, UP; editorCameraArm.offset = SHVec3{0.0f};
system->GetCameraAxis(camera, view, right, UP); return;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) editorCamera.SetPosition(targetPos);
{
//std::cout << "Camera movement: "<<right.x<<", " << right.y << std::endl;
camera.position -= right * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D))
{
camera.position += right * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W))
{
camera.position += view * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S))
{
camera.position -= view * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::Q))
{
camera.position += UP * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::E))
{
camera.position -= UP * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::RMB))
{
double mouseX, mouseY; double mouseX, mouseY;
SHInputManager::GetMouseVelocity(&mouseX,&mouseY); SHInputManager::GetMouseVelocity(&mouseX, &mouseY);
//std::cout << camera.yaw << std::endl; editorCameraArm.pitch -= mouseY * dt * editorCamera.turnSpeed.x;
editorCameraArm.yaw -= mouseX * dt * editorCamera.turnSpeed.y;
constexpr float pitchClamp = 85.0f;
if (editorCameraArm.pitch > pitchClamp)
editorCameraArm.pitch = pitchClamp;
if (editorCameraArm.pitch < -pitchClamp)
editorCameraArm.pitch = -pitchClamp;
editorCameraArm.armLength -= SHInputManager::GetMouseWheelVerticalDelta() * dt;
if (editorCameraArm.armLength < 1.0f)
editorCameraArm.armLength = 1.0f;
UpdatePivotArmComponent(editorCameraArm);
editorCamera.offset = editorCameraArm.GetOffset();
CameraLookAt(editorCamera, targetPos);
camera.pitch -= mouseY * dt * camera.turnSpeed.x;
camera.yaw -= mouseX * dt * camera.turnSpeed.y;
camera.dirtyView = true;
} }
//std::cout << "Camera position: " << camera.position.x << " " << camera.position.y << std::endl;
system->UpdateCameraComponent(system->editorCamera);
system->DecomposeViewMatrix(camera.viewMatrix, camera.pitch, camera.yaw, camera.roll, camera.position);
}
void SHCameraSystem::Init(void) void SHCameraSystem::Init(void)
{ {
@ -164,6 +146,9 @@ namespace SHADE
void SHCameraSystem::UpdateCameraComponent(SHCameraComponent& camera) noexcept void SHCameraSystem::UpdateCameraComponent(SHCameraComponent& camera) noexcept
{ {
if (camera.isActive == false)
return;
if (SHComponentManager::HasComponent<SHTransformComponent>(camera.GetEID()) == true && &camera != &editorCamera) if (SHComponentManager::HasComponent<SHTransformComponent>(camera.GetEID()) == true && &camera != &editorCamera)
{ {
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID()); auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID());
@ -183,11 +168,17 @@ namespace SHADE
if (SHComponentManager::HasComponent<SHCameraArmComponent>(camera.GetEID())) if (SHComponentManager::HasComponent<SHCameraArmComponent>(camera.GetEID()))
{ {
auto arm = SHComponentManager::GetComponent<SHCameraArmComponent>(camera.GetEID()); auto arm = SHComponentManager::GetComponent<SHCameraArmComponent>(camera.GetEID());
if (arm->isActive == true)
{
camera.offset = arm->GetOffset(); camera.offset = arm->GetOffset();
if(arm->lookAtCameraOrigin) if (arm->lookAtCameraOrigin)
CameraLookAt(camera, camera.position); CameraLookAt(camera, camera.position);
} }
}
SHVec3 view, right, UP; SHVec3 view, right, UP;
@ -287,11 +278,13 @@ namespace SHADE
for (auto& pivot : pivotDense) for (auto& pivot : pivotDense)
{ {
if(SHSceneManager::CheckNodeAndComponentsActive<SHCameraArmComponent>(pivot.GetEID()))
system->UpdatePivotArmComponent(pivot); system->UpdatePivotArmComponent(pivot);
} }
for (auto& cam : dense) for (auto& cam : dense)
{ {
if (SHSceneManager::CheckNodeAndComponentsActive<SHCameraComponent>(cam.GetEID()))
system->UpdateCameraComponent(cam); system->UpdateCameraComponent(cam);
} }
for (auto& handle : system->directorHandleList) for (auto& handle : system->directorHandleList)
@ -399,7 +392,7 @@ namespace SHADE
SHVec3 up = { 0.0f,1.0f,0.0f }; SHVec3 up = { 0.0f,1.0f,0.0f };
////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll)); //SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll));
//target = SHVec3::Normalise(target); //target = SHVec3::Normalise(target);

View File

@ -5,6 +5,7 @@
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "Resource/SHResourceLibrary.h" #include "Resource/SHResourceLibrary.h"
#include "SHCameraDirector.h" #include "SHCameraDirector.h"
#include "SHCameraArmComponent.h"
#include "SH_API.h" #include "SH_API.h"
namespace SHADE namespace SHADE
@ -18,6 +19,7 @@ namespace SHADE
//A camera component that represents editor camera. //A camera component that represents editor camera.
//This is not tied to any entity. Hence this EID should not be used. //This is not tied to any entity. Hence this EID should not be used.
SHCameraComponent editorCamera; SHCameraComponent editorCamera;
SHCameraArmComponent editorCameraArm;
SHResourceLibrary<SHCameraDirector> directorLibrary; SHResourceLibrary<SHCameraDirector> directorLibrary;
std::vector<DirectorHandle> directorHandleList; std::vector<DirectorHandle> directorHandleList;
@ -34,14 +36,7 @@ namespace SHADE
void Init (void); void Init (void);
void Exit (void); void Exit (void);
class SH_API EditorCameraUpdate final : public SHSystemRoutine
{
public:
EditorCameraUpdate() : SHSystemRoutine("Editor Camera Update", true) { };
virtual void Execute(double dt) noexcept override final;
};
friend class EditorCameraUpdate; friend class EditorCameraUpdate;
class SH_API CameraSystemUpdate final: public SHSystemRoutine class SH_API CameraSystemUpdate final: public SHSystemRoutine
@ -63,6 +58,7 @@ namespace SHADE
void DecomposeViewMatrix(SHMatrix const& matrix, float& pitch, float& yaw, float& roll, SHVec3& pos) noexcept; void DecomposeViewMatrix(SHMatrix const& matrix, float& pitch, float& yaw, float& roll, SHVec3& pos) noexcept;
void SetCameraViewMatrix(SHCameraComponent& camera, SHMatrix const& viewMatrix) noexcept; void SetCameraViewMatrix(SHCameraComponent& camera, SHMatrix const& viewMatrix) noexcept;
void CameraLookAt(SHCameraComponent& camera, SHVec3 target) noexcept; void CameraLookAt(SHCameraComponent& camera, SHVec3 target) noexcept;
void UpdateEditorArm(double dt,bool active ,SHVec3 const& targetPos) noexcept;
}; };

View File

@ -10,63 +10,102 @@
namespace SHADE namespace SHADE
{ {
SHCommandManager::CommandStack SHCommandManager::undoStack{};
SHCommandManager::CommandStack SHCommandManager::redoStack{}; SHCommandManager::CommandStack SHCommandManager::undoStack(defaultStackSize);
SHCommandManager::CommandStack SHCommandManager::redoStack(defaultStackSize);
SHCommandManager::CommandStack SHCommandManager::secondaryUndoStack(defaultStackSize);
SHCommandManager::CommandStack SHCommandManager::secondaryRedoStack(defaultStackSize);
SHCommandManager::CommandStackPtr SHCommandManager::pCurrUndoStack(&undoStack);
SHCommandManager::CommandStackPtr SHCommandManager::pCurrRedoStack(&redoStack);
void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue) void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
{ {
redoStack = CommandStack(); *pCurrRedoStack = CommandStack(defaultStackSize);
commandPtr->Execute(); commandPtr->Execute();
if (overrideValue && !undoStack.empty()) if (overrideValue && !pCurrUndoStack->Empty())
{ {
undoStack.top()->Merge(commandPtr); pCurrUndoStack->Top()->Merge(commandPtr);
} }
else else
{ {
undoStack.push(commandPtr); pCurrUndoStack->Push(commandPtr);
} }
} }
void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr) void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr)
{ {
undoStack.push(commandPtr); pCurrUndoStack->Push(commandPtr);
} }
void SHCommandManager::UndoCommand() void SHCommandManager::UndoCommand()
{ {
if (undoStack.empty()) if (pCurrUndoStack->Empty())
return; return;
undoStack.top()->Undo(); pCurrUndoStack->Top()->Undo();
redoStack.push(undoStack.top()); pCurrRedoStack->Push(pCurrUndoStack->Top());
undoStack.pop(); pCurrUndoStack->Pop();
} }
void SHCommandManager::RedoCommand() void SHCommandManager::RedoCommand()
{ {
if (redoStack.empty()) if (pCurrRedoStack->Empty())
return; return;
redoStack.top()->Execute(); pCurrRedoStack->Top()->Execute();
undoStack.push(redoStack.top()); pCurrUndoStack->Push(pCurrRedoStack->Top());
redoStack.pop(); pCurrRedoStack->Pop();
} }
std::size_t SHCommandManager::GetUndoStackSize() std::size_t SHCommandManager::GetUndoStackSize()
{ {
return undoStack.size(); return pCurrUndoStack->Size();
} }
std::size_t SHCommandManager::GetRedoStackSize() std::size_t SHCommandManager::GetRedoStackSize()
{ {
return redoStack.size(); return pCurrRedoStack->Size();
} }
void SHCommandManager::PopLatestCommandFromRedoStack() void SHCommandManager::PopLatestCommandFromRedoStack()
{ {
redoStack.pop(); pCurrRedoStack->Pop();
} }
void SHCommandManager::PopLatestCommandFromUndoStack() void SHCommandManager::PopLatestCommandFromUndoStack()
{ {
undoStack.pop(); pCurrUndoStack->Pop();
} }
void SHCommandManager::SwapStacks()
{
if (pCurrUndoStack == &undoStack)
{
pCurrUndoStack = &secondaryUndoStack;
}
else
{
secondaryUndoStack.Clear();
pCurrUndoStack = &undoStack;
}
if (pCurrRedoStack == &redoStack)
{
pCurrRedoStack = &secondaryRedoStack;
}
else
{
secondaryRedoStack.Clear();
pCurrRedoStack = &redoStack;
}
}
void SHCommandManager::ClearAll()
{
undoStack.Clear();
redoStack.Clear();
secondaryUndoStack.Clear();
secondaryRedoStack.Clear();
}
}//namespace SHADE }//namespace SHADE

View File

@ -10,6 +10,7 @@
//#==============================================================# //#==============================================================#
#include "SHCommand.hpp" #include "SHCommand.hpp"
#include "SH_API.h" #include "SH_API.h"
#include "Tools/SHDeque.h"
namespace SHADE namespace SHADE
{ {
@ -22,7 +23,8 @@ namespace SHADE
using BaseCommandPtr = std::shared_ptr<SHBaseCommand>; using BaseCommandPtr = std::shared_ptr<SHBaseCommand>;
template<typename T> template<typename T>
using SHCommandPtr = std::shared_ptr<SHCommand<T>>; using SHCommandPtr = std::shared_ptr<SHCommand<T>>;
using CommandStack = std::stack<BaseCommandPtr>; using CommandStack = SHDeque<BaseCommandPtr>;
using CommandStackPtr = CommandStack*;
static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false); static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false);
static void RegisterCommand(BaseCommandPtr commandPtr); static void RegisterCommand(BaseCommandPtr commandPtr);
@ -34,8 +36,17 @@ namespace SHADE
static void PopLatestCommandFromRedoStack(); static void PopLatestCommandFromRedoStack();
static void PopLatestCommandFromUndoStack(); static void PopLatestCommandFromUndoStack();
static void SwapStacks();
static void ClearAll();
static constexpr CommandStack::SizeType defaultStackSize = 100;
private: private:
static CommandStackPtr pCurrUndoStack;
static CommandStackPtr pCurrRedoStack;
static CommandStack undoStack; static CommandStack undoStack;
static CommandStack secondaryUndoStack;
static CommandStack redoStack; static CommandStack redoStack;
static CommandStack secondaryRedoStack;
}; };
}//namespace SHADE }//namespace SHADE

View File

@ -13,11 +13,12 @@
#include "Editor/SHEditor.h" #include "Editor/SHEditor.h"
#include "Editor/DragDrop/SHDragDrop.hpp" #include "Editor/DragDrop/SHDragDrop.hpp"
#include "Editor/EditorWindow/MaterialInspector/SHMaterialInspector.h" #include "Editor/EditorWindow/MaterialInspector/SHMaterialInspector.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
namespace SHADE namespace SHADE
{ {
SHAssetBrowser::SHAssetBrowser() SHAssetBrowser::SHAssetBrowser()
:SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar), rootFolder(SHAssetManager::GetRootFolder()), prevFolder(rootFolder), currentFolder(rootFolder), assetBeingCreated(std::nullopt) :SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar), rootFolder(SHAssetManager::GetRootFolder()), prevFolder(rootFolder), currentFolder(rootFolder)
{ {
} }
@ -34,23 +35,48 @@ namespace SHADE
RecursivelyDrawTree(rootFolder); RecursivelyDrawTree(rootFolder);
DrawMenuBar(); DrawMenuBar();
DrawCurrentFolder(); DrawCurrentFolder();
DrawAssetBeingCreated();
} }
ImGui::End(); ImGui::End();
if(refreshQueued)
Refresh();
}
void SHAssetBrowser::QueueRefresh() noexcept
{
refreshQueued = true;
}
void SHAssetBrowser::Refresh() noexcept
{
SHAssetManager::RefreshDirectory();
rootFolder = SHAssetManager::GetRootFolder();
refreshQueued = false;
} }
void SHAssetBrowser::DrawMenuBar() void SHAssetBrowser::DrawMenuBar()
{ {
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
if(ImGui::SmallButton(ICON_MD_SYNC))
{
QueueRefresh();
}
if(ImGui::SmallButton(ICON_FA_CIRCLE_PLUS))
{
isAssetBeingCreated = true;
}
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
} }
//if !compiled, set genMeta to true
ImRect SHAssetBrowser::RecursivelyDrawTree(FolderPointer folder) ImRect SHAssetBrowser::RecursivelyDrawTree(FolderPointer folder)
{ {
auto const& subFolders = folder->subFolders; auto const& subFolders = folder->subFolders;
auto const& files = folder->files; auto files = folder->files;
const bool isSelected = std::ranges::find(selectedFolders, folder) != selectedFolders.end(); const bool isSelected = std::ranges::find(selectedFolders, folder) != selectedFolders.end();
ImGuiTreeNodeFlags flags = (subFolders.empty() && files.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow; ImGuiTreeNodeFlags flags = (subFolders.empty() && files.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow;
if (isSelected) if (isSelected)
@ -62,21 +88,10 @@ namespace SHADE
ImGuiID folderID = ImGui::GetItemID(); ImGuiID folderID = ImGui::GetItemID();
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
if (ImGui::BeginPopupContextItem()) //if (ImGui::BeginPopupContextItem())
{ //{
if (ImGui::BeginMenu("Create Asset")) // ImGui::EndPopup();
{ //}
//TODO: Change to rttr type enum align
if (ImGui::Selectable("Material"))
{
assetBeingCreated = { folder, AssetType::MATERIAL, "New Material" };
ImGui::TreeNodeSetOpen(folderID, true);
isOpen = true;
}
ImGui::EndMenu();
}
ImGui::EndPopup();
}
if (ImGui::IsItemClicked()) if (ImGui::IsItemClicked())
{ {
@ -100,19 +115,15 @@ namespace SHADE
drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1); drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1);
vertLineEnd.y = midPoint; vertLineEnd.y = midPoint;
} }
for (auto const& file : files) for (auto& file : files)
{ {
if(file.assetMeta == nullptr)
continue;
const float horizontalLineSize = 25.0f; const float horizontalLineSize = 25.0f;
const ImRect childRect = DrawFile(file.assetMeta); const ImRect childRect = DrawFile(file);
const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f; const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f;
drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1); drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1);
vertLineEnd.y = midPoint; vertLineEnd.y = midPoint;
} }
drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 1); drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 1);
if(assetBeingCreated.has_value() && std::get<0>(assetBeingCreated.value()) == folder)
DrawAssetBeingCreated();
ImGui::TreePop(); ImGui::TreePop();
} }
@ -148,7 +159,33 @@ namespace SHADE
//} //}
} }
ImRect SHAssetBrowser::DrawFile(SHAsset const* const asset) noexcept ImRect SHAssetBrowser::DrawFile(SHFile& file) noexcept
{
if(file.compilable)
{
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf;
static constexpr std::string_view icon = ICON_MD_FILE_PRESENT;
ImGui::PushID(file.name.data());
bool const isOpen = ImGui::TreeNodeEx(file.name.data(), flags, "%s %s%s", icon.data(), file.name.data(), file.ext.data());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
if(ImGui::BeginPopupContextItem())
{
if(ImGui::Selectable("Compile"))
{
SHAssetManager::CompileAsset(file.path, !file.compiled);
QueueRefresh();
}
ImGui::EndPopup();
}
ImGui::TreePop();
ImGui::PopID();
return nodeRect;
}
if(file.assetMeta)
DrawAsset(file.assetMeta, file.ext);
}
ImRect SHAssetBrowser::DrawAsset(SHAsset const* const asset, FileExt const& ext /*= ""*/) noexcept
{ {
if (asset == nullptr) if (asset == nullptr)
return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
@ -173,7 +210,7 @@ namespace SHADE
default:; default:;
} }
bool const isOpen = ImGui::TreeNodeEx(asset, flags, "%s %s", icon.data(), asset->name.data()); bool const isOpen = ImGui::TreeNodeEx(asset, flags, "%s %s%s", icon.data(), asset->name.data(), ext.data());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
if (SHDragDrop::BeginSource()) if (SHDragDrop::BeginSource())
{ {
@ -212,7 +249,6 @@ namespace SHADE
case AssetType::MAX_COUNT: break; case AssetType::MAX_COUNT: break;
default:; default:;
} }
} }
//TODO: Combine Draw asset and Draw Folder recursive drawing //TODO: Combine Draw asset and Draw Folder recursive drawing
@ -227,7 +263,7 @@ namespace SHADE
for(auto const& subAsset : asset->subAssets) for(auto const& subAsset : asset->subAssets)
{ {
const float horizontalLineSize = 25.0f; const float horizontalLineSize = 25.0f;
const ImRect childRect = DrawFile(subAsset); const ImRect childRect = DrawAsset(subAsset);
const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f; const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f;
drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1); drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1);
vertLineEnd.y = midPoint; vertLineEnd.y = midPoint;
@ -240,19 +276,52 @@ namespace SHADE
void SHAssetBrowser::DrawAssetBeingCreated() noexcept void SHAssetBrowser::DrawAssetBeingCreated() noexcept
{ {
if (!assetBeingCreated.has_value()) if(isAssetBeingCreated)
return; ImGui::OpenPopup(newAssetPopup.data());
auto& path = std::get<0>(assetBeingCreated.value());
auto& type = std::get<1>(assetBeingCreated.value()); if(ImGui::BeginPopupModal(newAssetPopup.data(), &isAssetBeingCreated))
auto& assetName = std::get<2>(assetBeingCreated.value());
if (ImGui::InputText("##newAssetName", &assetName, ImGuiInputTextFlags_EnterReturnsTrue))
{ {
AssetID assetId = SHAssetManager::CreateNewAsset(type, assetName); ImGui::RadioButton("Material", true);
ImGui::SameLine();
if (ImGui::InputText("##newAssetName", &nameOfAssetBeingCreated, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_AutoSelectAll))
{
AssetID assetId = SHAssetManager::CreateNewAsset(AssetType::MATERIAL, nameOfAssetBeingCreated);
if (auto matInspector = SHEditorWindowManager::GetEditorWindow<SHMaterialInspector>()) if (auto matInspector = SHEditorWindowManager::GetEditorWindow<SHMaterialInspector>())
{ {
matInspector->OpenMaterial(assetId, true); matInspector->OpenMaterial(assetId, true);
} }
assetBeingCreated.reset(); nameOfAssetBeingCreated.clear();
QueueRefresh();
isAssetBeingCreated = false;
ImGui::CloseCurrentPopup();
} }
ImGui::EndPopup();
}
//if (ImGui::BeginMenu("Create Asset"))
//{
// //TODO: Change to rttr type enum align
// if (ImGui::Selectable("Material"))
// {
// assetBeingCreated = { folder, AssetType::MATERIAL, "NewMaterial" };
// ImGui::TreeNodeSetOpen(folderID, true);
// isOpen = true;
// }
// ImGui::EndMenu();
//}
//if (!assetBeingCreated.has_value())
// return;
//auto& path = std::get<0>(assetBeingCreated.value());
//auto& type = std::get<1>(assetBeingCreated.value());
//auto& assetName = std::get<2>(assetBeingCreated.value());
//if (ImGui::InputText("##newAssetName", &assetName, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_AutoSelectAll))
//{
// AssetID assetId = SHAssetManager::CreateNewAsset(type, assetName);
// if (auto matInspector = SHEditorWindowManager::GetEditorWindow<SHMaterialInspector>())
// {
// matInspector->OpenMaterial(assetId, true);
// }
// assetBeingCreated.reset();
// QueueRefresh();
//}
} }
} }

View File

@ -10,24 +10,29 @@ namespace SHADE
class SHAssetBrowser final : public SHEditorWindow class SHAssetBrowser final : public SHEditorWindow
{ {
public: public:
using AssetEntry = std::tuple<FolderPointer, AssetType, std::string>;
SHAssetBrowser(); SHAssetBrowser();
void Init(); void Init();
void Update(); void Update();
void Refresh(); void QueueRefresh() noexcept;
private: private:
void DrawMenuBar(); void DrawMenuBar();
ImRect RecursivelyDrawTree(FolderPointer folder); ImRect RecursivelyDrawTree(FolderPointer folder);
void DrawCurrentFolder(); void DrawCurrentFolder();
ImRect DrawFile(SHAsset const* const asset) noexcept; ImRect DrawFile(SHFile& file) noexcept;
ImRect DrawAsset(SHAsset const* const asset, FileExt const& ext = "") noexcept;
void DrawAssetBeingCreated() noexcept; void DrawAssetBeingCreated() noexcept;
void Refresh() noexcept;
FolderPointer rootFolder, prevFolder, currentFolder; FolderPointer rootFolder, prevFolder, currentFolder;
std::optional<AssetEntry> assetBeingCreated;
std::vector<FolderPointer> selectedFolders; std::vector<FolderPointer> selectedFolders;
std::vector<AssetID> selectedAssets; std::vector<AssetID> selectedAssets;
static constexpr float tileWidth = 50.0f; static constexpr float tileWidth = 50.0f;
bool refreshQueued = false;
bool isAssetBeingCreated = false;
static constexpr std::string_view newAssetPopup = "Create New Asset";
std::string nameOfAssetBeingCreated;
}; };
} }

View File

@ -15,6 +15,7 @@
#include "Editor/DragDrop/SHDragDrop.hpp" #include "Editor/DragDrop/SHDragDrop.hpp"
#include "Tools/SHException.h" #include "Tools/SHException.h"
#include "Editor/IconsMaterialDesign.h" #include "Editor/IconsMaterialDesign.h"
#include "SHHierarchyPanelCommands.h"
//#==============================================================# //#==============================================================#
//|| Library Includes || //|| Library Includes ||
@ -105,15 +106,22 @@ namespace SHADE
PasteEntities(editor->selectedEntities.back()); PasteEntities(editor->selectedEntities.back());
} }
} }
if(ImGui::IsKeyReleased(ImGuiKey_Delete))
{
DeleteSelectedEntities();
}
} }
} }
if(ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) if(ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
if(ImGui::IsDragDropActive())
{ {
ParentSelectedEntities(MAX_EID, draggingEntities); ParentSelectedEntities(MAX_EID, draggingEntities);
draggingEntities.clear(); draggingEntities.clear();
ImGui::ClearDragDrop(); ImGui::ClearDragDrop();
} }
}
ImGui::End(); ImGui::End();
} }
@ -255,9 +263,10 @@ namespace SHADE
PasteEntities(eid); PasteEntities(eid);
skipFrame = true; skipFrame = true;
} }
if (ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) if (ImGui::Selectable(std::format("{} Delete selected", ICON_MD_DELETE).data()))
{ {
SHEntityManager::DestroyEntity(eid); //SHEntityManager::DestroyEntity(eid);
DeleteSelectedEntities();
} }
if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
@ -282,9 +291,12 @@ namespace SHADE
} }
else editor->selectedEntities.clear(); else editor->selectedEntities.clear();
} }
else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) else
{
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
editor->selectedEntities.clear(); editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid); editor->selectedEntities.push_back(eid);
}
}//if not selected }//if not selected
else else
{ {
@ -365,6 +377,7 @@ namespace SHADE
if (eid == beginEID || eid == endEID) if (eid == beginEID || eid == endEID)
{ {
startSelecting = true; startSelecting = true;
if(std::ranges::find(editor->selectedEntities, eid) == editor->selectedEntities.end())
editor->selectedEntities.push_back(eid); editor->selectedEntities.push_back(eid);
} }
} }
@ -372,6 +385,7 @@ namespace SHADE
{ {
if (!endSelecting) if (!endSelecting)
{ {
if (std::ranges::find(editor->selectedEntities, eid) == editor->selectedEntities.end())
editor->selectedEntities.push_back(eid); editor->selectedEntities.push_back(eid);
if (eid == endEID || eid == beginEID) if (eid == endEID || eid == beginEID)
{ {
@ -397,47 +411,39 @@ namespace SHADE
void SHHierarchyPanel::CopySelectedEntities() void SHHierarchyPanel::CopySelectedEntities()
{ {
const auto editor = SHSystemManager::GetSystem<SHEditor>(); const auto editor = SHSystemManager::GetSystem<SHEditor>();
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities)); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
std::vector<EntityID> entitiesToCopy{};
std::ranges::copy_if(editor->selectedEntities, std::back_inserter(entitiesToCopy), [&sceneGraph](EntityID const& eid)
{
if(sceneGraph.GetParent(eid)->GetEntityID() == MAX_EID)
return true;
return false;
});
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(entitiesToCopy));
} }
void SHHierarchyPanel::PasteEntities(EntityID parentEID) void SHHierarchyPanel::PasteEntities(EntityID parentEID)
{ {
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), parentEID)); //SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), parentEID).front());
SHCommandManager::PerformCommand(std::make_shared<SHPasteEntitiesCommand>(SHClipboardUtilities::GetDataFromClipboard(), parentEID));
} }
void SHCreateEntityCommand::Execute() void SHHierarchyPanel::DeleteSelectedEntities()
{ {
EntityID newEID = SHEntityManager::CreateEntity(eid); const auto editor = SHSystemManager::GetSystem<SHEditor>();
if (eid == MAX_EID) auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
eid = newEID;
std::vector<EntityID> entitiesToDelete{};
std::ranges::copy_if(editor->selectedEntities, std::back_inserter(entitiesToDelete), [&sceneGraph, &selectedEntities = editor->selectedEntities](EntityID const& eid)
{
EntityID parentEID = sceneGraph.GetParent(eid)->GetEntityID();
if (parentEID == MAX_EID)
return true;
else if(std::ranges::find(selectedEntities, parentEID) == selectedEntities.end())
return true;
return false;
});
SHCommandManager::PerformCommand(std::make_shared<SHDeleteEntitiesCommand>(entitiesToDelete));
} }
void SHCreateEntityCommand::Undo()
{
SHEntityManager::DestroyEntity(eid);
}
void SHEntityParentCommand::Execute()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
}
}
void SHEntityParentCommand::Undo()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
}
}
}//namespace SHADE }//namespace SHADE

View File

@ -10,7 +10,6 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h" #include "Editor/EditorWindow/SHEditorWindow.h"
#include "Editor/Command/SHCommand.hpp"
namespace SHADE namespace SHADE
{ {
class SHSceneNode; class SHSceneNode;
@ -33,6 +32,7 @@ namespace SHADE
void SelectAllEntities(); void SelectAllEntities();
void CopySelectedEntities(); void CopySelectedEntities();
void PasteEntities(EntityID parentEID = MAX_EID); void PasteEntities(EntityID parentEID = MAX_EID);
void DeleteSelectedEntities();
bool skipFrame = false; bool skipFrame = false;
std::string filter; std::string filter;
bool isAnyNodeSelected = false; bool isAnyNodeSelected = false;
@ -41,33 +41,4 @@ namespace SHADE
};//class SHHierarchyPanel };//class SHHierarchyPanel
//Might move to a different file
class SHCreateEntityCommand final : public SHBaseCommand
{
public:
void Execute() override;
void Undo() override;
private:
EntityID eid = MAX_EID;
};
class SHEntityParentCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID oldParentEID = MAX_EID;
EntityID newParentEID = MAX_EID;
};
using EntityParentData = std::unordered_map<EntityID, Data>;
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){}
void Execute() override;
void Undo() override;
private:
std::vector<EntityID> entities;
std::unordered_map<EntityID, Data> entityParentData;
};
}//namespace SHADE }//namespace SHADE

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHHierarchyPanelCommands.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Scene/SHSceneManager.h"
#include "Serialization/SHSerialization.h"
#include "SHHierarchyPanel.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
namespace SHADE
{
void SHCreateEntityCommand::Execute()
{
EntityID newEID = SHEntityManager::CreateEntity(eid);
if (eid == MAX_EID)
eid = newEID;
}
void SHCreateEntityCommand::Undo()
{
SHEntityManager::DestroyEntity(eid);
}
void SHEntityParentCommand::Execute()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
}
}
void SHEntityParentCommand::Undo()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
}
}
void SHPasteEntitiesCommand::Execute()
{
data.createdEntities.clear();
data.createdEntities = SHSerialization::DeserializeEntitiesFromString(data.entityData, data.parentEID);
data.entityData = SHSerialization::ResolveSerializedEntityIndices(data.entityData, data.createdEntities);
SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>()->SetScrollTo(data.createdEntities.begin()->second);
}
void SHPasteEntitiesCommand::Undo()
{
for (auto const& [oldEID, newEID] : data.createdEntities)
{
SHEntityManager::DestroyEntity(newEID);
}
}
void SHDeleteEntitiesCommand::Execute()
{
if(!data.createdEntities.empty())
{
for(auto& eid : data.entitiesToDelete)
{
eid = data.createdEntities[eid];
}
}
data.entityData = SHSerialization::SerializeEntitiesToString(data.entitiesToDelete);
for (auto const& eid : data.entitiesToDelete)
{
SHEntityManager::DestroyEntity(eid);
}
}
void SHDeleteEntitiesCommand::Undo()
{
data.createdEntities = SHSerialization::DeserializeEntitiesFromString(data.entityData);
data.entityData = SHSerialization::ResolveSerializedEntityIndices(data.entityData, data.createdEntities);
}
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <unordered_map>
#include "ECS_Base/SHECSMacros.h"
#include "Editor/Command/SHCommand.hpp"
#include "Serialization/SHSerialization.h"
namespace SHADE
{
class SHCreateEntityCommand final : public SHBaseCommand
{
public:
void Execute() override;
void Undo() override;
private:
EntityID eid = MAX_EID;
};
class SHEntityParentCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID oldParentEID = MAX_EID;
EntityID newParentEID = MAX_EID;
};
using EntityParentData = std::unordered_map<EntityID, Data>;
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData) :entities(entityIDs), entityParentData(inEntityParentData) {}
void Execute() override;
void Undo() override;
private:
std::vector<EntityID> entities{};
std::unordered_map<EntityID, Data> entityParentData{};
};
class SHPasteEntitiesCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID parentEID{MAX_EID};
std::string entityData{};
SHSerialization::CreatedEntitiesList createdEntities{};
};
SHPasteEntitiesCommand() = delete;
SHPasteEntitiesCommand(std::string const& serializedEntityData, EntityID parentEid = MAX_EID):data({parentEid, serializedEntityData, {}}){}
void Execute() override;
void Undo() override;
private:
Data data;
};
class SHDeleteEntitiesCommand final : public SHBaseCommand
{
public:
struct Data
{
std::vector<EntityID> entitiesToDelete{};
SHSerialization::CreatedEntitiesList createdEntities{};
std::string entityData{};
};
SHDeleteEntitiesCommand() = delete;
SHDeleteEntitiesCommand(std::vector<EntityID> entitiesToBeDeleted): data{entitiesToBeDeleted}{}
void Execute() override;
void Undo() override;
private:
Data data;
};
}

View File

@ -15,7 +15,7 @@
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
@ -246,21 +246,21 @@ namespace SHADE
if (collider->GetType() == SHCollisionShape::Type::BOX) if (collider->GetType() == SHCollisionShape::Type::BOX)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Box #{}", 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 });
auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape()); const auto* BOX = reinterpret_cast<const SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3 SHEditorWidgets::DragVec3
( (
"Half Extents", { "X", "Y", "Z" }, "Half Extents", { "X", "Y", "Z" },
[box] { return box->GetRelativeExtents(); }, [BOX] { return BOX->GetRelativeExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
} }
else if (collider->GetType() == SHCollisionShape::Type::SPHERE) else if (collider->GetType() == SHCollisionShape::Type::SPHERE)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", 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 });
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape()); const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat SHEditorWidgets::DragFloat
( (
"Radius", "Radius",
[sphere] { return sphere->GetRelativeRadius(); }, [SPHERE] { return SPHERE->GetRelativeRadius(); },
[collider](float const& value) { collider->SetBoundingSphere(value); }); [collider](float const& value) { collider->SetBoundingSphere(value); });
} }
else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) else if (collider->GetType() == SHCollisionShape::Type::CAPSULE)

View File

@ -14,8 +14,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Camera/SHCameraComponent.h" #include "Camera/SHCameraComponent.h"
#include "Camera/SHCameraArmComponent.h" #include "Camera/SHCameraArmComponent.h"
#include "SHEditorComponentView.h" #include "SHEditorComponentView.h"
@ -93,13 +93,14 @@ namespace SHADE
{ {
EntityID const& eid = editor->selectedEntities[0]; EntityID const& eid = editor->selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid); SHEntity* entity = SHEntityManager::GetEntityByID(eid);
if(!entity) SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(eid);
if(!entity || !entityNode)
{ {
ImGui::End(); ImGui::End();
return; return;
} }
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid); ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); }); SHEditorWidgets::CheckBox("##IsActive", [entityNode]()->bool {return entityNode->IsActive(); }, [entityNode](bool const& active) {entityNode->SetActive(active); });
ImGui::SameLine(); ImGui::SameLine();
ImGui::InputText("##EntityName", &entity->name); ImGui::InputText("##EntityName", &entity->name);

View File

@ -23,7 +23,7 @@
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Serialization/Configurations/SHConfigurationManager.h" #include "Serialization/Configurations/SHConfigurationManager.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" }; const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" };
@ -223,39 +223,20 @@ namespace SHADE
{ {
if(editor->SaveScene()) if(editor->SaveScene())
{ {
const SHEditorStateChangeEvent STATE_CHANGE_EVENT editor->Play();
{
.previousState = editor->editorState
};
editor->editorState = SHEditor::State::PLAY;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_PLAY_EVENT);
} }
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::BeginDisabled(editor->editorState == SHEditor::State::PAUSE); ImGui::BeginDisabled(editor->editorState == SHEditor::State::PAUSE);
if(ImGui::SmallButton(ICON_MD_PAUSE)) if(ImGui::SmallButton(ICON_MD_PAUSE))
{ {
const SHEditorStateChangeEvent STATE_CHANGE_EVENT editor->Pause();
{
.previousState = editor->editorState
};
editor->editorState = SHEditor::State::PAUSE;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_PAUSE_EVENT);
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::BeginDisabled(editor->editorState == SHEditor::State::STOP); ImGui::BeginDisabled(editor->editorState == SHEditor::State::STOP);
if(ImGui::SmallButton(ICON_MD_STOP)) if(ImGui::SmallButton(ICON_MD_STOP))
{ {
const SHEditorStateChangeEvent STATE_CHANGE_EVENT editor->Stop();
{
.previousState = editor->editorState
};
editor->editorState = SHEditor::State::STOP;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT);
editor->LoadScene(SHSceneManager::GetCurrentSceneAssetID());
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::EndMenuBar(); ImGui::EndMenuBar();

View File

@ -0,0 +1,8 @@
#include "SHpch.h"
#include "SHEditorWindowManager.h"
namespace SHADE
{
SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{};
}

View File

@ -0,0 +1,77 @@
#pragma once
#include <memory>
#include <unordered_map>
#include "SHEditorWindow.h"
#include "Tools/SHLog.h"
namespace SHADE
{
class SH_API SHEditorWindowManager
{
public:
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
/**
* @brief Get ID for the Editor Window Type
*
* @tparam T Type of Editor Window
* @return EditorWindowID ID of Editor Window Type
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static EditorWindowID GetEditorWindowID()
{
static EditorWindowID id;
static bool idCreated = false;
if (!idCreated)
{
id = windowCount++;
idCreated = true;
}
return id;
}
/**
* @brief Create an Editor Window
*
* @tparam T Type of Editor Window to create
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static void CreateEditorWindow()
{
static bool isCreated = false;
if (!isCreated)
{
editorWindows[GetEditorWindowID<T>()] = std::make_unique<T>();
isCreated = true;
}
else
{
SHLog::Warning("Attempt to create duplicate of Editor window type");
}
}
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
}
static EditorWindowMap editorWindows;
private:
// Number of windows; used for Editor Window ID Generation
static EditorWindowID windowCount;
// Map of Editor Windows
friend class SHEditor;
};
}

View File

@ -33,12 +33,31 @@ namespace SHADE
void SHEditorViewport::Update() void SHEditorViewport::Update()
{ {
SHEditorWindow::Update(); SHEditorWindow::Update();
if (shouldUpdateCamera)
{
auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>();
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (!editor->selectedEntities.empty())
{
if (SHTransformComponent* transform = SHComponentManager::GetComponent_s<SHTransformComponent>(editor->selectedEntities.front()))
{
targetPos = transform->GetWorldPosition();
}
else
{
targetPos = {};
}
}
else
{
targetPos = {};
}
if (shouldUpdateCamera || shouldUpdateCamArm)
{
camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime()); camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime());
shouldUpdateCamera = false; shouldUpdateCamera = false;
} }
camSystem->UpdateEditorArm(SHFrameRateController::GetRawDeltaTime(), shouldUpdateCamArm, targetPos);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
if (Begin()) if (Begin())
@ -51,7 +70,6 @@ namespace SHADE
beginCursorPos = ImGui::GetCursorScreenPos(); beginCursorPos = ImGui::GetCursorScreenPos();
viewportMousePos = { mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y }; viewportMousePos = { mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y };
gfxSystem->GetMousePickSystem()->SetViewportMousePos(viewportMousePos); gfxSystem->GetMousePickSystem()->SetViewportMousePos(viewportMousePos);
ImGui::Image((ImTextureID)descriptorSet, { beginContentRegionAvailable.x, beginContentRegionAvailable.y }); ImGui::Image((ImTextureID)descriptorSet, { beginContentRegionAvailable.x, beginContentRegionAvailable.y });
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right)) if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right))
@ -64,23 +82,27 @@ namespace SHADE
shouldUpdateCamera = true; shouldUpdateCamera = true;
} }
if (ImGui::IsWindowFocused() && !ImGui::IsMouseDown(ImGuiMouseButton_Right))
shouldUpdateCamArm = ImGui::IsWindowHovered() && ImGui::IsKeyDown(ImGuiKey_LeftAlt) && ImGui::IsMouseDown(ImGuiMouseButton_Left);
if (editor->editorState != SHEditor::State::PLAY && ImGui::IsWindowFocused() && !ImGui::IsMouseDown(ImGuiMouseButton_Right))
{ {
if (ImGui::IsKeyReleased(ImGuiKey_Q)) if (ImGui::IsKeyReleased(ImGuiKey_W))
{ {
transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE; transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE;
} }
if (ImGui::IsKeyReleased(ImGuiKey_W)) if (ImGui::IsKeyReleased(ImGuiKey_E))
{ {
transformGizmo.operation = SHTransformGizmo::Operation::ROTATE; transformGizmo.operation = SHTransformGizmo::Operation::ROTATE;
} }
if (ImGui::IsKeyReleased(ImGuiKey_E)) if (ImGui::IsKeyReleased(ImGuiKey_R))
{ {
transformGizmo.operation = SHTransformGizmo::Operation::SCALE; transformGizmo.operation = SHTransformGizmo::Operation::SCALE;
} }
} }
} }
ImGuizmo::SetRect(beginCursorPos.x, beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y); ImGuizmo::SetRect(beginCursorPos.x, beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
if(editor->editorState != SHEditor::State::PLAY)
transformGizmo.Draw(); transformGizmo.Draw();
ImGui::End(); ImGui::End();
ImGui::PopStyleVar(); ImGui::PopStyleVar();

View File

@ -29,5 +29,7 @@ namespace SHADE
void DrawMenuBar() noexcept; void DrawMenuBar() noexcept;
SHVec2 beginCursorPos; SHVec2 beginCursorPos;
bool shouldUpdateCamera = false; bool shouldUpdateCamera = false;
bool shouldUpdateCamArm = false;
SHVec3 targetPos;
};//class SHEditorViewport };//class SHEditorViewport
}//namespace SHADE }//namespace SHADE

View File

@ -11,6 +11,8 @@
#include "Camera/SHCameraSystem.h" #include "Camera/SHCameraSystem.h"
#include "Editor/Command/SHCommandManager.h" #include "Editor/Command/SHCommandManager.h"
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
namespace SHADE namespace SHADE
{ {
void SHTransformGizmo::Init() void SHTransformGizmo::Init()

View File

@ -29,6 +29,7 @@
//#==============================================================# //#==============================================================#
//|| Editor Window Includes || //|| Editor Window Includes ||
//#==============================================================# //#==============================================================#
#include "EditorWindow/SHEditorWindowManager.h"
#include "EditorWindow/SHEditorWindowIncludes.h" #include "EditorWindow/SHEditorWindowIncludes.h"
//#==============================================================# //#==============================================================#
@ -77,8 +78,6 @@ namespace SHADE
//#==============================================================# //#==============================================================#
//Handle<SHVkCommandPool> SHEditor::imguiCommandPool; //Handle<SHVkCommandPool> SHEditor::imguiCommandPool;
//Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer; //Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer;
SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{};
//std::vector<EntityID> SHEditor::selectedEntities; //std::vector<EntityID> SHEditor::selectedEntities;
//#==============================================================# //#==============================================================#
@ -168,6 +167,18 @@ namespace SHADE
{ {
SHCommandManager::UndoCommand(); SHCommandManager::UndoCommand();
} }
if(ImGui::IsKeyReleased(ImGuiKey_F5))
{
Play();
}
else if (ImGui::IsKeyReleased(ImGuiKey_F6))
{
Pause();
}
else if (ImGui::IsKeyReleased(ImGuiKey_F7))
{
Stop();
}
Render(); Render();
} }
@ -597,6 +608,48 @@ namespace SHADE
} }
} }
void SHEditor::Play()
{
if(editorState == State::PLAY)
return;
if (SaveScene())
{
const SHEditorStateChangeEvent STATE_CHANGE_EVENT
{
.previousState = editorState
};
editorState = State::PLAY;
SHCommandManager::SwapStacks();
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_PLAY_EVENT);
}
}
void SHEditor::Pause()
{
if (editorState == State::PAUSE)
return;
const SHEditorStateChangeEvent STATE_CHANGE_EVENT
{
.previousState = editorState
};
editorState = State::PAUSE;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_PAUSE_EVENT);
}
void SHEditor::Stop()
{
if (editorState == State::STOP)
return;
const SHEditorStateChangeEvent STATE_CHANGE_EVENT
{
.previousState = editorState
};
editorState = SHEditor::State::STOP;
SHCommandManager::SwapStacks();
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT);
LoadScene(SHSceneManager::GetCurrentSceneAssetID());
}
void SHEditor::NewFrame() void SHEditor::NewFrame()
{ {
SDL_Event event; SDL_Event event;

View File

@ -36,73 +36,7 @@ namespace SHADE
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkCommandPool; class SHVkCommandPool;
class SHEditorWindowManager
{
public:
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
/**
* @brief Get ID for the Editor Window Type
*
* @tparam T Type of Editor Window
* @return EditorWindowID ID of Editor Window Type
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static EditorWindowID GetEditorWindowID()
{
static EditorWindowID id;
static bool idCreated = false;
if (!idCreated)
{
id = windowCount++;
idCreated = true;
}
return id;
}
/**
* @brief Create an Editor Window
*
* @tparam T Type of Editor Window to create
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static void CreateEditorWindow()
{
static bool isCreated = false;
if (!isCreated)
{
editorWindows[GetEditorWindowID<T>()] = std::make_unique<T>();
isCreated = true;
}
else
{
SHLog::Warning("Attempt to create duplicate of Editor window type");
}
}
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
}
static EditorWindowMap editorWindows;
private:
// Number of windows; used for Editor Window ID Generation
static EditorWindowID windowCount;
// Map of Editor Windows
friend class SHEditor;
};
/** /**
* @brief SHEditor static class contains editor variables and implementation of editor functions. * @brief SHEditor static class contains editor variables and implementation of editor functions.
@ -184,6 +118,10 @@ namespace SHADE
void LoadScene(AssetID const& assetID) noexcept; void LoadScene(AssetID const& assetID) noexcept;
void Play();
void Pause();
void Stop();
// List of selected entities // List of selected entities
std::vector<EntityID> selectedEntities; std::vector<EntityID> selectedEntities;

View File

@ -53,9 +53,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Organizers */ /* ImGui Wrapper Functions - Organizers */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHEditorUI::CollapsingHeader(const std::string& title) bool SHEditorUI::CollapsingHeader(const std::string& title, bool* isHovered)
{ {
return ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen); const bool OPENED = ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
if (isHovered)
*isHovered = ImGui::IsItemHovered();
return OPENED;
} }
void SHEditorUI::SameLine() void SHEditorUI::SameLine()
@ -165,8 +168,10 @@ namespace SHADE
if (isHovered) if (isHovered)
*isHovered = ImGui::IsItemHovered(); *isHovered = ImGui::IsItemHovered();
ImGui::SameLine(); ImGui::SameLine();
return ImGui::InputInt("##", &value, return ImGui::DragInt("##", &value, 0.001f,
1, 10, std::numeric_limits<int>::min(),
std::numeric_limits<int>::max(),
"%d",
ImGuiInputTextFlags_EnterReturnsTrue); ImGuiInputTextFlags_EnterReturnsTrue);
} }
bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value, bool* isHovered) bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value, bool* isHovered)
@ -190,31 +195,22 @@ namespace SHADE
if (isHovered) if (isHovered)
*isHovered = ImGui::IsItemHovered(); *isHovered = ImGui::IsItemHovered();
ImGui::SameLine(); ImGui::SameLine();
return ImGui::InputFloat("##", &value, return ImGui::DragFloat("##", &value, 0.001f,
0.1f, 1.0f, "%.3f", std::numeric_limits<float>::lowest(),
std::numeric_limits<float>::max(),
"%.3f",
ImGuiInputTextFlags_EnterReturnsTrue); ImGuiInputTextFlags_EnterReturnsTrue);
} }
bool SHEditorUI::InputDouble(const std::string& label, double& value, bool* isHovered) bool SHEditorUI::InputDouble(const std::string& label, double& value, bool* isHovered)
{ {
ImGui::Text(label.c_str()); float val = value;
if (isHovered) const bool CHANGED = InputFloat(label, val, isHovered);
*isHovered = ImGui::IsItemHovered(); if (CHANGED)
ImGui::SameLine();
return ImGui::InputDouble("##", &value,
0.1, 1.0, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
bool SHEditorUI::InputAngle(const std::string& label, double& value, bool* isHovered)
{ {
ImGui::Text(label.c_str()); value = static_cast<double>(val);
if (isHovered) }
*isHovered = ImGui::IsItemHovered(); return CHANGED;
ImGui::SameLine();
return ImGui::InputDouble("##", &value,
1.0, 45.0, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
} }
bool SHEditorUI::InputSlider(const std::string& label, int min, int max, int& value, bool* isHovered /*= nullptr*/) bool SHEditorUI::InputSlider(const std::string& label, int min, int max, int& value, bool* isHovered /*= nullptr*/)
{ {
ImGui::Text(label.c_str()); ImGui::Text(label.c_str());
@ -266,10 +262,10 @@ namespace SHADE
static const std::vector<std::string> COMPONENT_LABELS = { "X", "Y" }; static const std::vector<std::string> COMPONENT_LABELS = { "X", "Y" };
return SHEditorWidgets::DragN<float, 2>(label, COMPONENT_LABELS, { &value.x, &value.y }, 0.1f, "%.3f", float{}, float{}, 0, isHovered); return SHEditorWidgets::DragN<float, 2>(label, COMPONENT_LABELS, { &value.x, &value.y }, 0.1f, "%.3f", float{}, float{}, 0, isHovered);
} }
bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, bool* isHovered, float speed) bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, bool* isHovered)
{ {
static const std::vector<std::string> COMPONENT_LABELS = { "X", "Y", "Z"}; static const std::vector<std::string> COMPONENT_LABELS = { "X", "Y", "Z"};
return SHEditorWidgets::DragN<float, 3>(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, speed, "%.3f", float{}, float{}, 0, isHovered); return SHEditorWidgets::DragN<float, 3>(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, 0.1f, "%.3f", float{}, float{}, 0, isHovered);
} }
bool SHEditorUI::InputTextField(const std::string& label, std::string& value, bool* isHovered) bool SHEditorUI::InputTextField(const std::string& label, std::string& value, bool* isHovered)

View File

@ -85,8 +85,9 @@ namespace SHADE
/// Wraps up ImGui::CollapsingHeader(). /// Wraps up ImGui::CollapsingHeader().
/// </summary> /// </summary>
/// <param name="title">Label for the header.</param> /// <param name="title">Label for the header.</param>
/// <param name="isHovered>If set, stores the hover state of this widget.</param>
/// <returns>True if the header is open, false otherwise.</returns> /// <returns>True if the header is open, false otherwise.</returns>
static bool CollapsingHeader(const std::string& title); static bool CollapsingHeader(const std::string& title, bool* isHovered = nullptr);
static void SameLine(); static void SameLine();
static void Separator(); static void Separator();
@ -219,17 +220,6 @@ namespace SHADE
/// <returns>True if the value was changed.</returns> /// <returns>True if the value was changed.</returns>
static bool InputDouble(const std::string& label, double& value, bool* isHovered = nullptr); static bool InputDouble(const std::string& label, double& value, bool* isHovered = nullptr);
/// <summary> /// <summary>
/// Creates a decimal field widget for double input with increments of higher
/// steps meant for angle variables.
/// <br/>
/// Wraps up ImGui::InputDouble().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <param name="isHovered>If set, stores the hover state of this widget.</param>
/// <returns>True if the value was changed.</returns>
static bool InputAngle(const std::string& label, double& value, bool* isHovered = nullptr);
/// <summary>
/// Creates an int slider field widget for double input. /// Creates an int slider field widget for double input.
/// <br/> /// <br/>
/// Wraps up ImGui::SliderInt(). /// Wraps up ImGui::SliderInt().
@ -296,7 +286,7 @@ namespace SHADE
/// <param name="value">Reference to the variable to store the result.</param> /// <param name="value">Reference to the variable to store the result.</param>
/// <param name="isHovered>If set, stores the hover state of this widget.</param> /// <param name="isHovered>If set, stores the hover state of this widget.</param>
/// <returns>True if the value was changed.</returns> /// <returns>True if the value was changed.</returns>
static bool InputVec3(const std::string& label, SHVec3& value, bool* isHovered = nullptr, float speed = 0.1f); static bool InputVec3(const std::string& label, SHVec3& value, bool* isHovered = nullptr);
/// <summary> /// <summary>
/// Creates a text field widget for string input. /// Creates a text field widget for string input.
/// <br/> /// <br/>

View File

@ -25,6 +25,19 @@ namespace SHADE
return true; return true;
} }
bool SHFileSystem::IsRecognised(char const* ext) noexcept
{
for (auto const& e : EXTENSIONS)
{
if (strcmp(ext, e.data()) == 0)
{
return true;
}
}
return false;
}
bool SHFileSystem::IsCompilable(std::string ext) noexcept bool SHFileSystem::IsCompilable(std::string ext) noexcept
{ {
for (auto const& external : EXTERNALS) for (auto const& external : EXTERNALS)
@ -38,7 +51,46 @@ namespace SHADE
return false; return false;
} }
void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept bool SHFileSystem::MatchExtention(FileExt raw, FileExt compiled) noexcept
{
if (raw == GLSL_EXTENSION)
{
if (compiled == SHADER_EXTENSION ||
compiled == SHADER_BUILT_IN_EXTENSION)
{
return true;
}
}
else if (raw == DDS_EXTENSION)
{
if (compiled == TEXTURE_EXTENSION)
{
return true;
}
}
else if (raw == FBX_EXTENSION)
{
if (compiled == MODEL_EXTENSION)
{
return true;
}
}
else if (raw == GLTF_EXTENSION)
{
if (compiled == MODEL_EXTENSION)
{
return true;
}
}
return false;
}
void SHFileSystem::BuildDirectory(
FolderPath path,
FolderPointer& root,
std::unordered_map<AssetID, SHAsset>& assetCollection,
std::vector<SHFile*>& toGenerate) noexcept
{ {
std::stack<FolderPointer> folderStack; std::stack<FolderPointer> folderStack;
root = new SHFolder("root"); root = new SHFolder("root");
@ -52,6 +104,7 @@ namespace SHADE
std::vector<SHAsset> assets; std::vector<SHAsset> assets;
// Get all subfolders/files in this current folder
for (auto& dirEntry : std::filesystem::directory_iterator(folder->path)) for (auto& dirEntry : std::filesystem::directory_iterator(folder->path))
{ {
auto path = dirEntry.path(); auto path = dirEntry.path();
@ -60,8 +113,6 @@ namespace SHADE
{ {
if (path.extension().string() == META_EXTENSION) if (path.extension().string() == META_EXTENSION)
{ {
//auto asset = SHAssetMetaHandler::RetrieveMetaData(path);
//assetCollection.insert({ asset.id, asset });
assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path)); assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path));
} }
else else
@ -71,31 +122,93 @@ namespace SHADE
path.string(), path.string(),
path.extension().string(), path.extension().string(),
nullptr, nullptr,
IsCompilable(path.extension().string()) IsCompilable(path.extension().string()),
false
); );
} }
continue; continue;
} }
// If item is folder
if (path.stem().string() == "bin"
|| path.stem().string() == "obj"
|| !std::filesystem::exists(path))
{
SHLOG_INFO("[FileSystem] Skipped paths in directory building: {}", path.string());
continue;
}
auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) }; auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
folderStack.push(newFolder); folderStack.push(newFolder);
} }
for (auto& file : folder->files)
{
if (!IsRecognised(file.ext.c_str()))
{
continue;
}
bool found{ false };
for (auto const& asset : assets) for (auto const& asset : assets)
{ {
assetCollection.emplace(asset.id, asset); assetCollection.emplace(asset.id, asset);
for(auto& file : folder->files)
{
if (file.name == asset.name) if (file.name == asset.name)
{ {
AssetPath path{ file.path }; AssetPath path{ file.path };
if (SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()) == asset.type) if (SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()) == asset.type)
{ {
file.assetMeta = &assetCollection[asset.id]; file.assetMeta = &assetCollection[asset.id];
found = true;
break; break;
} }
} }
} }
if (!found)
{
toGenerate.push_back(&file);
}
}
//for (auto const& asset : assets)
//{
// assetCollection.emplace(asset.id, asset);
// for(auto& file : folder->files)
// {
// if (file.name == asset.name)
// {
// AssetPath path{ file.path };
// if (SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()) == asset.type)
// {
// file.assetMeta = &assetCollection[asset.id];
// break;
// }
// }
// }
//}
for (auto i {0}; i < folder->files.size(); ++i)
{
auto& file = folder->files[i];
if (file.compilable)
{
for (auto j{ 0 }; j < folder->files.size(); ++j)
{
auto& check = folder->files[j];
if (i == j || check.compilable)
{
continue;
}
if (file.name == check.name)
{
if (MatchExtention(file.ext, check.ext))
{
file.compiled = true;
}
}
}
}
} }
} }
} }

View File

@ -19,10 +19,17 @@ namespace SHADE
class SHFileSystem class SHFileSystem
{ {
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,
std::vector<SHFile*>& toGenerate) noexcept;
static void DestroyDirectory(FolderPointer root) noexcept; static void DestroyDirectory(FolderPointer root) noexcept;
static bool IsRecognised(char const*) noexcept;
private: private:
static bool DeleteFolder(FolderPointer location) noexcept; static bool DeleteFolder(FolderPointer location) noexcept;
static bool IsCompilable(std::string ext) noexcept; static bool IsCompilable(std::string ext) noexcept;
static bool MatchExtention(FileExt raw, FileExt compiled) noexcept;
}; };
} }

View File

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

View File

@ -60,7 +60,7 @@ namespace SHADE
}); });
for (uint32_t i = 1; i <= SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i) for (uint32_t i = 1; i <= SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); ++i)
{ {
lightBindings.push_back (SHVkDescriptorSetLayout::Binding lightBindings.push_back (SHVkDescriptorSetLayout::Binding
{ {

View File

@ -317,13 +317,14 @@ namespace SHADE
void SHDebugDrawSystem::drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius) void SHDebugDrawSystem::drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius)
{ {
if (spherePoints.empty()) //if (spherePoints.empty())
{ {
spherePoints.clear();
// Generate // Generate
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] * radius); spherePoints.emplace_back(SPHERE.VertexPositions[idx] * radius + pos);
} }
} }
drawLineSet(storage, color, spherePoints.begin(), spherePoints.end()); drawLineSet(storage, color, spherePoints.begin(), spherePoints.end());

View File

@ -379,7 +379,7 @@ namespace SHADE
SHComponentManager::CreateComponentSparseSet<SHLightComponent>(); SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device; logicalDevice = device;
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES }; std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
std::fill (variableSizes.begin(), variableSizes.end(), 1); std::fill (variableSizes.begin(), variableSizes.end(), 1);
@ -431,7 +431,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::Run(SHMatrix const& viewMat, uint32_t frameIndex) noexcept void SHLightingSubSystem::Run(SHMatrix const& viewMat, uint32_t frameIndex) noexcept
{ {
static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>(); auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false; bool expanded = false;
@ -451,7 +451,7 @@ namespace SHADE
for (auto& light : lightComps) for (auto& light : lightComps)
{ {
auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type); auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it // First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer. // isn't, we write it to the correct buffer.
@ -491,7 +491,7 @@ namespace SHADE
// is a new buffer. If some expansion was detected, update descriptor sets. // is a new buffer. If some expansion was detected, update descriptor sets.
if (expanded) if (expanded)
{ {
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i) for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{ {
UpdateDescSet(i); UpdateDescSet(i);

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHPhysicsUtils.cpp * \file SHCollisionInfo.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for some Physics Utilities * \brief Implementation for Collision Info.
* *
* \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
@ -11,7 +11,7 @@
#include <SHpch.h> #include <SHpch.h>
// Primary Header // Primary Header
#include "SHPhysicsUtils.h" #include "SHCollisionInfo.h"
namespace SHADE namespace SHADE
{ {
@ -19,7 +19,7 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHCollisionEvent::SHCollisionEvent() noexcept SHCollisionInfo::SHCollisionInfo() noexcept
: collisionState { State::INVALID } : collisionState { State::INVALID }
{ {
ids[ENTITY_A] = MAX_EID; ids[ENTITY_A] = MAX_EID;
@ -28,7 +28,7 @@ namespace SHADE
ids[COLLIDER_B] = std::numeric_limits<uint32_t>::max(); ids[COLLIDER_B] = std::numeric_limits<uint32_t>::max();
} }
SHCollisionEvent::SHCollisionEvent(EntityID entityA, EntityID entityB) noexcept SHCollisionInfo::SHCollisionInfo(EntityID entityA, EntityID entityB) noexcept
: collisionState { State::INVALID } : collisionState { State::INVALID }
{ {
ids[ENTITY_A] = entityA; ids[ENTITY_A] = entityA;
@ -41,12 +41,12 @@ namespace SHADE
/* Operator Overload Definitions */ /* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHCollisionEvent::operator==(const SHCollisionEvent& rhs) const noexcept bool SHCollisionInfo::operator==(const SHCollisionInfo& rhs) const noexcept
{ {
return value[0] == rhs.value[0] && value[1] == rhs.value[1]; return value[0] == rhs.value[0] && value[1] == rhs.value[1];
} }
bool SHCollisionEvent::operator!=(const SHCollisionEvent& rhs) const noexcept bool SHCollisionInfo::operator!=(const SHCollisionInfo& rhs) const noexcept
{ {
return value[0] != rhs.value[0] || value[1] != rhs.value[1]; return value[0] != rhs.value[0] || value[1] != rhs.value[1];
} }
@ -55,37 +55,37 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
EntityID SHCollisionEvent::GetEntityA() const noexcept EntityID SHCollisionInfo::GetEntityA() const noexcept
{ {
return ids[ENTITY_A]; return ids[ENTITY_A];
} }
EntityID SHCollisionEvent::GetEntityB() const noexcept EntityID SHCollisionInfo::GetEntityB() const noexcept
{ {
return ids[ENTITY_B]; return ids[ENTITY_B];
} }
const SHRigidBodyComponent* SHCollisionEvent::GetRigidBodyA() const noexcept const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyA() const noexcept
{ {
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_A]); return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_A]);
} }
const SHRigidBodyComponent* SHCollisionEvent::GetRigidBodyB() const noexcept const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyB() const noexcept
{ {
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]); return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]);
} }
const SHCollisionShape* SHCollisionEvent::GetColliderA() const noexcept const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept
{ {
return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]); return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]);
} }
const SHCollisionShape* SHCollisionEvent::GetColliderB() const noexcept const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept
{ {
return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]); return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]);
} }
SHCollisionEvent::State SHCollisionEvent::GetCollisionState() const noexcept SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept
{ {
return collisionState; return collisionState;
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHPhysicsUtils.h * \file SHCollisionInfo.h
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for some Physics Utilities * \brief Interface for Collision Information for Collision & Triggers.
* *
* \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
@ -11,8 +11,8 @@
#pragma once #pragma once
// Project Headers // Project Headers
#include "Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
namespace SHADE namespace SHADE
@ -21,27 +21,14 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
struct SHPhysicsColliderAddedEvent class SH_API SHCollisionInfo
{
EntityID entityID;
SHCollisionShape::Type colliderType;
int colliderIndex;
};
struct SHPhysicsColliderRemovedEvent
{
EntityID entityID;
int colliderIndex;
};
class SH_API SHCollisionEvent
{ {
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Friends */ /* Friends */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem; friend class SHCollisionListener;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -62,23 +49,23 @@ namespace SHADE
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHCollisionEvent () noexcept; SHCollisionInfo () noexcept;
SHCollisionEvent (EntityID entityA, EntityID entityB) noexcept; SHCollisionInfo (EntityID entityA, EntityID entityB) noexcept;
SHCollisionEvent (const SHCollisionEvent& rhs) = default; SHCollisionInfo (const SHCollisionInfo& rhs) = default;
SHCollisionEvent (SHCollisionEvent&& rhs) = default; SHCollisionInfo (SHCollisionInfo&& rhs) = default;
~SHCollisionEvent () = default; ~SHCollisionInfo () = default;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Operator Overloads */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool operator== (const SHCollisionEvent& rhs) const noexcept; bool operator== (const SHCollisionInfo& rhs) const noexcept;
bool operator!= (const SHCollisionEvent& rhs) const noexcept; bool operator!= (const SHCollisionInfo& rhs) const noexcept;
SHCollisionEvent& operator= (const SHCollisionEvent& rhs) = default; SHCollisionInfo& operator= (const SHCollisionInfo& rhs) = default;
SHCollisionEvent& operator= (SHCollisionEvent&& rhs) = default; SHCollisionInfo& operator= (SHCollisionInfo&& rhs) = default;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
@ -112,5 +99,4 @@ namespace SHADE
State collisionState; State collisionState;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,236 @@
/****************************************************************************************
* \file SHCollisionListener.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Collision Listener.
*
* \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 "SHCollisionListener.h"
// Project Headers
#include "Physics/PhysicsObject/SHPhysicsObject.h"
#include "Physics/System/SHPhysicsSystem.h"
/*-------------------------------------------------------------------------------------*/
/* Local Helper Functions */
/*-------------------------------------------------------------------------------------*/
uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID)
{
for (uint32_t i = 0; i < physicsObject.GetCollisionBody()->getNbColliders(); ++i)
{
const auto* collider = physicsObject.GetCollisionBody()->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
}
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionListener::SHCollisionListener() noexcept
: system { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
const std::vector<SHCollisionInfo>& SHCollisionListener::GetCollisionInfoContainer() const noexcept
{
return collisionInfoContainer;
}
const std::vector<SHCollisionInfo>& SHCollisionListener::GetTriggerInfoContainer() const noexcept
{
return triggerInfoContainer;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionListener::BindToSystem(SHPhysicsSystem* physicsSystem) noexcept
{
system = physicsSystem;
}
void SHCollisionListener::BindToWorld(rp3d::PhysicsWorld* world) noexcept
{
if (!world)
return;
world->setEventListener(this);
}
void SHCollisionListener::CleanContainers() noexcept
{
static const auto CLEAR = [](std::vector<SHCollisionInfo>& container)
{
for (auto eventIter = container.begin(); eventIter != container.end();)
{
const bool CLEAR_EVENT = eventIter->GetCollisionState() == SHCollisionInfo::State::EXIT
|| eventIter->GetCollisionState() == SHCollisionInfo::State::INVALID;
if (CLEAR_EVENT)
eventIter = container.erase(eventIter);
else
++eventIter;
}
};
CLEAR(collisionInfoContainer);
CLEAR(triggerInfoContainer);
}
void SHCollisionListener::ClearContainers() noexcept
{
collisionInfoContainer.clear();
triggerInfoContainer.clear();
}
void SHCollisionListener::onContact(const rp3d::CollisionCallback::CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)
{
const auto CONTACT_PAIR = callbackData.getContactPair(i);
const SHCollisionInfo NEW_INFO = generateCollisionInfo(CONTACT_PAIR);
updateInfoContainers(NEW_INFO, collisionInfoContainer);
}
}
void SHCollisionListener::onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i)
{
const auto OVERLAP_PAIR = callbackData.getOverlappingPair(i);
const SHCollisionInfo NEW_INFO = generateTriggerInfo(OVERLAP_PAIR);
updateInfoContainers(NEW_INFO, triggerInfoContainer);
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionListener::updateInfoContainers(const SHCollisionInfo& collisionEvent, std::vector<SHCollisionInfo>& container) noexcept
{
const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionInfo& info)
{
const bool ENTITY_MATCH = (info.ids[0] == collisionEvent.ids[0] && info.ids[1] == collisionEvent.ids[1])
|| (info.ids[0] == collisionEvent.ids[1] && info.ids[1] == collisionEvent.ids[0]);
const bool COLLIDERS_MATCH = (info.ids[2] == collisionEvent.ids[2] && info.ids[3] == collisionEvent.ids[3])
|| (info.ids[2] == collisionEvent.ids[3] && info.ids[3] == collisionEvent.ids[2]);
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (IT == container.end())
container.emplace_back(collisionEvent);
else
IT->collisionState = collisionEvent.collisionState;
}
SHCollisionInfo SHCollisionListener::generateCollisionInfo(const rp3d::CollisionCallback::ContactPair& cp) const noexcept
{
SHCollisionInfo cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionInfo::State>(cp.getEventType());
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : system->GetPhysicsObjects())
{
// Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1)
{
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
matched[SHCollisionInfo::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2)
{
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);
matched[SHCollisionInfo::ENTITY_B] = true;
}
if (matched[SHCollisionInfo::ENTITY_A] == true && matched[SHCollisionInfo::ENTITY_B] == true)
return cInfo;
}
return cInfo;
}
SHCollisionInfo SHCollisionListener::generateTriggerInfo(const rp3d::OverlapCallback::OverlapPair& cp) const noexcept
{
SHCollisionInfo cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionInfo::State>(cp.getEventType());
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : system->GetPhysicsObjects())
{
// Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1)
{
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
matched[SHCollisionInfo::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2)
{
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);
matched[SHCollisionInfo::ENTITY_B] = true;
}
if (matched[SHCollisionInfo::ENTITY_A] == true && matched[SHCollisionInfo::ENTITY_B] == true)
return cInfo;
}
return cInfo;
}
} // namespace SHADE

View File

@ -0,0 +1,81 @@
/****************************************************************************************
* \file SHCollisionListener.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Collision Listener.
*
* \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
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "SH_API.h"
#include "SHCollisionInfo.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHPhysicsSystem;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHCollisionListener final : public rp3d::EventListener
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHCollisionListener() noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] const std::vector<SHCollisionInfo>& GetCollisionInfoContainer () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetTriggerInfoContainer () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept;
void BindToWorld (rp3d::PhysicsWorld* world) noexcept;
void CleanContainers () noexcept;
void ClearContainers () noexcept;
void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override;
void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem* system;
std::vector<SHCollisionInfo> collisionInfoContainer;
std::vector<SHCollisionInfo> triggerInfoContainer;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static void updateInfoContainers (const SHCollisionInfo& collisionEvent, std::vector<SHCollisionInfo>& container) noexcept;
SHCollisionInfo generateCollisionInfo (const rp3d::CollisionCallback::ContactPair& cp) const noexcept;
SHCollisionInfo generateTriggerInfo (const rp3d::OverlapCallback::OverlapPair& cp) const noexcept;
};
} // namespace SHADE

View File

@ -16,7 +16,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
namespace SHADE namespace SHADE
{ {
@ -72,7 +72,14 @@ namespace SHADE
void SHColliderComponent::OnCreate() void SHColliderComponent::OnCreate()
{ {
system = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{
SHLOG_ERROR("Physics System does not exist to link with Physics Components!")
return;
}
system = physicsSystem;
} }
void SHColliderComponent::OnDestroy() void SHColliderComponent::OnDestroy()
@ -88,7 +95,7 @@ namespace SHADE
{ {
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
auto* box = reinterpret_cast<SHBoundingBox*>(collisionShape.GetShape()); auto* box = reinterpret_cast<SHBoundingBox*>(collisionShape.shape);
const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents(); const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents();
// Recompute world extents based on new scale and fixed relative extents // Recompute world extents based on new scale and fixed relative extents
@ -99,7 +106,7 @@ namespace SHADE
} }
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
auto* sphere = reinterpret_cast<SHBoundingSphere*>(collisionShape.GetShape()); auto* sphere = reinterpret_cast<SHBoundingSphere*>(collisionShape.shape);
const float RELATIVE_RADIUS = sphere->GetRelativeRadius(); const float RELATIVE_RADIUS = sphere->GetRelativeRadius();
// Recompute world radius based on new scale and fixed radius // Recompute world radius based on new scale and fixed radius
@ -132,9 +139,10 @@ namespace SHADE
collider.SetBoundingBox(halfExtents); collider.SetBoundingBox(halfExtents);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
return static_cast<int>(collisionShapes.size()) - 1; system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
} }
int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept
@ -154,9 +162,10 @@ namespace SHADE
collider.SetBoundingSphere(radius); collider.SetBoundingSphere(radius);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
return static_cast<int>(collisionShapes.size()) - 1; system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
} }
void SHColliderComponent::RemoveCollider(int index) void SHColliderComponent::RemoveCollider(int index)

View File

@ -14,9 +14,9 @@
// Project Headers // Project Headers
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.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"
#include "SHCollisionShape.h"
//namespace SHADE //namespace SHADE
//{ //{

View File

@ -16,8 +16,8 @@
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "SHColliderComponent.h"
namespace SHADE namespace SHADE
{ {
@ -164,9 +164,8 @@ namespace SHADE
return rotationOffset; return rotationOffset;
} }
SHShape* SHCollisionShape::GetShape() noexcept const SHShape* SHCollisionShape::GetShape() const noexcept
{ {
dirty = true;
return shape; return shape;
} }

View File

@ -82,7 +82,7 @@ namespace SHADE
[[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept;
[[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept;
[[nodiscard]] SHShape* GetShape () noexcept; [[nodiscard]] const SHShape* GetShape () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */

View File

@ -19,7 +19,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
namespace SHADE namespace SHADE
{ {
@ -30,8 +30,17 @@ namespace SHADE
SHRigidBodyComponent::SHRigidBodyComponent() noexcept SHRigidBodyComponent::SHRigidBodyComponent() noexcept
: type { Type::DYNAMIC } : type { Type::DYNAMIC }
, interpolate { true } , interpolate { true }
, rp3dBody { nullptr } , flags { 0 }
{} , dirtyFlags { std::numeric_limits<uint16_t>::max() }
, mass { 1.0f }
, drag { 0.01f }
, angularDrag { 0.01f }
, system { nullptr }
{
// Initialise default flags
flags |= 1U << 0; // Gravity set to true
flags |= 1U << 1; // Sleeping allowed
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */ /* Getter Function Definitions */
@ -39,24 +48,14 @@ namespace SHADE
bool SHRigidBodyComponent::IsGravityEnabled() const noexcept bool SHRigidBodyComponent::IsGravityEnabled() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 0;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->isGravityEnabled();
} }
bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 1;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->isAllowedToSleep();
} }
bool SHRigidBodyComponent::IsInterpolating() const noexcept bool SHRigidBodyComponent::IsInterpolating() const noexcept
@ -71,151 +70,85 @@ namespace SHADE
float SHRigidBodyComponent::GetMass() const noexcept float SHRigidBodyComponent::GetMass() const noexcept
{ {
if (rp3dBody == nullptr) return mass;
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getMass();
} }
float SHRigidBodyComponent::GetDrag() const noexcept float SHRigidBodyComponent::GetDrag() const noexcept
{ {
if (rp3dBody == nullptr) return drag;
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getLinearDamping();
} }
float SHRigidBodyComponent::GetAngularDrag() const noexcept float SHRigidBodyComponent::GetAngularDrag() const noexcept
{ {
if (rp3dBody == nullptr) return angularDrag;
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getAngularDamping();
} }
bool SHRigidBodyComponent::GetFreezePositionX() const noexcept bool SHRigidBodyComponent::GetFreezePositionX() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 2;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.x, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezePositionY() const noexcept bool SHRigidBodyComponent::GetFreezePositionY() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 3;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.y, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 4;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.z, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 5;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.x, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 6;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.y, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 7;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.z, 0.0f);
} }
SHVec3 SHRigidBodyComponent::GetForce() const noexcept SHVec3 SHRigidBodyComponent::GetForce() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getForce();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->getForce(); return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetTorque() const noexcept SHVec3 SHRigidBodyComponent::GetTorque() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getTorque();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getTorque(); return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getLinearVelocity();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getLinearVelocity(); return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getAngularVelocity();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getAngularVelocity(); return SHVec3::Zero;
} }
const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept
@ -239,18 +172,13 @@ namespace SHADE
void SHRigidBodyComponent::SetType(Type newType) noexcept void SHRigidBodyComponent::SetType(Type newType) noexcept
{ {
static constexpr int FLAG_POS = 8;
if (type == newType) if (type == newType)
return; return;
type = newType; type = newType;
dirtyFlags |= 1U << FLAG_POS;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setType(static_cast<rp3d::BodyType>(type));
} }
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
@ -263,13 +191,8 @@ namespace SHADE
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ enableGravity ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->enableGravity(enableGravity);
} }
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
@ -282,127 +205,92 @@ namespace SHADE
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ isAllowedToSleep ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setIsAllowedToSleep(isAllowedToSleep);
} }
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{ {
static constexpr int FLAG_POS = 2;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezePositionX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.x = freezePositionX ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
} }
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{ {
static constexpr int FLAG_POS = 3;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezePositionY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.y = freezePositionY ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
} }
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{ {
static constexpr int FLAG_POS = 4;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezePositionZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.z = freezePositionZ ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
} }
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{ {
static constexpr int FLAG_POS = 5;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezeRotationX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.x = freezeRotationX ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
} }
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{ {
static constexpr int FLAG_POS = 6;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezeRotationY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.y = freezeRotationY ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
} }
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{ {
static constexpr int FLAG_POS = 7;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.z = freezeRotationZ ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
} }
void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept
@ -412,179 +300,127 @@ namespace SHADE
void SHRigidBodyComponent::SetMass(float newMass) noexcept void SHRigidBodyComponent::SetMass(float newMass) noexcept
{ {
static constexpr int FLAG_POS = 9;
if (type != Type::DYNAMIC) if (type != Type::DYNAMIC)
{ {
SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ mass = newMass;
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setMass(newMass);
} }
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
{ {
static constexpr int FLAG_POS = 10;
if (type != Type::DYNAMIC) if (type != Type::DYNAMIC)
{ {
SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID()) SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ drag = newDrag;
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearDamping(newDrag);
} }
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
{ {
static constexpr int FLAG_POS = 11;
if (type != Type::DYNAMIC) if (type != Type::DYNAMIC)
{ {
SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID()) SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ angularDrag = newAngularDrag;
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearDamping(newAngularDrag);
} }
void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
{ {
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) auto* physicsObject = system->GetPhysicsObject(GetEID());
{ physicsObject->GetRigidBody()->setLinearVelocity(newLinearVelocity);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearVelocity(newLinearVelocity);
} }
void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
{ {
static constexpr int FLAG_POS = 13;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) auto* physicsObject = system->GetPhysicsObject(GetEID());
{ physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setAngularVelocity(newAngularVelocity);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept void SHRigidBodyComponent::OnCreate()
{ {
if (rp3dBody == nullptr) auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{ {
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) SHLOG_ERROR("Physics System does not exist to link with Physics Components!")
return; return;
} }
rp3dBody->applyWorldForceAtCenterOfMass(force); system = physicsSystem;
}
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept
{
system->AddForce(GetEID(), force);
} }
void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddForceAtLocalPos(GetEID(), force, localPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyWorldForceAtLocalPosition(force, localPos);
} }
void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddForceAtWorldPos(GetEID(), force, worldPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyWorldForceAtWorldPosition(force, worldPos);
} }
void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeForce(GetEID(), relativeForce);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalForceAtCenterOfMass(relativeForce);
} }
void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeForceAtLocalPos(GetEID(), relativeForce, localPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos);
} }
void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeForceAtWorldPos(GetEID(), relativeForce, worldPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
} }
void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
{ {
if (rp3dBody == nullptr) system->AddTorque(GetEID(), torque);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyWorldTorque(torque);
} }
void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeTorque(GetEID(), relativeTorque);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalTorque(relativeTorque);
} }
} // namespace SHADE } // namespace SHADE

View File

@ -17,16 +17,6 @@
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h" #include "Math/SHQuaternion.h"
//namespace SHADE
//{
// class SHPhysicsSystem;
//}
namespace reactphysics3d
{
class RigidBody;
}
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -110,7 +100,7 @@ namespace SHADE
void SetType (Type newType) noexcept; void SetType (Type newType) noexcept;
void SetGravityEnabled (bool enableGravity) noexcept; void SetGravityEnabled (bool enableGravity) noexcept;
void SetIsAllowedToSleep(bool isAllowedToSleep) noexcept; void SetIsAllowedToSleep (bool isAllowedToSleep) noexcept;
void SetFreezePositionX (bool freezePositionX) noexcept; void SetFreezePositionX (bool freezePositionX) noexcept;
void SetFreezePositionY (bool freezePositionY) noexcept; void SetFreezePositionY (bool freezePositionY) noexcept;
void SetFreezePositionZ (bool freezePositionZ) noexcept; void SetFreezePositionZ (bool freezePositionZ) noexcept;
@ -130,6 +120,8 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void OnCreate () override;
void AddForce (const SHVec3& force) const noexcept; void AddForce (const SHVec3& force) const noexcept;
void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept; void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept;
void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept; void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept;
@ -147,12 +139,22 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static constexpr size_t NUM_FLAGS = 8; static constexpr size_t NUM_FLAGS = 8;
static constexpr size_t NUM_DIRTY_FLAGS = 16; static constexpr size_t NUM_DIRTY_FLAGS = 12;
Type type; Type type;
bool interpolate;
reactphysics3d::RigidBody* rp3dBody; bool interpolate;
uint8_t flags; // aZ aY aX lZ lY lX slp g
uint16_t dirtyFlags; // 0 0 0 0 aD d m t aZ aY aX lZ lY lX slp g
float mass;
float drag;
float angularDrag;
SHVec3 linearVelocity;
SHVec3 angularVelocity;
SHPhysicsSystem* system;
SHVec3 position; SHVec3 position;
SHQuaternion orientation; SHQuaternion orientation;

View File

@ -0,0 +1,359 @@
/****************************************************************************************
* \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object.
*
* \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 "SHPhysicsObject.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, factory { physicsFactory }
, world { physicsWorld }
, rp3dBody { nullptr }
{
// Implicitly create a static body.
const auto* TRANSFORM = SHComponentManager::GetComponent<SHTransformComponent>(eid);
const rp3d::Transform RP3D_TRANSFORM { TRANSFORM->GetWorldPosition(), TRANSFORM->GetWorldOrientation() };
rp3dBody = world->createRigidBody(RP3D_TRANSFORM);
rp3dBody->setType(rp3d::BodyType::STATIC);
}
SHPhysicsObject::~SHPhysicsObject() noexcept
{
factory = nullptr;
world = nullptr;
rp3dBody = nullptr;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHPhysicsObject::GetPosition() const noexcept
{
return rp3dBody->getTransform().getPosition();
}
SHQuaternion SHPhysicsObject::GetOrientation() const noexcept
{
return rp3dBody->getTransform().getOrientation();
}
SHVec3 SHPhysicsObject::GetRotation() const noexcept
{
return SHQuaternion{ rp3dBody->getTransform().getOrientation() }.ToEuler();
}
rp3d::CollisionBody* SHPhysicsObject::GetCollisionBody() const noexcept
{
return rp3dBody;
}
rp3d::RigidBody* SHPhysicsObject::GetRigidBody() const noexcept
{
return rp3dBody;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::SetStaticBody() const noexcept
{
if (!rp3dBody)
return;
rp3dBody->setType(rp3d::BodyType::STATIC);
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
int SHPhysicsObject::AddCollisionShape(int index) const
{
// Get collider component
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (!colliderComponent)
{
SHLOGV_ERROR("Unable to add Collision Shape to Entity {} due to Missing Collider Component!", entityID)
return -1;
}
auto& collisionShape = colliderComponent->GetCollisionShape(index);
switch (collisionShape.GetType())
{
// TODO(Diren): Add more collider shapes
case SHCollisionShape::Type::BOX: addBoxShape(collisionShape); break;
case SHCollisionShape::Type::SPHERE: addSphereShape(collisionShape); break;
default: break;
}
rp3dBody->updateLocalCenterOfMassFromColliders();
rp3dBody->updateLocalInertiaTensorFromColliders();
return index;
}
void SHPhysicsObject::RemoveCollisionShape(int index) const
{
const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());
if (NUM_COLLIDERS == 0)
return;
if (index < 0 || index >= NUM_COLLIDERS)
throw std::invalid_argument("Index out of range!");
auto* collider = rp3dBody->getCollider(index);
rp3dBody->removeCollider(collider);
}
void SHPhysicsObject::RemoveAllCollisionShapes() const noexcept
{
int numColliders = static_cast<int>(rp3dBody->getNbColliders());
if (numColliders == 0)
return;
while (numColliders - 1 >= 0)
{
auto* collider = rp3dBody->getCollider(numColliders - 1);
rp3dBody->removeCollider(collider);
--numColliders;
}
}
void SHPhysicsObject::SyncRigidBody(SHRigidBodyComponent& component) const noexcept
{
if (component.dirtyFlags == 0)
return;
for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i)
{
if (const bool IS_DIRTY = component.dirtyFlags & (1U << i); IS_DIRTY)
{
switch (i)
{
case 0: // Gravity
{
const bool IS_ENABLED = component.flags & (1U << i);
rp3dBody->enableGravity(IS_ENABLED);
break;
}
case 1: // Sleeping
{
const bool IS_ENABLED = component.flags & (1U << i);
rp3dBody->setIsAllowedToSleep(IS_ENABLED);
break;
}
case 2: // Lock Position X
{
const bool IS_ENABLED = component.flags & (1U << i);
auto positionLock = rp3dBody->getLinearLockAxisFactor();
positionLock.x = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(positionLock);
break;
}
case 3: // Lock Position Y
{
const bool IS_ENABLED = component.flags & (1U << i);
auto positionLock = rp3dBody->getLinearLockAxisFactor();
positionLock.y = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(positionLock);
break;
}
case 4: // Lock Position Z
{
const bool IS_ENABLED = component.flags & (1U << i);
auto positionLock = rp3dBody->getLinearLockAxisFactor();
positionLock.z = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(positionLock);
break;
}
case 5: // Lock Rotation X
{
const bool IS_ENABLED = component.flags & (1U << i);
auto rotationLock = rp3dBody->getAngularLockAxisFactor();
rotationLock.x = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(rotationLock);
break;
}
case 6: // Lock Rotation Y
{
const bool IS_ENABLED = component.flags & (1U << i);
auto rotationLock = rp3dBody->getAngularLockAxisFactor();
rotationLock.y = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(rotationLock);
break;
}
case 7: // Lock Rotation Z
{
const bool IS_ENABLED = component.flags & (1U << i);
auto rotationLock = rp3dBody->getAngularLockAxisFactor();
rotationLock.z = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(rotationLock);
break;
}
case 8: // Type
{
rp3dBody->setType(static_cast<rp3d::BodyType>(component.type));
break;
}
case 9: // Mass
{
rp3dBody->setMass(component.mass);
rp3dBody->updateLocalCenterOfMassFromColliders();
rp3dBody->updateLocalInertiaTensorFromColliders();
break;
}
case 10: // Drag
{
rp3dBody->setLinearDamping(component.drag);
break;
}
case 11: // Angular Drag
{
rp3dBody->setAngularDamping(component.angularDrag);
break;
}
default: break;
}
}
}
component.dirtyFlags = 0;
}
void SHPhysicsObject::SyncColliders(SHColliderComponent& component) const noexcept
{
int index = 0;
for (auto& collisionShape : component.collisionShapes)
{
if (!collisionShape.dirty)
continue;
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX: syncBoxShape(index, collisionShape); break;
case SHCollisionShape::Type::SPHERE: syncSphereShape(index, collisionShape); break;
default: break;
}
// TODO(Diren): Update Material
collisionShape.dirty = false;
++index;
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::addBoxShape(SHCollisionShape& boxShape) const noexcept
{
const rp3d::Transform OFFSETS
{
boxShape.GetPositionOffset()
, boxShape.GetRotationOffset()
};
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(boxShape.GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(BOX->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS);
}
void SHPhysicsObject::syncBoxShape(int index, SHCollisionShape& boxShape) const noexcept
{
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(boxShape.GetShape());
auto* rp3dCollider = rp3dBody->getCollider(index);
auto* rp3dBox = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape());
const rp3d::Transform OFFSETS
{
boxShape.GetPositionOffset()
, boxShape.GetRotationOffset()
};
rp3dCollider->setIsTrigger(boxShape.IsTrigger());
rp3dCollider->setLocalToBodyTransform(OFFSETS);
rp3dBox->setHalfExtents(BOX->GetWorldExtents());
}
void SHPhysicsObject::addSphereShape(SHCollisionShape& sphereShape) const noexcept
{
const rp3d::Transform OFFSETS
{
sphereShape.GetPositionOffset()
, sphereShape.GetRotationOffset()
};
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(sphereShape.GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(SPHERE->GetWorldRadius());
rp3dBody->addCollider(newSphere, OFFSETS);
}
void SHPhysicsObject::syncSphereShape(int index, SHCollisionShape& sphereShape) const noexcept
{
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(sphereShape.GetShape());
auto* rp3dCollider = rp3dBody->getCollider(index);
auto* rp3dSphere = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
const rp3d::Transform OFFSETS
{
sphereShape.GetPositionOffset()
, sphereShape.GetRotationOffset()
};
rp3dCollider->setIsTrigger(sphereShape.IsTrigger());
rp3dCollider->setLocalToBodyTransform(OFFSETS);
rp3dSphere->setRadius(SPHERE->GetWorldRadius());
}
} // namespace SHADE

View File

@ -14,8 +14,8 @@
// Project Headers // Project Headers
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
namespace SHADE namespace SHADE
{ {
@ -31,6 +31,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem; friend class SHPhysicsSystem;
friend class SHPhysicsObjectManager;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -57,22 +58,25 @@ namespace SHADE
[[nodiscard]] SHQuaternion GetOrientation () const noexcept; [[nodiscard]] SHQuaternion GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept; [[nodiscard]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] rp3d::CollisionBody* GetCollisionBody () const noexcept;
[[nodiscard]] rp3d::RigidBody* GetRigidBody () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetPosition (const SHVec3& position) noexcept; void SetStaticBody () const noexcept;
void SetOrientation (const SHQuaternion& orientation) noexcept;
void SetRotation (const SHVec3& rotation) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
int AddCollider (SHCollisionShape* collider); int AddCollisionShape (int index) const;
void RemoveCollider (int index); void RemoveCollisionShape (int index) const;
void RemoveAllCollisionShapes () const noexcept;
void SyncColliders (SHColliderComponent* c) const noexcept; void SyncRigidBody (SHRigidBodyComponent& component) const noexcept;
void SyncColliders (SHColliderComponent& component) const noexcept;
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -83,7 +87,22 @@ namespace SHADE
rp3d::PhysicsCommon* factory; rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* world; rp3d::PhysicsWorld* world;
rp3d::CollisionBody* rp3dBody; // Can be either a collision body or a rigid body
rp3d::RigidBody* rp3dBody;
rp3d::Transform prevTransform; // Cached transform for interpolation rp3d::Transform prevTransform; // Cached transform for interpolation
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
// Box Shapes
void addBoxShape (SHCollisionShape& boxShape) const noexcept;
void syncBoxShape (int index, SHCollisionShape& boxShape) const noexcept;
// Sphere Shapes
void addSphereShape (SHCollisionShape& sphereShape) const noexcept;
void syncSphereShape (int index, SHCollisionShape& sphereShape) const noexcept;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,301 @@
/****************************************************************************************
* \file SHPhysicsObjectManager.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object Manager.
*
* \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 "SHPhysicsObjectManager.h"
// Project Headers
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[2][3]
{
addRigidBody , addCollider
, removeRigidBody , removeCollider
, addCollisionShape , removeCollisionShape
};
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::SetFactory(rp3d::PhysicsCommon& physicsFactory) noexcept
{
factory = &physicsFactory;
}
void SHPhysicsObjectManager::SetWorld(rp3d::PhysicsWorld* physicsWorld) noexcept
{
world = physicsWorld;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID eid) noexcept
{
const auto it = physicsObjects.find(eid);
if (it == physicsObjects.end())
return nullptr;
return &it->second;
}
const SHPhysicsObjectManager::PhysicsObjectEntityMap SHPhysicsObjectManager::GetPhysicsObjects() const noexcept
{
return physicsObjects;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::AddRigidBody(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::ADD
, .component = PhysicsComponents::RIGID_BODY
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::AddCollider(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::ADD
, .component = PhysicsComponents::COLLIDER
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::AddCollisionShape(EntityID eid, int shapeIndex) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::ADD
, .component = PhysicsComponents::COLLISION_SHAPE
, .shapeIndex = shapeIndex
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::RemoveRigidBody(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::REMOVE
, .component = PhysicsComponents::RIGID_BODY
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::RemoveCollider(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::REMOVE
, .component = PhysicsComponents::COLLIDER
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::RemoveCollisionShape(EntityID eid, int shapeIndex) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::REMOVE
, .component = PhysicsComponents::COLLISION_SHAPE
, .shapeIndex = shapeIndex
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::UpdateCommands()
{
if (commandQueue.empty())
return;
while (!commandQueue.empty())
{
const QueueCommand COMMAND = commandQueue.front();
commandQueue.pop();
// Check validity of command
if (COMMAND.command == QueueCommand::Command::INVALID || COMMAND.component == PhysicsComponents::INVALID)
continue;
// Get physics components
const PhysicsComponentGroup COMPONENT_GROUP
{
.eid = COMMAND.eid
, .rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(COMMAND.eid)
, .colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(COMMAND.eid)
};
// Delete any object that is missing both components
// We infer that a remove command has been pushed for these, but we will ignore those if both components have already been removed.
if (!COMPONENT_GROUP.rigidBodyComponent && !COMPONENT_GROUP.colliderComponent)
{
destroyPhysicsObject(COMMAND.eid);
continue;
}
// Find the physics Object. If none found and attempting to add, create an object.
SHPhysicsObject* physicsObject = GetPhysicsObject(COMMAND.eid);
if (!physicsObject && COMMAND.command == QueueCommand::Command::ADD)
physicsObject = createPhysicsObject(COMMAND.eid);
componentFunc[SHUtilities::ConvertEnum(COMMAND.command)][SHUtilities::ConvertEnum(COMMAND.component)](COMMAND, physicsObject, COMPONENT_GROUP);
}
}
void SHPhysicsObjectManager::RemoveAllObjects()
{
// Destroy all objects and clear
for (auto& physicsObject : physicsObjects | std::views::values)
{
world->destroyRigidBody(physicsObject.GetRigidBody());
physicsObject.rp3dBody = nullptr;
}
physicsObjects.clear();
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID eid) noexcept
{
// Force transforms to sync
SHVec3 worldPos = SHVec3::Zero;
SHQuaternion worldRot = SHQuaternion::Identity;
const SHTransformComponent* TRANSFORM = nullptr;
if (SHEntityManager::IsValidEID(eid))
TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (TRANSFORM)
{
worldPos = TRANSFORM->GetWorldPosition();
worldRot = TRANSFORM->GetWorldOrientation();
}
const rp3d::Transform RP3D_TRANSFORM{ worldPos, worldRot };
auto& newPhysicsObject = physicsObjects.emplace(eid, SHPhysicsObject{ eid, factory, world }).first->second;
newPhysicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM);
newPhysicsObject.prevTransform = RP3D_TRANSFORM;
return &newPhysicsObject;
}
void SHPhysicsObjectManager::destroyPhysicsObject(EntityID eid) noexcept
{
const auto ITER = physicsObjects.find(eid);
if (ITER == physicsObjects.end())
{
// Assume the object has already been successfully destroyed
return;
}
world->destroyRigidBody(ITER->second.GetRigidBody());
ITER->second.rp3dBody = nullptr;
physicsObjects.erase(eid);
}
void SHPhysicsObjectManager::addRigidBody(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add body!")
if (!componentGroup.rigidBodyComponent)
{
SHLOG_ERROR("Entity {} is missing a Rigidbody Component. Unable to update physics object!", componentGroup.eid)
return;
}
// A static rigid body is implicitly created on creation of a physics object.
// We only need to sync rigid bodies here in the event it is non-static.
physicsObject->SyncRigidBody(*componentGroup.rigidBodyComponent);
}
void SHPhysicsObjectManager::addCollider(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add collider!")
if (!componentGroup.colliderComponent)
{
SHLOG_ERROR("Entity {} is missing a Rigidbody Component. Unable to update physics object!", componentGroup.eid)
return;
}
const int NUM_SHAPES = static_cast<int>(componentGroup.colliderComponent->GetCollisionShapes().size());
for (int i = 0; i < NUM_SHAPES; ++i)
physicsObject->AddCollisionShape(i);
physicsObject->SyncColliders(*componentGroup.colliderComponent);
}
void SHPhysicsObjectManager::removeRigidBody(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove body!")
if (componentGroup.colliderComponent)
physicsObject->SetStaticBody();
}
void SHPhysicsObjectManager::removeCollider(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collider!")
physicsObject->RemoveAllCollisionShapes();
}
void SHPhysicsObjectManager::addCollisionShape(const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add collision shape!")
physicsObject->AddCollisionShape(command.shapeIndex);
}
void SHPhysicsObjectManager::removeCollisionShape(const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collision shape!")
physicsObject->RemoveCollisionShape(command.shapeIndex);
}
} // namespace SHADE

View File

@ -0,0 +1,177 @@
/****************************************************************************************
* \file SHPhysicsObjectManager.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Object Manager.
*
* \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 <unordered_map>
#include <queue>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "SHPhysicsObject.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsObjectManager
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using PhysicsObjectEntityMap = std::unordered_map<EntityID, SHPhysicsObject>;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class PhysicsComponents
{
RIGID_BODY
, COLLIDER
, COLLISION_SHAPE
, TOTAL
, INVALID = -1
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsObjectManager () = default;
~SHPhysicsObjectManager () = default;
SHPhysicsObjectManager (const SHPhysicsObjectManager&) = delete;
SHPhysicsObjectManager (SHPhysicsObjectManager&&) = delete;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHPhysicsObjectManager& operator=(const SHPhysicsObjectManager&) = delete;
SHPhysicsObjectManager& operator=(SHPhysicsObjectManager&&) = delete;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const PhysicsObjectEntityMap GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFactory (rp3d::PhysicsCommon& physicsFactory) noexcept;
void SetWorld (rp3d::PhysicsWorld* physicsWorld) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void AddRigidBody (EntityID eid) noexcept;
void AddCollider (EntityID eid) noexcept;
void AddCollisionShape (EntityID eid, int shapeIndex) noexcept;
void RemoveRigidBody (EntityID eid) noexcept;
void RemoveCollider (EntityID eid) noexcept;
void RemoveCollisionShape (EntityID eid, int shapeIndex) noexcept;
void UpdateCommands ();
void RemoveAllObjects ();
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct QueueCommand
{
/*-------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------------*/
enum class Command
{
ADD
, REMOVE
, INVALID = -1
};
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
EntityID eid = MAX_EID;
Command command = Command::INVALID;
PhysicsComponents component = PhysicsComponents::INVALID;
int shapeIndex = -1; // Only used when adding & removing collision shapes
};
struct PhysicsComponentGroup
{
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
EntityID eid = MAX_EID;
SHRigidBodyComponent* rigidBodyComponent = nullptr;
SHColliderComponent* colliderComponent = nullptr;
};
using CommandFunctionPtr = void(*)(const QueueCommand&, SHPhysicsObject*, const PhysicsComponentGroup&);
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static CommandFunctionPtr componentFunc[2][3]; // 2 commands, 3 components
rp3d::PhysicsCommon* factory = nullptr;
rp3d::PhysicsWorld* world = nullptr;
PhysicsObjectEntityMap physicsObjects;
std::queue<QueueCommand> commandQueue;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* createPhysicsObject (EntityID eid) noexcept;
void destroyPhysicsObject (EntityID eid) noexcept;
static void addRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void addCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void addCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
};
} // namespace SHADE

View File

@ -0,0 +1,37 @@
/****************************************************************************************
* \file SHPhysicsUtils.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for some Physics Utilities
*
* \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 "Interface/SHCollisionShape.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHPhysicsColliderAddedEvent
{
EntityID entityID;
SHCollisionShape::Type colliderType;
int colliderIndex;
};
struct SHPhysicsColliderRemovedEvent
{
EntityID entityID;
int colliderIndex;
};
} // namespace SHADE

View File

@ -1,219 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object.
*
* \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 "SHPhysicsObject.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, factory { physicsFactory }
, world { physicsWorld }
, rp3dBody { nullptr }
{}
SHPhysicsObject::~SHPhysicsObject() noexcept
{
factory = nullptr;
world = nullptr;
rp3dBody = nullptr;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHPhysicsObject::GetPosition() const noexcept
{
SHVec3 result;
if (rp3dBody)
result = SHVec3{ rp3dBody->getTransform().getPosition() };
return result;
}
SHQuaternion SHPhysicsObject::GetOrientation() const noexcept
{
SHQuaternion result;
if (rp3dBody)
result = SHQuaternion{ rp3dBody->getTransform().getOrientation() };
return result;
}
SHVec3 SHPhysicsObject::GetRotation() const noexcept
{
SHVec3 result;
if (rp3dBody)
result = SHQuaternion{ rp3dBody->getTransform().getOrientation() }.ToEuler();
return result;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::SetPosition(const SHVec3& position) noexcept
{
if (!rp3dBody)
{
SHLOG_ERROR("Cannot set position of a non-existent physics body for Entity {}", entityID)
return;
}
rp3d::Transform rp3dTF;
rp3dTF.setPosition(position);
rp3dTF.setOrientation(rp3dBody->getTransform().getOrientation());
rp3dBody->setTransform(rp3dTF);
prevTransform = rp3dTF;
}
void SHPhysicsObject::SetOrientation(const SHQuaternion& orientation) noexcept
{
if (!rp3dBody)
{
SHLOG_ERROR("Cannot set orientation of a non-existent physics body for Entity {}", entityID)
return;
}
rp3d::Transform rp3dTF;
rp3dTF.setPosition(rp3dBody->getTransform().getPosition());
rp3dTF.setOrientation(orientation);
rp3dBody->setTransform(rp3dTF);
prevTransform = rp3dTF;
}
void SHPhysicsObject::SetRotation(const SHVec3& rotation) noexcept
{
if (!rp3dBody)
{
SHLOG_ERROR("Cannot set rotation of a non-existent physics body for Entity {}", entityID)
return;
}
rp3d::Transform rp3dTF;
rp3dTF.setPosition(rp3dBody->getTransform().getPosition());
rp3dTF.setOrientation(rotation);
rp3dBody->setTransform(rp3dTF);
prevTransform = rp3dTF;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
int SHPhysicsObject::AddCollider(SHCollisionShape* collider)
{
const rp3d::Transform OFFSETS{ collider->GetPositionOffset(), collider->GetRotationOffset() };
switch (collider->GetType())
{
case SHCollisionShape::Type::BOX:
{
const auto* box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(box->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS);
break;
}
case SHCollisionShape::Type::SPHERE:
{
const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(sphere->GetWorldRadius());
rp3dBody->addCollider(newSphere, OFFSETS);
break;
}
// TODO(Diren): Add more collider shapes
default: break;
}
return static_cast<int>(rp3dBody->getNbColliders()) - 1;
}
void SHPhysicsObject::RemoveCollider(int index)
{
const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());
if (NUM_COLLIDERS == 0)
return;
if (index < 0 || index >= NUM_COLLIDERS)
throw std::invalid_argument("Index out of range!");
auto* collider = rp3dBody->getCollider(index);
rp3dBody->removeCollider(collider);
}
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept
{
int index = 0;
for (auto& collider : c->collisionShapes)
{
if (!collider.dirty)
continue;
auto* rp3dCollider = rp3dBody->getCollider(index);
// Update trigger flag
rp3dCollider->setIsTrigger(collider.IsTrigger());
// Update offsets
rp3dCollider->setLocalToBodyTransform(rp3d::Transform(collider.GetPositionOffset(), collider.GetRotationOffset()));
switch (collider.GetType())
{
case SHCollisionShape::Type::BOX:
{
const auto* box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
auto* rp3dBoxShape = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape());
rp3dBoxShape->setHalfExtents(box->GetWorldExtents());
break;
}
case SHCollisionShape::Type::SPHERE:
{
const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape());
auto* rp3dSphereShape = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
rp3dSphereShape->setRadius(sphere->GetWorldRadius());
break;
}
default: break;
}
// TODO(Diren): Update Material
collider.dirty = false;
++index;
}
}
} // namespace SHADE

View File

@ -1,856 +0,0 @@
/****************************************************************************************
* \file SHPhysicsSystem.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics System
*
* \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 "SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/SHMathHelpers.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::SHPhysicsSystem()
: worldUpdated { false }
, debugDrawFlags { 0 }
, interpolationFactor { 0.0 }
, fixedDT { 60.0 }
, world { nullptr }
{}
SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate()
: SHSystemRoutine { "Physics PreUpdate", true }
{}
SHPhysicsSystem::PhysicsFixedUpdate::PhysicsFixedUpdate()
: SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics FixedUpdate", false }
{}
SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate()
: SHSystemRoutine { "Physics PostUpdate", false }
{}
SHPhysicsSystem::PhysicsDebugDraw::PhysicsDebugDraw()
: SHSystemRoutine { "Physics DebugDraw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
double SHPhysicsSystem::GetFixedDT() const noexcept
{
return fixedDT;
}
bool SHPhysicsSystem::IsSleepingEnabled() const noexcept
{
if (world)
return world->isSleepingEnabled();
SHLOGV_WARNING("No physics world has been initialised!")
return false;
}
SHVec3 SHPhysicsSystem::GetWorldGravity() const noexcept
{
SHVec3 result;
if (world)
{
result = world->getGravity();
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
return result;
}
uint16_t SHPhysicsSystem::GetNumberVelocityIterations() const noexcept
{
if (world)
return world->getNbIterationsVelocitySolver();
SHLOGV_WARNING("No physics world has been initialised!")
return 0;
}
uint16_t SHPhysicsSystem::GetNumberPositionIterations() const noexcept
{
if (world)
return world->getNbIterationsPositionSolver();
SHLOGV_WARNING("No physics world has been initialised!")
return 0;
}
bool SHPhysicsSystem::GetDrawColliders() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER);
}
bool SHPhysicsSystem::GetDrawColliderAABBs() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB);
}
bool SHPhysicsSystem::GetDrawBroadPhase() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB);
}
bool SHPhysicsSystem::GetDrawContactPoints() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS);
}
bool SHPhysicsSystem::GetDrawContactNormals() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS);
}
const SHPhysicsSystem::CollisionEvents& SHPhysicsSystem::GetCollisionInfo() const noexcept
{
return collisionInfo;
}
const SHPhysicsSystem::CollisionEvents& SHPhysicsSystem::GetTriggerInfo() const noexcept
{
return triggerInfo;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept
{
fixedDT = fixedUpdateRate;
}
void SHPhysicsSystem::SetWorldGravity(const SHVec3& gravity) const noexcept
{
if (world)
{
world->setGravity(gravity);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetNumberVelocityIterations(uint16_t numVelIterations) const noexcept
{
if (world)
{
world->setNbIterationsVelocitySolver(numVelIterations);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetNumberPositionIterations(uint16_t numPosIterations) const noexcept
{
if (world)
{
world->setNbIterationsPositionSolver(numPosIterations);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetSleepingEnabled(bool enableSleeping) const noexcept
{
if (world)
{
world->enableSleeping(enableSleeping);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetWorldSettings(const WorldSettings& settings) const noexcept
{
if (world)
{
world->setGravity(settings.gravity);
world->setNbIterationsVelocitySolver(settings.numVelocitySolverIterations);
world->setNbIterationsPositionSolver(settings.numPositionSolverIterations);
world->enableSleeping(settings.sleepingEnabled);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetDrawColliders(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLISION_SHAPE,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawColliderAABBs(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLIDER_AABB,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawBroadPhase(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLIDER_BROADPHASE_AABB,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawContactPoints(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::CONTACT_POINT,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawContactNormals(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL,
shouldDraw
);
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::Init()
{
// Create a physics world with the default settings
rp3d::PhysicsWorld::WorldSettings settings;
settings.gravity = SHVec3{ 0.0f, -9.81f, 0.0f };
settings.isSleepingEnabled = true;
settings.defaultVelocitySolverNbIterations = 8;
settings.defaultPositionSolverNbIterations = 3;
settings.defaultFrictionCoefficient = 0.4f;
settings.defaultBounciness = 0.0f;
world = factory.createPhysicsWorld(settings);
world->setEventListener(this);
world->setIsDebugRenderingEnabled(true);
// Set up solvers
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::AddPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::RemovePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
#ifdef SHEDITOR
const std::shared_ptr EDITOR_STOP_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::ResetWorld) };
const ReceiverPtr EDITOR_STOP_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EDITOR_STOP_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, EDITOR_STOP_RECEIVER_PTR);
#endif
}
void SHPhysicsSystem::Exit()
{
factory.destroyPhysicsWorld(world);
}
void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollisionShape* collider)
{
auto* physicsObject = GetPhysicsObject(entityID);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = collider->GetType()
, .colliderIndex = physicsObject->AddCollider(collider)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
}
void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index)
{
auto* physicsObject = GetPhysicsObject(entityID);
physicsObject->RemoveCollider(index);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = entityID
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
}
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
// Sync transforms
for (auto& [entityID, physicsObject] : system->map)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (transformComponent && transformComponent->HasChanged())
{
const auto WORLD_POS = transformComponent->GetWorldPosition();
const auto WORLD_ROT = transformComponent->GetWorldOrientation();
const auto WORLD_SCL = transformComponent->GetWorldScale();
physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT);
// Sync physics component transforms
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
colliderComponent->scale = WORLD_SCL;
colliderComponent->RecomputeCollisionShapes();
}
}
// Sync rigid bodies
if (rigidBodyComponent)
{
// Sync active states
const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive;
SyncActiveStates(physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE)
continue;
}
// Sync colliders
if (colliderComponent)
{
const bool COMPONENT_ACTIVE = colliderComponent->isActive;
SyncActiveStates(physicsObject, colliderComponent->isActive);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncColliders(colliderComponent);
}
}
}
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
accumulatedTime += dt;
int count = 0;
while (accumulatedTime > fixedTimeStep)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->world->update(static_cast<rp3d::decimal>(fixedTimeStep));
accumulatedTime -= fixedTimeStep;
++count;
}
stats.numSteps = count;
physicsSystem->worldUpdated = count > 0;
physicsSystem->interpolationFactor = accumulatedTime / fixedTimeStep;
}
void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
// Interpolate transforms for rendering
if (physicsSystem->worldUpdated)
{
physicsSystem->SyncTransforms();
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
physicsSystem->ClearInvalidCollisions();
}
}
void SHPhysicsSystem::PhysicsDebugDraw::Execute(double) noexcept
{
const auto* PHYSICS_SYSTEM = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
if (PHYSICS_SYSTEM->debugDrawFlags == 0)
return;
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOGV_ERROR("Unable to debug draw physics objects due to missing SHDebugDrawSystem!");
return;
}
const auto& RP3D_DEBUG_RENDERER = PHYSICS_SYSTEM->world->getDebugRenderer();
const auto& LINES = RP3D_DEBUG_RENDERER.getLines();
const auto& TRIANGLES = RP3D_DEBUG_RENDERER.getTriangles();
// Draw all lines
for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbLines(); ++i)
{
const auto& LINE = LINES[i];
debugDrawSystem->DrawLine(SHColour{ LINE.color1 }, LINE.point1, LINE.point2);
}
for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbTriangles(); ++i)
{
const auto& TRIANGLE = TRIANGLES[i];
SHColour triColour{ TRIANGLE.color1 };
triColour.a() = 1.0f;
debugDrawSystem->DrawTri(triColour, TRIANGLE.point1, TRIANGLE.point2, TRIANGLE.point3);
}
}
void SHPhysicsSystem::onContact(const CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)
{
const auto CONTACT_PAIR = callbackData.getContactPair(i);
const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(CONTACT_PAIR);
UpdateEventContainers(NEW_EVENT, collisionInfo);
}
}
void SHPhysicsSystem::onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i)
{
const auto& OVERLAP_PAIR = callbackData.getOverlappingPair(i);
const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(OVERLAP_PAIR);
UpdateEventContainers(NEW_EVENT, triggerInfo);
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsSystem::EnsurePhysicsObject(EntityID entityID) noexcept
{
const auto it = map.find(entityID);
if (it == map.end())
{
auto* newPhysicsObject = &map.emplace(entityID, SHPhysicsObject{entityID, &factory, world}).first->second;
return newPhysicsObject;
}
return &(it->second);
}
SHPhysicsObject* SHPhysicsSystem::GetPhysicsObject(EntityID entityID) noexcept
{
const auto it = map.find(entityID);
if (it == map.end())
{
//SHLOG_ERROR("Entity {} is not in the physics system!", entityID)
return nullptr;
}
return &(it->second);
}
void SHPhysicsSystem::DestroyPhysicsObject(EntityID entityID) noexcept
{
map.erase(entityID);
}
void SHPhysicsSystem::SyncActiveStates(SHPhysicsObject& physicsObject, bool componentActive) noexcept
{
const bool RP3D_ACTIVE = physicsObject.rp3dBody->isActive();
if (RP3D_ACTIVE != componentActive)
physicsObject.rp3dBody->setIsActive(componentActive);
}
void SHPhysicsSystem::SyncTransforms() noexcept
{
for (auto& [entityID, physicsObject] : map)
{
rp3d::Vector3 rp3dPos;
rp3d::Quaternion rp3dRot;
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
// Check if transform should be interpolated
if (rigidBodyComponent != nullptr)
{
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
continue;
if (rigidBodyComponent->IsInterpolating())
{
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
rp3dPos = INTERPOLATED_TF.getPosition();
rp3dRot = INTERPOLATED_TF.getOrientation();
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (colliderComponent != nullptr)
{
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
// Convert RP3D Transform to SHADE
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent != nullptr)
{
transformComponent->SetWorldPosition(rp3dPos);
transformComponent->SetWorldOrientation(rp3dRot);
}
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
}
}
void SHPhysicsSystem::UpdateEventContainers(const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept
{
const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = (e.ids[0] == collisionEvent.ids[0] && e.ids[1] == collisionEvent.ids[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;
});
if (IT == container.end())
container.emplace_back(collisionEvent);
else
IT->collisionState = collisionEvent.collisionState;
}
void SHPhysicsSystem::ClearInvalidCollisions() noexcept
{
static const auto CLEAR = [](CollisionEvents& container)
{
for (auto eventIter = container.begin(); eventIter != container.end();)
{
const bool CLEAR_EVENT = eventIter->GetCollisionState() == SHCollisionEvent::State::EXIT
|| eventIter->GetCollisionState() == SHCollisionEvent::State::INVALID;
if (CLEAR_EVENT)
eventIter = container.erase(eventIter);
else
++eventIter;
}
};
CLEAR(collisionInfo);
CLEAR(triggerInfo);
}
SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = EnsurePhysicsObject(ENTITY_ID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(ENTITY_ID);
if (transformComponent == nullptr)
{
SHLOG_ERROR("Entity {} cannot add a Physics Component without a Transform! Component not created!", ENTITY_ID)
return EVENT_DATA->handle;
}
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (ADDED_ID == RIGID_BODY_ID)
{
if (colliderComponent != nullptr)
{
world->destroyCollisionBody(physicsObject->rp3dBody);
physicsObject->rp3dBody = nullptr;
}
rigidBodyComponent->position = transformComponent->GetWorldPosition();
rigidBodyComponent->orientation = transformComponent->GetWorldOrientation();
physicsObject->rp3dBody = world->createRigidBody
(
rp3d::Transform{ rigidBodyComponent->position, rigidBodyComponent->orientation }
);
rigidBodyComponent->rp3dBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody);
// Add collision shapes back into the body
if (colliderComponent != nullptr)
{
for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider);
}
}
if (ADDED_ID == COLLIDER_ID)
{
SHASSERT(colliderComponent != nullptr, "Collider Component was not added to Entity " + std::to_string(ENTITY_ID) + "!");
colliderComponent->position = transformComponent->GetWorldPosition();
colliderComponent->orientation = transformComponent->GetWorldOrientation();
colliderComponent->scale = transformComponent->GetWorldScale();
if (physicsObject->rp3dBody == nullptr)
{
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
}
// Add Collision Shapes
for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider);
}
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::RemovePhysicsComponent(SHEventPtr removeComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = GetPhysicsObject(ENTITY_ID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
// Wake up all physics objects
for (auto& [entityID, object] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
}
if (REMOVED_ID == RIGID_BODY_ID && physicsObject != nullptr)
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr;
if (colliderComponent != nullptr)
{
// Preserve colliders as a collision body
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider);
}
}
if (REMOVED_ID == COLLIDER_ID && physicsObject != nullptr)
{
// Remove all colliders
const int NUM_COLLIDERS = static_cast<int>(physicsObject->rp3dBody->getNbColliders());
for (int i = NUM_COLLIDERS - 1; i >= 0; --i)
{
auto* collider = physicsObject->rp3dBody->getCollider(i);
physicsObject->rp3dBody->removeCollider(collider);
}
// Check for a rigidbody component
if (rigidBodyComponent == nullptr)
physicsObject->rp3dBody = nullptr;
}
if (physicsObject != nullptr && physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(ENTITY_ID);
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::ResetWorld(SHEventPtr editorStopEvent)
{
// TODO(Diren): Rebuild world based on how scene reloading is done
for (auto& [entityID, physicsObject] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
}
return editorStopEvent->handle;
}
} // namespace SHADE

View File

@ -1,207 +0,0 @@
/****************************************************************************************
* \file SHPhysicsSystem.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for the Physics System
*
* \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 <queue>
#include <unordered_map>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Components/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "SHPhysicsObject.h"
#include "SHPhysicsUtils.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem final : public SHSystem
, public rp3d::EventListener
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct WorldSettings
{
SHVec3 gravity;
uint16_t numVelocitySolverIterations;
uint16_t numPositionSolverIterations;
bool sleepingEnabled;
};
using CollisionEvents = std::vector<SHCollisionEvent>;
enum class DebugDrawFlags : uint8_t
{
COLLIDER = 1
, COLLIDER_AABB = 2
, BROAD_PHASE_AABB = 4
, CONTACT_POINTS = 8
, CONTACT_NORMALS = 16
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem();
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] bool IsSleepingEnabled () const noexcept;
[[nodiscard]] SHVec3 GetWorldGravity () const noexcept;
[[nodiscard]] uint16_t GetNumberVelocityIterations () const noexcept;
[[nodiscard]] uint16_t GetNumberPositionIterations () const noexcept;
[[nodiscard]] bool GetDrawColliders () const noexcept;
[[nodiscard]] bool GetDrawColliderAABBs () const noexcept;
[[nodiscard]] bool GetDrawBroadPhase () const noexcept;
[[nodiscard]] bool GetDrawContactPoints () const noexcept;
[[nodiscard]] bool GetDrawContactNormals () const noexcept;
[[nodiscard]] const CollisionEvents& GetCollisionInfo () const noexcept;
[[nodiscard]] const CollisionEvents& GetTriggerInfo () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFixedDT (double fixedUpdateRate) noexcept;
void SetWorldGravity (const SHVec3& gravity) const noexcept;
void SetNumberVelocityIterations (uint16_t numVelIterations) const noexcept;
void SetNumberPositionIterations (uint16_t numPosIterations) const noexcept;
void SetSleepingEnabled (bool enableSleeping) const noexcept;
void SetWorldSettings (const WorldSettings& settings) const noexcept;
// TODO(Diren): Can the debug draw flags be done through an enum?
void SetDrawColliders (bool shouldDraw) noexcept;
void SetDrawColliderAABBs (bool shouldDraw) noexcept;
void SetDrawBroadPhase (bool shouldDraw) noexcept;
void SetDrawContactPoints (bool shouldDraw) noexcept;
void SetDrawContactNormals (bool shouldDraw) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init () override;
void Exit () override;
void AddCollisionShape (EntityID entityID, SHCollisionShape* collider);
void RemoveCollisionShape (EntityID entityID, int index);
void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override;
void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
PhysicsPreUpdate();
void Execute(double dt) noexcept override;
};
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
{
public:
PhysicsFixedUpdate();
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
PhysicsPostUpdate();
void Execute(double dt) noexcept override;
};
class SH_API PhysicsDebugDraw final : public SHSystemRoutine
{
public:
PhysicsDebugDraw();
void Execute(double dt) noexcept override;
};
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using EntityObjectMap = std::unordered_map<EntityID, SHPhysicsObject>;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool worldUpdated;
uint8_t debugDrawFlags;
double interpolationFactor;
double fixedDT;
rp3d::PhysicsWorld* world;
rp3d::PhysicsCommon factory;
EntityObjectMap map;
CollisionEvents collisionInfo;
CollisionEvents triggerInfo;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept;
static void SyncActiveStates (SHPhysicsObject& physicsObject, bool componentActive) noexcept;
void SyncTransforms () noexcept;
static void UpdateEventContainers (const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept;
void ClearInvalidCollisions () noexcept;
SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent);
SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent);
SHEventHandle ResetWorld (SHEventPtr editorStopEvent);
template <typename RP3DCollisionPair, typename = std::enable_if_t
<std::is_same_v<RP3DCollisionPair, rp3d::CollisionCallback::ContactPair>
|| std::is_same_v<RP3DCollisionPair, rp3d::OverlapCallback::OverlapPair>>>
SHCollisionEvent GenerateCollisionEvent (const RP3DCollisionPair& cp) noexcept;
};
} // namespace SHADE
#include "SHPhysicsSystem.hpp"

View File

@ -1,84 +0,0 @@
/****************************************************************************************
* \file SHPhysicsSystem.hpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for templated functions the Physics System
*
* \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 <type_traits>
// Primary Header
#include "SHPhysicsSystem.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
template <typename RP3DCollisionPair, typename Condition>
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const RP3DCollisionPair& cp) noexcept
{
static const auto MATCH_COLLIDER = []
(
const SHPhysicsObject& physicsObject
, const rp3d::Entity colliderID
)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
};
SHCollisionEvent cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
return cInfo;
}
} // namespace SHADE

View File

@ -0,0 +1,71 @@
/****************************************************************************************
* \file SHPhysicsWorld.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics World.
*
* \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 "SHPhysicsWorld.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsWorldState::SHPhysicsWorldState() noexcept
: world { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Members Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsWorldState::CreateWorld(rp3d::PhysicsCommon& factory)
{
rp3d::PhysicsWorld::WorldSettings rp3dWorldSettings;
rp3dWorldSettings.gravity = settings.gravity;
rp3dWorldSettings.defaultVelocitySolverNbIterations = settings.numVelocitySolverIterations;
rp3dWorldSettings.defaultPositionSolverNbIterations = settings.numPositionSolverIterations;
rp3dWorldSettings.isSleepingEnabled = settings.sleepingEnabled;
// These are my preferred default values. QoL for modifying these.
rp3dWorldSettings.defaultBounciness = 0.0f;
rp3dWorldSettings.defaultFrictionCoefficient = 0.4f;
world = factory.createPhysicsWorld(rp3dWorldSettings);
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
}
void SHPhysicsWorldState::DestroyWorld(rp3d::PhysicsCommon& factory)
{
if (!world)
return;
factory.destroyPhysicsWorld(world);
world = nullptr;
}
void SHPhysicsWorldState::UpdateSettings() const noexcept
{
if (!world)
{
SHLOGV_ERROR("Unable to update Physics World settings without creating a world!")
return;
}
world->setGravity(settings.gravity);
world->setNbIterationsVelocitySolver(settings.numVelocitySolverIterations);
world->setNbIterationsPositionSolver(settings.numPositionSolverIterations);
world->enableSleeping(settings.sleepingEnabled);
}
} // namespace SHADE

View File

@ -0,0 +1,74 @@
/****************************************************************************************
* \file SHPhysicsWorld.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics World.
*
* \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 <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/SHMath.h"
#include "SH_API.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
struct SH_API SHPhysicsWorldState
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct WorldSettings
{
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
SHVec3 gravity = SHVec3{ 0.0f, -9.81f, 0.0f };
uint16_t numVelocitySolverIterations = 15;
uint16_t numPositionSolverIterations = 8;
bool sleepingEnabled = true;
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
rp3d::PhysicsWorld* world;
WorldSettings settings;
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsWorldState() noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void CreateWorld (rp3d::PhysicsCommon& factory);
void DestroyWorld (rp3d::PhysicsCommon& factory);
/**
* @brief Applies the current settings to the physics world. The world must be created
* before this is called.
*/
void UpdateSettings () const noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,228 @@
/****************************************************************************************
* \file SHPhysicsDebugDrawSystem.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics Debug Draw System
*
* \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 "SHPhysicsDebugDrawSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[SHPhysicsDebugDrawSystem::NUM_FLAGS] =
{
SHPhysicsDebugDrawSystem::drawColliders
, SHPhysicsDebugDrawSystem::drawColliderAABBs
, SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs
, SHPhysicsDebugDrawSystem::drawContactPoints
, SHPhysicsDebugDrawSystem::drawContactNormals
};
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept
: debugDrawFlags { 0 }
, physicsSystem { nullptr }
, rp3dDebugRenderer { nullptr }
{
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER)] =
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB)] = SHColour::YELLOW;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB)] = SHColour::CYAN;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS)] = SHColour::RED;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS)] = SHColour::RED;
}
SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine()
: SHSystemRoutine { "Physics Debug Draw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept
{
const auto INT_FLAG = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS)
{
SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to get debug draw state!", INT_FLAG)
return false;
}
return debugDrawFlags & 1U << SHUtilities::ConvertEnum(flag);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept
{
const auto INT_FLAG = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS)
{
SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to set debug draw state!", INT_FLAG)
return;
}
value ? (debugDrawFlags |= 1U << INT_FLAG) : (debugDrawFlags &= ~(1U << INT_FLAG));
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::Init()
{
SystemFamily::GetID<SHPhysicsDebugDrawSystem>();
SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!")
physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
}
void SHPhysicsDebugDrawSystem::Exit()
{
physicsSystem = nullptr;
}
void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem());
for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i)
{
const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0;
if (DRAW)
drawFunctions[i](system->rp3dDebugRenderer);
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::drawColliders(rp3d::DebugRenderer* debugRenderer) noexcept
{
const auto& COLLIDER_SET = SHComponentManager::GetDense<SHColliderComponent>();
for (const auto& COLLIDER : COLLIDER_SET)
{
for (auto& collisionShape : COLLIDER.GetCollisionShapes())
{
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX: debugDrawBox(COLLIDER, collisionShape); break;
case SHCollisionShape::Type::SPHERE: debugDrawSphere(COLLIDER, collisionShape); break;
default: break;
}
}
}
}
void SHPhysicsDebugDrawSystem::drawColliderAABBs(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawContactPoints(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawContactNormals(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::debugDrawBox(const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept
{
static constexpr uint32_t NUM_BOX_VERTICES = 8;
static const SHVec3 boxVertices[NUM_BOX_VERTICES]
{
{ 0.5f, 0.5f, -0.5f } // TOP_RIGHT_BACK
, { -0.5f, 0.5f, -0.5f } // TOP_LEFT_BACK
, { 0.5f, -0.5f, -0.5f } // BTM_RIGHT_BACK
, { -0.5f, -0.5f, -0.5f } // BTM_LEFT_BACK
, { 0.5f, 0.5f, 0.5f } // TOP_RIGHT_FRONT
, { -0.5f, 0.5f, 0.5f } // TOP_LEFT_FRONT
, { 0.5f, -0.5f, 0.5f } // BTM_RIGHT_FRONT
, { -0.5f, -0.5f, 0.5f } // BTM_LEFT_FRONT
};
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!")
return;
}
auto* BOX = reinterpret_cast<const SHBoundingBox*>(collisionShape.GetShape());
// Calculate final position & orientation
const SHVec3 FINAL_POS = colliderComponent.GetPosition() + collisionShape.GetPositionOffset();
const SHQuaternion FINAL_ROT = colliderComponent.GetOrientation() * SHQuaternion::FromEuler(collisionShape.GetRotationOffset());
const SHMatrix BOX_TRS = SHMatrix::Scale(BOX->GetWorldExtents() * 2.0f) * SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(FINAL_POS);
const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN;
std::array<SHVec3, NUM_BOX_VERTICES> transformedVertices;
for (uint32_t i = 0; i < NUM_BOX_VERTICES / 2; ++i)
{
const uint32_t IDX1 = i;
const uint32_t IDX2 = i + NUM_BOX_VERTICES / 2;
transformedVertices[IDX1] = SHVec3::Transform(boxVertices[IDX1], BOX_TRS);
transformedVertices[IDX2] = SHVec3::Transform(boxVertices[IDX2], BOX_TRS);
// Draw 4 line to connect the quads
debugDrawSystem->DrawLine(COLLIDER_COLOUR, transformedVertices[IDX1], transformedVertices[IDX2]);
}
// A, B, C, D
std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] };
debugDrawSystem->DrawPoly(COLLIDER_COLOUR, backQuad.begin(), backQuad.end());
// E, F, G, H
std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] };
debugDrawSystem->DrawPoly(COLLIDER_COLOUR, frontQuad.begin(), frontQuad.end());
}
void SHPhysicsDebugDrawSystem::debugDrawSphere(const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept
{
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!")
return;
}
auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collisionShape.GetShape());
const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN;
// Calculate final position & orientation
const SHVec3 FINAL_POS = colliderComponent.GetPosition() + collisionShape.GetPositionOffset();
debugDrawSystem->DrawSphere(COLLIDER_COLOUR, FINAL_POS, SPHERE->GetWorldRadius());
}
} // namespace SHADE

View File

@ -0,0 +1,123 @@
/****************************************************************************************
* \file SHPhysicsDebugDrawSystem.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for the Physics Debug Draw System
*
* \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 <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Math/SHColour.h"
#include "SHPhysicsSystem.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsDebugDrawSystem final : public SHSystem
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class DebugDrawFlags
{
COLLIDER
, COLLIDER_AABB
, BROAD_PHASE_AABB
, CONTACT_POINTS
, CONTACT_NORMALS
, NUM_FLAGS
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem() noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init() override;
void Exit() override;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsDebugDrawRoutine();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
};
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using DebugDrawFunction = void(*)(rp3d::DebugRenderer*) noexcept;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS);
static const DebugDrawFunction drawFunctions[NUM_FLAGS];
uint8_t debugDrawFlags;
SHPhysicsSystem* physicsSystem;
rp3d::DebugRenderer* rp3dDebugRenderer;
SHColour debugColours[NUM_FLAGS];
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static void drawColliders (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawColliderAABBs (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawBroadPhaseAABBs (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawContactPoints (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawContactNormals (rp3d::DebugRenderer* debugRenderer) noexcept;
static void debugDrawBox (const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept;
static void debugDrawSphere (const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,343 @@
/****************************************************************************************
* \file SHPhysicsSystem.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics System
*
* \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 "SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Physics/SHPhysicsEvents.h"
#include "Scene/SHSceneManager.h"
/*-------------------------------------------------------------------------------------*/
/* Local Helper Functions */
/*-------------------------------------------------------------------------------------*/
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::SHPhysicsSystem()
: worldUpdated { false }
, interpolationFactor { 0.0 }
, fixedDT { 60.0 }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
double SHPhysicsSystem::GetFixedDT() const noexcept
{
return fixedDT;
}
const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept
{
return worldState.settings;
}
const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllCollisionInfo() const noexcept
{
return collisionListener.GetCollisionInfoContainer();
}
const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllTriggerInfo() const noexcept
{
return collisionListener.GetTriggerInfoContainer();
}
const SHPhysicsObject* const SHPhysicsSystem::GetPhysicsObject(EntityID eid) noexcept
{
return objectManager.GetPhysicsObject(eid);
}
const SHPhysicsObjectManager::PhysicsObjectEntityMap& SHPhysicsSystem::GetPhysicsObjects() const noexcept
{
return objectManager.physicsObjects;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept
{
fixedDT = fixedUpdateRate;
}
void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept
{
worldState.settings = settings;
worldState.UpdateSettings();
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::Init()
{
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::addPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::removePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
#ifdef SHEDITOR
// Subscribe to Editor State Change Events
const std::shared_ptr ON_PLAY_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::onPlay) };
const ReceiverPtr ON_PLAY_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ON_PLAY_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, ON_PLAY_RECEIVER_PTR);
const std::shared_ptr ON_STOP_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::onStop) };
const ReceiverPtr ON_STOP_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ON_STOP_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, ON_STOP_RECEIVER_PTR);
#endif
// Link Physics Object Manager with System
objectManager.SetFactory(factory);
// Link Collision Listener with System
collisionListener.BindToSystem(this);
}
void SHPhysicsSystem::Exit()
{
worldState.DestroyWorld(factory);
}
void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex)
{
static const auto ADD_SHAPE = [&](EntityID entityID, int index)
{
objectManager.AddCollisionShape(entityID, index);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = SHComponentManager::GetComponent<SHColliderComponent>(entityID)->GetCollisionShape(index).GetType()
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
};
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
ADD_SHAPE(eid, shapeIndex);
#else
ADD_SHAPE(eid, shapeIndex);
#endif
}
void SHPhysicsSystem::RemoveCollisionShape(EntityID eid, int shapeIndex)
{
static const auto REMOVE_SHAPE = [&](EntityID entityID, int index)
{
objectManager.RemoveCollisionShape(entityID, index);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = entityID
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
};
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
REMOVE_SHAPE(eid, shapeIndex);
#else
REMOVE_SHAPE(eid, shapeIndex);
#endif
}
void SHPhysicsSystem::AddForce(EntityID eid, const SHVec3& force) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddForceAtLocalPos(EntityID eid, const SHVec3& force, const SHVec3& localPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddForceAtWorldPos(EntityID eid, const SHVec3& force, const SHVec3& worldPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeForce(EntityID eid, const SHVec3& relativeForce) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID eid, const SHVec3& relativeForce, const SHVec3& localPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID eid, const SHVec3& relativeForce, const SHVec3& worldPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddTorque(EntityID eid, const SHVec3& torque) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeTorque(EntityID eid, const SHVec3& relativeTorque) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID EID = EVENT_DATA->data->eid;
// We only add tell the physics object manager to add a component if the scene is played
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID);
#else
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID);
#endif
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::removePhysicsComponent(SHEventPtr removeComponentEvent) noexcept
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID EID = EVENT_DATA->data->eid;
// We only add tell the physics object manager to remove a component if the scene is played
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID);
#else
REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID);
#endif
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::onPlay(SHEventPtr onPlayEvent)
{
static const auto BUILD_PHYSICS_OBJECT = [&](SHSceneNode* node)
{
const EntityID EID = node->GetEntityID();
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(EID))
objectManager.AddRigidBody(EID);
if (SHComponentManager::HasComponent<SHColliderComponent>(EID))
objectManager.AddCollider(EID);
};
////////////////////////////////
// Create physics world
worldState.CreateWorld(factory);
// Link Collision Listener
collisionListener.BindToWorld(worldState.world);
// Link with object manager & create all physics objects
objectManager.SetWorld(worldState.world);
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
SCENE_GRAPH.Traverse(BUILD_PHYSICS_OBJECT);
return onPlayEvent->handle;
}
SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent)
{
// Remove all physics objects
objectManager.RemoveAllObjects();
objectManager.SetWorld(nullptr);
// Clear all collision info
// Collision listener is automatically unbound when world is destroyed
collisionListener.ClearContainers();
// Destroy the world
worldState.DestroyWorld(factory);
return onStopEvent->handle;
}
} // namespace SHADE

View File

@ -0,0 +1,212 @@
/****************************************************************************************
* \file SHPhysicsSystem.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for the Physics System
*
* \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 <queue>
#include <unordered_map>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/Collision/SHCollisionListener.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/PhysicsObject//SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem final : public SHSystem
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsDebugDrawSystem;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem();
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllTriggerInfo () const noexcept;
[[nodiscard]] const SHPhysicsObject* const GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFixedDT (double fixedUpdateRate) noexcept;
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init () override;
void Exit () override;
// Specific Handling for Collision Shapes as they are not under the Component System
void AddCollisionShape (EntityID eid, int shapeIndex);
void RemoveCollisionShape (EntityID eid, int shapeIndex);
// Forces are applied from components here. These functions should only be invoked during play (through scripts)
// Thus there is no need to check for an editor.
void AddForce (EntityID eid, const SHVec3& force) noexcept;
void AddForceAtLocalPos (EntityID eid, const SHVec3& force, const SHVec3& localPos) noexcept;
void AddForceAtWorldPos (EntityID eid, const SHVec3& force, const SHVec3& worldPos) noexcept;
void AddRelativeForce (EntityID eid, const SHVec3& relativeForce) noexcept;
void AddRelativeForceAtLocalPos (EntityID eid, const SHVec3& relativeForce, const SHVec3& localPos) noexcept;
void AddRelativeForceAtWorldPos (EntityID eid, const SHVec3& relativeForce, const SHVec3& worldPos) noexcept;
void AddTorque (EntityID eid, const SHVec3& torque) noexcept;
void AddRelativeTorque (EntityID eid, const SHVec3& relativeTorque) noexcept;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPreUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept;
static void preUpdateSyncTransform
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
) noexcept;
};
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsFixedUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPostUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept;
};
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// System data
bool worldUpdated;
double interpolationFactor;
double fixedDT;
// rp3d
rp3d::PhysicsCommon factory;
// Interface objects
SHPhysicsWorldState worldState;
SHPhysicsObjectManager objectManager;
SHCollisionListener collisionListener;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept;
SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept;
SHEventHandle onPlay (SHEventPtr onPlayEvent);
SHEventHandle onStop (SHEventPtr onStopEvent);
};
} // namespace SHADE

View File

@ -16,35 +16,34 @@ of DigiPen Institute of Technology is prohibited.
#include "SHPhysicsSystemInterface.h" #include "SHPhysicsSystemInterface.h"
// Project Includes // Project Includes
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Physics/SHPhysicsUtils.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Static Usage Functions */ /* Static Usage Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept const std::vector<SHCollisionInfo>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept
{ {
static std::vector<SHCollisionEvent> emptyVec; static std::vector<SHCollisionInfo> emptyVec;
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem) if (phySystem)
{ {
return phySystem->GetCollisionInfo(); return phySystem->GetAllCollisionInfo();
} }
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead."); SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead.");
return emptyVec; return emptyVec;
} }
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept const std::vector<SHCollisionInfo>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept
{ {
static std::vector<SHCollisionEvent> emptyVec; static std::vector<SHCollisionInfo> emptyVec;
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem) if (phySystem)
{ {
return phySystem->GetTriggerInfo(); return phySystem->GetAllTriggerInfo();
} }
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead."); SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead.");

View File

@ -19,7 +19,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Forward Declarations */ /* Forward Declarations */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SHCollisionEvent; class SHCollisionInfo;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -39,8 +39,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Static Usage Functions */ /* Static Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo() noexcept; [[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo() noexcept;
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetTriggerInfo() noexcept; [[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo() noexcept;
[[nodiscard]] static double GetFixedDT() noexcept; [[nodiscard]] static double GetFixedDT() noexcept;
}; };
} }

View File

@ -0,0 +1,315 @@
/****************************************************************************************
* \file SHPhysicsSystemRoutines.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics System Routines
*
* \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 "SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Scripting/SHScriptEngine.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate()
: SHSystemRoutine { "Physics PreUpdate", true }
{}
SHPhysicsSystem::PhysicsFixedUpdate::PhysicsFixedUpdate()
: SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics FixedUpdate", false }
{}
SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate()
: SHSystemRoutine { "Physics PostUpdate", false }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
#ifdef SHEDITOR
auto* editor = SHSystemManager::GetSystem<SHEditor>();
// Only Sync on Play.
// Otherwise, Components are only holding data until the world is built on play.
if (editor)
{
if (editor->editorState != SHEditor::State::STOP)
{
physicsSystem->objectManager.UpdateCommands();
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
syncOnPlay(entityID, physicsObject);
}
}
else
{
auto& rigidBodyDense = SHComponentManager::GetDense<SHRigidBodyComponent>();
auto& colliderDense = SHComponentManager::GetDense<SHColliderComponent>();
for (auto& rigidBodyComponent : rigidBodyDense)
{
const auto* TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(rigidBodyComponent.GetEID());
if (TRANSFORM && TRANSFORM->HasChanged())
{
rigidBodyComponent.position = TRANSFORM->GetWorldPosition();
rigidBodyComponent.orientation = TRANSFORM->GetWorldOrientation();
}
}
for (auto& colliderComponent : colliderDense)
{
const auto* TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(colliderComponent.GetEID());
if (TRANSFORM && TRANSFORM->HasChanged())
{
colliderComponent.position = TRANSFORM->GetWorldPosition();
colliderComponent.orientation = TRANSFORM->GetWorldOrientation();
colliderComponent.scale = TRANSFORM->GetWorldScale();
colliderComponent.RecomputeCollisionShapes();
}
}
}
}
#else
// Always sync Rigid Body & Collider Components with Physics Objects
// Do not check for an editor here
physicsSystem->objectManager.UpdateCommands();
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
syncOnPlay(entityID, physicsObject);
}
#endif
}
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
accumulatedTime += dt;
int count = 0;
while (accumulatedTime > fixedTimeStep)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(fixedTimeStep));
accumulatedTime -= fixedTimeStep;
++count;
}
stats.numSteps = count;
physicsSystem->worldUpdated = count > 0;
physicsSystem->interpolationFactor = accumulatedTime / fixedTimeStep;
}
void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
// Interpolate transforms for rendering
if (physicsSystem->worldUpdated)
{
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects)
{
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (transformComponent)
{
postUpdateSyncTransforms
(
physicsObject
, *transformComponent
, rigidBodyComponent
, colliderComponent
, physicsSystem->interpolationFactor
);
}
}
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
// Since this function never runs when editor in not in play, execute the function anyway
physicsSystem->collisionListener.CleanContainers();
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::PhysicsPreUpdate::syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept
{
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(eid);
// Sync transforms & physics components transforms
if (transformComponent && transformComponent->HasChanged())
{
preUpdateSyncTransform
(
physicsObject
, *transformComponent
, rigidBodyComponent
, colliderComponent
);
}
// Sync Rigid Bodies
if (rigidBodyComponent)
physicsObject.SyncRigidBody(*rigidBodyComponent);
// Sync Colliders
if (colliderComponent)
physicsObject.SyncColliders(*colliderComponent);
}
void SHPhysicsSystem::PhysicsPreUpdate::preUpdateSyncTransform
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
) noexcept
{
const SHVec3& WORLD_POS = transformComponent.GetWorldPosition();
const SHQuaternion& WORLD_ROT = transformComponent.GetWorldOrientation();
const SHVec3& WORLD_SCL = transformComponent.GetWorldScale();
const rp3d::Transform RP3D_TRANSFORM { WORLD_POS, WORLD_ROT };
physicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM);
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
colliderComponent->scale = WORLD_SCL;
colliderComponent->RecomputeCollisionShapes();
}
}
void SHPhysicsSystem::PhysicsPostUpdate::postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept
{
rp3d::Vector3 rp3dPos;
rp3d::Quaternion rp3dRot;
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
// Check if transform should be interpolated
if (rigidBodyComponent)
{
// Skip static bodies
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
return;
if (rigidBodyComponent->IsInterpolating())
{
// Interpolate transforms between current and predicted next transform
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
rp3dPos = INTERPOLATED_TF.getPosition();
rp3dRot = INTERPOLATED_TF.getOrientation();
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (colliderComponent)
{
// Sync with colliders
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
// Convert RP3D Transform to SHADE
transformComponent.SetWorldPosition(rp3dPos);
transformComponent.SetWorldOrientation(rp3dRot);
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
}
} // namespace SHADE

View File

@ -21,6 +21,7 @@
#include "SH_API.h" #include "SH_API.h"
#include "ECS_Base/General/SHFamily.h" #include "ECS_Base/General/SHFamily.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "ECS_Base/Managers/SHComponentManager.h"
namespace SHADE namespace SHADE
{ {
@ -116,6 +117,56 @@ namespace SHADE
sceneChanged = true; sceneChanged = true;
} }
/********************************************************************
* \brief
* Check if the Entity's scene node is active and all the
* components specified are active.
* This does not check if the entity HasComponent. Please use
* CheckNodeAndHasComponentActive for that.
* \param eid
* EntityID of the entity to check for.
* \return
* true if scene node is active and all the components specified
* are also active.
********************************************************************/
template<typename ...ComponentTypes>
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), bool> CheckNodeAndComponentsActive(EntityID eid)
{
return CheckNodeActive(eid) && (... && SHComponentManager::GetComponent_s<ComponentTypes>(eid)->isActive);
}
/********************************************************************
* \brief
* Check if the Entity's scene node is active and all the
* components specified are active.
* This also checks to verify that the entity has such components.
* \param eid
* EntityID of the entity to check for.
* \return
* true if scene node is active and all the components specified
* are also active.
********************************************************************/
template<typename ...ComponentTypes>
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), bool> CheckNodeAndHasComponentsActive(EntityID eid)
{
return CheckNodeActive(eid)
&& (... && SHComponentManager::HasComponent<ComponentTypes>(eid))
&& (... && SHComponentManager::GetComponent_s<ComponentTypes>(eid)->isActive);
}
/********************************************************************
* \brief
* Check if Scene node is active.
* \param eid
* EntityID of the entity to check for.
* \return
* true if scene node is active
********************************************************************/
static bool CheckNodeActive(EntityID eid)
{
return GetCurrentSceneGraph().IsActiveInHierarchy(eid);
}
/*!************************************************************************* /*!*************************************************************************
* \brief * \brief

View File

@ -136,7 +136,7 @@ namespace SHADE
for (auto* child : children) for (auto* child : children)
{ {
SetActive(newActiveState); child->SetActive(newActiveState);
} }
} }

View File

@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited.
#include <fstream> // std::fstream #include <fstream> // std::fstream
#include <filesystem> // std::filesystem::canonical, std::filesystem::remove #include <filesystem> // std::filesystem::canonical, std::filesystem::remove
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <thread> // std::this_thread::sleep_for
// Project Headers // Project Headers
#include "Tools/SHLogger.h" #include "Tools/SHLogger.h"
#include "Tools/SHStringUtils.h" #include "Tools/SHStringUtils.h"
@ -24,7 +25,9 @@ of DigiPen Institute of Technology is prohibited.
#include "Events/SHEvent.h" #include "Events/SHEvent.h"
#include "Events/SHEventReceiver.h" #include "Events/SHEventReceiver.h"
#include "Events/SHEventManager.hpp" #include "Events/SHEventManager.hpp"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Physics/SHPhysicsEvents.h"
#include "Scene/SHSceneGraphEvents.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
@ -177,10 +180,10 @@ namespace SHADE
} }
// Prepare directory (delete useless files) // Prepare directory (delete useless files)
deleteFolder(CSPROJ_DIR + "\\net5.0"); deleteFolder(CSPROJ_DIR + "/net5.0");
deleteFolder(CSPROJ_DIR + "\\ref"); deleteFolder(CSPROJ_DIR + "/ref");
deleteFolder(CSPROJ_DIR + "\\obj"); deleteFolder(CSPROJ_DIR + "/obj");
deleteFolder(CSPROJ_DIR + "\\bin"); deleteFolder(CSPROJ_DIR + "/bin");
// Attempt to build the assembly // Attempt to build the assembly
std::ostringstream oss; std::ostringstream oss;
@ -214,7 +217,10 @@ namespace SHADE
// Clean up built files // Clean up built files
deleteFolder("./tmp"); deleteFolder("./tmp");
deleteFolder(CSPROJ_DIR + "\\obj"); deleteFolder(CSPROJ_DIR + "/bin");
using namespace std::chrono_literals;
std::this_thread::sleep_for(50ms); // Not sure why this works but it prevents the folders from respawning
deleteFolder(CSPROJ_DIR + "/obj");
// Read the build log and output to the console // Read the build log and output to the console
dumpBuildLog(BUILD_LOG_PATH); dumpBuildLog(BUILD_LOG_PATH);
@ -232,8 +238,13 @@ namespace SHADE
void SHScriptEngine::GenerateScriptsCsProjFile(const std::filesystem::path& path) const void SHScriptEngine::GenerateScriptsCsProjFile(const std::filesystem::path& path) const
{ {
// Compute relative path
const std::filesystem::path EXE_DIR = std::filesystem::current_path();
const std::filesystem::path MANAGED_DLL_DIR = EXE_DIR / "SHADE_Managed.dll";
const std::filesystem::path CS_DLL_DIR = EXE_DIR / "SHADE_CSharp.dll";
// Sample // Sample
static std::string_view FILE_CONTENTS = static std::string_view FILE_CONTENTS_BEGIN =
"<Project Sdk=\"Microsoft.NET.Sdk\">\n\ "<Project Sdk=\"Microsoft.NET.Sdk\">\n\
<PropertyGroup>\n\ <PropertyGroup>\n\
<TargetFramework>net5.0</TargetFramework>\n\ <TargetFramework>net5.0</TargetFramework>\n\
@ -263,14 +274,12 @@ namespace SHADE
<None Remove=\".gitmodules\" />\n\ <None Remove=\".gitmodules\" />\n\
</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\ static std::string_view FILE_CONTENTS_MID =
<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\ static std::string_view FILE_CONTENTS_END =
<HintPath Condition=\"Exists('..\\..\\bin\\Debug\\SHADE_Managed.dll')\">..\\..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\ " </Reference>\n\
<HintPath Condition=\"Exists('..\\..\\bin\\Release\\SHADE_Managed.dll')\">..\\..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\
</Reference>\n\
</ItemGroup>\n\ </ItemGroup>\n\
</Project>"; </Project>";
@ -280,7 +289,12 @@ namespace SHADE
throw std::runtime_error("Unable to create CsProj file!"); throw std::runtime_error("Unable to create CsProj file!");
// Fill the file // Fill the file
file << FILE_CONTENTS; const std::filesystem::path CSPROJ_DIR = path.parent_path();
file << FILE_CONTENTS_BEGIN
<< " <HintPath>" << std::filesystem::relative(MANAGED_DLL_DIR, CSPROJ_DIR).string() << "</HintPath>\n"
<< FILE_CONTENTS_MID
<< " <HintPath>" << std::filesystem::relative(CS_DLL_DIR, CSPROJ_DIR).string() << "</HintPath>\n"
<< FILE_CONTENTS_END;
// Close // Close
file.close(); file.close();

View File

@ -14,7 +14,7 @@
#include "Camera/SHCameraComponent.h" #include "Camera/SHCameraComponent.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
@ -61,20 +61,21 @@ namespace SHADE
out << YAML::EndSeq; out << YAML::EndSeq;
} }
static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID) static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, SHSerialization::CreatedEntitiesList& createdEntities, EntityID parentEID = MAX_EID)
{ {
EntityID eid = MAX_EID; EntityID eid{MAX_EID}, oldEID{MAX_EID};
if (!node) if (!node)
return eid; return eid;
if (node[EIDNode]) if (node[EIDNode])
eid = node[EIDNode].as<EntityID>(); oldEID = eid = node[EIDNode].as<EntityID>();
std::string name = "Default"; std::string name = "UnnamedEntitiy";
if (node[EntityNameNode]) if (node[EntityNameNode])
name = node[EntityNameNode].as<std::string>(); name = node[EntityNameNode].as<std::string>();
//Compile component IDs //Compile component IDs
const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]); const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]);
eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID); eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID);
createdEntities.push_back(eid); createdEntities[oldEID] = eid;
//createdEntities.push_back(eid);
if (node[NumberOfChildrenNode]) if (node[NumberOfChildrenNode])
{ {
if (const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0) if (const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0)
@ -106,7 +107,7 @@ namespace SHADE
return NewSceneName.data(); return NewSceneName.data();
} }
YAML::Node entities = YAML::Load(assetData->data); YAML::Node entities = YAML::Load(assetData->data);
std::vector<EntityID> createdEntities{}; CreatedEntitiesList createdEntities{};
//Create Entities //Create Entities
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
@ -122,14 +123,14 @@ namespace SHADE
AssetQueue assetQueue; AssetQueue assetQueue;
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
SHSerializationHelper::FetchAssetsFromComponent<SHRenderable>((*it)[ComponentsNode], *entityVecIt, assetQueue); SHSerializationHelper::FetchAssetsFromComponent<SHRenderable>((*it)[ComponentsNode], createdEntities[(*it)[EIDNode].as<EntityID>()], assetQueue);
} }
LoadAssetsFromAssetQueue(assetQueue); LoadAssetsFromAssetQueue(assetQueue);
//Initialize Entity //Initialize Entity
entityVecIt = createdEntities.begin(); entityVecIt = createdEntities.begin();
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
InitializeEntity(*it, *entityVecIt++); InitializeEntity(*it, createdEntities[(*it)[EIDNode].as<EntityID>()]);
} }
return assetData->name; return assetData->name;
@ -160,9 +161,9 @@ namespace SHADE
return std::string(out.c_str()); return std::string(out.c_str());
} }
void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path) //void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path)
{ //{
} //}
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
@ -218,13 +219,13 @@ namespace SHADE
return node; return node;
} }
EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept SHSerialization::CreatedEntitiesList SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept
{ {
if (data.empty()) if (data.empty())
return MAX_EID; return {};
YAML::Node entities = YAML::Load(data.c_str()); YAML::Node entities = YAML::Load(data.c_str());
EntityID eid{ MAX_EID }; EntityID eid{ MAX_EID };
std::vector<EntityID> createdEntities; CreatedEntitiesList createdEntities{};
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
eid = DeserializeEntity(it, *it, createdEntities, parentEID); eid = DeserializeEntity(it, *it, createdEntities, parentEID);
@ -232,14 +233,14 @@ namespace SHADE
if (createdEntities.empty()) if (createdEntities.empty())
{ {
SHLOG_ERROR("Failed to create entities from deserializaiton") SHLOG_ERROR("Failed to create entities from deserializaiton")
return MAX_EID; return createdEntities;
} }
auto entityVecIt = createdEntities.begin(); //auto entityVecIt = createdEntities.begin();
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
InitializeEntity(*it, *entityVecIt++); InitializeEntity(*it, createdEntities[(*it)[EIDNode].as<EntityID>()]);
} }
return eid; return createdEntities;
} }
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
@ -290,6 +291,41 @@ namespace SHADE
SHResourceManager::FinaliseChanges(); SHResourceManager::FinaliseChanges();
} }
void ResolveSerializedEntityID(YAML::Emitter& out, YAML::iterator& it, YAML::Node const& entityNode, SHSerialization::CreatedEntitiesList const& createdEntities)
{
EntityID eid = entityNode[EIDNode].as<EntityID>();
YAML::Node resolvedNode = entityNode;
resolvedNode[EIDNode] = createdEntities.at(eid);
out << resolvedNode;
if (entityNode[NumberOfChildrenNode])
{
if (const int numOfChildren = entityNode[NumberOfChildrenNode].as<int>(); numOfChildren > 0)
{
++it;
for (int i = 0; i < numOfChildren; ++i)
{
ResolveSerializedEntityID(out, it, (*it), createdEntities);
//DeserializeEntity(it, (*it), createdEntities, eid);
if ((i + 1) < numOfChildren)
++it;
}
}
}
}
std::string SHSerialization::ResolveSerializedEntityIndices(std::string serializedEntityData, CreatedEntitiesList const& createdEntities) noexcept
{
YAML::Node entities = YAML::Load(serializedEntityData);
YAML::Emitter out;
out << YAML::BeginSeq;
for (auto it = entities.begin(); it != entities.end(); ++it)
{
ResolveSerializedEntityID(out, it, (*it), createdEntities);
}
out << YAML::EndSeq;
return out.c_str();
}
void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid) void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid)
{ {
auto const componentsNode = entityNode[ComponentsNode]; auto const componentsNode = entityNode[ComponentsNode];

View File

@ -2,7 +2,6 @@
#include "SH_API.h" #include "SH_API.h"
#include <string> #include <string>
#include <filesystem>
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
@ -26,8 +25,12 @@ namespace SHADE
constexpr const char* NumberOfChildrenNode = "NumberOfChildren"; constexpr const char* NumberOfChildrenNode = "NumberOfChildren";
constexpr const char* ScriptsNode = "Scripts"; constexpr const char* ScriptsNode = "Scripts";
struct SH_API SHSerialization class SH_API SHSerialization
{ {
public:
//Original EID : New EID
using CreatedEntitiesList = std::unordered_map<EntityID, EntityID>;
static bool SerializeSceneToFile(AssetID const& sceneAssetID); static bool SerializeSceneToFile(AssetID const& sceneAssetID);
static std::string SerializeSceneToString(); static std::string SerializeSceneToString();
static void SerializeSceneToEmitter(YAML::Emitter& out); static void SerializeSceneToEmitter(YAML::Emitter& out);
@ -38,15 +41,18 @@ namespace SHADE
static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out); static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out);
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept; static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept;
static void SerializeEntityToFile(std::filesystem::path const& path); //static void SerializeEntityToFile(std::filesystem::path const& path);
static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode); static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode);
static EntityID DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept; static CreatedEntitiesList DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept;
static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode); static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode);
static void LoadAssetsFromAssetQueue(std::unordered_map<AssetID, AssetType>& assetQueue); static void LoadAssetsFromAssetQueue(std::unordered_map<AssetID, AssetType>& assetQueue);
static std::string ResolveSerializedEntityIndices(std::string serializedEntityData, CreatedEntitiesList const& createdEntities) noexcept;
private: private:
//static void ResolveSerializedEntityID(YAML::Emitter& out, YAML::iterator& it, YAML::Node const& entityNode, CreatedEntitiesList const& createdEntities);
static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid); static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid);
static constexpr std::string_view NewSceneName = "New Scene"; static constexpr std::string_view NewSceneName = "New Scene";

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/SHCollisionShape.h" #include "Physics/Interface/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"
@ -11,7 +11,7 @@
#include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
namespace YAML namespace YAML
{ {
using namespace SHADE; using namespace SHADE;
@ -130,14 +130,14 @@ namespace YAML
{ {
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
auto const bb = reinterpret_cast<SHBoundingBox*>(rhs.GetShape()); const auto* BOX = reinterpret_cast<const SHBoundingBox*>(rhs.GetShape());
node[HalfExtents] = bb->GetRelativeExtents(); node[HalfExtents] = BOX->GetRelativeExtents();
} }
break; break;
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
auto const bs = reinterpret_cast<SHBoundingSphere*>(rhs.GetShape()); const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs.GetShape());
node[Radius] = bs->GetRelativeRadius(); node[Radius] = SPHERE->GetRelativeRadius();
} }
break; break;
case SHCollisionShape::Type::CAPSULE: break; case SHCollisionShape::Type::CAPSULE: break;

View File

@ -0,0 +1,69 @@
#pragma once
#pragma once
#include "SH_API.h"
#include <deque>
namespace SHADE
{
template<typename T>
class SH_API SHDeque
{
public:
using ValueType = T;
using Pointer = T*;
using ValueRef = T&;
using ValueConstRef = T const&;
using SizeType = uint32_t;
using ContainerType = std::deque<ValueType>;
using ContainerTypeConstRef = std::deque<ValueType>;
SHDeque(SizeType n) : max_size(n) {}
ContainerTypeConstRef const& GetDeque() const
{
return deque;
}
void Push(ValueConstRef obj)
{
if (deque.size() < max_size)
deque.push_front(std::move(obj));
else
{
deque.pop_back();
deque.push_front(std::move(obj));
}
}
bool Empty()
{
return deque.empty();
}
void Pop()
{
deque.pop_front();
}
ValueConstRef Top()
{
return deque.front();
}
SizeType Size() const noexcept
{
return deque.size();
}
void Clear()
{
deque.clear();
}
private:
int max_size;
ContainerType deque{};
};
}

View File

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

Some files were not shown because too many files have changed in this diff Show More