diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index b865f028..63276d04 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -72,6 +72,9 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); + + // Link up SHDebugDraw + SHDebugDraw::Init(SHSystemManager::GetSystem()); #ifdef SHEDITOR SDL_Init(SDL_INIT_VIDEO); @@ -91,6 +94,7 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); @@ -148,6 +152,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/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index cf5056a5..6259a7c6 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -46,6 +46,7 @@ #include #include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" +#include "Tools/SHDebugDraw.h" RTTR_REGISTRATION { @@ -77,7 +78,6 @@ namespace SHADE //#==============================================================# void SHEditor::Init() { - IMGUI_CHECKVERSION(); if(auto context = ImGui::CreateContext()) { @@ -120,6 +120,17 @@ namespace SHADE window->Init(); } + /* Editor View Gridlines */ + SetUpGridLines(true, true); + // Handle state changes so that we only show in edit mode + std::shared_ptr> stateChangeEventReceiver + { + std::make_shared>(this, &SHEditor::onEditorStateChanged) + }; + SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, std::dynamic_pointer_cast(stateChangeEventReceiver)); + SHEventManager::SubscribeTo(SH_EDITOR_ON_PAUSE_EVENT, std::dynamic_pointer_cast(stateChangeEventReceiver)); + SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, std::dynamic_pointer_cast(stateChangeEventReceiver)); + SHLOG_INFO("Successfully initialised SHADE Engine Editor") } @@ -180,6 +191,97 @@ namespace SHADE io->Fonts->Build(); } + void SHEditor::SetUpGridLines(bool drawGrid, bool drawAxes) + { + // Clear existing lines + SHDebugDraw::ClearPersistentDraws(); + + static constexpr float DELTA = 1.0f; + static constexpr int EXTENT_COUNT = static_cast(500.0f /* TODO: Remove hard code */ / DELTA); + static constexpr float LINE_HALF_LENGTH = (DELTA * static_cast(EXTENT_COUNT)) * 0.5f; + + // Render Grid + static const SHColour GRID_COL = { 0.2f, 0.2f, 0.2f, 1.0f }; + if (drawGrid) + { + for (int i = 1; i < EXTENT_COUNT; ++i) + { + // X-Axis Lines + SHDebugDraw::PersistentLine + ( + GRID_COL, + SHVec3 { -LINE_HALF_LENGTH, 0.0f, i * DELTA }, + SHVec3 { LINE_HALF_LENGTH, 0.0f, i * DELTA } + ); + SHDebugDraw::PersistentLine + ( + GRID_COL, + SHVec3 { -LINE_HALF_LENGTH, 0.0f, i * -DELTA }, + SHVec3 { LINE_HALF_LENGTH, 0.0f, i * -DELTA } + ); + // Y-Axis Lines + SHDebugDraw::PersistentLine + ( + GRID_COL, + SHVec3 { i * DELTA, 0.0f, -LINE_HALF_LENGTH }, + SHVec3 { i * DELTA, 0.0f, LINE_HALF_LENGTH } + ); + SHDebugDraw::PersistentLine + ( + GRID_COL, + SHVec3 { -i * DELTA, 0.0f, -LINE_HALF_LENGTH }, + SHVec3 { -i * DELTA, 0.0f, LINE_HALF_LENGTH } + ); + } + } + + // Render World Axes + if (drawAxes || drawGrid) + { + const SHColour X_AXIS_COL = drawAxes ? SHColour::RED : GRID_COL; + const SHColour Y_AXIS_COL = drawAxes ? SHColour::GREEN : GRID_COL; + const SHColour Z_AXIS_COL = drawAxes ? SHColour::BLUE : GRID_COL; + // X + SHDebugDraw::PersistentLine + ( + X_AXIS_COL, + SHVec3 { -LINE_HALF_LENGTH, 0.0f, 0.0f }, + SHVec3 { LINE_HALF_LENGTH, 0.0f, 0.0f } + ); + // Y + SHDebugDraw::PersistentLine + ( + Y_AXIS_COL, + SHVec3 { 0.0f, -LINE_HALF_LENGTH, 0.0f }, + SHVec3 { 0.0f, LINE_HALF_LENGTH, 0.0f } + ); + // Z + SHDebugDraw::PersistentLine + ( + Z_AXIS_COL, + SHVec3 { 0.0f, 0.0f, -LINE_HALF_LENGTH }, + SHVec3 { 0.0f, 0.0f, LINE_HALF_LENGTH } + ); + } + } + + SHEventHandle SHEditor::onEditorStateChanged(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + switch (editorState) + { + case State::PAUSE: + case State::STOP: + SetUpGridLines(true, true); + break; + case State::PLAY: + default: + SHDebugDraw::ClearPersistentDraws(); + break; + } + return eventData->handle; + } + void SHEditor::Exit() { for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) diff --git a/SHADE_Engine/src/Editor/SHEditor.h b/SHADE_Engine/src/Editor/SHEditor.h index 624069db..6e0ef5ae 100644 --- a/SHADE_Engine/src/Editor/SHEditor.h +++ b/SHADE_Engine/src/Editor/SHEditor.h @@ -16,8 +16,9 @@ #include "Resource/SHHandle.h" #include "EditorWindow/SHEditorWindow.h" #include "Tools/SHLog.h" -#include "Gizmos/SHTransformGizmo.h" - +#include "Gizmos/SHTransformGizmo.h"` +#include "Events/SHEventDefines.h" +#include "Events/SHEvent.h" //#==============================================================# //|| Library Includes || @@ -194,6 +195,10 @@ namespace SHADE void InitFonts() noexcept; + void SetUpGridLines(bool drawGrid, bool drawAxes); + + SHEventHandle onEditorStateChanged(SHEventPtr eventPtr); + // Handle to command pool used for ImGui Vulkan Backend Handle imguiCommandPool; // Handle to command buffer used for ImGui Vulkan Backend diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index 08019665..37d15808 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -43,20 +43,41 @@ namespace SHADE return; } + // Get the system + SHDebugDrawSystem* system = static_cast(GetSystem()); + // Get current frame index const uint32_t FRAME_IDX = gfxSys->GetCurrentFrameIndex(); - // Create the buffer if it doesn't exist or just update it - SHDebugDrawSystem* system = static_cast(GetSystem()); + /* Non-Persistent Buffer */ + // Update the buffer system->numPoints[FRAME_IDX] = system->points.size(); const uint32_t DATA_SIZE = sizeof(PointVertex) * system->points.size(); if (DATA_SIZE > 0) { - system->vertexBuffers[FRAME_IDX]->WriteToMemory(system->points.data(), DATA_SIZE, 0, 0); + system->vertexBuffers[FRAME_IDX]->WriteToMemory(system->points.data(), DATA_SIZE, 0, 0); } // Reset for next frame system->points.clear(); + + /* Persistent Buffer */ + // Check if there are changes + if (system->persistentBuffersCleared[FRAME_IDX] + || + system->numPersistentPoints[FRAME_IDX] != system->persistentPoints.size()) + { + // Update Buffer + system->numPersistentPoints[FRAME_IDX] = system->persistentPoints.size(); + const uint32_t DATA_SIZE = sizeof(PointVertex) * system->persistentPoints.size(); + if (DATA_SIZE > 0) + { + system->persistentVertexBuffers[FRAME_IDX]->WriteToMemory(system->persistentPoints.data(), DATA_SIZE, 0, 0); + } + + // Reset Flag + system->persistentBuffersCleared[FRAME_IDX] = false; + } } /*---------------------------------------------------------------------------------*/ @@ -75,31 +96,63 @@ namespace SHADE const uint32_t FRAME_IDX = GFX_SYSTEM->GetCurrentFrameIndex(); // Don't draw if no points - if (numPoints[FRAME_IDX] <= 0) - return; + if (numPoints[FRAME_IDX] > 0) + { + cmdBuffer->BindPipeline(GFX_SYSTEM->GetDebugDrawPipeline()); + cmdBuffer->SetLineWidth(LineWidth); + cmdBuffer->BindVertexBuffer(0, vertexBuffers[FRAME_IDX], 0); + cmdBuffer->DrawArrays(numPoints[FRAME_IDX], 1, 0, 0); + } + }); + auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); + subPassWithDepth->AddExteriorDrawCalls([this, GFX_SYSTEM](Handle& cmdBuffer) + { + // Get Current frame index + const uint32_t FRAME_IDX = GFX_SYSTEM->GetCurrentFrameIndex(); - cmdBuffer->BindPipeline(GFX_SYSTEM->GetDebugDrawPipeline()); - cmdBuffer->SetLineWidth(LineWidth); - cmdBuffer->BindVertexBuffer(0, vertexBuffers[FRAME_IDX], 0); - cmdBuffer->DrawArrays(numPoints[FRAME_IDX], 1, 0, 0); + // Don't draw if no points + if (numPersistentPoints[FRAME_IDX] > 0) + { + cmdBuffer->BindPipeline(GFX_SYSTEM->GetDebugDrawDepthPipeline()); + cmdBuffer->SetLineWidth(LineWidth); + cmdBuffer->BindVertexBuffer(0, persistentVertexBuffers[FRAME_IDX], 0); + cmdBuffer->DrawArrays(numPersistentPoints[FRAME_IDX], 1, 0, 0); + } }); // Reset trackers std::fill_n(numPoints.begin(), numPoints.size(), 0); + std::fill_n(numPersistentPoints.begin(), numPersistentPoints.size(), 0); + for (bool& cleared : persistentBuffersCleared) + cleared = true; // Allocate buffers + // - Non-Persistent Draws static constexpr uint32_t BUFFER_SIZE = MAX_POINTS * sizeof(PointVertex); for (Handle& bufHandle : vertexBuffers) { - bufHandle = GFX_SYSTEM->GetDevice()->CreateBuffer - ( - BUFFER_SIZE, - nullptr, - 0, - vk::BufferUsageFlagBits::eVertexBuffer, - VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, - VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT - ); + bufHandle = GFX_SYSTEM->GetDevice()->CreateBuffer + ( + BUFFER_SIZE, + nullptr, + 0, + vk::BufferUsageFlagBits::eVertexBuffer, + VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, + VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT + ); + } + // - Persistent Draws + for (Handle& bufHandle : persistentVertexBuffers) + { + bufHandle = GFX_SYSTEM->GetDevice()->CreateBuffer + ( + BUFFER_SIZE, + nullptr, + 0, + vk::BufferUsageFlagBits::eVertexBuffer, + VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, + VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT + ); } } @@ -110,6 +163,11 @@ namespace SHADE if (vertexBuffer) vertexBuffer.Free(); } + for (auto vertexBuffer : persistentVertexBuffers) + { + if (vertexBuffer) + vertexBuffer.Free(); + } } /*---------------------------------------------------------------------------------*/ @@ -117,54 +175,120 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ void SHDebugDrawSystem::DrawLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt) { - if (points.size() > MAX_POINTS) + drawLine(points, color, startPt, endPt); + } + + void SHDebugDrawSystem::DrawTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3) + { + drawPoly(points, color, { pt1, pt2, pt3 }); + } + + void SHDebugDrawSystem::DrawQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4) + { + drawPoly(points, color, { pt1, pt2, pt3, pt4 }); + } + + void SHDebugDrawSystem::DrawPoly(const SHVec4& color, std::initializer_list pointList) + { + drawPoly(points, color, pointList.begin(), pointList.end()); + } + + void SHDebugDrawSystem::DrawCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size) + { + drawCube(points, color, pos, size); + } + + void SHDebugDrawSystem::DrawSphere(const SHVec4& color, const SHVec3& pos, double radius) + { + drawSphere(points, color, pos, radius); + } + + /*---------------------------------------------------------------------------------*/ + /* Persistent Draw Functions */ + /*---------------------------------------------------------------------------------*/ + void SHDebugDrawSystem::DrawPersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt) + { + drawLine(persistentPoints, color, startPt, endPt); + } + + void SHDebugDrawSystem::DrawPersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3) + { + drawPoly(persistentPoints, color, { pt1, pt2, pt3 }); + } + + void SHDebugDrawSystem::DrawPersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4) + { + drawPoly(persistentPoints, color, { pt1, pt2, pt3, pt4 }); + } + + void SHDebugDrawSystem::DrawPersistentPoly(const SHVec4& color, std::initializer_list pointList) + { + drawPoly(persistentPoints, color, pointList.begin(), pointList.end()); + } + + void SHDebugDrawSystem::DrawPersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size) + { + drawCube(persistentPoints, color, pos, size); + } + + void SHDebugDrawSystem::DrawPersistentSphere(const SHVec4& color, const SHVec3& pos, double radius) + { + drawSphere(persistentPoints, color, pos, radius); + } + + void SHDebugDrawSystem::ClearPersistentDraws() + { + persistentPoints.clear(); + for (bool& cleared : persistentBuffersCleared) + cleared = true; + } + + void SHDebugDrawSystem::drawLine(std::vector& storage, const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt) + { + if (storage.size() > MAX_POINTS) { SHLOG_WARNING("[DebugDraw] Exceeded maximum size of drawable debug elements."); return; } - points.emplace_back(PointVertex{ startPt, color }); - points.emplace_back(PointVertex{ endPt, color }); + storage.emplace_back(PointVertex{ startPt, color }); + storage.emplace_back(PointVertex{ endPt, color }); } - void SHDebugDrawSystem::DrawTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3) + void SHDebugDrawSystem::drawLineSet(std::vector& storage, const SHVec4& color, std::initializer_list pointList) { - DrawPoly(color, { pt1, pt2, pt3 }); + drawLineSet(storage, color, pointList.begin(), pointList.end()); } - void SHDebugDrawSystem::DrawQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4) + void SHDebugDrawSystem::drawPoly(std::vector& storage, const SHVec4& color, std::initializer_list pointList) { - DrawPoly(color, { pt1, pt2, pt3, pt4 }); + drawPoly(storage, color, pointList.begin(), pointList.end()); } - void SHDebugDrawSystem::DrawPoly(const SHVec4& color, std::initializer_list pointList) + void SHDebugDrawSystem::drawCube(std::vector& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& size) { - DrawPoly(color, pointList.begin(), pointList.end()); - } + static const SHVec3 EXTENTS = SHVec3{ 0.5f, 0.5f, 0.5f }; + static const SHVec3 UNIT_BOT_LEFT_FRONT = SHVec3{ pos - EXTENTS }; + static const SHVec3 UNIT_BOT_RIGHT_FRONT = SHVec3{ pos + SHVec3 { EXTENTS.x, -EXTENTS.y, -EXTENTS.z } }; + static const SHVec3 UNIT_BOT_RIGHT_BACK = SHVec3{ pos + SHVec3 { EXTENTS.x, -EXTENTS.y, EXTENTS.z } }; + static const SHVec3 UNIT_BOT_LEFT_BACK = SHVec3{ pos + SHVec3 { -EXTENTS.x, -EXTENTS.y, EXTENTS.z } }; + static const SHVec3 UNIT_TOP_LEFT_BACK = SHVec3{ pos + SHVec3 { -EXTENTS.x, EXTENTS.y, EXTENTS.z } }; + static const SHVec3 UNIT_TOP_RIGHT_FRONT = SHVec3{ pos + SHVec3 { EXTENTS.x, EXTENTS.y, -EXTENTS.z } }; + static const SHVec3 UNIT_TOP_LEFT_FRONT = SHVec3{ pos + SHVec3 { -EXTENTS.x, EXTENTS.y, -EXTENTS.z } }; + static const SHVec3 UNIT_TOP_RIGHT_BACK = SHVec3{ pos + EXTENTS }; - void SHDebugDrawSystem::DrawCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size) - { - static const SHVec3 EXTENTS = SHVec3 { 0.5f, 0.5f, 0.5f }; - static const SHVec3 UNIT_BOT_LEFT_FRONT = SHVec3 { pos - EXTENTS }; - static const SHVec3 UNIT_BOT_RIGHT_FRONT = SHVec3 { pos + SHVec3 { EXTENTS.x, -EXTENTS.y, -EXTENTS.z } }; - static const SHVec3 UNIT_BOT_RIGHT_BACK = SHVec3 { pos + SHVec3 { EXTENTS.x, -EXTENTS.y, EXTENTS.z } }; - static const SHVec3 UNIT_BOT_LEFT_BACK = SHVec3 { pos + SHVec3 { -EXTENTS.x, -EXTENTS.y, EXTENTS.z } }; - static const SHVec3 UNIT_TOP_LEFT_BACK = SHVec3 { pos + SHVec3 { -EXTENTS.x, EXTENTS.y, EXTENTS.z } }; - static const SHVec3 UNIT_TOP_RIGHT_FRONT = SHVec3 { pos + SHVec3 { EXTENTS.x, EXTENTS.y, -EXTENTS.z } }; - static const SHVec3 UNIT_TOP_LEFT_FRONT = SHVec3 { pos + SHVec3 { -EXTENTS.x, EXTENTS.y, -EXTENTS.z } }; - static const SHVec3 UNIT_TOP_RIGHT_BACK = SHVec3 { pos + EXTENTS }; - - const SHVec3 BOT_LEFT_BACK = UNIT_BOT_LEFT_BACK * size; - const SHVec3 BOT_RIGHT_BACK = UNIT_BOT_RIGHT_BACK * size; - const SHVec3 BOT_LEFT_FRONT = UNIT_BOT_LEFT_FRONT * size; + const SHVec3 BOT_LEFT_BACK = UNIT_BOT_LEFT_BACK * size; + const SHVec3 BOT_RIGHT_BACK = UNIT_BOT_RIGHT_BACK * size; + const SHVec3 BOT_LEFT_FRONT = UNIT_BOT_LEFT_FRONT * size; const SHVec3 BOT_RIGHT_FRONT = UNIT_BOT_RIGHT_FRONT * size; - const SHVec3 TOP_LEFT_BACK = UNIT_TOP_LEFT_BACK * size; - const SHVec3 TOP_RIGHT_BACK = UNIT_TOP_RIGHT_BACK * size; - const SHVec3 TOP_LEFT_FRONT = UNIT_TOP_LEFT_FRONT * size; + const SHVec3 TOP_LEFT_BACK = UNIT_TOP_LEFT_BACK * size; + const SHVec3 TOP_RIGHT_BACK = UNIT_TOP_RIGHT_BACK * size; + const SHVec3 TOP_LEFT_FRONT = UNIT_TOP_LEFT_FRONT * size; const SHVec3 TOP_RIGHT_FRONT = UNIT_TOP_RIGHT_FRONT * size; - DrawPoly + drawLineSet ( + storage, color, { // Bottom Square @@ -186,7 +310,7 @@ namespace SHADE ); } - void SHDebugDrawSystem::DrawSphere(const SHVec4& color, const SHVec3& pos, double radius) + void SHDebugDrawSystem::drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, double radius) { if (spherePoints.empty()) { @@ -197,6 +321,6 @@ namespace SHADE spherePoints.emplace_back(SPHERE.VertexPositions[idx]); } } - DrawPoly(color, spherePoints.begin(), spherePoints.end()); + drawLineSet(storage, color, spherePoints.begin(), spherePoints.end()); } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h index 4b83958d..20ddcd42 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h @@ -126,6 +126,82 @@ namespace SHADE /// Size of the rendered sphere. void DrawSphere(const SHVec4& color, const SHVec3& pos, double radius); + /*---------------------------------------------------------------------------------*/ + /* Persistent Draw Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Renders a line between two points in world space that will persist until + /// ClearPersistentDraws() is called. These lines are depth tested. + /// + /// Colour of the line. + /// First point of the line. + /// Second point of the line. + void DrawPersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt); + /// + /// Renders a triangle indicated by three points in world space that will persist + /// until ClearPersistentDraws() is called. These lines are depth tested. + /// + /// Colour of the triangle. + /// First point of the triangle. + /// Second point of the triangle. + /// Third point of the triangle. + void DrawPersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3); + /// + /// Renders a quadrilateral indicated by four points in world space that will persist + /// until ClearPersistentDraws() is called. These lines are depth tested. + /// + /// Colour of the quadrilateral. + /// First point of the triangle. + /// Second point of the quadrilateral. + /// Third point of the quadrilateral. + /// Third point of the quadrilateral. + void DrawPersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4); + /// + /// Renders a polygon indicated by the specified set of points in world space that + /// will persist until ClearPersistentDraws() is called. These lines are depth + /// tested. + /// + /// Colour of the polygon. + /// List of points for the polygon. + void DrawPersistentPoly(const SHVec4& color, std::initializer_list pointList); + /// + /// Renders a polygon indicated by the specified set of points in world space that + /// will persist until ClearPersistentDraws() is called. These lines are depth + /// tested. + /// + /// Iterator for a STL-like container. + /// Colour of the polygon. + /// + /// Iterator to the first point of the point container. + /// + /// + /// One past last iterator of the point container. + /// + template + void DrawPersistentPoly(const SHVec4& color, IterType pointListBegin, IterType pointListEnd); + /// + /// Renders a wireframe cube centered around the position specified in world space + /// that will persist until ClearPersistentDraws() is called. These lines are depth + /// tested. + /// + /// Colour of the cube. + /// Position where the cube wil be centered at. + /// Size of the rendered cube. + void DrawPersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size); + /// + /// Renders a wireframe sphere centered around the position specified in world space + /// that will persist until ClearPersistentDraws() is called. These lines are depth + /// tested. + /// + /// Colour of the sphere. + /// Position where the sphere wil be centered at. + /// Size of the rendered sphere. + void DrawPersistentSphere(const SHVec4& color, const SHVec3& pos, double radius); + /// + /// Clears any persistent drawn debug primitives. + /// + void ClearPersistentDraws(); + private: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -136,7 +212,8 @@ namespace SHADE SHVec4 Color; }; using TripleBuffer = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; - using TripleUInt = std::array; + using TripleUInt = std::array; + using TripleBool = std::array; /*---------------------------------------------------------------------------------*/ /* Constants */ @@ -148,11 +225,28 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ // CPU Buffers std::vector points; + std::vector persistentPoints; // GPU Buffers TripleBuffer vertexBuffers; TripleUInt numPoints; + TripleBuffer persistentVertexBuffers; + TripleUInt numPersistentPoints; + TripleBool persistentBuffersCleared; // Cached Points for polygon drawing std::vector spherePoints; + + /*---------------------------------------------------------------------------------*/ + /* Helper Draw Functions */ + /*---------------------------------------------------------------------------------*/ + void drawLine(std::vector& storage, const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt); + void drawLineSet(std::vector& storage, const SHVec4& color, std::initializer_list pointList); + template + void drawLineSet(std::vector& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd); + void drawPoly(std::vector& storage, const SHVec4& color, std::initializer_list pointList); + template + void drawPoly(std::vector& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd); + void drawCube(std::vector& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& size); + void drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, double radius); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.hpp index 14fbb42f..2a171e73 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.hpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.hpp @@ -20,12 +20,21 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ template void SHDebugDrawSystem::DrawPoly(const SHVec4& color, IterType pointListBegin, IterType pointListEnd) + { + drawPoly(points, color, pointListBegin, pointListEnd); + } + + /*-----------------------------------------------------------------------------------*/ + /* Helper Draw Functions */ + /*-----------------------------------------------------------------------------------*/ + template + void SHDebugDrawSystem::drawLineSet(std::vector& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd) { // Ensure dereferenced type is SHVec3 static_assert(std::is_same_v>, "Parameters to DrawPoly must be SHVec3."); // Check if points exceeded max - if (points.size() > MAX_POINTS) + if (storage.size() > MAX_POINTS) { SHLOG_WARNING("[DebugDraw] Exceeded maximum size of drawable debug elements."); return; @@ -42,7 +51,39 @@ namespace SHADE const size_t POINTS_ROUNDED_COUNT = POINTS_COUNT / 2 * 2; for (auto pointIter = pointListBegin; pointIter != (pointListBegin + POINTS_ROUNDED_COUNT); ++pointIter) { - points.emplace_back(PointVertex{ *pointIter, color }); + storage.emplace_back(PointVertex{ *pointIter, color }); } } + template + void SHDebugDrawSystem::drawPoly(std::vector& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd) + { + // Ensure dereferenced type is SHVec3 + static_assert(std::is_same_v>, "Parameters to DrawPoly must be SHVec3."); + + // Check if points exceeded max + if (storage.size() > MAX_POINTS) + { + SHLOG_WARNING("[DebugDraw] Exceeded maximum size of drawable debug elements."); + return; + } + + const size_t POINTS_COUNT = pointListEnd - pointListBegin; + // Invalid polygon + if (POINTS_COUNT < 2) + { + SHLOG_WARNING("[SHDebugDraw] Invalid polygon provided to DrawPoly()."); + return; + } + + // Trace the polygon + for (auto pointIter = pointListBegin + 1; pointIter != pointListEnd; ++pointIter) + { + storage.emplace_back(PointVertex{ *(pointIter - 1), color }); + storage.emplace_back(PointVertex{ *pointIter , color }); + } + + // Close the line loop + storage.emplace_back(PointVertex{ *(pointListEnd - 1), color }); + storage.emplace_back(PointVertex{ *pointListBegin , color }); + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index eb9269e6..153aa611 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -214,6 +214,16 @@ namespace SHADE ssaoTransferCmdBuffer->EndRecording(); graphicsQueue->SubmitCommandBuffer({ ssaoTransferCmdBuffer }); + // Set up Debug Draw Passes + // - Depth Tested + auto debugDrawNodeDepth = worldRenderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer"}); + auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth"); + debugDrawDepthSubpass->AddColorOutput("Scene"); + debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); + // - No Depth Test + auto debugDrawNode = worldRenderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" }); + auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw"); + debugDrawSubpass->AddColorOutput("Scene"); graphicsQueue->WaitIdle(); @@ -222,23 +232,18 @@ namespace SHADE Handle ssaoPass = gBufferNode->AddNodeCompute(ssaoShader, {"Position", "Normals", "SSAO"}); auto ssaoDataBuffer = ssaoStorage->GetBuffer(); ssaoPass->ModifyWriteDescBufferComputeResource(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, SHSSAO::DESC_SET_BUFFER_BINDING, { &ssaoDataBuffer, 1 }, 0, ssaoStorage->GetBuffer()->GetSizeStored()); - auto viewSamplerLayout = ssaoStorage->GetViewSamplerLayout(); + ssaoPass->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, SHSSAO::DESC_SET_IMAGE_BINDING, {&viewSamplerLayout, 1}); - Handle ssaoBlurPass = gBufferNode->AddNodeCompute(ssaoBlurShader, { "SSAO", "SSAO Blur"}); + Handle ssaoBlurPass = gBufferNode->AddNodeCompute(ssaoBlurShader, { "SSAO", "SSAO Blur"}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); - // Set up Debug Draw Pass - auto debugDrawNode = worldRenderGraph->AddNode("Debug Draw", { "Scene" }, {"G-Buffer"}); - auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw"); - debugDrawSubpass->AddColorOutput("Scene"); - // Dummy Node auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Debug Draw" }); // no predecessors auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass"); @@ -264,53 +269,8 @@ namespace SHADE defaultMaterial = AddMaterial(defaultVertShader, defaultFragShader, gBufferSubpass); // Create debug draw pipeline - auto debugDrawPipelineLayout = resourceManager.Create - ( - device, SHPipelineLayoutParams - { - .shaderModules = { debugVertShader, debugFragShader }, - .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() - } - ); - debugDrawPipeline = resourceManager.Create(device, debugDrawPipelineLayout, nullptr, debugDrawNode->GetRenderpass(), debugDrawSubpass); - debugDrawPipeline->GetPipelineState().SetRasterizationState(SHRasterizationState - { - .polygonMode = vk::PolygonMode::eLine, - .cull_mode = vk::CullModeFlagBits::eNone - }); - debugDrawPipeline->GetPipelineState().SetInputAssemblyState(SHInputAssemblyState - { - .topology = vk::PrimitiveTopology::eLineList - }); - - SHVertexInputState debugDrawVertexInputState; - debugDrawVertexInputState.AddBinding(false, true, { SHVertexAttribute(SHAttribFormat::FLOAT_4D), SHVertexAttribute(SHAttribFormat::FLOAT_4D) }); - debugDrawPipeline->GetPipelineState().SetVertexInputState(debugDrawVertexInputState); - SHColorBlendState colorBlendState{}; - colorBlendState.logic_op_enable = VK_FALSE; - colorBlendState.logic_op = vk::LogicOp::eCopy; - - auto const& subpassColorReferences = debugDrawSubpass->GetColorAttachmentReferences(); - colorBlendState.attachments.reserve(subpassColorReferences.size()); - - for (auto& att : subpassColorReferences) - { - colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState - { - .blendEnable = SHVkUtil::IsBlendCompatible(debugDrawSubpass->GetFormatFromAttachmentReference(att.attachment)), - .srcColorBlendFactor = vk::BlendFactor::eSrcAlpha, - .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, - .colorBlendOp = vk::BlendOp::eAdd, - .srcAlphaBlendFactor = vk::BlendFactor::eOne, - .dstAlphaBlendFactor = vk::BlendFactor::eZero, - .alphaBlendOp = vk::BlendOp::eAdd, - .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, - } - ); - } - - debugDrawPipeline->GetPipelineState().SetColorBlenState(colorBlendState); - debugDrawPipeline->ConstructPipeline(); + debugDrawPipeline = createDebugDrawPipeline(debugDrawNode->GetRenderpass(), debugDrawSubpass); + debugDrawDepthPipeline = createDebugDrawPipeline(debugDrawNodeDepth->GetRenderpass(), debugDrawDepthSubpass); } void SHGraphicsSystem::InitMiddleEnd(void) noexcept @@ -933,5 +893,57 @@ namespace SHADE return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); } + Handle SHGraphicsSystem::createDebugDrawPipeline(Handle renderPass, Handle subpass) + { + auto pipelineLayout = resourceManager.Create + ( + device, SHPipelineLayoutParams + { + .shaderModules = { debugVertShader, debugFragShader }, + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() + } + ); + auto pipeline = resourceManager.Create(device, pipelineLayout, nullptr, renderPass, subpass); + pipeline->GetPipelineState().SetRasterizationState(SHRasterizationState + { + .polygonMode = vk::PolygonMode::eLine, + .cull_mode = vk::CullModeFlagBits::eNone + }); + pipeline->GetPipelineState().SetInputAssemblyState(SHInputAssemblyState + { + .topology = vk::PrimitiveTopology::eLineList + }); + + SHVertexInputState debugDrawVertexInputState; + debugDrawVertexInputState.AddBinding(false, true, { SHVertexAttribute(SHAttribFormat::FLOAT_4D), SHVertexAttribute(SHAttribFormat::FLOAT_4D) }); + pipeline->GetPipelineState().SetVertexInputState(debugDrawVertexInputState); + SHColorBlendState colorBlendState{}; + colorBlendState.logic_op_enable = VK_FALSE; + colorBlendState.logic_op = vk::LogicOp::eCopy; + + auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); + colorBlendState.attachments.reserve(subpassColorReferences.size()); + + for (auto& att : subpassColorReferences) + { + colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState + { + .blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(att.attachment)), + .srcColorBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eOne, + .dstAlphaBlendFactor = vk::BlendFactor::eZero, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }); + } + + pipeline->GetPipelineState().SetColorBlenState(colorBlendState); + pipeline->ConstructPipeline(); + + return pipeline; + } + #pragma endregion MISC } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index d8b4650e..0cd4f187 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -290,6 +290,7 @@ namespace SHADE Handle GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;}; Handle GetPrimaryRenderpass() const noexcept; Handle GetDebugDrawPipeline(void) const noexcept { return debugDrawPipeline; } + Handle GetDebugDrawDepthPipeline(void) const noexcept { return debugDrawDepthPipeline; } uint32_t GetCurrentFrameIndex(void) const noexcept { return renderContext.GetCurrentFrame(); } /*-----------------------------------------------------------------------------*/ @@ -360,6 +361,7 @@ namespace SHADE // Built-In Materials Handle defaultMaterial; Handle debugDrawPipeline; + Handle debugDrawDepthPipeline; Handle worldRenderGraph; @@ -373,5 +375,9 @@ namespace SHADE uint32_t resizeHeight = 1; bool restoredFromMinimize = false; + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + Handle createDebugDrawPipeline(Handle renderPass, Handle subpass); }; } \ No newline at end of file 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/SHDebugDraw.cpp b/SHADE_Engine/src/Tools/SHDebugDraw.cpp index a5b86c42..b8aa8b0e 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.cpp +++ b/SHADE_Engine/src/Tools/SHDebugDraw.cpp @@ -25,7 +25,7 @@ namespace SHADE /* Static Member Definitions */ /*-----------------------------------------------------------------------------------*/ SHDebugDrawSystem* SHDebugDraw::dbgDrawSys = nullptr; - + /*-----------------------------------------------------------------------------------*/ /* Lifecycle Functions */ /*-----------------------------------------------------------------------------------*/ @@ -70,4 +70,40 @@ namespace SHADE { dbgDrawSys->DrawSphere(color, pos, radius); } + + void SHDebugDraw::PersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt) + { + dbgDrawSys->DrawPersistentLine(color, startPt, endPt); + } + + void SHDebugDraw::PersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3) + { + dbgDrawSys->DrawPersistentTri(color, pt1, pt2, pt3); + } + + void SHDebugDraw::PersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4) + { + dbgDrawSys->DrawPersistentQuad(color, pt1, pt2, pt3, pt4); + } + + void SHDebugDraw::PersistentPoly(const SHVec4& color, std::initializer_list pointList) + { + dbgDrawSys->DrawPersistentPoly(color, pointList); + } + + void SHDebugDraw::PersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size) + { + dbgDrawSys->DrawPersistentCube(color, pos, size); + } + + void SHDebugDraw::PersistentSphere(const SHVec4& color, const SHVec3& pos, double radius) + { + dbgDrawSys->DrawPersistentSphere(color, pos, radius); + } + + void SHDebugDraw::ClearPersistentDraws() + { + dbgDrawSys->ClearPersistentDraws(); + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.h b/SHADE_Engine/src/Tools/SHDebugDraw.h index 7ce44ec2..04504c3a 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.h +++ b/SHADE_Engine/src/Tools/SHDebugDraw.h @@ -92,6 +92,64 @@ namespace SHADE /// Size of the rendered sphere. static void Sphere(const SHVec4& color, const SHVec3& pos, double radius); + /*---------------------------------------------------------------------------------*/ + /* Persistent Draw Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Renders a line between two points in world space that will persist until + /// ClearPersistentDraws() is called. + /// + /// Colour of the line. + /// First point of the line. + /// Second point of the line. + static void PersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt); + /// + /// Renders a triangle indicated by three points in world space that will persist + /// until ClearPersistentDraws() is called. + /// + /// Colour of the triangle. + /// First point of the triangle. + /// Second point of the triangle. + /// Third point of the triangle. + static void PersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3); + /// + /// Renders a quadrilateral indicated by four points in world space that will persist + /// until ClearPersistentDraws() is called. + /// + /// Colour of the quadrilateral. + /// First point of the triangle. + /// Second point of the quadrilateral. + /// Third point of the quadrilateral. + /// Third point of the quadrilateral. + static void PersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4); + /// + /// Renders a polygon indicated by the specified set of points in world space that + /// will persist until ClearPersistentDraws() is called. + /// + /// Colour of the polygon. + /// List of points for the polygon. + static void PersistentPoly(const SHVec4& color, std::initializer_list pointList); + /// + /// Renders a wireframe cube centered around the position specified in world space + /// that will persist until ClearPersistentDraws() is called. + /// + /// Colour of the cube. + /// Position where the cube wil be centered at. + /// Size of the rendered cube. + static void PersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size); + /// + /// Renders a wireframe sphere centered around the position specified in world space + /// that will persist until ClearPersistentDraws() is called. + /// + /// Colour of the sphere. + /// Position where the sphere wil be centered at. + /// Size of the rendered sphere. + static void PersistentSphere(const SHVec4& color, const SHVec3& pos, double radius); + /// + /// Clears any persistent drawn debug primitives. + /// + static void ClearPersistentDraws(); + private: /*---------------------------------------------------------------------------------*/ /* Static Data Members */ 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; /**