Added debug renderer + imgui renderer
All code made by gemini with some help
This commit is contained in:
@@ -2,24 +2,32 @@
|
||||
|
||||
#include <Core/Application/ApplicationManager.h>
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/HAL/Display/Display.h>
|
||||
#include <Core/HAL/Event/SystemEvent.h>
|
||||
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||
#include <Core/JulietInit.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Math/Matrix.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
#include <cstdlib>
|
||||
#include <Engine/Debug/MemoryDebugger.h>
|
||||
#include <Graphics/Camera.h>
|
||||
#include <Graphics/DebugDisplay.h>
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <Graphics/GraphicsConfig.h>
|
||||
#include <Graphics/GraphicsPipeline.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
#include <Juliet.h>
|
||||
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <cstdlib>
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
#include <Graphics/ImGuiRenderer.h>
|
||||
#include <imgui.h>
|
||||
#endif
|
||||
|
||||
static bool ShowMemoryDebugger = false;
|
||||
|
||||
// TODO : Replace with message box from framework + call main and not winmain + subsystem
|
||||
// TODO : Think how to do the draw pipeline.
|
||||
@@ -33,6 +41,13 @@
|
||||
|
||||
using namespace Juliet;
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllexport) extern const unsigned int D3D12SDKVersion = 615;
|
||||
}
|
||||
extern "C" {
|
||||
__declspec(dllexport) extern const char* D3D12SDKPath = ".\\";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using GameInit_t = void (*)(GameInitParams*);
|
||||
@@ -44,6 +59,7 @@ namespace
|
||||
GameShutdown_t Shutdown = nullptr;
|
||||
GameUpdate_t Update = nullptr;
|
||||
} Game;
|
||||
|
||||
const char* GameFunctionTable[] = { "GameInit", "GameShutdown", "GameUpdate" };
|
||||
} // namespace
|
||||
|
||||
@@ -91,15 +107,15 @@ void JulietApplication::Init()
|
||||
ColorTargetDescription colorTargetDescription = {};
|
||||
colorTargetDescription.Format = GetSwapChainTextureFormat(GraphicsDevice, MainWindow);
|
||||
|
||||
GraphicsPipelineCreateInfo pipelineCI = {};
|
||||
pipelineCI.VertexShader = vertexShader;
|
||||
pipelineCI.FragmentShader = fragmentShader;
|
||||
pipelineCI.PrimitiveType = PrimitiveType::TriangleList;
|
||||
pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription,
|
||||
.NumColorTargets = 1,
|
||||
.DepthStencilFormat = TextureFormat::D32_FLOAT,
|
||||
.HasDepthStencilTarget = true };
|
||||
pipelineCI.RasterizerState.FillMode = FillMode::Solid;
|
||||
GraphicsPipelineCreateInfo pipelineCI = {};
|
||||
pipelineCI.VertexShader = vertexShader;
|
||||
pipelineCI.FragmentShader = fragmentShader;
|
||||
pipelineCI.PrimitiveType = PrimitiveType::TriangleList;
|
||||
pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription,
|
||||
.NumColorTargets = 1,
|
||||
.DepthStencilFormat = TextureFormat::D32_FLOAT,
|
||||
.HasDepthStencilTarget = true };
|
||||
pipelineCI.RasterizerState.FillMode = FillMode::Solid;
|
||||
pipelineCI.DepthStencilState.EnableDepthTest = true;
|
||||
pipelineCI.DepthStencilState.EnableDepthWrite = true;
|
||||
pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;
|
||||
@@ -128,10 +144,10 @@ void JulietApplication::Init()
|
||||
Running = false;
|
||||
}
|
||||
|
||||
// Create Buffers
|
||||
// Create Buffers - Using StructuredBuffer for bindless SRV access in shader
|
||||
BufferCreateInfo bufferCI = {};
|
||||
bufferCI.Size = 256;
|
||||
bufferCI.Usage = BufferUsage::StructuredBuffer; // Changed to StructuredBuffer As Requested
|
||||
bufferCI.Usage = BufferUsage::StructuredBuffer; // SRV for ResourceDescriptorHeap access
|
||||
ConstantBuffer = CreateGraphicsBuffer(GraphicsDevice, bufferCI);
|
||||
|
||||
TransferBufferCreateInfo transferCI = {};
|
||||
@@ -139,6 +155,28 @@ void JulietApplication::Init()
|
||||
transferCI.Usage = TransferBufferUsage::Upload;
|
||||
TransferBuffer = CreateGraphicsTransferBuffer(GraphicsDevice, transferCI);
|
||||
|
||||
// Upload Static Data for Test
|
||||
if (TransferBuffer && ConstantBuffer)
|
||||
{
|
||||
void* data = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
||||
if (data)
|
||||
{
|
||||
Matrix projection = PerspectiveFov(60.0f * (3.14159f / 180.0f), 1200.0f / 800.0f, 0.1f, 1000.0f);
|
||||
Matrix view = LookAt({ 30.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f });
|
||||
Matrix model = Matrix::Identity();
|
||||
Matrix mvp = projection * view * model;
|
||||
|
||||
MemCopy(data, &mvp, sizeof(Matrix));
|
||||
UnmapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
||||
|
||||
CommandList* initCmd = AcquireCommandList(GraphicsDevice);
|
||||
CopyBuffer(initCmd, ConstantBuffer, TransferBuffer, 256);
|
||||
TransitionBufferToReadable(initCmd, ConstantBuffer);
|
||||
SubmitCommandLists(initCmd);
|
||||
WaitUntilGPUIsIdle(GraphicsDevice);
|
||||
}
|
||||
}
|
||||
|
||||
if (vertexShader)
|
||||
{
|
||||
DestroyShader(GraphicsDevice, vertexShader);
|
||||
@@ -165,9 +203,6 @@ void JulietApplication::Init()
|
||||
params.ScratchArena = GetScratchArena();
|
||||
Game.Init(¶ms);
|
||||
}
|
||||
|
||||
// Initialize DebugDisplay
|
||||
DebugDisplay_Initialize(GraphicsDevice);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,12 +216,6 @@ void JulietApplication::Shutdown()
|
||||
ShutdownHotReloadCode(GameCode);
|
||||
}
|
||||
|
||||
// Shutdown DebugDisplay before graphics device
|
||||
if (GraphicsDevice)
|
||||
{
|
||||
DebugDisplay_Shutdown(GraphicsDevice);
|
||||
}
|
||||
|
||||
if (GraphicsPipeline)
|
||||
{
|
||||
DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline);
|
||||
@@ -243,7 +272,6 @@ void JulietApplication::Update()
|
||||
}
|
||||
|
||||
// Shader hot reload using keyboard.
|
||||
// TODO: Add Input debounce in the library. (Just pressed vs pressed)
|
||||
if (!reloadShadersDebounce && ((GetKeyModState() & KeyMod::Alt) != KeyMod::None) && IsKeyDown(ScanCode::R))
|
||||
{
|
||||
reloadShaders = true;
|
||||
@@ -256,6 +284,16 @@ void JulietApplication::Update()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
ImGui::ShowDemoWindow();
|
||||
#endif
|
||||
|
||||
// Debug display shapes - can be called from anywhere before engine flush
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false);
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true);
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
|
||||
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 5.0f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
|
||||
|
||||
Game.Update(0.0f);
|
||||
|
||||
if (ShouldReloadCode(GameCode))
|
||||
@@ -265,7 +303,6 @@ void JulietApplication::Update()
|
||||
|
||||
if (reloadShaders)
|
||||
{
|
||||
// We need to wait for the gpu to be idle to recreate our graphics pipelines
|
||||
WaitUntilGPUIsIdle(GraphicsDevice);
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
@@ -293,104 +330,121 @@ void JulietApplication::Update()
|
||||
#endif
|
||||
}
|
||||
|
||||
// Draw here for now
|
||||
// 1) Acquire a Command Buffer
|
||||
CommandList* cmdList = AcquireCommandList(GraphicsDevice, QueueType::Graphics);
|
||||
if (cmdList == nullptr)
|
||||
// Memory debugger toggle
|
||||
static bool toggleDebounce = false;
|
||||
if (IsKeyDown(Juliet::ScanCode::Home))
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Tool, "Failed to acquire command list.");
|
||||
Running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Texture* swapChainTexture = nullptr;
|
||||
if (!WaitAndAcquireSwapChainTexture(cmdList, MainWindow, &swapChainTexture))
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Tool, "Failed to acquire swapchain texture.");
|
||||
Running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (swapChainTexture)
|
||||
{
|
||||
ColorTargetInfo colorTargetInfo = {};
|
||||
colorTargetInfo.TargetTexture = swapChainTexture;
|
||||
colorTargetInfo.ClearColor = { .R = .0f, .G = .0f, .B = .0f, .A = 1.f };
|
||||
colorTargetInfo.LoadOperation = LoadOperation::Clear;
|
||||
colorTargetInfo.StoreOperation = StoreOperation::Store;
|
||||
|
||||
if (ConstantBuffer && TransferBuffer)
|
||||
if (!toggleDebounce)
|
||||
{
|
||||
void* ptr = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
||||
if (ptr)
|
||||
{
|
||||
Vertex* vertices = static_cast<Vertex*>(ptr);
|
||||
ShowMemoryDebugger = !ShowMemoryDebugger;
|
||||
toggleDebounce = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
toggleDebounce = false;
|
||||
}
|
||||
|
||||
// Triangle 1
|
||||
vertices[0] = { { -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f, 1.0f } }; // Red
|
||||
vertices[1] = { { 0.0f, 0.5f }, { 0.0f, 1.0f, 0.0f, 1.0f } }; // Green
|
||||
vertices[2] = { { 0.5f, -0.5f }, { 0.0f, 0.0f, 1.0f, 1.0f } }; // Blue
|
||||
// Auto-close logic
|
||||
if (AutoCloseFrameCount > 0)
|
||||
{
|
||||
AutoCloseFrameCount--;
|
||||
if (AutoCloseFrameCount == 0)
|
||||
{
|
||||
Log(LogLevel::Message, LogCategory::Tool, "Auto-closing application as requested.");
|
||||
Running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Triangle 2
|
||||
vertices[3] = { { -0.5f, 0.5f }, { 1.0f, 1.0f, 0.0f, 1.0f } }; // Yellow
|
||||
vertices[4] = { { 0.0f, 0.8f }, { 0.0f, 1.0f, 1.0f, 1.0f } }; // Cyan
|
||||
vertices[5] = { { 0.5f, 0.5f }, { 1.0f, 0.0f, 1.0f, 1.0f } }; // Magenta
|
||||
void JulietApplication::OnPreRender(CommandList* cmd)
|
||||
{
|
||||
// Buffer uploads
|
||||
if (ConstantBuffer && TransferBuffer)
|
||||
{
|
||||
void* ptr = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
||||
if (ptr)
|
||||
{
|
||||
auto vertices = static_cast<Vertex*>(ptr);
|
||||
|
||||
UnmapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
||||
}
|
||||
// Triangle 1
|
||||
vertices[0] = { { -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f, 1.0f } }; // Red
|
||||
vertices[1] = { { 0.0f, 0.5f }, { 0.0f, 1.0f, 0.0f, 1.0f } }; // Green
|
||||
vertices[2] = { { 0.5f, -0.5f }, { 0.0f, 0.0f, 1.0f, 1.0f } }; // Blue
|
||||
|
||||
CopyBuffer(cmdList, ConstantBuffer, TransferBuffer, 256);
|
||||
TransitionBufferToReadable(cmdList, ConstantBuffer);
|
||||
// Triangle 2
|
||||
vertices[3] = { { -0.5f, 0.5f }, { 1.0f, 1.0f, 0.0f, 1.0f } }; // Yellow
|
||||
vertices[4] = { { 0.0f, 0.8f }, { 0.0f, 1.0f, 1.0f, 1.0f } }; // Cyan
|
||||
vertices[5] = { { 0.5f, 0.5f }, { 1.0f, 0.0f, 1.0f, 1.0f } }; // Magenta
|
||||
|
||||
UnmapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
||||
}
|
||||
|
||||
// Test lines and sphere - GIANT SCALE
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false); // X-Axis (Red)
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true); // Y-Axis (Green)
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true); // Z-Axis (Blue) - Up
|
||||
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 5.0f, { 1.0f, 1.0f, 0.0f, 1.0f }, true); // Yellow sphere
|
||||
|
||||
// Prepare debug data (outside render pass)
|
||||
DebugDisplay_Prepare(cmdList);
|
||||
|
||||
DepthStencilTargetInfo depthTargetInfo = {};
|
||||
depthTargetInfo.TargetTexture = DepthBuffer;
|
||||
depthTargetInfo.ClearDepth = 1.0f;
|
||||
depthTargetInfo.LoadOperation = LoadOperation::Clear;
|
||||
depthTargetInfo.StoreOperation = StoreOperation::Store;
|
||||
|
||||
RenderPass* renderPass = BeginRenderPass(cmdList, colorTargetInfo, &depthTargetInfo);
|
||||
BindGraphicsPipeline(renderPass, GraphicsPipeline);
|
||||
|
||||
// Pass descriptor index via Push Constants AFTER finding the pipeline (RootSignature)
|
||||
uint32 descriptorIndex = GetDescriptorIndex(GraphicsDevice, ConstantBuffer);
|
||||
SetPushConstants(cmdList, ShaderStage::Vertex, 0, 1, &descriptorIndex);
|
||||
|
||||
DrawPrimitives(renderPass, 6, 1, 0, 0);
|
||||
|
||||
// Debug Display - render shapes (inside render pass)
|
||||
static float orbitTime = 0.0f;
|
||||
orbitTime += 0.016f; // Rough approximation for 60fps
|
||||
|
||||
float radius = 30.0f;
|
||||
Camera debugCamera = {};
|
||||
debugCamera.Position = { cosf(orbitTime) * radius, sinf(orbitTime) * radius, 10.0f }; // Rotate in XY plane
|
||||
debugCamera.Target = { 0.0f, 0.0f, 0.0f };
|
||||
debugCamera.Up = { 0.0f, 0.0f, 1.0f }; // Z-Up
|
||||
debugCamera.FOV = 1.047f; // 60 degrees
|
||||
debugCamera.AspectRatio = 1200.0f / 800.0f;
|
||||
debugCamera.NearPlane = 0.1f;
|
||||
debugCamera.FarPlane = 1000.0f;
|
||||
|
||||
DebugDisplay_Flush(cmdList, renderPass, debugCamera);
|
||||
|
||||
EndRenderPass(renderPass);
|
||||
CopyBuffer(cmd, ConstantBuffer, TransferBuffer, 256);
|
||||
TransitionBufferToReadable(cmd, ConstantBuffer);
|
||||
}
|
||||
|
||||
// Submit Commands
|
||||
SubmitCommandLists(cmdList);
|
||||
|
||||
// Reset Scratch Arena at the end of the frame
|
||||
ScratchArenaReset();
|
||||
}
|
||||
|
||||
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
||||
{
|
||||
BindGraphicsPipeline(pass, GraphicsPipeline);
|
||||
|
||||
uint32 descriptorIndex = GetDescriptorIndex(GraphicsDevice, ConstantBuffer);
|
||||
|
||||
struct PushData
|
||||
{
|
||||
float ViewProjection[16];
|
||||
uint32 BufferIndex;
|
||||
} pushData = {};
|
||||
pushData.BufferIndex = descriptorIndex;
|
||||
|
||||
SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
|
||||
|
||||
DrawPrimitives(pass, 6, 1, 0, 0);
|
||||
|
||||
if (ShowMemoryDebugger)
|
||||
{
|
||||
MemoryDebugger::DrawGlobalArenas();
|
||||
}
|
||||
}
|
||||
|
||||
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
|
||||
{
|
||||
ColorTargetInfo info = {};
|
||||
info.TargetTexture = swapchainTexture;
|
||||
info.ClearColor = { .R = 0.0f, .G = 0.0f, .B = 0.0f, .A = 1.0f };
|
||||
info.LoadOperation = LoadOperation::Clear;
|
||||
info.StoreOperation = StoreOperation::Store;
|
||||
return info;
|
||||
}
|
||||
|
||||
DepthStencilTargetInfo* JulietApplication::GetDepthTargetInfo()
|
||||
{
|
||||
static DepthStencilTargetInfo info = {};
|
||||
info.TargetTexture = DepthBuffer;
|
||||
info.ClearDepth = 1.0f;
|
||||
info.LoadOperation = LoadOperation::Clear;
|
||||
info.StoreOperation = StoreOperation::Store;
|
||||
return &info;
|
||||
}
|
||||
|
||||
Camera JulietApplication::GetDebugCamera()
|
||||
{
|
||||
static float orbitTime = 0.0f;
|
||||
orbitTime += 0.016f;
|
||||
|
||||
float radius = 30.0f;
|
||||
Camera cam = {};
|
||||
cam.Position = { cosf(orbitTime) * radius, sinf(orbitTime) * radius, 10.0f };
|
||||
cam.Target = { 0.0f, 0.0f, 0.0f };
|
||||
cam.Up = { 0.0f, 0.0f, 1.0f };
|
||||
cam.FOV = 1.047f;
|
||||
cam.AspectRatio = 1200.0f / 800.0f;
|
||||
cam.NearPlane = 0.1f;
|
||||
cam.FarPlane = 1000.0f;
|
||||
return cam;
|
||||
}
|
||||
|
||||
bool JulietApplication::IsRunning()
|
||||
@@ -419,10 +473,28 @@ int main(int /*argc*/, char** /*argv*/)
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
if (__argc > 1)
|
||||
{
|
||||
for (int i = 1; i < __argc; ++i)
|
||||
{
|
||||
if (strcmp(__argv[i], "-autoclose") == 0 && (i + 1 < __argc))
|
||||
{
|
||||
int frames = atoi(__argv[i + 1]);
|
||||
EditorApplication.SetAutoCloseFrameCount(frames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StartApplication(EditorApplication, JulietInit_Flags::Display);
|
||||
|
||||
// Pause here to not close the console window immediatly on stop
|
||||
system("PAUSE");
|
||||
// Only pause if not in auto-close mode
|
||||
if (EditorApplication.GetAutoCloseFrameCount() == -1)
|
||||
{
|
||||
system("PAUSE");
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user