diff --git a/Assets/Scenes/M2Scene.shade b/Assets/Scenes/M2Scene.shade index 68156787..21050428 100644 --- a/Assets/Scenes/M2Scene.shade +++ b/Assets/Scenes/M2Scene.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 0, z: 0} + Position: {x: 0, y: 0, z: 8} Pitch: 0 Yaw: 0 Roll: 0 @@ -36,8 +36,8 @@ RigidBody Component: Type: Static Mass: 1 - Drag: 0 - Angular Drag: 0 + Drag: 0.00999999978 + Angular Drag: 0.00999999978 Use Gravity: true Interpolate: true Freeze Position X: false @@ -56,18 +56,15 @@ Density: 1 Position Offset: {x: 0, y: 0, z: 0} Scripts: ~ -- EID: 2 - Name: Player +- EID: 10 + Name: Default IsActive: true - NumberOfChildren: 3 + NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -3.06177855, y: -2, z: -5} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 2, y: 2, z: 2} - Renderable Component: - Mesh: 149697411 - Material: 126974645 + Translate: {x: -4.40482807, y: 2.57871056, z: -5.21213436} + Rotate: {x: -0.361265004, y: 1.11661232, z: -0.626627684} + Scale: {x: 0.999982238, y: 0.999987125, z: 0.999981165} RigidBody Component: Type: Dynamic Mass: 1 @@ -89,7 +86,7 @@ Friction: 0.400000006 Bounciness: 0 Density: 1 - Position Offset: {x: 0, y: 0.5, z: 0} + Position Offset: {x: 0, y: 0, z: 0} Scripts: ~ - EID: 3 Name: Empty diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 6b67dbce..bf5b8d49 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -24,14 +24,15 @@ #include "Scene/SHSceneManager.h" // 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 "Camera/SHCameraSystem.h" +#include "FRC/SHFramerateController.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 #include "Graphics/MiddleEnd/Interface/SHRenderable.h" @@ -39,7 +40,6 @@ #include "Scenes/SBTestScene.h" - #include "Assets/SHAssetManager.h" #include "Scenes/SBMainScene.h" #include "Serialization/Configurations/SHConfigurationManager.h" @@ -67,16 +67,21 @@ namespace Sandbox window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow, wndData); // Create Systems - SHSystemManager::CreateSystem(); + SHSystemManager::CreateSystem(); - SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); - SHGraphicsSystem* graphicsSystem = static_cast(SHSystemManager::GetSystem()); + SHSystemManager::CreateSystem(); + SHSystemManager::CreateSystem(); + SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); - SHSystemManager::CreateSystem(); + + + SHSystemManager::CreateSystem(); + SHGraphicsSystem* graphicsSystem = static_cast(SHSystemManager::GetSystem()); // Link up SHDebugDraw + SHSystemManager::CreateSystem(); SHDebugDraw::Init(SHSystemManager::GetSystem()); #ifdef SHEDITOR @@ -101,7 +106,8 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); + + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); @@ -165,7 +171,7 @@ namespace Sandbox if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) { drawColliders = !drawColliders; - SHSystemManager::GetSystem()->SetDrawColliders(drawColliders); + SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders); } } // Finish all graphics jobs first diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp index 34190915..b14f2e6f 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -10,8 +10,8 @@ #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Physics/Components/SHRigidBodyComponent.h" -#include "Physics/Components/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Assets/SHAssetManager.h" diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 8281f114..bcc7f09d 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -10,8 +10,8 @@ #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Physics/Components/SHRigidBodyComponent.h" -#include "Physics/Components/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Assets/SHAssetManager.h" diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 85d10c1a..2e55ea7a 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -15,7 +15,7 @@ #include "Editor/SHEditorWidgets.hpp" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" -#include "Physics/Components/SHColliderComponent.h" +#include "Physics/Interface/SHColliderComponent.h" #include "Reflection/SHReflectionMetadata.h" #include "Resource/SHResourceManager.h" @@ -246,21 +246,21 @@ namespace SHADE if (collider->GetType() == SHCollisionShape::Type::BOX) { SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto box = reinterpret_cast(collider->GetShape()); + const auto* BOX = reinterpret_cast(collider->GetShape()); SHEditorWidgets::DragVec3 ( "Half Extents", { "X", "Y", "Z" }, - [box] { return box->GetRelativeExtents(); }, + [BOX] { return BOX->GetRelativeExtents(); }, [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } else if (collider->GetType() == SHCollisionShape::Type::SPHERE) { SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto sphere = reinterpret_cast(collider->GetShape()); + const auto* SPHERE = reinterpret_cast(collider->GetShape()); SHEditorWidgets::DragFloat ( "Radius", - [sphere] { return sphere->GetRelativeRadius(); }, + [SPHERE] { return SPHERE->GetRelativeRadius(); }, [collider](float const& value) { collider->SetBoundingSphere(value); }); } else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index dde49838..f240e321 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -14,8 +14,8 @@ #include "Scripting/SHScriptEngine.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/Components/SHRigidBodyComponent.h" -#include "Physics/Components/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" #include "Camera/SHCameraComponent.h" #include "Camera/SHCameraArmComponent.h" #include "SHEditorComponentView.h" diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp index 53adf2fe..de42d9a3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp @@ -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 { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index daa6a23d..60262607 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -317,13 +317,14 @@ namespace SHADE void SHDebugDrawSystem::drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, double radius) { - if (spherePoints.empty()) + //if (spherePoints.empty()) { + spherePoints.clear(); // Generate static const SHMeshData SPHERE = SHPrimitiveGenerator::Sphere(); 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()); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 02bd8f1f..51eaf5f1 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -379,7 +379,7 @@ namespace SHADE SHComponentManager::CreateComponentSparseSet(); 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 variableSizes{ NUM_LIGHT_TYPES }; std::fill (variableSizes.begin(), variableSizes.end(), 1); @@ -431,7 +431,7 @@ namespace SHADE /***************************************************************************/ 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(); bool expanded = false; @@ -451,7 +451,7 @@ namespace SHADE 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 // 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. 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) { UpdateDescSet(i); diff --git a/SHADE_Engine/src/Physics/SHPhysicsUtils.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp similarity index 72% rename from SHADE_Engine/src/Physics/SHPhysicsUtils.cpp rename to SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp index 14b6cc2f..43ad05ca 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsUtils.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHPhysicsUtils.cpp + * \file SHCollisionInfo.cpp * \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 * disclosure of this file or its contents without the prior written consent @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHPhysicsUtils.h" +#include "SHCollisionInfo.h" namespace SHADE { @@ -19,7 +19,7 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollisionEvent::SHCollisionEvent() noexcept + SHCollisionInfo::SHCollisionInfo() noexcept : collisionState { State::INVALID } { ids[ENTITY_A] = MAX_EID; @@ -28,7 +28,7 @@ namespace SHADE ids[COLLIDER_B] = std::numeric_limits::max(); } - SHCollisionEvent::SHCollisionEvent(EntityID entityA, EntityID entityB) noexcept + SHCollisionInfo::SHCollisionInfo(EntityID entityA, EntityID entityB) noexcept : collisionState { State::INVALID } { ids[ENTITY_A] = entityA; @@ -41,12 +41,12 @@ namespace SHADE /* 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]; } - 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]; } @@ -55,37 +55,37 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - EntityID SHCollisionEvent::GetEntityA() const noexcept + EntityID SHCollisionInfo::GetEntityA() const noexcept { return ids[ENTITY_A]; } - EntityID SHCollisionEvent::GetEntityB() const noexcept + EntityID SHCollisionInfo::GetEntityB() const noexcept { return ids[ENTITY_B]; } - const SHRigidBodyComponent* SHCollisionEvent::GetRigidBodyA() const noexcept + const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyA() const noexcept { return SHComponentManager::GetComponent_s(ids[ENTITY_A]); } - const SHRigidBodyComponent* SHCollisionEvent::GetRigidBodyB() const noexcept + const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyB() const noexcept { return SHComponentManager::GetComponent_s(ids[ENTITY_B]); } - const SHCollisionShape* SHCollisionEvent::GetColliderA() const noexcept + const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept { return &SHComponentManager::GetComponent(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]); } - const SHCollisionShape* SHCollisionEvent::GetColliderB() const noexcept + const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept { return &SHComponentManager::GetComponent(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]); } - SHCollisionEvent::State SHCollisionEvent::GetCollisionState() const noexcept + SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept { return collisionState; } diff --git a/SHADE_Engine/src/Physics/SHPhysicsUtils.h b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h similarity index 71% rename from SHADE_Engine/src/Physics/SHPhysicsUtils.h rename to SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h index 753f8d3b..d2dad647 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsUtils.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHPhysicsUtils.h + * \file SHCollisionInfo.h * \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 * disclosure of this file or its contents without the prior written consent @@ -11,8 +11,8 @@ #pragma once // Project Headers -#include "Components/SHColliderComponent.h" -#include "Components/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" namespace SHADE @@ -21,27 +21,14 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - struct SHPhysicsColliderAddedEvent - { - EntityID entityID; - SHCollisionShape::Type colliderType; - int colliderIndex; - }; - - struct SHPhysicsColliderRemovedEvent - { - EntityID entityID; - int colliderIndex; - }; - - class SH_API SHCollisionEvent + class SH_API SHCollisionInfo { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHPhysicsSystem; + friend class SHCollisionListener; public: /*---------------------------------------------------------------------------------*/ @@ -62,23 +49,23 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionEvent () noexcept; - SHCollisionEvent (EntityID entityA, EntityID entityB) noexcept; + SHCollisionInfo () noexcept; + SHCollisionInfo (EntityID entityA, EntityID entityB) noexcept; - SHCollisionEvent (const SHCollisionEvent& rhs) = default; - SHCollisionEvent (SHCollisionEvent&& rhs) = default; - ~SHCollisionEvent () = default; + SHCollisionInfo (const SHCollisionInfo& rhs) = default; + SHCollisionInfo (SHCollisionInfo&& rhs) = default; + ~SHCollisionInfo () = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - bool operator== (const SHCollisionEvent& rhs) const noexcept; - bool operator!= (const SHCollisionEvent& rhs) const noexcept; + bool operator== (const SHCollisionInfo& rhs) const noexcept; + bool operator!= (const SHCollisionInfo& rhs) const noexcept; - SHCollisionEvent& operator= (const SHCollisionEvent& rhs) = default; - SHCollisionEvent& operator= (SHCollisionEvent&& rhs) = default; + SHCollisionInfo& operator= (const SHCollisionInfo& rhs) = default; + SHCollisionInfo& operator= (SHCollisionInfo&& rhs) = default; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -88,8 +75,8 @@ namespace SHADE [[nodiscard]] EntityID GetEntityB () const noexcept; [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept; [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept; - [[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept; - [[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept; + [[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept; + [[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept; [[nodiscard]] State GetCollisionState () const noexcept; private: @@ -112,5 +99,4 @@ namespace SHADE State collisionState; }; - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp new file mode 100644 index 00000000..e8379b09 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp @@ -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 + +// 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::max(); +} + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionListener::SHCollisionListener() noexcept + : system { nullptr } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const std::vector& SHCollisionListener::GetCollisionInfoContainer() const noexcept + { + return collisionInfoContainer; + } + + const std::vector& 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& 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& 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(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(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h new file mode 100644 index 00000000..6262b946 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h @@ -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 + +// 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& GetCollisionInfoContainer () const noexcept; + [[nodiscard]] const std::vector& 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 collisionInfoContainer; + std::vector triggerInfoContainer; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + static void updateInfoContainers (const SHCollisionInfo& collisionEvent, std::vector& container) noexcept; + + SHCollisionInfo generateCollisionInfo (const rp3d::CollisionCallback::ContactPair& cp) const noexcept; + SHCollisionInfo generateTriggerInfo (const rp3d::OverlapCallback::OverlapPair& cp) const noexcept; + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp similarity index 89% rename from SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp rename to SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index 93126fc5..1c8149ad 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -16,7 +16,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/SHMathHelpers.h" -#include "Physics/SHPhysicsSystem.h" +#include "Physics/System/SHPhysicsSystem.h" namespace SHADE { @@ -72,7 +72,14 @@ namespace SHADE void SHColliderComponent::OnCreate() { - system = SHSystemManager::GetSystem(); + auto* physicsSystem = SHSystemManager::GetSystem(); + if (!physicsSystem) + { + SHLOG_ERROR("Physics System does not exist to link with Physics Components!") + return; + } + + system = physicsSystem; } void SHColliderComponent::OnDestroy() @@ -88,7 +95,7 @@ namespace SHADE { case SHCollisionShape::Type::BOX: { - auto* box = reinterpret_cast(collisionShape.GetShape()); + auto* box = reinterpret_cast(collisionShape.shape); const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents(); // Recompute world extents based on new scale and fixed relative extents @@ -99,7 +106,7 @@ namespace SHADE } case SHCollisionShape::Type::SPHERE: { - auto* sphere = reinterpret_cast(collisionShape.GetShape()); + auto* sphere = reinterpret_cast(collisionShape.shape); const float RELATIVE_RADIUS = sphere->GetRelativeRadius(); // Recompute world radius based on new scale and fixed radius @@ -132,9 +139,10 @@ namespace SHADE collider.SetBoundingBox(halfExtents); // Notify Physics System - system->AddCollisionShape(GetEID(), &collider); + const int NEW_SHAPE_INDEX = static_cast(collisionShapes.size()) - 1; - return static_cast(collisionShapes.size()) - 1; + system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX); + return NEW_SHAPE_INDEX; } int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept @@ -154,9 +162,10 @@ namespace SHADE collider.SetBoundingSphere(radius); // Notify Physics System - system->AddCollisionShape(GetEID(), &collider); + const int NEW_SHAPE_INDEX = static_cast(collisionShapes.size()) - 1; - return static_cast(collisionShapes.size()) - 1; + system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX); + return NEW_SHAPE_INDEX; } void SHColliderComponent::RemoveCollider(int index) diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h similarity index 98% rename from SHADE_Engine/src/Physics/Components/SHColliderComponent.h rename to SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index 5f9b7a1b..88dc306f 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -14,9 +14,9 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" -#include "Physics/SHCollisionShape.h" #include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingSphere.h" +#include "SHCollisionShape.h" //namespace SHADE //{ diff --git a/SHADE_Engine/src/Physics/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp similarity index 98% rename from SHADE_Engine/src/Physics/SHCollisionShape.cpp rename to SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp index c8f8020c..1ea2a7d3 100644 --- a/SHADE_Engine/src/Physics/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp @@ -16,8 +16,8 @@ #include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingSphere.h" #include "Math/SHMathHelpers.h" -#include "Physics/Components/SHColliderComponent.h" #include "Reflection/SHReflectionMetadata.h" +#include "SHColliderComponent.h" namespace SHADE { @@ -164,9 +164,8 @@ namespace SHADE return rotationOffset; } - SHShape* SHCollisionShape::GetShape() noexcept + const SHShape* SHCollisionShape::GetShape() const noexcept { - dirty = true; return shape; } diff --git a/SHADE_Engine/src/Physics/SHCollisionShape.h b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h similarity index 98% rename from SHADE_Engine/src/Physics/SHCollisionShape.h rename to SHADE_Engine/src/Physics/Interface/SHCollisionShape.h index 9c8c1d41..526428fd 100644 --- a/SHADE_Engine/src/Physics/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h @@ -82,7 +82,7 @@ namespace SHADE [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; - [[nodiscard]] SHShape* GetShape () noexcept; + [[nodiscard]] const SHShape* GetShape () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ diff --git a/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp b/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp similarity index 100% rename from SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp rename to SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp diff --git a/SHADE_Engine/src/Physics/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h similarity index 100% rename from SHADE_Engine/src/Physics/SHPhysicsMaterial.h rename to SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp similarity index 55% rename from SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp rename to SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index 369d26a5..5fe1e55e 100644 --- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -19,7 +19,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/SHMathHelpers.h" -#include "Physics/SHPhysicsSystem.h" +#include "Physics/System/SHPhysicsSystem.h" namespace SHADE { @@ -30,8 +30,17 @@ namespace SHADE SHRigidBodyComponent::SHRigidBodyComponent() noexcept : type { Type::DYNAMIC } , interpolate { true } - , rp3dBody { nullptr } - {} + , flags { 0 } + , dirtyFlags { std::numeric_limits::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 */ @@ -39,24 +48,14 @@ namespace SHADE bool SHRigidBodyComponent::IsGravityEnabled() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - return rp3dBody->isGravityEnabled(); + static constexpr int FLAG_POS = 0; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - return rp3dBody->isAllowedToSleep(); + static constexpr int FLAG_POS = 1; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::IsInterpolating() const noexcept @@ -71,151 +70,85 @@ namespace SHADE float SHRigidBodyComponent::GetMass() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return 0.0f; - } - - return rp3dBody->getMass(); + return mass; } float SHRigidBodyComponent::GetDrag() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return 0.0f; - } - - return rp3dBody->getLinearDamping(); + return drag; } float SHRigidBodyComponent::GetAngularDrag() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return 0.0f; - } - - return rp3dBody->getAngularDamping(); + return angularDrag; } bool SHRigidBodyComponent::GetFreezePositionX() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor(); - return SHMath::CompareFloat(LINEAR_CONSTRAINTS.x, 0.0f); + static constexpr int FLAG_POS = 2; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezePositionY() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor(); - return SHMath::CompareFloat(LINEAR_CONSTRAINTS.y, 0.0f); + static constexpr int FLAG_POS = 3; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor(); - return SHMath::CompareFloat(LINEAR_CONSTRAINTS.z, 0.0f); + static constexpr int FLAG_POS = 4; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor(); - return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.x, 0.0f); + static constexpr int FLAG_POS = 5; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor(); - return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.y, 0.0f); + static constexpr int FLAG_POS = 6; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } - - const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor(); - return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.z, 0.0f); + static constexpr int FLAG_POS = 7; + return flags & (1U << FLAG_POS); } SHVec3 SHRigidBodyComponent::GetForce() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return false; - } + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getForce(); - return rp3dBody->getForce(); + return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetTorque() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return SHVec3::Zero; - } + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getTorque(); - return rp3dBody->getTorque(); + return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return SHVec3::Zero; - } + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getLinearVelocity(); - return rp3dBody->getLinearVelocity(); + return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return SHVec3::Zero; - } + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getAngularVelocity(); - return rp3dBody->getAngularVelocity(); + return SHVec3::Zero; } const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept @@ -239,18 +172,13 @@ namespace SHADE void SHRigidBodyComponent::SetType(Type newType) noexcept { + static constexpr int FLAG_POS = 8; + if (type == newType) return; type = newType; - - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setType(static_cast(type)); + dirtyFlags |= 1U << FLAG_POS; } void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept @@ -263,13 +191,8 @@ namespace SHADE return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->enableGravity(enableGravity); + dirtyFlags |= 1U << FLAG_POS; + enableGravity ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept @@ -282,127 +205,92 @@ namespace SHADE return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setIsAllowedToSleep(isAllowedToSleep); + dirtyFlags |= 1U << FLAG_POS; + isAllowedToSleep ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept { + static constexpr int FLAG_POS = 2; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - auto linearConstraints = rp3dBody->getLinearLockAxisFactor(); - linearConstraints.x = freezePositionX ? 0.0f : 1.0f; - rp3dBody->setLinearLockAxisFactor(linearConstraints); + dirtyFlags |= 1U << FLAG_POS; + freezePositionX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept { + static constexpr int FLAG_POS = 3; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - auto linearConstraints = rp3dBody->getLinearLockAxisFactor(); - linearConstraints.y = freezePositionY ? 0.0f : 1.0f; - rp3dBody->setLinearLockAxisFactor(linearConstraints); + dirtyFlags |= 1U << FLAG_POS; + freezePositionY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept { + static constexpr int FLAG_POS = 4; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - auto linearConstraints = rp3dBody->getLinearLockAxisFactor(); - linearConstraints.z = freezePositionZ ? 0.0f : 1.0f; - rp3dBody->setLinearLockAxisFactor(linearConstraints); + dirtyFlags |= 1U << FLAG_POS; + freezePositionZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept { + static constexpr int FLAG_POS = 5; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - auto angularConstraints = rp3dBody->getAngularLockAxisFactor(); - angularConstraints.x = freezeRotationX ? 0.0f : 1.0f; - rp3dBody->setAngularLockAxisFactor(angularConstraints); + dirtyFlags |= 1U << FLAG_POS; + freezeRotationX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept { + static constexpr int FLAG_POS = 6; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - auto angularConstraints = rp3dBody->getAngularLockAxisFactor(); - angularConstraints.y = freezeRotationY ? 0.0f : 1.0f; - rp3dBody->setAngularLockAxisFactor(angularConstraints); + dirtyFlags |= 1U << FLAG_POS; + freezeRotationY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept { + static constexpr int FLAG_POS = 7; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - auto angularConstraints = rp3dBody->getAngularLockAxisFactor(); - angularConstraints.z = freezeRotationZ ? 0.0f : 1.0f; - rp3dBody->setAngularLockAxisFactor(angularConstraints); + dirtyFlags |= 1U << FLAG_POS; + freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept @@ -412,179 +300,127 @@ namespace SHADE void SHRigidBodyComponent::SetMass(float newMass) noexcept { + static constexpr int FLAG_POS = 9; + if (type != Type::DYNAMIC) { SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setMass(newMass); + dirtyFlags |= 1U << FLAG_POS; + mass = newMass; } void SHRigidBodyComponent::SetDrag(float newDrag) noexcept { + static constexpr int FLAG_POS = 10; + if (type != Type::DYNAMIC) { SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setLinearDamping(newDrag); + dirtyFlags |= 1U << FLAG_POS; + drag = newDrag; } void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept { + static constexpr int FLAG_POS = 11; + if (type != Type::DYNAMIC) { SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setLinearDamping(newAngularDrag); + dirtyFlags |= 1U << FLAG_POS; + angularDrag = newAngularDrag; } void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setLinearVelocity(newLinearVelocity); + auto* physicsObject = system->GetPhysicsObject(GetEID()); + physicsObject->GetRigidBody()->setLinearVelocity(newLinearVelocity); } void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept { + static constexpr int FLAG_POS = 13; + if (type == Type::STATIC) { SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID()) return; } - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->setAngularVelocity(newAngularVelocity); + auto* physicsObject = system->GetPhysicsObject(GetEID()); + physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity); } /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept + void SHRigidBodyComponent::OnCreate() { - if (rp3dBody == nullptr) + auto* physicsSystem = SHSystemManager::GetSystem(); + if (!physicsSystem) { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) + SHLOG_ERROR("Physics System does not exist to link with Physics Components!") 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 { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyWorldForceAtLocalPosition(force, localPos); + system->AddForceAtLocalPos(GetEID(), force, localPos); } void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyWorldForceAtWorldPosition(force, worldPos); + system->AddForceAtWorldPos(GetEID(), force, worldPos); } void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyLocalForceAtCenterOfMass(relativeForce); + system->AddRelativeForce(GetEID(), relativeForce); } void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos); + system->AddRelativeForceAtLocalPos(GetEID(), relativeForce, localPos); } void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos); + system->AddRelativeForceAtWorldPos(GetEID(), relativeForce, worldPos); } void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyWorldTorque(torque); + system->AddTorque(GetEID(), torque); } void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept { - if (rp3dBody == nullptr) - { - SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) - return; - } - - rp3dBody->applyLocalTorque(relativeTorque); + system->AddRelativeTorque(GetEID(), relativeTorque); } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h similarity index 78% rename from SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h rename to SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index ba7d2dd9..48a5d723 100644 --- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -17,16 +17,6 @@ #include "Math/Vector/SHVec3.h" #include "Math/SHQuaternion.h" -//namespace SHADE -//{ -// class SHPhysicsSystem; -//} - -namespace reactphysics3d -{ - class RigidBody; -} - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -107,29 +97,31 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetType (Type newType) noexcept; + void SetType (Type newType) noexcept; - void SetGravityEnabled (bool enableGravity) noexcept; - void SetIsAllowedToSleep(bool isAllowedToSleep) noexcept; - void SetFreezePositionX (bool freezePositionX) noexcept; - void SetFreezePositionY (bool freezePositionY) noexcept; - void SetFreezePositionZ (bool freezePositionZ) noexcept; - void SetFreezeRotationX (bool freezeRotationX) noexcept; - void SetFreezeRotationY (bool freezeRotationY) noexcept; - void SetFreezeRotationZ (bool freezeRotationZ) noexcept; - void SetInterpolate (bool allowInterpolation) noexcept; + void SetGravityEnabled (bool enableGravity) noexcept; + void SetIsAllowedToSleep (bool isAllowedToSleep) noexcept; + void SetFreezePositionX (bool freezePositionX) noexcept; + void SetFreezePositionY (bool freezePositionY) noexcept; + void SetFreezePositionZ (bool freezePositionZ) noexcept; + void SetFreezeRotationX (bool freezeRotationX) noexcept; + void SetFreezeRotationY (bool freezeRotationY) noexcept; + void SetFreezeRotationZ (bool freezeRotationZ) noexcept; + void SetInterpolate (bool allowInterpolation) noexcept; - void SetMass (float newMass) noexcept; - void SetDrag (float newDrag) noexcept; - void SetAngularDrag (float newAngularDrag) noexcept; + void SetMass (float newMass) noexcept; + void SetDrag (float newDrag) noexcept; + void SetAngularDrag (float newAngularDrag) noexcept; - void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; - void SetAngularVelocity (const SHVec3& newAngularVelocity) noexcept; + void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; + void SetAngularVelocity (const SHVec3& newAngularVelocity) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ + void OnCreate () override; + void AddForce (const SHVec3& force) const noexcept; void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept; void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept; @@ -147,15 +139,25 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ 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; - bool interpolate; + Type type; - 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 - SHVec3 position; - SHQuaternion orientation; + float mass; + float drag; + float angularDrag; + + SHVec3 linearVelocity; + SHVec3 angularVelocity; + + SHPhysicsSystem* system; + + SHVec3 position; + SHQuaternion orientation; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp new file mode 100644 index 00000000..0c9fa405 --- /dev/null +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp @@ -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 + +// 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(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(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(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(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(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(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(boxShape.GetShape()); + + auto* rp3dCollider = rp3dBody->getCollider(index); + auto* rp3dBox = reinterpret_cast(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(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(sphereShape.GetShape()); + + auto* rp3dCollider = rp3dBody->getCollider(index); + auto* rp3dSphere = reinterpret_cast(rp3dCollider->getCollisionShape()); + + const rp3d::Transform OFFSETS + { + sphereShape.GetPositionOffset() + , sphereShape.GetRotationOffset() + }; + + rp3dCollider->setIsTrigger(sphereShape.IsTrigger()); + rp3dCollider->setLocalToBodyTransform(OFFSETS); + + rp3dSphere->setRadius(SPHERE->GetWorldRadius()); + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h similarity index 70% rename from SHADE_Engine/src/Physics/SHPhysicsObject.h rename to SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h index 09b70b11..f18a0738 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h @@ -14,8 +14,8 @@ // Project Headers #include "Math/Transform/SHTransformComponent.h" -#include "Components/SHRigidBodyComponent.h" -#include "Components/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" namespace SHADE { @@ -31,6 +31,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; + friend class SHPhysicsObjectManager; public: /*---------------------------------------------------------------------------------*/ @@ -53,26 +54,29 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetPosition () const noexcept; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept; - [[nodiscard]] SHVec3 GetRotation () const noexcept; + [[nodiscard]] SHVec3 GetPosition () const noexcept; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; + + [[nodiscard]] rp3d::CollisionBody* GetCollisionBody () const noexcept; + [[nodiscard]] rp3d::RigidBody* GetRigidBody () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetPosition (const SHVec3& position) noexcept; - void SetOrientation (const SHQuaternion& orientation) noexcept; - void SetRotation (const SHVec3& rotation) noexcept; + void SetStaticBody () const noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - int AddCollider (SHCollisionShape* collider); - void RemoveCollider (int index); + int AddCollisionShape (int index) const; + 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: /*---------------------------------------------------------------------------------*/ @@ -83,7 +87,22 @@ namespace SHADE rp3d::PhysicsCommon* factory; 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 + + /*---------------------------------------------------------------------------------*/ + /* 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp new file mode 100644 index 00000000..13f525e6 --- /dev/null +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp @@ -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 + +// 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(COMMAND.eid) + , .colliderComponent = SHComponentManager::GetComponent_s(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(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(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h new file mode 100644 index 00000000..d8c9b805 --- /dev/null +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h @@ -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 +#include + +#include + +// 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; + + 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 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsEvents.h b/SHADE_Engine/src/Physics/SHPhysicsEvents.h new file mode 100644 index 00000000..ae48a75b --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsEvents.h @@ -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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp deleted file mode 100644 index 00c6943b..00000000 --- a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp +++ /dev/null @@ -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 - -// 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(collider->GetShape()); - rp3d::BoxShape* newBox = factory->createBoxShape(box->GetWorldExtents()); - - rp3dBody->addCollider(newBox, OFFSETS); - break; - } - case SHCollisionShape::Type::SPHERE: - { - const auto* sphere = reinterpret_cast(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(rp3dBody->getNbColliders()) - 1; - } - - void SHPhysicsObject::RemoveCollider(int index) - { - const int NUM_COLLIDERS = static_cast(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(collider.GetShape()); - - auto* rp3dBoxShape = reinterpret_cast(rp3dCollider->getCollisionShape()); - rp3dBoxShape->setHalfExtents(box->GetWorldExtents()); - - break; - } - case SHCollisionShape::Type::SPHERE: - { - const auto* sphere = reinterpret_cast(collider.GetShape()); - - auto* rp3dSphereShape = reinterpret_cast(rp3dCollider->getCollisionShape()); - rp3dSphereShape->setRadius(sphere->GetWorldRadius()); - - break; - } - default: break; - } - - // TODO(Diren): Update Material - - collider.dirty = false; - ++index; - } - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp deleted file mode 100644 index 437b5ff8..00000000 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ /dev/null @@ -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 - -// 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>(this, &SHPhysicsSystem::AddPhysicsComponent) }; - const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(ADD_COMPONENT_RECEIVER); - SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR); - - const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::RemovePhysicsComponent) }; - const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(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>(this, &SHPhysicsSystem::ResetWorld) }; - const ReceiverPtr EDITOR_STOP_RECEIVER_PTR = std::dynamic_pointer_cast(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(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(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); - } - - void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept - { - auto* system = reinterpret_cast(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(entityID); - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - auto* colliderComponent = SHComponentManager::GetComponent_s(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(GetSystem()); - auto* scriptingSystem = SHSystemManager::GetSystem(); - 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(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(GetSystem()); - auto* scriptingSystem = SHSystemManager::GetSystem(); - 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(GetSystem()); - if (PHYSICS_SYSTEM->debugDrawFlags == 0) - return; - - auto* debugDrawSystem = SHSystemManager::GetSystem(); - 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(entityID); - auto* colliderComponent = SHComponentManager::GetComponent_s(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(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(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*>(addComponentEvent.get()); - - static const auto RIGID_BODY_ID = ComponentFamily::GetID(); - static const auto COLLIDER_ID = ComponentFamily::GetID(); - - 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(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(ENTITY_ID); - auto* colliderComponent = SHComponentManager::GetComponent_s(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(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*>(removeComponentEvent.get()); - - static const auto RIGID_BODY_ID = ComponentFamily::GetID(); - static const auto COLLIDER_ID = ComponentFamily::GetID(); - - 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(ENTITY_ID); - auto* colliderComponent = SHComponentManager::GetComponent_s(ENTITY_ID); - - // Wake up all physics objects - for (auto& [entityID, object] : map) - { - if (SHComponentManager::HasComponent(entityID)) - reinterpret_cast(object.rp3dBody)->setIsSleeping(false); - } - - if (REMOVED_ID == RIGID_BODY_ID && physicsObject != nullptr) - { - world->destroyRigidBody(reinterpret_cast(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(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(entityID)) - { - auto* rp3dRigidBody = reinterpret_cast(physicsObject.rp3dBody); - rp3dRigidBody->resetForce(); - rp3dRigidBody->resetTorque(); - rp3dRigidBody->setLinearVelocity(SHVec3::Zero); - rp3dRigidBody->setAngularVelocity(SHVec3::Zero); - } - } - - return editorStopEvent->handle; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/SHPhysicsSystem.h deleted file mode 100644 index 55575c73..00000000 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.h +++ /dev/null @@ -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 -#include - -#include - -// 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; - - 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; - - /*---------------------------------------------------------------------------------*/ - /* 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 - || std::is_same_v>> - SHCollisionEvent GenerateCollisionEvent (const RP3DCollisionPair& cp) noexcept; - }; -} // namespace SHADE - -#include "SHPhysicsSystem.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.hpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.hpp deleted file mode 100644 index 957fb3aa..00000000 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.hpp +++ /dev/null @@ -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 - -// Primary Header -#include "SHPhysicsSystem.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - template - 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::max(); - }; - - SHCollisionEvent cInfo; - - // Update collision state - cInfo.collisionState = static_cast(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp new file mode 100644 index 00000000..85e76702 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp @@ -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 + +// 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/SHPhysicsWorld.h new file mode 100644 index 00000000..091ae062 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsWorld.h @@ -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 + +// 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp new file mode 100644 index 00000000..ff441ac2 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -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 + +// 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(); + + SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!") + physicsSystem = SHSystemManager::GetSystem(); + } + + void SHPhysicsDebugDrawSystem::Exit() + { + physicsSystem = nullptr; + } + + void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept + { + auto* system = reinterpret_cast(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(); + 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(); + if (debugDrawSystem == nullptr) + { + SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") + return; + } + + auto* BOX = reinterpret_cast(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 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(); + if (debugDrawSystem == nullptr) + { + SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") + return; + } + + auto* SPHERE = reinterpret_cast(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h new file mode 100644 index 00000000..53037ab2 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -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 + +// 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 diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp new file mode 100644 index 00000000..34f0c698 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -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 + +// 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& SHPhysicsSystem::GetAllCollisionInfo() const noexcept + { + return collisionListener.GetCollisionInfoContainer(); + } + + const std::vector& 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>(this, &SHPhysicsSystem::addPhysicsComponent) }; + const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(ADD_COMPONENT_RECEIVER); + SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR); + + const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::removePhysicsComponent) }; + const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(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>(this, &SHPhysicsSystem::onPlay) }; + const ReceiverPtr ON_PLAY_RECEIVER_PTR = std::dynamic_pointer_cast(ON_PLAY_RECEIVER); + SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, ON_PLAY_RECEIVER_PTR); + + const std::shared_ptr ON_STOP_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::onStop) }; + const ReceiverPtr ON_STOP_RECEIVER_PTR = std::dynamic_pointer_cast(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(entityID)->GetCollisionShape(index).GetType() + , .colliderIndex = index + }; + + SHEventManager::BroadcastEvent(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + }; + + #ifdef SHEDITOR + + const auto* EDITOR = SHSystemManager::GetSystem(); + 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(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); + }; + + #ifdef SHEDITOR + + const auto* EDITOR = SHSystemManager::GetSystem(); + 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*>(addComponentEvent.get()); + + static const auto RIGID_BODY_ID = ComponentFamily::GetID(); + static const auto COLLIDER_ID = ComponentFamily::GetID(); + + 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(); + + 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*>(removeComponentEvent.get()); + + static const auto RIGID_BODY_ID = ComponentFamily::GetID(); + static const auto COLLIDER_ID = ComponentFamily::GetID(); + + 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(); + + 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(EID)) + objectManager.AddRigidBody(EID); + + if (SHComponentManager::HasComponent(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h new file mode 100644 index 00000000..4254efc7 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -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 +#include + +// External Dependencies +#include + +// 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& GetAllCollisionInfo () const noexcept; + [[nodiscard]] const std::vector& 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp similarity index 81% rename from SHADE_Engine/src/Physics/SHPhysicsSystemInterface.cpp rename to SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index 4b292340..30d29167 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -16,35 +16,34 @@ of DigiPen Institute of Technology is prohibited. #include "SHPhysicsSystemInterface.h" // Project Includes #include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/SHPhysicsSystem.h" -#include "Physics/SHPhysicsUtils.h" +#include "Physics/System/SHPhysicsSystem.h" namespace SHADE { /*-----------------------------------------------------------------------------------*/ /* Static Usage Functions */ /*-----------------------------------------------------------------------------------*/ - const std::vector& SHPhysicsSystemInterface::GetCollisionInfo() noexcept + const std::vector& SHPhysicsSystemInterface::GetCollisionInfo() noexcept { - static std::vector emptyVec; + static std::vector emptyVec; auto phySystem = SHSystemManager::GetSystem(); if (phySystem) { - return phySystem->GetCollisionInfo(); + return phySystem->GetAllCollisionInfo(); } SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead."); return emptyVec; } - const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept + const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept { - static std::vector emptyVec; + static std::vector emptyVec; auto phySystem = SHSystemManager::GetSystem(); if (phySystem) { - return phySystem->GetTriggerInfo(); + return phySystem->GetAllTriggerInfo(); } SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead."); diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h similarity index 91% rename from SHADE_Engine/src/Physics/SHPhysicsSystemInterface.h rename to SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index da6a0433..bdd04686 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -19,7 +19,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Forward Declarations */ /*-----------------------------------------------------------------------------------*/ - class SHCollisionEvent; + class SHCollisionInfo; /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -39,8 +39,8 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo() noexcept; + [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo() noexcept; [[nodiscard]] static double GetFixedDT() noexcept; }; } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp new file mode 100644 index 00000000..059202e5 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp @@ -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 + +// 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(GetSystem()); + + #ifdef SHEDITOR + + auto* editor = SHSystemManager::GetSystem(); + + // 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(); + auto& colliderDense = SHComponentManager::GetDense(); + + for (auto& rigidBodyComponent : rigidBodyDense) + { + const auto* TRANSFORM = SHComponentManager::GetComponent_s(rigidBodyComponent.GetEID()); + + if (TRANSFORM && TRANSFORM->HasChanged()) + { + rigidBodyComponent.position = TRANSFORM->GetWorldPosition(); + rigidBodyComponent.orientation = TRANSFORM->GetWorldOrientation(); + } + } + + for (auto& colliderComponent : colliderDense) + { + const auto* TRANSFORM = SHComponentManager::GetComponent_s(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(GetSystem()); + auto* scriptingSystem = SHSystemManager::GetSystem(); + 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(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(GetSystem()); + auto* scriptingSystem = SHSystemManager::GetSystem(); + + 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(entityID); + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); + auto* colliderComponent = SHComponentManager::GetComponent_s(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(eid); + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(eid); + auto* colliderComponent = SHComponentManager::GetComponent_s(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(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 18c2b9e3..1fa4e6d7 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -25,7 +25,10 @@ of DigiPen Institute of Technology is prohibited. #include "Events/SHEvent.h" #include "Events/SHEventReceiver.h" #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" namespace SHADE diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index d2312627..8e4e350c 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -14,7 +14,7 @@ #include "Camera/SHCameraComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Math/Transform/SHTransformComponent.h" -#include "Physics/Components/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 1b93c63a..0f8933e2 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -3,7 +3,7 @@ #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingSphere.h" -#include "Physics/SHCollisionShape.h" +#include "Physics/Interface/SHCollisionShape.h" #include "Resource/SHResourceManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" @@ -11,7 +11,7 @@ #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "SHSerializationTools.h" -#include "Physics/Components/SHColliderComponent.h" +#include "Physics/Interface/SHColliderComponent.h" namespace YAML { using namespace SHADE; @@ -130,14 +130,14 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - auto const bb = reinterpret_cast(rhs.GetShape()); - node[HalfExtents] = bb->GetRelativeExtents(); + const auto* BOX = reinterpret_cast(rhs.GetShape()); + node[HalfExtents] = BOX->GetRelativeExtents(); } break; case SHCollisionShape::Type::SPHERE: { - auto const bs = reinterpret_cast(rhs.GetShape()); - node[Radius] = bs->GetRelativeRadius(); + const auto* SPHERE = reinterpret_cast(rhs.GetShape()); + node[Radius] = SPHERE->GetRelativeRadius(); } break; case SHCollisionShape::Type::CAPSULE: break; diff --git a/SHADE_Engine/src/Tools/SHUtilities.h b/SHADE_Engine/src/Tools/SHUtilities.h index 287a827e..6cdd91ee 100644 --- a/SHADE_Engine/src/Tools/SHUtilities.h +++ b/SHADE_Engine/src/Tools/SHUtilities.h @@ -35,22 +35,12 @@ namespace SHADE /** * @brief Converts an enum class member from it's type to any other type. * @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. * @returns The value of the enum class member in the output type. */ template > 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 - static constexpr typename std::underlying_type_t ToUnderlying (Enum value) noexcept; - }; } // namespace SHADE diff --git a/SHADE_Engine/src/Tools/SHUtilities.hpp b/SHADE_Engine/src/Tools/SHUtilities.hpp index e0404ea1..3f0668a2 100644 --- a/SHADE_Engine/src/Tools/SHUtilities.hpp +++ b/SHADE_Engine/src/Tools/SHUtilities.hpp @@ -24,11 +24,4 @@ namespace SHADE { return static_cast(enumClassMember); } - - template - constexpr typename std::underlying_type_t SHUtilities::ToUnderlying(Enum value) noexcept - { - return static_cast>(value); - } - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index dc17ae7f..1711e8b9 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. #pragma once // External Dependencies -#include "Physics/Components/SHColliderComponent.h" +#include "Physics/Interface/SHColliderComponent.h" // Project Includes #include "Components/Component.hxx" #include "Math/Vector3.hxx" diff --git a/SHADE_Managed/src/Components/RigidBody.hxx b/SHADE_Managed/src/Components/RigidBody.hxx index d3a30612..f2953bbd 100644 --- a/SHADE_Managed/src/Components/RigidBody.hxx +++ b/SHADE_Managed/src/Components/RigidBody.hxx @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. #pragma once // External Dependencies -#include "Physics/Components/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" // Project Includes #include "Components/Component.hxx" diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 00c3c182..80f070e2 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -22,8 +22,8 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "ECS_Base/Managers/SHEntityManager.h" #include "Math/Transform/SHTransformComponent.h" -#include "Physics/Components/SHColliderComponent.h" -#include "Physics/Components/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/SHLog.h" diff --git a/SHADE_Managed/src/Engine/Time.cxx b/SHADE_Managed/src/Engine/Time.cxx index 36032e00..8784ec90 100644 --- a/SHADE_Managed/src/Engine/Time.cxx +++ b/SHADE_Managed/src/Engine/Time.cxx @@ -16,7 +16,7 @@ of DigiPen Institute of Technology is prohibited. #include "SHpch.h" // External Dependencies #include "FRC/SHFramerateController.h" -#include "Physics/SHPhysicsSystemInterface.h" +#include "Physics/System/SHPhysicsSystemInterface.h" // Primary Header #include "Time.hxx" diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index a6f978a1..318f5839 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -28,8 +28,9 @@ of DigiPen Institute of Technology is prohibited. #include "Engine/Entity.hxx" #include "Serialisation/SerialisationUtilities.hxx" #include "Engine/Application.hxx" -#include "Physics/SHPhysicsSystemInterface.h" -#include "Physics/SHPhysicsUtils.h" +#include "Physics/System/SHPhysicsSystemInterface.h" +#include "Physics/SHPhysicsEvents.h" +#include "Physics/Collision/SHCollisionInfo.h" namespace SHADE { @@ -555,13 +556,13 @@ namespace SHADE Script^ script = entityScripts[i]; switch (collisionInfo.GetCollisionState()) { - case SHCollisionEvent::State::ENTER: + case SHCollisionInfo::State::ENTER: script->OnCollisionEnter(info); break; - case SHCollisionEvent::State::STAY: + case SHCollisionInfo::State::STAY: script->OnCollisionStay(info); break; - case SHCollisionEvent::State::EXIT: + case SHCollisionInfo::State::EXIT: script->OnCollisionExit(info); break; } @@ -597,13 +598,13 @@ namespace SHADE Script^ script = entityScripts[i]; switch (triggerInfo.GetCollisionState()) { - case SHCollisionEvent::State::ENTER: + case SHCollisionInfo::State::ENTER: script->OnTriggerEnter(info); break; - case SHCollisionEvent::State::STAY: + case SHCollisionInfo::State::STAY: script->OnTriggerStay(info); break; - case SHCollisionEvent::State::EXIT: + case SHCollisionInfo::State::EXIT: script->OnTriggerExit(info); break; }