diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 10cc09b3..7103c592 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -94,6 +94,7 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); @@ -148,6 +149,13 @@ namespace Sandbox #endif SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f); editor->PollPicking(); + + static bool drawColliders = false; + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::SPACE)) + { + drawColliders = !drawColliders; + SHSystemManager::GetSystem()->SetDrawColliders(drawColliders); + } } // Finish all graphics jobs first graphicsSystem->AwaitGraphicsExecution(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 4777fc6a..20615fdc 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -265,14 +265,15 @@ namespace SHADE { const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale(); const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); - return sphere->GetRadius() / MAX_SCALE; + return (sphere->GetRadius() / MAX_SCALE) * 2.0f; }, - [collider](float const& value) { collider->SetBoundingSphere(value); }); + [collider](float const& value) { collider->SetBoundingSphere(value); }); } else if (collider->GetType() == SHCollider::Type::CAPSULE) { } + { 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); }); @@ -297,6 +298,9 @@ namespace SHADE }); SHEditorWidgets::EndPanel(); } + + SHEditorWidgets::CheckBox("Is Trigger", [collider] { return collider->IsTrigger(); }, [collider](bool value) { collider->SetIsTrigger(value); }); + if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) { colliderToDelete = i; diff --git a/SHADE_Engine/src/Math/SHColour.cpp b/SHADE_Engine/src/Math/SHColour.cpp index 944c37cb..fc2f2a08 100644 --- a/SHADE_Engine/src/Math/SHColour.cpp +++ b/SHADE_Engine/src/Math/SHColour.cpp @@ -118,6 +118,17 @@ namespace SHADE } {} + SHColour::SHColour(uint32_t rgba) noexcept + : XMFLOAT4 { 0.0f, 0.0f, 0.0f, 1.0f } + { + const SHColour32 TMP { ._32bitValue = rgba }; + + x = static_cast(TMP._8bitValues[0]) / 255.0f; + y = static_cast(TMP._8bitValues[1]) / 255.0f; + z = static_cast(TMP._8bitValues[2]) / 255.0f; + w = static_cast(TMP._8bitValues[3]) / 255.0f; + } + SHColour::SHColour(const SHVec3& rgb) noexcept : XMFLOAT4 { rgb.x, rgb.y, rgb.z, 1.0f } {} diff --git a/SHADE_Engine/src/Math/SHColour.h b/SHADE_Engine/src/Math/SHColour.h index a6adf7bb..5dac0edd 100644 --- a/SHADE_Engine/src/Math/SHColour.h +++ b/SHADE_Engine/src/Math/SHColour.h @@ -34,6 +34,12 @@ namespace SHADE float v = 0.0f; }; + union SH_API SHColour32 + { + uint32_t _32bitValue; + uint8_t _8bitValues[4]; + }; + class SH_API SHColour : public DirectX::XMFLOAT4 { public: @@ -46,6 +52,7 @@ namespace SHADE SHColour (float r, float g, float b, float a) noexcept; SHColour (uint8_t r, uint8_t g, uint8_t b) noexcept; SHColour (uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + SHColour (uint32_t rgba) noexcept; SHColour (const SHVec3& rgb) noexcept; SHColour (const SHVec4& rgba) noexcept; diff --git a/SHADE_Engine/src/Physics/SHCollider.cpp b/SHADE_Engine/src/Physics/SHCollider.cpp index 6cea3dc1..6d455d67 100644 --- a/SHADE_Engine/src/Physics/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/SHCollider.cpp @@ -212,7 +212,7 @@ namespace SHADE const SHVec3 TF_WORLD_SCALE = transformComponent->GetWorldScale(); const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); - worldRadius *= MAX_SCALE; + worldRadius *= MAX_SCALE * 0.5f; } if (type == Type::SPHERE) diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp index e1acccd9..bdee8ba1 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -17,10 +17,12 @@ #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Math/SHMathHelpers.h" #include "Math/Transform/SHTransformComponent.h" #include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" +#include "Tools/SHUtilities.h" namespace SHADE { @@ -30,6 +32,7 @@ namespace SHADE SHPhysicsSystem::SHPhysicsSystem() : worldUpdated { false } + , debugDrawFlags { 0 } , interpolationFactor { 0.0 } , fixedDT { 60.0 } , world { nullptr } @@ -47,6 +50,11 @@ namespace SHADE : SHSystemRoutine { "Physics PostUpdate", false } {} + SHPhysicsSystem::PhysicsDebugDraw::PhysicsDebugDraw() + : SHSystemRoutine { "Physics DebugDraw", true } + {} + + /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -99,6 +107,31 @@ namespace SHADE return 0; } + bool SHPhysicsSystem::GetDrawColliders() const noexcept + { + return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER); + } + + bool SHPhysicsSystem::GetDrawColliderAABBs() const noexcept + { + return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB); + } + + bool SHPhysicsSystem::GetDrawBroadPhase() const noexcept + { + return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB); + } + + bool SHPhysicsSystem::GetDrawContactPoints() const noexcept + { + return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS); + } + + bool SHPhysicsSystem::GetDrawContactNormals() const noexcept + { + return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS); + } + const SHPhysicsSystem::CollisionEvents& SHPhysicsSystem::GetCollisionInfo() const noexcept { return collisionInfo; @@ -181,6 +214,96 @@ namespace SHADE } } + void SHPhysicsSystem::SetDrawColliders(bool shouldDraw) noexcept + { + static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER); + shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE); + + if (world == nullptr) + { + SHLOGV_WARNING("No physics world has been initialised!") + return; + } + + world->getDebugRenderer().setIsDebugItemDisplayed + ( + rp3d::DebugRenderer::DebugItem::COLLISION_SHAPE, + shouldDraw + ); + } + + void SHPhysicsSystem::SetDrawColliderAABBs(bool shouldDraw) noexcept + { + static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB); + shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE); + + if (world == nullptr) + { + SHLOGV_WARNING("No physics world has been initialised!") + return; + } + + world->getDebugRenderer().setIsDebugItemDisplayed + ( + rp3d::DebugRenderer::DebugItem::COLLIDER_AABB, + shouldDraw + ); + } + + void SHPhysicsSystem::SetDrawBroadPhase(bool shouldDraw) noexcept + { + static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB); + shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE); + + if (world == nullptr) + { + SHLOGV_WARNING("No physics world has been initialised!") + return; + } + + world->getDebugRenderer().setIsDebugItemDisplayed + ( + rp3d::DebugRenderer::DebugItem::COLLIDER_BROADPHASE_AABB, + shouldDraw + ); + } + + void SHPhysicsSystem::SetDrawContactPoints(bool shouldDraw) noexcept + { + static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS); + shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE); + + if (world == nullptr) + { + SHLOGV_WARNING("No physics world has been initialised!") + return; + } + + world->getDebugRenderer().setIsDebugItemDisplayed + ( + rp3d::DebugRenderer::DebugItem::CONTACT_POINT, + shouldDraw + ); + } + + void SHPhysicsSystem::SetDrawContactNormals(bool shouldDraw) noexcept + { + static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS); + shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE); + + if (world == nullptr) + { + SHLOGV_WARNING("No physics world has been initialised!") + return; + } + + world->getDebugRenderer().setIsDebugItemDisplayed + ( + rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, + shouldDraw + ); + } + /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -198,6 +321,7 @@ namespace SHADE world = factory.createPhysicsWorld(settings); world->setEventListener(this); + world->setIsDebugRenderingEnabled(true); // Set up solvers world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES); @@ -323,7 +447,7 @@ namespace SHADE auto* scriptingSystem = SHSystemManager::GetSystem(); if (scriptingSystem == nullptr) { - SHLOGV_WARNING("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); + SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); } fixedTimeStep = 1.0 / physicsSystem->fixedDT; @@ -353,7 +477,7 @@ namespace SHADE auto* scriptingSystem = SHSystemManager::GetSystem(); if (scriptingSystem == nullptr) { - SHLOGV_WARNING("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); + SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); } // Interpolate transforms for rendering @@ -369,6 +493,40 @@ namespace SHADE } } + void SHPhysicsSystem::PhysicsDebugDraw::Execute(double) noexcept + { + const auto* PHYSICS_SYSTEM = reinterpret_cast(GetSystem()); + if (PHYSICS_SYSTEM->debugDrawFlags == 0) + return; + + auto* debugDrawSystem = SHSystemManager::GetSystem(); + if (debugDrawSystem == nullptr) + { + SHLOGV_ERROR("Unable to debug draw physics objects due to missing SHDebugDrawSystem!"); + return; + } + + const auto& RP3D_DEBUG_RENDERER = PHYSICS_SYSTEM->world->getDebugRenderer(); + + const auto& LINES = RP3D_DEBUG_RENDERER.getLines(); + const auto& TRIANGLES = RP3D_DEBUG_RENDERER.getTriangles(); + + // Draw all lines + for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbLines(); ++i) + { + const auto& LINE = LINES[i]; + debugDrawSystem->DrawLine(SHColour{ LINE.color1 }, LINE.point1, LINE.point2); + } + + for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbTriangles(); ++i) + { + const auto& TRIANGLE = TRIANGLES[i]; + SHColour triColour{ TRIANGLE.color1 }; + triColour.a() = 1.0f; + debugDrawSystem->DrawTri(triColour, TRIANGLE.point1, TRIANGLE.point2, TRIANGLE.point3); + } + } + void SHPhysicsSystem::onContact(const CallbackData& callbackData) { for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i) diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/SHPhysicsSystem.h index 1d773618..05e6e57e 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.h @@ -51,6 +51,15 @@ namespace SHADE using CollisionEvents = std::vector; + enum class DebugDrawFlags : uint8_t + { + COLLIDER = 1 + , COLLIDER_AABB = 2 + , BROAD_PHASE_AABB = 4 + , CONTACT_POINTS = 8 + , CONTACT_NORMALS = 16 + }; + /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ @@ -69,6 +78,12 @@ namespace SHADE [[nodiscard]] uint16_t GetNumberVelocityIterations () const noexcept; [[nodiscard]] uint16_t GetNumberPositionIterations () const noexcept; + [[nodiscard]] bool GetDrawColliders () const noexcept; + [[nodiscard]] bool GetDrawColliderAABBs () const noexcept; + [[nodiscard]] bool GetDrawBroadPhase () const noexcept; + [[nodiscard]] bool GetDrawContactPoints () const noexcept; + [[nodiscard]] bool GetDrawContactNormals () const noexcept; + [[nodiscard]] const CollisionEvents& GetCollisionInfo () const noexcept; [[nodiscard]] const CollisionEvents& GetTriggerInfo () const noexcept; @@ -85,6 +100,13 @@ namespace SHADE void SetWorldSettings (const WorldSettings& settings) const noexcept; + // TODO(Diren): Can the debug draw flags be done through an enum? + void SetDrawColliders (bool shouldDraw) noexcept; + void SetDrawColliderAABBs (bool shouldDraw) noexcept; + void SetDrawBroadPhase (bool shouldDraw) noexcept; + void SetDrawContactPoints (bool shouldDraw) noexcept; + void SetDrawContactNormals (bool shouldDraw) noexcept; + /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ @@ -105,48 +127,31 @@ namespace SHADE class SH_API PhysicsPreUpdate final : public SHSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ PhysicsPreUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - void Execute(double dt) noexcept override; }; class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ PhysicsFixedUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - void Execute (double dt) noexcept override; }; class SH_API PhysicsPostUpdate final : public SHSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ PhysicsPostUpdate(); + void Execute(double dt) noexcept override; + }; - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - + class SH_API PhysicsDebugDraw final : public SHSystemRoutine + { + public: + PhysicsDebugDraw(); void Execute(double dt) noexcept override; }; @@ -162,6 +167,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool worldUpdated; + uint8_t debugDrawFlags; double interpolationFactor; double fixedDT; diff --git a/SHADE_Engine/src/Tools/SHUtilities.h b/SHADE_Engine/src/Tools/SHUtilities.h index b3d840e7..287a827e 100644 --- a/SHADE_Engine/src/Tools/SHUtilities.h +++ b/SHADE_Engine/src/Tools/SHUtilities.h @@ -39,7 +39,7 @@ namespace SHADE * @param[in] enumClassMember A member of the specified enum class. * @returns The value of the enum class member in the output type. */ - template + template > static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept; /**