feat: add line renderer / visualisations for box collidors as a test
This commit is contained in:
@@ -37,12 +37,14 @@ set(SRC_FILES
|
|||||||
"src/Graphics/Managers/MemoryManager.cpp"
|
"src/Graphics/Managers/MemoryManager.cpp"
|
||||||
"src/Graphics/Managers/FrameManager.cpp"
|
"src/Graphics/Managers/FrameManager.cpp"
|
||||||
"src/Graphics/Managers/ImageManager.cpp"
|
"src/Graphics/Managers/ImageManager.cpp"
|
||||||
|
"src/Graphics/Managers/LineRenderingManager.cpp"
|
||||||
|
|
||||||
"src/Graphics/Resources/GPUImage.cpp"
|
"src/Graphics/Resources/GPUImage.cpp"
|
||||||
"src/Graphics/Resources/NBuffer.cpp"
|
"src/Graphics/Resources/NBuffer.cpp"
|
||||||
"src/Graphics/Resources/Cubemap.cpp"
|
"src/Graphics/Resources/Cubemap.cpp"
|
||||||
|
|
||||||
"src/Graphics/Pipelines/MeshPipeline.cpp"
|
"src/Graphics/Pipelines/MeshPipeline.cpp"
|
||||||
|
"src/Graphics/Pipelines/LineRenderingPass.cpp"
|
||||||
"src/Graphics/Pipelines/SkyboxPipeline.cpp"
|
"src/Graphics/Pipelines/SkyboxPipeline.cpp"
|
||||||
"src/Graphics/Pipelines/SkinningPipeline.cpp"
|
"src/Graphics/Pipelines/SkinningPipeline.cpp"
|
||||||
"src/Graphics/Pipelines/ImguiPass.cpp"
|
"src/Graphics/Pipelines/ImguiPass.cpp"
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) in vec4 inColor;
|
||||||
|
layout (location = 0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outFragColor = inColor;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) in vec4 inPosition;
|
||||||
|
layout (location = 1) in vec4 inColor;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout (push_constant) uniform LinePushConstants {
|
||||||
|
mat4 viewProjection;
|
||||||
|
} pcs;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = pcs.viewProjection * inPosition;
|
||||||
|
outColor = inColor;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef DESTRUM_LINERENDERINGMANAGER_H
|
||||||
|
#define DESTRUM_LINERENDERINGMANAGER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
|
||||||
|
#include <destrum/Singleton.h>
|
||||||
|
|
||||||
|
struct Line {
|
||||||
|
glm::vec3 start{};
|
||||||
|
glm::vec3 end{};
|
||||||
|
glm::vec4 color{1.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
class LineRenderingManager final : public Singleton<LineRenderingManager> {
|
||||||
|
public:
|
||||||
|
friend class Singleton<LineRenderingManager>;
|
||||||
|
|
||||||
|
void SubmitLine(const Line& line);
|
||||||
|
void SubmitLine(
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& end,
|
||||||
|
const glm::vec4& color = glm::vec4{1.0f});
|
||||||
|
|
||||||
|
[[nodiscard]] const std::vector<Line>& GetLines() const { return lines; }
|
||||||
|
|
||||||
|
void ClearLines();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LineRenderingManager() = default;
|
||||||
|
|
||||||
|
std::vector<Line> lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DESTRUM_LINERENDERINGMANAGER_H
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef DESTRUM_LINERENDERINGPASS_H
|
||||||
|
#define DESTRUM_LINERENDERINGPASS_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||||
|
#include <destrum/Graphics/Resources/NBuffer.h>
|
||||||
|
|
||||||
|
class Camera;
|
||||||
|
class GfxDevice;
|
||||||
|
struct GPUImage;
|
||||||
|
class Pipeline;
|
||||||
|
|
||||||
|
class LineRenderingPass final {
|
||||||
|
public:
|
||||||
|
void init(GfxDevice& gfxDevice, VkFormat drawImageFormat);
|
||||||
|
void draw(
|
||||||
|
VkCommandBuffer cmd,
|
||||||
|
GfxDevice& gfxDevice,
|
||||||
|
const GPUImage& target,
|
||||||
|
const Camera& camera,
|
||||||
|
LineRenderingManager& lineManager);
|
||||||
|
void cleanup(GfxDevice& gfxDevice);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LineVertex {
|
||||||
|
glm::vec4 position;
|
||||||
|
glm::vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ensureVertexCapacity(GfxDevice& gfxDevice, std::size_t requiredVertices);
|
||||||
|
|
||||||
|
VkPipelineLayout pipelineLayout{VK_NULL_HANDLE};
|
||||||
|
std::unique_ptr<Pipeline> pipeline;
|
||||||
|
NBuffer vertexBuffer;
|
||||||
|
std::size_t vertexCapacity{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DESTRUM_LINERENDERINGPASS_H
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <glm/vec3.hpp>
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
#include <destrum/Graphics/Camera.h>
|
#include <destrum/Graphics/Camera.h>
|
||||||
|
#include <destrum/Graphics/Pipelines/LineRenderingPass.h>
|
||||||
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
||||||
#include <destrum/Graphics/ids.h>
|
#include <destrum/Graphics/ids.h>
|
||||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||||
@@ -111,6 +112,7 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<MeshPipeline> meshPipeline;
|
std::unique_ptr<MeshPipeline> meshPipeline;
|
||||||
std::unique_ptr<SkyboxPipeline> skyboxPipeline;
|
std::unique_ptr<SkyboxPipeline> skyboxPipeline;
|
||||||
|
std::unique_ptr<LineRenderingPass> lineRenderingPass;
|
||||||
|
|
||||||
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
||||||
bool initialized{false};
|
bool initialized{false};
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||||
|
|
||||||
|
void LineRenderingManager::SubmitLine(const Line& line)
|
||||||
|
{
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRenderingManager::SubmitLine(
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& end,
|
||||||
|
const glm::vec4& color)
|
||||||
|
{
|
||||||
|
SubmitLine(Line{
|
||||||
|
.start = start,
|
||||||
|
.end = end,
|
||||||
|
.color = color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRenderingManager::ClearLines()
|
||||||
|
{
|
||||||
|
lines.clear();
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
#include <destrum/Graphics/Pipelines/LineRenderingPass.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <destrum/FS/AssetFS.h>
|
||||||
|
#include <destrum/Graphics/Camera.h>
|
||||||
|
#include <destrum/Graphics/GPUImage.h>
|
||||||
|
#include <destrum/Graphics/GfxDevice.h>
|
||||||
|
#include <destrum/Graphics/Pipeline.h>
|
||||||
|
#include <destrum/Graphics/Util.h>
|
||||||
|
|
||||||
|
#include "volk.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr std::size_t InitialVertexCapacity = 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRenderingPass::init(GfxDevice& gfxDevice, VkFormat drawImageFormat)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
vertexBuffer.init(
|
||||||
|
gfxDevice,
|
||||||
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
|
InitialVertexCapacity * sizeof(LineVertex),
|
||||||
|
"line vertices");
|
||||||
|
vertexCapacity = InitialVertexCapacity;
|
||||||
|
|
||||||
|
const auto vertexShader =
|
||||||
|
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/line.vert");
|
||||||
|
const auto fragmentShader =
|
||||||
|
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/line.frag");
|
||||||
|
|
||||||
|
const auto pushConstantRange = VkPushConstantRange{
|
||||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.offset = 0,
|
||||||
|
.size = sizeof(glm::mat4),
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto pipelineLayoutInfo = VkPipelineLayoutCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.pushConstantRangeCount = 1,
|
||||||
|
.pPushConstantRanges = &pushConstantRange,
|
||||||
|
};
|
||||||
|
|
||||||
|
VK_CHECK(vkCreatePipelineLayout(
|
||||||
|
gfxDevice.getDevice(),
|
||||||
|
&pipelineLayoutInfo,
|
||||||
|
nullptr,
|
||||||
|
&pipelineLayout));
|
||||||
|
|
||||||
|
PipelineConfigInfo pipelineConfig{};
|
||||||
|
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
|
||||||
|
pipelineConfig.name = "Line Rendering Pipeline";
|
||||||
|
pipelineConfig.pipelineLayout = pipelineLayout;
|
||||||
|
pipelineConfig.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||||
|
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
|
||||||
|
pipelineConfig.depthStencilInfo.depthTestEnable = VK_FALSE;
|
||||||
|
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
|
||||||
|
pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
pipelineConfig.colorAttachments = {drawImageFormat};
|
||||||
|
pipelineConfig.depthAttachment = VK_FORMAT_UNDEFINED;
|
||||||
|
|
||||||
|
pipelineConfig.vertexBindingDescriptions = {
|
||||||
|
VkVertexInputBindingDescription{
|
||||||
|
.binding = 0,
|
||||||
|
.stride = sizeof(LineVertex),
|
||||||
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pipelineConfig.vertexAttributeDescriptions = {
|
||||||
|
VkVertexInputAttributeDescription{
|
||||||
|
.location = 0,
|
||||||
|
.binding = 0,
|
||||||
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||||
|
.offset = offsetof(LineVertex, position),
|
||||||
|
},
|
||||||
|
VkVertexInputAttributeDescription{
|
||||||
|
.location = 1,
|
||||||
|
.binding = 0,
|
||||||
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||||
|
.offset = offsetof(LineVertex, color),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pipelineConfig.colorBlendAttachment.blendEnable = VK_TRUE;
|
||||||
|
pipelineConfig.colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
pipelineConfig.colorBlendAttachment.dstColorBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
pipelineConfig.colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
pipelineConfig.colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
pipelineConfig.colorBlendAttachment.dstAlphaBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
pipelineConfig.colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
|
||||||
|
pipeline = std::make_unique<Pipeline>(
|
||||||
|
gfxDevice,
|
||||||
|
vertexShader.string(),
|
||||||
|
fragmentShader.string(),
|
||||||
|
pipelineConfig);
|
||||||
|
} catch (...) {
|
||||||
|
cleanup(gfxDevice);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRenderingPass::draw(
|
||||||
|
VkCommandBuffer cmd,
|
||||||
|
GfxDevice& gfxDevice,
|
||||||
|
const GPUImage& target,
|
||||||
|
const Camera& camera,
|
||||||
|
LineRenderingManager& lineManager)
|
||||||
|
{
|
||||||
|
const auto& lines = lineManager.GetLines();
|
||||||
|
if (!pipeline || lines.empty()) {
|
||||||
|
lineManager.ClearLines();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.size() > std::numeric_limits<std::size_t>::max() / 2) {
|
||||||
|
throw std::overflow_error("Too many lines submitted for rendering");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LineVertex> vertices;
|
||||||
|
vertices.reserve(lines.size() * 2);
|
||||||
|
for (const Line& line : lines) {
|
||||||
|
vertices.push_back(LineVertex{
|
||||||
|
.position = glm::vec4{line.start, 1.0f},
|
||||||
|
.color = line.color,
|
||||||
|
});
|
||||||
|
vertices.push_back(LineVertex{
|
||||||
|
.position = glm::vec4{line.end, 1.0f},
|
||||||
|
.color = line.color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertices.size() > std::numeric_limits<std::uint32_t>::max()) {
|
||||||
|
throw std::overflow_error("Too many line vertices submitted for rendering");
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureVertexCapacity(gfxDevice, vertices.size());
|
||||||
|
vertexBuffer.uploadNewData(
|
||||||
|
cmd,
|
||||||
|
gfxDevice.getCurrentFrameIndex(),
|
||||||
|
vertices.data(),
|
||||||
|
vertices.size() * sizeof(LineVertex));
|
||||||
|
|
||||||
|
auto renderInfo = vkutil::createRenderingInfo({
|
||||||
|
.renderExtent = target.getExtent2D(),
|
||||||
|
.colorImageView = target.imageView,
|
||||||
|
});
|
||||||
|
|
||||||
|
vkCmdBeginRendering(cmd, &renderInfo.renderingInfo);
|
||||||
|
|
||||||
|
pipeline->bind(cmd);
|
||||||
|
|
||||||
|
const auto viewport = VkViewport{
|
||||||
|
.x = 0.0f,
|
||||||
|
.y = 0.0f,
|
||||||
|
.width = static_cast<float>(target.extent.width),
|
||||||
|
.height = static_cast<float>(target.extent.height),
|
||||||
|
.minDepth = 0.0f,
|
||||||
|
.maxDepth = 1.0f,
|
||||||
|
};
|
||||||
|
vkCmdSetViewport(cmd, 0, 1, &viewport);
|
||||||
|
|
||||||
|
const auto scissor = VkRect2D{
|
||||||
|
.offset = {},
|
||||||
|
.extent = target.getExtent2D(),
|
||||||
|
};
|
||||||
|
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||||
|
vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL);
|
||||||
|
|
||||||
|
const glm::mat4 viewProjection = camera.GetViewProjectionMatrix();
|
||||||
|
vkCmdPushConstants(
|
||||||
|
cmd,
|
||||||
|
pipelineLayout,
|
||||||
|
VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
0,
|
||||||
|
sizeof(viewProjection),
|
||||||
|
&viewProjection);
|
||||||
|
|
||||||
|
const VkBuffer vertexBufferHandle = vertexBuffer.getBuffer().buffer;
|
||||||
|
const VkDeviceSize vertexBufferOffset = 0;
|
||||||
|
vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBufferHandle, &vertexBufferOffset);
|
||||||
|
vkCmdDraw(cmd, static_cast<std::uint32_t>(vertices.size()), 1, 0, 0);
|
||||||
|
|
||||||
|
vkCmdEndRendering(cmd);
|
||||||
|
lineManager.ClearLines();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRenderingPass::cleanup(GfxDevice& gfxDevice)
|
||||||
|
{
|
||||||
|
pipeline.reset();
|
||||||
|
|
||||||
|
if (pipelineLayout != VK_NULL_HANDLE && gfxDevice.getDevice() != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineLayout(gfxDevice.getDevice(), pipelineLayout, nullptr);
|
||||||
|
}
|
||||||
|
pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
vertexBuffer.cleanup(gfxDevice);
|
||||||
|
vertexCapacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRenderingPass::ensureVertexCapacity(
|
||||||
|
GfxDevice& gfxDevice,
|
||||||
|
std::size_t requiredVertices)
|
||||||
|
{
|
||||||
|
if (requiredVertices <= vertexCapacity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t newCapacity = std::max(vertexCapacity, InitialVertexCapacity);
|
||||||
|
while (newCapacity < requiredVertices) {
|
||||||
|
if (newCapacity > std::numeric_limits<std::size_t>::max() / 2) {
|
||||||
|
newCapacity = requiredVertices;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newCapacity *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxDevice.waitIdle();
|
||||||
|
vertexBuffer.cleanup(gfxDevice);
|
||||||
|
vertexBuffer.init(
|
||||||
|
gfxDevice,
|
||||||
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
|
newCapacity * sizeof(LineVertex),
|
||||||
|
"line vertices");
|
||||||
|
vertexCapacity = newCapacity;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <destrum/Graphics/Renderer.h>
|
#include <destrum/Graphics/Renderer.h>
|
||||||
|
|
||||||
|
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||||
#include <destrum/Graphics/Util.h>
|
#include <destrum/Graphics/Util.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -36,6 +37,9 @@ void GameRenderer::init(GfxDevice& gfxDevice, RenderResources& _resources, glm::
|
|||||||
skinningPipeline = std::make_unique<SkinningPipeline>();
|
skinningPipeline = std::make_unique<SkinningPipeline>();
|
||||||
skinningPipeline->init(gfxDevice);
|
skinningPipeline->init(gfxDevice);
|
||||||
|
|
||||||
|
lineRenderingPass = std::make_unique<LineRenderingPass>();
|
||||||
|
lineRenderingPass->init(gfxDevice, drawImageFormat);
|
||||||
|
|
||||||
GameState::GetInstance().SetRenderer(this);
|
GameState::GetInstance().SetRenderer(this);
|
||||||
initialized = true;
|
initialized = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@@ -194,6 +198,17 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
vkCmdEndRendering(cmd);
|
vkCmdEndRendering(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "LineRenderingPass::draw");
|
||||||
|
|
||||||
|
lineRenderingPass->draw(
|
||||||
|
cmd,
|
||||||
|
gfxDevice,
|
||||||
|
drawImage,
|
||||||
|
camera,
|
||||||
|
LineRenderingManager::GetInstance());
|
||||||
|
}
|
||||||
// vkutil::cmdEndLabel(cmd);
|
// vkutil::cmdEndLabel(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +223,9 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
|
|||||||
if (skinningPipeline)
|
if (skinningPipeline)
|
||||||
skinningPipeline->cleanup(gfxDevice);
|
skinningPipeline->cleanup(gfxDevice);
|
||||||
|
|
||||||
|
if (lineRenderingPass)
|
||||||
|
lineRenderingPass->cleanup(gfxDevice);
|
||||||
|
|
||||||
if (skyboxPipeline)
|
if (skyboxPipeline)
|
||||||
skyboxPipeline->cleanup(device);
|
skyboxPipeline->cleanup(device);
|
||||||
|
|
||||||
@@ -228,6 +246,7 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
|
|||||||
meshPipeline.reset();
|
meshPipeline.reset();
|
||||||
skyboxPipeline.reset();
|
skyboxPipeline.reset();
|
||||||
skinningPipeline.reset();
|
skinningPipeline.reset();
|
||||||
|
lineRenderingPass.reset();
|
||||||
pendingMaterialUploads.clear();
|
pendingMaterialUploads.clear();
|
||||||
meshDrawCommands.clear();
|
meshDrawCommands.clear();
|
||||||
sortedMeshDrawCommands.clear();
|
sortedMeshDrawCommands.clear();
|
||||||
|
|||||||
@@ -21,7 +21,14 @@ public:
|
|||||||
void customFixedUpdate(float dt) override;
|
void customFixedUpdate(float dt) override;
|
||||||
|
|
||||||
void onWindowResize(int newWidth, int newHeight) override;
|
void onWindowResize(int newWidth, int newHeight) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void drawDebugMenuBar();
|
||||||
|
void saveCurrentScene();
|
||||||
|
void loadScene();
|
||||||
|
void createEmptyScene();
|
||||||
|
void submitBoxColliderDebugLines();
|
||||||
|
|
||||||
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
|
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
|
||||||
|
|
||||||
MeshID sphereMesh;
|
MeshID sphereMesh;
|
||||||
@@ -34,6 +41,7 @@ private:
|
|||||||
char scenePath[512]{"scenes/debug_scene.json"};
|
char scenePath[512]{"scenes/debug_scene.json"};
|
||||||
char newSceneName[128]{"EmptyScene"};
|
char newSceneName[128]{"EmptyScene"};
|
||||||
std::string sceneStatus;
|
std::string sceneStatus;
|
||||||
|
bool renderBoxColliders{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //LIGHTKEEPER_H
|
#endif //LIGHTKEEPER_H
|
||||||
|
|||||||
+122
-10
@@ -1,7 +1,9 @@
|
|||||||
#include "Lightkeeper.h"
|
#include "Lightkeeper.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <destrum/FS/AssetFS.h>
|
#include <destrum/FS/AssetFS.h>
|
||||||
#include <destrum/Assets/AssetManager.h>
|
#include <destrum/Assets/AssetManager.h>
|
||||||
|
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||||
#include "glm/gtx/transform.hpp"
|
#include "glm/gtx/transform.hpp"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include <destrum/Components/Physics/Rigidbody.h>
|
#include <destrum/Components/Physics/Rigidbody.h>
|
||||||
@@ -446,11 +448,18 @@ void LightKeeper::customUpdate(float dt)
|
|||||||
SceneManager::GetInstance().Update(dt);
|
SceneManager::GetInstance().Update(dt);
|
||||||
SceneManager::GetInstance().LateUpdate(dt);
|
SceneManager::GetInstance().LateUpdate(dt);
|
||||||
|
|
||||||
|
if (m_params.showDebugUi) {
|
||||||
|
drawDebugMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
LineRenderingManager::GetInstance().SubmitLine({0, 0, 0}, {0, 10, 0}, {255, 0, 0, 255});
|
||||||
|
|
||||||
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_1))
|
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_1))
|
||||||
{
|
{
|
||||||
renderer.setRenderWireframe(!renderer.getRenderWireframe());
|
renderer.setRenderWireframe(!renderer.getRenderWireframe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_params.showDebugUi) {
|
||||||
ImGui::Begin("Test");
|
ImGui::Begin("Test");
|
||||||
if (ImGui::Button("SPawn ball"))
|
if (ImGui::Button("SPawn ball"))
|
||||||
{
|
{
|
||||||
@@ -470,12 +479,54 @@ void LightKeeper::customUpdate(float dt)
|
|||||||
SceneManager::GetInstance().GetCurrentScene().GetPhysics().RefreshGameObject(*sphere);
|
SceneManager::GetInstance().GetCurrentScene().GetPhysics().RefreshGameObject(*sphere);
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Begin("Scene Debug");
|
void LightKeeper::drawDebugMenuBar()
|
||||||
|
{
|
||||||
|
if (!ImGui::BeginMainMenuBar()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("File")) {
|
||||||
|
ImGui::TextDisabled("Scene");
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(320.0f);
|
||||||
ImGui::InputText("Scene path", scenePath, sizeof(scenePath));
|
ImGui::InputText("Scene path", scenePath, sizeof(scenePath));
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(320.0f);
|
||||||
ImGui::InputText("New scene name", newSceneName, sizeof(newSceneName));
|
ImGui::InputText("New scene name", newSceneName, sizeof(newSceneName));
|
||||||
|
|
||||||
if (ImGui::Button("Save Current Scene")) {
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("New Empty Scene")) {
|
||||||
|
createEmptyScene();
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Load")) {
|
||||||
|
loadScene();
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Save")) {
|
||||||
|
saveCurrentScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sceneStatus.empty()) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextWrapped("%s", sceneStatus.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Render")) {
|
||||||
|
ImGui::MenuItem("Box Colliders", nullptr, &renderBoxColliders);
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightKeeper::saveCurrentScene()
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
||||||
const auto parent = path.parent_path();
|
const auto parent = path.parent_path();
|
||||||
@@ -493,10 +544,10 @@ void LightKeeper::customUpdate(float dt)
|
|||||||
} catch (const std::exception& exception) {
|
} catch (const std::exception& exception) {
|
||||||
sceneStatus = std::string{"Save failed: "} + exception.what();
|
sceneStatus = std::string{"Save failed: "} + exception.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
void LightKeeper::loadScene()
|
||||||
if (ImGui::Button("Load Scene")) {
|
{
|
||||||
try {
|
try {
|
||||||
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
||||||
if (SceneSerializer::Load(
|
if (SceneSerializer::Load(
|
||||||
@@ -509,9 +560,10 @@ void LightKeeper::customUpdate(float dt)
|
|||||||
} catch (const std::exception& exception) {
|
} catch (const std::exception& exception) {
|
||||||
sceneStatus = std::string{"Load failed: "} + exception.what();
|
sceneStatus = std::string{"Load failed: "} + exception.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("New Empty Scene")) {
|
void LightKeeper::createEmptyScene()
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
const std::string name = newSceneName[0] != '\0'
|
const std::string name = newSceneName[0] != '\0'
|
||||||
? newSceneName
|
? newSceneName
|
||||||
@@ -524,12 +576,71 @@ void LightKeeper::customUpdate(float dt)
|
|||||||
} catch (const std::exception& exception) {
|
} catch (const std::exception& exception) {
|
||||||
sceneStatus = std::string{"New scene failed: "} + exception.what();
|
sceneStatus = std::string{"New scene failed: "} + exception.what();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightKeeper::submitBoxColliderDebugLines()
|
||||||
|
{
|
||||||
|
if (!renderBoxColliders) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sceneStatus.empty()) {
|
auto& sceneManager = SceneManager::GetInstance();
|
||||||
ImGui::TextWrapped("%s", sceneStatus.c_str());
|
if (sceneManager.GetSceneCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene& scene = sceneManager.GetCurrentScene();
|
||||||
|
auto& lineManager = LineRenderingManager::GetInstance();
|
||||||
|
constexpr std::array<std::array<std::size_t, 2>, 12> edges{{
|
||||||
|
{{0, 1}}, {{1, 3}}, {{3, 2}}, {{2, 0}},
|
||||||
|
{{4, 5}}, {{5, 7}}, {{7, 6}}, {{6, 4}},
|
||||||
|
{{0, 4}}, {{1, 5}}, {{2, 6}}, {{3, 7}},
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (const auto& objectPtr : scene.GetObjects()) {
|
||||||
|
if (!objectPtr || objectPtr->IsBeingDestroyed() ||
|
||||||
|
!objectPtr->IsActiveInHierarchy()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* boxCollider = objectPtr->GetComponent<BoxCollider>();
|
||||||
|
if (boxCollider == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collider dimensions are already in world units. Physics does not
|
||||||
|
// apply the GameObject scale when constructing the shape.
|
||||||
|
const glm::vec3 center = boxCollider->GetCenterOffset();
|
||||||
|
const glm::vec3 halfExtents = boxCollider->GetHalfExtents();
|
||||||
|
const std::array<glm::vec3, 8> localCorners{
|
||||||
|
center + glm::vec3{-halfExtents.x, -halfExtents.y, -halfExtents.z},
|
||||||
|
center + glm::vec3{ halfExtents.x, -halfExtents.y, -halfExtents.z},
|
||||||
|
center + glm::vec3{-halfExtents.x, halfExtents.y, -halfExtents.z},
|
||||||
|
center + glm::vec3{ halfExtents.x, halfExtents.y, -halfExtents.z},
|
||||||
|
center + glm::vec3{-halfExtents.x, -halfExtents.y, halfExtents.z},
|
||||||
|
center + glm::vec3{ halfExtents.x, -halfExtents.y, halfExtents.z},
|
||||||
|
center + glm::vec3{-halfExtents.x, halfExtents.y, halfExtents.z},
|
||||||
|
center + glm::vec3{ halfExtents.x, halfExtents.y, halfExtents.z},
|
||||||
|
};
|
||||||
|
|
||||||
|
Transform& transform = objectPtr->GetTransform();
|
||||||
|
const glm::vec3 worldPosition = transform.GetWorldPosition();
|
||||||
|
const glm::quat worldRotation = transform.GetWorldRotation();
|
||||||
|
std::array<glm::vec3, 8> worldCorners{};
|
||||||
|
for (std::size_t index = 0; index < localCorners.size(); ++index) {
|
||||||
|
worldCorners[index] = worldPosition + worldRotation * localCorners[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::vec4 color = boxCollider->IsTrigger()
|
||||||
|
? glm::vec4{1.0f, 0.75f, 0.1f, 1.0f}
|
||||||
|
: glm::vec4{0.1f, 0.8f, 1.0f, 1.0f};
|
||||||
|
for (const auto& edge : edges) {
|
||||||
|
lineManager.SubmitLine(
|
||||||
|
worldCorners[edge[0]],
|
||||||
|
worldCorners[edge[1]],
|
||||||
|
color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightKeeper::customDraw()
|
void LightKeeper::customDraw()
|
||||||
@@ -540,6 +651,7 @@ void LightKeeper::customDraw()
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderer.beginDrawing(gfxDevice);
|
renderer.beginDrawing(gfxDevice);
|
||||||
|
submitBoxColliderDebugLines();
|
||||||
|
|
||||||
const RenderContext ctx{
|
const RenderContext ctx{
|
||||||
.renderer = renderer,
|
.renderer = renderer,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <destrum/Components/Animator.h>
|
#include <destrum/Components/Animator.h>
|
||||||
#include <destrum/Components/Physics/Rigidbody.h>
|
#include <destrum/Components/Physics/Rigidbody.h>
|
||||||
#include <destrum/Graphics/Material.h>
|
#include <destrum/Graphics/Material.h>
|
||||||
|
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class TestComponent final : public Component {
|
class TestComponent final : public Component {
|
||||||
@@ -189,6 +190,29 @@ namespace {
|
|||||||
"RigidBody legacy alias must not be registered");
|
"RigidBody legacy alias must not be registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testLineRenderingManager()
|
||||||
|
{
|
||||||
|
auto& lineManager = LineRenderingManager::GetInstance();
|
||||||
|
lineManager.ClearLines();
|
||||||
|
|
||||||
|
lineManager.SubmitLine(
|
||||||
|
glm::vec3{0.0f},
|
||||||
|
glm::vec3{1.0f, 0.0f, 0.0f},
|
||||||
|
glm::vec4{1.0f, 0.0f, 0.0f, 1.0f});
|
||||||
|
lineManager.SubmitLine(Line{
|
||||||
|
.start = glm::vec3{1.0f},
|
||||||
|
.end = glm::vec3{2.0f},
|
||||||
|
.color = glm::vec4{0.0f, 1.0f, 0.0f, 1.0f},
|
||||||
|
});
|
||||||
|
|
||||||
|
check(lineManager.GetLines().size() == 2,
|
||||||
|
"line rendering manager must retain submitted lines");
|
||||||
|
|
||||||
|
lineManager.ClearLines();
|
||||||
|
check(lineManager.GetLines().empty(),
|
||||||
|
"line rendering manager must clear transient lines");
|
||||||
|
}
|
||||||
|
|
||||||
void testAssetPathValidation()
|
void testAssetPathValidation()
|
||||||
{
|
{
|
||||||
const auto root = std::filesystem::temp_directory_path() / "destrum_asset_test";
|
const auto root = std::filesystem::temp_directory_path() / "destrum_asset_test";
|
||||||
@@ -469,6 +493,7 @@ int main()
|
|||||||
testEventRemoval();
|
testEventRemoval();
|
||||||
testComponentRemoval();
|
testComponentRemoval();
|
||||||
testEngineComponentRegistration();
|
testEngineComponentRegistration();
|
||||||
|
testLineRenderingManager();
|
||||||
testAssetPathValidation();
|
testAssetPathValidation();
|
||||||
testLegacySceneLoad();
|
testLegacySceneLoad();
|
||||||
testSceneLoadRollback();
|
testSceneLoadRollback();
|
||||||
|
|||||||
Reference in New Issue
Block a user