Merge pull request #162 from SHADE-DP/SP3-1-DebugDraw2

Added editor gridlines and fixed SHDebugDraw::DrawPoly()
This commit is contained in:
XiaoQiDigipen 2022-11-02 16:30:53 +08:00 committed by GitHub
commit 3175d4c3a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 588 additions and 109 deletions

View File

@ -72,6 +72,9 @@ namespace Sandbox
SHSystemManager::CreateSystem<SHAudioSystem>();
SHSystemManager::CreateSystem<SHCameraSystem>();
SHSystemManager::CreateSystem<SHDebugDrawSystem>();
// Link up SHDebugDraw
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
#ifdef SHEDITOR
SDL_Init(SDL_INIT_VIDEO);
@ -127,9 +130,6 @@ namespace Sandbox
SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC();
// Link up SHDebugDraw
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
}
void SBApplication::Update(void)

View File

@ -46,6 +46,7 @@
#include <backends/imgui_impl_vulkan.h>
#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<SHEventReceiverSpec<SHEditor>> stateChangeEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHEditor>>(this, &SHEditor::onEditorStateChanged)
};
SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(stateChangeEventReceiver));
SHEventManager::SubscribeTo(SH_EDITOR_ON_PAUSE_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(stateChangeEventReceiver));
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(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<int>(500.0f /* TODO: Remove hard code */ / DELTA);
static constexpr float LINE_HALF_LENGTH = (DELTA * static_cast<float>(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<const SHEventSpec<SHEditorStateChangeEvent>*>(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)

View File

@ -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<SHVkCommandPool> imguiCommandPool;
// Handle to command buffer used for ImGui Vulkan Backend

View File

@ -43,20 +43,41 @@ namespace SHADE
return;
}
// Get the system
SHDebugDrawSystem* system = static_cast<SHDebugDrawSystem*>(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<SHDebugDrawSystem*>(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<SHVkCommandBuffer>& 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<SHVkBuffer>& 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<SHVkBuffer>& 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<SHVec3> 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<SHVec3> 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<PointVertex>& 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<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> 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<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList)
{
DrawPoly(color, { pt1, pt2, pt3, pt4 });
drawPoly(storage, color, pointList.begin(), pointList.end());
}
void SHDebugDrawSystem::DrawPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList)
void SHDebugDrawSystem::drawCube(std::vector<PointVertex>& 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<PointVertex>& 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());
}
}

View File

@ -126,6 +126,82 @@ namespace SHADE
/// <param name="size">Size of the rendered sphere.</param>
void DrawSphere(const SHVec4& color, const SHVec3& pos, double radius);
/*---------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Renders a line between two points in world space that will persist until
/// ClearPersistentDraws() is called. These lines are depth tested.
/// </summary>
/// <param name="color">Colour of the line.</param>
/// <param name="startPt">First point of the line.</param>
/// <param name="endPt">Second point of the line.</param>
void DrawPersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt);
/// <summary>
/// Renders a triangle indicated by three points in world space that will persist
/// until ClearPersistentDraws() is called. These lines are depth tested.
/// </summary>
/// <param name="color">Colour of the triangle.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the triangle.</param>
/// <param name="pt3">Third point of the triangle.</param>
void DrawPersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3);
/// <summary>
/// Renders a quadrilateral indicated by four points in world space that will persist
/// until ClearPersistentDraws() is called. These lines are depth tested.
/// </summary>
/// <param name="color">Colour of the quadrilateral.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the quadrilateral.</param>
/// <param name="pt3">Third point of the quadrilateral.</param>
/// <param name="pt4">Third point of the quadrilateral.</param>
void DrawPersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4);
/// <summary>
/// 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.
/// </summary>
/// <param name="color">Colour of the polygon.</param>
/// <param name="pointList">List of points for the polygon.</param>
void DrawPersistentPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList);
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="IterType">Iterator for a STL-like container.</typeparam>
/// <param name="color">Colour of the polygon.</param>
/// <param name="pointListBegin">
/// Iterator to the first point of the point container.
/// </param>
/// <param name="pointListEnd">
/// One past last iterator of the point container.
/// </param>
template<typename IterType>
void DrawPersistentPoly(const SHVec4& color, IterType pointListBegin, IterType pointListEnd);
/// <summary>
/// Renders a wireframe cube centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called. These lines are depth
/// tested.
/// </summary>
/// <param name="color">Colour of the cube.</param>
/// <param name="pos">Position where the cube wil be centered at.</param>
/// <param name="size">Size of the rendered cube.</param>
void DrawPersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size);
/// <summary>
/// Renders a wireframe sphere centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called. These lines are depth
/// tested.
/// </summary>
/// <param name="color">Colour of the sphere.</param>
/// <param name="pos">Position where the sphere wil be centered at.</param>
/// <param name="size">Size of the rendered sphere.</param>
void DrawPersistentSphere(const SHVec4& color, const SHVec3& pos, double radius);
/// <summary>
/// Clears any persistent drawn debug primitives.
/// </summary>
void ClearPersistentDraws();
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -136,7 +212,8 @@ namespace SHADE
SHVec4 Color;
};
using TripleBuffer = std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleUInt = std::array<uint32_t, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleUInt = std::array<uint32_t , SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleBool = std::array<bool , SHGraphicsConstants::NUM_FRAME_BUFFERS>;
/*---------------------------------------------------------------------------------*/
/* Constants */
@ -148,11 +225,28 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
// CPU Buffers
std::vector<PointVertex> points;
std::vector<PointVertex> persistentPoints;
// GPU Buffers
TripleBuffer vertexBuffers;
TripleUInt numPoints;
TripleBuffer persistentVertexBuffers;
TripleUInt numPersistentPoints;
TripleBool persistentBuffersCleared;
// Cached Points for polygon drawing
std::vector<SHVec3> spherePoints;
/*---------------------------------------------------------------------------------*/
/* Helper Draw Functions */
/*---------------------------------------------------------------------------------*/
void drawLine(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt);
void drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList);
template<typename IterType>
void drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd);
void drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList);
template<typename IterType>
void drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd);
void drawCube(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& size);
void drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius);
};
}

View File

@ -20,12 +20,21 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
template<typename IterType>
void SHDebugDrawSystem::DrawPoly(const SHVec4& color, IterType pointListBegin, IterType pointListEnd)
{
drawPoly(points, color, pointListBegin, pointListEnd);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Draw Functions */
/*-----------------------------------------------------------------------------------*/
template<typename IterType>
void SHDebugDrawSystem::drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd)
{
// Ensure dereferenced type is SHVec3
static_assert(std::is_same_v<SHVec3, std::remove_cvref_t<decltype(*pointListBegin)>>, "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<typename IterType>
void SHDebugDrawSystem::drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd)
{
// Ensure dereferenced type is SHVec3
static_assert(std::is_same_v<SHVec3, std::remove_cvref_t<decltype(*pointListBegin)>>, "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 });
}
}

View File

@ -171,7 +171,7 @@ namespace SHADE
"Normals",
"Albedo",
"Depth Buffer",
"Scene"
"Scene"
},
{}); // no predecessors
@ -186,8 +186,14 @@ namespace SHADE
// deferred composite
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" });
// Set up Debug Draw Pass
auto debugDrawNode = worldRenderGraph->AddNode("Debug Draw", { "Scene" }, {"G-Buffer"});
// 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");
@ -209,53 +215,8 @@ namespace SHADE
defaultMaterial = AddMaterial(defaultVertShader, defaultFragShader, gBufferSubpass);
// Create debug draw pipeline
auto debugDrawPipelineLayout = resourceManager.Create<SHVkPipelineLayout>
(
device, SHPipelineLayoutParams
{
.shaderModules = { debugVertShader, debugFragShader },
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
}
);
debugDrawPipeline = resourceManager.Create<SHVkPipeline>(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
@ -867,5 +828,57 @@ namespace SHADE
return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data());
}
Handle<SHVkPipeline> SHGraphicsSystem::createDebugDrawPipeline(Handle<SHVkRenderpass> renderPass, Handle<SHSubpass> subpass)
{
auto pipelineLayout = resourceManager.Create<SHVkPipelineLayout>
(
device, SHPipelineLayoutParams
{
.shaderModules = { debugVertShader, debugFragShader },
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
}
);
auto pipeline = resourceManager.Create<SHVkPipeline>(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
}

View File

@ -289,6 +289,7 @@ namespace SHADE
Handle<SHPostOffscreenRenderSystem> GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;};
Handle<SHRenderGraphNode> GetPrimaryRenderpass() const noexcept;
Handle<SHVkPipeline> GetDebugDrawPipeline(void) const noexcept { return debugDrawPipeline; }
Handle<SHVkPipeline> GetDebugDrawDepthPipeline(void) const noexcept { return debugDrawDepthPipeline; }
uint32_t GetCurrentFrameIndex(void) const noexcept { return renderContext.GetCurrentFrame(); }
/*-----------------------------------------------------------------------------*/
@ -355,6 +356,7 @@ namespace SHADE
// Built-In Materials
Handle<SHMaterial> defaultMaterial;
Handle<SHVkPipeline> debugDrawPipeline;
Handle<SHVkPipeline> debugDrawDepthPipeline;
Handle<SHRenderGraph> worldRenderGraph;
@ -367,5 +369,9 @@ namespace SHADE
uint32_t resizeHeight;
bool restoredFromMinimize = false;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHVkPipeline> createDebugDrawPipeline(Handle<SHVkRenderpass> renderPass, Handle<SHSubpass> subpass);
};
}

View File

@ -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<SHVec3> 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();
}
}

View File

@ -92,6 +92,64 @@ namespace SHADE
/// <param name="size">Size of the rendered sphere.</param>
static void Sphere(const SHVec4& color, const SHVec3& pos, double radius);
/*---------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Renders a line between two points in world space that will persist until
/// ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the line.</param>
/// <param name="startPt">First point of the line.</param>
/// <param name="endPt">Second point of the line.</param>
static void PersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt);
/// <summary>
/// Renders a triangle indicated by three points in world space that will persist
/// until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the triangle.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the triangle.</param>
/// <param name="pt3">Third point of the triangle.</param>
static void PersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3);
/// <summary>
/// Renders a quadrilateral indicated by four points in world space that will persist
/// until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the quadrilateral.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the quadrilateral.</param>
/// <param name="pt3">Third point of the quadrilateral.</param>
/// <param name="pt4">Third point of the quadrilateral.</param>
static void PersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4);
/// <summary>
/// Renders a polygon indicated by the specified set of points in world space that
/// will persist until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the polygon.</param>
/// <param name="pointList">List of points for the polygon.</param>
static void PersistentPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList);
/// <summary>
/// Renders a wireframe cube centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the cube.</param>
/// <param name="pos">Position where the cube wil be centered at.</param>
/// <param name="size">Size of the rendered cube.</param>
static void PersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size);
/// <summary>
/// Renders a wireframe sphere centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the sphere.</param>
/// <param name="pos">Position where the sphere wil be centered at.</param>
/// <param name="size">Size of the rendered sphere.</param>
static void PersistentSphere(const SHVec4& color, const SHVec3& pos, double radius);
/// <summary>
/// Clears any persistent drawn debug primitives.
/// </summary>
static void ClearPersistentDraws();
private:
/*---------------------------------------------------------------------------------*/
/* Static Data Members */