Added basic concept of Mesh

Right now can create a quad or a cube.
Need a mesh renderer taht keep the buffer and all to optimally handle the mega buffer.
This commit is contained in:
2026-02-15 17:44:48 -05:00
parent c2a5cb84b2
commit 87831d0fd6
22 changed files with 285 additions and 163 deletions

Binary file not shown.

View File

@@ -8,31 +8,7 @@ struct Input
float4 main(Input input) : SV_Target0
{
// Retrieve the texture using SM6.6 bindless syntax
// Texture2D texture = ResourceDescriptorHeap[TextureIndex]; (Must cast to Texture2D<float4>)
// Wait, ResourceDescriptorHeap indexing returns a wrapper, usually we use Textures[TextureIndex]?
// Juliet seems to use `ResourceDescriptorHeap` for Buffers.
// Let's check Triangle.vert/frag.
// In bindless, usually:
// Texture2D<float4> tex = ResourceDescriptorHeap[TextureIndex];
// SamplerState samp = SamplerDescriptorHeap[0]; // Assuming static sampler or passed index
// I need to check how Juliet accesses textures.
// I'll assume standard SM6.6 usage.
Texture2D<float4> tex = ResourceDescriptorHeap[TextureIndex];
SamplerState samp = SamplerDescriptorHeap[0]; // Point sampler or Linear? ImGui usually uses Linear.
// D3D12GraphicsDevice.cpp created static samplers.
// Root signature has Static Samplers.
// RegisterSpace 0.
// Sampler register 0 is Point/Nearest?
// Let's check CreateGraphicsRootSignature in D3D12GraphicsDevice.cpp.
// It creates s_nearest at 0.
// If I want Linear, I might need another sampler or rely on s_nearest for font (pixel art font?)
// Default ImGui font is usually antialiased, so Linear is preferred.
// But pixel aligned UI...
// I will use `SamplerDescriptorHeap[0]` for now.
SamplerState samp = SamplerDescriptorHeap[0];
return input.Color * tex.Sample(samp, input.UV);
}

View File

@@ -18,14 +18,10 @@ Output main(uint vertexIndex : SV_VertexID)
{
Output output;
// Retrieve the vertex buffer using SM6.6 bindless syntax
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
// Add VertexOffset for indexed drawing with bindless buffers
// (SV_VertexID in indexed draw is raw index from index buffer, doesn't include BaseVertexLocation)
uint actualVertexIndex = vertexIndex + VertexOffset;
// ImDrawVert stride = 20 bytes (Vec2 pos + Vec2 uv + uint color)
uint stride = 20;
uint offset = actualVertexIndex * stride;
@@ -33,34 +29,12 @@ Output main(uint vertexIndex : SV_VertexID)
float2 uv = asfloat(buffer.Load2(offset + 8));
uint col = buffer.Load(offset + 16);
// Unpack color (uint to float4)
// ImGui colors are 0xAABBGGRR (ABGR packed)
// We need to unpack to float4.
// HLSL unpacks as little endian.
// uint 0xAABBGGRR -> byte0=RR, byte1=GG, byte2=BB, byte3=AA
float4 c;
c.x = float(col & 0xFF) / 255.0f;
c.y = float((col >> 8) & 0xFF) / 255.0f;
c.z = float((col >> 16) & 0xFF) / 255.0f;
c.w = float((col >> 24) & 0xFF) / 255.0f;
// Transform
// ImGui sends pixel coordinates.
// We need to transform to NDC [-1, 1].
// PushConstants should contain Scale and Translate.
// float2 Scale = 2.0 / DisplaySize
// float2 Translate = -1.0 - (DisplayPos * Scale)
// We will assume PushConstants are float2 Scale, float2 Translate.
// Struct in RootConstants.hlsl?
// RootConstants.hlsl likely defines `cbuffer PushConstants : register(b0)`.
// Let's assume standard push constants usage.
// Debug.vert.hlsl used `ViewProjection`.
// We need to customize PushConstants or reuse `ViewProjection` slot?
// Juliet uses 128 bytes of push constants.
// We can map float4 ProjectionMatrix (or similar).
// Use Scale and Translate from RootConstants
output.Position = float4(pos * Scale + Translate, 0.0f, 1.0f);
output.Color = c;
output.UV = uv;

View File

@@ -10,20 +10,16 @@ Output main(uint vertexIndex : SV_VertexID)
{
Output output;
// Retrieve the buffer using SM6.6 bindless syntax
// Use BufferIndex from RootConstants (pushed via SetPushConstants)
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
// Read position from buffer (Index * stride)
// Stride = 2 float (pos) + 4 float (color) = 6 * 4 = 24 bytes ?
// Let's assume just position 2D (8 bytes) + Color (16 bytes)
uint stride = 24;
uint stride = 28;
uint offset = vertexIndex * stride;
float2 pos = asfloat(buffer.Load2(offset));
float4 col = asfloat(buffer.Load4(offset + 8));
float3 pos = asfloat(buffer.Load3(offset));
float4 col = asfloat(buffer.Load4(offset + 12));
output.Position = float4(pos, 0.0f, 1.0f);
//output.Position = float4(pos, 1.0f);
output.Position = mul(ViewProjection, float4(pos, 1.0f));
output.Color = col;
return output;
}

View File

@@ -108,9 +108,11 @@
<CustomBuild Include="include\Graphics\GraphicsConfig.h" />
<CustomBuild Include="include\Graphics\GraphicsPipeline.h" />
<CustomBuild Include="include\Graphics\ImGuiRenderer.h" />
<CustomBuild Include="include\Graphics\Mesh.h" />
<CustomBuild Include="include\Graphics\RenderPass.h" />
<CustomBuild Include="include\Graphics\Shader.h" />
<CustomBuild Include="include\Graphics\Texture.h" />
<CustomBuild Include="include\Graphics\VertexData.h" />
<CustomBuild Include="include\Juliet.h" />
<CustomBuild Include="Juliet.bff" />
<CustomBuild Include="src\Core\Application\ApplicationManager.cpp" />
@@ -220,6 +222,7 @@
<CustomBuild Include="src\Graphics\Graphics.cpp" />
<CustomBuild Include="src\Graphics\GraphicsDevice.h" />
<CustomBuild Include="src\Graphics\ImGuiRenderer.cpp" />
<CustomBuild Include="src\Graphics\Mesh.cpp" />
<CustomBuild Include="src\UnitTest\Container\VectorUnitTest.cpp" />
<CustomBuild Include="src\UnitTest\RunUnitTests.cpp" />
</ItemGroup>

View File

@@ -172,6 +172,9 @@
<CustomBuild Include="include\Graphics\ImGuiRenderer.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="include\Graphics\Mesh.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="include\Graphics\RenderPass.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
@@ -181,6 +184,9 @@
<CustomBuild Include="include\Graphics\Texture.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="include\Graphics\VertexData.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="include\Juliet.h">
<Filter>include</Filter>
</CustomBuild>
@@ -507,6 +513,9 @@
<CustomBuild Include="src\Graphics\ImGuiRenderer.cpp">
<Filter>src\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="src\Graphics\Mesh.cpp">
<Filter>src\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="src\UnitTest\Container\VectorUnitTest.cpp">
<Filter>src\UnitTest\Container</Filter>
</CustomBuild>

View File

@@ -17,7 +17,7 @@ namespace Juliet
DataFirst = DataLast = nullptr;
Count = 0;
JULIET_DEBUG_ONLY(Name = name ? name : Name);
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
ArenaParams params{ .AllowRealloc = AllowRealloc JULIET_DEBUG_PARAM(.CanReserveMore = false) };
Arena = ArenaAllocate(params JULIET_DEBUG_PARAM(Name));
InternalArena = true;
@@ -29,7 +29,7 @@ namespace Juliet
{
Assert(!Arena);
JULIET_DEBUG_ONLY(Name = name ? name : Name);
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
DataFirst = DataLast = nullptr;
Count = 0;
@@ -196,7 +196,7 @@ namespace Juliet
size_t Count;
size_t Capacity;
bool InternalArena : 1;
JULIET_DEBUG_ONLY(const char* Name = "VectorArena");
JULIET_DEBUG_ONLY(const char* Name = "VectorArena";)
};
static_assert(std::is_standard_layout_v<VectorArena<int>>,
"VectorArena must have a standard layout to remain POD-like.");

View File

@@ -85,23 +85,17 @@ namespace Juliet
[[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr<Arena> arena);
template <typename Type>
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena)
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* tag = nullptr))
{
return static_cast<Type*>(
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_ONLY(, typeid(Type).name())));
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_PARAM(tag ? tag : typeid(Type).name())));
}
template <typename Type>
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count JULIET_DEBUG_ONLY(, const char* tag))
{
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)), true JULIET_DEBUG_ONLY(, tag)));
}
template <typename Type>
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count)
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count JULIET_DEBUG_PARAM(const char* tag = nullptr))
{
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)),
true JULIET_DEBUG_ONLY(, typeid(Type).name())));
true JULIET_DEBUG_PARAM(tag ? tag : typeid(Type).name())));
}
TempArena ArenaTempBegin(NonNullPtr<Arena> arena);

View File

@@ -134,13 +134,11 @@ namespace Juliet
extern JULIET_API void BindGraphicsPipeline(NonNullPtr<RenderPass> renderPass, NonNullPtr<GraphicsPipeline> graphicsPipeline);
extern JULIET_API void DrawPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numVertices, uint32 numInstances,
uint32 firstVertex, uint32 firstInstance);
extern JULIET_API void DrawIndexedPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numIndices,
uint32 numInstances, uint32 firstIndex, uint32 vertexOffset,
uint32 firstInstance);
extern JULIET_API void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
extern JULIET_API void DrawIndexedPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numIndices, uint32 numInstances,
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance);
extern JULIET_API void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
IndexFormat format, size_t indexCount, index_t offset);
extern JULIET_API void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage,
uint32 rootParameterIndex, uint32 numConstants, const void* constants);

View File

@@ -0,0 +1,28 @@
#pragma once
#include <Core/Common/CoreTypes.h>
#include <Core/Common/NonNullPtr.h>
#include <Juliet.h>
namespace Juliet
{
struct Arena;
struct Vertex;
struct Mesh
{
Vertex* Vertices;
uint16* Indices;
size_t VertexCount;
size_t IndexCount;
index_t VertexOffset;
index_t IndexOffset;
index_t IndexByteOffset;
};
JULIET_API Mesh* CreateCubeMesh(NonNullPtr<Arena> arena);
JULIET_API Mesh* CreateQuadMesh(NonNullPtr<Arena> arena);
JULIET_API void DestroyMesh(NonNullPtr<Mesh> mesh);
} // namespace Juliet

View File

@@ -0,0 +1,10 @@
#pragma once
namespace Juliet
{
struct Vertex
{
float Position[3];
float Color[4];
};
} // namespace Juliet

View File

@@ -361,30 +361,40 @@ namespace Juliet::D3D12
d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference);
}
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format)
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format,
size_t indexCount, index_t offset)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
auto* d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
// Transition to INDEX_BUFFER state if needed
if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_INDEX_BUFFER)
if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ)
{
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = d3d12Buffer->Handle;
barrier.Transition.StateBefore = d3d12Buffer->CurrentState;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
barrier.Transition.StateAfter =
D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier);
d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_INDEX_BUFFER;
d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ;
}
D3D12_INDEX_BUFFER_VIEW ibView;
ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress();
ibView.SizeInBytes = static_cast<UINT>(d3d12Buffer->Size);
ibView.Format = (format == IndexFormat::UInt16) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset;
if (format == IndexFormat::UInt16)
{
ibView.SizeInBytes = static_cast<UINT>(indexCount * sizeof(uint16));
ibView.Format = DXGI_FORMAT_R16_UINT;
}
else
{
ibView.SizeInBytes = static_cast<UINT>(indexCount * sizeof(uint32));
ibView.Format = DXGI_FORMAT_R32_UINT;
}
d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView);
}

View File

@@ -97,7 +97,8 @@ namespace Juliet::D3D12
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
extern void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
extern void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
IndexFormat format, index_t offset);
extern void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
uint32 numConstants, const void* constants);

View File

@@ -623,27 +623,6 @@ namespace Juliet::D3D12
Free(device.Get());
}
// Note: SetViewPort, SetScissorRect, SetBlendConstants, SetStencilReference
// are defined in D3D12CommandList.cpp and used directly via D3D12:: namespace
// BindGraphicsPipeline is now assigned directly from D3D12:: namespace
// DrawPrimitives is now assigned directly from D3D12:: namespace
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex,
static_cast<INT>(vertexOffset), firstInstance);
}
// WaitUntilGPUIsIdle, SetPushConstants are now assigned directly from D3D12:: namespace
// QueryFence, ReleaseFence, CreateShader, DestroyShader are now assigned directly from D3D12:: namespace
// CreateGraphicsPipeline is assigned directly from D3D12:: namespace
void DestroyGraphicsPipeline(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> pipeline)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
@@ -656,8 +635,6 @@ namespace Juliet::D3D12
}
}
// Buffer functions are assigned directly from D3D12:: namespace
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst, NonNullPtr<GraphicsTransferBuffer> src)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
@@ -1053,7 +1030,7 @@ namespace Juliet::D3D12
device->SetStencilReference = D3D12::SetStencilReference;
device->BindGraphicsPipeline = D3D12::BindGraphicsPipeline;
device->DrawPrimitives = D3D12::DrawPrimitives;
device->DrawIndexedPrimitives = DrawIndexedPrimitives;
device->DrawIndexedPrimitives = D3D12::DrawIndexedPrimitives;
device->SetIndexBuffer = D3D12::SetIndexBuffer;
device->WaitUntilGPUIsIdle = D3D12::WaitUntilGPUIsIdle;

View File

@@ -283,4 +283,12 @@ namespace Juliet::D3D12
d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance);
}
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex,
static_cast<INT>(vertexOffset), firstInstance);
}
} // namespace Juliet::D3D12

View File

@@ -13,4 +13,6 @@ namespace Juliet::D3D12
extern void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
extern void DrawPrimitives(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,
uint32 firstVertex, uint32 firstInstance);
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance);
} // namespace Juliet::D3D12

View File

@@ -1,11 +1,10 @@
#include <Core/HAL/Filesystem/Filesystem.h>
#include <Core/HAL/IO/IOStream.h>
#include <Core/ImGui/ImGuiTests.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Graphics/Graphics.h>
#include <Graphics/GraphicsDevice.h>
#include <Core/ImGui/ImGuiTests.h>
namespace Juliet
{
@@ -63,7 +62,6 @@ namespace Juliet
newDevice->Name = chosenFactory->Name;
return newDevice;
}
}
return nullptr;
}
@@ -263,13 +261,14 @@ namespace Juliet
commandListHeader->Device->SetStencilReference(commandList, reference);
}
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format)
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format,
size_t indexCount, index_t offset)
{
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList.Get());
if (commandListHeader->Device->SetIndexBuffer)
{
commandListHeader->Device->SetIndexBuffer(commandList, buffer, format);
commandListHeader->Device->SetIndexBuffer(commandList, buffer, format, indexCount, offset);
}
}
@@ -297,13 +296,11 @@ namespace Juliet
if (commandListHeader->Device->DrawIndexedPrimitives)
{
commandListHeader->Device->DrawIndexedPrimitives(commandList, numIndices, numInstances, firstIndex, vertexOffset, firstInstance);
commandListHeader->Device->DrawIndexedPrimitives(commandList, numIndices, numInstances, firstIndex,
vertexOffset, firstInstance);
}
}
void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
uint32 numConstants, const void* constants)
{
@@ -399,8 +396,7 @@ namespace Juliet
headers->Device->CopyBuffer(commandList, dst, src, size, dstOffset, srcOffset);
}
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst,
NonNullPtr<GraphicsTransferBuffer> src)
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst, NonNullPtr<GraphicsTransferBuffer> src)
{
auto* headers = reinterpret_cast<CommandListHeader*>(commandList.Get());
if (headers->Device->CopyBufferToTexture)
@@ -409,7 +405,6 @@ namespace Juliet
}
}
void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer)
{
auto* header = reinterpret_cast<CommandListHeader*>(commandList.Get());
@@ -426,7 +421,6 @@ namespace Juliet
return device->GetDescriptorIndexTexture(device, texture);
}
void DestroyGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
{
device->DestroyGraphicsBuffer(buffer);

View File

@@ -68,7 +68,8 @@ namespace Juliet
void (*SetScissorRect)(NonNullPtr<CommandList> commandList, const Rectangle& viewPort);
void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants);
void (*SetStencilReference)(NonNullPtr<CommandList> commandList, uint8 reference);
void (*SetIndexBuffer)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
void (*SetIndexBuffer)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
IndexFormat format, size_t indexCount, index_t offset);
void (*BindGraphicsPipeline)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
void (*DrawPrimitives)(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,

View File

@@ -223,9 +223,7 @@ namespace Juliet
DestroyShader(device, g_ImGuiState.VertexShader);
}
if (g_ImGuiState.FragmentShader)
{
DestroyShader(device, g_ImGuiState.FragmentShader);
}
if (g_ImGuiState.FontTexture)
@@ -344,7 +342,7 @@ namespace Juliet
TransitionBufferToReadable(cmdList, currentFrame.VertexBuffer);
// SetIndexBuffer transitions from COPY_DEST to INDEX_BUFFER (barrier waits for copy to complete)
SetIndexBuffer(cmdList, currentFrame.IndexBuffer, IndexFormat::UInt16);
SetIndexBuffer(cmdList, currentFrame.IndexBuffer, IndexFormat::UInt16, totalIdx, 0);
// Render
BindGraphicsPipeline(renderPass, g_ImGuiState.Pipeline);
@@ -379,7 +377,7 @@ namespace Juliet
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != nullptr)
{
// pcmd->UserCallback(cmd_list, pcmd);
pcmd->UserCallback(cmd_list, pcmd);
}
else
{

View File

@@ -0,0 +1,99 @@
#include <Graphics/Mesh.h>
#include <Core/Memory/MemoryArena.h>
#include <Graphics/VertexData.h>
namespace Juliet
{
Mesh* CreateCubeMesh(NonNullPtr<Arena> arena)
{
Mesh* result = ArenaPushStruct<Mesh>(arena.Get());
constexpr Vertex vertexData[] = {
// Front Face (Z = -0.5f)
{ { -0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f } }, // 0: Top Left
{ { 0.5f, 0.5f, -0.5f }, { 1.0f, 0.0f } }, // 1: Top Right
{ { 0.5f, -0.5f, -0.5f }, { 1.0f, 1.0f } }, // 2: Bottom Right
{ { -0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f } }, // 3: Bottom Left
// Back Face (Z = 0.5f)
{ { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f } }, // 4: Top Left
{ { -0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f } }, // 5: Top Right
{ { -0.5f, -0.5f, 0.5f }, { 1.0f, 1.0f } }, // 6: Bottom Right
{ { 0.5f, -0.5f, 0.5f }, { 0.0f, 1.0f } }, // 7: Bottom Left
// Top Face (Y = 0.5f)
{ { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f } }, // 8: Top Left
{ { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f } }, // 9: Top Right
{ { 0.5f, 0.5f, -0.5f }, { 1.0f, 1.0f } }, // 10: Bottom Right
{ { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f } }, // 11: Bottom Left
// Bottom Face (Y = -0.5f)
{ { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f } }, // 12: Top Left
{ { 0.5f, -0.5f, -0.5f }, { 1.0f, 0.0f } }, // 13: Top Right
{ { 0.5f, -0.5f, 0.5f }, { 1.0f, 1.0f } }, // 14: Bottom Right
{ { -0.5f, -0.5f, 0.5f }, { 0.0f, 1.0f } }, // 15: Bottom Left
// Right Face (X = 0.5f)
{ { 0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f } }, // 16: Top Left
{ { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f } }, // 17: Top Right
{ { 0.5f, -0.5f, 0.5f }, { 1.0f, 1.0f } }, // 18: Bottom Right
{ { 0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f } }, // 19: Bottom Left
// Left Face (X = -0.5f)
{ { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f } }, // 20: Top Left
{ { -0.5f, 0.5f, -0.5f }, { 1.0f, 0.0f } }, // 21: Top Right
{ { -0.5f, -0.5f, -0.5f }, { 1.0f, 1.0f } }, // 22: Bottom Right
{ { -0.5f, -0.5f, 0.5f }, { 0.0f, 1.0f } } // 23: Bottom Left
};
constexpr size_t cubeVertexCount = ArraySize(vertexData);
result->VertexCount = cubeVertexCount;
result->Vertices = ArenaPushArray<Vertex>(arena.Get(), cubeVertexCount);
MemCopy(result->Vertices, vertexData, sizeof(Vertex) * cubeVertexCount);
constexpr uint16 indices[] = { 0, 1, 2, 0, 2, 3, // Front
4, 5, 6, 4, 6, 7, // Back
8, 9, 10, 8, 10, 11, // Top
12, 13, 14, 12, 14, 15, // Bottom
16, 17, 18, 16, 18, 19, // Right
20, 21, 22, 20, 22, 23 }; // Left
constexpr size_t indexCubeCount = ArraySize(indices);
result->IndexCount = indexCubeCount;
result->Indices = ArenaPushArray<uint16>(arena.Get(), indexCubeCount JULIET_DEBUG_PARAM("Indices"));
MemCopy(result->Indices, indices, sizeof(uint16) * indexCubeCount);
return result;
}
Mesh* CreateQuadMesh(NonNullPtr<Arena> arena)
{
Mesh* result = ArenaPushStruct<Mesh>(arena.Get());
// Using the exact 6 vertices from the working triangles!
constexpr Vertex vertexData[] = {
// Triangle 1 (Clockwise)
{ { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, // 0: Red
{ { 0.0f, 0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, // 1: Green
{ { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }, // 2: Blue
// Triangle 2 (Clockwise)
{ { -0.5f, 0.5f, 0.0f }, { 1.0f, 1.0f, 0.0f, 1.0f } }, // 3: Yellow
{ { 0.0f, 0.8f, 0.0f }, { 0.0f, 1.0f, 1.0f, 1.0f } }, // 4: Cyan
{ { 0.5f, 0.5f, 0.0f }, { 1.0f, 0.0f, 1.0f, 1.0f } } // 5: Magenta
};
constexpr size_t triVertexCount = ArraySize(vertexData);
result->VertexCount = triVertexCount;
result->Vertices = ArenaPushArray<Vertex>(arena.Get(), triVertexCount);
MemCopy(result->Vertices, vertexData, sizeof(Vertex) * triVertexCount);
// Just the 6 indices for the two triangles
constexpr uint16 indices[] = { 0, 1, 2, 3, 4, 5 };
constexpr size_t triIndexCount = ArraySize(indices);
result->IndexCount = triIndexCount;
result->Indices = ArenaPushArray<uint16>(arena.Get(), triIndexCount JULIET_DEBUG_PARAM("Indices"));
MemCopy(result->Indices, indices, sizeof(uint16) * triIndexCount);
return result;
}
} // namespace Juliet

View File

@@ -20,7 +20,9 @@
#include <Graphics/Graphics.h>
#include <Graphics/GraphicsConfig.h>
#include <Graphics/GraphicsPipeline.h>
#include <Graphics/Mesh.h>
#include <Graphics/RenderPass.h>
#include <Graphics/VertexData.h>
#include <Juliet.h>
#ifdef JULIET_ENABLE_IMGUI
@@ -63,12 +65,6 @@ namespace
const char* GameFunctionTable[] = { "GameInit", "GameShutdown", "GameUpdate" };
} // namespace
struct Vertex
{
float Position[2];
float Color[4];
};
void JulietApplication::Init()
{
Log(LogLevel::Message, LogCategory::Tool, "Initializing Juliet Application...");
@@ -88,7 +84,6 @@ void JulietApplication::Init()
if (Running)
{
AttachToWindow(GraphicsDevice, MainWindow);
{
// Create graphics pipeline
String entryPoint = WrapString("main");
@@ -146,12 +141,12 @@ void JulietApplication::Init()
// Create Buffers - Using StructuredBuffer for bindless SRV access in shader
BufferCreateInfo bufferCI = {};
bufferCI.Size = 256;
bufferCI.Size = 1024;
bufferCI.Usage = BufferUsage::StructuredBuffer; // SRV for ResourceDescriptorHeap access
ConstantBuffer = CreateGraphicsBuffer(GraphicsDevice, bufferCI);
TransferBufferCreateInfo transferCI = {};
transferCI.Size = 256;
transferCI.Size = 1024;
transferCI.Usage = TransferBufferUsage::Upload;
TransferBuffer = CreateGraphicsTransferBuffer(GraphicsDevice, transferCI);
@@ -176,6 +171,10 @@ void JulietApplication::Init()
}
}
CubeArena = ArenaAllocate({ .ReserveSize = Kilobytes(1llu), .CommitSize = Kilobytes(1llu) } JULIET_DEBUG_PARAM("CubeArena"));
CubeMesh = CreateCubeMesh(CubeArena);
// CubeMesh = CreateQuadMesh(CubeArena);
if (vertexShader)
{
DestroyShader(GraphicsDevice, vertexShader);
@@ -209,6 +208,8 @@ void JulietApplication::Shutdown()
{
Log(LogLevel::Message, LogCategory::Tool, "Shutting down Juliet Application...");
ArenaRelease(CubeArena);
if (GameCode.IsValid)
{
Game.Shutdown();
@@ -283,10 +284,10 @@ void JulietApplication::Update()
ImGui::ShowDemoWindow();
#endif
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);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 0.5f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
Game.Update(0.0f);
@@ -362,28 +363,49 @@ void JulietApplication::Update()
void JulietApplication::OnPreRender(CommandList* cmd)
{
index_t index = 0;
// Buffer uploads
if (ConstantBuffer && TransferBuffer)
{
void* ptr = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
if (ptr)
{
auto vertices = static_cast<Vertex*>(ptr);
Vertex* vertices = static_cast<Vertex*>(ptr);
// 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
// // Triangle 1
// vertices[index++] = { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }; // Red
// vertices[index++] = { { 0.0f, 0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }; // Green
// vertices[index++] = { { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }; // Blue
//
// // Triangle 2
// vertices[index++] = { { -0.5f, 0.5f, 0.0f }, { 1.0f, 1.0f, 0.0f, 1.0f } }; // Yellow
// vertices[index++] = { { 0.0f, 0.8f, 0.0f }, { 0.0f, 1.0f, 1.0f, 1.0f } }; // Cyan
// vertices[index++] = { { 0.5f, 0.5f, 0.0f }, { 1.0f, 0.0f, 1.0f, 1.0f } }; // Magenta
// 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
if (CubeMesh)
{
CubeMesh->VertexOffset = index;
size_t vertexSize = CubeMesh->VertexCount * sizeof(Vertex);
MemCopy(vertices + index, CubeMesh->Vertices, vertexSize);
CubeMesh->IndexByteOffset = (index + CubeMesh->VertexCount) * sizeof(Vertex);
// Align
CubeMesh->IndexByteOffset = (CubeMesh->IndexByteOffset + 255) & static_cast<size_t>(~255);
size_t indexSize = CubeMesh->IndexCount * sizeof(uint16);
CubeMesh->IndexOffset = 0;
uint8* ptrOneByte = static_cast<uint8*>(ptr);
uint16* dst = reinterpret_cast<uint16*>(ptrOneByte + CubeMesh->IndexByteOffset);
MemCopy(dst, CubeMesh->Indices, indexSize);
}
UnmapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
}
CopyBuffer(cmd, ConstantBuffer, TransferBuffer, 256);
CopyBuffer(cmd, ConstantBuffer, TransferBuffer, CubeMesh->IndexByteOffset + (CubeMesh->IndexCount * sizeof(uint16)));
TransitionBufferToReadable(cmd, ConstantBuffer);
}
}
@@ -396,14 +418,19 @@ void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
struct PushData
{
float ViewProjection[16];
Matrix ViewProjection;
uint32 BufferIndex;
} pushData = {};
pushData.BufferIndex = descriptorIndex;
} pushData = {};
pushData.BufferIndex = descriptorIndex;
pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera());
SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
DrawPrimitives(pass, 6, 1, 0, 0);
SetIndexBuffer(cmd, ConstantBuffer, IndexFormat::UInt16, CubeMesh->IndexCount, CubeMesh->IndexByteOffset);
// DrawIndexedPrimitives(pass, static_cast<uint32>(CubeMesh->IndexCount), 1, 0, 0, 0);
DrawIndexedPrimitives(pass, static_cast<uint32>(CubeMesh->IndexCount), 1,
static_cast<uint32>(CubeMesh->IndexOffset), static_cast<uint32>(CubeMesh->VertexOffset), 0);
}
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
@@ -428,18 +455,32 @@ DepthStencilTargetInfo* JulietApplication::GetDepthTargetInfo()
Camera JulietApplication::GetDebugCamera()
{
static float orbitTime = 0.0f;
orbitTime += 0.016f;
static float time = 0.0f;
time += 0.016f;
float orbitSpeed = 0.5f;
float currentOrbitTime = time * orbitSpeed;
// --- Adjusted for 1-Meter Scale ---
float baseRadius = 2.5f; // Hover 2.5 meters away (down from 15.0f)
float radius = baseRadius;
/* Uncomment for active zoom
float zoomAmplitude = 1.0f; // Oscillate between 1.5m and 3.5m away
float zoomSpeed = 0.8f;
radius = baseRadius + (sinf(time * zoomSpeed) * zoomAmplitude);
*/
float zHeight = radius * 0.5f; // Keep a nice downward viewing angle
float radius = 30.0f;
Camera cam = {};
cam.Position = { cosf(orbitTime) * radius, sinf(orbitTime) * radius, 10.0f };
cam.Position = { cosf(currentOrbitTime) * radius, sinf(currentOrbitTime) * radius, zHeight };
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;
}
@@ -447,7 +488,6 @@ bool JulietApplication::IsRunning()
{
return Running;
}
namespace
{
JulietApplication EditorApplication;

View File

@@ -8,6 +8,7 @@
namespace Juliet
{
struct Mesh;
struct GraphicsTransferBuffer;
struct GraphicsBuffer;
struct GraphicsDevice;
@@ -45,11 +46,14 @@ class JulietApplication : public Juliet::IApplication
Juliet::GraphicsTransferBuffer* TransferBuffer = {};
Juliet::Texture* DepthBuffer = {};
Juliet::Mesh* CubeMesh = {};
Juliet::Arena* CubeArena = nullptr;
Juliet::Arena* GameArena = nullptr;
Juliet::Arena* GameScratchArena = nullptr;
bool Running = false;
int AutoCloseFrameCount = -1;
bool Running = false;
};
JulietApplication& GetEditorApplication();