Support lighting using a graphics buffer that is kep open!

This commit is contained in:
2026-02-23 19:24:57 -05:00
parent 4312ecd172
commit 3277624ec2
26 changed files with 342 additions and 146 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,14 @@
#ifndef ROOT_CONSTANTS_HLSL #ifndef ROOT_CONSTANTS_HLSL
#define ROOT_CONSTANTS_HLSL #define ROOT_CONSTANTS_HLSL
struct PointLight
{
float3 Position;
float Radius;
float3 Color;
float Intensity;
};
cbuffer RootConstants : register(b0, space0) cbuffer RootConstants : register(b0, space0)
{ {
row_major float4x4 ViewProjection; row_major float4x4 ViewProjection;
@@ -16,6 +24,9 @@ cbuffer RootConstants : register(b0, space0)
float LightPad; float LightPad;
float3 LightColor; float3 LightColor;
float AmbientIntensity; float AmbientIntensity;
uint LightBufferIndex;
uint ActiveLightCount;
}; };

View File

@@ -1,10 +1,46 @@
#include "RootConstants.hlsl" #include "RootConstants.hlsl"
float4 main(float4 Color : TEXCOORD0, float3 WorldNormal : TEXCOORD1) : SV_Target0 struct Input
{ {
float3 N = normalize(WorldNormal); float4 Color : TEXCOORD0;
float NdotL = saturate(dot(N, -LightDirection)); float3 WorldNormal : TEXCOORD1;
float3 diffuse = Color.rgb * LightColor * NdotL; float3 WorldPosition : TEXCOORD2;
float3 ambient = Color.rgb * AmbientIntensity; };
return float4(diffuse + ambient, Color.a);
float4 main(Input input) : SV_Target0
{
float3 normal = normalize(input.WorldNormal);
// Initial ambient component
float3 result = input.Color.rgb * LightColor * AmbientIntensity;
// Directional light contribution
float ndotl = max(dot(normal, -LightDirection), 0.0);
result += input.Color.rgb * LightColor * ndotl;
// Point lights
if (ActiveLightCount > 0)
{
StructuredBuffer<PointLight> pointLights = ResourceDescriptorHeap[LightBufferIndex];
for (uint i = 0; i < ActiveLightCount; ++i)
{
PointLight light = pointLights[i];
float3 lightDir = light.Position - input.WorldPosition;
float dist = length(lightDir);
if (dist < light.Radius)
{
lightDir = normalize(lightDir);
float attenuation = 1.0 - (dist / light.Radius);
attenuation = max(attenuation, 0.0);
float pndotl = max(dot(normal, lightDir), 0.0);
result += light.Color * input.Color.rgb * pndotl * attenuation * light.Intensity;
}
}
}
return float4(result, input.Color.a);
} }

View File

@@ -2,6 +2,7 @@ struct Output
{ {
float4 Color : TEXCOORD0; float4 Color : TEXCOORD0;
float3 WorldNormal : TEXCOORD1; float3 WorldNormal : TEXCOORD1;
float3 WorldPosition : TEXCOORD2;
float4 Position : SV_Position; float4 Position : SV_Position;
}; };
@@ -20,8 +21,10 @@ Output main(uint vertexIndex : SV_VertexID)
float3 normal = asfloat(buffer.Load3(offset + 12)); float3 normal = asfloat(buffer.Load3(offset + 12));
float4 col = asfloat(buffer.Load4(offset + 24)); float4 col = asfloat(buffer.Load4(offset + 24));
output.Position = mul(ViewProjection, mul(Model, float4(pos, 1.0f))); float4 worldPos = mul(Model, float4(pos, 1.0f));
output.Position = mul(ViewProjection, worldPos);
output.Color = col; output.Color = col;
output.WorldPosition = worldPos.xyz;
float3 worldNormal = mul((float3x3)Model, normal); float3 worldNormal = mul((float3x3)Model, normal);
output.WorldNormal = worldNormal; output.WorldNormal = worldNormal;

View File

@@ -193,11 +193,16 @@ namespace Juliet
{ {
Assert(Arena); Assert(Arena);
ArenaClear(Arena); if (InternalArena)
{
ArenaClear(Arena);
Data = nullptr;
Capacity = 0;
Reserve(ReserveSize);
}
DataFirst = DataLast = nullptr; DataFirst = DataLast = nullptr;
Data = nullptr;
Count = 0; Count = 0;
Capacity = 0;
} }
bool IsEmpty() const { return Count == 0; } bool IsEmpty() const { return Count == 0; }

View File

@@ -37,6 +37,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
(void)hPrev; (void)hPrev;
(void)szCmdLine; (void)szCmdLine;
(void)sw; (void)sw;
return Juliet::Bootstrap(JulietMain, __argc, __wargv); return Juliet::Bootstrap(JulietMain, __argc, __wargv);
} }
} }

View File

@@ -81,6 +81,13 @@ namespace Juliet
return result; return result;
} }
inline void MatrixTranslate(Matrix& m, const Vector3& v)
{
m.m[0][3] += v.x;
m.m[1][3] += v.y;
m.m[2][3] += v.z;
}
[[nodiscard]] inline Matrix MatrixRotation(float x, float y, float z) [[nodiscard]] inline Matrix MatrixRotation(float x, float y, float z)
{ {
return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z); return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z);

View File

@@ -164,6 +164,8 @@ namespace Juliet
extern JULIET_API GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GraphicsDevice> device, const BufferCreateInfo& createInfo); extern JULIET_API GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GraphicsDevice> device, const BufferCreateInfo& createInfo);
extern JULIET_API GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, extern JULIET_API GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device,
const TransferBufferCreateInfo& createInfo); const TransferBufferCreateInfo& createInfo);
extern JULIET_API void* MapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer);
extern JULIET_API void UnmapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer);
extern JULIET_API void* MapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer); extern JULIET_API void* MapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer);
extern JULIET_API void UnmapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer); extern JULIET_API void UnmapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer);
extern JULIET_API void CopyBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> dst, extern JULIET_API void CopyBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> dst,

View File

@@ -8,7 +8,6 @@ namespace Juliet
IndexBuffer = 1 << 0, IndexBuffer = 1 << 0,
ConstantBuffer = 1 << 1, ConstantBuffer = 1 << 1,
StructuredBuffer = 1 << 2, StructuredBuffer = 1 << 2,
VertexBuffer = 1 << 3,
}; };
enum class TransferBufferUsage : uint8 enum class TransferBufferUsage : uint8
@@ -20,7 +19,9 @@ namespace Juliet
struct BufferCreateInfo struct BufferCreateInfo
{ {
size_t Size; size_t Size;
size_t Stride;
BufferUsage Usage; BufferUsage Usage;
bool IsDynamic;
}; };
struct TransferBufferCreateInfo struct TransferBufferCreateInfo

View File

@@ -0,0 +1,15 @@
#pragma once
#include <Juliet.h>
#include <Core/Math/Vector.h>
namespace Juliet
{
struct PointLight
{
Vector3 Position;
float Radius;
Vector3 Color;
float Intensity;
};
} // namespace Juliet

View File

@@ -2,6 +2,7 @@
#include <Core/Container/Vector.h> #include <Core/Container/Vector.h>
#include <Core/Math/Matrix.h> #include <Core/Math/Matrix.h>
#include <Graphics/Lighting.h>
#include <Graphics/PushConstants.h> #include <Graphics/PushConstants.h>
#include <Graphics/VertexData.h> #include <Graphics/VertexData.h>
#include <Juliet.h> #include <Juliet.h>
@@ -17,13 +18,15 @@ namespace Juliet
struct GraphicsDevice; struct GraphicsDevice;
struct Mesh; struct Mesh;
using MeshID = index_t; using MeshID = index_t;
using LightID = index_t;
constexpr size_t kGeometryPage = Megabytes(64); constexpr size_t kGeometryPage = Megabytes(64);
constexpr size_t kIndexPage = Megabytes(32); constexpr size_t kIndexPage = Megabytes(32);
constexpr size_t kDefaultMeshNumber = 500; constexpr size_t kDefaultMeshNumber = 500;
constexpr size_t kDefaultVertexCount = 2'000'000; // Fit less than one geometry page constexpr size_t kDefaultVertexCount = 2'000'000; // Fit less than one geometry page
constexpr size_t kDefaultIndexCount = 16'000'000; // Fit less than one index page constexpr size_t kDefaultIndexCount = 16'000'000; // Fit less than one index page
constexpr size_t kDefaultLightCount = 1024;
struct MeshRenderer struct MeshRenderer
{ {
@@ -31,12 +34,16 @@ namespace Juliet
VectorArena<Mesh, kDefaultMeshNumber, false> Meshes; VectorArena<Mesh, kDefaultMeshNumber, false> Meshes;
VectorArena<Vertex, kDefaultVertexCount, false> Vertices; VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
VectorArena<Index, kDefaultIndexCount, false> Indices; VectorArena<Index, kDefaultIndexCount, false> Indices;
VectorArena<PointLight, kDefaultLightCount, false> PointLights;
GraphicsBuffer* VertexBuffer; GraphicsBuffer* VertexBuffer;
GraphicsBuffer* IndexBuffer; GraphicsBuffer* IndexBuffer;
GraphicsTransferBuffer* StreamCopyBuffer; GraphicsTransferBuffer* StreamCopyBuffer;
GraphicsTransferBuffer* LoadCopyBuffer; GraphicsTransferBuffer* LoadCopyBuffer;
GraphicsBuffer* LightsBuffer;
PointLight* MappedLights;
GraphicsDevice* Device; GraphicsDevice* Device;
GraphicsPipeline* Pipeline; GraphicsPipeline* Pipeline;
}; };
@@ -48,6 +55,12 @@ namespace Juliet
JULIET_API void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList); JULIET_API void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList);
JULIET_API void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData); JULIET_API void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData);
// Lights
[[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light);
JULIET_API void SetPointLightPosition(LightID id, const Vector3& position);
JULIET_API void SetPointLightColor(LightID id, const Vector3& color);
JULIET_API void ClearPointLights();
// Utils // Utils
[[nodiscard]] JULIET_API MeshID AddCube(); [[nodiscard]] JULIET_API MeshID AddCube();
[[nodiscard]] JULIET_API MeshID AddQuad(); [[nodiscard]] JULIET_API MeshID AddQuad();

View File

@@ -21,5 +21,8 @@ namespace Juliet
float LightPad; float LightPad;
Vector3 LightColor; Vector3 LightColor;
float AmbientIntensity; float AmbientIntensity;
uint32 LightBufferIndex;
uint32 ActiveLightCount;
}; };
} // namespace Juliet } // namespace Juliet

View File

@@ -17,7 +17,7 @@ namespace Juliet
{ {
Byte* OS_Reserve(size_t size) Byte* OS_Reserve(size_t size)
{ {
auto result = static_cast<Byte*>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE)); auto* result = static_cast<Byte*>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
return result; return result;
} }
@@ -68,8 +68,6 @@ namespace Juliet
{ {
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv)
{ {
(void)argc;
(void)argv;
SetUnhandledExceptionFilter(&ExceptionFilter); SetUnhandledExceptionFilter(&ExceptionFilter);
// Allow only one instance to be launched. // Allow only one instance to be launched.
@@ -87,12 +85,8 @@ namespace Juliet
GUID guid = WSAID_MULTIPLE_RIO; GUID guid = WSAID_MULTIPLE_RIO;
DWORD rio_byte = 0; DWORD rio_byte = 0;
SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
int result = WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
(void**)&w32_rio_functions, sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr); reinterpret_cast<void**>(&w32_rio_functions), sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr);
if (result != 0)
{
LogError(LogCategory::Core, "Couldnt get w32 RIO Functions. Error code %d", result);
}
closesocket(Sock); closesocket(Sock);
} }

View File

@@ -38,7 +38,6 @@ namespace Juliet::D3D12
case BufferUsage::ConstantBuffer: return "ConstantBuffer"; case BufferUsage::ConstantBuffer: return "ConstantBuffer";
case BufferUsage::StructuredBuffer: return "StructuredBuffer"; case BufferUsage::StructuredBuffer: return "StructuredBuffer";
case BufferUsage::IndexBuffer: return "IndexBuffer"; case BufferUsage::IndexBuffer: return "IndexBuffer";
case BufferUsage::VertexBuffer: return "VertexBuffer";
} }
return "Unknown"; return "Unknown";
} }
@@ -62,95 +61,62 @@ namespace Juliet::D3D12
Free(buffer); Free(buffer);
} }
D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, BufferUsage usage, D3D12BufferType type) D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, size_t stride, BufferUsage usage,
D3D12BufferType type, bool isDynamic)
{ {
auto buffer = static_cast<D3D12Buffer*>(Calloc(1, sizeof(D3D12Buffer))); auto* buffer = static_cast<D3D12Buffer*>(Calloc(1, sizeof(D3D12Buffer)));
if (!buffer) if (!buffer)
{ {
return nullptr; return nullptr;
} }
if (type == D3D12BufferType::Base && usage == BufferUsage::None)
{
Assert(false, "Creating Base buffer with BufferUsage::None is invalid");
DestroyBuffer(buffer);
return nullptr;
}
// Align size for Constant Buffers // Align size for Constant Buffers
if (usage == BufferUsage::ConstantBuffer) if (usage == BufferUsage::ConstantBuffer)
{ {
size = (size + 255U) & ~255U; size = (size + 255U) & ~255U;
} }
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
D3D12_HEAP_PROPERTIES heapProperties = {}; D3D12_HEAP_PROPERTIES heapProperties = {};
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
switch (type) D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
// Constant buffers or Dynamic buffers generally need to be uploaded every frame
const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer);
if (type == D3D12BufferType::TransferDownload)
{ {
case D3D12BufferType::Base: heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
}
else if (isUpload)
{
if (d3d12Driver->GPUUploadHeapSupported)
{ {
switch (usage) heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
{ initialState = D3D12_RESOURCE_STATE_COMMON;
case BufferUsage::None:
{
Assert(false, "Creating buffer with invalid usage");
DestroyBuffer(buffer);
return nullptr;
}
case BufferUsage::IndexBuffer:
case BufferUsage::StructuredBuffer:
case BufferUsage::VertexBuffer:
{
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
break;
}
case BufferUsage::ConstantBuffer:
{
if (d3d12Driver->GPUUploadHeapSupported)
{
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
}
else
{
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
}
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
break;
}
}
break;
} }
case D3D12BufferType::TransferDownload: else
{ {
heapProperties.Type = D3D12_HEAP_TYPE_READBACK; heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
break;
}
case D3D12BufferType::TransferUpload:
{
if (d3d12Driver->GPUUploadHeapSupported)
{
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
}
else
{
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
}
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
break;
} }
} }
else
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; {
// Must be a static buffer (Base type)
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
initialState = D3D12_RESOURCE_STATE_COMMON;
}
D3D12_RESOURCE_DESC desc = {}; D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
@@ -167,20 +133,22 @@ namespace Juliet::D3D12
Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s", Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s",
(void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage)); (void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage));
ID3D12Resource* handle = nullptr; ID3D12Resource* handle = nullptr;
HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc, HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc,
initialState, nullptr, IID_ID3D12Resource, initialState, nullptr, IID_ID3D12Resource,
reinterpret_cast<void**>(&handle)); reinterpret_cast<void**>(&handle));
if (FAILED(result)) if (FAILED(result))
{ {
Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", (uint32)result); Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast<uint32>(result));
Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d", Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d",
(unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type); (unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type);
HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason(); HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason();
if (FAILED(removeReason)) if (FAILED(removeReason))
{ {
Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", (uint32)removeReason); Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast<uint32>(removeReason));
} }
DestroyBuffer(buffer); DestroyBuffer(buffer);
@@ -205,20 +173,33 @@ namespace Juliet::D3D12
if (usage == BufferUsage::ConstantBuffer) if (usage == BufferUsage::ConstantBuffer)
{ {
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress(); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
cbvDesc.SizeInBytes = static_cast<uint32>(size); cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
cbvDesc.SizeInBytes = static_cast<uint32>(size);
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle); d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
} }
else if (usage == BufferUsage::StructuredBuffer) else if (usage == BufferUsage::StructuredBuffer)
{ {
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
srvDesc.Buffer.StructureByteStride = 0; if (stride > 0)
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; {
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.Buffer.NumElements = static_cast<uint32>(size / stride);
srvDesc.Buffer.StructureByteStride = static_cast<uint32>(stride);
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
}
else
{
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
srvDesc.Buffer.StructureByteStride = 0;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
}
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle); d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index); Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
} }
@@ -233,10 +214,10 @@ namespace Juliet::D3D12
} }
} // namespace } // namespace
GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage) GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic)
{ {
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get()); auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
return reinterpret_cast<GraphicsBuffer*>(CreateBuffer(d3d12Driver, size, usage, D3D12BufferType::Base)); return reinterpret_cast<GraphicsBuffer*>(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic));
} }
void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer) void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer)
@@ -248,8 +229,9 @@ namespace Juliet::D3D12
{ {
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get()); auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
return reinterpret_cast<GraphicsTransferBuffer*>( return reinterpret_cast<GraphicsTransferBuffer*>(
CreateBuffer(d3d12Driver, size, BufferUsage::None, CreateBuffer(d3d12Driver, size, 0, BufferUsage::None,
usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload)); usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload,
false));
} }
void DestroyGraphicsTransferBuffer(NonNullPtr<GraphicsTransferBuffer> buffer) void DestroyGraphicsTransferBuffer(NonNullPtr<GraphicsTransferBuffer> buffer)
@@ -276,6 +258,24 @@ namespace Juliet::D3D12
d3d12Buffer->Handle->Unmap(0, nullptr); d3d12Buffer->Handle->Unmap(0, nullptr);
} }
void* MapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
{
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
void* ptr = nullptr;
D3D12_RANGE readRange = { 0, 0 };
if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr)))
{
return nullptr;
}
return ptr;
}
void UnmapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
{
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
d3d12Buffer->Handle->Unmap(0, nullptr);
}
uint32 GetDescriptorIndex(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer) uint32 GetDescriptorIndex(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
{ {
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get()); auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());

View File

@@ -20,7 +20,7 @@ namespace Juliet::D3D12
size_t Size; size_t Size;
}; };
extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage); extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic);
extern void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer); extern void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer);
extern GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage); extern GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage);

View File

@@ -1032,8 +1032,10 @@ namespace Juliet::D3D12
device->DestroyShader = DestroyShader; device->DestroyShader = DestroyShader;
device->CreateGraphicsPipeline = CreateGraphicsPipeline; device->CreateGraphicsPipeline = CreateGraphicsPipeline;
device->DestroyGraphicsPipeline = DestroyGraphicsPipeline; device->DestroyGraphicsPipeline = DestroyGraphicsPipeline;
device->CreateGraphicsBuffer = CreateGraphicsBuffer; device->CreateGraphicsBuffer = CreateGraphicsBuffer;
device->DestroyGraphicsBuffer = DestroyGraphicsBuffer; device->DestroyGraphicsBuffer = DestroyGraphicsBuffer;
device->MapGraphicsBuffer = MapBuffer;
device->UnmapGraphicsBuffer = UnmapBuffer;
device->CreateGraphicsTransferBuffer = CreateGraphicsTransferBuffer; device->CreateGraphicsTransferBuffer = CreateGraphicsTransferBuffer;
device->DestroyGraphicsTransferBuffer = DestroyGraphicsTransferBuffer; device->DestroyGraphicsTransferBuffer = DestroyGraphicsTransferBuffer;
device->MapGraphicsTransferBuffer = MapBuffer; device->MapGraphicsTransferBuffer = MapBuffer;

View File

@@ -371,7 +371,7 @@ namespace Juliet
GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GraphicsDevice> device, const BufferCreateInfo& createInfo) GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GraphicsDevice> device, const BufferCreateInfo& createInfo)
{ {
return device->CreateGraphicsBuffer(device->Driver, createInfo.Size, createInfo.Usage); return device->CreateGraphicsBuffer(device->Driver, createInfo.Size, createInfo.Stride, createInfo.Usage, createInfo.IsDynamic);
} }
GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, const TransferBufferCreateInfo& createInfo) GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, const TransferBufferCreateInfo& createInfo)
@@ -379,6 +379,16 @@ namespace Juliet
return device->CreateGraphicsTransferBuffer(device->Driver, createInfo.Size, createInfo.Usage); return device->CreateGraphicsTransferBuffer(device->Driver, createInfo.Size, createInfo.Usage);
} }
void* MapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
{
return device->MapGraphicsBuffer(device->Driver, buffer);
}
void UnmapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
{
device->UnmapGraphicsBuffer(device->Driver, buffer);
}
void* MapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer) void* MapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer)
{ {
return device->MapGraphicsTransferBuffer(device->Driver, buffer); return device->MapGraphicsTransferBuffer(device->Driver, buffer);

View File

@@ -100,9 +100,12 @@ namespace Juliet
void (*DestroyTexture)(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture); void (*DestroyTexture)(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture);
// Buffers // Buffers
GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage); GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic);
void (*DestroyGraphicsBuffer)(NonNullPtr<GraphicsBuffer> buffer); void (*DestroyGraphicsBuffer)(NonNullPtr<GraphicsBuffer> buffer);
void* (*MapGraphicsBuffer)(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsBuffer> buffer);
void (*UnmapGraphicsBuffer)(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsBuffer> buffer);
GraphicsTransferBuffer* (*CreateGraphicsTransferBuffer)(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage); GraphicsTransferBuffer* (*CreateGraphicsTransferBuffer)(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage);
void (*DestroyGraphicsTransferBuffer)(NonNullPtr<GraphicsTransferBuffer> buffer); void (*DestroyGraphicsTransferBuffer)(NonNullPtr<GraphicsTransferBuffer> buffer);

View File

@@ -150,8 +150,8 @@ namespace Juliet
TextureCreateInfo texCI = {}; TextureCreateInfo texCI = {};
texCI.Type = TextureType::Texture_2D; texCI.Type = TextureType::Texture_2D;
texCI.Width = (uint32)width; texCI.Width = static_cast<uint32>(width);
texCI.Height = (uint32)height; texCI.Height = static_cast<uint32>(height);
texCI.Format = TextureFormat::R8G8B8A8_UNORM; texCI.Format = TextureFormat::R8G8B8A8_UNORM;
texCI.Flags = TextureUsageFlag::Sampler; texCI.Flags = TextureUsageFlag::Sampler;
@@ -160,10 +160,10 @@ namespace Juliet
texCI.SampleCount = TextureSampleCount::One; texCI.SampleCount = TextureSampleCount::One;
g_ImGuiState.FontTexture = CreateTexture(device, texCI); g_ImGuiState.FontTexture = CreateTexture(device, texCI);
io.Fonts->SetTexID((ImTextureID)g_ImGuiState.FontTexture); io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(g_ImGuiState.FontTexture));
// Upload data // Upload data
uint32 rowPitch = (uint32)width * 4u; uint32 rowPitch = static_cast<uint32>(width) * 4u;
uint32 alignedRowPitch = (rowPitch + 255u) & ~255u; uint32 alignedRowPitch = (rowPitch + 255u) & ~255u;
uint32 textureSize = alignedRowPitch * static_cast<uint32>(height); uint32 textureSize = alignedRowPitch * static_cast<uint32>(height);
@@ -177,7 +177,7 @@ namespace Juliet
return false; return false;
} }
auto dst = (uint8*)MapGraphicsTransferBuffer(device, tb); auto* dst = static_cast<uint8*>(MapGraphicsTransferBuffer(device, tb));
for (uint32 y = 0; y < static_cast<uint32>(height); ++y) for (uint32 y = 0; y < static_cast<uint32>(height); ++y)
{ {
@@ -315,13 +315,13 @@ namespace Juliet
FrameResources& currentFrame = g_ImGuiState.Frames[g_ImGuiState.FrameIndex]; FrameResources& currentFrame = g_ImGuiState.Frames[g_ImGuiState.FrameIndex];
// Upload Buffers // Upload Buffers
uint32 totalVtx = (uint32)drawData->TotalVtxCount; uint32 totalVtx = static_cast<uint32>(drawData->TotalVtxCount);
uint32 totalIdx = (uint32)drawData->TotalIdxCount; uint32 totalIdx = static_cast<uint32>(drawData->TotalIdxCount);
EnsureBufferSize(currentFrame, totalVtx * sizeof(ImDrawVert), totalIdx * sizeof(ImDrawIdx)); EnsureBufferSize(currentFrame, totalVtx * sizeof(ImDrawVert), totalIdx * sizeof(ImDrawIdx));
auto vtxDst = (ImDrawVert*)MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload); auto* vtxDst = static_cast<ImDrawVert*>(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload));
auto idxDst = (ImDrawIdx*)MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload); auto* idxDst = static_cast<ImDrawIdx*>(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload));
for (int n = 0; n < drawData->CmdListsCount; n++) for (int n = 0; n < drawData->CmdListsCount; n++)
{ {
@@ -403,28 +403,18 @@ namespace Juliet
SetScissorRect(renderPass, scissorRect); SetScissorRect(renderPass, scissorRect);
// Bind Texture // Bind Texture
uint32 textureIndex = GetDescriptorIndex(g_ImGuiState.Device, (Texture*)pcmd->GetTexID()); uint32 textureIndex = GetDescriptorIndex(g_ImGuiState.Device, reinterpret_cast<Texture*>(pcmd->GetTexID()));
// Push Constants // Push Constants
// Layout: ViewProjection(64) + BufferIndex(4) + TextureIndex(4) + VertexOffset(4) + Padding(4) + Scale(8) + Translate(8) PushData pushData = {}; // Zero-initialize all fields
struct
{
float dummyVP[16]; // Occupy VP slot
uint32 bufferIndex;
uint32 textureIndex;
uint32 vertexOffset; // Base vertex for indexed bindless drawing
uint32 padding; // Alignment padding
float scale[2];
float translate[2];
} pushData = {}; // Zero-initialize all fields
pushData.bufferIndex = GetDescriptorIndex(g_ImGuiState.Device, currentFrame.VertexBuffer); pushData.BufferIndex = GetDescriptorIndex(g_ImGuiState.Device, currentFrame.VertexBuffer);
pushData.textureIndex = textureIndex; pushData.TextureIndex = textureIndex;
pushData.vertexOffset = pcmd->VtxOffset + globalVtxOffset; // Pass vertex offset for bindless pushData.VertexOffset = pcmd->VtxOffset + globalVtxOffset; // Pass vertex offset for bindless
pushData.scale[0] = scale[0]; pushData.Scale[0] = scale[0];
pushData.scale[1] = scale[1]; pushData.Scale[1] = scale[1];
pushData.translate[0] = translate[0]; pushData.Translate[0] = translate[0];
pushData.translate[1] = translate[1]; pushData.Translate[1] = translate[1];
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);

View File

@@ -20,6 +20,7 @@ namespace Juliet
g_MeshRenderer.Meshes.Create(arena JULIET_DEBUG_PARAM("Meshes")); g_MeshRenderer.Meshes.Create(arena JULIET_DEBUG_PARAM("Meshes"));
g_MeshRenderer.Vertices.Create(arena JULIET_DEBUG_PARAM("Vertices")); g_MeshRenderer.Vertices.Create(arena JULIET_DEBUG_PARAM("Vertices"));
g_MeshRenderer.Indices.Create(arena JULIET_DEBUG_PARAM("Indices")); g_MeshRenderer.Indices.Create(arena JULIET_DEBUG_PARAM("Indices"));
g_MeshRenderer.PointLights.Create(arena JULIET_DEBUG_PARAM("PointLights"));
} }
bool InitializeMeshRendererGraphics(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window) bool InitializeMeshRendererGraphics(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
@@ -53,6 +54,8 @@ namespace Juliet
.DepthStencilFormat = TextureFormat::D32_FLOAT, .DepthStencilFormat = TextureFormat::D32_FLOAT,
.HasDepthStencilTarget = true }; .HasDepthStencilTarget = true };
pipelineCI.RasterizerState.FillMode = FillMode::Solid; pipelineCI.RasterizerState.FillMode = FillMode::Solid;
pipelineCI.RasterizerState.CullMode = CullMode::None;
pipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise;
pipelineCI.DepthStencilState.EnableDepthTest = true; pipelineCI.DepthStencilState.EnableDepthTest = true;
pipelineCI.DepthStencilState.EnableDepthWrite = true; pipelineCI.DepthStencilState.EnableDepthWrite = true;
pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less; pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;
@@ -67,13 +70,33 @@ namespace Juliet
// Create the vertex and index buffers // Create the vertex and index buffers
BufferCreateInfo vertexBufferCI = {}; BufferCreateInfo vertexBufferCI = {};
vertexBufferCI.Size = kGeometryPage; vertexBufferCI.Size = kGeometryPage;
vertexBufferCI.Stride = 0;
vertexBufferCI.Usage = BufferUsage::StructuredBuffer; vertexBufferCI.Usage = BufferUsage::StructuredBuffer;
g_MeshRenderer.VertexBuffer = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI); g_MeshRenderer.VertexBuffer = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI);
Assert(g_MeshRenderer.VertexBuffer != nullptr);
BufferCreateInfo indexBufferCI = {}; BufferCreateInfo indexBufferCI = {};
indexBufferCI.Size = kIndexPage; indexBufferCI.Size = kIndexPage;
indexBufferCI.Usage = BufferUsage::IndexBuffer; indexBufferCI.Usage = BufferUsage::IndexBuffer;
g_MeshRenderer.IndexBuffer = CreateGraphicsBuffer(graphicsDevice, indexBufferCI); g_MeshRenderer.IndexBuffer = CreateGraphicsBuffer(graphicsDevice, indexBufferCI);
Assert(g_MeshRenderer.IndexBuffer != nullptr);
// Lights Buffer
BufferCreateInfo lightsBufferCI = {};
lightsBufferCI.Size = 1024 * sizeof(PointLight); // Max 1024 lights for now
lightsBufferCI.Stride = sizeof(PointLight);
lightsBufferCI.Usage = BufferUsage::StructuredBuffer;
lightsBufferCI.IsDynamic = true;
g_MeshRenderer.LightsBuffer = CreateGraphicsBuffer(graphicsDevice, lightsBufferCI);
Assert(g_MeshRenderer.LightsBuffer != nullptr);
g_MeshRenderer.MappedLights = static_cast<PointLight*>(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.LightsBuffer));
Assert(g_MeshRenderer.MappedLights != nullptr);
// Sync existing lights that might have been added before graphics initialization
for (index_t i = 0; i < g_MeshRenderer.PointLights.Count; ++i)
{
g_MeshRenderer.MappedLights[i] = g_MeshRenderer.PointLights.Data[i];
}
if (vertexShader) if (vertexShader)
{ {
@@ -88,7 +111,6 @@ namespace Juliet
CommandList* loadCmd = AcquireCommandList(device); CommandList* loadCmd = AcquireCommandList(device);
LoadMeshesOnGPU(loadCmd); LoadMeshesOnGPU(loadCmd);
SubmitCommandLists(loadCmd); SubmitCommandLists(loadCmd);
return result; return result;
} }
@@ -103,6 +125,12 @@ namespace Juliet
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer); DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer);
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
if (g_MeshRenderer.LightsBuffer)
{
UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
}
} }
void ShutdownMeshRenderer() void ShutdownMeshRenderer()
@@ -110,6 +138,7 @@ namespace Juliet
g_MeshRenderer.Indices.Destroy(); g_MeshRenderer.Indices.Destroy();
g_MeshRenderer.Vertices.Destroy(); g_MeshRenderer.Vertices.Destroy();
g_MeshRenderer.Meshes.Destroy(); g_MeshRenderer.Meshes.Destroy();
g_MeshRenderer.PointLights.Destroy();
} }
void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList) void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList)
@@ -159,6 +188,8 @@ namespace Juliet
MemCopy(ptrOneByte + indexOfByteOffset, g_MeshRenderer.Indices.Data, totalIndexBytes); MemCopy(ptrOneByte + indexOfByteOffset, g_MeshRenderer.Indices.Data, totalIndexBytes);
UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
CopyBuffer(cmdList, g_MeshRenderer.VertexBuffer, g_MeshRenderer.LoadCopyBuffer, totalVertexBytes, 0, 0); CopyBuffer(cmdList, g_MeshRenderer.VertexBuffer, g_MeshRenderer.LoadCopyBuffer, totalVertexBytes, 0, 0);
CopyBuffer(cmdList, g_MeshRenderer.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset); CopyBuffer(cmdList, g_MeshRenderer.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset);
@@ -181,8 +212,11 @@ namespace Juliet
BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline); BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline);
uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
uint32 lightDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
pushData.BufferIndex = vertexDescriptorIndex; pushData.BufferIndex = vertexDescriptorIndex;
pushData.LightBufferIndex = lightDescriptorIndex;
pushData.ActiveLightCount = static_cast<uint32>(g_MeshRenderer.PointLights.Count);
SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0); SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0);
@@ -202,6 +236,43 @@ namespace Juliet
} }
} }
LightID AddPointLight(const PointLight& light)
{
Assert(g_MeshRenderer.PointLights.Count < kDefaultLightCount);
LightID id = g_MeshRenderer.PointLights.Count;
g_MeshRenderer.PointLights.PushBack(light);
if (g_MeshRenderer.MappedLights)
{
g_MeshRenderer.MappedLights[id] = light;
}
return id;
}
void SetPointLightPosition(LightID id, const Vector3& position)
{
Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
g_MeshRenderer.PointLights.Data[id].Position = position;
if (g_MeshRenderer.MappedLights)
{
g_MeshRenderer.MappedLights[id].Position = position;
}
}
void SetPointLightColor(LightID id, const Vector3& color)
{
Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
g_MeshRenderer.PointLights.Data[id].Color = color;
if (g_MeshRenderer.MappedLights)
{
g_MeshRenderer.MappedLights[id].Color = color;
}
}
void ClearPointLights()
{
g_MeshRenderer.PointLights.Clear();
}
MeshID AddCube() MeshID AddCube()
{ {
Mesh result = {}; Mesh result = {};
@@ -300,6 +371,7 @@ namespace Juliet
Assert(id < static_cast<MeshID>(g_MeshRenderer.Meshes.Count)); Assert(id < static_cast<MeshID>(g_MeshRenderer.Meshes.Count));
g_MeshRenderer.Meshes.Data[id].Transform = transform; g_MeshRenderer.Meshes.Data[id].Transform = transform;
} }
#if ALLOW_SHADER_HOT_RELOAD #if ALLOW_SHADER_HOT_RELOAD
void ReloadMeshRendererShaders() void ReloadMeshRendererShaders()
{ {

View File

@@ -1,5 +1,12 @@
#include "main.h" #include "main.h"
#ifdef global
#undef global
#endif
#include <ios>
#include <iosfwd>
#define global static
#include <Core/Application/ApplicationManager.h> #include <Core/Application/ApplicationManager.h>
#include <Core/Common/EnumUtils.h> #include <Core/Common/EnumUtils.h>
#include <Core/Common/String.h> #include <Core/Common/String.h>
@@ -44,13 +51,6 @@ static bool ShowMemoryDebugger = false;
using namespace Juliet; using namespace Juliet;
extern "C" {
__declspec(dllexport) extern const unsigned int D3D12SDKVersion = 615;
}
extern "C" {
__declspec(dllexport) extern const char* D3D12SDKPath = ".\\";
}
namespace namespace
{ {
using GameInit_t = void (*)(GameInitParams*); using GameInit_t = void (*)(GameInitParams*);
@@ -64,6 +64,9 @@ namespace
} Game; } Game;
const char* GameFunctionTable[] = { "GameInit", "GameShutdown", "GameUpdate" }; const char* GameFunctionTable[] = { "GameInit", "GameShutdown", "GameUpdate" };
LightID RedLightID = 0;
LightID BlueLightID = 0;
} // namespace } // namespace
void JulietApplication::Init(NonNullPtr<Arena>) void JulietApplication::Init(NonNullPtr<Arena>)
@@ -75,6 +78,7 @@ void JulietApplication::Init(NonNullPtr<Arena>)
#if JULIET_DEBUG #if JULIET_DEBUG
config.EnableDebug = true; config.EnableDebug = true;
#endif #endif
GraphicsDevice = CreateGraphicsDevice(config); GraphicsDevice = CreateGraphicsDevice(config);
MainWindow = CreatePlatformWindow("Juliet Editor", 1280, 720); MainWindow = CreatePlatformWindow("Juliet Editor", 1280, 720);
@@ -119,6 +123,21 @@ void JulietApplication::Init(NonNullPtr<Arena>)
SetMeshTransform(cube, MatrixTranslation(x, y, 0.0f) * rotation); SetMeshTransform(cube, MatrixTranslation(x, y, 0.0f) * rotation);
} }
} }
// Start with some default test lights
PointLight redLight = {};
redLight.Position = { 5.0f, 5.0f, 2.0f };
redLight.Radius = 10.0f;
redLight.Color = { 1.0f, 0.2f, 0.2f };
redLight.Intensity = 5.0f;
RedLightID = AddPointLight(redLight);
PointLight blueLight = {};
blueLight.Position = { -5.0f, 0.0f, 2.0f };
blueLight.Radius = 15.0f;
blueLight.Color = { 0.2f, 0.2f, 1.0f };
blueLight.Intensity = 8.0f;
BlueLightID = AddPointLight(blueLight);
} }
GameCode.Functions = reinterpret_cast<void**>(&Game); GameCode.Functions = reinterpret_cast<void**>(&Game);
@@ -232,14 +251,23 @@ void JulietApplication::Update()
} }
} }
ArenaClear(GameScratchArena);
Vector3 redLightPos{ cosf(CameraTime * 2.0f) * 5.0f, sinf(CameraTime * 2.0f) * 5.0f, 2.0f };
SetPointLightPosition(RedLightID, redLightPos);
Vector3 blueLightPos{ -5.0f, cosf(CameraTime) * 3.0f, 2.0f };
SetPointLightPosition(BlueLightID, blueLightPos);
#ifdef JULIET_ENABLE_IMGUI #ifdef JULIET_ENABLE_IMGUI
// ImGui::ShowDemoWindow(); ImGui::ShowDemoWindow();
#endif #endif
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 }, { 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, 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_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); DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 0.5f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
DebugDisplay_DrawSphere(blueLightPos, 0.5f, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
DebugDisplay_DrawSphere(redLightPos, 0.5f, { 1.0f, 0.0f, 0.0f, 1.0f }, true);
Game.Update(0.0f); Game.Update(0.0f);