diff --git a/Assets/Scenes/PhysicsTest.shade b/Assets/Scenes/PhysicsTest.shade new file mode 100644 index 00000000..b3fda265 --- /dev/null +++ b/Assets/Scenes/PhysicsTest.shade @@ -0,0 +1,210 @@ +- EID: 0 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 7, z: 0} + Rotate: {x: 0, y: 0, z: 0.785398185} + Scale: {x: 0.999999344, y: 0.999999821, z: 0.999999523} + IsActive: true + RigidBody Component: + Type: Dynamic + Drag: 0.00999999978 + Angular Drag: 0 + Use Gravity: true + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 200 + torqueAmount: 5 +- EID: 1 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 4, z: 0} + Rotate: {x: -0, y: 0, z: -0.436332315} + Scale: {x: 4.5999999, y: 1, z: 1} + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 2 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Camera Component: + Position: {x: 0, y: 2, z: 7} + Pitch: 0 + Yaw: 95 + Roll: 0 + Width: 1920 + Height: 1080 + Near: 0.00999999978 + Far: 10000 + Perspective: true + IsActive: true + Scripts: ~ +- EID: 65539 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 2.70000005, y: 0.5, z: 0} + Rotate: {x: -0, y: 0, z: 0.436332315} + Scale: {x: 4.5999999, y: 1, z: 1} + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 4 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: -1.70000005, z: 0} + Rotate: {x: -0, y: 0, z: 0} + Scale: {x: 10, y: 0.5, z: 10} + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 5 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -4.80000019, y: 3, z: 0} + Rotate: {x: -0, y: 0, z: 1.57079637} + Scale: {x: 10, y: 0.5, z: 10} + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 65542 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 4.80000019, y: 3, z: 0} + Rotate: {x: -0, y: 0, z: 1.57079637} + Scale: {x: 10, y: 0.5, z: 10} + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 7 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: 3} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Static + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ \ No newline at end of file diff --git a/Assets/Scenes/PhysicsTest.shade.shmeta b/Assets/Scenes/PhysicsTest.shade.shmeta new file mode 100644 index 00000000..11f96258 --- /dev/null +++ b/Assets/Scenes/PhysicsTest.shade.shmeta @@ -0,0 +1,3 @@ +Name: PhysicsTest +ID: 97086054 +Type: 5 diff --git a/Assets/Scenes/Test.shade b/Assets/Scenes/Test.shade new file mode 100644 index 00000000..4b831802 --- /dev/null +++ b/Assets/Scenes/Test.shade @@ -0,0 +1,42 @@ +- EID: 0 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Camera Component: + Position: {x: 0, y: 0, z: 0} + Pitch: 0 + Yaw: 0 + Roll: 0 + Width: 1920 + Height: 1080 + Near: 0.00999999978 + Far: 10000 + Perspective: true + IsActive: true + Scripts: ~ +- EID: 1 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Dynamic + Drag: 0.00999999978 + Angular Drag: 0.100000001 + Use Gravity: false + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Scripts: ~ \ No newline at end of file diff --git a/Assets/Scenes/Test.shade.shmeta b/Assets/Scenes/Test.shade.shmeta new file mode 100644 index 00000000..d5ded40c --- /dev/null +++ b/Assets/Scenes/Test.shade.shmeta @@ -0,0 +1,3 @@ +Name: Test +ID: 97979840 +Type: 5 diff --git a/Assets/Scenes/x.shade b/Assets/Scenes/x.shade new file mode 100644 index 00000000..ae4767bc --- /dev/null +++ b/Assets/Scenes/x.shade @@ -0,0 +1,25 @@ +- EID: 65536 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Dynamic + Drag: 0.00999999978 + Angular Drag: 0.100000001 + Use Gravity: false + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Scripts: ~ \ No newline at end of file diff --git a/Assets/Scenes/x.shade.shmeta b/Assets/Scenes/x.shade.shmeta new file mode 100644 index 00000000..2e00ee43 --- /dev/null +++ b/Assets/Scenes/x.shade.shmeta @@ -0,0 +1,3 @@ +Name: x +ID: 91446183 +Type: 5 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 4466c7a8..e97d9eb4 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -119,11 +119,11 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); #ifndef _PUBLISH - SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); #endif SHSystemManager::RegisterRoutine(); @@ -206,27 +206,6 @@ namespace Sandbox #else SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime()); #endif - // TODO: Move into an Editor menu - static bool drawContacts = false; - if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9)) - { - drawContacts = !drawContacts; - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts); - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts); - } - static bool drawColliders = false; - if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) - { - drawColliders = !drawColliders; - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders); - } - static bool drawRays = false; - if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F11)) - { - drawRays = !drawRays; - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); - } - } // Finish all graphics jobs first graphicsSystem->AwaitGraphicsExecution(); diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp index 73926115..dd713980 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -44,23 +44,6 @@ namespace Sandbox { sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID); - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOGV_CRITICAL("Failed to get the physics system for building the scene!") - return; - } - - #ifdef SHEDITOR - - physicsSystem->ForceBuild(SHSceneManager::GetCurrentSceneGraph()); - - #else - - physicsSystem->BuildScene(SHSceneManager::GetCurrentSceneGraph()); - - #endif - /*-----------------------------------------------------------------------*/ /* TESTING CODE */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index a5edd124..52327b22 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -92,7 +92,7 @@ namespace Sandbox floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC); - floorCollider.AddBoundingBox(); + //floorCollider.AddBoundingBox(); // Create blank entity with a script //testObj = SHADE::SHEntityManager::CreateEntity(); @@ -113,9 +113,9 @@ namespace Sandbox racoonTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); racoonTransform.SetWorldPosition({ -3.0f, -2.0f, -5.0f }); - racoonCollider.AddBoundingBox(); + //racoonCollider.AddBoundingBox(); racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f)); - racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); + //racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); auto racoonItemLocation = SHEntityManager::CreateEntity(); auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s(racoonItemLocation); @@ -138,15 +138,15 @@ namespace Sandbox itemTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); itemTransform.SetWorldPosition({ 0.0f, -2.0f, -5.0f }); - itemCollider.AddBoundingBox(); - itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f)); + //itemCollider.AddBoundingBox(); + //itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f)); itemCollider.GetCollisionShape(1).SetIsTrigger(true); itemCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); - itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); + //itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); itemCollider.GetCollisionShape(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); - itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f)); + //itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f)); itemRigidBody.SetInterpolate(false); itemRigidBody.SetFreezeRotationX(true); @@ -167,9 +167,9 @@ namespace Sandbox AITransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); AITransform.SetWorldPosition({ -8.0f, -2.0f, 2.5f }); - AICollider.AddBoundingBox(); + //AICollider.AddBoundingBox(); AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); - AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); + //AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); AIRigidBody.SetInterpolate(false); AIRigidBody.SetFreezeRotationX(true); diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 6feece48..b31345cd 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -10,7 +10,6 @@ #include "Scene/SHSceneManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" -#include "Math/Geometry/SHBox.h" #include "Math/SHRay.h" #include "Physics/System/SHPhysicsSystem.h" @@ -186,25 +185,25 @@ namespace SHADE //SHLOG_INFO("Ray position: {},{},{} direction:{},{},{}",pivot.ray.position.x, pivot.ray.position.y, pivot.ray.position.z,pivot.ray.direction.x, pivot.ray.direction.y, pivot.ray.direction.z) - auto result = physicsSystem->Raycast(pivot.ray ); - if (result && result.distance < pivot.GetArmLength()) - { - - SHVec3 newOffset = SHVec3{ 0.0f,0.0f, result.distance * 0.8f }; - newOffset = SHVec3::RotateX(newOffset, -(SHMath::DegreesToRadians(pivot.GetPitch()))); - newOffset = SHVec3::RotateY(newOffset, (SHMath::DegreesToRadians(pivot.GetYaw()))); - pivot.offset = newOffset; - //SHLOG_INFO("CAMERA COLLISION HIT, {}", result.distance); - } - else - { - //SHLOG_INFO("CAMERA COLLISION CANT HIT CAMERA"); - } + //auto result = physicsSystem->Raycast(pivot.ray ); + //if (result && result.distance < pivot.GetArmLength()) + //{ + // + // SHVec3 newOffset = SHVec3{ 0.0f,0.0f, result.distance * 0.8f }; + // newOffset = SHVec3::RotateX(newOffset, -(SHMath::DegreesToRadians(pivot.GetPitch()))); + // newOffset = SHVec3::RotateY(newOffset, (SHMath::DegreesToRadians(pivot.GetYaw()))); + // pivot.offset = newOffset; + // //SHLOG_INFO("CAMERA COLLISION HIT, {}", result.distance); + //} + //else + //{ + // //SHLOG_INFO("CAMERA COLLISION CANT HIT CAMERA"); + //} - - + // + // - // pivot.rtMatrix = SHMatrix::Inverse(pivot.rtMatrix); + //// pivot.rtMatrix = SHMatrix::Inverse(pivot.rtMatrix); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp index 8169aa5c..f28e29c5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp @@ -1,7 +1,7 @@ #include "SHpch.h" #include "SHColliderTagPanel.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Editor/SHEditorWidgets.hpp" namespace SHADE @@ -15,7 +15,7 @@ namespace SHADE ImGui::TableNextRow(); ImGui::PushID("CollisionTagNames"); - for (int i = SHCollisionTag::NUM_LAYERS; i >= 0; --i) + for (int i = SHCollisionTag::NUM_LAYERS; i >= 1; --i) { ImGui::TableNextColumn(); if(i == SHCollisionTag::NUM_LAYERS) continue; @@ -29,7 +29,7 @@ namespace SHADE ImGui::PopID(); } ImGui::PopID(); - for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) + for (int i = 0; i < SHCollisionTag::NUM_LAYERS - 1; ++i) { std::string tagName = SHCollisionTagMatrix::GetTagName(i); auto tag = SHCollisionTagMatrix::GetTag(i); @@ -53,8 +53,8 @@ namespace SHADE tagName2 = std::to_string(idx); ImGui::TableNextColumn(); - //if(i == idx) - // continue; + if(i == idx) + continue; std::string label = std::format("##{} vs {}", tagName, tagName2); SHEditorWidgets::CheckBox(label, [tag, &idx]{return tag->GetLayerState(idx);}, [tag, i, idx](bool const& value){tag->SetLayerState(idx, value); SHCollisionTagMatrix::GetTag(idx)->SetLayerState(i, value);}, label.substr(2)); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index a2873bd0..b3653fff 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -18,12 +18,13 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Reflection/SHReflectionMetadata.h" #include "Resource/SHResourceManager.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Serialization/SHSerializationHelper.hpp" #include "Tools/Utilities/SHClipboardUtilities.h" #include "SHInspectorCommands.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Animation/SHAnimatorComponent.h" +#include "Physics/Collision/Shapes/SHBox.h" +#include "Physics/Collision/Shapes/SHSphere.h" namespace SHADE { template @@ -302,7 +303,7 @@ namespace SHADE { SHEditorWidgets::DragVec3("Force", { "X", "Y", "Z" }, [component] {return component->GetForce(); }, [](SHVec3 const& value) {}, false, "Force", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); SHEditorWidgets::DragVec3("Torque", { "X", "Y", "Z" }, [component] {return component->GetTorque(); }, [](SHVec3 const& value) {}, false, "Torque", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); - SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->GetIsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); + SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->IsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); } } @@ -334,6 +335,8 @@ namespace SHADE { DrawContextMenu(component); + SHEditorWidgets::CheckBox("Draw Colliders", [component] { return component->GetDebugDrawState(); }, [component](bool value) { component->SetDebugDrawState(value); }); + auto& colliders = component->GetCollisionShapes(); int const size = static_cast(colliders.size()); ImGui::BeginChild("Collision Shapes", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true); @@ -341,57 +344,57 @@ namespace SHADE for (int i{}; i < size; ++i) { ImGui::PushID(i); - SHCollisionShape* collider = &component->GetCollisionShape(i); + SHCollisionShape* collisionShape = &component->GetCollisionShape(i); auto cursorPos = ImGui::GetCursorPos(); - if (collider->GetType() == SHCollisionShape::Type::BOX) + if (collisionShape->GetType() == SHCollisionShape::Type::BOX) { SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - const auto* BOX = reinterpret_cast(collider->GetShape()); + auto* boxShape = dynamic_cast(collisionShape); SHEditorWidgets::DragVec3 ( "Half Extents", { "X", "Y", "Z" }, - [BOX] { return BOX->GetRelativeExtents(); }, - [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); + [boxShape] { return boxShape->GetRelativeExtents(); }, + [boxShape](SHVec3 const& vec) { boxShape->SetRelativeExtents(vec); }); } - else if (collider->GetType() == SHCollisionShape::Type::SPHERE) + else if (collisionShape->GetType() == SHCollisionShape::Type::SPHERE) { SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - const auto* SPHERE = reinterpret_cast(collider->GetShape()); + auto* sphereShape = dynamic_cast(collisionShape); SHEditorWidgets::DragFloat ( "Radius", - [SPHERE] { return SPHERE->GetRelativeRadius(); }, - [collider](float const& value) { collider->SetBoundingSphere(value); }); + [sphereShape] { return sphereShape->GetRelativeRadius(); }, + [sphereShape](float const& value) { sphereShape->SetRelativeRadius(value); }); } - else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) - { + //else if (collisionShape->GetType() == SHCollisionShape::Type::CAPSULE) + //{ - } + //} { - SHEditorWidgets::CheckBox("Is Trigger", [collider] { return collider->IsTrigger(); }, [collider](bool value) { collider->SetIsTrigger(value); }); - SHEditorWidgets::ComboBox("Tag", collisionTagNames, [collider]{return SHCollisionTagMatrix::GetTagIndex(collider->GetCollisionTag().GetName());}, [collider](int const& value){collider->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));}); + SHEditorWidgets::CheckBox("Is Trigger", [collisionShape] { return collisionShape->IsTrigger(); }, [collisionShape](bool value) { collisionShape->SetIsTrigger(value); }); + SHEditorWidgets::ComboBox("Tag", collisionTagNames, [collisionShape]{return SHCollisionTagMatrix::GetTagIndex(collisionShape->GetCollisionTag().GetName());}, [collisionShape](int const& value){collisionShape->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));}); if(ImGui::CollapsingHeader("Physics Material")) { - SHEditorWidgets::DragFloat("Friction", [collider] { return collider->GetFriction(); }, [collider](float value) { collider->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f); - SHEditorWidgets::DragFloat("Bounciness", [collider] { return collider->GetBounciness(); }, [collider](float value) { collider->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f); - SHEditorWidgets::DragFloat("Mass Density", [collider] { return collider->GetDensity(); }, [collider](float value) { collider->SetDensity(value); }, "Mass Density", 0.1f, 0.0f); + SHEditorWidgets::DragFloat("Friction", [collisionShape] { return collisionShape->GetFriction(); }, [collisionShape](float value) { collisionShape->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f); + SHEditorWidgets::DragFloat("Bounciness", [collisionShape] { return collisionShape->GetBounciness(); }, [collisionShape](float value) { collisionShape->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f); + SHEditorWidgets::DragFloat("Mass Density", [collisionShape] { return collisionShape->GetDensity(); }, [collisionShape](float value) { collisionShape->SetDensity(value); }, "Mass Density", 0.1f, 0.0f); } SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f }); - SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collisionShape] {return collisionShape->GetPositionOffset(); }, [&collisionShape](SHVec3 const& vec) {collisionShape->SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, - [&collider] + [&collisionShape] { - auto offset = collider->GetRotationOffset(); + auto offset = collisionShape->GetRotationOffset(); return offset; }, - [&collider](SHVec3 const& vec) + [&collisionShape](SHVec3 const& vec) { - collider->SetRotationOffset(vec); + collisionShape->SetRotationOffset(vec); }, true); SHEditorWidgets::EndPanel(); } @@ -406,7 +409,7 @@ namespace SHADE } if (colliderToDelete.has_value()) { - component->RemoveCollider(colliderToDelete.value()); + component->RemoveCollisionShape(colliderToDelete.value()); } ImGui::EndChild(); @@ -416,11 +419,11 @@ namespace SHADE if (ImGui::Selectable("Box Collider")) { - newColl = component->AddBoundingBox(); + newColl = component->AddBoxCollisionShape(SHVec3::One); } if (ImGui::Selectable("Sphere Collider")) { - newColl = component->AddBoundingSphere(); + newColl = component->AddSphereCollisionShape(1.0f); } //No idea why this doesn't work diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 3fe9ceb5..e8c943c2 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -25,6 +25,7 @@ #include "Serialization/SHSerialization.h" #include "Serialization/Configurations/SHConfigurationManager.h" #include "Editor/EditorWindow/SHEditorWindowManager.h" +#include "Physics/System/SHPhysicsDebugDrawSystem.h" const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" }; @@ -88,6 +89,7 @@ namespace SHADE DrawThemeMenu(); DrawLayoutMenu(); DrawApplicationConfig(); + DrawPhysicsSettings(); std::string const sceneName{std::format("Current Scene: {}",SHSceneManager::GetSceneName().data())}; auto const size = ImGui::CalcTextSize(sceneName.data()); @@ -304,4 +306,27 @@ namespace SHADE ImGui::EndMenu(); } } + + void SHEditorMenuBar::DrawPhysicsSettings() noexcept + { + if (ImGui::BeginMenu("Physics Settings")) + { + if (auto* physicsDebugDraw = SHSystemManager::GetSystem()) + { + bool drawColliders = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS); + if (ImGui::Checkbox("Draw Colliders", &drawColliders)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS, drawColliders); + + bool drawContactPoints = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS); + if (ImGui::Checkbox("Draw Contact Points", &drawContactPoints)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS, drawContactPoints); + + bool drawRays = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS); + if (ImGui::Checkbox("Draw Rays", &drawRays)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); + } + + ImGui::EndMenu(); + } + } }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h index 77ebcf55..4891dc5b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h @@ -25,6 +25,7 @@ namespace SHADE void DrawThemeMenu() noexcept; void DrawLayoutMenu() noexcept; void DrawApplicationConfig() noexcept; + void DrawPhysicsSettings() noexcept; float menuBarHeight = 20.0f; std::vector layoutPaths; diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index c090cd69..e2fcba10 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -24,4 +24,5 @@ constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 }; constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 }; constexpr SHEventIdentifier SH_BUTTON_CLICK_EVENT { 18 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_DRAW_EVENT { 19 }; diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp deleted file mode 100644 index 7261749b..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHBox.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/**************************************************************************************** - * \file SHBox.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a 3-Dimensional Axis Aligned Bounding Box - * - * \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 "SHBox.h" -// Project Headers -#include "Math/SHMathHelpers.h" -#include "Math/SHRay.h" - -using namespace DirectX; - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHBox::SHBox() noexcept - : RelativeExtents { SHVec3::One } - { - type = Type::BOX; - } - - SHBox::SHBox(const SHVec3& c, const SHVec3& hE) noexcept - : RelativeExtents { SHVec3::One } - { - type = Type::BOX; - - Center = c; - Extents = hE; - } - - - SHBox::SHBox(const SHBox& rhs) noexcept - { - if (this == &rhs) - return; - - type = Type::BOX; - - Center = rhs.Center; - Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; - } - - SHBox::SHBox(SHBox&& rhs) noexcept - { - type = Type::BOX; - - Center = rhs.Center; - Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHBox& SHBox::operator=(const SHBox& rhs) noexcept - { - if (rhs.type != Type::BOX) - { - SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") - } - else if (this != &rhs) - { - Center = rhs.Center; - Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; - } - - return *this; - } - - SHBox& SHBox::operator=(SHBox&& rhs) noexcept - { - if (rhs.type != Type::BOX) - { - SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") - } - else - { - Center = rhs.Center; - Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; - } - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHVec3 SHBox::GetCenter() const noexcept - { - return Center; - } - - SHVec3 SHBox::GetWorldExtents() const noexcept - { - return Extents; - } - - const SHVec3& SHBox::GetRelativeExtents() const noexcept - { - return RelativeExtents; - } - - SHVec3 SHBox::GetMin() const noexcept - { - return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z }; - } - - SHVec3 SHBox::GetMax() const noexcept - { - return SHVec3{ Center.x + Extents.x, Center.y + Extents.y, Center.z + Extents.z }; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHBox::SetCenter(const SHVec3& newCenter) noexcept - { - Center = newCenter; - } - - void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept - { - Extents = newWorldExtents; - } - - void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept - { - RelativeExtents = newRelativeExtents; - } - - void SHBox::SetMin(const SHVec3& min) noexcept - { - const SHVec3 MAX = GetMax(); - - Center = SHVec3::Lerp(min, MAX, 0.5f); - Extents = SHVec3::Abs((MAX - min) * 0.5f); - } - - void SHBox::SetMax(const SHVec3& max) noexcept - { - const SHVec3 MIN = GetMin(); - - Center = SHVec3::Lerp(MIN, max, 0.5f); - Extents = SHVec3::Abs((max - MIN) * 0.5f); - } - - void SHBox::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept - { - Center = SHVec3::Lerp(min, max, 0.5f); - Extents = SHVec3::Abs((max - min) * 0.5f); - } - - std::vector SHBox::GetVertices() const noexcept - { - std::vector vertices{ 8 }; - GetCorners(vertices.data()); - return vertices; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHBox::TestPoint(const SHVec3& point) const noexcept - { - return BoundingBox::Contains(point); - } - - SHRaycastResult SHBox::Raycast(const SHRay& ray) const noexcept - { - SHRaycastResult result; - - result.hit = Intersects(ray.position, ray.direction, result.distance); - if (result.hit) - { - result.position = ray.position + ray.direction * result.distance; - result.angle = SHVec3::Angle(ray.position, result.position); - } - - return result; - } - - bool SHBox::Contains(const SHBox& rhs) const noexcept - { - return BoundingBox::Contains(rhs); - } - - float SHBox::Volume() const noexcept - { - return 8.0f * (Extents.x * Extents.y * Extents.z); - } - - float SHBox::SurfaceArea() const noexcept - { - return 8.0f * ((Extents.x * Extents.y) - + (Extents.x * Extents.z) - + (Extents.y * Extents.z)); - } - - /*-----------------------------------------------------------------------------------*/ - /* Static Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHBox SHBox::Combine(const SHBox& lhs, const SHBox& rhs) noexcept - { - SHBox result; - CreateMerged(result, lhs, rhs); - return result; - } - - bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept - { - return lhs.Intersects(rhs); - } - - SHBox SHBox::BuildFromBoxes(const SHBox* boxes, size_t numBoxes) noexcept - { - SHBox result; - - for (size_t i = 1; i < numBoxes; ++i) - CreateMerged(result, boxes[i - 1], boxes[i]); - - return result; - } - - SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept - { - SHBox result; - CreateFromPoints(result, numVertices, vertices, stride); - return result; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h deleted file mode 100644 index a0ca9458..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHBox.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************************** - * \file SHBox.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a 3-Dimensional Axis Aligned Bounding Box - * - * \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 "SHShape.h" -#include "SH_API.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHBox : public SHShape, - private DirectX::BoundingBox - { - public: - /*---------------------------------------------------------------------------------*/ - /* Static Data Members */ - /*---------------------------------------------------------------------------------*/ - - static constexpr size_t NUM_VERTICES = 8; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - ~SHBox () override = default; - - SHBox () noexcept; - SHBox (const SHVec3& center, const SHVec3& halfExtents) noexcept; - SHBox (const SHBox& rhs) noexcept; - SHBox (SHBox&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHBox& operator= (const SHBox& rhs) noexcept; - SHBox& operator= (SHBox&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] const SHVec3& GetRelativeExtents () const noexcept; - [[nodiscard]] SHVec3 GetMin () const noexcept; - [[nodiscard]] SHVec3 GetMax () const noexcept; - [[nodiscard]] std::vector GetVertices () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetCenter (const SHVec3& newCenter) noexcept; - void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; - void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept; - void SetMin (const SHVec3& min) noexcept; - void SetMax (const SHVec3& max) noexcept; - void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override; - - [[nodiscard]] bool Contains (const SHBox& rhs) const noexcept; - [[nodiscard]] float Volume () const noexcept; - [[nodiscard]] float SurfaceArea () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Static Function Members */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] static SHBox Combine (const SHBox& lhs, const SHBox& rhs) noexcept; - [[nodiscard]] static bool Intersect (const SHBox& lhs, const SHBox& rhs) noexcept; - [[nodiscard]] static SHBox BuildFromBoxes (const SHBox* boxes, size_t numBoxes) noexcept; - [[nodiscard]] static SHBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - SHVec3 RelativeExtents; - }; - - -} // namespace SHADE - diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp deleted file mode 100644 index 54935251..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/**************************************************************************************** - * \file SHBoundingSphere.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Bounding Sphere - * - * \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 "SHSphere.h" -// Project Headers -#include "Math/SHMathHelpers.h" -#include "Math/SHRay.h" - -using namespace DirectX; - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere::SHSphere() noexcept - : RelativeRadius { 1.0f } - { - type = Type::SPHERE; - } - - SHSphere::SHSphere(const SHVec3& center, float radius) noexcept - : RelativeRadius { 1.0f } - { - type = Type::SPHERE; - - Center = center; - Radius = radius; - } - - SHSphere::SHSphere(const SHSphere& rhs) noexcept - { - if (this == &rhs) - return; - - type = Type::SPHERE; - - Center = rhs.Center; - Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; - } - - SHSphere::SHSphere(SHSphere&& rhs) noexcept - { - type = Type::SPHERE; - - Center = rhs.Center; - Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept - { - if (rhs.type != Type::SPHERE) - { - SHLOG_WARNING("Cannot assign a non-sphere to a sphere!") - } - else if (this != &rhs) - { - Center = rhs.Center; - Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; - } - - return *this; - } - - SHSphere& SHSphere::operator=(SHSphere&& rhs) noexcept - { - if (rhs.type != Type::SPHERE) - { - SHLOG_WARNING("Cannot assign a non-sphere to a sphere!") - } - else - { - Center = rhs.Center; - Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; - } - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHVec3 SHSphere::GetCenter() const noexcept - { - return Center; - } - - float SHSphere::GetWorldRadius() const noexcept - { - return Radius; - } - - float SHSphere::GetRelativeRadius() const noexcept - { - return RelativeRadius; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHSphere::SetCenter(const SHVec3& center) noexcept - { - Center = center; - } - - void SHSphere::SetWorldRadius(float newWorldRadius) noexcept - { - Radius = newWorldRadius; - } - - void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept - { - RelativeRadius = newRelativeRadius; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHSphere::TestPoint(const SHVec3& point) const noexcept - { - return BoundingSphere::Contains(point); - } - - SHRaycastResult SHSphere::Raycast(const SHRay& ray) const noexcept - { - SHRaycastResult result; - - result.hit = Intersects(ray.position, ray.direction, result.distance); - if (result.hit) - { - result.position = ray.position + ray.direction * result.distance; - result.angle = SHVec3::Angle(ray.position, result.position); - } - - return result; - } - - bool SHSphere::Contains(const SHSphere& rhs) const noexcept - { - return BoundingSphere::Contains(rhs); - } - - float SHSphere::Volume() const noexcept - { - return (4.0f / 3.0f) * SHMath::PI * (Radius * Radius * Radius); - } - - float SHSphere::SurfaceArea() const noexcept - { - return 4.0f * SHMath::PI * (Radius * Radius); - } - - /*-----------------------------------------------------------------------------------*/ - /* Static Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere SHSphere::Combine(const SHSphere& lhs, const SHSphere& rhs) noexcept - { - SHSphere result; - CreateMerged(result, lhs, rhs); - return result; - } - - bool SHSphere::Intersect(const SHSphere& lhs, const SHSphere& rhs) noexcept - { - return lhs.Intersects(rhs); - } - - SHSphere SHSphere::BuildFromSpheres(const SHSphere* spheres, size_t numSpheres) noexcept - { - SHSphere result; - - for (size_t i = 1; i < numSpheres; ++i) - CreateMerged(result, spheres[i - 1], spheres[i]); - - return result; - } - - SHSphere SHSphere::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept - { - SHSphere result; - CreateFromPoints(result, numVertices, vertices, stride); - return result; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHRay.cpp b/SHADE_Engine/src/Math/SHRay.cpp index c4931aba..b8a47f0e 100644 --- a/SHADE_Engine/src/Math/SHRay.cpp +++ b/SHADE_Engine/src/Math/SHRay.cpp @@ -10,6 +10,8 @@ #include +#include + // Primary Header #include "SHRay.h" @@ -30,7 +32,7 @@ namespace SHADE , direction { dir } {} - SHRay::SHRay(const reactphysics3d::Ray rp3dRay) noexcept + SHRay::SHRay(const reactphysics3d::Ray& rp3dRay) noexcept : position { rp3dRay.point1 } , direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) } {} diff --git a/SHADE_Engine/src/Math/SHRay.h b/SHADE_Engine/src/Math/SHRay.h index 18efc224..6e33be5e 100644 --- a/SHADE_Engine/src/Math/SHRay.h +++ b/SHADE_Engine/src/Math/SHRay.h @@ -16,8 +16,13 @@ #include "SH_API.h" #include "Vector/SHVec3.h" +/*-------------------------------------------------------------------------------------*/ +/* Forward Declarations */ +/*-------------------------------------------------------------------------------------*/ + namespace SHADE { + /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -40,7 +45,7 @@ namespace SHADE SHRay () noexcept; SHRay (const SHVec3& pos, const SHVec3& dir) noexcept; - SHRay (const reactphysics3d::Ray rp3dRay) noexcept; + SHRay (const reactphysics3d::Ray& rp3dRay) noexcept; SHRay (const SHRay&) noexcept = default; SHRay (SHRay&& ) noexcept = default; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.h diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.cpp diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTags.h b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTags.h rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.h diff --git a/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp b/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp rename to SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.cpp diff --git a/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h similarity index 100% rename from SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h rename to SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp deleted file mode 100644 index cab5c93b..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsRaycaster.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Physics Raycaster. - * - * \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 "SHPhysicsRaycaster.h" - -/* - * TODO(DIREN): - * Once the physics engine has been rebuilt, this whole implementation should change - * and just call PhysicsWorld.Raycast etc. - * - * SHRaycastResult can be converted to a bool when necessary. - */ - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsRaycaster::SHPhysicsRaycaster() noexcept - : world { nullptr } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHPhysicsRaycaster::RaycastPairs& SHPhysicsRaycaster::GetRaycasts() const noexcept - { - return raycasts; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsRaycaster::SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept - { - objectManager = physicsObjectManager; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept - { - world = physicsWorld; - } - - void SHPhysicsRaycaster::ClearFrame() noexcept - { - raycasts.clear(); - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept - { - // Reset temp - temp = SHPhysicsRaycastResult{}; - temp.distance = distance; - - if (!world) - { - SHLOG_ERROR("Physics world missing for raycasting!") - return temp; - } - - // If distance in infinity, cast to the default max distance of 2 km. - if (distance == std::numeric_limits::infinity()) - { - world->raycast(ray, this, collisionTag); - } - else - { - const SHVec3 END_POINT = ray.position + ray.direction * distance; - const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; - world->raycast(RP3D_RAY, this, collisionTag); - } - - // If a hit was found, populate temp info for return. - if (temp.hit) - { - temp.distance = SHVec3::Distance(ray.position, temp.position); - temp.angle = SHVec3::Angle(ray.position, temp.position); - } - - raycasts.emplace_back(ray, temp); - return temp; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept - { - temp = SHPhysicsRaycastResult{}; - temp.distance = SHVec3::Distance(start, end); - - if (!world) - { - SHLOG_ERROR("Physics world missing for raycasting!") - return temp; - } - - const rp3d::Ray RP3D_RAY{ start, end }; - world->raycast(RP3D_RAY, this, collisionTag); - - if (temp.hit) - { - temp.distance = SHVec3::Distance(start, temp.position); - temp.angle = SHVec3::Angle(start, temp.position); - } - - raycasts.emplace_back(RP3D_RAY, temp); - return temp; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept - { - SHPhysicsRaycastResult result; - result.distance = distance; - - // Get a valid physics object with at least 1 collider. - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody(); - - // Data to populate - rp3d::RaycastInfo rp3dRaycastInfo; - bool hit = false; - - if (distance == std::numeric_limits::infinity()) - { - hit = rp3dBody->raycast(ray, rp3dRaycastInfo); - } - else - { - const SHVec3 END_POINT = ray.position + ray.direction * distance; - const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; - hit = rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo); - } - - if (hit) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(ray.position, result.position); - result.angle = SHVec3::Angle(ray.position, result.position); - result.entityHit = eid; - result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity()); - } - - raycasts.emplace_back(ray, result); - return result; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept - { - SHPhysicsRaycastResult result; - result.distance = distance; - - // Get a valid physics object with at least 1 collider. - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - // Boundary check for shape index - if (shapeIndex < 0 || shapeIndex >= static_cast(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders())) - { - SHLOGV_WARNING("Invalid collision shape index passed in") - return result; - } - - auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex); - - rp3d::RaycastInfo rp3dRaycastInfo; - bool hit = false; - if (distance == std::numeric_limits::infinity()) - { - hit = rp3dCollider->raycast(ray, rp3dRaycastInfo); - } - else - { - const SHVec3 END_POINT = ray.position + ray.direction * distance; - const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; - hit = rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo); - } - - if (hit) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(ray.position, result.position); - result.angle = SHVec3::Angle(ray.position, result.position); - result.entityHit = eid; - result.shapeIndex = shapeIndex; - } - - raycasts.emplace_back(ray, result); - return result; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept - { - SHPhysicsRaycastResult result; - result.distance = SHVec3::Distance(start, end); - - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody(); - - rp3d::RaycastInfo rp3dRaycastInfo; - - const rp3d::Ray RP3D_RAY{ start, end }; - if (rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo)) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(start, result.position); - result.angle = SHVec3::Angle(end, result.position); - result.entityHit = eid; - result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity()); - } - - raycasts.emplace_back(RP3D_RAY, result); - return result; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept - { - SHPhysicsRaycastResult result; - result.distance = SHVec3::Distance(start, end); - - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - if (shapeIndex < 0 || shapeIndex >= static_cast(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders())) - { - SHLOGV_WARNING("Invalid collision shape index passed in") - return result; - } - - auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex); - - rp3d::RaycastInfo rp3dRaycastInfo; - - const rp3d::Ray RP3D_RAY{ start, end }; - if (rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo)) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(start, result.position); - result.angle = SHVec3::Angle(end, result.position); - result.entityHit = eid; - result.shapeIndex = shapeIndex; - } - - raycasts.emplace_back(RP3D_RAY, result); - return result; - } - - rp3d::decimal SHPhysicsRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) - { - temp.hit = true; - temp.position = raycastInfo.worldPoint; - temp.normal = raycastInfo.worldNormal; - - if (!objectManager) - { - SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies") - return 0.0f; - } - - // Compare body IDs to find the matching physics object - const auto HIT_BODY_EID = raycastInfo.body->getEntity(); - - for (const auto& [entityID, physicsObject] : objectManager->GetPhysicsObjects()) - { - const auto RP3D_BODY = physicsObject.GetCollisionBody(); - - // Match rp3d bodies - if (RP3D_BODY->getEntity() != HIT_BODY_EID) - continue; - - temp.entityHit = entityID; - - // Find collider index - if (const int INDEX = findColliderIndex(RP3D_BODY, raycastInfo.collider->getEntity()); INDEX > -1) - { - temp.shapeIndex = INDEX; - break; - } - } - - return 0.0f; - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject* SHPhysicsRaycaster::validateColliderRaycast(EntityID eid) noexcept - { - if (!objectManager) - { - SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies") - return nullptr; - } - - auto* physicsObject = objectManager->GetPhysicsObject(eid); - if (!physicsObject || physicsObject->GetCollisionBody()->getNbColliders() == 0) - { - SHLOGV_WARNING("Cannot cast ray at an entity without colliders!") - return nullptr; - } - - return physicsObject; - } - - int SHPhysicsRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept - { - const int NUM_COLLISION_SHAPES = static_cast(rp3dBody->getNbColliders()); - for (int i = 0; i < NUM_COLLISION_SHAPES; ++i) - { - const auto COLLIDER_EID = rp3dBody->getCollider(i)->getEntity(); - if (COLLIDER_EID == rp3dColliderEID) - return i; - } - - return -1; - } - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h deleted file mode 100644 index 447207c7..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsRaycaster.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Physics Raycaster. - * - * \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 - -// Project Headers -#include "Math/SHRay.h" -#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" -#include "Physics/SHPhysicsWorld.h" -#include "SH_API.h" -#include "SHCollisionTags.h" -#include "SHPhysicsRaycastResult.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHPhysicsRaycaster : public reactphysics3d::RaycastCallback - { - private: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using RaycastPair = std::pair; - using RaycastPairs = std::vector; - - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsRaycaster() noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] const RaycastPairs& GetRaycasts() const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept; - void ClearFrame () noexcept; - - // TODO(Diren): Filtering, return all shades ray hits - - SHPhysicsRaycastResult Raycast - ( - const SHRay& ray - , float distance = std::numeric_limits::infinity() - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - SHPhysicsRaycastResult Linecast - ( - const SHVec3& start - , const SHVec3& end - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , int shapeIndex - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , int shapeIndex - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - rp3d::PhysicsWorld* world; - SHPhysicsObjectManager* objectManager; // For - SHPhysicsRaycastResult temp; // Holds the temporary result after casting into the world - RaycastPairs raycasts; // Used for debug drawing - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject* validateColliderRaycast (EntityID eid) noexcept; - static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept; - }; - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp new file mode 100644 index 00000000..1e2a4a22 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp @@ -0,0 +1,105 @@ +/**************************************************************************************** + * \file SHBoxCollisionShape.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Box Collision Shape. + * + * \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 + +#include + +// Primary Header +#include "SHBox.h" + +// Project Headers +#include "Math/SHMatrix.h" +#include "Physics/Interface/SHColliderComponent.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHBox::SHBox() noexcept + : SHCollisionShape (Type::BOX) + , relativeExtents { SHVec3::One } + , scale { SHVec3::One } + { + if (rp3dCollider) + dynamic_cast(rp3dCollider->getCollisionShape())->setHalfExtents(SHVec3::One * 0.5f); + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3 SHBox::GetWorldExtents() const noexcept + { + return SHVec3{ dynamic_cast(rp3dCollider->getCollisionShape())->getHalfExtents() }; + } + + SHVec3 SHBox::GetRelativeExtents() const noexcept + { + return relativeExtents; + } + + SHVec3 SHBox::GetWorldCentroid() const noexcept + { + const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset); + const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position); + return SHVec3::Transform(positionOffset, TRS); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept + { + dynamic_cast(rp3dCollider->getCollisionShape())->setHalfExtents(newWorldExtents); + + // Recompute Relative radius + relativeExtents = 2.0f * newWorldExtents / scale; + } + + void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept + { + relativeExtents = newRelativeExtents; + + // Recompute world radius + dynamic_cast(rp3dCollider->getCollisionShape())->setHalfExtents(relativeExtents * scale * 0.5f); + } + + void SHBox::SetScale(const SHVec3& newScale) noexcept + { + scale = SHVec3::Abs(newScale); + + // Recompute world radius + dynamic_cast(rp3dCollider->getCollisionShape())->setHalfExtents(relativeExtents * scale * 0.5f); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMatrix SHBox::GetTRS() const noexcept + { + const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset); + const SHVec3 SCALE = GetWorldExtents() * 2.0f; + + const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position); + const SHVec3 POSITION = SHVec3::Transform(positionOffset, TRS); + + return SHMatrix::Transform(POSITION, ROTATION, SCALE); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h similarity index 57% rename from SHADE_Engine/src/Math/Geometry/SHSphere.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h index e056f21a..5fa394d9 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHBoundingSphere.h + * \file SHBox.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Bounding Sphere. + * \brief Interface for a Box Collision Shape. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -10,11 +10,8 @@ #pragma once -#include - // Project Headers -#include "SHShape.h" -#include "SH_API.h" +#include "SHCollisionShape.h" namespace SHADE { @@ -22,71 +19,60 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SH_API SHSphere : public SHShape, - private DirectX::BoundingSphere + /** + * @brief + * Encapsulate a Box Shape used for Physics Simulations. + */ + class SH_API SHBox final : public SHCollisionShape { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHColliderComponent; + public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHSphere () noexcept; - SHSphere (const SHVec3& center, float radius) noexcept; - SHSphere (const SHSphere& rhs) noexcept; - SHSphere (SHSphere&& rhs) noexcept; - - ~SHSphere () override = default; + SHBox () noexcept; + ~SHBox () override = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHSphere& operator= (const SHSphere& rhs) noexcept; - SHSphere& operator= (SHSphere&& rhs) noexcept; - /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] float GetWorldRadius () const noexcept; - [[nodiscard]] float GetRelativeRadius () const noexcept; + [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; + [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; + + [[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCenter (const SHVec3& center) noexcept; - void SetWorldRadius (float newWorldRadius) noexcept; - void SetRelativeRadius (float newRelativeRadius) noexcept; + void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; + void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept; + void SetScale (const SHVec3& newScale) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override; - - [[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept; - [[nodiscard]] float Volume () const noexcept; - [[nodiscard]] float SurfaceArea () const noexcept; - - - /*---------------------------------------------------------------------------------*/ - /* Static Function Members */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept; - [[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept; - [[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept; - [[nodiscard]] static SHSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; + [[nodiscard]] SHMatrix GetTRS () const noexcept override; private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - float RelativeRadius; - + SHVec3 relativeExtents; + SHVec3 scale; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp new file mode 100644 index 00000000..2acffe29 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp @@ -0,0 +1,209 @@ +/**************************************************************************************** + * \file SHCollider.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Collider. + * + * \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 + + +#include + +// Primary Header +#include "SHCollisionShape.h" + +// Project Headers +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" +#include "Reflection/SHReflectionMetadata.h" +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionShape::SHCollisionShape(Type colliderType) + : rp3dCollider { nullptr } + , collider { nullptr } + , collisionTag { SHCollisionTagMatrix::GetTag(0) } + , flags { 0 } + { + flags |= 1U << SHUtilities::ConvertEnum(colliderType); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHCollisionShape::GetFriction() const noexcept + { + return material.GetFriction(); + } + + float SHCollisionShape::GetBounciness() const noexcept + { + return material.GetBounciness(); + } + + float SHCollisionShape::GetDensity() const noexcept + { + return material.GetDensity(); + } + + const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept + { + return material; + } + + const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept + { + return positionOffset; + } + + const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept + { + return rotationOffset; + } + + SHCollisionShape::Type SHCollisionShape::GetType() const noexcept + { + for (int i = 0; i < SHUtilities::ConvertEnum(Type::COUNT); ++i) + { + const uint8_t FLAG_VALUE = 1U << SHUtilities::ConvertEnum(static_cast(i)); + + if (flags & FLAG_VALUE) + return static_cast(i); + } + + return Type::INVALID; + } + + bool SHCollisionShape::IsTrigger() const noexcept + { + static constexpr int FLAG_POS = 3; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + return flags & FLAG_VALUE; + } + + bool SHCollisionShape::IsColliding() const noexcept + { + static constexpr int FLAG_POS = 4; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + return flags & FLAG_VALUE; + } + + const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept + { + return *collisionTag; + } + + SHVec3 SHCollisionShape::GetWorldCentroid() const noexcept + { + return collider->GetTransform().position; + } + + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept + { + collisionTag = newCollisionTag; + } + + void SHCollisionShape::SetFriction(float friction) noexcept + { + material.SetFriction(friction); + rp3dCollider->getMaterial().setFrictionCoefficient(material.GetFriction()); + } + + void SHCollisionShape::SetBounciness(float bounciness) noexcept + { + material.SetBounciness(bounciness); + rp3dCollider->getMaterial().setBounciness(material.GetBounciness()); + } + + void SHCollisionShape::SetDensity(float density) noexcept + { + material.SetDensity(density); + rp3dCollider->getMaterial().setMassDensity(material.GetDensity()); + } + + void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept + { + material = newMaterial; + + auto& rp3dMaterial = rp3dCollider->getMaterial(); + rp3dMaterial.setFrictionCoefficient(material.GetFriction()); + rp3dMaterial.setBounciness(material.GetBounciness()); + rp3dMaterial.setMassDensity(material.GetDensity()); + } + + void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept + { + positionOffset = posOffset; + Update(); + } + + void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept + { + rotationOffset = rotOffset; + Update(); + } + + void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept + { + static constexpr int FLAG_POS = 3; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + isTrigger ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; + + rp3dCollider->setIsTrigger(isTrigger); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionShape::Update() noexcept + { + const rp3d::Transform OFFSETS{ positionOffset, SHQuaternion::FromEuler(rotationOffset) }; + rp3dCollider->setLocalToBodyTransform(OFFSETS); + } + + SHMatrix SHCollisionShape::GetTRS() const noexcept + { + return SHMatrix::Identity; + } + +} // namespace SHADE + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::enumeration("Collider Type") + ( + value("Box", SHCollisionShape::Type::BOX), + value("Sphere", SHCollisionShape::Type::SPHERE) + // TODO(Diren): Add More Shapes + ); + + registration::class_("Collider") + .property("IsTrigger" , &SHCollisionShape::IsTrigger , &SHCollisionShape::SetIsTrigger ) + .property("Friction" , &SHCollisionShape::GetFriction , &SHCollisionShape::SetFriction ) + .property("Bounciness" , &SHCollisionShape::GetBounciness , &SHCollisionShape::SetBounciness ) + .property("Density" , &SHCollisionShape::GetDensity , &SHCollisionShape::SetDensity ) + .property("Position Offset" , &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset) + .property("Rotation Offset" , &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true)); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h new file mode 100644 index 00000000..44c4d479 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h @@ -0,0 +1,157 @@ +/**************************************************************************************** + * \file SHCollisionShape.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Base CollisionShape Class. + * + * \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 + +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" +#include "Physics/Collision/CollisionTags/SHCollisionTags.h" +#include "Physics/Collision/SHPhysicsMaterial.h" +#include "Math/Transform/SHTransform.h" +#include "Physics/Collision/SHPhysicsRaycastResult.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHColliderComponent; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHCollisionShape + { + private: + + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsSystem; + friend class SHColliderComponent; + + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Type + { + SPHERE + , BOX + + , COUNT + , INVALID = -1 + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShape(Type colliderType = Type::INVALID); + + SHCollisionShape(const SHCollisionShape& rhs) noexcept = default; + SHCollisionShape(SHCollisionShape&& rhs) noexcept = default; + virtual ~SHCollisionShape() noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept = default; + SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + // Material Properties + // TODO: Remove individual setters once instanced materials are supported + + [[nodiscard]] float GetFriction() const noexcept; + [[nodiscard]] float GetBounciness() const noexcept; + [[nodiscard]] float GetDensity() const noexcept; + [[nodiscard]] const SHPhysicsMaterial& GetMaterial() const noexcept; + + // Offsets + + [[nodiscard]] const SHVec3& GetPositionOffset() const noexcept; + [[nodiscard]] const SHVec3& GetRotationOffset() const noexcept; + + // Flags + + [[nodiscard]] Type GetType() const noexcept; + [[nodiscard]] bool IsTrigger() const noexcept; + [[nodiscard]] bool IsColliding() const noexcept; + + [[nodiscard]] const SHCollisionTag& GetCollisionTag() const noexcept; + + [[nodiscard]] virtual SHVec3 GetWorldCentroid() const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept; + + void SetFriction(float friction) noexcept; + void SetBounciness(float bounciness) noexcept; + void SetDensity(float density) noexcept; + void SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept; + + void SetPositionOffset(const SHVec3& posOffset) noexcept; + void SetRotationOffset(const SHVec3& rotOffset) noexcept; + + // Forces rigidbody to recompute mass if one exists + void SetIsTrigger(bool isTrigger) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Computes the transform of the shape. + */ + void Update() noexcept; + + /** + * @brief + * Computes the TRS matrix for rendering the shape. + * @return + * The model-to-world matrix for rendering the shape. + */ + [[nodiscard]] virtual SHMatrix GetTRS() const noexcept; + + protected: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + reactphysics3d::Collider* rp3dCollider; + SHColliderComponent* collider; // The collider it belongs to. + SHCollisionTag* collisionTag; + SHPhysicsMaterial material; // TODO: Change to pointer once instancing is supported + + SHVec3 positionOffset; + SHVec3 rotationOffset; + + uint8_t flags; // 0 0 0 trigger 0 capsule sphere box + + + RTTR_ENABLE() + }; +} diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp new file mode 100644 index 00000000..f8c73f90 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp @@ -0,0 +1,105 @@ +/**************************************************************************************** + * \file SHSphereCollisionShape.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Sphere Collision Shape. + * + * \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 + +#include + +// Primary Header +#include "SHSphere.h" + +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Math/SHMatrix.h" +#include "Physics/Interface/SHColliderComponent.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSphere::SHSphere() noexcept + : SHCollisionShape (Type::SPHERE) + , relativeRadius { 1.0f } + , scale { 1.0f } + { + if (rp3dCollider) + dynamic_cast(rp3dCollider->getCollisionShape())->setRadius(0.5f); + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHSphere::GetWorldRadius() const noexcept + { + return dynamic_cast(rp3dCollider->getCollisionShape())->getRadius(); + } + + float SHSphere::GetRelativeRadius() const noexcept + { + return relativeRadius; + } + + SHVec3 SHSphere::GetWorldCentroid() const noexcept + { + const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset); + const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position); + return SHVec3::Transform(positionOffset, TRS); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHSphere::SetWorldRadius(float newWorldRadius) noexcept + { + dynamic_cast(rp3dCollider->getCollisionShape())->setRadius(newWorldRadius); + + // Recompute Relative radius + relativeRadius = 2.0f * newWorldRadius / scale; + } + + void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept + { + relativeRadius = newRelativeRadius; + + // Recompute world radius + dynamic_cast(rp3dCollider->getCollisionShape())->setRadius(relativeRadius * scale * 0.5f); + } + + void SHSphere::SetScale(float maxScale) noexcept + { + scale = std::fabs(maxScale); + + // Recompute world radius + dynamic_cast(rp3dCollider->getCollisionShape())->setRadius(relativeRadius * scale * 0.5f); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMatrix SHSphere::GetTRS() const noexcept + { + const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset); + const SHVec3 SCALE = GetWorldRadius() * 2.0f; + + const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position); + const SHVec3 POSITION = SHVec3::Transform(positionOffset, TRS); + + return SHMatrix::Transform(POSITION, ROTATION, SCALE); + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h similarity index 64% rename from SHADE_Engine/src/Math/Geometry/SHShape.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h index 812cb169..bf9301fe 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHShape.h + * \file SHSphereCollisionShape.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a shape. + * \brief Interface for a Sphere Collision Shape. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -11,9 +11,7 @@ #pragma once // Project Headers -#include "SH_API.h" -#include "Math/SHRay.h" - +#include "SHCollisionShape.h" namespace SHADE { @@ -21,62 +19,60 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SH_API SHShape + /** + * @brief + * Encapsulate a Sphere Shape used for Physics Simulations. + */ + class SH_API SHSphere final : public SHCollisionShape { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHColliderComponent; + public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class Type - { - BOX - , SPHERE - , CAPSULE - , CONVEX_HULL - - , COUNT - , NONE = -1 - }; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - bool isIntersecting; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - virtual ~SHShape () = default; + SHSphere () noexcept; + ~SHSphere () override = default; - SHShape (const SHShape&) = default; - SHShape (SHShape&&) = default; - - SHShape& operator=(const SHShape&) = default; - SHShape& operator=(SHShape&&) = default; - - SHShape(); + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] float GetWorldRadius () const noexcept; + [[nodiscard]] float GetRelativeRadius () const noexcept; + + [[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetWorldRadius (float newWorldRadius) noexcept; + void SetRelativeRadius (float newRelativeRadius) noexcept; + void SetScale (float maxScale) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0; - [[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0; + [[nodiscard]] SHMatrix GetTRS () const noexcept override; - protected: + private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; + float relativeRadius; + float scale; }; -} // namespace SHADE \ No newline at end of file +} diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp similarity index 57% rename from SHADE_Engine/src/Math/Geometry/SHShape.cpp rename to SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp index 2f869029..26387d6c 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHShape.cpp + * \file SHPhysicsObject.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a shape. + * \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 @@ -11,25 +11,25 @@ #include // Primary Header -#include "SHShape.h" +#include "SHPhysicsObject.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ + /* Constructor & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHShape::SHShape() - : type { Type::NONE } + SHPhysicsObject::SHPhysicsObject(EntityID eid) noexcept + : entityID { eid } {} - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHShape::Type SHShape::GetType() const noexcept + SHPhysicsObject::~SHPhysicsObject() noexcept { - return type; + entityID = MAX_EID; + body = nullptr; } - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h new file mode 100644 index 00000000..f9568e33 --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h @@ -0,0 +1,48 @@ +/**************************************************************************************** + * \file SHPhysicsObject.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface 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. +****************************************************************************************/ + +#pragma once + +#include + +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + /*-------------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a rigid body and a collider tied to an Entity. + */ + struct SH_API SHPhysicsObject + { + public: + /*-----------------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------------*/ + + // We use a rigid body all the time. Colliders without rigid bodies have a static body. + + EntityID entityID = MAX_EID; + rp3d::RigidBody* body = nullptr; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject (EntityID eid) noexcept; + ~SHPhysicsObject () noexcept; + + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp new file mode 100644 index 00000000..9fc403f8 --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp @@ -0,0 +1,408 @@ +/**************************************************************************************** + * \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 "Math/Transform/SHTransformComponent.h" +#include "Physics/Collision/Shapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHBox.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObjectManager::SHPhysicsObjectManager() noexcept + : factory { nullptr } + , physicsWorld { nullptr } + {} + + + + SHPhysicsObjectManager::~SHPhysicsObjectManager() noexcept + { + RemoveAllObjects(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObjectManager::EntityObjectMap& SHPhysicsObjectManager::GetPhysicsObjects() noexcept + { + return physicsObjects; + } + + const SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID entityID) noexcept + { + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) + { + SHLOG_ERROR("Cannot find physics object for entity {}!", entityID) + return nullptr; + } + + return &PHYSICS_OBJECT_ITERATOR->second; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsObjectManager::SetFactory(rp3d::PhysicsCommon* physicsFactory) noexcept + { + factory = physicsFactory; + } + + void SHPhysicsObjectManager::SetPhysicsWorld(rp3d::PhysicsWorld* world) noexcept + { + physicsWorld = world; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsObjectManager::AddRigidBody(EntityID entityID) noexcept + { + SHASSERT(physicsWorld, "Physics World Missing ffrom Physics Object Manager!") + + SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID); + + // Get the rigidbody and transform components + auto* rigidBodyComponent = SHComponentManager::GetComponent(entityID); + auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + + + + if (!physicsObject->body) + { + if (!transformComponent) + { + SHLOG_ERROR("Unable to create a rigid body for Entity {} with missing transform!", entityID) + return; + } + + // Create a new rigidbody in the physics object + const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() }; + physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM); + } + + // Link with the component + rigidBodyComponent->SetRigidBody(physicsObject->body); + + // Reset the type + const auto RIGID_BODY_TYPE = rigidBodyComponent->GetType(); + switch (RIGID_BODY_TYPE) + { + case SHRigidBodyComponent::Type::STATIC: + physicsObject->body->setType(rp3d::BodyType::STATIC); + break; + case SHRigidBodyComponent::Type::KINEMATIC: + physicsObject->body->setType(rp3d::BodyType::KINEMATIC); + break; + case SHRigidBodyComponent::Type::DYNAMIC: + physicsObject->body->setType(rp3d::BodyType::DYNAMIC); + break; + default: + break; + } + } + + void SHPhysicsObjectManager::RemoveRigidBody(EntityID entityID) noexcept + { + SHASSERT(physicsWorld, "Physics World Missing from Physics Object Manager!") + + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) + return; + + SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + + // If a collider component exists, we just set the body to static + if (SHComponentManager::GetComponent_s(entityID)) + physicsObject->body->setType(rp3d::BodyType::STATIC); + else + { + physicsWorld->destroyRigidBody(physicsObject->body); + destroyPhysicsObject(entityID); + } + } + + void SHPhysicsObjectManager::AddCollider(EntityID entityID) noexcept + { + SHASSERT(physicsWorld, "Physics World Missing from Physics Object Manager!") + + SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID); + + // Get the collider & transform component + auto* colliderComponent = SHComponentManager::GetComponent(entityID); + auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + + // Check if a body already exists. If it does, link it with the component + if (!physicsObject->body) + { + if (!transformComponent) + { + SHLOG_ERROR("Unable to create a collider for Entity {} with missing transform!", entityID) + return; + } + + // Create a static body + const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() }; + physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM); + physicsObject->body->setType(rp3d::BodyType::STATIC); + } + + // Link with component + colliderComponent->SetFactory(factory); + colliderComponent->SetCollisionBody(physicsObject->body); + } + + void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept + { + auto* colliderComponent = SHComponentManager::GetComponent(entityID); + + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR != physicsObjects.end()) + { + SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + + // Remove all collision shapes from the body + int32_t numShapes = static_cast(physicsObject->body->getNbColliders()); + while (--numShapes >= 0) + { + auto* rp3dCollider = physicsObject->body->getCollider(numShapes); + physicsObject->body->removeCollider(rp3dCollider); + + delete colliderComponent->shapes[numShapes]; + colliderComponent->shapes[numShapes] = nullptr; + } + + colliderComponent->shapes.clear(); + + // Destroy if no rigidbody component + if (!SHComponentManager::GetComponent_s(entityID)) + destroyPhysicsObject(entityID); + } + } + + void SHPhysicsObjectManager::RemoveAllObjects() noexcept + { + // Physics objects itself will delete the object + physicsObjects.clear(); + } + + void SHPhysicsObjectManager::AddRigidBodyDef(EntityID entityID) noexcept + { + auto* rigidBody = SHComponentManager::GetComponent(entityID); + + const SHRigidBodyDef RIGID_BODY_DEF + { + .entityID = rigidBody->GetEID() + , .bodyType = rigidBody->type + , .flags = rigidBody->flags + , .interpolate = rigidBody->interpolate + , .drag = rigidBody->drag + , .angularDrag = rigidBody->angularDrag + }; + + rigidBodyQueue.push(RIGID_BODY_DEF); + } + + void SHPhysicsObjectManager::AddColliderDef(EntityID entityID) noexcept + { + auto* collider = SHComponentManager::GetComponent(entityID); + + SHColliderDef colliderDef + { + .entityID = collider->GetEID() + }; + + for (const auto* shape : collider->shapes) + { + SHColliderDef::ShapeDef shapeDef + { + .type = shape->GetType() + , .posOffset = shape->GetPositionOffset() + , .rotOffset = shape->GetRotationOffset() + }; + + switch (shape->GetType()) + { + case SHCollisionShape::Type::SPHERE: + shapeDef.size.x = dynamic_cast(shape)->GetWorldRadius(); + break; + case SHCollisionShape::Type::BOX: + shapeDef.size = dynamic_cast(shape)->GetWorldExtents(); + break; + default: + break; + } + + colliderDef.shapes.emplace_back(shapeDef); + } + + colliderQueue.push(colliderDef); + } + + void SHPhysicsObjectManager::FlushDefinitions() noexcept + { + SHASSERT(physicsWorld, "Physics World Missing ffrom Physics Object Manager!") + + // Flush all rigid bodies + while (!rigidBodyQueue.empty()) + { + const SHRigidBodyDef& DEF = rigidBodyQueue.front(); + + SHPhysicsObject* physicsObject = ensurePhysicsObject(DEF.entityID); + + // Get transform component + auto* transformComponent = SHComponentManager::GetComponent_s(DEF.entityID); + if (!transformComponent) + { + SHLOG_ERROR("Unable to create a rigid body for Entity {} with missing transform!", DEF.entityID) + + rigidBodyQueue.pop(); + continue; + } + + // Create a new rigidbody in the physics object + const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() }; + physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM); + + // Get rigidBody component + auto* rigidBodyComponent = SHComponentManager::GetComponent(DEF.entityID); + rigidBodyComponent->SetRigidBody(physicsObject->body); + + // Set type + rigidBodyComponent->type = DEF.bodyType; + switch (DEF.bodyType) + { + case SHRigidBodyComponent::Type::STATIC: + physicsObject->body->setType(rp3d::BodyType::STATIC); + break; + case SHRigidBodyComponent::Type::KINEMATIC: + physicsObject->body->setType(rp3d::BodyType::KINEMATIC); + break; + case SHRigidBodyComponent::Type::DYNAMIC: + physicsObject->body->setType(rp3d::BodyType::DYNAMIC); + break; + default: + break; + } + + + // Re-set properties + rigidBodyComponent->SetGravityEnabled (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::GRAVITY)); + rigidBodyComponent->SetIsAllowedToSleep (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::SLEEPING)); + rigidBodyComponent->SetFreezePositionX (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::LINEAR_X)); + rigidBodyComponent->SetFreezePositionY (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::LINEAR_Y)); + rigidBodyComponent->SetFreezePositionZ (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::LINEAR_Z)); + rigidBodyComponent->SetFreezeRotationX (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::ANGULAR_X)); + rigidBodyComponent->SetFreezeRotationY (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::ANGULAR_Y)); + rigidBodyComponent->SetFreezeRotationZ (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::ANGULAR_Z)); + + rigidBodyComponent->SetInterpolate (DEF.interpolate); + rigidBodyComponent->SetDrag (DEF.drag); + rigidBodyComponent->SetAngularDrag (DEF.angularDrag); + + rigidBodyQueue.pop(); + } + + // Flush all colliders + while (!colliderQueue.empty()) + { + const SHColliderDef& DEF = colliderQueue.front(); + + SHPhysicsObject* physicsObject = ensurePhysicsObject(DEF.entityID); + + // Get transform component + auto* transformComponent = SHComponentManager::GetComponent_s(DEF.entityID); + if (!transformComponent) + { + SHLOG_ERROR("Unable to create a collider for Entity {} with missing transform!", DEF.entityID) + + colliderQueue.pop(); + continue; + } + + if (!physicsObject->body) + { + // Create a static body + const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() }; + physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM); + physicsObject->body->setType(rp3d::BodyType::STATIC); + } + + // Get rigidBody component + auto* colliderComponent = SHComponentManager::GetComponent(DEF.entityID); + + colliderComponent->SetFactory(factory); + colliderComponent->SetCollisionBody(physicsObject->body); + + // Add all shapes + for (auto& shapeDef : DEF.shapes) + { + switch (shapeDef.type) + { + case SHCollisionShape::Type::SPHERE: + { + colliderComponent->AddSphereCollisionShape(shapeDef.size.x); + break; + } + case SHCollisionShape::Type::BOX: + { + colliderComponent->AddBoxCollisionShape(shapeDef.size); + break; + } + default: break; + } + } + } + + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID entityID) + { + const auto& NEW_OBJECT = physicsObjects.emplace(entityID, SHPhysicsObject{entityID}).first; + return &NEW_OBJECT->second; + } + + SHPhysicsObject* SHPhysicsObjectManager::ensurePhysicsObject(EntityID entityID) + { + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + + SHPhysicsObject* physicsObject = PHYSICS_OBJECT_ITERATOR == physicsObjects.end() + ? createPhysicsObject(entityID) + : &PHYSICS_OBJECT_ITERATOR->second; + + return physicsObject; + } + + + void SHPhysicsObjectManager::destroyPhysicsObject(EntityID entityID) + { + physicsObjects.erase(entityID); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h new file mode 100644 index 00000000..3c333ff9 --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h @@ -0,0 +1,183 @@ +/**************************************************************************************** + * \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" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" + +namespace SHADE +{ + /*-------------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a manager for physics objects that links raw physics components with the + * engine's components. + */ + class SH_API SHPhysicsObjectManager + { + private: + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + using EntityObjectMap = std::unordered_map; + + public: + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + struct SHRigidBodyDef + { + EntityID entityID = MAX_EID; + SHRigidBodyComponent::Type bodyType = SHRigidBodyComponent::Type::STATIC; + uint8_t flags = 0; // aZ aY aX lZ lY lX sleepEnabled gravity + bool interpolate = true; + float drag = 0.0f; + float angularDrag = 0.0f; + }; + + struct SHColliderDef + { + struct ShapeDef + { + SHCollisionShape::Type type = SHCollisionShape::Type::SPHERE; + SHVec3 posOffset = SHVec3::Zero; + SHVec3 rotOffset = SHVec3::Zero; + SHVec3 size = SHVec3::Zero; // x for sphere radius, all 3 for box extents + }; + + EntityID entityID = MAX_EID; + std::vector shapes; + }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObjectManager () noexcept; + ~SHPhysicsObjectManager () noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*-----------------------------------------------------------------------------------*/ + + [[nodiscard]] EntityObjectMap& GetPhysicsObjects () noexcept; + [[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*-----------------------------------------------------------------------------------*/ + + void SetFactory (rp3d::PhysicsCommon* physicsFactory) noexcept; + void SetPhysicsWorld(rp3d::PhysicsWorld* world) noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Creates a rigid body and links it with the rigid body component. + * @param entityID + * The entity to link the new rigid body to. + */ + void AddRigidBody (EntityID entityID) noexcept; + + /** + * @brief + * Destroys a rigid body and removes the link with the rigid body component. + * @param entityID + * The entity to destroy the rigid body of. + */ + void RemoveRigidBody (EntityID entityID) noexcept; + + /** + * @brief + * Creates a composite collider and links it with the collider component. + * @param entityID + * The entity to link the new collider to. + */ + void AddCollider (EntityID entityID) noexcept; + + /** + * @brief + * Destroys a composite collider and removes the link with the collider component. + * @param entityID + * The entity to destroy the collider of. + */ + void RemoveCollider (EntityID entityID) noexcept; + + /** + * @brief + * Removes all physics object in the manager. This is only meant to be called when + * the world is being destroyed or the scene is being changed. + */ + void RemoveAllObjects () noexcept; + + /** + * @brief Adds a rigidbody definition to add to the physics world. + * @param rigidBody + * The rigidbody component + */ + void AddRigidBodyDef (EntityID entityID) noexcept; + + /** + * @brief Adds a collider definition to add to the physics world. + * @param collider + * The collider component + */ + void AddColliderDef (EntityID entityID) noexcept; + + /** + * @brief Adds all loaded definitions into the physics world. + */ + void FlushDefinitions () noexcept; + + private: + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + using RigidBodyQueue = std::queue; + using ColliderQueue = std::queue; + + /*-----------------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------------*/ + + rp3d::PhysicsCommon* factory; + rp3d::PhysicsWorld* physicsWorld; + EntityObjectMap physicsObjects; + + RigidBodyQueue rigidBodyQueue; + ColliderQueue colliderQueue; + + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject* createPhysicsObject (EntityID entityID); + SHPhysicsObject* ensurePhysicsObject (EntityID entityID); + void destroyPhysicsObject (EntityID entityID); + + + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index d7db2c64..15d01042 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -9,6 +9,7 @@ ****************************************************************************************/ #include +#include // Primary Header #include "SHColliderComponent.h" @@ -16,7 +17,9 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/SHMathHelpers.h" -#include "Physics/System/SHPhysicsSystem.h" +#include "Physics/SHPhysicsEvents.h" +#include "Physics/Collision/Shapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHBox.h" namespace SHADE { @@ -25,185 +28,237 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHColliderComponent::SHColliderComponent() noexcept - : system { nullptr } + : flags { ACTIVE_FLAG | MOVED_FLAG } + , collisionBody { nullptr } {} /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + bool SHColliderComponent::GetDebugDrawState() const noexcept + { + return flags & DRAW_FLAG; + } + + const SHTransform& SHColliderComponent::GetTransform() const noexcept + { + return transform; + } const SHVec3& SHColliderComponent::GetPosition() const noexcept { - return position; + return transform.position; } const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept { - return orientation; - } - - SHVec3 SHColliderComponent::GetRotation() const noexcept - { - return orientation.ToEuler(); + return transform.orientation; } const SHVec3& SHColliderComponent::GetScale() const noexcept { - return scale; + return transform.scale; } const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept { - return collisionShapes; + return shapes; } SHCollisionShape& SHColliderComponent::GetCollisionShape(int index) { - if (index < 0 || static_cast(index) >= collisionShapes.size()) - throw std::invalid_argument("Out-of-range access!"); + const int NUM_SHAPES = static_cast(shapes.size()); - return collisionShapes[index]; + if (index < 0 || index >= NUM_SHAPES) + throw std::invalid_argument("Out-of-range index!"); + + return *shapes[index]; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHColliderComponent::SetDebugDrawState(bool state) noexcept + { + state ? flags |= DRAW_FLAG : flags &= ~(DRAW_FLAG); + + #ifdef SHEDITOR + + // Broadcast event for the Debug Draw system to catch + const SHColliderOnDebugDrawEvent EVENT_DATA + { + .entityID = GetEID() + , .debugDrawState = state + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_DRAW_EVENT); + + #endif + } + + void SHColliderComponent::SetFactory(rp3d::PhysicsCommon* physicsCommon) noexcept + { + factory = physicsCommon; + } + + void SHColliderComponent::SetCollisionBody(rp3d::CollisionBody* body) noexcept + { + collisionBody = body; + } + + void SHColliderComponent::SetTransform(const SHTransform& newTransform) noexcept + { + flags |= MOVED_FLAG; + transform = newTransform; + } + + void SHColliderComponent::SetPosition(const SHVec3& newPosition) noexcept + { + flags |= MOVED_FLAG; + transform.position = newPosition; + } + + void SHColliderComponent::SetOrientation(const SHQuaternion& newOrientation) noexcept + { + flags |= MOVED_FLAG; + transform.orientation = newOrientation; + } + + void SHColliderComponent::SetScale(const SHVec3& newScale) noexcept + { + flags |= MOVED_FLAG; + transform.scale = newScale; } /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHColliderComponent::OnCreate() + const SHMatrix& SHColliderComponent::ComputeTRS() noexcept { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOG_ERROR("Physics System does not exist to link with Physics Components!") - return; - } - - system = physicsSystem; - - // Sync with transform if one already exists - if (auto* transformComponent = SHComponentManager::GetComponent_s(GetEID()); transformComponent) - { - position = transformComponent->GetWorldPosition(); - orientation = transformComponent->GetWorldOrientation(); - scale = transformComponent->GetWorldScale(); - } + return transform.ComputeTRS(); } - void SHColliderComponent::OnDestroy() + int SHColliderComponent::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) { + SHASSERT(factory, "Physics factory missing from Collider Component! Unable to add colliders!") + const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z })); + + // Create collision shape + shapes.emplace_back(new SHSphere{}); + auto* newSphere = dynamic_cast(shapes.back()); + + newSphere->collider = this; + newSphere->positionOffset = posOffset; + newSphere->rotationOffset = rotOffset; + newSphere->relativeRadius = relativeRadius; + newSphere->scale = SPHERE_SCALE; + + + rp3d::SphereShape* rp3dSphere = factory->createSphereShape(relativeRadius * SPHERE_SCALE * 0.5f); + + const rp3d::Transform OFFSETS{ posOffset, SHQuaternion::FromEuler(rotOffset) }; + newSphere->rp3dCollider = collisionBody->addCollider(rp3dSphere, OFFSETS); + + const uint32_t NEW_INDEX = static_cast(shapes.size()); + + // Broadcast Event for adding a shape + const SHPhysicsColliderAddedEvent EVENT_DATA + { + .entityID = GetEID() + , .colliderType = SHCollisionShape::Type::BOX + , .colliderIndex = static_cast(NEW_INDEX) + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + + dynamic_cast(collisionBody)->updateMassPropertiesFromColliders(); + + return static_cast(NEW_INDEX); } - void SHColliderComponent::RecomputeCollisionShapes() noexcept + int SHColliderComponent::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset) { - for (auto& collisionShape : collisionShapes) + SHASSERT(factory, "Physics factory missing from Collider Component! Unable to add colliders!") + + // Create collision shape + shapes.emplace_back(new SHBox{}); + auto* newBox = dynamic_cast(shapes.back()); + + newBox->collider = this; + newBox->positionOffset = posOffset; + newBox->rotationOffset = rotOffset; + newBox->relativeExtents = relativeExtents; + newBox->scale = SHVec3::Abs(transform.scale); + + + + rp3d::BoxShape* rp3dBox = factory->createBoxShape(relativeExtents * newBox->scale * 0.5f); + + const rp3d::Transform OFFSETS{ posOffset, SHQuaternion::FromEuler(rotOffset) }; + newBox->rp3dCollider = collisionBody->addCollider(rp3dBox, OFFSETS); + + const uint32_t NEW_INDEX = static_cast(shapes.size()); + + // Broadcast Event for adding a shape + const SHPhysicsColliderAddedEvent EVENT_DATA { - switch (collisionShape.GetType()) + .entityID = GetEID() + , .colliderType = SHCollisionShape::Type::BOX + , .colliderIndex = static_cast(NEW_INDEX) + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + + dynamic_cast(collisionBody)->updateMassPropertiesFromColliders(); + + return static_cast(NEW_INDEX); + } + + void SHColliderComponent::RemoveCollisionShape(int index) + { + const int NUM_SHAPES = static_cast(shapes.size()); + + if (index < 0 || index >= NUM_SHAPES) + throw std::invalid_argument("Out-of-range index!"); + + int i = 0; + for (auto shapeIter = shapes.begin(); shapeIter != shapes.end(); ++i, ++shapeIter) + { + if (i == index) { - case SHCollisionShape::Type::BOX: + collisionBody->removeCollider((*shapeIter)->rp3dCollider); + dynamic_cast(collisionBody)->updateMassPropertiesFromColliders(); + + const SHPhysicsColliderRemovedEvent EVENT_DATA { - auto* box = reinterpret_cast(collisionShape.shape); - const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents(); + .entityID = GetEID() + , .colliderType = (*shapeIter)->GetType() + , .colliderIndex = index + }; - // Recompute world extents based on new scale and fixed relative extents + // Broadcast Event for removing a shape + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); - const SHVec3 WORLD_EXTENTS = RELATIVE_EXTENTS * (scale * 0.5f); - box->SetWorldExtents(WORLD_EXTENTS); + SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, GetEID()) - continue; - } - case SHCollisionShape::Type::SPHERE: - { - auto* sphere = reinterpret_cast(collisionShape.shape); - const float RELATIVE_RADIUS = sphere->GetRelativeRadius(); - - // Recompute world radius based on new scale and fixed radius - - const float MAX_SCALE = SHMath::Max({ scale.x, scale.y, scale.z }); - const float WORLD_RADIUS = RELATIVE_RADIUS * MAX_SCALE * 0.5f; - sphere->SetWorldRadius(WORLD_RADIUS); - - continue; - } - default: continue; + delete *shapeIter; + shapeIter = shapes.erase(shapeIter); + return; } } } - int SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset, const SHVec3& rotOffset) noexcept + void SHColliderComponent::Update() noexcept { - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!") - return -1; - } - - static constexpr auto TYPE = SHCollisionShape::Type::BOX; - - auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE }); - - collider.entityID = GetEID(); - collider.SetPositionOffset(posOffset); - collider.SetRotationOffset(rotOffset); - collider.SetBoundingBox(halfExtents); - - // Notify Physics System - const int NEW_SHAPE_INDEX = static_cast(collisionShapes.size()) - 1; - - system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX); - return NEW_SHAPE_INDEX; + for (auto& shape : shapes) + shape->Update(); } - int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept - { - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!") - return -1; - } - static constexpr auto TYPE = SHCollisionShape::Type::SPHERE; - - auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE }); - - collider.entityID = GetEID(); - collider.SetPositionOffset(posOffset); - collider.SetBoundingSphere(radius); - - // Notify Physics System - const int NEW_SHAPE_INDEX = static_cast(collisionShapes.size()) - 1; - - system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX); - return NEW_SHAPE_INDEX; - } - - void SHColliderComponent::RemoveCollider(int index) - { - if (index < 0 || static_cast(index) >= collisionShapes.size()) - throw std::invalid_argument("Out-of-range access!"); - - int idx = 0; - auto it = collisionShapes.begin(); - for (; it != collisionShapes.end(); ++it) - { - if (idx == index) - break; - - ++idx; - } - - it = collisionShapes.erase(it); - - // Notify Physics System - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to remove Collider!") - return; - } - - system->RemoveCollisionShape(GetEID(), index); - } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index 0781f3cf..63a59e55 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -10,18 +10,24 @@ #pragma once +#include + #include // Project Headers #include "ECS_Base/Components/SHComponent.h" -#include "Math/Geometry/SHBox.h" -#include "Math/Geometry/SHSphere.h" -#include "SHCollisionShape.h" +#include "Math/Transform/SHTransform.h" +#include "Physics/Collision/Shapes/SHCollisionShape.h" -//namespace SHADE -//{ -// class SHPhysicsSystem; -//} +/*-------------------------------------------------------------------------------------*/ +/* Forward Declarations */ +/*-------------------------------------------------------------------------------------*/ + +namespace reactphysics3d +{ + class PhysicsCommon; + class CollisionBody; +} namespace SHADE { @@ -37,13 +43,13 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; - friend class SHPhysicsObject; + friend class SHPhysicsObjectManager; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using CollisionShapes = std::vector; + using CollisionShapes = std::vector; public: @@ -67,29 +73,88 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool HasChanged () const noexcept; + [[nodiscard]] bool GetDebugDrawState () const noexcept; - [[nodiscard]] const SHVec3& GetPosition () const noexcept; - [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; - [[nodiscard]] SHVec3 GetRotation () const noexcept; - [[nodiscard]] const SHVec3& GetScale () const noexcept; + [[nodiscard]] const SHTransform& GetTransform () const noexcept; + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + [[nodiscard]] const SHVec3& GetScale () const noexcept; - [[nodiscard]] const CollisionShapes& GetCollisionShapes() const noexcept; - [[nodiscard]] SHCollisionShape& GetCollisionShape (int index); + [[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept; + [[nodiscard]] SHCollisionShape& GetCollisionShape (int index); + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetDebugDrawState (bool state) noexcept; + + void SetFactory (reactphysics3d::PhysicsCommon* physicsCommon) noexcept; + void SetCollisionBody (reactphysics3d::CollisionBody* body) noexcept; + + void SetTransform (const SHTransform& newTransform) noexcept; + void SetPosition (const SHVec3& newPosition) noexcept; + void SetOrientation (const SHQuaternion& newOrientation) noexcept; + void SetScale (const SHVec3& newScale) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - void OnCreate () override; - void OnDestroy () override; + /** + * @brief + * Computes the TRS for the collider's transform + * @return + * The computed TRS. + */ + const SHMatrix& ComputeTRS() noexcept; - void RecomputeCollisionShapes () noexcept; + /** + * @brief + * Adds a sphere collision shape. + * @param relativeRadius + * The relative radius is constructed with respect to the world scale.
+ * Radius = max(scale.x, scale.y, scale.z) * 0.5 * relativeRadius + * @param posOffset + * The position offset of the sphere from the center of the collider. Defaults to a Zero Vector. + * @param rotOffset + * The rotation offset of the sphere from the rotation of the collider. Defaults to a Zero Vector. + * @return + * The index of the newly added shape. + */ + int AddSphereCollisionShape (float relativeRadius, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); - void RemoveCollider (int index); + /** + * @brief + * Adds a box collision shape. + * @param relativeExtents + * The relative extents are constructed with respect to the world scale.
+ * Extents = scale * 0.5 * relativeExtents + * @param posOffset + * The position offset of the box from the center of the collider. Defaults to a Zero Vector. + * @param rotOffset + * The rotation offset of the box from the rotation of the collider. Defaults to a Zero Vector. + * @return + * The index of the newly added shape. + */ + int AddBoxCollisionShape (const SHVec3& relativeExtents, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); - int AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero) noexcept; - int AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept; + /** + * @brief + * Removes a shape from the container. Removal reduces the size of the container. + * If removing all, perform removal from back to front. + * @param index + * The index of the shape to remove. + * @throws + * Invalid argument for out-of-range indices. + */ + void RemoveCollisionShape (int index); + + /** + * @brief + * Recomputes the transforms for all shapes in this composite collider. + */ + void Update () noexcept; private: @@ -97,12 +162,15 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHPhysicsSystem* system; + static constexpr uint8_t ACTIVE_FLAG = 1U << 0; + static constexpr uint8_t DRAW_FLAG = 1U << 1; + static constexpr uint8_t MOVED_FLAG = 1U << 2; - SHVec3 position; - SHQuaternion orientation; - SHVec3 scale; - CollisionShapes collisionShapes; + uint8_t flags; // 0 0 0 0 0 hasMoved debugDraw active + reactphysics3d::PhysicsCommon* factory; + reactphysics3d::CollisionBody* collisionBody; + SHTransform transform; + CollisionShapes shapes; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp deleted file mode 100644 index f597077f..00000000 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/**************************************************************************************** - * \file SHCollider.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Collider. - * - * \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 "SHCollisionShape.h" -// Project Headers -#include "Math/Geometry/SHBox.h" -#include "Math/Geometry/SHSphere.h" -#include "Math/SHMathHelpers.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" -#include "Reflection/SHReflectionMetadata.h" -#include "SHColliderComponent.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionShape::SHCollisionShape(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial) - : type { colliderType } - , entityID { eid } - , isTrigger { false } - , dirty { true } - , shape { nullptr } - , material { physicsMaterial } - , collisionTag { SHCollisionTagMatrix::GetTag(0) } - { - switch (type) - { - case Type::BOX: - { - shape = new SHBox{ SHVec3::Zero, SHVec3::One }; - break; - } - case Type::SPHERE: - { - shape = new SHSphere{ SHVec3::Zero, 0.5f }; - break; - } - default: break; - } - } - - SHCollisionShape::SHCollisionShape(const SHCollisionShape& rhs) noexcept - : type { rhs.type} - , entityID { rhs.entityID } - , isTrigger { rhs.isTrigger } - , dirty { true } - , shape { nullptr } - , material { rhs.material } - , positionOffset { rhs.positionOffset } - , rotationOffset { rhs.rotationOffset } - , collisionTag { rhs.collisionTag } - { - CopyShape(rhs.shape); - } - - SHCollisionShape::SHCollisionShape(SHCollisionShape&& rhs) noexcept - : type { rhs.type} - , entityID { rhs.entityID } - , isTrigger { rhs.isTrigger } - , dirty { true } - , shape { nullptr } - , material { rhs.material } - , positionOffset { rhs.positionOffset } - , rotationOffset { rhs.rotationOffset } - , collisionTag { rhs.collisionTag } - { - CopyShape(rhs.shape); - } - - SHCollisionShape::~SHCollisionShape() noexcept - { - shape = nullptr; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionShape& SHCollisionShape::operator=(const SHCollisionShape& rhs) noexcept - { - if (this == &rhs) - return *this; - - type = rhs.type; - entityID = rhs.entityID; - isTrigger = rhs.isTrigger; - dirty = true; - material = rhs.material; - positionOffset = rhs.positionOffset; - rotationOffset = rhs.rotationOffset; - collisionTag = rhs.collisionTag; - - delete shape; - CopyShape(rhs.shape); - - return *this; - } - - SHCollisionShape& SHCollisionShape::operator=(SHCollisionShape&& rhs) noexcept - { - type = rhs.type; - entityID = rhs.entityID; - isTrigger = rhs.isTrigger; - dirty = true; - material = rhs.material; - positionOffset = rhs.positionOffset; - rotationOffset = rhs.rotationOffset; - collisionTag = rhs.collisionTag; - - delete shape; - CopyShape(rhs.shape); - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHCollisionShape::HasChanged() const noexcept - { - return dirty; - } - - bool SHCollisionShape::IsTrigger() const noexcept - { - return isTrigger; - } - - SHCollisionShape::Type SHCollisionShape::GetType() const noexcept - { - return type; - } - - const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept - { - return *collisionTag; - } - - float SHCollisionShape::GetFriction() const noexcept - { - return material.GetFriction(); - } - - float SHCollisionShape::GetBounciness() const noexcept - { - return material.GetBounciness(); - } - - float SHCollisionShape::GetDensity() const noexcept - { - return material.GetDensity(); - } - - const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept - { - return material; - } - - const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept - { - return positionOffset; - } - - const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept - { - return rotationOffset; - } - - const SHShape* SHCollisionShape::GetShape() const noexcept - { - return shape; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::SetBoundingBox(const SHVec3& halfExtents) - { - dirty = true; - - const auto* COLLIDER = SHComponentManager::GetComponent(entityID); - auto* box = reinterpret_cast(shape); - - SHVec3 correctedHalfExtents = halfExtents; - - // Get current relative halfExtents for error checking. 0 is ignored - const SHVec3& CURRENT_RELATIVE_EXTENTS = box->GetRelativeExtents(); - for (size_t i = 0; i < SHVec3::SIZE; ++i) - { - if (SHMath::CompareFloat(halfExtents[i], 0.0f)) - correctedHalfExtents[i] = CURRENT_RELATIVE_EXTENTS[i]; - } - - // Set the half extents relative to world scale - const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale() * 0.5f; - - if (type != Type::BOX) - { - type = Type::BOX; - - delete shape; - shape = new SHBox{ positionOffset, WORLD_EXTENTS }; - } - - box->SetWorldExtents(WORLD_EXTENTS); - box->SetRelativeExtents(correctedHalfExtents); - } - - void SHCollisionShape::SetBoundingSphere(float radius) - { - dirty = true; - - auto* sphere = reinterpret_cast(shape); - const auto* COLLIDER = SHComponentManager::GetComponent(entityID); - - // Get current relative halfExtents for error checking. 0 is ignored - const float CURRENT_RELATIVE_RADIUS = sphere->GetRelativeRadius(); - if (SHMath::CompareFloat(radius, 0.0f)) - radius = CURRENT_RELATIVE_RADIUS; - - // Set the radius relative to world scale - const SHVec3 WORLD_SCALE = COLLIDER->GetScale(); - const float MAX_SCALE = SHMath::Max({ WORLD_SCALE.x, WORLD_SCALE.y, WORLD_SCALE.z }); - const float WORLD_RADIUS = radius * MAX_SCALE * 0.5f; - - if (type != Type::SPHERE) - { - type = Type::SPHERE; - - delete shape; - shape = new SHSphere{ positionOffset, WORLD_RADIUS }; - } - - sphere->SetWorldRadius(WORLD_RADIUS); - sphere->SetRelativeRadius(radius); - } - - void SHCollisionShape::SetIsTrigger(bool trigger) noexcept - { - dirty = true; - isTrigger = trigger; - } - - void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept - { - dirty = true; - collisionTag = newCollisionTag; - } - - void SHCollisionShape::SetFriction(float friction) noexcept - { - dirty = true; - material.SetFriction(friction); - } - - void SHCollisionShape::SetBounciness(float bounciness) noexcept - { - dirty = true; - material.SetBounciness(bounciness); - } - - void SHCollisionShape::SetDensity(float density) noexcept - { - dirty = true; - material.SetDensity(density); - } - - void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept - { - dirty = true; - material = newMaterial; - } - - void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept - { - dirty = true; - positionOffset = posOffset; - - switch (type) - { - case Type::BOX: - { - reinterpret_cast(shape)->SetCenter(positionOffset); - break; - } - case Type::SPHERE: - { - reinterpret_cast(shape)->SetCenter(positionOffset); - break; - } - default: break; - } - } - - void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept - { - dirty = true; - rotationOffset = rotOffset; - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::CopyShape(const SHShape* rhs) - { - switch (type) - { - case Type::BOX: - { - const auto* RHS_BOX = reinterpret_cast(rhs); - - shape = new SHBox{ positionOffset, RHS_BOX->GetWorldExtents() }; - auto* lhsBox = reinterpret_cast(shape); - lhsBox->SetRelativeExtents(RHS_BOX->GetRelativeExtents()); - - break; - } - case Type::SPHERE: - { - const auto* RHS_SPHERE = reinterpret_cast(rhs); - - shape = new SHSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() }; - auto* lhsSphere = reinterpret_cast(shape); - lhsSphere->SetRelativeRadius(RHS_SPHERE->GetRelativeRadius()); - - break; - } - default: break; - } - } - -} // namespace SHADE - -RTTR_REGISTRATION -{ - using namespace SHADE; - using namespace rttr; - - registration::enumeration("Collider Type") - ( - value("Box", SHCollisionShape::Type::BOX), - value("Sphere", SHCollisionShape::Type::SPHERE) - // TODO(Diren): Add More Shapes - ); - - registration::class_("Collider") - .property("IsTrigger" , &SHCollisionShape::IsTrigger , &SHCollisionShape::SetIsTrigger ) - .property("Friction" , &SHCollisionShape::GetFriction , &SHCollisionShape::SetFriction ) - .property("Bounciness" , &SHCollisionShape::GetBounciness , &SHCollisionShape::SetBounciness ) - .property("Density" , &SHCollisionShape::GetDensity , &SHCollisionShape::SetDensity ) - .property("Position Offset" , &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset) - .property("Rotation Offset" , &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true)); -} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h deleted file mode 100644 index 597814a6..00000000 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************************** - * \file SHCollider.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Collider. - * - * \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/Entity/SHEntity.h" -#include "Math/Geometry/SHShape.h" -#include "Math/SHQuaternion.h" -#include "SHPhysicsMaterial.h" -#include "Physics/Collision/SHCollisionTags.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHCollisionShape - { - private: - - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHColliderComponent; - friend class SHPhysicsObject; - - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class Type - { - BOX - , SPHERE - , CAPSULE - }; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionShape (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT); - - SHCollisionShape (const SHCollisionShape& rhs) noexcept; - SHCollisionShape (SHCollisionShape&& rhs) noexcept; - ~SHCollisionShape () noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept; - SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] bool HasChanged () const noexcept; - - [[nodiscard]] bool IsTrigger () const noexcept; - - [[nodiscard]] Type GetType () const noexcept; - - [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; - - [[nodiscard]] float GetFriction () const noexcept; - [[nodiscard]] float GetBounciness () const noexcept; - [[nodiscard]] float GetDensity () const noexcept; - [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; - - [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; - [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; - - [[nodiscard]] const SHShape* GetShape () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetBoundingBox (const SHVec3& halfExtents); - void SetBoundingSphere (float radius); - - void SetIsTrigger (bool isTrigger) noexcept; - void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; - void SetFriction (float friction) noexcept; - void SetBounciness (float bounciness) noexcept; - void SetDensity (float density) noexcept; - void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; - - void SetPositionOffset (const SHVec3& posOffset) noexcept; - void SetRotationOffset (const SHVec3& rotOffset) noexcept; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - Type type; - EntityID entityID; // The entity this collider belongs to - bool isTrigger; - bool dirty; - - SHShape* shape; - SHPhysicsMaterial material; - - SHVec3 positionOffset; - SHVec3 rotationOffset; - - SHCollisionTag* collisionTag; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void CopyShape(const SHShape* rhs); - - RTTR_ENABLE() - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index 330c3abe..a374665d 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -20,6 +20,7 @@ #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/SHMathHelpers.h" #include "Physics/System/SHPhysicsSystem.h" +#include "Tools/Utilities/SHUtilities.h" namespace SHADE { @@ -29,99 +30,78 @@ namespace SHADE SHRigidBodyComponent::SHRigidBodyComponent() noexcept : type { Type::DYNAMIC } + , interpolate { true } , flags { 0 } - , dirtyFlags { std::numeric_limits::max() } - , mass { 1.0f } , drag { 0.01f } - , angularDrag { 0.01f } - , system { nullptr } + , angularDrag { 0.1f } + , rigidBody { nullptr } { - // Initialise default flags - flags |= 1U << 0; // Gravity set to true - flags |= 1U << 1; // Sleeping allowed - flags |= 1U << 8; // Interpolate by default + // Default flags + flags |= 1U << 0; // enable gravity } /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHRigidBodyComponent::IsGravityEnabled() const noexcept - { - static constexpr int FLAG_POS = 0; - return flags & (1U << FLAG_POS); - } - - bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept - { - static constexpr int FLAG_POS = 1; - return flags & (1U << FLAG_POS); - } - - bool SHRigidBodyComponent::IsInterpolating() const noexcept - { - static constexpr int FLAG_POS = 8; - return flags & (1U << FLAG_POS); - } - - bool SHRigidBodyComponent::GetIsSleeping() const noexcept - { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->isSleeping(); - - return false; - } - SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept { return type; } + bool SHRigidBodyComponent::IsGravityEnabled() const noexcept + { + return flags & SHUtilities::ConvertEnum(Flags::GRAVITY); + } + + bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept + { + return flags & SHUtilities::ConvertEnum(Flags::SLEEPING); + } + + bool SHRigidBodyComponent::IsInterpolating() const noexcept + { + return interpolate; + } + + bool SHRigidBodyComponent::IsSleeping() const noexcept + { + return rigidBody ? rigidBody->isSleeping() : false; + } + bool SHRigidBodyComponent::GetFreezePositionX() const noexcept { - static constexpr int FLAG_POS = 2; - return flags & (1U << FLAG_POS); + return flags & SHUtilities::ConvertEnum(Flags::LINEAR_X); } bool SHRigidBodyComponent::GetFreezePositionY() const noexcept { - static constexpr int FLAG_POS = 3; - return flags & (1U << FLAG_POS); + return flags & SHUtilities::ConvertEnum(Flags::LINEAR_Y); } bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept { - static constexpr int FLAG_POS = 4; - return flags & (1U << FLAG_POS); + return flags & SHUtilities::ConvertEnum(Flags::LINEAR_Z); } bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept { - static constexpr int FLAG_POS = 5; - return flags & (1U << FLAG_POS); + return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_X); } bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept { - static constexpr int FLAG_POS = 6; - return flags & (1U << FLAG_POS); + return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_Y); } bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept { - static constexpr int FLAG_POS = 7; - return flags & (1U << FLAG_POS); + return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_Z); } - //bool SHRigidBodyComponent::GetAutoMass() const noexcept - //{ - // static constexpr int FLAG_POS = 9; - // return flags & (1U << FLAG_POS); - //} - - float SHRigidBodyComponent::GetMass() const noexcept + float SHRigidBodyComponent::GetMass() const noexcept { - return mass; + return rigidBody ? rigidBody->getMass() : 0.0f; } float SHRigidBodyComponent::GetDrag() const noexcept @@ -136,49 +116,32 @@ namespace SHADE SHVec3 SHRigidBodyComponent::GetForce() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getForce(); - - return SHVec3::Zero; + return rigidBody ? SHVec3{ rigidBody->getForce() } : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetTorque() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getTorque(); - - return SHVec3::Zero; + return rigidBody ? SHVec3{ rigidBody->getTorque() } : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getLinearVelocity(); - - return SHVec3::Zero; + return rigidBody ? SHVec3{ rigidBody->getLinearVelocity() } : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getAngularVelocity(); - - return SHVec3::Zero; + return rigidBody ? SHVec3{ rigidBody->getAngularVelocity() } : SHVec3::Zero; } - const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept + SHVec3 SHRigidBodyComponent::GetPosition() const noexcept { - return position; - } - - const SHQuaternion& SHRigidBodyComponent::GetOrientation() const noexcept - { - return orientation; + return rigidBody ? SHVec3{ rigidBody->getTransform().getPosition() } : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetRotation() const noexcept { - return orientation.ToEuler(); + return rigidBody ? SHQuaternion{ rigidBody->getTransform().getOrientation() }.ToEuler() : SHVec3::Zero; } /*-----------------------------------------------------------------------------------*/ @@ -187,224 +150,174 @@ namespace SHADE void SHRigidBodyComponent::SetType(Type newType) noexcept { - static constexpr int FLAG_POS = 8; - if (type == newType) return; type = newType; - dirtyFlags |= 1U << FLAG_POS; + + SHASSERT(rigidBody, "Unable to find rp3dBody on RigidBodyComponent!") + + switch (type) + { + case Type::STATIC: + rigidBody->setType(rp3d::BodyType::STATIC); + break; + case Type::KINEMATIC: + rigidBody->setType(rp3d::BodyType::KINEMATIC); + break; + case Type::DYNAMIC: + rigidBody->setType(rp3d::BodyType::DYNAMIC); + break; + default: + break; + } } + void SHRigidBodyComponent::SetRigidBody(rp3d::RigidBody* body) noexcept + { + rigidBody = body; + } + + void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept { - static constexpr int FLAG_POS = 0; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::GRAVITY); + enableGravity ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - enableGravity ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + if (rigidBody) + rigidBody->enableGravity(enableGravity); } void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept { - static constexpr int FLAG_POS = 1; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::SLEEPING); + isAllowedToSleep ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - isAllowedToSleep ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + if (rigidBody) + rigidBody->setIsAllowedToSleep(isAllowedToSleep); } void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept { - static constexpr int FLAG_POS = 2; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_X); + freezePositionX ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type == Type::STATIC) + if (rigidBody) { - SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) - return; + rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor(); + linearLock.x = freezePositionX ? 0.0f : 1.0f; + rigidBody->setLinearLockAxisFactor(linearLock); } - - 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; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_Y); + freezePositionY ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type == Type::STATIC) + if (rigidBody) { - SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) - return; + rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor(); + linearLock.y = freezePositionY ? 0.0f : 1.0f; + rigidBody->setLinearLockAxisFactor(linearLock); } - - 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; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_Z); + freezePositionZ ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type == Type::STATIC) + if (rigidBody) { - SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) - return; + rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor(); + linearLock.z = freezePositionZ ? 0.0f : 1.0f; + rigidBody->setLinearLockAxisFactor(linearLock); } - - 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; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_X); + freezeRotationX ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type == Type::STATIC) + if (rigidBody) { - SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) - return; + rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor(); + angularLock.x = freezeRotationX ? 0.0f : 1.0f; + rigidBody->setAngularLockAxisFactor(angularLock); } - - 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; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_Y); + freezeRotationY ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type == Type::STATIC) + if (rigidBody) { - SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) - return; + rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor(); + angularLock.y = freezeRotationY ? 0.0f : 1.0f; + rigidBody->setAngularLockAxisFactor(angularLock); } - - 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; + constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_Z); + freezeRotationZ ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - if (type == Type::STATIC) + if (rigidBody) { - SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) - return; + rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor(); + angularLock.z = freezeRotationZ ? 0.0f : 1.0f; + rigidBody->setAngularLockAxisFactor(angularLock); } - - dirtyFlags |= 1U << FLAG_POS; - freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept { - static constexpr int FLAG_POS = 8; - allowInterpolation ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + interpolate = allowInterpolation; } - //void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept - //{ - // static constexpr int FLAG_POS = 9; - // autoMass ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); - - // dirtyFlags |= 1U << FLAG_POS; - //} - - //void SHRigidBodyComponent::SetMass(float newMass) noexcept - //{ - // static constexpr int FLAG_POS = 9; - - // if (newMass < 0.0f) - // return; - - // if (type != Type::DYNAMIC) - // { - // SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) - // return; - // } - - // dirtyFlags |= 1U << FLAG_POS; - // mass = newMass; - - // // Turn off automass - // flags &= ~(1U << FLAG_POS); - //} - 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; - } - - dirtyFlags |= 1U << FLAG_POS; drag = newDrag; + + if (rigidBody) + rigidBody->setLinearDamping(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; - } - - dirtyFlags |= 1U << FLAG_POS; angularDrag = newAngularDrag; + + if (rigidBody) + rigidBody->setAngularDamping(newAngularDrag); } void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { - if (type == Type::STATIC) { SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID()) return; } - auto* physicsObject = system->GetPhysicsObject(GetEID()); - if (!physicsObject) - { - SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID()) - return; - } - physicsObject->GetRigidBody()->setLinearVelocity(newLinearVelocity); + if (rigidBody) + rigidBody->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; } - auto* physicsObject = system->GetPhysicsObject(GetEID()); - if (!physicsObject) - { - SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID()) - return; - } - physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity); + if (rigidBody) + rigidBody->setAngularVelocity(newAngularVelocity); } /*-----------------------------------------------------------------------------------*/ @@ -413,81 +326,67 @@ namespace SHADE void SHRigidBodyComponent::OnCreate() { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOG_ERROR("Physics System does not exist to link with Physics Components!") - return; - } - system = physicsSystem; - - // Sync with transform if one already exists - if (auto* transformComponent = SHComponentManager::GetComponent_s(GetEID()); transformComponent) - { - position = transformComponent->GetWorldPosition(); - orientation = transformComponent->GetWorldOrientation(); - } } void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldForceAtCenterOfMass(force); + if (rigidBody) + rigidBody->applyWorldForceAtCenterOfMass(force); } void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldForceAtLocalPosition(force, localPos); + if (rigidBody) + rigidBody->applyWorldForceAtLocalPosition(force, localPos); } void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldForceAtWorldPosition(force, worldPos); + if (rigidBody) + rigidBody->applyWorldForceAtWorldPosition(force, worldPos); } void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalForceAtCenterOfMass(relativeForce); + if (rigidBody) + rigidBody->applyLocalForceAtCenterOfMass(relativeForce); } void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalForceAtLocalPosition(relativeForce, localPos); + if (rigidBody) + rigidBody->applyLocalForceAtLocalPosition(relativeForce, localPos); } void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalForceAtWorldPosition(relativeForce, worldPos); + if (rigidBody) + rigidBody->applyLocalForceAtWorldPosition(relativeForce, worldPos); } void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldTorque(torque); + if (rigidBody) + rigidBody->applyWorldTorque(torque); } void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalTorque(relativeTorque); + if (rigidBody) + rigidBody->applyLocalTorque(relativeTorque); } void SHRigidBodyComponent::ClearForces() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->resetForce(); + if (rigidBody) + rigidBody->resetForce(); } void SHRigidBodyComponent::ClearTorque() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->resetTorque(); + if (rigidBody) + rigidBody->resetTorque(); } } // namespace SHADE @@ -506,13 +405,11 @@ RTTR_REGISTRATION registration::class_("RigidBody Component") .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) - //.property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) .property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag ) .property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag ) .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled ) .property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate ) .property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep) - //.property("Auto Mass" , &SHRigidBodyComponent::GetAutoMass , &SHRigidBodyComponent::SetAutoMass ) .property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX ) .property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY ) .property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ ) diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index 532b3312..5fe49dbe 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -17,6 +17,15 @@ #include "Math/Vector/SHVec3.h" #include "Math/SHQuaternion.h" +/*-------------------------------------------------------------------------------------*/ +/* Forward Declarations */ +/*-------------------------------------------------------------------------------------*/ + +namespace reactphysics3d +{ + class RigidBody; +} + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -31,7 +40,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; - friend class SHPhysicsObject; + friend class SHPhysicsObjectManager; public: /*---------------------------------------------------------------------------------*/ @@ -67,35 +76,31 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool IsGravityEnabled () const noexcept; - [[nodiscard]] bool IsAllowedToSleep () const noexcept; - [[nodiscard]] bool IsInterpolating () const noexcept; + [[nodiscard]] Type GetType () const noexcept; - [[nodiscard]] bool GetIsSleeping () const noexcept; + [[nodiscard]] bool IsGravityEnabled () const noexcept; + [[nodiscard]] bool IsAllowedToSleep () const noexcept; + [[nodiscard]] bool IsInterpolating () const noexcept; + [[nodiscard]] bool IsSleeping () const noexcept; - [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] bool GetFreezePositionX () const noexcept; + [[nodiscard]] bool GetFreezePositionY () const noexcept; + [[nodiscard]] bool GetFreezePositionZ () const noexcept; + [[nodiscard]] bool GetFreezeRotationX () const noexcept; + [[nodiscard]] bool GetFreezeRotationY () const noexcept; + [[nodiscard]] bool GetFreezeRotationZ () const noexcept; - [[nodiscard]] bool GetFreezePositionX () const noexcept; - [[nodiscard]] bool GetFreezePositionY () const noexcept; - [[nodiscard]] bool GetFreezePositionZ () const noexcept; - [[nodiscard]] bool GetFreezeRotationX () const noexcept; - [[nodiscard]] bool GetFreezeRotationY () const noexcept; - [[nodiscard]] bool GetFreezeRotationZ () const noexcept; + [[nodiscard]] float GetMass () const noexcept; + [[nodiscard]] float GetDrag () const noexcept; + [[nodiscard]] float GetAngularDrag () const noexcept; - //[[nodiscard]] bool GetAutoMass () const noexcept; + [[nodiscard]] SHVec3 GetForce () const noexcept; + [[nodiscard]] SHVec3 GetTorque () const noexcept; + [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; + [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; - [[nodiscard]] float GetMass () const noexcept; - [[nodiscard]] float GetDrag () const noexcept; - [[nodiscard]] float GetAngularDrag () const noexcept; - - [[nodiscard]] SHVec3 GetForce () const noexcept; - [[nodiscard]] SHVec3 GetTorque () const noexcept; - [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; - [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; - - [[nodiscard]] const SHVec3& GetPosition () const noexcept; - [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; - [[nodiscard]] SHVec3 GetRotation () const noexcept; + [[nodiscard]] SHVec3 GetPosition () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ @@ -103,8 +108,11 @@ namespace SHADE void SetType (Type newType) noexcept; + void SetRigidBody (reactphysics3d::RigidBody* body) 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; @@ -112,9 +120,7 @@ namespace SHADE void SetFreezeRotationY (bool freezeRotationY) noexcept; void SetFreezeRotationZ (bool freezeRotationZ) noexcept; void SetInterpolate (bool allowInterpolation) noexcept; - //void SetAutoMass (bool autoMass) noexcept; - //void SetMass (float newMass) noexcept; void SetDrag (float newDrag) noexcept; void SetAngularDrag (float newAngularDrag) noexcept; @@ -140,29 +146,42 @@ namespace SHADE void ClearTorque () const noexcept; private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Flags : uint8_t + { + GRAVITY = 0x0 + , SLEEPING = 0x1 + , LINEAR_X = 0x2 + , LINEAR_Y = 0x4 + , LINEAR_Z = 0x8 + , ANGULAR_X = 0x10 + , ANGULAR_Y = 0x20 + , ANGULAR_Z = 0x30 + }; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr size_t NUM_FLAGS = 8; - static constexpr size_t NUM_DIRTY_FLAGS = 12; + static constexpr size_t NUM_FLAGS = 8; - Type type; + Type type; + bool interpolate; - uint16_t flags; // 0 0 0 0 0 0 am ip 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 + // Used for storing serialised data + uint8_t flags; // aZ aY aX lZ lY lX sleepEnabled gravity + float drag; + float angularDrag; - float mass; - float drag; - float angularDrag; + // For interpolation - SHVec3 linearVelocity; - SHVec3 angularVelocity; + SHVec3 position; + SHQuaternion orientation; - SHPhysicsSystem* system; - - SHVec3 position; - SHQuaternion orientation; + reactphysics3d::RigidBody* rigidBody; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp deleted file mode 100644 index 71b08831..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp +++ /dev/null @@ -1,431 +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" -#include "Scene/SHSceneManager.h" - - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept - : entityID { eid } - , collidersActive { true } - , 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) - { - // 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; - } - - auto* rp3dCollider = rp3dBody->getCollider(rp3dBody->getNbColliders() - 1); - syncColliderProperties(collisionShape, rp3dCollider); - - if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC) - { - rp3dBody->updateMassPropertiesFromColliders(); - - if (auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); rigidBodyComponent) - rigidBodyComponent->mass = rp3dBody->getMass(); - } - - return index; - } - - void SHPhysicsObject::RemoveCollisionShape(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); - - if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC) - { - rp3dBody->updateMassPropertiesFromColliders(); - - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - if (rigidBodyComponent) - rigidBodyComponent->mass = rp3dBody->getMass(); - } - } - - 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 - { - // This state is synced in the pre-update routine - if (!rp3dBody->isActive()) - return; - - 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); - - //if (component.GetAutoMass()) - //{ - // rp3dBody->updateMassPropertiesFromColliders(); - // component.mass = rp3dBody->getMass(); - //} - //else - //{ - // 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 - { - // This state is synced in the pre-update routine - if (!rp3dBody->isActive()) - return; - - const int NUM_SHAPES = static_cast(rp3dBody->getNbColliders()); - for (int i = 0; i < NUM_SHAPES; ++i) - { - auto& collisionShape = component.collisionShapes[i]; - - if (!collisionShape.dirty) - continue; - - switch (collisionShape.GetType()) - { - case SHCollisionShape::Type::BOX: syncBoxShape(i, collisionShape); break; - case SHCollisionShape::Type::SPHERE: syncSphereShape(i, collisionShape); break; - default: break; - } - - auto* rp3dCollider = rp3dBody->getCollider(i); - syncColliderProperties(collisionShape, rp3dCollider); - - collisionShape.dirty = false; - } - - // Set rigidbody mass if dynamic - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - if (rigidBodyComponent) - { - // This is generally expensive, will be optimised in the future with my own engine. - rp3dBody->updateMassPropertiesFromColliders(); - rigidBodyComponent->mass = rp3dBody->getMass(); - } - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsObject::syncColliderProperties(const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept - { - rp3dCollider->setIsTrigger(collisionShape.IsTrigger()); - - auto& rp3dMaterial = rp3dCollider->getMaterial(); - - rp3dMaterial.setFrictionCoefficient(collisionShape.GetFriction()); - rp3dMaterial.setBounciness(collisionShape.GetBounciness()); - rp3dMaterial.setMassDensity(collisionShape.GetDensity()); - - const unsigned short MASK_BITS = collisionShape.GetCollisionTag(); - rp3dCollider->setCollisionCategoryBits(MASK_BITS); - rp3dCollider->setCollideWithMaskBits(MASK_BITS); - } - - void SHPhysicsObject::addBoxShape(const 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, const 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(const 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, const 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/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h deleted file mode 100644 index c572ca2e..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsObject.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface 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. -****************************************************************************************/ - -#pragma once - -#include - -// Project Headers -#include "Math/Transform/SHTransformComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" -#include "Physics/Interface/SHColliderComponent.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHPhysicsObject - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHPhysicsSystem; - friend class SHPhysicsObjectManager; - - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject (EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept; - SHPhysicsObject (const SHPhysicsObject& rhs) noexcept = default; - SHPhysicsObject (SHPhysicsObject&& rhs) noexcept = default; - virtual ~SHPhysicsObject () noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept = default; - SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept = default; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[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 SetStaticBody () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - int AddCollisionShape (int index); - void RemoveCollisionShape (int index); - void RemoveAllCollisionShapes () const noexcept; - - void SyncRigidBody (SHRigidBodyComponent& component) const noexcept; - void SyncColliders (SHColliderComponent& component) const noexcept; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - EntityID entityID; - bool collidersActive; // Only used to sync with SHADE components - - rp3d::PhysicsCommon* factory; - rp3d::PhysicsWorld* world; - - rp3d::RigidBody* rp3dBody; - rp3d::Transform prevTransform; // Cached transform for interpolation - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void syncColliderProperties (const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept; - - // Box Shapes - - void addBoxShape (const SHCollisionShape& boxShape) const noexcept; - void syncBoxShape (int index, const SHCollisionShape& boxShape) const noexcept; - - // Sphere Shapes - - void addSphereShape (const SHCollisionShape& sphereShape) const noexcept; - void syncSphereShape (int index, const 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 deleted file mode 100644 index 7c111a2d..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/**************************************************************************************** - * \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/Utilities/SHUtilities.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Static Data Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[3][2] - { - addRigidBody , addCollider , addCollisionShape - , removeRigidBody , removeCollider , 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); - wakeAllObjects(); - 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); - - // If any removal was done, wake all objects - if (COMMAND.command == QueueCommand::Command::REMOVE) - wakeAllObjects(); - } - } - - 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. - // Nothing is needed here. - } - - 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); - } - - void SHPhysicsObjectManager::wakeAllObjects() noexcept - { - for (auto& physicsObject : physicsObjects | std::views::values) - physicsObject.GetRigidBody()->setIsSleeping(false); - } - - -} // 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 deleted file mode 100644 index f41c62ad..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************************** - * \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[3][2]; // 3 components, 2 commands - - 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; - - void wakeAllObjects () 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/Collision/SHCollisionListener.cpp b/SHADE_Engine/src/Physics/RP3DWrapper/SHCollisionListener.cpp similarity index 94% rename from SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp rename to SHADE_Engine/src/Physics/RP3DWrapper/SHCollisionListener.cpp index 3e485153..98f6bdc1 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp +++ b/SHADE_Engine/src/Physics/RP3DWrapper/SHCollisionListener.cpp @@ -15,7 +15,7 @@ // Project Headers #include "ECS_Base/Managers/SHEntityManager.h" -#include "Physics/PhysicsObject/SHPhysicsObject.h" +#include "Physics/Interface/PhysicsObject/SHPhysicsObject.h" #include "Physics/System/SHPhysicsSystem.h" #include "Scene/SHSceneManager.h" @@ -25,9 +25,9 @@ uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID) { - for (uint32_t i = 0; i < physicsObject.GetCollisionBody()->getNbColliders(); ++i) + for (uint32_t i = 0; i < physicsObject.body->getNbColliders(); ++i) { - const auto* collider = physicsObject.GetCollisionBody()->getCollider(i); + const auto* collider = physicsObject.body->getCollider(i); if (collider->getEntity() == colliderID) return i; } @@ -178,10 +178,10 @@ namespace SHADE bool matched[2] = { false, false }; - for (auto& [entityID, physicsObject] : system->GetPhysicsObjects()) + for (auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects()) { // Match body 1 - if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1) + if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.body->getEntity() == body1) { cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID; cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1); @@ -190,7 +190,7 @@ namespace SHADE } // Match body 2 - if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2) + if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.body->getEntity() == body2) { cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID; cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2); @@ -222,10 +222,10 @@ namespace SHADE bool matched[2] = { false, false }; - for (auto& [entityID, physicsObject] : system->GetPhysicsObjects()) + for (auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects()) { // Match body 1 - if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1) + if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.body->getEntity() == body1) { cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID; cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1); @@ -234,7 +234,7 @@ namespace SHADE } // Match body 2 - if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2) + if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.body->getEntity() == body2) { cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID; cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2); diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h b/SHADE_Engine/src/Physics/RP3DWrapper/SHCollisionListener.h similarity index 98% rename from SHADE_Engine/src/Physics/Collision/SHCollisionListener.h rename to SHADE_Engine/src/Physics/RP3DWrapper/SHCollisionListener.h index 62882556..6aa09fe4 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h +++ b/SHADE_Engine/src/Physics/RP3DWrapper/SHCollisionListener.h @@ -15,7 +15,7 @@ // Project Headers #include "SH_API.h" -#include "SHCollisionInfo.h" +#include "Physics/Collision/SHCollisionInfo.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/RP3DWrapper/SHPhysicsWorld.cpp similarity index 100% rename from SHADE_Engine/src/Physics/SHPhysicsWorld.cpp rename to SHADE_Engine/src/Physics/RP3DWrapper/SHPhysicsWorld.cpp diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/RP3DWrapper/SHPhysicsWorld.h similarity index 97% rename from SHADE_Engine/src/Physics/SHPhysicsWorld.h rename to SHADE_Engine/src/Physics/RP3DWrapper/SHPhysicsWorld.h index c5152c44..09a2b260 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/RP3DWrapper/SHPhysicsWorld.h @@ -13,8 +13,7 @@ #include // Project Headers -#include "Math/SHMath.h" -#include "SH_API.h" +#include "Math/Vector/SHVec3.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/RP3DWrapper/SHRaycaster.cpp b/SHADE_Engine/src/Physics/RP3DWrapper/SHRaycaster.cpp new file mode 100644 index 00000000..c420d208 --- /dev/null +++ b/SHADE_Engine/src/Physics/RP3DWrapper/SHRaycaster.cpp @@ -0,0 +1,132 @@ +/**************************************************************************************** + * \file SHPhysicsRaycaster.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Raycaster. + * + * \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 "SHRaycaster.h" + +#include "Physics/System/SHPhysicsSystem.h" + +/* + * TODO(DIREN): + * Once the physics engine has been rebuilt, this whole implementation should change + * and just call PhysicsWorld.Raycast etc. + * + * SHRaycastResult can be converted to a bool when necessary. + */ + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHRaycaster::SHRaycaster() noexcept + : system { nullptr } + , world { nullptr } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHRaycaster::BindToSystem(SHPhysicsSystem* physicsSystem) noexcept + { + system = physicsSystem; + } + + void SHRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept + { + world = physicsWorld; + } + + const SHRaycaster::RaycastResults& SHRaycaster::Raycast(const RaycastInfo& info) noexcept + { + results.clear(); + currentInfo = info; + + SHASSERT(world, "Physics World missing link with Raycaster!") + + // Clamp distance to 2km + const float DISTANCE = std::clamp(info.distance, 0.0f, SHRay::MAX_RAYCAST_DIST); + + const rp3d::Ray RP3D_RAY = { info.ray.position, info.ray.position + info.ray.direction * DISTANCE }; + world->raycast(RP3D_RAY, this, info.layers); + + // Reset + currentInfo.reset(); + + return results; + } + + rp3d::decimal SHRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) + { + SHASSERT(system, "Physics System unlinked with Raycaster!") + + SHPhysicsRaycastResult result; + + // Compare body IDs to find the matching physics object + const auto HIT_BODY_EID = raycastInfo.body->getEntity(); + + for (const auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects()) + { + // Match rp3d bodies + if (physicsObject.body->getEntity() != HIT_BODY_EID) + continue; + + // Skip ignored entity + if (currentInfo->colliderEntityID.has_value()) + if (entityID == currentInfo->colliderEntityID) + return 1.0f; + + result.entityHit = entityID; + + // Find collider index + if (const int INDEX = findColliderIndex(physicsObject.body, raycastInfo.collider->getEntity()); INDEX > -1) + { + result.shapeIndex = INDEX; + break; + } + } + + result.hit = true; + result.position = raycastInfo.worldPoint; + result.normal = raycastInfo.worldNormal; + result.distance = SHVec3::Distance(currentInfo->ray.position, result.position); + result.angle = SHVec3::Angle(currentInfo->ray.position, result.position); + + results.emplace_back(result); + + if (currentInfo->continuous) + return 1.0f; + + return 0.0f; + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + int SHRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept + { + const int NUM_COLLISION_SHAPES = static_cast(rp3dBody->getNbColliders()); + for (int i = 0; i < NUM_COLLISION_SHAPES; ++i) + { + const auto COLLIDER_EID = rp3dBody->getCollider(i)->getEntity(); + if (COLLIDER_EID == rp3dColliderEID) + return i; + } + + return -1; + } + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/RP3DWrapper/SHRaycaster.h b/SHADE_Engine/src/Physics/RP3DWrapper/SHRaycaster.h new file mode 100644 index 00000000..280ccb37 --- /dev/null +++ b/SHADE_Engine/src/Physics/RP3DWrapper/SHRaycaster.h @@ -0,0 +1,133 @@ +/**************************************************************************************** + * \file SHPhysicsRaycaster.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Raycaster. + * + * \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 + +// Project Headers +#include "Math/SHRay.h" +#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" +#include "Physics/Collision/SHPhysicsRaycastResult.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHPhysicsSystem; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHRaycaster : public reactphysics3d::RaycastCallback + { + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using RaycastResults = std::vector; + + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct RaycastInfo + { + private: + /*-------------------------------------------------------------------------------*/ + /* Friends */ + /*-------------------------------------------------------------------------------*/ + + friend class SHRaycaster; + + public: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + bool continuous = false; + uint16_t layers = static_cast(SHCollisionTag::Layer::ALL); + float distance = std::numeric_limits::infinity(); + SHRay ray; + + /*-------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*-------------------------------------------------------------------------------*/ + + /** + * @brief + * Sets the collider ID for the raycast. Setting this specifies that the ray + * should ignore this collider. + * @param eid + * The entity ID of the collider. + */ + void SetColliderID(EntityID eid) noexcept { colliderEntityID = eid; } + + private: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + std::optional colliderEntityID; + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHRaycaster() noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept; + void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept; + + rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override; + + /** + * @brief + * Casts a ray into the physics world. + * @param info + * Contains the information for the raycast. + * @return + * A container of the objects hit by the ray. If nothing was hit, the container + * will be empty. + */ + [[nodiscard]] const RaycastResults& Raycast(const RaycastInfo& info) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsSystem* system; + rp3d::PhysicsWorld* world; + RaycastResults results; // Holds the temporary result after casting into the world + std::optional currentInfo; // Hold the state of the current raycast. + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept; + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsEvents.h b/SHADE_Engine/src/Physics/SHPhysicsEvents.h index ae48a75b..a192ec3f 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsEvents.h +++ b/SHADE_Engine/src/Physics/SHPhysicsEvents.h @@ -11,8 +11,7 @@ #pragma once // Project Headers -#include "Interface/SHCollisionShape.h" - +#include "Collision/Shapes/SHCollisionShape.h" namespace SHADE { @@ -28,9 +27,16 @@ namespace SHADE }; struct SHPhysicsColliderRemovedEvent + { + EntityID entityID; + SHCollisionShape::Type colliderType; + int colliderIndex; + }; + + struct SHColliderOnDebugDrawEvent { EntityID entityID; - int colliderIndex; + bool debugDrawState; }; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp new file mode 100644 index 00000000..469e835d --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -0,0 +1,113 @@ +/**************************************************************************************** + * \file SHPhysicsDebugDrawRutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Debut Draw Routine + * + * \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 "Physics/System/SHPhysicsDebugDrawSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Physics/System/SHPhysicsSystem.h" +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsDebugDrawSystem::PhysicsDebugDraw::PhysicsDebugDraw() + : SHSystemRoutine { "Physics Debug-Draw", true } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsDebugDrawSystem::PhysicsDebugDraw::Execute(double) noexcept + { + auto* physicsDebugDrawSystem = reinterpret_cast(GetSystem()); + + if (!physicsDebugDrawSystem->IsDebugDrawActive()) + return; + + auto* debugDrawSystem = SHSystemManager::GetSystem(); + + const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS); + const bool DRAW_CONTACTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::CONTACTS); + const bool DRAW_RAYCASTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::RAYCASTS); +\ + // If draw all colliders is active, get all colliders from the dense set and draw. + // Else we check if any colliders have been flagged for drawing. + if (DRAW_COLLIDERS) + { + const auto& COLLIDER_COMPONENT_DENSE = SHComponentManager::GetDense(); + for (const auto& COLLIDER_COMPONENT : COLLIDER_COMPONENT_DENSE) + drawCollider(debugDrawSystem, COLLIDER_COMPONENT); + } + else if (!physicsDebugDrawSystem->collidersToDraw.empty()) + { + for (const auto EID : physicsDebugDrawSystem->collidersToDraw) + drawCollider(debugDrawSystem, *SHComponentManager::GetComponent(EID)); + } + + auto* physicsSystem = SHSystemManager::GetSystem(); + if (!physicsSystem) + return; + + rp3d::DebugRenderer* rp3dRenderer = nullptr; + if (physicsSystem->worldState.world) + rp3dRenderer = &physicsSystem->worldState.world->getDebugRenderer(); + + // No world exists, nothing else to be drawn + if (!rp3dRenderer) + return; + + rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, DRAW_CONTACTS); + rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, DRAW_CONTACTS); + + if (DRAW_CONTACTS) + { + const SHColour& CONTACT_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)]; + + const int NUM_TRIS = static_cast(rp3dRenderer->getNbTriangles()); + if (NUM_TRIS == 0) // No contact points + return; + + // Draw contacts + const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray(); + for (int i = 0; i < NUM_TRIS; ++i) + debugDrawSystem->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, CONTACT_COLOUR, true); + + // Draw normals + const int NUM_LINES = static_cast(rp3dRenderer->getNbLines()); + + const auto& LINE_ARRAY = rp3dRenderer->getLinesArray(); + for (int i = 0; i < NUM_LINES; ++i) + debugDrawSystem->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, CONTACT_COLOUR, true); + } + + if (DRAW_RAYCASTS) + { + const SHColour& RAY_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)]; + + const auto& RAYS = physicsSystem->raycastHits; + for (const auto& hit : RAYS) + debugDrawSystem->DrawLine(hit.start, hit.end, RAY_COLOUR, true); + + // Clear rays for the physics system + physicsSystem->raycastHits.clear(); + } + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp new file mode 100644 index 00000000..5f97daaf --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -0,0 +1,120 @@ +/**************************************************************************************** + * \file SHPhysicsPostUpdateRoutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Post-Update Routine + * + * \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 "Physics/System/SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneManager.h" +#include "Scripting/SHScriptEngine.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate() + : SHSystemRoutine { "Physics Post-Update", false } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + 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!"); + } + + const float FACTOR = static_cast(physicsSystem->interpolationFactor); + + // Interpolate transforms for rendering. + // Only rigid bodies can move due to physics, so we run through the rigid body component dense set. + if (physicsSystem->worldUpdated) + { + for (auto& [entityID, physicsObject] : physicsSystem->objectManager.GetPhysicsObjects()) + { + // Skip missing transforms + auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + if (!transformComponent) + continue; + + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); + + // Skip invalid bodies (Should not occur) + if (!rigidBodyComponent || !rigidBodyComponent->rigidBody) + continue; + + // Skip inactive bodies + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + if (!IS_ACTIVE || rigidBodyComponent->type == SHRigidBodyComponent::Type::STATIC) + continue; + + const rp3d::Transform& CURRENT_TF = physicsObject.body->getTransform(); + + if (rigidBodyComponent->IsInterpolating()) + { + const rp3d::Transform PREV_TF + { + rigidBodyComponent->position + , rigidBodyComponent->orientation + }; + + const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast(FACTOR)); + + const SHVec3 RENDER_POSITION = INTERPOLATED_TF.getPosition(); + const SHQuaternion RENDER_ORIENTATION = INTERPOLATED_TF.getOrientation(); + + transformComponent->SetWorldPosition(RENDER_POSITION); + transformComponent->SetWorldOrientation(RENDER_ORIENTATION); + } + else + { + transformComponent->SetWorldPosition(CURRENT_TF.getPosition()); + transformComponent->SetWorldOrientation(CURRENT_TF.getOrientation()); + } + + rigidBodyComponent->position = CURRENT_TF.getPosition(); + rigidBodyComponent->orientation = CURRENT_TF.getOrientation(); + + // Set colliders transform if exists + if (auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); colliderComponent) + { + colliderComponent->transform.position = CURRENT_TF.getPosition(); + colliderComponent->transform.orientation = CURRENT_TF.getOrientation(); + } + + /* + * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. + */ + } + + // Since this function never runs when editor in not in play, execute the function anyway + physicsSystem->collisionListener.CleanContainers(); + } + + + + // Collision & Trigger messages + if (scriptingSystem != nullptr) + scriptingSystem->ExecuteCollisionFunctions(); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp new file mode 100644 index 00000000..3a085dd0 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -0,0 +1,95 @@ +/**************************************************************************************** + * \file SHPhysicsPreUpdateRoutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Pre-Update Routine + * + * \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 "Physics/System/SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneManager.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate() + : SHSystemRoutine { "Physics Pre-Update", true } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept + { + auto* physicsSystem = reinterpret_cast(GetSystem()); + + // Get all physics objects & sync transforms + auto& physicsObjects = physicsSystem->objectManager.GetPhysicsObjects(); + for (auto& [entityID, physicsObject] : physicsObjects) + { + const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); + // Assume transform is always active + const bool UPDATE_TRANSFORM = TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged(); + + if (!UPDATE_TRANSFORM) + continue; + + // We assume that all engine components and physics object components have been successfully linked + + if (!physicsObject.body) + continue; + + // Set body transform + const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); + + const rp3d::Transform NEW_TRANSFORM{ WORLD_POS, WORLD_ROT }; + physicsObject.body->setTransform(NEW_TRANSFORM); + + // Sync rigid body active states if one exists + if (auto* shadeBody = SHComponentManager::GetComponent_s(entityID); shadeBody) + { + const bool SHADE_BODY_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + const bool RP3D_BODY_ACTIVE = physicsObject.body->isActive(); + + if (SHADE_BODY_ACTIVE != RP3D_BODY_ACTIVE) + physicsObject.body->setIsActive(SHADE_BODY_ACTIVE); + + shadeBody->position = WORLD_POS; + shadeBody->orientation = WORLD_ROT; + } + + // Sync collider active states if one exists + if (auto* shadeCollider = SHComponentManager::GetComponent_s(entityID); shadeCollider) + { + const bool SHADE_COLLIDER_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + const bool RP3D_COLLIDERS_ACTIVE = shadeCollider->flags & SHColliderComponent::ACTIVE_FLAG; + + // Modify the static body's active state + // The collision listener & raycaster will handle culling inactive colliders. + if (SHADE_COLLIDER_ACTIVE != RP3D_COLLIDERS_ACTIVE) + physicsObject.body->setIsActive(SHADE_COLLIDER_ACTIVE); + + shadeCollider->transform.position = WORLD_POS; + shadeCollider->transform.orientation = WORLD_ROT; + shadeCollider->transform.scale = TRANSFORM_COMPONENT->GetWorldScale(); + + shadeCollider->Update(); + } + } + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp new file mode 100644 index 00000000..d4f6d623 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp @@ -0,0 +1,66 @@ +/**************************************************************************************** + * \file SHPhysicsUpdateRoutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Update Routine + * + * \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 "Physics/System/SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Scripting/SHScriptEngine.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::PhysicsUpdate::PhysicsUpdate() + : SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics Update", false } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::PhysicsUpdate::Execute(double dt) noexcept + { + auto* physicsSystem = reinterpret_cast(GetSystem()); + + auto* scriptEngine = SHSystemManager::GetSystem(); + if (!scriptEngine) + { + SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing ScriptEngine!") + } + + const double FIXED_DT = physicsSystem->fixedDT; + accumulatedTime += dt; + + int count = 0; + while (accumulatedTime > FIXED_DT) + { + if (scriptEngine) + scriptEngine->ExecuteFixedUpdates(); + + if (physicsSystem->worldState.world) + physicsSystem->worldState.world->update(static_cast(FIXED_DT)); + + accumulatedTime -= FIXED_DT; + ++count; + } + + stats.numSteps = count; + physicsSystem->worldUpdated = count > 0; + + physicsSystem->interpolationFactor = physicsSystem->worldUpdated ? accumulatedTime / FIXED_DT : 0.0; + } + +} // 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 index 96af5e39..226ba2f9 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -13,79 +13,59 @@ // Primary Header #include "SHPhysicsDebugDrawSystem.h" -// Project Headers +// Project Header #include "ECS_Base/Managers/SHSystemManager.h" -#include "Editor/SHEditor.h" -#include "Scene/SHSceneManager.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Physics/SHPhysicsEvents.h" +#include "Tools/Utilities/SHUtilities.h" namespace SHADE { - /*-----------------------------------------------------------------------------------*/ - /* Static Data Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[NUM_FLAGS] = + const SHColour SHPhysicsDebugDrawSystem::DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::COUNT)] { - drawColliders - , drawColliderAABBs - , drawBroadPhaseAABBs - , drawContactPoints - , drawContactNormals - , drawRaycasts + SHColour::GREEN // Colliders + , SHColour::PURPLE // Triggers + , SHColour::RED // Contacts + , SHColour::ORANGE // Raycasts }; - SHVec3 SHPhysicsDebugDrawSystem::boxVertices[NUM_BOX_VERTICES]; - /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept - : debugDrawFlags { 0 } - , physicsSystem { nullptr } + : flags { 0 } { - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER)] = SHColour::GREEN; - 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; - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::RAYCASTS)] = SHColour::ORANGE; + collidersToDraw.clear(); } - SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine() - : SHSystemRoutine { "Physics Debug Draw", true } - {} - /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept + bool SHPhysicsDebugDrawSystem::IsDebugDrawActive() 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 flags & ACTIVE_FLAG; + } - return debugDrawFlags & 1U << SHUtilities::ConvertEnum(flag); + bool SHPhysicsDebugDrawSystem::GetFlagState(DebugDrawFlags flag) const noexcept + { + const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); + return flags & ENUM_VALUE; } /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept + void SHPhysicsDebugDrawSystem::SetFlagState(DebugDrawFlags flag, bool state) 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; - } + const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); + state ? flags |= ENUM_VALUE : flags &= ~ENUM_VALUE; - value ? (debugDrawFlags |= 1U << INT_FLAG) : (debugDrawFlags &= ~(1U << INT_FLAG)); + // If no other debug drawing state is active, turn active off. Otherwise, we maintain + // the active state. + flags == ACTIVE_FLAG ? flags = 0 : flags |= ACTIVE_FLAG; } /*-----------------------------------------------------------------------------------*/ @@ -96,240 +76,76 @@ namespace SHADE { SystemFamily::GetID(); - SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!") - physicsSystem = SHSystemManager::GetSystem(); + // Register collider draw event + const std::shared_ptr EVENT_RECEIVER = std::make_shared>(this, &SHPhysicsDebugDrawSystem::onColliderDraw); + const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast(EVENT_RECEIVER); - // Generate shapes - generateBox(); + //SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_DRAW_EVENT, EVENT_RECEIVER_PTR); } void SHPhysicsDebugDrawSystem::Exit() { - physicsSystem = nullptr; + } - void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept + void SHPhysicsDebugDrawSystem::AddRaycast(const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept { - auto* system = reinterpret_cast(GetSystem()); - - auto* debugDrawSystem = SHSystemManager::GetSystem(); - if (debugDrawSystem == nullptr) - { - SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") - return; - } - - rp3d::DebugRenderer* rp3dRenderer = nullptr; - if (system->physicsSystem->worldState.world) - rp3dRenderer = &system->physicsSystem->worldState.world->getDebugRenderer(); - - for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i) - { - const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0; - if (DRAW) - { - drawFunctions[i](debugDrawSystem, rp3dRenderer); - } - else - { - if (rp3dRenderer && (i == 3 || i == 4)) - { - rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_POINT, false); - rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_NORMAL, false); - } - } - - } - - // Automatically clear the container of raycasts despite debug drawing state - // TODO(Diren): Move this somewhere else - system->physicsSystem->raycaster.ClearFrame(); + } /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsDebugDrawSystem::drawColliders(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept + SHEventHandle SHPhysicsDebugDrawSystem::onColliderDraw(SHEventPtr onColliderDrawEvent) { - const auto& COLLIDER_SET = SHComponentManager::GetDense(); - for (const auto& COLLIDER : COLLIDER_SET) - { - // Skip inactive colliders - if (!SHSceneManager::CheckNodeAndComponentsActive(COLLIDER.GetEID())) - continue; + const auto& EVENT_DATA = reinterpret_cast*>(onColliderDrawEvent.get())->data; - for (auto& collisionShape : COLLIDER.GetCollisionShapes()) + // Add to the container to draw all colliders + if (EVENT_DATA->debugDrawState) + { + if (collidersToDraw.empty()) + flags |= ACTIVE_FLAG; + + collidersToDraw.emplace(EVENT_DATA->entityID); + } + else + { + collidersToDraw.erase(EVENT_DATA->entityID); + + // if no colliders queued for drawing and no other debug drawing is enabled, disable debug drawing + if (collidersToDraw.empty() && flags == ACTIVE_FLAG) + flags = 0; + } + + return onColliderDrawEvent.get()->handle; + } + + void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHColliderComponent& collider) noexcept + { + for (const auto& SHAPE : collider.GetCollisionShapes()) + { + const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(SHAPE->IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)]; + + switch (SHAPE->GetType()) { - switch (collisionShape.GetType()) + case SHCollisionShape::Type::SPHERE: { - case SHCollisionShape::Type::BOX: debugDrawBox(debugRenderer, COLLIDER, collisionShape); break; - case SHCollisionShape::Type::SPHERE: debugDrawSphere(debugRenderer, COLLIDER, collisionShape); break; - default: break; + debugDrawSystem->DrawWireSphere(SHAPE->GetTRS(), DRAW_COLOUR, true); + break; } + case SHCollisionShape::Type::BOX: + { + debugDrawSystem->DrawWireCube(SHAPE->GetTRS(), DRAW_COLOUR, true); + break; + } + //case SHCollisionShape::Type::CAPSULE: + //{ + // break; + //} + default: break; } } } - void SHPhysicsDebugDrawSystem::drawColliderAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - - } - - void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - - } - - void SHPhysicsDebugDrawSystem::drawContactPoints(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - #ifdef SHEDITOR - - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - { - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true); - const int NUM_TRIS = static_cast(rp3dRenderer->getNbTriangles()); - if (NUM_TRIS == 0) - return; - - const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray(); - for (int i = 0; i < NUM_TRIS; ++i) - debugRenderer->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, SHColour::RED); - } - - #else - - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true); - const int NUM_TRIS = static_cast(rp3dRenderer->getNbTriangles()); - if (NUM_TRIS == 0) - return; - - const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray(); - for (int i = 0; i < NUM_TRIS; ++i) - debugRenderer->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, SHColour::RED); - - #endif - } - - void SHPhysicsDebugDrawSystem::drawContactNormals(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - #ifdef SHEDITOR - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - { - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true); - const int NUM_LINES = static_cast(rp3dRenderer->getNbLines()); - if (NUM_LINES == 0) - return; - - const auto& LINE_ARRAY = rp3dRenderer->getLinesArray(); - for (int i = 0; i < NUM_LINES; ++i) - debugRenderer->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, SHColour::RED); - } - - #else - - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true); - const int NUM_LINES = static_cast(rp3dRenderer->getNbLines()); - if (NUM_LINES == 0) - return; - - const auto& LINE_ARRAY = rp3dRenderer->getLinesArray(); - for (int i = 0; i < NUM_LINES; ++i) - debugRenderer->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, SHColour::RED); - - #endif - } - - void SHPhysicsDebugDrawSystem::drawRaycasts(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOG_ERROR("Unable to retrieve physics system for debug drawing raycasts!") - return; - } - - const SHColour& RAY_COLOUR = SHColour::ORANGE; - - // Draw all raycast pairs - for (const auto& [ray, raycastResult] : physicsSystem->raycaster.GetRaycasts()) - { - // If infinity, it is an infinite raycast. If not, render the distance in raycastResult. - // Ignore the hit variable as it will always correspond to the length of the raycast, hit or miss. - const float RENDER_DIST = raycastResult.distance == std::numeric_limits::infinity() ? SHRay::MAX_RAYCAST_DIST : raycastResult.distance; - const SHVec3 END_POS = ray.position + (ray.direction * RENDER_DIST); - - debugRenderer->DrawLine(ray.position, END_POS, RAY_COLOUR); - } - } - - - void SHPhysicsDebugDrawSystem::generateBox() noexcept - { - boxVertices[0] = { 0.5f, 0.5f, -0.5f }; // TOP_RIGHT_BACK - boxVertices[1] = { -0.5f, 0.5f, -0.5f }; // TOP_LEFT_BACK - boxVertices[2] = { 0.5f, -0.5f, -0.5f }; // BTM_RIGHT_BACK - boxVertices[3] = { -0.5f, -0.5f, -0.5f }; // BTM_LEFT_BACK - boxVertices[4] = { 0.5f, 0.5f, 0.5f }; // TOP_RIGHT_FRONT - boxVertices[5] = { -0.5f, 0.5f, 0.5f }; // TOP_LEFT_FRONT - boxVertices[6] = { 0.5f, -0.5f, 0.5f }; // BTM_RIGHT_FRONT - boxVertices[7] = { -0.5f, -0.5f, 0.5f }; // BTM_LEFT_FRONT - } - - void SHPhysicsDebugDrawSystem::debugDrawBox(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept - { - auto* BOX = reinterpret_cast(collisionShape.GetShape()); - - // Calculate final position & orientation - const SHVec3 COLLIDER_POS = colliderComponent.GetPosition(); - const SHVec3 BOX_POS = collisionShape.GetPositionOffset(); - const SHQuaternion COLLIDER_ROT = colliderComponent.GetOrientation(); - const SHQuaternion BOX_ROT = SHQuaternion::FromEuler(collisionShape.GetRotationOffset()); - - - const SHMatrix COLLIDER_TR = SHMatrix::Rotate(COLLIDER_ROT) * SHMatrix::Translate(COLLIDER_POS); - const SHMatrix BOX_TRS = SHMatrix::Scale(BOX->GetWorldExtents() * 2.0f) * SHMatrix::Rotate(BOX_ROT) * SHMatrix::Translate(BOX_POS); - - const SHMatrix FINAL_TRS = BOX_TRS * COLLIDER_TR; - - 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], FINAL_TRS); - transformedVertices[IDX2] = SHVec3::Transform(boxVertices[IDX2], FINAL_TRS); - - // Draw 4 line to connect the quads - debugRenderer->DrawLine(transformedVertices[IDX1], transformedVertices[IDX2], COLLIDER_COLOUR); - } - - // A, B, C, D - std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] }; - debugRenderer->DrawLineLoop(backQuad.begin(), backQuad.end(), COLLIDER_COLOUR); - - // E, F, G, H - std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] }; - debugRenderer->DrawLineLoop(frontQuad.begin(), frontQuad.end(), COLLIDER_COLOUR); - } - - void SHPhysicsDebugDrawSystem::debugDrawSphere(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept - { - auto* SPHERE = reinterpret_cast(collisionShape.GetShape()); - - const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN; - - // Calculate final position & orientation - const SHQuaternion FINAL_ROT = colliderComponent.GetOrientation() * SHQuaternion::FromEuler(collisionShape.GetRotationOffset()); - const SHMatrix TR = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(colliderComponent.GetPosition()); - - /* #KWFix */ - //debugRenderer->DrawSphere(COLLIDER_COLOUR, SHVec3::Transform(collisionShape.GetPositionOffset(), TR), 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 index dc703092..8c2c9b78 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -10,14 +10,16 @@ #pragma once -#include +#include // Project Headers +#include "ECS_Base/Entity/SHEntity.h" +#include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystemRoutine.h" +#include "Events/SHEvent.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" -#include "Math/SHColour.h" -#include "SHPhysicsSystem.h" -#include "Tools/Utilities/SHUtilities.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Collision/SHPhysicsRaycastResult.h" namespace SHADE { @@ -28,63 +30,54 @@ namespace SHADE class SH_API SHPhysicsDebugDrawSystem final : public SHSystem { public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - enum class DebugDrawFlags + enum class DebugDrawFlags : uint8_t { - COLLIDER - , COLLIDER_AABB - , BROAD_PHASE_AABB - , CONTACT_POINTS - , CONTACT_NORMALS - , RAYCASTS - - , NUM_FLAGS + COLLIDERS = 0x02 + , CONTACTS = 0x04 + , RAYCASTS = 0x08 }; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHPhysicsDebugDrawSystem() noexcept; + SHPhysicsDebugDrawSystem () noexcept; + ~SHPhysicsDebugDrawSystem() noexcept = default; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept; - + [[nodiscard]] bool IsDebugDrawActive () const noexcept; + [[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept; + void SetFlagState (DebugDrawFlags flag, bool state) noexcept; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Member Functions */ /*---------------------------------------------------------------------------------*/ - void Init() override; - void Exit() override; + void Init () override; + void Exit () override; + + void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept; /*---------------------------------------------------------------------------------*/ /* System Routines */ /*---------------------------------------------------------------------------------*/ - class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine + /** + * @brief + * If the editor is enabled, this routine invokes debug drawing for colliders and collision information. + */ + class SH_API PhysicsDebugDraw final : public SHSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - - PhysicsDebugDrawRoutine(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ + PhysicsDebugDraw(); void Execute(double dt) noexcept override; }; @@ -93,46 +86,58 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using DebugDrawFunction = void(*)(SHDebugDrawSystem*, rp3d::DebugRenderer*) noexcept; + union DebugDrawInfo + { + struct Contact + { + SHVec3 worldPos; + SHVec3 normal; + } contact; + + struct Raycast + { + SHVec3 start; + SHVec3 end; + } raycast; + }; + + using Colliders = std::unordered_set; + using Raycasts = std::vector; + using Contacts = std::vector; + + enum class Colours + { + COLLIDER + , TRIGGER + , CONTACT + , RAYCAST + + , COUNT + }; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); - static const DebugDrawFunction drawFunctions[NUM_FLAGS]; + static constexpr uint8_t ACTIVE_FLAG = 0x01; - // SHAPES INFO + static const SHColour DEBUG_DRAW_COLOURS[static_cast(Colours::COUNT)]; - static constexpr size_t NUM_BOX_VERTICES = 8; - static SHVec3 boxVertices[NUM_BOX_VERTICES]; + // 0 0 0 drawBroadphase drawRaycasts drawContacts drawAllColliders debugDrawActive + uint8_t flags; + + Colliders collidersToDraw; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); + + static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHColliderComponent& collider) noexcept; + static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; - - uint8_t debugDrawFlags; - SHPhysicsSystem* physicsSystem; - SHColour debugColours[NUM_FLAGS]; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - // Generic Draw Functions - - static void drawColliders (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawColliderAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawBroadPhaseAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawContactPoints (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawContactNormals (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawRaycasts (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - - // Shape Generation Functions - - static void generateBox () noexcept; - - // Shape Draw Functions - - static void debugDrawBox (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; - static void debugDrawSphere (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; }; -} // namespace SHADE + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 768c9b77..22a51c41 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -19,8 +19,9 @@ #include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" -#include "Physics/SHPhysicsEvents.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" #include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" @@ -30,11 +31,23 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsSystem::SHPhysicsSystem() + SHPhysicsSystem::SHPhysicsSystem() noexcept : worldUpdated { false } , interpolationFactor { 0.0 } , fixedDT { DEFAULT_FIXED_STEP } - {} + { + // Add more events here to register them + + eventFunctions[0] = { &SHPhysicsSystem::onComponentAdded , SH_COMPONENT_ADDED_EVENT }; + eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT }; + eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST }; + eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST }; + } + + SHPhysicsSystem::~SHPhysicsSystem() + { + worldState.DestroyWorld(factory); + } /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ @@ -45,9 +58,9 @@ namespace SHADE return 1.0 / fixedDT; } - const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept + double SHPhysicsSystem::GetFixedDT() const noexcept { - return worldState.settings; + return fixedDT; } const std::vector& SHPhysicsSystem::GetAllCollisionInfo() const noexcept @@ -60,30 +73,43 @@ namespace SHADE return collisionListener.GetTriggerInfoContainer(); } - const SHPhysicsObject* SHPhysicsSystem::GetPhysicsObject(EntityID eid) noexcept - { - return objectManager.GetPhysicsObject(eid); - } - - - const SHPhysicsObjectManager::PhysicsObjectEntityMap& SHPhysicsSystem::GetPhysicsObjects() const noexcept - { - return objectManager.physicsObjects; - } - /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept { + // Handle invalid input + if (fixedUpdateRate <= 0.0) + { + SHLOGV_WARNING("Invalid value for setting fixed update rate! Fixed update rate unchanged.") + return; + } + fixedDT = 1.0 / fixedUpdateRate; + + // Handle potential incorrect / unintended input + if (fixedDT > 1.0) + { + SHLOGV_WARNING("Fixed Update Rate Time is set below 1. This may result in undesirable behaviour.") + } } - void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept + void SHPhysicsSystem::SetFixedDT(double fixedDt) noexcept { - worldState.settings = settings; - worldState.UpdateSettings(); + if (fixedDt <= 0.0) + { + SHLOGV_WARNING("Invalid value for setting fixed delta time! Fixed delta time unchanged.") + return; + } + + fixedDT = fixedDt; + + // Handle potential incorrect / unintended input + if (fixedDT > 1.0) + { + SHLOGV_WARNING("Fixed Delta Time is set above 1. This may result in undesirable behaviour.") + } } /*-----------------------------------------------------------------------------------*/ @@ -92,40 +118,23 @@ namespace SHADE void SHPhysicsSystem::Init() { + // TODO(Diren): Consider using a non-static collision tag matrix. // Initialise collision tags std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath); - // Link Physics Object Manager with System & Raycaster - objectManager.SetFactory(factory); - raycaster.SetObjectManager(&objectManager); + // Register Events + for (int i = 0; i < NUM_EVENT_FUNCTIONS; ++i) + { + const std::shared_ptr EVENT_RECEIVER = std::make_shared>(this, eventFunctions[i].first); + const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast(EVENT_RECEIVER); - // Link Collision Listener with System - collisionListener.BindToSystem(this); + SHEventManager::SubscribeTo(eventFunctions[i].second, EVENT_RECEIVER_PTR); + } - // 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 - + objectManager.SetFactory(&factory); + raycaster.BindToSystem(this); } void SHPhysicsSystem::Exit() @@ -138,344 +147,165 @@ namespace SHADE SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath); } - void SHPhysicsSystem::BuildScene(SHSceneGraph& sceneGraph) + const std::vector& SHPhysicsSystem::Raycast(const SHRaycaster::RaycastInfo& info) noexcept { - static const auto BUILD_NEW_SCENE_PHYSICS_OBJECT = [&](SHSceneNode* node) - { - const EntityID EID = node->GetEntityID(); + auto& results = raycaster.Raycast(info); - if (SHComponentManager::HasComponent(EID)) - objectManager.AddRigidBody(EID); + // Load start and end points into the container for debug drawing + #ifdef SHEDITOR - if (SHComponentManager::HasComponent(EID)) - { - objectManager.AddCollider(EID); + SHVec3 endPos = info.ray.position + info.ray.direction * SHRay::MAX_RAYCAST_DIST; - auto* COLLIDER = SHComponentManager::GetComponent(EID); - for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i) - objectManager.AddCollisionShape(EID, i); - } + if (!results.empty()) + endPos = results.back().position; - }; + raycastHits.emplace_back(info.ray.position, endPos); + + #endif - //////////////////////////////// - - // Destroy an existing world - if (worldState.world != nullptr) - { - objectManager.RemoveAllObjects(); - objectManager.SetWorld(nullptr); - - collisionListener.ClearContainers(); - raycaster.ClearFrame(); - - worldState.DestroyWorld(factory); - } - - worldState.CreateWorld(factory); -#ifdef _PUBLISH - worldState.world->setIsDebugRenderingEnabled(false); -#else - worldState.world->setIsDebugRenderingEnabled(true); -#endif - - // Link Collision Listener & Raycaster - collisionListener.BindToWorld(worldState.world); - raycaster.BindToWorld(worldState.world); - - // Link with object manager & create all physics objects - objectManager.SetWorld(worldState.world); - - // When building a scene, clear the object manager command queue and build scene objects again. - // This is done to avoid duplicate adds. - while (!objectManager.commandQueue.empty()) - objectManager.commandQueue.pop(); - - sceneGraph.Traverse(BUILD_NEW_SCENE_PHYSICS_OBJECT); - objectManager.UpdateCommands(); + return results; } - void SHPhysicsSystem::ForceBuild(SHSceneGraph& sceneGraph) - { - // HACK: Band-aid fix. To be removed. - objectManager.UpdateCommands(); - } - - - void SHPhysicsSystem::ForceUpdate() - { - if (!worldState.world) - { - SHLOGV_ERROR("Unable to force update without a Physics world!") - return; - } - - auto* scriptingSystem = SHSystemManager::GetSystem(); - if (scriptingSystem == nullptr) - { - SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); - } - - // Force the physics world to update once - if (scriptingSystem != nullptr) - scriptingSystem->ExecuteFixedUpdates(); - - worldState.world->update(static_cast(fixedDT)); - - // Sync transforms. No interpolation applied here - for (auto& [entityID, physicsObject] : objectManager.physicsObjects) - { - auto* transformComponent = SHComponentManager::GetComponent_s(entityID); - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); - - const auto& CURRENT_TF = physicsObject.GetRigidBody()->getTransform(); - const auto& RENDER_POS = CURRENT_TF.getPosition(); - const auto& RENDER_ROT = CURRENT_TF.getOrientation(); - - // Cache transform - physicsObject.prevTransform = CURRENT_TF; - - // Sync with physics components - if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive(entityID)) - { - rigidBodyComponent->position = RENDER_POS; - rigidBodyComponent->orientation = RENDER_ROT; - } - - if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive(entityID)) - { - colliderComponent->position = RENDER_POS; - colliderComponent->orientation = RENDER_ROT; - } - - // Set transform for rendering - if (transformComponent) - { - transformComponent->SetWorldPosition(RENDER_POS); - transformComponent->SetWorldOrientation(RENDER_ROT); - } - } - } - - SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept - { - return raycaster.Raycast(ray, distance, collisionTag); - } - - SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept - { - return raycaster.Linecast(start, end, collisionTag); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept - { - return raycaster.ColliderRaycast(eid, ray, distance); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept - { - return raycaster.ColliderRaycast(eid, shapeIndex, ray, distance); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept - { - return raycaster.ColliderLinecast(eid, start, end); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept - { - return raycaster.ColliderLinecast(eid, shapeIndex, start, end); - } - - void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex) - { - static const auto ADD_SHAPE = [&](EntityID entityID, int index) - { - objectManager.AddCollisionShape(entityID, index); - - auto* colliderComponent = SHComponentManager::GetComponent(entityID); - auto& collisionShape = colliderComponent->GetCollisionShape(index); - - const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA - { - .entityID = entityID - , .colliderType = collisionShape.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 - } /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept + SHEventHandle SHPhysicsSystem::onSceneInit(SHEventPtr onSceneInitEvent) { - const auto& EVENT_DATA = reinterpret_cast*>(addComponentEvent.get()); + /* + * If a world already exists, destroy it + * Recreate the world. + * + * If there is an editor and editor mode is already playing, link all entities with the world immediately. + */ - 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) + // Destroy an existing world if there is one. + //! This should almost never happen. + if (worldState.world) { - 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)) + // Remove all references of physics objects from the world + for (const auto& PHYSICS_OBJECT : objectManager.GetPhysicsObjects() | std::views::values) { - objectManager.AddCollider(EID); + if (PHYSICS_OBJECT.body) + { + // Remove all colliders and destroy world + int32_t numShapes = static_cast(PHYSICS_OBJECT.body->getNbColliders()); + while (--numShapes >= 0) + { + auto* rp3dCollider = PHYSICS_OBJECT.body->getCollider(numShapes); + PHYSICS_OBJECT.body->removeCollider(rp3dCollider); + } - auto* COLLIDER = SHComponentManager::GetComponent(EID); - for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i) - objectManager.AddCollisionShape(EID, i); + worldState.world->destroyRigidBody(PHYSICS_OBJECT.body); + } } - }; - //////////////////////////////// - - // Create physics world - if (worldState.world != nullptr) - return onPlayEvent->handle; + worldState.DestroyWorld(factory); + } + // Create the physics world & collision space worldState.CreateWorld(factory); -#ifdef _PUBLISH - worldState.world->setIsDebugRenderingEnabled(false); -#else - worldState.world->setIsDebugRenderingEnabled(true); -#endif - // Link Collision Listener & Raycaster + // Link with managers + objectManager.SetPhysicsWorld(worldState.world); + objectManager.FlushDefinitions(); + collisionListener.BindToWorld(worldState.world); - raycaster.BindToWorld(worldState.world); - // Link with object manager & create all physics objects - objectManager.SetWorld(worldState.world); - - // Build scene - SHSceneManager::GetCurrentSceneGraph().Traverse(BUILD_PHYSICS_OBJECT); - objectManager.UpdateCommands(); - - return onPlayEvent->handle; + return onSceneInitEvent.get()->handle; } - SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent) + SHEventHandle SHPhysicsSystem::onSceneExit(SHEventPtr onSceneExitEvent) { - // Remove all physics objects - objectManager.RemoveAllObjects(); - objectManager.SetWorld(nullptr); + /* + * Destroy the physics world. + * Destroy all physics objects. + */ - // Clear all collision info - // Collision listener is automatically unbound when world is destroyed - collisionListener.ClearContainers(); - raycaster.ClearFrame(); + if (worldState.world) + { + // Remove all references of physics objects from the world + for (const auto& PHYSICS_OBJECT : objectManager.GetPhysicsObjects() | std::views::values) + { + if (PHYSICS_OBJECT.body) + worldState.world->destroyRigidBody(PHYSICS_OBJECT.body); + } - // Destroy the world - worldState.DestroyWorld(factory); + worldState.DestroyWorld(factory); + } - return onStopEvent->handle; + // Unlink with managers + objectManager.SetPhysicsWorld(nullptr); + + return onSceneExitEvent.get()->handle; } + + SHEventHandle SHPhysicsSystem::onComponentAdded(SHEventPtr onComponentAddedEvent) + { + static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID(); + static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID(); + + const auto& EVENT_DATA = reinterpret_cast*>(onComponentAddedEvent.get())->data; + + const auto ADDED_ID = EVENT_DATA->addedComponentType; + + const bool IS_RIGID_BODY = ADDED_ID == RIGID_BODY_COMPONENT_ID; + const bool IS_COLLIDER = ADDED_ID == COLLIDER_COMPONENT_ID; + + // Check if its a physics component + const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER; + if (!IS_PHYSICS_COMPONENT) + return onComponentAddedEvent.get()->handle; + + const EntityID EID = EVENT_DATA->eid; + + // Link engine components with physics object component + if (IS_RIGID_BODY) + { + if (worldState.world) + objectManager.AddRigidBody(EID); + else + objectManager.AddRigidBodyDef(EID); + } + + if (IS_COLLIDER) + { + if (worldState.world) + objectManager.AddCollider(EID); + else + objectManager.AddColliderDef(EID); + } + + return onComponentAddedEvent.get()->handle; + } + + SHEventHandle SHPhysicsSystem::onComponentRemoved(SHEventPtr onComponentRemovedEvent) + { + static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID(); + static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID(); + + const auto& EVENT_DATA = reinterpret_cast*>(onComponentRemovedEvent.get())->data; + + const auto REMOVED_DATA = EVENT_DATA->removedComponentType; + + const bool IS_RIGID_BODY = REMOVED_DATA == RIGID_BODY_COMPONENT_ID; + const bool IS_COLLIDER = REMOVED_DATA == COLLIDER_COMPONENT_ID; + + // Check if its a physics component + const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER; + if (!IS_PHYSICS_COMPONENT) + return onComponentRemovedEvent.get()->handle; + + const EntityID EID = EVENT_DATA->eid; + + if (IS_RIGID_BODY) + objectManager.RemoveRigidBody(EID); + + if (IS_COLLIDER) + objectManager.RemoveCollider(EID); + + return onComponentRemovedEvent.get()->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 index 99db493e..312c3625 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -10,8 +10,7 @@ #pragma once -#include -#include +#include // External Dependencies #include @@ -19,14 +18,11 @@ // 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/Collision/SHPhysicsRaycaster.h" -#include "Physics/Interface/SHRigidBodyComponent.h" -#include "Physics/Interface/SHColliderComponent.h" -#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" -#include "Physics/SHPhysicsWorld.h" +#include "Physics/Collision/SHCollisionInfo.h" +#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h" +#include "Physics/RP3DWrapper/SHPhysicsWorld.h" +#include "Physics/RP3DWrapper/SHCollisionListener.h" +#include "Physics/RP3DWrapper/SHRaycaster.h" #include "Scene/SHSceneGraph.h" namespace SHADE @@ -43,254 +39,150 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsDebugDrawSystem; + friend class SHCollisionListener; + friend class SHRaycaster; public: + + /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHPhysicsSystem(); + SHPhysicsSystem () noexcept; + ~SHPhysicsSystem() noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] double GetFixedUpdateRate () const noexcept; - [[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept; + [[nodiscard]] double GetFixedUpdateRate () const noexcept; + [[nodiscard]] double GetFixedDT () const noexcept; - [[nodiscard]] const std::vector& GetAllCollisionInfo () const noexcept; - [[nodiscard]] const std::vector& GetAllTriggerInfo () const noexcept; + [[nodiscard]] const std::vector& GetAllTriggerInfo () const noexcept; + [[nodiscard]] const std::vector& GetAllCollisionInfo () const noexcept; - [[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept; - [[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetFixedUpdateRate (double fixedUpdateRate) noexcept; - void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept; - + void SetFixedUpdateRate (double fixedUpdateRate) noexcept; + void SetFixedDT (double fixedDt) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - void Init () override; - void Exit () override; - - void BuildScene (SHSceneGraph& sceneGraph); - void ForceBuild (SHSceneGraph& sceneGraph); - void ForceUpdate (); + /** + * @brief + * - Initialises the static collision tag matrix. + * - Registers the system to catch specific events. + */ + void Init() override; + void Exit() override; /** - * @brief Casts a ray into the world. - * @param ray The ray to cast. - * @param distance The distance to cast the ray. Defaults to infinity. - * @param collisionTag The collision tag to use for filtering the raycast. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult Raycast - ( - const SHRay& ray - , float distance = std::numeric_limits::infinity() - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - /** - * @brief Casts a bounded ray into the world. - * @param start The starting point of the ray. - * @param end The end point of the ray. - * @param collisionTag The collision tag to use for filtering the bounded raycast. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult Linecast - ( - const SHVec3& start - , const SHVec3& end - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - /** - * @brief Casts a ray at a body with colliders. - * @param eid The entity to cast to. - * @param ray The ray to cast. - * @param distance The distance to cast the ray. Defaults to infinity. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - /** - * @brief Casts a ray at a collider. - * @param eid The entity to cast to. - * @param shapeIndex The index of the collision shape. - * @param ray The ray to cast. - * @param distance The distance to cast the ray. Defaults to infinity. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , int shapeIndex - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - /** - * @brief Casts a bounded ray at a body with colliders. - * @param eid - * @param start - * @param end - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - /** - * @brief - * @param eid - * @param shapeIndex - * @param start - * @param end - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , int shapeIndex - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - // Specific Handling for Collision Shapes as they are not under the Component System. - // This is done as events need to be sent out. - // TODO(Diren): Consider using a static method through the ColliderComponent. - - void AddCollisionShape (EntityID eid, int shapeIndex); - void RemoveCollisionShape (EntityID eid, int shapeIndex); + * @brief + * Casts a ray into the collision space. + * @param info + * Contains the information for the raycast. + * @return + * A container of the objects hit by the ray. If nothing was hit, the container + * will be empty. + */ + [[nodiscard]] const std::vector& Raycast(const SHRaycaster::RaycastInfo& info) noexcept; /*---------------------------------------------------------------------------------*/ /* System Routines */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * The physics update routine that runs before the simulation is updated. + * This is always running, regardless of the editor state. + *
+ * This update game logic is applied before the simulation runs. + */ class SH_API PhysicsPreUpdate final : public SHSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - PhysicsPreUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - void Execute(double dt) noexcept override; - - private: - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - - void syncRigidBodyActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept; - void syncColliderActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept; - 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 + /** + * @brief + * The physics update routine that runs at a fixed rate. This is where the main + * simulation runs. If delta time is large enough, this may run more than once per + * frame. If delta time is small enough, this may not run at all. + */ + class SH_API PhysicsUpdate final : public SHFixedSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - - PhysicsFixedUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - - void Execute (double dt) noexcept override; + PhysicsUpdate(); + void Execute(double dt) noexcept override; }; + /** + * @brief + * The physics update that runs after the simulation. This sets the rendering + * transforms and sends messages to scripting system for collision & trigger events.
+ * + */ 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: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using EventFunctionPair = std::pair; + + struct RaycastHit + { + SHVec3 start; + SHVec3 end; + }; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - // System data + static constexpr int NUM_EVENT_FUNCTIONS = 4; + // Event function container for cleanly registering to events + EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS]; + + // System data bool worldUpdated; double interpolationFactor; double fixedDT; - // rp3d + // Sub-systems / managers rp3d::PhysicsCommon factory; - - // Interface objects - SHPhysicsWorldState worldState; SHPhysicsObjectManager objectManager; SHCollisionListener collisionListener; - SHPhysicsRaycaster raycaster; + SHRaycaster raycaster; + + // For the debug drawer to draw rays + #ifdef SHEDITOR + std::vector raycastHits; + #endif /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept; - SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept; + SHEventHandle onSceneInit (SHEventPtr onSceneInitEvent); + SHEventHandle onSceneExit (SHEventPtr onSceneExitEvent); - SHEventHandle onPlay (SHEventPtr onPlayEvent); - SHEventHandle onStop (SHEventPtr onStopEvent); - SHEventHandle buildScene (SHEventPtr onSceneChangeEvent); + SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent); + SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index 1fb11274..f1326bed 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -52,85 +52,43 @@ namespace SHADE double SHPhysicsSystemInterface::GetFixedDT() noexcept { - auto phySystem = SHSystemManager::GetSystem(); - if (phySystem) - { - return 1.0 / phySystem->GetFixedUpdateRate(); - } + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetFixedDT(); SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); return 0.0; } - SHPhysicsRaycastResult SHPhysicsSystemInterface::Raycast(const SHRay& ray, float distance) noexcept + int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept { auto* physicsSystem = SHSystemManager::GetSystem(); if (physicsSystem) - { - return physicsSystem->Raycast(ray, distance); - } + return physicsSystem->GetFixedUpdateRate(); - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; + SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead."); + return 0.0; } - SHPhysicsRaycastResult SHPhysicsSystemInterface::Linecast(const SHVec3& start, const SHVec3& end) noexcept + const std::vector& SHPhysicsSystemInterface::Raycast(const RaycastInfo& info) noexcept { + static std::vector emptyVec; + auto* physicsSystem = SHSystemManager::GetSystem(); if (physicsSystem) { - return physicsSystem->Linecast(start, end); + SHRaycaster::RaycastInfo raycastInfo; + raycastInfo.continuous = info.continuous; + raycastInfo.distance = info.distance; + raycastInfo.layers = info.layers; + raycastInfo.ray = info.ray; + + if (info.colliderEntityID.has_value()) + raycastInfo.SetColliderID(info.colliderEntityID.value()); + + return physicsSystem->Raycast(raycastInfo); } - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderRaycast(eid, ray, distance); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderRaycast(eid, shapeIndex, ray, distance); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderLinecast(eid, start, end); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderLinecast(eid, shapeIndex, start, end); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; + return emptyVec; } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index 0065aee3..8815e674 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -12,11 +12,13 @@ of DigiPen Institute of Technology is prohibited. #pragma once // STL Includes +#include #include // Project Headers #include "ECS_Base/Entity/SHEntity.h" - +#include "Math/SHRay.h" +#include "Physics/Collision/CollisionTags/SHCollisionTags.h" namespace SHADE { @@ -25,11 +27,8 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ class SHCollisionInfo; - class SHVec3; - struct SHRay; struct SHPhysicsRaycastResult; - /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -39,7 +38,49 @@ namespace SHADE /// class SH_API SHPhysicsSystemInterface final { + public: + + struct RaycastInfo + { + private: + /*-------------------------------------------------------------------------------*/ + /* Friends */ + /*-------------------------------------------------------------------------------*/ + + friend class SHPhysicsSystemInterface; + public: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + bool continuous = false; + uint16_t layers = static_cast(SHCollisionTag::Layer::ALL); + float distance = std::numeric_limits::infinity(); + SHRay ray; + + /*-------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*-------------------------------------------------------------------------------*/ + + /** + * @brief + * Sets the collider ID for the raycast. Setting this specifies that the ray + * should ignore this collider. + * @param eid + * The entity ID of the collider. + */ + void SetColliderID(EntityID eid) noexcept { colliderEntityID = eid; } + + private: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + std::optional colliderEntityID; + }; + + /*---------------------------------------------------------------------------------*/ /* Constructor */ /*---------------------------------------------------------------------------------*/ @@ -49,15 +90,11 @@ namespace SHADE /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; - [[nodiscard]] static double GetFixedDT () noexcept; + [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; + [[nodiscard]] static double GetFixedDT () noexcept; + [[nodiscard]] static int GetFixedUpdateRate () noexcept; + [[nodiscard]] static const std::vector& Raycast (const RaycastInfo& info) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult Raycast (const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult Linecast (const SHVec3& start, const SHVec3& end) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, int shapeIndex, const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, const SHVec3& start, const SHVec3& end) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept; }; } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp deleted file mode 100644 index a5ca957a..00000000 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/**************************************************************************************** - * \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/SHEntityManager.h" -#include "ECS_Base/Managers/SHSystemManager.h" -#include "Editor/SHEditor.h" -#include "Scene/SHSceneManager.h" -#include "Scripting/SHScriptEngine.h" - -#include "Input/SHInputManager.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" - -/*-------------------------------------------------------------------------------------*/ -/* Local Functions */ -/*-------------------------------------------------------------------------------------*/ - -void testFunction(); - -///////////////////////////////////////////////////////////////////////////////////////// - -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 - - // Only Sync on Play. - // Otherwise, Components are only holding data until the world is built on play. - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && 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; - - // Sync active states between SHADE & RP3D - syncRigidBodyActive(entityID, physicsObject); - syncColliderActive(entityID, physicsObject); - - 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; - - syncRigidBodyActive(entityID, physicsObject); - syncColliderActive(entityID, physicsObject); - - 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!"); - } - - const double FIXED_DT = physicsSystem->fixedDT; - // HACK: Clamp DT here to prevent a ridiculous amount of updates. This limits updates from large dt to 2. - // HACK: This should be done by the FRC and not here for predictable behaviour. - - accumulatedTime += dt; - - //testFunction(); - - int count = 0; - while (accumulatedTime > FIXED_DT) - { - if (scriptingSystem != nullptr) - scriptingSystem->ExecuteFixedUpdates(); - - physicsSystem->worldState.world->update(static_cast(FIXED_DT)); - - accumulatedTime -= FIXED_DT; - ++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); - - 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::syncRigidBodyActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept - { - if (!SHComponentManager::HasComponent(eid)) - return; - - const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive(eid); - const bool IS_RP3D_BODY_ACTIVE = physicsObject.GetRigidBody()->isActive(); - - if (IS_ACTIVE_IN_SCENE != IS_RP3D_BODY_ACTIVE) - physicsObject.GetRigidBody()->setIsActive(IS_ACTIVE_IN_SCENE); - } - - void SHPhysicsSystem::PhysicsPreUpdate::syncColliderActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept - { - const auto* COLLIDER = SHComponentManager::GetComponent_s(eid); - if (!COLLIDER) - return; - - const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive(eid); - const bool IS_RP3D_COLLIDER_ACTIVE = physicsObject.collidersActive; - - if (IS_ACTIVE_IN_SCENE != IS_RP3D_COLLIDER_ACTIVE) - { - // HACK: If active state turned off, remove all collision shapes. If turned on, add them back. - auto* physicsSystem = reinterpret_cast(GetSystem()); - - const int NUM_SHAPES = static_cast(COLLIDER->GetCollisionShapes().size()); - if (IS_ACTIVE_IN_SCENE) - { - for (int i = 0; i < NUM_SHAPES; ++i) - physicsSystem->objectManager.AddCollisionShape(eid, i); - } - else - { - for (int i = NUM_SHAPES - 1; i >= 0; --i) - physicsSystem->objectManager.RemoveCollisionShape(eid, i); - } - - physicsObject.collidersActive = IS_ACTIVE_IN_SCENE; - } - } - - 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()) - { - physicsObject.GetRigidBody()->setIsSleeping(false); - - 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 - { - if (!transformComponent) - return; - - 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); - physicsObject.prevTransform = RP3D_TRANSFORM; - - if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - rigidBodyComponent->position = WORLD_POS; - rigidBodyComponent->orientation = WORLD_ROT; - } - - if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - 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 - { - const rp3d::Transform& CURRENT_TF = physicsObject.GetRigidBody()->getTransform(); - auto renderPos = CURRENT_TF.getPosition(); - auto renderRot = CURRENT_TF.getOrientation(); - - // Cache transforms - if (physicsObject.GetRigidBody()->isActive()) - physicsObject.prevTransform = CURRENT_TF; - - // Sync with rigid bodies - if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - // Skip static bodies - if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC) - return; - - // Check if transform should be interpolated - 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)); - - renderPos = INTERPOLATED_TF.getPosition(); - renderRot = INTERPOLATED_TF.getOrientation(); - } - - rigidBodyComponent->position = CURRENT_TF.getPosition(); - rigidBodyComponent->orientation = CURRENT_TF.getOrientation(); - - // Sync with colliders - if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - // Skip colliders without rigidbody components. If any transform was updated, it was done in pre-update. - - colliderComponent->position = CURRENT_TF.getPosition(); - colliderComponent->orientation = CURRENT_TF.getOrientation(); - } - - // Set transform for rendering - if (transformComponent) - { - transformComponent->SetWorldPosition(renderPos); - transformComponent->SetWorldOrientation(renderRot); - } - } - } -} // namespace SHADE - -///////////////////////////////////////////////////////////////////////////////////////// - -void testFunction() -{ - using namespace SHADE; - - // Test movement - const float forceModifier = 25.0f; - EntityID eid = 65538; - - if (SHEntityManager::IsValidEID(eid)) - { - auto* rb = SHComponentManager::GetComponent_s(eid); - if (rb) - { - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W)) - rb->AddForce(SHVec3::UnitZ * forceModifier); - - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) - rb->AddForce(-SHVec3::UnitX * forceModifier); - - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S)) - rb->AddForce(-SHVec3::UnitZ * forceModifier); - - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D)) - rb->AddForce(SHVec3::UnitX * forceModifier); - } - } - - // Cast rays - auto* tag = SHCollisionTagMatrix::GetTag(1); - tag->SetLayerState(SHCollisionTag::Layer::_1, false); - tag->SetLayerState(SHCollisionTag::Layer::_2, true); - - SHRay ray { SHVec3{3.0f, 3.5f, 0.0f}, -SHVec3::UnitX }; - auto* physicsSystem = SHSystemManager::GetSystem(); - physicsSystem->Raycast(ray, std::numeric_limits::infinity(), *tag); -} diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index fb35ea2c..6c019874 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -3,9 +3,8 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" -#include "Math/Geometry/SHBox.h" -#include "Math/Geometry/SHSphere.h" -#include "Physics/Interface/SHCollisionShape.h" +#include "Physics/Collision/Shapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHBox.h" #include "Resource/SHResourceManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" @@ -15,7 +14,7 @@ #include "SHSerializationTools.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Animation/SHAnimatorComponent.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" namespace YAML { @@ -149,17 +148,17 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - const auto* BOX = reinterpret_cast(rhs.GetShape()); - node[HalfExtents] = BOX->GetRelativeExtents(); + const auto& BOX_SHAPE = dynamic_cast(rhs); + node[HalfExtents] = BOX_SHAPE.GetRelativeExtents(); } break; case SHCollisionShape::Type::SPHERE: { - const auto* SPHERE = reinterpret_cast(rhs.GetShape()); - node[Radius] = SPHERE->GetRelativeRadius(); + const auto& SPHERE_SHAPE = dynamic_cast(rhs); + node[Radius] = SPHERE_SHAPE.GetRelativeRadius(); } break; - case SHCollisionShape::Type::CAPSULE: break; + //case SHCollisionShape::Type::CAPSULE: break; default:; } @@ -192,16 +191,16 @@ namespace YAML case SHCollisionShape::Type::BOX: { if (node[HalfExtents].IsDefined()) - rhs.SetBoundingBox(node[HalfExtents].as()); + dynamic_cast(rhs).SetRelativeExtents(node[HalfExtents].as()); } break; case SHCollisionShape::Type::SPHERE: { if (node[Radius].IsDefined()) - rhs.SetBoundingSphere(node[Radius].as()); + dynamic_cast(rhs).SetRelativeRadius(node[Radius].as()); } break; - case SHCollisionShape::Type::CAPSULE: break; + //case SHCollisionShape::Type::CAPSULE: break; default:; } if (node[Friction].IsDefined()) @@ -254,9 +253,9 @@ namespace YAML switch (colliderType) { - case SHCollisionShape::Type::BOX: rhs.AddBoundingBox(); break; - case SHCollisionShape::Type::SPHERE: rhs.AddBoundingSphere(); break; - case SHCollisionShape::Type::CAPSULE: break; + case SHCollisionShape::Type::BOX: rhs.AddBoxCollisionShape(SHVec3::One); break; + case SHCollisionShape::Type::SPHERE: rhs.AddSphereCollisionShape(1.0f); break; + //case SHCollisionShape::Type::CAPSULE: break; default:; } YAML::convert::decode(colliderNode, rhs.GetCollisionShape(numColliders++)); diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index b5f1444f..ac191cdd 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -4,7 +4,6 @@ \par email: kahwei.tng\@digipen.edu \date Oct 20, 2022 \brief Contains the definition of the functions of the managed Collider class. - Note: This file is written in C++17/CLI. Copyright (C) 2022 DigiPen Institute of Technology. @@ -15,11 +14,14 @@ of DigiPen Institute of Technology is prohibited. #include "SHpch.h" // Primary Header #include "Collider.hxx" + +#include "Physics/Collision/Shapes/SHBox.h" +#include "Physics/Collision/Shapes/SHSphere.h" #include "Utility/Debug.hxx" namespace SHADE { - /*---------------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ /* CollisionShape - Constructors */ /*---------------------------------------------------------------------------------*/ CollisionShape::CollisionShape(int arrayIdx, Entity attachedEntity) @@ -120,7 +122,7 @@ namespace SHADE /* BoxCollider - Constructors */ /*---------------------------------------------------------------------------------*/ BoxCollider::BoxCollider(int arrayIdx, Entity attachedEntity) - : CollisionShape { arrayIndex, attachedEntity } + : CollisionShape { arrayIdx, attachedEntity } {} /*---------------------------------------------------------------------------------*/ @@ -128,35 +130,20 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 BoxCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetCenter()); - } - void BoxCollider::Center::set(Vector3 value) - { - getNativeCollisionShape().SetCenter(Convert::ToNative(value)); + return Convert::ToCLI(getNativeCollisionShape().GetWorldCentroid()); } Vector3 BoxCollider::HalfExtents::get() { - return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); } void BoxCollider::HalfExtents::set(Vector3 value) { - getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); + getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); } - Vector3 BoxCollider::Min::get() + Quaternion BoxCollider::Orientation::get() { - return Convert::ToCLI(getNativeCollisionShape().GetMin()); - } - void BoxCollider::Min::set(Vector3 value) - { - getNativeCollisionShape().SetMin(Convert::ToNative(value)); - } - Vector3 BoxCollider::Max::get() - { - return Convert::ToCLI(getNativeCollisionShape().GetMax()); - } - void BoxCollider::Max::set(Vector3 value) - { - getNativeCollisionShape().SetMax(Convert::ToNative(value)); + //return Convert::ToCLI(getNativeCollisionShape().GetWorldOrientation()); + return Quaternion::Identity; } /*---------------------------------------------------------------------------------*/ @@ -164,11 +151,13 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool BoxCollider::TestPoint(Vector3 point) { - return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + //return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + return false; } bool BoxCollider::Raycast(Ray ray, float maxDistance) { - return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + //return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + return false; } /*---------------------------------------------------------------------------------*/ @@ -176,19 +165,15 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 SphereCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetCenter()); - } - void SphereCollider::Center::set(Vector3 value) - { - getNativeCollisionShape().SetCenter(Convert::ToNative(value)); + return Convert::ToCLI(getNativeCollisionShape().GetWorldCentroid()); } float SphereCollider::Radius::get() { - return getNativeCollisionShape().GetWorldRadius(); + return getNativeCollisionShape().GetWorldRadius(); } void SphereCollider::Radius::set(float value) { - getNativeCollisionShape().SetWorldRadius(value); + getNativeCollisionShape().SetWorldRadius(value); } /*---------------------------------------------------------------------------------*/ @@ -196,11 +181,13 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool SphereCollider::TestPoint(Vector3 point) { - return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + //return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + return false; } bool SphereCollider::Raycast(Ray ray, float maxDistance) { - return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + //return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + return false; } /*---------------------------------------------------------------------------------*/ @@ -231,7 +218,10 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ int Collider::CollisionShapeCount::get() { - return static_cast(GetNativeComponent()->GetCollisionShapes().size()); + if (const auto* nativeComponent = GetNativeComponent(); nativeComponent) + return static_cast(nativeComponent->GetCollisionShapes().size()); + + return -1; } /*---------------------------------------------------------------------------------*/ @@ -314,7 +304,7 @@ namespace SHADE for (const auto& collider : GetNativeComponent()->GetCollisionShapes()) { CollisionShape^ bound = nullptr; - switch (collider.GetType()) + switch (collider->GetType()) { case SHCollisionShape::Type::BOX: bound = gcnew BoxCollider(i, Owner.GetEntity()); @@ -322,9 +312,9 @@ namespace SHADE case SHCollisionShape::Type::SPHERE: bound = gcnew SphereCollider(i, Owner.GetEntity()); break; - case SHCollisionShape::Type::CAPSULE: - // TODO - break; + //case SHCollisionShape::Type::CAPSULE: + // // TODO + // break; default: Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping."); break; @@ -335,4 +325,4 @@ namespace SHADE subColliderList->Add(bound); } } -} +} \ No newline at end of file diff --git a/SHADE_Managed/src/Components/Collider.h++ b/SHADE_Managed/src/Components/Collider.h++ index 8ea648aa..b16e8063 100644 --- a/SHADE_Managed/src/Components/Collider.h++ +++ b/SHADE_Managed/src/Components/Collider.h++ @@ -31,7 +31,7 @@ namespace SHADE if (shape.GetType() != SHCollisionShape::Type::BOX) throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); - return reinterpret_cast(shape); + return dynamic_cast(shape); } catch (std::invalid_argument&) { diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index a649483f..3c7b060e 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -1,7 +1,9 @@ /************************************************************************************//*! \file Collider.hxx \author Tng Kah Wei, kahwei.tng, 390009620 + Diren D Bharwani, diren.dbharwani, 390002520 \par email: kahwei.tng\@digipen.edu + email: diren.dbharwani\@digipen.edu \date Oct 20, 2022 \brief Contains the definition of the managed Collider class with the declaration of functions for working with it. @@ -142,15 +144,14 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Center of the Bounding Box formed by this bound. + /// Center of the box collider. /// property Vector3 Center { Vector3 get(); - void set(Vector3 value); } /// - /// Half of the scale of the Bounding Box formed by this bound. + /// Half of the scale of the box collider. /// property Vector3 HalfExtents { @@ -158,22 +159,11 @@ namespace SHADE void set(Vector3 value); } /// - /// Position of the bottom left back corner of the Bounding Box formed by this - /// bound. + /// The orientation of the box. /// - property Vector3 Min + property Quaternion Orientation { - Vector3 get(); - void set(Vector3 value); - } - /// - /// Position of the top right front corner of the Bounding Box formed by this - /// bound. - /// - property Vector3 Max - { - Vector3 get(); - void set(Vector3 value); + Quaternion get(); } /*-----------------------------------------------------------------------------*/ @@ -201,12 +191,11 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Center of the Bounding Sphere formed by this bound. + /// Center of the sphere. /// property Vector3 Center { Vector3 get(); - void set(Vector3 value); } /// /// Radius of the Bounding Sphere formed by this bound. diff --git a/SHADE_Managed/src/Physics/Physics.cxx b/SHADE_Managed/src/Physics/Physics.cxx index 9e2c1413..e5c376d2 100644 --- a/SHADE_Managed/src/Physics/Physics.cxx +++ b/SHADE_Managed/src/Physics/Physics.cxx @@ -15,10 +15,14 @@ // External Dependencies #include "Physics/System/SHPhysicsSystemInterface.h" // Project Header +#include "Components/Collider.hxx" +#include "Components/Transform.hxx" #include "Engine/GameObject.hxx" #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" +using namespace System::Collections::Generic; + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -41,49 +45,262 @@ namespace SHADE /* Raycast Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - RaycastHit Physics::Raycast(Ray ray) + List^ Physics::Raycast(Ray ray, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray))); + List^ results = gcnew List(); + + // Cast natively + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::Raycast(Ray ray, float distance) + List^ Physics::Raycast(Ray ray, float distance, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray), distance)); + List^ results = gcnew List(); + + // Cast natively + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.distance = distance; + raycastInfo.continuous = continuous; + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::Linecast(Vector3 start, Vector3 end) + List^ Physics::Linecast(Vector3 start, Vector3 end, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::Linecast(Convert::ToNative(start), Convert::ToNative(end))); + List^ results = gcnew List(); + + // Cast natively + Vector3 direction = end - start; + direction.Normalise(); + const Ray CLI_RAY( start, direction ); + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(CLI_RAY); + raycastInfo.distance = (end - start).GetMagnitude(); + raycastInfo.continuous = continuous; + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray) + List^ Physics::ColliderRaycast(GameObject object, Ray ray, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray))); + List^ results = gcnew List(); + + // Get the collider's position (same as the transform) + Transform^ managedTransform = object.GetComponent(); + if (!managedTransform) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform."); + + const Vector3 COLLIDER_POS = managedTransform->GlobalPosition; + ray.Position += COLLIDER_POS; + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance) + List^ Physics::ColliderRaycast(GameObject object, Ray ray, float distance, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray), distance)); + List^ results = gcnew List(); + + // Get the collider's position (same as the transform) + Transform^ managedTransform = object.GetComponent(); + if (!managedTransform) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform."); + + const Vector3 COLLIDER_POS = managedTransform->GlobalPosition; + ray.Position += COLLIDER_POS; + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.distance = distance; + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray) + List^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray))); + List^ results = gcnew List(); + + // Get the collider's position + Vector3 shapePos = Vector3::Zero; + Collider^ managedCollider = object.GetComponent(); + if (!managedCollider) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider."); + + CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex); + if (!managedShape) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); + + const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); + shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); + + ray.Position += shapePos; + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance) + List^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray), distance)); + List^ results = gcnew List(); + + // Get the collider's position + Vector3 shapePos = Vector3::Zero; + Collider^ managedCollider = object.GetComponent(); + if (!managedCollider) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider."); + + CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex); + if (!managedShape) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); + + const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); + shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); + + ray.Position += shapePos; + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + raycastInfo.distance = distance; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end) + List^ Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, Convert::ToNative(start), Convert::ToNative(end))); + List^ results = gcnew List(); + + // Get the collider's position (same as the transform) + Transform^ managedTransform = object.GetComponent(); + if (!managedTransform) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform."); + + const Vector3 COLLIDER_POS = managedTransform->GlobalPosition; + start += COLLIDER_POS; + + Vector3 direction = end - start; + direction.Normalise(); + const Ray CLI_RAY( start, direction ); + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(CLI_RAY); + raycastInfo.distance = (end - start).GetMagnitude(); + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end) + List^ Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, shapeIndex, Convert::ToNative(start), Convert::ToNative(end))); + List^ results = gcnew List(); + + // Get the collider's position + Vector3 shapePos = Vector3::Zero; + Collider^ managedCollider = object.GetComponent(); + if (!managedCollider) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider."); + + CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex); + if (!managedShape) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); + + const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); + shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); + + start += shapePos; + + Vector3 direction = end - start; + direction.Normalise(); + const Ray CLI_RAY( start, direction ); + + SHPhysicsSystemInterface::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(CLI_RAY); + raycastInfo.continuous = continuous; + raycastInfo.distance = (end - start).GetMagnitude(); + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Physics/Physics.hxx b/SHADE_Managed/src/Physics/Physics.hxx index f13e5952..573d8cad 100644 --- a/SHADE_Managed/src/Physics/Physics.hxx +++ b/SHADE_Managed/src/Physics/Physics.hxx @@ -40,82 +40,143 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /// - /// Casts an infinite ray into the world. + /// Casts an infinite ray into the world.
+ /// This raycast will stop at the first object hit. ///
/// The ray to cast. - /// The result of the raycast. - static RaycastHit Raycast (Ray ray); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ Raycast (Ray ray, bool continuous); /// /// Casts a ray for a given distance into the world. /// /// The ray to cast. /// The distance to cast the ray. - /// The result of the raycast. - static RaycastHit Raycast (Ray ray, float distance); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ Raycast (Ray ray, float distance, bool continuous); /// /// Casts a bounded ray into the world. /// /// The start of the bounded ray. /// The end of the bounded ray. - /// The result of the raycast. - static RaycastHit Linecast (Vector3 start, Vector3 end); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ Linecast (Vector3 start, Vector3 end, bool continuous); /// /// Casts an infinite ray w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// The ray to cast. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, Ray ray); + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, Ray ray, bool continuous); /// /// Casts a ray for a given distance w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// The ray to cast. + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// /// The distance to cast the ray. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, Ray ray, float distance, bool continuous); /// /// Casts an infinite ray w.r.t a specific collider on a GameObject. /// /// The GameObject to cast the ray to. /// The collision shape index on the collider to cast to. - /// The ray to cast. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray); + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, bool continuous); /// /// Casts a ray for a given distance w.r.t a specific collider on a GameObject. /// /// The GameObject to cast the ray to. /// The collision shape index on the collider to cast to. - /// The ray to cast. + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// /// The distance to cast the ray. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance, bool continuous); /// /// Casts a bounded ray w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// The start of the bounded ray. + /// + /// The start of the bounded ray.
+ /// The start of the ray is offset from the collider's position. /// - /// The result of the raycast. - static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderLineCast (GameObject object, Vector3 start, Vector3 end, bool continuous); /// /// Casts a bounded ray w.r.t a specific collider on a GameObject. /// /// The GameObject to cast the ray to. /// The collision shape index on the collider to cast to. - /// The start of the bounded ray. + /// + /// The start of the bounded ray.
+ /// The start of the ray is offset from the collider's position. /// The end of the bounded ray. - /// The result of the raycast. - static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned./// + static System::Collections::Generic::List^ ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous); private: /*---------------------------------------------------------------------------------*/