Compare commits
21 Commits
7a5bb0526f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 446670bd29 | |||
| 581656568b | |||
| 3277624ec2 | |||
| 4312ecd172 | |||
| 1056301981 | |||
| 932c45d844 | |||
| a781facd48 | |||
| 1e1ec84fa1 | |||
| f98be3c7f3 | |||
| bc6ce3afb6 | |||
| 816fdc27b1 | |||
| b38cc5e3d5 | |||
| 431015f009 | |||
| a7947bfa17 | |||
| 8e83cd32f6 | |||
| 2362cefbc0 | |||
| bbd1095227 | |||
| 49fc0a24d1 | |||
| e1eb9976ad | |||
| 3492cf52d8 | |||
| 762cfe52cf |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -13,6 +13,7 @@
|
|||||||
.idea/
|
.idea/
|
||||||
.vs/
|
.vs/
|
||||||
[Ii]ntermediate/
|
[Ii]ntermediate/
|
||||||
|
[sS]hip/
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
build_*.txt
|
build_*.txt
|
||||||
@@ -51,3 +52,5 @@ launch_*.txt
|
|||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
misc/agent_error.log
|
||||||
|
misc/agent_output_ship.log
|
||||||
|
|||||||
292
AgentData/lighting_and_skybox_plan.md
Normal file
292
AgentData/lighting_and_skybox_plan.md
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
# Lighting & Skybox Plan
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
| Item | Current |
|
||||||
|
|------|---------|
|
||||||
|
| Vertex format | `float3 Position` + `float4 Color` (28 bytes, no normals) |
|
||||||
|
| Vertex shader | [Triangle.vert.hlsl](file:///w:/Classified/Juliet/Assets/source/Triangle.vert.hlsl) — bindless buffer read, `mul(VP, mul(Model, pos))` |
|
||||||
|
| Fragment shader | [SolidColor.frag.hlsl](file:///w:/Classified/Juliet/Assets/source/SolidColor.frag.hlsl) — passthrough `return Color` |
|
||||||
|
| Push constants | `ViewProjection` + `Model` + `BufferIndex` + extras |
|
||||||
|
| Texturing | None — no sampler usage, no texture reads |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: Add Normals to Vertex Data
|
||||||
|
|
||||||
|
Lighting requires normals. This is the foundation for everything else.
|
||||||
|
|
||||||
|
### Vertex Format Change
|
||||||
|
|
||||||
|
```diff
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
float Position[3];
|
||||||
|
+ float Normal[3];
|
||||||
|
float Color[4];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Stride**: 28 → 40 bytes
|
||||||
|
- Update `Triangle.vert.hlsl` stride constant: `uint stride = 40;`
|
||||||
|
- Load normal after position: `float3 normal = asfloat(buffer.Load3(offset + 12));`
|
||||||
|
- Load color shifts to: `float4 col = asfloat(buffer.Load4(offset + 24));`
|
||||||
|
|
||||||
|
### Files to modify
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| [VertexData.h](file:///w:/Classified/Juliet/Juliet/include/Graphics/VertexData.h) | Add `float Normal[3]` to `Vertex` |
|
||||||
|
| [MeshRenderer.cpp](file:///w:/Classified/Juliet/Juliet/src/Graphics/MeshRenderer.cpp) | Update `AddCube()` to include per-face normals |
|
||||||
|
| [Triangle.vert.hlsl](file:///w:/Classified/Juliet/Assets/source/Triangle.vert.hlsl) | Update stride, load normal, pass to fragment |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Basic Directional Light (Diffuse)
|
||||||
|
|
||||||
|
Simple single directional light with diffuse (Lambert) shading.
|
||||||
|
|
||||||
|
### Approach: Push light data through RootConstants
|
||||||
|
|
||||||
|
Add light direction and color to `RootConstants.hlsl` and the C++ `PushData`:
|
||||||
|
|
||||||
|
```hlsl
|
||||||
|
// RootConstants.hlsl additions
|
||||||
|
float3 LightDirection; // Normalized, world-space
|
||||||
|
float _LightPad;
|
||||||
|
float3 LightColor;
|
||||||
|
float AmbientIntensity;
|
||||||
|
```
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// PushData additions
|
||||||
|
Vector3 LightDirection;
|
||||||
|
float _LightPad;
|
||||||
|
Vector3 LightColor;
|
||||||
|
float AmbientIntensity;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shader Changes
|
||||||
|
|
||||||
|
**Vertex shader** — transform normal to world space and pass it to fragment:
|
||||||
|
|
||||||
|
```hlsl
|
||||||
|
// Triangle.vert.hlsl output struct
|
||||||
|
struct Output
|
||||||
|
{
|
||||||
|
float4 Color : TEXCOORD0;
|
||||||
|
float3 WorldNormal : TEXCOORD1;
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
// In main():
|
||||||
|
float3 worldNormal = mul((float3x3)Model, normal);
|
||||||
|
output.WorldNormal = worldNormal;
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Using `(float3x3)Model` for normal transform is only correct for uniform-scale transforms. For non-uniform scale, you'd need the inverse-transpose. Fine for now with translation-only transforms.
|
||||||
|
|
||||||
|
**Fragment shader** — apply Lambert diffuse:
|
||||||
|
|
||||||
|
```hlsl
|
||||||
|
// SolidColor.frag.hlsl → rename to Lit.frag.hlsl
|
||||||
|
#include "RootConstants.hlsl"
|
||||||
|
|
||||||
|
float4 main(float4 Color : TEXCOORD0, float3 WorldNormal : TEXCOORD1) : SV_Target0
|
||||||
|
{
|
||||||
|
float3 N = normalize(WorldNormal);
|
||||||
|
float NdotL = saturate(dot(N, -LightDirection));
|
||||||
|
float3 diffuse = Color.rgb * LightColor * NdotL;
|
||||||
|
float3 ambient = Color.rgb * AmbientIntensity;
|
||||||
|
return float4(diffuse + ambient, Color.a);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files to modify
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| [RootConstants.hlsl](file:///w:/Classified/Juliet/Assets/source/RootConstants.hlsl) | Add light params |
|
||||||
|
| [MeshRenderer.h](file:///w:/Classified/Juliet/Juliet/include/Graphics/MeshRenderer.h) | Add light params to `PushData` |
|
||||||
|
| [Triangle.vert.hlsl](file:///w:/Classified/Juliet/Assets/source/Triangle.vert.hlsl) | Pass world normal to fragment |
|
||||||
|
| [SolidColor.frag.hlsl](file:///w:/Classified/Juliet/Assets/source/SolidColor.frag.hlsl) | Lambert diffuse + ambient |
|
||||||
|
| [DebugDisplayRenderer.cpp](file:///w:/Classified/Juliet/Juliet/src/Graphics/DebugDisplayRenderer.cpp) | Update push data struct to match new layout |
|
||||||
|
| [main.cpp](file:///w:/Classified/Juliet/JulietApp/main.cpp) | Set `LightDirection`, `LightColor`, `AmbientIntensity` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: Skybox
|
||||||
|
|
||||||
|
A skybox renders a cubemap texture behind all geometry, giving the scene a background.
|
||||||
|
|
||||||
|
### Approach: Fullscreen-triangle with inverse VP
|
||||||
|
|
||||||
|
Render a fullscreen triangle as the very last thing (or first with depth write off), sample a cubemap using the camera view direction reconstructed from screen coordinates.
|
||||||
|
|
||||||
|
### New Assets
|
||||||
|
|
||||||
|
- **Skybox cubemap texture** — a `.dds` or 6 `.png` face images loaded as a `TextureCube`
|
||||||
|
- **New shaders**: `Skybox.vert.hlsl` + `Skybox.frag.hlsl`
|
||||||
|
|
||||||
|
### Shader Design
|
||||||
|
|
||||||
|
**Vertex shader** — fullscreen triangle using `SV_VertexID`:
|
||||||
|
|
||||||
|
```hlsl
|
||||||
|
// Skybox.vert.hlsl
|
||||||
|
#include "RootConstants.hlsl"
|
||||||
|
|
||||||
|
struct Output
|
||||||
|
{
|
||||||
|
float3 ViewDir : TEXCOORD0;
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
Output main(uint vertexID : SV_VertexID)
|
||||||
|
{
|
||||||
|
Output output;
|
||||||
|
|
||||||
|
// Fullscreen triangle
|
||||||
|
float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
|
||||||
|
float4 clipPos = float4(uv * 2.0 - 1.0, 1.0, 1.0);
|
||||||
|
clipPos.y = -clipPos.y;
|
||||||
|
|
||||||
|
output.Position = clipPos;
|
||||||
|
|
||||||
|
// Reconstruct view direction from clip space
|
||||||
|
// InverseViewProjection needs to be added to RootConstants
|
||||||
|
float4 worldPos = mul(InverseViewProjection, clipPos);
|
||||||
|
output.ViewDir = worldPos.xyz / worldPos.w;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fragment shader** — sample cubemap:
|
||||||
|
|
||||||
|
```hlsl
|
||||||
|
// Skybox.frag.hlsl
|
||||||
|
#include "RootConstants.hlsl"
|
||||||
|
|
||||||
|
float4 main(float3 ViewDir : TEXCOORD0) : SV_Target0
|
||||||
|
{
|
||||||
|
TextureCube skybox = ResourceDescriptorHeap[TextureIndex];
|
||||||
|
SamplerState samp = SamplerDescriptorHeap[0]; // Linear clamp
|
||||||
|
return skybox.Sample(samp, normalize(ViewDir));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pipeline Requirements
|
||||||
|
|
||||||
|
| Setting | Value |
|
||||||
|
|---------|-------|
|
||||||
|
| Depth write | **Off** (skybox is infinitely far) |
|
||||||
|
| Depth test | **LessEqual** or **Off** (render behind everything) |
|
||||||
|
| Cull mode | **None** (fullscreen triangle) |
|
||||||
|
| Draw call | `Draw(3, 0)` — no vertex buffer needed |
|
||||||
|
|
||||||
|
### New C++ Components
|
||||||
|
|
||||||
|
1. **Cubemap loading** — need to create `TextureCube` from 6 face images or a `.dds` cubemap file
|
||||||
|
2. **Skybox pipeline** — new `GraphicsPipeline` with the skybox shaders and the pipeline settings above
|
||||||
|
3. **Sampler** — need at least one linear sampler in the sampler heap (may already exist for ImGui)
|
||||||
|
4. **`InverseViewProjection`** — add to `RootConstants` and compute in C++ via a `MatrixInverse` function
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> `MatrixInverse` needs to be implemented in `Matrix.h`. This is a non-trivial 4×4 matrix inversion (adjugate/determinant method or Gauss-Jordan).
|
||||||
|
|
||||||
|
### Files to modify/create
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| [NEW] `Skybox.vert.hlsl` | Fullscreen triangle + view direction |
|
||||||
|
| [NEW] `Skybox.frag.hlsl` | Cubemap sample |
|
||||||
|
| [RootConstants.hlsl](file:///w:/Classified/Juliet/Assets/source/RootConstants.hlsl) | Add `InverseViewProjection` |
|
||||||
|
| [Matrix.h](file:///w:/Classified/Juliet/Juliet/include/Core/Math/Matrix.h) | Add `MatrixInverse()` |
|
||||||
|
| [MeshRenderer.h](file:///w:/Classified/Juliet/Juliet/include/Graphics/MeshRenderer.h) | Add `InverseViewProjection` to `PushData` |
|
||||||
|
| [main.cpp](file:///w:/Classified/Juliet/JulietApp/main.cpp) | Create skybox pipeline, load cubemap, render skybox |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Implementation Order
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A["Phase 1<br/>Add Normals"] --> B["Phase 2<br/>Directional Light"]
|
||||||
|
B --> C["Phase 3<br/>Skybox"]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Phase 1** (normals) is the smallest and unblocks Phase 2
|
||||||
|
2. **Phase 2** (lighting) gives the cubes visible 3D depth immediately
|
||||||
|
3. **Phase 3** (skybox) is independent of lighting but benefits from having `MatrixInverse` and sampler infrastructure
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Phases 1+2 together are a single session of work (~8 files). Phase 3 is larger due to cubemap loading and new pipeline creation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Open Questions (Answered)
|
||||||
|
|
||||||
|
1. **Cubemap source** — **Procedural gradient skybox** chosen because asset loading infrastructure is not yet established.
|
||||||
|
2. **Sampler heap** — Evaluate what exists. However, with a procedural skybox, we won't need a sampler for Phase 3! (The sky color can be procedurally generated from the reconstructed view direction).
|
||||||
|
3. **Specular** — **Blinn-Phong** specular, structured in an agnostic way so PBR (physically based rendering) parameters can be plugged in later.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: Forward Rendered Entity Lights
|
||||||
|
|
||||||
|
A simple, fast forward renderer using a Global Structured Buffer for entity-based point lights.
|
||||||
|
|
||||||
|
### Approach: Bindless Global Lights Buffer
|
||||||
|
|
||||||
|
Instead of passing each light via PushConstants, we pass a `StructuredBuffer<PointLight>` index and iterate over the active lights in the fragment shader.
|
||||||
|
|
||||||
|
### New C++ Components
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct PointLight
|
||||||
|
{
|
||||||
|
Vector3 Position;
|
||||||
|
float Radius;
|
||||||
|
Vector3 Color;
|
||||||
|
float Intensity;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Lights Buffer Allocation**: Allocate a `StructuredBuffer` large enough for all potential lights (e.g., max 1024).
|
||||||
|
2. **Buffer Upload**: Loop through the active game entity lights every frame and upload them using the TransferBuffer system.
|
||||||
|
3. **PushData Update**:
|
||||||
|
- `uint32 LightsBufferIndex`
|
||||||
|
- `uint32 ActiveLightCount`
|
||||||
|
|
||||||
|
### Shader Design
|
||||||
|
|
||||||
|
**Fragment Shader Expansion** loop over all `ActiveLightCount` to compute the attenuation and diffuse, then accumulate.
|
||||||
|
|
||||||
|
```hlsl
|
||||||
|
StructuredBuffer<PointLight> lights = ResourceDescriptorHeap[LightsBufferIndex];
|
||||||
|
|
||||||
|
float3 totalDiffuse = Color.rgb * LightColor * NdotL; // Include Directional Sun
|
||||||
|
|
||||||
|
for (uint i = 0; i < ActiveLightCount; ++i)
|
||||||
|
{
|
||||||
|
PointLight light = lights[i];
|
||||||
|
|
||||||
|
float3 lightVector = light.Position - WorldPosition;
|
||||||
|
float distance = length(lightVector);
|
||||||
|
|
||||||
|
if (distance > light.Radius) continue;
|
||||||
|
|
||||||
|
float3 L = lightVector / distance;
|
||||||
|
float NdotL = saturate(dot(N, L));
|
||||||
|
|
||||||
|
float attenuation = 1.0 - saturate(distance / light.Radius);
|
||||||
|
attenuation *= attenuation; // inverse square-ish
|
||||||
|
|
||||||
|
totalDiffuse += Color.rgb * light.Color * light.Intensity * NdotL * attenuation;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Passing `WorldPosition` to the Fragment shader from the Vertex shader is required for positional lighting.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Assets/compiled/Skybox.frag.dxil
Normal file
BIN
Assets/compiled/Skybox.frag.dxil
Normal file
Binary file not shown.
BIN
Assets/compiled/Skybox.vert.dxil
Normal file
BIN
Assets/compiled/Skybox.vert.dxil
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,8 +13,8 @@ Output main(uint vertexIndex : SV_VertexID)
|
|||||||
// Retrieve the vertex buffer using SM6.6 bindless syntax
|
// Retrieve the vertex buffer using SM6.6 bindless syntax
|
||||||
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
||||||
|
|
||||||
// TextureIndex is used as vertex offset for consolidated buffer (depth-tested at 0, overlay at halfMax)
|
// VertexOffset is used as vertex offset for consolidated buffer (depth-tested at 0, overlay at halfMax)
|
||||||
uint actualVertexIndex = vertexIndex + TextureIndex;
|
uint actualVertexIndex = vertexIndex + VertexOffset;
|
||||||
|
|
||||||
// Vertex layout: float3 Position (12 bytes) + float4 Color (16 bytes) = 28 bytes stride
|
// Vertex layout: float3 Position (12 bytes) + float4 Color (16 bytes) = 28 bytes stride
|
||||||
uint stride = 28;
|
uint stride = 28;
|
||||||
|
|||||||
@@ -1,15 +1,39 @@
|
|||||||
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransformData
|
||||||
|
{
|
||||||
|
row_major float4x4 Model;
|
||||||
|
};
|
||||||
|
|
||||||
cbuffer RootConstants : register(b0, space0)
|
cbuffer RootConstants : register(b0, space0)
|
||||||
{
|
{
|
||||||
row_major float4x4 ViewProjection;
|
row_major float4x4 ViewProjection;
|
||||||
|
uint MeshIndex;
|
||||||
|
uint TransformsBufferIndex;
|
||||||
uint BufferIndex;
|
uint BufferIndex;
|
||||||
uint TextureIndex;
|
uint TextureIndex;
|
||||||
uint VertexOffset; // Base vertex for indexed drawing with bindless buffers
|
uint VertexOffset; // Base vertex for indexed drawing with bindless buffers
|
||||||
uint _Padding; // Padding for alignment
|
uint _Padding; // Padding for alignment
|
||||||
float2 Scale; // 2D scale factor
|
float2 Scale; // 2D scale factor
|
||||||
float2 Translate; // 2D translation
|
float2 Translate; // 2D translation
|
||||||
|
float2 _Padding2; // Explicit padding to align LightDirection to 16 bytes
|
||||||
|
|
||||||
|
float3 GlobalLightDirection; // Normalized, world-space
|
||||||
|
float GlobalLightPad;
|
||||||
|
float3 GlobalLightColor;
|
||||||
|
float GlobalAmbientIntensity;
|
||||||
|
|
||||||
|
uint LightBufferIndex;
|
||||||
|
uint ActiveLightCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
26
Assets/source/Skybox.frag.hlsl
Normal file
26
Assets/source/Skybox.frag.hlsl
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "RootConstants.hlsl"
|
||||||
|
|
||||||
|
float4 main(float3 ViewDir : TEXCOORD0) : SV_Target0
|
||||||
|
{
|
||||||
|
float3 dir = normalize(ViewDir);
|
||||||
|
|
||||||
|
// Simple Procedural Gradient Skybox Colors
|
||||||
|
float3 skyZenithColor = float3(0.05f, 0.15f, 0.45f); // Deep blue top
|
||||||
|
float3 skyHorizonColor = float3(0.4f, 0.6f, 0.9f); // Light blue horizon
|
||||||
|
float3 groundColor = float3(0.1f, 0.1f, 0.15f); // Dark ground
|
||||||
|
|
||||||
|
float t = dir.z; // -1 to 1 based on vertical alignment
|
||||||
|
|
||||||
|
float3 finalColor = groundColor;
|
||||||
|
|
||||||
|
if (t > 0.0f) {
|
||||||
|
// Blend from horizon to zenith
|
||||||
|
finalColor = lerp(skyHorizonColor, skyZenithColor, t);
|
||||||
|
} else {
|
||||||
|
// Ground - quick blend from horizon to ground
|
||||||
|
finalColor = lerp(skyHorizonColor, groundColor, saturate(-t * 2.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine with overall ambient lighting scale
|
||||||
|
return float4(finalColor, 1.0f);
|
||||||
|
}
|
||||||
74
Assets/source/Skybox.vert.hlsl
Normal file
74
Assets/source/Skybox.vert.hlsl
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "RootConstants.hlsl"
|
||||||
|
|
||||||
|
struct Output
|
||||||
|
{
|
||||||
|
float3 ViewDir : TEXCOORD0;
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
float4x4 Inverse(float4x4 m)
|
||||||
|
{
|
||||||
|
float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0];
|
||||||
|
float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1];
|
||||||
|
float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2];
|
||||||
|
float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3];
|
||||||
|
|
||||||
|
float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
|
||||||
|
float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
|
||||||
|
float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
|
||||||
|
float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
|
||||||
|
|
||||||
|
float det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
|
||||||
|
float idet = 1.0f / det;
|
||||||
|
|
||||||
|
float4x4 ret;
|
||||||
|
ret[0][0] = t11 * idet;
|
||||||
|
ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet;
|
||||||
|
ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet;
|
||||||
|
ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet;
|
||||||
|
|
||||||
|
ret[1][0] = t12 * idet;
|
||||||
|
ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet;
|
||||||
|
ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet;
|
||||||
|
ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet;
|
||||||
|
|
||||||
|
ret[2][0] = t13 * idet;
|
||||||
|
ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet;
|
||||||
|
ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet;
|
||||||
|
ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet;
|
||||||
|
|
||||||
|
ret[3][0] = t14 * idet;
|
||||||
|
ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet;
|
||||||
|
ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet;
|
||||||
|
ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Output main(uint vertexID : SV_VertexID)
|
||||||
|
{
|
||||||
|
Output output;
|
||||||
|
|
||||||
|
// Fullscreen triangle properties
|
||||||
|
// vertexID 0 -> uv(0,0) -> pos(-1, 1)
|
||||||
|
// vertexID 1 -> uv(2,0) -> pos( 3, 1)
|
||||||
|
// vertexID 2 -> uv(0,2) -> pos(-1, -3)
|
||||||
|
float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
|
||||||
|
|
||||||
|
// Map uv to clip space position.
|
||||||
|
// Z is set to 1.0 (far plane in reverse-Z or standard depth)
|
||||||
|
// Assuming standard Z projection ranges from 0 to 1, we use 1.0 for the far plane.
|
||||||
|
// Depending on reverse-z, this might need to be 0.0, but let's stick to standard 1.0
|
||||||
|
// depth for skyboxes.
|
||||||
|
float4 clipPos = float4(uv * 2.0 - 1.0, 1.0, 1.0);
|
||||||
|
clipPos.y = -clipPos.y; // Flip Y for D3D
|
||||||
|
|
||||||
|
output.Position = clipPos;
|
||||||
|
|
||||||
|
// Reconstruct view direction from clip space
|
||||||
|
float4x4 inverseVP = Inverse(ViewProjection);
|
||||||
|
float4 worldPos = mul(inverseVP, clipPos);
|
||||||
|
output.ViewDir = worldPos.xyz / worldPos.w;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
@@ -1,4 +1,46 @@
|
|||||||
float4 main(float4 Color : TEXCOORD0) : SV_Target0
|
#include "RootConstants.hlsl"
|
||||||
|
|
||||||
|
struct Input
|
||||||
{
|
{
|
||||||
return Color;
|
float4 Color : TEXCOORD0;
|
||||||
|
float3 WorldNormal : TEXCOORD1;
|
||||||
|
float3 WorldPosition : TEXCOORD2;
|
||||||
|
};
|
||||||
|
|
||||||
|
float4 main(Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
float3 normal = normalize(input.WorldNormal);
|
||||||
|
|
||||||
|
// Initial ambient component
|
||||||
|
float3 result = input.Color.rgb * GlobalLightColor * GlobalAmbientIntensity;
|
||||||
|
|
||||||
|
// Directional light contribution
|
||||||
|
float ndotl = max(dot(normal, -GlobalLightDirection), 0.0);
|
||||||
|
result += input.Color.rgb * GlobalLightColor * 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
struct Output
|
struct Output
|
||||||
{
|
{
|
||||||
float4 Color : TEXCOORD0;
|
float4 Color : TEXCOORD0;
|
||||||
|
float3 WorldNormal : TEXCOORD1;
|
||||||
|
float3 WorldPosition : TEXCOORD2;
|
||||||
float4 Position : SV_Position;
|
float4 Position : SV_Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12,14 +14,23 @@ Output main(uint vertexIndex : SV_VertexID)
|
|||||||
|
|
||||||
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
||||||
|
|
||||||
uint stride = 28;
|
uint stride = 40;
|
||||||
uint offset = vertexIndex * stride;
|
uint offset = vertexIndex * stride;
|
||||||
|
|
||||||
float3 pos = asfloat(buffer.Load3(offset));
|
float3 pos = asfloat(buffer.Load3(offset));
|
||||||
float4 col = asfloat(buffer.Load4(offset + 12));
|
float3 normal = asfloat(buffer.Load3(offset + 12));
|
||||||
|
float4 col = asfloat(buffer.Load4(offset + 24));
|
||||||
|
|
||||||
//output.Position = float4(pos, 1.0f);
|
// Fetch Model Matrix
|
||||||
output.Position = mul(ViewProjection, float4(pos, 1.0f));
|
StructuredBuffer<TransformData> transformsBuffer = ResourceDescriptorHeap[TransformsBufferIndex];
|
||||||
|
float4x4 Model = transformsBuffer[MeshIndex].Model;
|
||||||
|
|
||||||
|
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);
|
||||||
|
output.WorldNormal = worldNormal;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
2
External/Imgui
vendored
2
External/Imgui
vendored
Submodule External/Imgui updated: eaa32bb787...acdaaef625
@@ -47,8 +47,11 @@
|
|||||||
// --- DLL BUILD ---
|
// --- DLL BUILD ---
|
||||||
DLL( '$ProjectName$-Lib-$Platform$-$BuildConfigName$' )
|
DLL( '$ProjectName$-Lib-$Platform$-$BuildConfigName$' )
|
||||||
{
|
{
|
||||||
.Libraries = { '$ProjectName$-Objs-$Platform$-$BuildConfigName$',
|
.Libraries = { '$ProjectName$-Objs-$Platform$-$BuildConfigName$' }
|
||||||
'ImGui-Lib-$Platform$-$BuildConfigName$' }
|
If ( .BuildConfigName != 'Release' )
|
||||||
|
{
|
||||||
|
^Libraries + { 'ImGui-Lib-$Platform$-$BuildConfigName$' }
|
||||||
|
}
|
||||||
|
|
||||||
.LinkerOutput = '$BinPath$/$Platform$-$BuildConfigName$/$ProjectName$.dll' // Output .dll to Bin
|
.LinkerOutput = '$BinPath$/$Platform$-$BuildConfigName$/$ProjectName$.dll' // Output .dll to Bin
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,10 @@
|
|||||||
<CustomBuild Include="src\UnitTest\RunUnitTests.cpp" />
|
<CustomBuild Include="src\UnitTest\RunUnitTests.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="include\Graphics\MeshRenderer.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\Graphics\MeshRenderer.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{ab9c7e88-6c94-4f93-bc2a-7f5284b7d434}</ProjectGuid>
|
<ProjectGuid>{ab9c7e88-6c94-4f93-bc2a-7f5284b7d434}</ProjectGuid>
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
enum class JulietInit_Flags : uint8;
|
enum class JulietInit_Flags : uint8;
|
||||||
|
|
||||||
|
struct Arena;
|
||||||
extern JULIET_API void StartApplication(IApplication& app, JulietInit_Flags flags);
|
extern JULIET_API void StartApplication(IApplication& app, JulietInit_Flags flags);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
struct RenderPass;
|
struct RenderPass;
|
||||||
@@ -7,12 +9,13 @@ namespace Juliet
|
|||||||
struct Texture;
|
struct Texture;
|
||||||
struct ColorTargetInfo;
|
struct ColorTargetInfo;
|
||||||
struct DepthStencilTargetInfo;
|
struct DepthStencilTargetInfo;
|
||||||
|
struct Arena;
|
||||||
|
|
||||||
class IApplication
|
class IApplication
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IApplication() = default;
|
virtual ~IApplication() = default;
|
||||||
virtual void Init() = 0;
|
virtual void Init(NonNullPtr<Arena> arena) = 0;
|
||||||
virtual void Shutdown() = 0;
|
virtual void Shutdown() = 0;
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
virtual bool IsRunning() = 0;
|
virtual bool IsRunning() = 0;
|
||||||
|
|||||||
@@ -98,6 +98,34 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PushBack(const Type* buffer, size_t amount)
|
||||||
|
{
|
||||||
|
Assert(Arena);
|
||||||
|
|
||||||
|
if (Count + amount > Capacity)
|
||||||
|
{
|
||||||
|
if (Capacity == 0 && Count + amount < ReserveSize)
|
||||||
|
{
|
||||||
|
Reserve(ReserveSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t newCapacity = Max(Capacity * 2, AlignPow2(Capacity + amount, AlignOf(Type)));
|
||||||
|
Reserve(newCapacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* dst = Data + Count;
|
||||||
|
MemCopy(dst, buffer, amount * sizeof(Type));
|
||||||
|
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
DataFirst = dst;
|
||||||
|
}
|
||||||
|
DataLast = dst + amount;
|
||||||
|
Count += amount;
|
||||||
|
}
|
||||||
|
|
||||||
void PushBack(const Type& value)
|
void PushBack(const Type& value)
|
||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
@@ -165,13 +193,20 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
|
|
||||||
|
if (InternalArena)
|
||||||
|
{
|
||||||
ArenaClear(Arena);
|
ArenaClear(Arena);
|
||||||
DataFirst = DataLast = nullptr;
|
|
||||||
Data = nullptr;
|
Data = nullptr;
|
||||||
Count = 0;
|
|
||||||
Capacity = 0;
|
Capacity = 0;
|
||||||
|
Reserve(ReserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const { return Count == 0; }
|
||||||
|
|
||||||
// C++ Accessors for loop supports and Index based access
|
// C++ Accessors for loop supports and Index based access
|
||||||
Type& operator[](size_t index) { return DataFirst[index]; }
|
Type& operator[](size_t index) { return DataFirst[index]; }
|
||||||
const Type& operator[](size_t index) const { return DataFirst[index]; }
|
const Type& operator[](size_t index) const { return DataFirst[index]; }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Common/String.h>
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -16,4 +17,5 @@ namespace Juliet
|
|||||||
extern JULIET_API void HideWindow(NonNullPtr<Window> window);
|
extern JULIET_API void HideWindow(NonNullPtr<Window> window);
|
||||||
|
|
||||||
extern JULIET_API WindowID GetWindowID(NonNullPtr<Window> window);
|
extern JULIET_API WindowID GetWindowID(NonNullPtr<Window> window);
|
||||||
|
extern JULIET_API void SetWindowTitle(NonNullPtr<Window> window, String title);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -5,7 +5,16 @@
|
|||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
// Returns the path to the application directory
|
// Returns the path to the application directory
|
||||||
extern JULIET_API String GetBasePath();
|
[[nodiscard]] extern JULIET_API String GetBasePath();
|
||||||
|
|
||||||
extern JULIET_API bool IsAbsolutePath(String path);
|
// Returns the resolved base path to the compiled shaders directory.
|
||||||
|
// In dev, this resolves to ../../Assets/compiled/ relative to the exe.
|
||||||
|
// In shipping, this resolves to Assets/Shaders/ next to the exe.
|
||||||
|
[[nodiscard]] extern JULIET_API String GetAssetBasePath();
|
||||||
|
|
||||||
|
// Builds a full path to an asset file given its filename (e.g. "Triangle.vert.dxil").
|
||||||
|
// The caller owns the returned buffer and must free it.
|
||||||
|
[[nodiscard]] extern JULIET_API String GetAssetPath(String filename);
|
||||||
|
|
||||||
|
[[nodiscard]]extern JULIET_API bool IsAbsolutePath(String path);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Graphics/D3D12/D3D12Buffer.h>
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -31,6 +32,11 @@ namespace Juliet
|
|||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
||||||
|
namespace Debug
|
||||||
|
{
|
||||||
|
JULIET_API bool IsDebuggerPresent();
|
||||||
|
} // namespace Debug
|
||||||
|
|
||||||
using EntryPointFunc = int (*)(int, wchar_t**);
|
using EntryPointFunc = int (*)(int, wchar_t**);
|
||||||
JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
|
JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
|
||||||
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
|
|
||||||
struct ImGuiContext;
|
struct ImGuiContext;
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -25,3 +27,5 @@ namespace Juliet
|
|||||||
JULIET_API void RunTests();
|
JULIET_API void RunTests();
|
||||||
} // namespace ImGuiService
|
} // namespace ImGuiService
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|
||||||
|
#endif // JULIET_ENABLE_IMGUI
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace Juliet
|
|||||||
extern void JULIET_API LogScopeEnd();
|
extern void JULIET_API LogScopeEnd();
|
||||||
|
|
||||||
extern void JULIET_API Log(LogLevel level, LogCategory category, const char* fmt, ...);
|
extern void JULIET_API Log(LogLevel level, LogCategory category, const char* fmt, ...);
|
||||||
|
extern void JULIET_API LogDebug(LogCategory category, const char* fmt, ...);
|
||||||
extern void JULIET_API LogMessage(LogCategory category, const char* fmt, ...);
|
extern void JULIET_API LogMessage(LogCategory category, const char* fmt, ...);
|
||||||
extern void JULIET_API LogWarning(LogCategory category, const char* fmt, ...);
|
extern void JULIET_API LogWarning(LogCategory category, const char* fmt, ...);
|
||||||
extern void JULIET_API LogError(LogCategory category, const char* fmt, ...);
|
extern void JULIET_API LogError(LogCategory category, const char* fmt, ...);
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
enum class LogLevel : uint8
|
enum class LogLevel : uint8
|
||||||
{
|
{
|
||||||
Message = 0,
|
Debug = 0,
|
||||||
Warning = 1,
|
Message = 1,
|
||||||
Error = 2,
|
Warning = 2,
|
||||||
|
Error = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LogCategory : uint8
|
enum class LogCategory : uint8
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ namespace Juliet
|
|||||||
struct Matrix
|
struct Matrix
|
||||||
{
|
{
|
||||||
float m[4][4];
|
float m[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
static Matrix Identity()
|
[[nodiscard]] inline Matrix MatrixIdentity()
|
||||||
{
|
{
|
||||||
Matrix result = {};
|
Matrix result = {};
|
||||||
result.m[0][0] = 1.0f;
|
result.m[0][0] = 1.0f;
|
||||||
@@ -19,7 +20,7 @@ namespace Juliet
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix operator*(const Matrix& rhs) const
|
[[nodiscard]] inline Matrix operator*(const Matrix& lhs, const Matrix& rhs)
|
||||||
{
|
{
|
||||||
Matrix result = {};
|
Matrix result = {};
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
@@ -28,13 +29,78 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
for (int k = 0; k < 4; ++k)
|
for (int k = 0; k < 4; ++k)
|
||||||
{
|
{
|
||||||
result.m[i][j] += m[i][k] * rhs.m[k][j];
|
result.m[i][j] += lhs.m[i][k] * rhs.m[k][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixTranslation(float x, float y, float z)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][3] = x;
|
||||||
|
result.m[1][3] = y;
|
||||||
|
result.m[2][3] = z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixScale(float x, float y, float z)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][0] = x;
|
||||||
|
result.m[1][1] = y;
|
||||||
|
result.m[2][2] = z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotationX(float radians)
|
||||||
|
{
|
||||||
|
float c = cosf(radians);
|
||||||
|
float s = sinf(radians);
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[1][1] = c;
|
||||||
|
result.m[1][2] = -s;
|
||||||
|
result.m[2][1] = s;
|
||||||
|
result.m[2][2] = c;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotationY(float radians)
|
||||||
|
{
|
||||||
|
float c = cosf(radians);
|
||||||
|
float s = sinf(radians);
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][0] = c;
|
||||||
|
result.m[0][2] = s;
|
||||||
|
result.m[2][0] = -s;
|
||||||
|
result.m[2][2] = c;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotationZ(float radians)
|
||||||
|
{
|
||||||
|
float c = cosf(radians);
|
||||||
|
float s = sinf(radians);
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][0] = c;
|
||||||
|
result.m[0][1] = -s;
|
||||||
|
result.m[1][0] = s;
|
||||||
|
result.m[1][1] = c;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z);
|
||||||
|
}
|
||||||
|
|
||||||
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
|
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
|
||||||
{
|
{
|
||||||
@@ -83,4 +149,46 @@ namespace Juliet
|
|||||||
result.m[3][3] = 0.0f;
|
result.m[3][3] = 0.0f;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixInverse(const Matrix& m)
|
||||||
|
{
|
||||||
|
Matrix out = {};
|
||||||
|
|
||||||
|
float m00 = m.m[0][0], m01 = m.m[0][1], m02 = m.m[0][2], m03 = m.m[0][3];
|
||||||
|
float m10 = m.m[1][0], m11 = m.m[1][1], m12 = m.m[1][2], m13 = m.m[1][3];
|
||||||
|
float m20 = m.m[2][0], m21 = m.m[2][1], m22 = m.m[2][2], m23 = m.m[2][3];
|
||||||
|
float m30 = m.m[3][0], m31 = m.m[3][1], m32 = m.m[3][2], m33 = m.m[3][3];
|
||||||
|
|
||||||
|
out.m[0][0] = m11 * m22 * m33 - m11 * m23 * m32 - m21 * m12 * m33 + m21 * m13 * m32 + m31 * m12 * m23 - m31 * m13 * m22;
|
||||||
|
out.m[1][0] = -m10 * m22 * m33 + m10 * m23 * m32 + m20 * m12 * m33 - m20 * m13 * m32 - m30 * m12 * m23 + m30 * m13 * m22;
|
||||||
|
out.m[2][0] = m10 * m21 * m33 - m10 * m23 * m31 - m20 * m11 * m33 + m20 * m13 * m31 + m30 * m11 * m23 - m30 * m13 * m21;
|
||||||
|
out.m[3][0] = -m10 * m21 * m32 + m10 * m22 * m31 + m20 * m11 * m32 - m20 * m12 * m31 - m30 * m11 * m22 + m30 * m12 * m21;
|
||||||
|
|
||||||
|
out.m[0][1] = -m01 * m22 * m33 + m01 * m23 * m32 + m21 * m02 * m33 - m21 * m03 * m32 - m31 * m02 * m23 + m31 * m03 * m22;
|
||||||
|
out.m[1][1] = m00 * m22 * m33 - m00 * m23 * m32 - m20 * m02 * m33 + m20 * m03 * m32 + m30 * m02 * m23 - m30 * m03 * m22;
|
||||||
|
out.m[2][1] = -m00 * m21 * m33 + m00 * m23 * m31 + m20 * m01 * m33 - m20 * m03 * m31 - m30 * m01 * m23 + m30 * m03 * m21;
|
||||||
|
out.m[3][1] = m00 * m21 * m32 - m00 * m22 * m31 - m20 * m01 * m32 + m20 * m02 * m31 + m30 * m01 * m22 - m30 * m02 * m21;
|
||||||
|
|
||||||
|
out.m[0][2] = m01 * m12 * m33 - m01 * m13 * m32 - m11 * m02 * m33 + m11 * m03 * m32 + m31 * m02 * m13 - m31 * m03 * m12;
|
||||||
|
out.m[1][2] = -m00 * m12 * m33 + m00 * m13 * m32 + m10 * m02 * m33 - m10 * m03 * m32 - m30 * m02 * m13 + m30 * m03 * m12;
|
||||||
|
out.m[2][2] = m00 * m11 * m33 - m00 * m13 * m31 - m10 * m01 * m33 + m10 * m03 * m31 + m30 * m01 * m13 - m30 * m03 * m11;
|
||||||
|
out.m[3][2] = -m00 * m11 * m32 + m00 * m12 * m31 + m10 * m01 * m32 - m10 * m02 * m31 - m30 * m01 * m12 + m30 * m02 * m11;
|
||||||
|
|
||||||
|
out.m[0][3] = -m01 * m12 * m23 + m01 * m13 * m22 + m11 * m02 * m23 - m11 * m03 * m22 - m21 * m02 * m13 + m21 * m03 * m12;
|
||||||
|
out.m[1][3] = m00 * m12 * m23 - m00 * m13 * m22 - m10 * m02 * m23 + m10 * m03 * m22 + m20 * m02 * m13 - m20 * m03 * m12;
|
||||||
|
out.m[2][3] = -m00 * m11 * m23 + m00 * m13 * m21 + m10 * m01 * m23 - m10 * m03 * m21 - m20 * m01 * m13 + m20 * m03 * m11;
|
||||||
|
out.m[3][3] = m00 * m11 * m22 - m00 * m12 * m21 - m10 * m01 * m22 + m10 * m02 * m21 + m20 * m01 * m12 - m20 * m02 * m11;
|
||||||
|
|
||||||
|
float det = m00 * out.m[0][0] + m01 * out.m[1][0] + m02 * out.m[2][0] + m03 * out.m[3][0];
|
||||||
|
|
||||||
|
if (det != 0.0f)
|
||||||
|
{
|
||||||
|
float invDet = 1.0f / det;
|
||||||
|
for (int r = 0; r < 4; ++r)
|
||||||
|
for (int c = 0; c < 4; ++c)
|
||||||
|
out.m[r][c] *= invDet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Juliet
|
|||||||
struct Engine
|
struct Engine
|
||||||
{
|
{
|
||||||
IApplication* Application = nullptr;
|
IApplication* Application = nullptr;
|
||||||
|
Arena* PlatformArena = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitializeEngine(JulietInit_Flags flags);
|
void InitializeEngine(JulietInit_Flags flags);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
15
Juliet/include/Graphics/Lighting.h
Normal file
15
Juliet/include/Graphics/Lighting.h
Normal 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
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Math/Matrix.h>
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -11,18 +12,12 @@ namespace Juliet
|
|||||||
|
|
||||||
struct Mesh
|
struct Mesh
|
||||||
{
|
{
|
||||||
Vertex* Vertices;
|
|
||||||
uint16* Indices;
|
|
||||||
|
|
||||||
size_t VertexCount;
|
size_t VertexCount;
|
||||||
size_t IndexCount;
|
size_t IndexCount;
|
||||||
|
|
||||||
index_t VertexOffset;
|
index_t VertexOffset;
|
||||||
index_t IndexOffset;
|
index_t IndexOffset;
|
||||||
index_t IndexByteOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
JULIET_API Mesh* CreateCubeMesh(NonNullPtr<Arena> arena);
|
Matrix Transform = MatrixIdentity();
|
||||||
JULIET_API Mesh* CreateQuadMesh(NonNullPtr<Arena> arena);
|
};
|
||||||
JULIET_API void DestroyMesh(NonNullPtr<Mesh> mesh);
|
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
75
Juliet/include/Graphics/MeshRenderer.h
Normal file
75
Juliet/include/Graphics/MeshRenderer.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Container/Vector.h>
|
||||||
|
#include <Core/Math/Matrix.h>
|
||||||
|
#include <Graphics/Lighting.h>
|
||||||
|
#include <Graphics/PushConstants.h>
|
||||||
|
#include <Graphics/VertexData.h>
|
||||||
|
#include <Juliet.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
struct GraphicsTransferBuffer;
|
||||||
|
struct RenderPass;
|
||||||
|
struct CommandList;
|
||||||
|
struct GraphicsBuffer;
|
||||||
|
struct Window;
|
||||||
|
struct GraphicsPipeline;
|
||||||
|
struct GraphicsDevice;
|
||||||
|
struct Mesh;
|
||||||
|
|
||||||
|
using MeshID = index_t;
|
||||||
|
using LightID = index_t;
|
||||||
|
|
||||||
|
constexpr size_t kGeometryPage = Megabytes(64);
|
||||||
|
constexpr size_t kIndexPage = Megabytes(32);
|
||||||
|
constexpr size_t kDefaultMeshNumber = 500;
|
||||||
|
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 kDefaultLightCount = 1024;
|
||||||
|
|
||||||
|
struct MeshRenderer
|
||||||
|
{
|
||||||
|
// Note we prevent realloc for now.
|
||||||
|
VectorArena<Mesh, kDefaultMeshNumber, false> Meshes;
|
||||||
|
VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
|
||||||
|
VectorArena<Index, kDefaultIndexCount, false> Indices;
|
||||||
|
VectorArena<PointLight, kDefaultLightCount, false> PointLights;
|
||||||
|
|
||||||
|
GraphicsBuffer* VertexBuffer;
|
||||||
|
GraphicsBuffer* IndexBuffer;
|
||||||
|
GraphicsTransferBuffer* StreamCopyBuffer;
|
||||||
|
GraphicsTransferBuffer* LoadCopyBuffer;
|
||||||
|
|
||||||
|
GraphicsBuffer* LightsBuffer;
|
||||||
|
PointLight* MappedLights;
|
||||||
|
|
||||||
|
GraphicsDevice* Device;
|
||||||
|
GraphicsPipeline* Pipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
JULIET_API void InitializeMeshRenderer(NonNullPtr<Arena> arena);
|
||||||
|
[[nodiscard]] JULIET_API bool InitializeMeshRendererGraphics(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
|
||||||
|
JULIET_API void ShutdownMeshRendererGraphics();
|
||||||
|
JULIET_API void ShutdownMeshRenderer();
|
||||||
|
JULIET_API void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList);
|
||||||
|
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 SetPointLightRadius(LightID id, float radius);
|
||||||
|
JULIET_API void SetPointLightIntensity(LightID id, float intensity);
|
||||||
|
JULIET_API void ClearPointLights();
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
[[nodiscard]] JULIET_API MeshID AddCube();
|
||||||
|
[[nodiscard]] JULIET_API MeshID AddQuad();
|
||||||
|
JULIET_API void SetMeshTransform(MeshID id, const Matrix& transform);
|
||||||
|
|
||||||
|
#if ALLOW_SHADER_HOT_RELOAD
|
||||||
|
JULIET_API void ReloadMeshRendererShaders();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
30
Juliet/include/Graphics/PushConstants.h
Normal file
30
Juliet/include/Graphics/PushConstants.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Math/Matrix.h>
|
||||||
|
#include <Core/Math/Vector.h>
|
||||||
|
#include <Juliet.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
struct PushData
|
||||||
|
{
|
||||||
|
Matrix ViewProjection;
|
||||||
|
uint32 MeshIndex;
|
||||||
|
uint32 TransformsBufferIndex;
|
||||||
|
uint32 BufferIndex;
|
||||||
|
uint32 TextureIndex;
|
||||||
|
uint32 VertexOffset;
|
||||||
|
uint32 Padding;
|
||||||
|
float Scale[2];
|
||||||
|
float Translate[2];
|
||||||
|
float Padding2[2];
|
||||||
|
|
||||||
|
Vector3 GlobalLightDirection;
|
||||||
|
float GlobalLightPad;
|
||||||
|
Vector3 GlobalLightColor;
|
||||||
|
float GlobalAmbientIntensity;
|
||||||
|
|
||||||
|
uint32 LightBufferIndex;
|
||||||
|
uint32 ActiveLightCount;
|
||||||
|
};
|
||||||
|
} // namespace Juliet
|
||||||
29
Juliet/include/Graphics/SkyboxRenderer.h
Normal file
29
Juliet/include/Graphics/SkyboxRenderer.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Math/Matrix.h>
|
||||||
|
#include <Juliet.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
struct RenderPass;
|
||||||
|
struct CommandList;
|
||||||
|
struct Window;
|
||||||
|
struct GraphicsPipeline;
|
||||||
|
struct GraphicsDevice;
|
||||||
|
|
||||||
|
struct SkyboxRenderer
|
||||||
|
{
|
||||||
|
GraphicsDevice* Device;
|
||||||
|
GraphicsPipeline* Pipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr<GraphicsDevice> device,
|
||||||
|
NonNullPtr<Window> window);
|
||||||
|
JULIET_API void ShutdownSkyboxRenderer();
|
||||||
|
JULIET_API void RenderSkybox(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, const Matrix& viewProjection);
|
||||||
|
|
||||||
|
#if ALLOW_SHADER_HOT_RELOAD
|
||||||
|
JULIET_API void ReloadSkyboxShaders();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
@@ -5,6 +5,9 @@ namespace Juliet
|
|||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
float Position[3];
|
float Position[3];
|
||||||
|
float Normal[3];
|
||||||
float Color[4];
|
float Color[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Index = uint16;
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
// Find and destroy
|
// Find and destroy
|
||||||
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
|
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
|
||||||
for (index_t idx = windows.Size() - 1; idx != 0; --idx)
|
for (index_t idx = windows.Size(); idx-- > 0;)
|
||||||
{
|
{
|
||||||
Window& windowRef = windows[idx];
|
Window& windowRef = windows[idx];
|
||||||
if (windowRef.ID == window->ID)
|
if (windowRef.ID == window->ID)
|
||||||
@@ -149,6 +149,11 @@ namespace Juliet
|
|||||||
return window->ID;
|
return window->ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetWindowTitle(NonNullPtr<Window> window, String title)
|
||||||
|
{
|
||||||
|
g_CurrentDisplayDevice->SetWindowTitle(g_CurrentDisplayDevice, window, title);
|
||||||
|
}
|
||||||
|
|
||||||
// Display Device Utils. Not exposed in the API
|
// Display Device Utils. Not exposed in the API
|
||||||
DisplayDevice* GetDisplayDevice()
|
DisplayDevice* GetDisplayDevice()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace Juliet
|
|||||||
void (*DestroyPlatformWindow)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
void (*DestroyPlatformWindow)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
||||||
void (*ShowWindow)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
void (*ShowWindow)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
||||||
void (*HideWindow)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
void (*HideWindow)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
||||||
|
void (*SetWindowTitle)(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window, String title);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
void (*PumpEvents)(NonNullPtr<DisplayDevice> self);
|
void (*PumpEvents)(NonNullPtr<DisplayDevice> self);
|
||||||
|
|||||||
@@ -33,10 +33,11 @@ namespace Juliet::Win32
|
|||||||
device->DestroyPlatformWindow = DestroyPlatformWindow;
|
device->DestroyPlatformWindow = DestroyPlatformWindow;
|
||||||
device->ShowWindow = ShowWindow;
|
device->ShowWindow = ShowWindow;
|
||||||
device->HideWindow = HideWindow;
|
device->HideWindow = HideWindow;
|
||||||
|
device->SetWindowTitle = SetWindowTitle;
|
||||||
|
|
||||||
device->PumpEvents = PumpEvents;
|
device->PumpEvents = PumpEvents;
|
||||||
|
|
||||||
device->Windows.Create(JULIET_DEBUG_ONLY("Display Windows"));
|
device->Windows.Create(arena JULIET_DEBUG_PARAM("Display Windows"));
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,10 @@
|
|||||||
// For GET_X_LPARAM, GET_Y_LPARAM.
|
// For GET_X_LPARAM, GET_Y_LPARAM.
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
#include <imgui.h> // Need For IMGUI_IMPL_API
|
#include <imgui.h> // Need For IMGUI_IMPL_API
|
||||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Juliet::Win32
|
namespace Juliet::Win32
|
||||||
{
|
{
|
||||||
@@ -145,10 +147,12 @@ namespace Juliet::Win32
|
|||||||
|
|
||||||
LRESULT CALLBACK Win32MainWindowCallback(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK Win32MainWindowCallback(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
if (ImGui_ImplWin32_WndProcHandler(handle, message, wParam, lParam))
|
if (ImGui_ImplWin32_WndProcHandler(handle, message, wParam, lParam))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
LRESULT returnCode = -1;
|
LRESULT returnCode = -1;
|
||||||
|
|
||||||
|
|||||||
@@ -92,4 +92,13 @@ namespace Juliet::Win32
|
|||||||
auto& win32State = static_cast<Window32State&>(*window->State);
|
auto& win32State = static_cast<Window32State&>(*window->State);
|
||||||
::ShowWindow(win32State.Handle, SW_HIDE);
|
::ShowWindow(win32State.Handle, SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetWindowTitle(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window, String title)
|
||||||
|
{
|
||||||
|
Assert(window);
|
||||||
|
Assert(window->State);
|
||||||
|
|
||||||
|
auto& win32State = static_cast<Window32State&>(*window->State);
|
||||||
|
SetWindowTextA(win32State.Handle, CStr(title));
|
||||||
|
}
|
||||||
} // namespace Juliet::Win32
|
} // namespace Juliet::Win32
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ namespace Juliet::Win32
|
|||||||
extern void DestroyPlatformWindow(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
extern void DestroyPlatformWindow(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
||||||
extern void ShowWindow(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
extern void ShowWindow(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
||||||
extern void HideWindow(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
extern void HideWindow(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window);
|
||||||
|
extern void SetWindowTitle(NonNullPtr<DisplayDevice> self, NonNullPtr<Window> window, String title);
|
||||||
} // namespace Juliet::Win32
|
} // namespace Juliet::Win32
|
||||||
|
|||||||
@@ -1,14 +1,29 @@
|
|||||||
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Core/Common/CoreUtils.h>
|
||||||
#include <Core/Common/String.h>
|
#include <Core/Common/String.h>
|
||||||
#include <Core/HAL/Filesystem/Filesystem.h>
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
#include <Core/HAL/Filesystem/Filesystem_Platform.h>
|
#include <Core/HAL/Filesystem/Filesystem_Platform.h>
|
||||||
#include <Core/HAL/Filesystem/Filesystem_Private.h>
|
#include <Core/HAL/Filesystem/Filesystem_Private.h>
|
||||||
|
#include <Core/HAL/Win32.h>
|
||||||
|
#include <Core/Logging/LogManager.h>
|
||||||
|
#include <Core/Logging/LogTypes.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
#include <Core/Memory/Allocator.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
String CachedBasePath = {};
|
String CachedBasePath = {};
|
||||||
|
String CachedAssetBasePath = {};
|
||||||
|
|
||||||
|
bool DirectoryExists(const char* path)
|
||||||
|
{
|
||||||
|
Assert(path);
|
||||||
|
DWORD attributes = GetFileAttributesA(path);
|
||||||
|
return (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String GetBasePath()
|
String GetBasePath()
|
||||||
@@ -20,6 +35,27 @@ namespace Juliet
|
|||||||
return CachedBasePath;
|
return CachedBasePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String GetAssetBasePath()
|
||||||
|
{
|
||||||
|
return CachedAssetBasePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] String GetAssetPath(String filename)
|
||||||
|
{
|
||||||
|
Assert(IsValid(CachedAssetBasePath));
|
||||||
|
Assert(IsValid(filename));
|
||||||
|
|
||||||
|
size_t totalSize = CachedAssetBasePath.Size + filename.Size + 1;
|
||||||
|
auto* buffer = static_cast<char*>(Calloc(totalSize, sizeof(char)));
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buffer, totalSize, "%s%s", CStr(CachedAssetBasePath), CStr(filename));
|
||||||
|
return { buffer, totalSize - 1 };
|
||||||
|
}
|
||||||
|
|
||||||
bool IsAbsolutePath(String path)
|
bool IsAbsolutePath(String path)
|
||||||
{
|
{
|
||||||
if (!IsValid(path))
|
if (!IsValid(path))
|
||||||
@@ -29,7 +65,40 @@ namespace Juliet
|
|||||||
return Platform::IsAbsolutePath(path);
|
return Platform::IsAbsolutePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFilesystem() {}
|
void InitFilesystem()
|
||||||
|
{
|
||||||
|
String basePath = GetBasePath();
|
||||||
|
Assert(IsValid(basePath));
|
||||||
|
|
||||||
|
// Probe candidate paths for compiled shader directory
|
||||||
|
// 1. Shipping layout: Assets/Shaders/ next to the exe
|
||||||
|
// 2. Dev layout: ../../Assets/compiled/ (exe is in bin/x64Clang-<Config>/)
|
||||||
|
constexpr const char* kCandidates[] = {
|
||||||
|
"Assets/Shaders/",
|
||||||
|
"../../Assets/compiled/"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const char* candidate : kCandidates)
|
||||||
|
{
|
||||||
|
char probePath[512];
|
||||||
|
snprintf(probePath, sizeof(probePath), "%s%s", CStr(basePath), candidate);
|
||||||
|
|
||||||
|
if (DirectoryExists(probePath))
|
||||||
|
{
|
||||||
|
size_t len = strlen(probePath);
|
||||||
|
auto* buffer = static_cast<char*>(Calloc(len + 1, sizeof(char)));
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
snprintf(buffer, len + 1, "%s", probePath);
|
||||||
|
CachedAssetBasePath = { buffer, len };
|
||||||
|
Log(LogLevel::Message, LogCategory::Core, "Asset base path: %s", buffer);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(LogLevel::Error, LogCategory::Core, "Filesystem: Could not find Assets/compiled/ directory!");
|
||||||
|
}
|
||||||
|
|
||||||
void ShutdownFilesystem()
|
void ShutdownFilesystem()
|
||||||
{
|
{
|
||||||
@@ -38,5 +107,10 @@ namespace Juliet
|
|||||||
CachedBasePath.Size = 0;
|
CachedBasePath.Size = 0;
|
||||||
SafeFree(CachedBasePath.Data);
|
SafeFree(CachedBasePath.Data);
|
||||||
}
|
}
|
||||||
|
if (IsValid(CachedAssetBasePath))
|
||||||
|
{
|
||||||
|
CachedAssetBasePath.Size = 0;
|
||||||
|
SafeFree(CachedAssetBasePath.Data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace Juliet::Platform
|
|||||||
|
|
||||||
bool IsAbsolutePath(String path)
|
bool IsAbsolutePath(String path)
|
||||||
{
|
{
|
||||||
if (path.Data || path.Size == 0)
|
if (!path.Data || path.Size == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
||||||
|
namespace Debug
|
||||||
|
{
|
||||||
|
bool IsDebuggerPresent()
|
||||||
|
{
|
||||||
|
return Internal::IsDebuggerPresent();
|
||||||
|
}
|
||||||
|
} // namespace Debug
|
||||||
|
|
||||||
int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv)
|
int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv)
|
||||||
{
|
{
|
||||||
return Internal::OS_Main(entryPointFunc, argc, argv);
|
return Internal::OS_Main(entryPointFunc, argc, argv);
|
||||||
|
|||||||
@@ -2,16 +2,17 @@
|
|||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
namespace Memory
|
namespace Memory::Internal
|
||||||
{
|
|
||||||
namespace Internal
|
|
||||||
{
|
{
|
||||||
Byte* OS_Reserve(size_t size);
|
Byte* OS_Reserve(size_t size);
|
||||||
bool OS_Commit(Byte* ptr, size_t size);
|
bool OS_Commit(Byte* ptr, size_t size);
|
||||||
void OS_Release(Byte* ptr, size_t size);
|
void OS_Release(Byte* ptr, size_t size);
|
||||||
} // namespace Internal
|
} // namespace Memory::Internal
|
||||||
} // namespace Memory
|
|
||||||
|
|
||||||
|
namespace Debug::Internal
|
||||||
|
{
|
||||||
|
bool IsDebuggerPresent();
|
||||||
|
} // namespace Debug::Internal
|
||||||
namespace Internal
|
namespace Internal
|
||||||
{
|
{
|
||||||
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
|
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <Core/HAL/OS/OS.h>
|
#include <Core/HAL/OS/OS.h>
|
||||||
#include <Core/HAL/OS/OS_Private.h>
|
#include <Core/HAL/OS/OS_Private.h>
|
||||||
#include <Core/HAL/Win32.h>
|
#include <Core/HAL/Win32.h>
|
||||||
|
#include <Core/Logging/LogManager.h>
|
||||||
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
@@ -15,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,8 +27,12 @@ namespace Juliet
|
|||||||
|
|
||||||
Assert(size <= static_cast<size_t>(MaxValueOf<DWORD>()));
|
Assert(size <= static_cast<size_t>(MaxValueOf<DWORD>()));
|
||||||
|
|
||||||
|
if (w32_rio_functions.RIORegisterBuffer != nullptr && w32_rio_functions.RIODeregisterBuffer != nullptr)
|
||||||
|
{
|
||||||
w32_rio_functions.RIODeregisterBuffer(
|
w32_rio_functions.RIODeregisterBuffer(
|
||||||
w32_rio_functions.RIORegisterBuffer(reinterpret_cast<PCHAR>(ptr), static_cast<DWORD>(size)));
|
w32_rio_functions.RIORegisterBuffer(reinterpret_cast<PCHAR>(ptr), static_cast<DWORD>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +45,14 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
} // namespace Memory::Internal
|
} // namespace Memory::Internal
|
||||||
|
|
||||||
|
namespace Debug::Internal
|
||||||
|
{
|
||||||
|
bool IsDebuggerPresent()
|
||||||
|
{
|
||||||
|
return ::IsDebuggerPresent();
|
||||||
|
}
|
||||||
|
} // namespace Debug::Internal
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Used to handle a crash/exception
|
// Used to handle a crash/exception
|
||||||
@@ -54,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.
|
||||||
@@ -74,11 +86,12 @@ namespace Juliet
|
|||||||
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);
|
||||||
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);
|
||||||
closesocket(Sock);
|
closesocket(Sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryPointFunc(argc, argv);
|
int result = entryPointFunc(argc, argv);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
#include <Core/ImGui/ImGuiService.h>
|
#include <Core/ImGui/ImGuiService.h>
|
||||||
#include <Core/ImGui/ImGuiTests.h>
|
#include <Core/ImGui/ImGuiTests.h>
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
|
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
|
|
||||||
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
|
|
||||||
#include <backends/imgui_impl_win32.h>
|
#include <backends/imgui_impl_win32.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
@@ -102,3 +103,5 @@ namespace Juliet::ImGuiService
|
|||||||
Juliet::UnitTest::TestImGui();
|
Juliet::UnitTest::TestImGui();
|
||||||
}
|
}
|
||||||
} // namespace Juliet::ImGuiService
|
} // namespace Juliet::ImGuiService
|
||||||
|
|
||||||
|
#endif // JULIET_ENABLE_IMGUI
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace Juliet::UnitTest
|
|||||||
{
|
{
|
||||||
void TestImGui()
|
void TestImGui()
|
||||||
{
|
{
|
||||||
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
ImGuiContext* ctx = ImGuiService::GetContext();
|
ImGuiContext* ctx = ImGuiService::GetContext();
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext() != ctx)
|
if (ImGui::GetCurrentContext() != ctx)
|
||||||
@@ -68,5 +69,6 @@ namespace Juliet::UnitTest
|
|||||||
(void)drawList;
|
(void)drawList;
|
||||||
|
|
||||||
printf("ImGui tests passed (Exhaustive).\n");
|
printf("ImGui tests passed (Exhaustive).\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace Juliet::UnitTest
|
} // namespace Juliet::UnitTest
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ namespace Juliet
|
|||||||
};
|
};
|
||||||
DECLARE_QUEUE(LogsEntry);
|
DECLARE_QUEUE(LogsEntry);
|
||||||
|
|
||||||
|
// TODO: Debug level per category
|
||||||
|
const bool kPrintDebugLog = false;
|
||||||
|
|
||||||
// A log scope accumulates log until end of scope.
|
// A log scope accumulates log until end of scope.
|
||||||
// Can be used to accumulate then write in a log file each frame.
|
// Can be used to accumulate then write in a log file each frame.
|
||||||
struct LogScope
|
struct LogScope
|
||||||
@@ -133,6 +136,11 @@ namespace Juliet
|
|||||||
|
|
||||||
void Log(LogLevel level, LogCategory category, const char* fmt, va_list args)
|
void Log(LogLevel level, LogCategory category, const char* fmt, va_list args)
|
||||||
{
|
{
|
||||||
|
if (level == LogLevel::Debug && kPrintDebugLog == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO : Revisit, copy from https://github.com/Eclmist/Ether/blob/develop/src/common/logging/loggingmanager.cpp
|
// TODO : Revisit, copy from https://github.com/Eclmist/Ether/blob/develop/src/common/logging/loggingmanager.cpp
|
||||||
char formattedBuffer[4096];
|
char formattedBuffer[4096];
|
||||||
|
|
||||||
@@ -163,6 +171,14 @@ namespace Juliet
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogDebug(LogCategory category, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
Log(LogLevel::Debug, category, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
void LogMessage(LogCategory category, const char* fmt, ...)
|
void LogMessage(LogCategory category, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|||||||
@@ -75,12 +75,12 @@ namespace Juliet
|
|||||||
|
|
||||||
void ArenaRelease(NonNullPtr<Arena> arena)
|
void ArenaRelease(NonNullPtr<Arena> arena)
|
||||||
{
|
{
|
||||||
JULIET_DEBUG_ONLY(DebugUnregisterArena(arena);)
|
// Release active blocks (Current chain)
|
||||||
|
|
||||||
for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous)
|
for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous)
|
||||||
{
|
{
|
||||||
previous = node->Previous;
|
previous = node->Previous;
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(DebugUnregisterArena(node);)
|
||||||
JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);)
|
JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);)
|
||||||
|
|
||||||
Memory::OS_Release(node, node->Reserved);
|
Memory::OS_Release(node, node->Reserved);
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
arena->GlobalNext->GlobalPrev = arena->GlobalPrev;
|
arena->GlobalNext->GlobalPrev = arena->GlobalPrev;
|
||||||
}
|
}
|
||||||
|
arena->GlobalPrev = nullptr;
|
||||||
|
arena->GlobalNext = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name)
|
void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name)
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
#include <Engine/Engine.h>
|
#include <Engine/Engine.h>
|
||||||
#include <Graphics/DebugDisplay.h>
|
#include <Graphics/DebugDisplay.h>
|
||||||
#include <Graphics/Graphics.h>
|
#include <Graphics/Graphics.h>
|
||||||
|
#include <Graphics/MeshRenderer.h>
|
||||||
#include <Graphics/RenderPass.h>
|
#include <Graphics/RenderPass.h>
|
||||||
|
#include <Graphics/SkyboxRenderer.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef JULIET_ENABLE_IMGUI
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
@@ -37,6 +39,16 @@ namespace Juliet
|
|||||||
if (device)
|
if (device)
|
||||||
{
|
{
|
||||||
DebugDisplay_Initialize(device);
|
DebugDisplay_Initialize(device);
|
||||||
|
if (Window* window = EngineInstance.Application->GetPlatformWindow())
|
||||||
|
{
|
||||||
|
bool success = InitializeMeshRendererGraphics(device, window);
|
||||||
|
Assert(success);
|
||||||
|
(void)(success);
|
||||||
|
|
||||||
|
success = InitializeSkyboxRenderer(device, window);
|
||||||
|
Assert(success);
|
||||||
|
(void)(success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JULIET_ENABLE_IMGUI
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
@@ -73,6 +85,8 @@ namespace Juliet
|
|||||||
if (device)
|
if (device)
|
||||||
{
|
{
|
||||||
DebugDisplay_Shutdown(device);
|
DebugDisplay_Shutdown(device);
|
||||||
|
ShutdownSkyboxRenderer();
|
||||||
|
ShutdownMeshRendererGraphics();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +136,9 @@ namespace Juliet
|
|||||||
Camera debugCamera = EngineInstance.Application->GetDebugCamera();
|
Camera debugCamera = EngineInstance.Application->GetDebugCamera();
|
||||||
DebugDisplay_Flush(cmdList, pass, debugCamera);
|
DebugDisplay_Flush(cmdList, pass, debugCamera);
|
||||||
|
|
||||||
|
// Note: The MeshRenderer and SkyboxRenderer draw calls are still inside Application->OnRender
|
||||||
|
// They shouldn't be moved here directly without an interface since they require PushData.
|
||||||
|
|
||||||
#ifdef JULIET_ENABLE_IMGUI
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
// ImGui rendering (always last before EndRenderPass)
|
// ImGui rendering (always last before EndRenderPass)
|
||||||
ImGuiRenderer_Render(cmdList, pass);
|
ImGuiRenderer_Render(cmdList, pass);
|
||||||
@@ -136,6 +153,8 @@ namespace Juliet
|
|||||||
|
|
||||||
void InitializeEngine(JulietInit_Flags flags)
|
void InitializeEngine(JulietInit_Flags flags)
|
||||||
{
|
{
|
||||||
|
EngineInstance.PlatformArena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_PARAM("Platform Arena"));
|
||||||
|
|
||||||
InitializeLogManager();
|
InitializeLogManager();
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
#if JULIET_DEBUG
|
||||||
@@ -153,12 +172,17 @@ namespace Juliet
|
|||||||
|
|
||||||
ShutdownFilesystem();
|
ShutdownFilesystem();
|
||||||
ShutdownLogManager();
|
ShutdownLogManager();
|
||||||
|
|
||||||
|
ArenaRelease(EngineInstance.PlatformArena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadApplication(IApplication& app)
|
void LoadApplication(IApplication& app)
|
||||||
{
|
{
|
||||||
EngineInstance.Application = &app;
|
EngineInstance.Application = &app;
|
||||||
EngineInstance.Application->Init();
|
|
||||||
|
InitializeMeshRenderer(EngineInstance.PlatformArena);
|
||||||
|
|
||||||
|
EngineInstance.Application->Init(EngineInstance.PlatformArena);
|
||||||
|
|
||||||
// Systems depending on Window/GraphicsDevice
|
// Systems depending on Window/GraphicsDevice
|
||||||
InitializeDependentSystems();
|
InitializeDependentSystems();
|
||||||
@@ -170,6 +194,9 @@ namespace Juliet
|
|||||||
ShutdownDependentSystems();
|
ShutdownDependentSystems();
|
||||||
|
|
||||||
EngineInstance.Application->Shutdown();
|
EngineInstance.Application->Shutdown();
|
||||||
|
|
||||||
|
ShutdownMeshRenderer();
|
||||||
|
|
||||||
EngineInstance.Application = nullptr;
|
EngineInstance.Application = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 = {};
|
||||||
|
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||||
|
|
||||||
switch (type)
|
// Constant buffers or Dynamic buffers generally need to be uploaded every frame
|
||||||
{
|
const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer);
|
||||||
case D3D12BufferType::Base:
|
|
||||||
{
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case BufferUsage::None:
|
|
||||||
{
|
|
||||||
Assert(false, "Creating buffer with invalid usage");
|
|
||||||
DestroyBuffer(buffer);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BufferUsage::IndexBuffer:
|
if (type == D3D12BufferType::TransferDownload)
|
||||||
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;
|
|
||||||
}
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case D3D12BufferType::TransferDownload:
|
|
||||||
{
|
{
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE;
|
|
||||||
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case D3D12BufferType::TransferUpload:
|
else if (isUpload)
|
||||||
{
|
{
|
||||||
if (d3d12Driver->GPUUploadHeapSupported)
|
if (d3d12Driver->GPUUploadHeapSupported)
|
||||||
{
|
{
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
||||||
|
initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
heapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
||||||
}
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
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,6 +173,7 @@ namespace Juliet::D3D12
|
|||||||
|
|
||||||
if (usage == BufferUsage::ConstantBuffer)
|
if (usage == BufferUsage::ConstantBuffer)
|
||||||
{
|
{
|
||||||
|
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
||||||
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
||||||
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
||||||
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
||||||
@@ -212,13 +181,25 @@ namespace Juliet::D3D12
|
|||||||
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;
|
||||||
|
|
||||||
|
if (stride > 0)
|
||||||
|
{
|
||||||
|
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.NumElements = static_cast<uint32>(size / 4);
|
||||||
srvDesc.Buffer.StructureByteStride = 0;
|
srvDesc.Buffer.StructureByteStride = 0;
|
||||||
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
|
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());
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -246,7 +246,8 @@ namespace Juliet::D3D12
|
|||||||
d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists);
|
d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists);
|
||||||
|
|
||||||
// Acquire a fence and set it to the in-flight fence
|
// Acquire a fence and set it to the in-flight fence
|
||||||
d3d12CommandList->InFlightFence = Internal::AcquireFence(d3d12Driver);
|
d3d12CommandList->InFlightFence =
|
||||||
|
Internal::AcquireFence(d3d12Driver JULIET_DEBUG_PARAM(ConstString("SubmitCommandLists")));
|
||||||
if (!d3d12CommandList->InFlightFence)
|
if (!d3d12CommandList->InFlightFence)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -305,14 +306,22 @@ namespace Juliet::D3D12
|
|||||||
windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight;
|
windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : Correctly clean up and destroy
|
|
||||||
// Check for cleanups
|
// Check for cleanups
|
||||||
for (int32 i = d3d12Driver->SubmittedCommandListCount - 1; i >= 0; i -= 1)
|
{
|
||||||
|
int32 i = 0;
|
||||||
|
while (i < d3d12Driver->SubmittedCommandListCount)
|
||||||
{
|
{
|
||||||
uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue();
|
uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue();
|
||||||
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
||||||
{
|
{
|
||||||
success &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
|
success &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
|
||||||
|
// CleanCommandList swaps [i] with last and decrements count.
|
||||||
|
// Don't increment — re-check the swapped-in element.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,7 +496,8 @@ namespace Juliet::D3D12
|
|||||||
// Release Fence if needed
|
// Release Fence if needed
|
||||||
if (commandList->AutoReleaseFence)
|
if (commandList->AutoReleaseFence)
|
||||||
{
|
{
|
||||||
ReleaseFence(driver.Get(), reinterpret_cast<Fence*>(commandList->InFlightFence));
|
ReleaseFence(driver.Get(), reinterpret_cast<Fence*>(commandList->InFlightFence)
|
||||||
|
JULIET_DEBUG_PARAM(ConstString("CleanCommandList")));
|
||||||
commandList->InFlightFence = nullptr;
|
commandList->InFlightFence = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,6 +520,7 @@ namespace Juliet::D3D12
|
|||||||
{
|
{
|
||||||
driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1];
|
driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1];
|
||||||
driver->SubmittedCommandListCount -= 1;
|
driver->SubmittedCommandListCount -= 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,6 @@
|
|||||||
#define D3D12_CREATEDEVICE_FUNC "D3D12CreateDevice"
|
#define D3D12_CREATEDEVICE_FUNC "D3D12CreateDevice"
|
||||||
#define D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC "D3D12SerializeVersionedRootSignature"
|
#define D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC "D3D12SerializeVersionedRootSignature"
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
// Used to enable the "Agility SDK" components
|
|
||||||
__declspec(dllexport) extern const unsigned int D3D12SDKVersion = 615;
|
|
||||||
__declspec(dllexport) extern const char* D3D12SDKPath = ".\\D3D12\\";
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason
|
// TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason
|
||||||
// + Will load the dll when needed
|
// + Will load the dll when needed
|
||||||
// This will prevent us from using IID_ variables as they are defined in dxguid.lib
|
// This will prevent us from using IID_ variables as they are defined in dxguid.lib
|
||||||
@@ -604,7 +598,8 @@ namespace Juliet::D3D12
|
|||||||
{
|
{
|
||||||
if (windowData->InFlightFences[idx] != nullptr)
|
if (windowData->InFlightFences[idx] != nullptr)
|
||||||
{
|
{
|
||||||
ReleaseFence(driver, windowData->InFlightFences[idx]);
|
ReleaseFence(driver,
|
||||||
|
windowData->InFlightFences[idx] JULIET_DEBUG_PARAM(ConstString("DeatchFromWindow")));
|
||||||
windowData->InFlightFences[idx] = nullptr;
|
windowData->InFlightFences[idx] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1039,6 +1034,8 @@ namespace Juliet::D3D12
|
|||||||
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;
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ namespace Juliet::D3D12
|
|||||||
{
|
{
|
||||||
// Wait until the fence for the frame is signaled.
|
// Wait until the fence for the frame is signaled.
|
||||||
// In VSYNC this means waiting that the least recent presented frame is done
|
// In VSYNC this means waiting that the least recent presented frame is done
|
||||||
if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], 1))
|
if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter],
|
||||||
|
1 JULIET_DEBUG_PARAM(ConstString("AcquireSwapChainTexture"))))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -155,7 +156,8 @@ namespace Juliet::D3D12
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter]);
|
ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter] JULIET_DEBUG_PARAM(
|
||||||
|
ConstString("AcquireSwapChainTexture")));
|
||||||
windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr;
|
windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +221,8 @@ namespace Juliet::D3D12
|
|||||||
|
|
||||||
if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr)
|
if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr)
|
||||||
{
|
{
|
||||||
if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], 1))
|
if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter],
|
||||||
|
1 JULIET_DEBUG_PARAM(ConstString("WaitForSwapchain"))))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,21 @@ namespace Juliet::D3D12
|
|||||||
driver->AvailableFenceCapacity = driver->AvailableFenceCapacity * 2;
|
driver->AvailableFenceCapacity = driver->AvailableFenceCapacity * 2;
|
||||||
driver->AvailableFences = static_cast<D3D12Fence**>(
|
driver->AvailableFences = static_cast<D3D12Fence**>(
|
||||||
Realloc(driver->AvailableFences, sizeof(D3D12Fence*) * driver->AvailableFenceCapacity));
|
Realloc(driver->AvailableFences, sizeof(D3D12Fence*) * driver->AvailableFenceCapacity));
|
||||||
|
|
||||||
|
LogDebug(LogCategory::Graphics, "ReleaseFenceToPool With Realloc");
|
||||||
}
|
}
|
||||||
driver->AvailableFences[driver->AvailableFenceCount] = fence;
|
driver->AvailableFences[driver->AvailableFenceCount] = fence;
|
||||||
driver->AvailableFenceCount += 1;
|
driver->AvailableFenceCount += 1;
|
||||||
|
|
||||||
|
LogDebug(LogCategory::Graphics, "ReleaseFenceToPool %x fence. Handle %x | Event %x | Refcount %d",
|
||||||
|
fence.Get(), fence->Handle, fence->Event, fence->ReferenceCount);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver)
|
bool WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver)
|
||||||
{
|
{
|
||||||
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
||||||
D3D12Fence* fence = Internal::AcquireFence(d3d12driver);
|
D3D12Fence* fence = Internal::AcquireFence(d3d12driver JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle")));
|
||||||
if (!fence)
|
if (!fence)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -56,14 +61,19 @@ namespace Juliet::D3D12
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseFence(driver, reinterpret_cast<Fence*>(fence));
|
ReleaseFence(driver, reinterpret_cast<Fence*>(fence) JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle")));
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx)
|
{
|
||||||
|
int32 idx = 0;
|
||||||
|
while (idx < d3d12driver->SubmittedCommandListCount)
|
||||||
{
|
{
|
||||||
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
||||||
|
// CleanCommandList swaps [idx] with last and decrements count.
|
||||||
|
// Don't increment — re-check the swapped-in element.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal::DisposePendingResourcces(d3d12driver);
|
Internal::DisposePendingResourcces(d3d12driver);
|
||||||
@@ -71,16 +81,17 @@ namespace Juliet::D3D12
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences, uint32 numFences)
|
bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences, uint32 numFences JULIET_DEBUG_PARAM(String querier))
|
||||||
{
|
{
|
||||||
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
||||||
|
|
||||||
// TODO: use scratch allocator for alloca (stack alloc)
|
// TODO: use scratch allocator for alloca (stack alloc)
|
||||||
auto events = static_cast<HANDLE*>(alloca(sizeof(HANDLE) * numFences));
|
HANDLE* events = static_cast<HANDLE*>(alloca(sizeof(HANDLE) * numFences));
|
||||||
|
MemoryZero(events, sizeof(HANDLE) * numFences);
|
||||||
|
|
||||||
for (uint32 i = 0; i < numFences; ++i)
|
for (uint32 i = 0; i < numFences; ++i)
|
||||||
{
|
{
|
||||||
auto fence = reinterpret_cast<D3D12Fence*>(fences[i]);
|
D3D12Fence* fence = reinterpret_cast<D3D12Fence*>(fences[i]);
|
||||||
|
|
||||||
HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event);
|
HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event);
|
||||||
if (FAILED(res))
|
if (FAILED(res))
|
||||||
@@ -91,6 +102,15 @@ namespace Juliet::D3D12
|
|||||||
|
|
||||||
events[i] = fence->Event;
|
events[i] = fence->Event;
|
||||||
}
|
}
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
LogDebug(LogCategory::Graphics, "Waiting for %d fences. Querier %s", numFences, CStr(querier));
|
||||||
|
#endif
|
||||||
|
for (uint32 i = 0; i < numFences; ++i)
|
||||||
|
{
|
||||||
|
D3D12Fence* d3d12fence = reinterpret_cast<D3D12Fence*>(fences[i]);
|
||||||
|
LogDebug(LogCategory::Graphics, "Waiting for %x fence. Handle %x | Event %x | Refcount %d", d3d12fence,
|
||||||
|
d3d12fence->Handle, d3d12fence->Event, d3d12fence->ReferenceCount);
|
||||||
|
}
|
||||||
|
|
||||||
DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE);
|
DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE);
|
||||||
if (waitResult == WAIT_FAILED)
|
if (waitResult == WAIT_FAILED)
|
||||||
@@ -102,13 +122,20 @@ namespace Juliet::D3D12
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx -= 1)
|
{
|
||||||
|
int32 idx = 0;
|
||||||
|
while (idx < d3d12driver->SubmittedCommandListCount)
|
||||||
{
|
{
|
||||||
uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue();
|
uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue();
|
||||||
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
||||||
{
|
{
|
||||||
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal::DisposePendingResourcces(d3d12driver);
|
Internal::DisposePendingResourcces(d3d12driver);
|
||||||
@@ -122,11 +149,15 @@ namespace Juliet::D3D12
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence)
|
void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence JULIET_DEBUG_PARAM(String querier))
|
||||||
{
|
{
|
||||||
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
||||||
auto d3d12Fence = reinterpret_cast<D3D12Fence*>(fence.Get());
|
auto d3d12Fence = reinterpret_cast<D3D12Fence*>(fence.Get());
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
LogDebug(LogCategory::Graphics, "ReleaseFence | %x fence. Handle %x | Event %x | Refcount %d | Querier %s", d3d12Fence,
|
||||||
|
d3d12Fence->Handle, d3d12Fence->Event, d3d12Fence->ReferenceCount, CStr(querier));
|
||||||
|
#endif
|
||||||
if (--d3d12Fence->ReferenceCount == 0)
|
if (--d3d12Fence->ReferenceCount == 0)
|
||||||
{
|
{
|
||||||
ReleaseFenceToPool(d3d12driver, d3d12Fence);
|
ReleaseFenceToPool(d3d12driver, d3d12Fence);
|
||||||
@@ -170,7 +201,7 @@ namespace Juliet::D3D12
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver)
|
D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver JULIET_DEBUG_PARAM(String querier))
|
||||||
{
|
{
|
||||||
D3D12Fence* fence;
|
D3D12Fence* fence;
|
||||||
ID3D12Fence* handle;
|
ID3D12Fence* handle;
|
||||||
@@ -197,15 +228,28 @@ namespace Juliet::D3D12
|
|||||||
fence->Handle = handle;
|
fence->Handle = handle;
|
||||||
fence->Event = CreateEvent(nullptr, false, false, nullptr);
|
fence->Event = CreateEvent(nullptr, false, false, nullptr);
|
||||||
fence->ReferenceCount = 0;
|
fence->ReferenceCount = 0;
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0 NEW fence", CStr(querier));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fence = driver->AvailableFences[driver->AvailableFenceCount - 1];
|
fence = driver->AvailableFences[driver->AvailableFenceCount - 1];
|
||||||
driver->AvailableFenceCount -= 1;
|
driver->AvailableFenceCount -= 1;
|
||||||
fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE);
|
fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE);
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0, RECYCLING", CStr(querier));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fence->ReferenceCount += 1;
|
fence->ReferenceCount += 1;
|
||||||
|
Assert(fence->ReferenceCount == 1);
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
LogDebug(LogCategory::Graphics, "Acquire Querier %s | %x fence. Handle %x | Event %x | Refcount %d",
|
||||||
|
CStr(querier), fence, fence->Handle, fence->Event, fence->ReferenceCount);
|
||||||
|
#endif
|
||||||
|
|
||||||
return fence;
|
return fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ namespace Juliet::D3D12
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern bool WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver);
|
extern bool WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver);
|
||||||
extern bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences, uint32 numFences);
|
extern bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences,
|
||||||
|
uint32 numFences JULIET_DEBUG_PARAM(String querier));
|
||||||
extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
||||||
extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence JULIET_DEBUG_PARAM(String querier));
|
||||||
|
|
||||||
namespace Internal
|
namespace Internal
|
||||||
{
|
{
|
||||||
@@ -36,7 +37,7 @@ namespace Juliet::D3D12
|
|||||||
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource,
|
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource,
|
||||||
uint32 subresourceIndex, bool needsUavBarrier);
|
uint32 subresourceIndex, bool needsUavBarrier);
|
||||||
|
|
||||||
extern D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver);
|
extern D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver JULIET_DEBUG_PARAM(String querier));
|
||||||
extern void DestroyFence(NonNullPtr<D3D12Fence> fence);
|
extern void DestroyFence(NonNullPtr<D3D12Fence> fence);
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Juliet::D3D12
|
} // namespace Juliet::D3D12
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
|
#include <algorithm>
|
||||||
#include <Core/Common/EnumUtils.h>
|
#include <Core/Common/EnumUtils.h>
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
#include <Core/Memory/Allocator.h>
|
||||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||||
|
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||||
#include <Graphics/D3D12/D3D12Synchronization.h>
|
#include <Graphics/D3D12/D3D12Synchronization.h>
|
||||||
#include <Graphics/D3D12/D3D12Texture.h>
|
#include <Graphics/D3D12/D3D12Texture.h>
|
||||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
|
||||||
#include <Graphics/D3D12/D3D12Utils.h>
|
#include <Graphics/D3D12/D3D12Utils.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace Juliet::D3D12
|
namespace Juliet::D3D12
|
||||||
{
|
{
|
||||||
@@ -375,13 +375,9 @@ namespace Juliet::D3D12
|
|||||||
case TextureType::Texture_2D:
|
case TextureType::Texture_2D:
|
||||||
case TextureType::Texture_2DArray:
|
case TextureType::Texture_2DArray:
|
||||||
case TextureType::Texture_Cube:
|
case TextureType::Texture_Cube:
|
||||||
case TextureType::Texture_CubeArray:
|
case TextureType::Texture_CubeArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break;
|
||||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
||||||
break;
|
|
||||||
case TextureType::Texture_3D:
|
case TextureType::Texture_3D:
|
||||||
case TextureType::Texture_3DArray:
|
case TextureType::Texture_3DArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break;
|
||||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
desc.Alignment = 0;
|
desc.Alignment = 0;
|
||||||
@@ -396,14 +392,24 @@ namespace Juliet::D3D12
|
|||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
|
if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
|
||||||
|
{
|
||||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||||
|
}
|
||||||
if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
|
if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
|
||||||
|
{
|
||||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||||
|
}
|
||||||
if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None)
|
if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None)
|
||||||
|
{
|
||||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||||
|
}
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
heapProps.CreationNodeMask = 0; // We don't do multi-adapter operation
|
||||||
|
heapProps.VisibleNodeMask = 0; // We don't do multi-adapter operation
|
||||||
|
|
||||||
ID3D12Resource* resource = nullptr;
|
ID3D12Resource* resource = nullptr;
|
||||||
D3D12_CLEAR_VALUE clearValue = {};
|
D3D12_CLEAR_VALUE clearValue = {};
|
||||||
@@ -426,8 +432,9 @@ namespace Juliet::D3D12
|
|||||||
pClearValue = &clearValue;
|
pClearValue = &clearValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D12_RESOURCE_STATES initialState = GetDefaultTextureResourceState(createInfo.Flags);
|
||||||
HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc,
|
HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_COMMON, pClearValue, IID_ID3D12Resource,
|
initialState, pClearValue, IID_ID3D12Resource,
|
||||||
reinterpret_cast<void**>(&resource));
|
reinterpret_cast<void**>(&resource));
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
@@ -454,7 +461,8 @@ namespace Juliet::D3D12
|
|||||||
uint32 numLayers = std::max<uint32>(1, createInfo.LayerCount);
|
uint32 numLayers = std::max<uint32>(1, createInfo.LayerCount);
|
||||||
uint32 numMips = std::max<uint32>(1, createInfo.MipLevelCount);
|
uint32 numMips = std::max<uint32>(1, createInfo.MipLevelCount);
|
||||||
texture->SubresourceCount = numLayers * numMips;
|
texture->SubresourceCount = numLayers * numMips;
|
||||||
texture->Subresources = static_cast<D3D12TextureSubresource*>(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource)));
|
texture->Subresources =
|
||||||
|
static_cast<D3D12TextureSubresource*>(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource)));
|
||||||
|
|
||||||
for (uint32 layer = 0; layer < numLayers; ++layer)
|
for (uint32 layer = 0; layer < numLayers; ++layer)
|
||||||
{
|
{
|
||||||
@@ -529,7 +537,6 @@ namespace Juliet::D3D12
|
|||||||
}
|
}
|
||||||
|
|
||||||
return reinterpret_cast<Texture*>(textureContainer);
|
return reinterpret_cast<Texture*>(textureContainer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyTexture(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture)
|
void DestroyTexture(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture)
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
#include <Core/Memory/Allocator.h>
|
||||||
#include <Graphics/GraphicsPipeline.h>
|
#include <Graphics/GraphicsPipeline.h>
|
||||||
|
#include <Graphics/PushConstants.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
@@ -84,11 +86,11 @@ namespace Juliet
|
|||||||
ShaderCreateInfo shaderCI = {};
|
ShaderCreateInfo shaderCI = {};
|
||||||
shaderCI.EntryPoint = entryPoint;
|
shaderCI.EntryPoint = entryPoint;
|
||||||
|
|
||||||
String vertPath = WrapString("../../Assets/compiled/Debug.vert.dxil");
|
String vertPath = GetAssetPath(WrapString("Debug.vert.dxil"));
|
||||||
shaderCI.Stage = ShaderStage::Vertex;
|
shaderCI.Stage = ShaderStage::Vertex;
|
||||||
Shader* vertexShader = CreateShader(device, vertPath, shaderCI);
|
Shader* vertexShader = CreateShader(device, vertPath, shaderCI);
|
||||||
|
|
||||||
String fragPath = WrapString("../../Assets/compiled/Debug.frag.dxil");
|
String fragPath = GetAssetPath(WrapString("Debug.frag.dxil"));
|
||||||
shaderCI.Stage = ShaderStage::Fragment;
|
shaderCI.Stage = ShaderStage::Fragment;
|
||||||
Shader* fragmentShader = CreateShader(device, fragPath, shaderCI);
|
Shader* fragmentShader = CreateShader(device, fragPath, shaderCI);
|
||||||
|
|
||||||
@@ -298,19 +300,24 @@ namespace Juliet
|
|||||||
// Render depth-tested primitives (vertices at offset 0 in buffer)
|
// Render depth-tested primitives (vertices at offset 0 in buffer)
|
||||||
if (g_DebugState.DepthTestedVertexCount > 0 && g_DebugState.DepthTestedPipeline && g_DebugState.VertexBuffer)
|
if (g_DebugState.DepthTestedVertexCount > 0 && g_DebugState.DepthTestedPipeline && g_DebugState.VertexBuffer)
|
||||||
{
|
{
|
||||||
BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline);
|
|
||||||
|
|
||||||
// Pack VP matrix + buffer index into push constants
|
// Pack VP matrix + buffer index into push constants
|
||||||
struct
|
PushData pushData = {};
|
||||||
{
|
pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera);
|
||||||
Matrix vp;
|
pushData.MeshIndex = 0;
|
||||||
uint32 bufferIndex;
|
pushData.TransformsBufferIndex = 0; // Not used by debug shader but layout must match
|
||||||
uint32 vertexOffset; // Offset in vertices (not bytes)
|
pushData.BufferIndex = bufferIndex;
|
||||||
uint32 padding[2];
|
pushData.TextureIndex = 0;
|
||||||
} pushData;
|
pushData.VertexOffset = 0; // Depth-tested vertices start at 0
|
||||||
pushData.vp = Camera_GetViewProjectionMatrix(camera);
|
pushData.Padding = 0;
|
||||||
pushData.bufferIndex = bufferIndex;
|
pushData.Scale[0] = 1.0f; pushData.Scale[1] = 1.0f;
|
||||||
pushData.vertexOffset = 0; // Depth-tested vertices start at 0
|
pushData.Translate[0] = 0.0f; pushData.Translate[1] = 0.0f;
|
||||||
|
|
||||||
|
// Dummy light data as we don't light debug primitives
|
||||||
|
pushData.GlobalLightDirection = {0,0,-1};
|
||||||
|
pushData.GlobalLightPad = 0;
|
||||||
|
pushData.GlobalLightColor = {1,1,1};
|
||||||
|
pushData.GlobalAmbientIntensity = 1.0f;
|
||||||
|
|
||||||
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
|
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
|
||||||
|
|
||||||
DrawPrimitives(renderPass, g_DebugState.DepthTestedVertexCount, 1, 0, 0);
|
DrawPrimitives(renderPass, g_DebugState.DepthTestedVertexCount, 1, 0, 0);
|
||||||
@@ -322,16 +329,23 @@ namespace Juliet
|
|||||||
BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline);
|
BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline);
|
||||||
|
|
||||||
// Pack VP matrix + buffer index into push constants
|
// Pack VP matrix + buffer index into push constants
|
||||||
struct
|
PushData pushData = {};
|
||||||
{
|
pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera);
|
||||||
Matrix vp;
|
pushData.MeshIndex = 0;
|
||||||
uint32 bufferIndex;
|
pushData.TransformsBufferIndex = 0;
|
||||||
uint32 vertexOffset; // Offset in vertices (not bytes)
|
pushData.BufferIndex = bufferIndex;
|
||||||
uint32 padding[2];
|
pushData.TextureIndex = 0;
|
||||||
} pushData;
|
pushData.VertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half
|
||||||
pushData.vp = Camera_GetViewProjectionMatrix(camera);
|
pushData.Padding = 0;
|
||||||
pushData.bufferIndex = bufferIndex;
|
pushData.Scale[0] = 1.0f; pushData.Scale[1] = 1.0f;
|
||||||
pushData.vertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half
|
pushData.Translate[0] = 0.0f; pushData.Translate[1] = 0.0f;
|
||||||
|
|
||||||
|
// Dummy light data as we don't light debug primitives
|
||||||
|
pushData.GlobalLightDirection = {0,0,-1};
|
||||||
|
pushData.GlobalLightPad = 0;
|
||||||
|
pushData.GlobalLightColor = {1,1,1};
|
||||||
|
pushData.GlobalAmbientIntensity = 1.0f;
|
||||||
|
|
||||||
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
|
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
|
||||||
|
|
||||||
DrawPrimitives(renderPass, g_DebugState.OverlayVertexCount, 1, 0, 0);
|
DrawPrimitives(renderPass, g_DebugState.OverlayVertexCount, 1, 0, 0);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace Juliet
|
|||||||
// Fences
|
// Fences
|
||||||
bool (*WaitUntilGPUIsIdle)(NonNullPtr<GPUDriver> driver);
|
bool (*WaitUntilGPUIsIdle)(NonNullPtr<GPUDriver> driver);
|
||||||
bool (*QueryFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
bool (*QueryFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
||||||
void (*ReleaseFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
void (*ReleaseFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence JULIET_DEBUG_PARAM(String querier));
|
||||||
|
|
||||||
// Shaders
|
// Shaders
|
||||||
Shader* (*CreateShader)(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
|
Shader* (*CreateShader)(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <Graphics/GraphicsPipeline.h>
|
#include <Graphics/GraphicsPipeline.h>
|
||||||
|
|
||||||
@@ -127,11 +128,11 @@ namespace Juliet
|
|||||||
ShaderCreateInfo shaderCI = {};
|
ShaderCreateInfo shaderCI = {};
|
||||||
shaderCI.EntryPoint = entryPoint;
|
shaderCI.EntryPoint = entryPoint;
|
||||||
|
|
||||||
String vertPath = WrapString("../../Assets/compiled/ImGui.vert.dxil");
|
String vertPath = GetAssetPath(WrapString("ImGui.vert.dxil"));
|
||||||
shaderCI.Stage = ShaderStage::Vertex;
|
shaderCI.Stage = ShaderStage::Vertex;
|
||||||
g_ImGuiState.VertexShader = CreateShader(device, vertPath, shaderCI);
|
g_ImGuiState.VertexShader = CreateShader(device, vertPath, shaderCI);
|
||||||
|
|
||||||
String fragPath = WrapString("../../Assets/compiled/ImGui.frag.dxil");
|
String fragPath = GetAssetPath(WrapString("ImGui.frag.dxil"));
|
||||||
shaderCI.Stage = ShaderStage::Fragment;
|
shaderCI.Stage = ShaderStage::Fragment;
|
||||||
g_ImGuiState.FragmentShader = CreateShader(device, fragPath, shaderCI);
|
g_ImGuiState.FragmentShader = CreateShader(device, fragPath, shaderCI);
|
||||||
|
|
||||||
@@ -149,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;
|
||||||
@@ -159,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);
|
||||||
|
|
||||||
@@ -176,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)
|
||||||
{
|
{
|
||||||
@@ -314,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++)
|
||||||
{
|
{
|
||||||
@@ -402,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);
|
||||||
|
|
||||||
|
|||||||
@@ -5,95 +5,5 @@
|
|||||||
|
|
||||||
namespace Juliet
|
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
|
} // namespace Juliet
|
||||||
|
|||||||
473
Juliet/src/Graphics/MeshRenderer.cpp
Normal file
473
Juliet/src/Graphics/MeshRenderer.cpp
Normal file
@@ -0,0 +1,473 @@
|
|||||||
|
#include <Graphics/MeshRenderer.h>
|
||||||
|
|
||||||
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
|
#include <Core/Logging/LogManager.h>
|
||||||
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
#include <Core/Math/Matrix.h>
|
||||||
|
#include <Graphics/GraphicsDevice.h>
|
||||||
|
#include <Graphics/Mesh.h>
|
||||||
|
#include <Graphics/VertexData.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct MeshRendererState
|
||||||
|
{
|
||||||
|
GraphicsDevice* Device = nullptr;
|
||||||
|
GraphicsPipeline* Pipeline = nullptr;
|
||||||
|
GraphicsBuffer* VertexBuffer = nullptr;
|
||||||
|
GraphicsBuffer* IndexBuffer = nullptr;
|
||||||
|
GraphicsBuffer* LightsBuffer = nullptr;
|
||||||
|
GraphicsBuffer* TransformsBuffer = nullptr;
|
||||||
|
GraphicsTransferBuffer* LoadCopyBuffer = nullptr;
|
||||||
|
|
||||||
|
VectorArena<Mesh, kDefaultMeshNumber, false> Meshes;
|
||||||
|
VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
|
||||||
|
VectorArena<Index, kDefaultIndexCount, false> Indices;
|
||||||
|
VectorArena<PointLight, kDefaultLightCount, false> PointLights;
|
||||||
|
|
||||||
|
PointLight* MappedLights = nullptr;
|
||||||
|
Matrix* MappedTransforms = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
MeshRendererState g_MeshRenderer;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void InitializeMeshRenderer(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
g_MeshRenderer.Meshes.Create(arena JULIET_DEBUG_PARAM("Meshes"));
|
||||||
|
g_MeshRenderer.Vertices.Create(arena JULIET_DEBUG_PARAM("Vertices"));
|
||||||
|
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 result = true;
|
||||||
|
|
||||||
|
GraphicsDevice* graphicsDevice = g_MeshRenderer.Device = device.Get();
|
||||||
|
|
||||||
|
// Create graphics pipeline
|
||||||
|
String entryPoint = WrapString("main");
|
||||||
|
ShaderCreateInfo shaderCI = {};
|
||||||
|
shaderCI.EntryPoint = entryPoint;
|
||||||
|
|
||||||
|
String shaderPath = GetAssetPath(WrapString("Triangle.vert.dxil"));
|
||||||
|
shaderCI.Stage = ShaderStage::Vertex;
|
||||||
|
Shader* vertexShader = CreateShader(graphicsDevice, shaderPath, shaderCI);
|
||||||
|
|
||||||
|
shaderPath = GetAssetPath(WrapString("SolidColor.frag.dxil"));
|
||||||
|
shaderCI.Stage = ShaderStage::Fragment;
|
||||||
|
Shader* fragmentShader = CreateShader(graphicsDevice, shaderPath, shaderCI);
|
||||||
|
|
||||||
|
ColorTargetDescription colorTargetDescription = {};
|
||||||
|
colorTargetDescription.Format = GetSwapChainTextureFormat(graphicsDevice, window);
|
||||||
|
|
||||||
|
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.RasterizerState.CullMode = CullMode::None;
|
||||||
|
pipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise;
|
||||||
|
pipelineCI.DepthStencilState.EnableDepthTest = true;
|
||||||
|
pipelineCI.DepthStencilState.EnableDepthWrite = true;
|
||||||
|
pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;
|
||||||
|
|
||||||
|
g_MeshRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, pipelineCI);
|
||||||
|
if (g_MeshRenderer.Pipeline == nullptr)
|
||||||
|
{
|
||||||
|
LogError(LogCategory::Graphics, "Failed to create graphics pipeline!");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the vertex and index buffers
|
||||||
|
BufferCreateInfo vertexBufferCI = {};
|
||||||
|
vertexBufferCI.Size = kGeometryPage;
|
||||||
|
vertexBufferCI.Stride = 0;
|
||||||
|
vertexBufferCI.Usage = BufferUsage::StructuredBuffer;
|
||||||
|
g_MeshRenderer.VertexBuffer = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI);
|
||||||
|
Assert(g_MeshRenderer.VertexBuffer != nullptr);
|
||||||
|
|
||||||
|
BufferCreateInfo indexBufferCI = {};
|
||||||
|
indexBufferCI.Size = kIndexPage;
|
||||||
|
indexBufferCI.Usage = BufferUsage::IndexBuffer;
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Transforms Buffer
|
||||||
|
BufferCreateInfo transformsBufferCI = {};
|
||||||
|
transformsBufferCI.Size = 10000 * sizeof(Matrix); // Max 10000 meshes for now
|
||||||
|
transformsBufferCI.Stride = sizeof(Matrix);
|
||||||
|
transformsBufferCI.Usage = BufferUsage::StructuredBuffer;
|
||||||
|
transformsBufferCI.IsDynamic = true;
|
||||||
|
g_MeshRenderer.TransformsBuffer = CreateGraphicsBuffer(graphicsDevice, transformsBufferCI);
|
||||||
|
Assert(g_MeshRenderer.TransformsBuffer != nullptr);
|
||||||
|
g_MeshRenderer.MappedTransforms =
|
||||||
|
static_cast<Matrix*>(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.TransformsBuffer));
|
||||||
|
Assert(g_MeshRenderer.MappedTransforms != 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)
|
||||||
|
{
|
||||||
|
DestroyShader(graphicsDevice, vertexShader);
|
||||||
|
}
|
||||||
|
if (fragmentShader)
|
||||||
|
{
|
||||||
|
DestroyShader(graphicsDevice, fragmentShader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load evereything that is already in the vectors
|
||||||
|
CommandList* loadCmd = AcquireCommandList(device);
|
||||||
|
LoadMeshesOnGPU(loadCmd);
|
||||||
|
SubmitCommandLists(loadCmd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownMeshRendererGraphics()
|
||||||
|
{
|
||||||
|
if (g_MeshRenderer.LoadCopyBuffer)
|
||||||
|
{
|
||||||
|
UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
g_MeshRenderer.LoadCopyBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer);
|
||||||
|
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);
|
||||||
|
g_MeshRenderer.LightsBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_MeshRenderer.TransformsBuffer)
|
||||||
|
{
|
||||||
|
UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer);
|
||||||
|
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer);
|
||||||
|
g_MeshRenderer.TransformsBuffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownMeshRenderer()
|
||||||
|
{
|
||||||
|
g_MeshRenderer.Indices.Destroy();
|
||||||
|
g_MeshRenderer.Vertices.Destroy();
|
||||||
|
g_MeshRenderer.Meshes.Destroy();
|
||||||
|
g_MeshRenderer.PointLights.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList)
|
||||||
|
{
|
||||||
|
if (g_MeshRenderer.Meshes.IsEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading everything in one go.
|
||||||
|
// Destroy the buffer at the end
|
||||||
|
|
||||||
|
TransferBufferCreateInfo uploadBCI = {};
|
||||||
|
uploadBCI.Usage = TransferBufferUsage::Upload;
|
||||||
|
uploadBCI.Size = kGeometryPage + kIndexPage;
|
||||||
|
g_MeshRenderer.LoadCopyBuffer = CreateGraphicsTransferBuffer(g_MeshRenderer.Device, uploadBCI);
|
||||||
|
|
||||||
|
void* map = MapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
|
||||||
|
Vertex* vertices = g_MeshRenderer.Vertices.Data;
|
||||||
|
if (!vertices)
|
||||||
|
{
|
||||||
|
UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
g_MeshRenderer.LoadCopyBuffer = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Index* indices = g_MeshRenderer.Indices.Data;
|
||||||
|
if (!indices)
|
||||||
|
{
|
||||||
|
UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
g_MeshRenderer.LoadCopyBuffer = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all meshes! This supports only one page for now
|
||||||
|
// Copy ALL Vertices in one block
|
||||||
|
size_t totalVertexBytes = g_MeshRenderer.Vertices.Count * sizeof(Vertex);
|
||||||
|
MemCopy(map, g_MeshRenderer.Vertices.Data, totalVertexBytes);
|
||||||
|
|
||||||
|
// Copy ALL Indices in one block
|
||||||
|
size_t indexOfByteOffset = (kGeometryPage + 255) & static_cast<size_t>(~255);
|
||||||
|
uint8* ptrOneByte = static_cast<uint8*>(map);
|
||||||
|
size_t totalIndexBytes = g_MeshRenderer.Indices.Count * sizeof(Index);
|
||||||
|
|
||||||
|
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.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset);
|
||||||
|
|
||||||
|
// Transition vertex buffer to SRV state (this barrier waits for copy to complete)
|
||||||
|
TransitionBufferToReadable(cmdList, g_MeshRenderer.VertexBuffer);
|
||||||
|
TransitionBufferToReadable(cmdList, g_MeshRenderer.IndexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData)
|
||||||
|
{
|
||||||
|
// First destroy any buffer that needs to be
|
||||||
|
if (g_MeshRenderer.LoadCopyBuffer)
|
||||||
|
{
|
||||||
|
WaitUntilGPUIsIdle(g_MeshRenderer.Device);
|
||||||
|
UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
|
||||||
|
g_MeshRenderer.LoadCopyBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline);
|
||||||
|
|
||||||
|
uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
|
||||||
|
uint32 lightDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
|
||||||
|
|
||||||
|
uint32 transformsDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer);
|
||||||
|
|
||||||
|
pushData.BufferIndex = vertexDescriptorIndex;
|
||||||
|
pushData.LightBufferIndex = lightDescriptorIndex;
|
||||||
|
pushData.TransformsBufferIndex = transformsDescriptorIndex;
|
||||||
|
pushData.ActiveLightCount = static_cast<uint32>(g_MeshRenderer.PointLights.Count);
|
||||||
|
|
||||||
|
SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0);
|
||||||
|
|
||||||
|
uint32 meshIndex = 0;
|
||||||
|
for (Mesh& mesh : g_MeshRenderer.Meshes)
|
||||||
|
{
|
||||||
|
if (g_MeshRenderer.MappedTransforms)
|
||||||
|
{
|
||||||
|
g_MeshRenderer.MappedTransforms[meshIndex] = mesh.Transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushData.MeshIndex = meshIndex;
|
||||||
|
pushData.TextureIndex = 0;
|
||||||
|
pushData.VertexOffset = static_cast<uint32>(mesh.VertexOffset);
|
||||||
|
pushData.Padding = 0;
|
||||||
|
pushData.Scale[0] = 1.0f;
|
||||||
|
pushData.Scale[1] = 1.0f;
|
||||||
|
pushData.Translate[0] = 0.0f;
|
||||||
|
pushData.Translate[1] = 0.0f;
|
||||||
|
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
|
||||||
|
DrawIndexedPrimitives(pass, static_cast<uint32>(mesh.IndexCount), 1, static_cast<uint32>(mesh.IndexOffset),
|
||||||
|
static_cast<uint32>(mesh.VertexOffset), 0);
|
||||||
|
meshIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 SetPointLightRadius(LightID id, float radius)
|
||||||
|
{
|
||||||
|
Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
|
||||||
|
g_MeshRenderer.PointLights.Data[id].Radius = radius;
|
||||||
|
if (g_MeshRenderer.MappedLights)
|
||||||
|
{
|
||||||
|
g_MeshRenderer.MappedLights[id].Radius = radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPointLightIntensity(LightID id, float intensity)
|
||||||
|
{
|
||||||
|
Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
|
||||||
|
g_MeshRenderer.PointLights.Data[id].Intensity = intensity;
|
||||||
|
if (g_MeshRenderer.MappedLights)
|
||||||
|
{
|
||||||
|
g_MeshRenderer.MappedLights[id].Intensity = intensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearPointLights()
|
||||||
|
{
|
||||||
|
g_MeshRenderer.PointLights.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshID AddCube()
|
||||||
|
{
|
||||||
|
Mesh result = {};
|
||||||
|
|
||||||
|
constexpr Vertex vertexData[] = { // Front Face (Z = -0.5f) — Red
|
||||||
|
{ { -0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
|
||||||
|
// Back Face (Z = 0.5f) — Green
|
||||||
|
{ { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
|
||||||
|
// Top Face (Y = 0.5f) — Blue
|
||||||
|
{ { -0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
|
||||||
|
// Bottom Face (Y = -0.5f) — Yellow
|
||||||
|
{ { -0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
|
||||||
|
// Right Face (X = 0.5f) — Cyan
|
||||||
|
{ { 0.5f, 0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
|
||||||
|
// Left Face (X = -0.5f) — Magenta
|
||||||
|
{ { -0.5f, 0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, 0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, -0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||||
|
{ { -0.5f, -0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }
|
||||||
|
};
|
||||||
|
constexpr size_t cubeVertexCount = ArraySize(vertexData);
|
||||||
|
result.VertexCount = cubeVertexCount;
|
||||||
|
result.VertexOffset = g_MeshRenderer.Vertices.Count;
|
||||||
|
g_MeshRenderer.Vertices.PushBack(vertexData, 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.IndexOffset = g_MeshRenderer.Indices.Count;
|
||||||
|
g_MeshRenderer.Indices.PushBack(indices, indexCubeCount);
|
||||||
|
|
||||||
|
MeshID id = g_MeshRenderer.Meshes.Count;
|
||||||
|
g_MeshRenderer.Meshes.PushBack(result);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshID AddQuad()
|
||||||
|
{
|
||||||
|
// Mesh result = {};
|
||||||
|
|
||||||
|
// // 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);
|
||||||
|
//
|
||||||
|
// g_MeshRenderer.Meshes.PushBack(std::move(result));
|
||||||
|
return g_MeshRenderer.Meshes.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMeshTransform(MeshID id, const Matrix& transform)
|
||||||
|
{
|
||||||
|
Assert(id < static_cast<MeshID>(g_MeshRenderer.Meshes.Count));
|
||||||
|
g_MeshRenderer.Meshes.Data[id].Transform = transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ALLOW_SHADER_HOT_RELOAD
|
||||||
|
void ReloadMeshRendererShaders()
|
||||||
|
{
|
||||||
|
auto* pipeline = g_MeshRenderer.Pipeline;
|
||||||
|
auto* device = g_MeshRenderer.Device;
|
||||||
|
|
||||||
|
String entryPoint = WrapString("main");
|
||||||
|
ShaderCreateInfo shaderCI = {};
|
||||||
|
shaderCI.EntryPoint = entryPoint;
|
||||||
|
String shaderPath = GetAssetPath(WrapString("Triangle.vert.dxil"));
|
||||||
|
shaderCI.Stage = ShaderStage::Vertex;
|
||||||
|
Shader* vertexShader = CreateShader(device, shaderPath, shaderCI);
|
||||||
|
|
||||||
|
shaderPath = GetAssetPath(WrapString("SolidColor.frag.dxil"));
|
||||||
|
shaderCI.Stage = ShaderStage::Fragment;
|
||||||
|
Shader* fragmentShader = CreateShader(device, shaderPath, shaderCI);
|
||||||
|
|
||||||
|
UpdateGraphicsPipelineShaders(device, pipeline, vertexShader, fragmentShader);
|
||||||
|
|
||||||
|
if (vertexShader)
|
||||||
|
{
|
||||||
|
DestroyShader(device, vertexShader);
|
||||||
|
}
|
||||||
|
if (fragmentShader)
|
||||||
|
{
|
||||||
|
DestroyShader(device, fragmentShader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Juliet
|
||||||
104
Juliet/src/Graphics/SkyboxRenderer.cpp
Normal file
104
Juliet/src/Graphics/SkyboxRenderer.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include <Graphics/SkyboxRenderer.h>
|
||||||
|
|
||||||
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
|
#include <Core/Logging/LogManager.h>
|
||||||
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
#include <Graphics/GraphicsDevice.h>
|
||||||
|
#include <Graphics/PushConstants.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
SkyboxRenderer g_SkyboxRenderer;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool InitializeSkyboxRenderer(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
GraphicsDevice* graphicsDevice = g_SkyboxRenderer.Device = device.Get();
|
||||||
|
|
||||||
|
String skyboxVSEntry = WrapString("main");
|
||||||
|
ShaderCreateInfo skyboxVSCI = {};
|
||||||
|
skyboxVSCI.EntryPoint = skyboxVSEntry;
|
||||||
|
skyboxVSCI.Stage = ShaderStage::Vertex;
|
||||||
|
String vsPath = GetAssetPath(WrapString("Skybox.vert.dxil"));
|
||||||
|
Shader* skyboxVS = CreateShader(graphicsDevice, vsPath, skyboxVSCI);
|
||||||
|
|
||||||
|
String skyboxFSEntry = WrapString("main");
|
||||||
|
ShaderCreateInfo skyboxFSCI = {};
|
||||||
|
skyboxFSCI.EntryPoint = skyboxFSEntry;
|
||||||
|
skyboxFSCI.Stage = ShaderStage::Fragment;
|
||||||
|
String fsPath = GetAssetPath(WrapString("Skybox.frag.dxil"));
|
||||||
|
Shader* skyboxFS = CreateShader(graphicsDevice, fsPath, skyboxFSCI);
|
||||||
|
|
||||||
|
ColorTargetDescription colorTargetDesc = {};
|
||||||
|
colorTargetDesc.Format = GetSwapChainTextureFormat(graphicsDevice, window);
|
||||||
|
|
||||||
|
GraphicsPipelineCreateInfo skyboxPipelineCI = {};
|
||||||
|
skyboxPipelineCI.VertexShader = skyboxVS;
|
||||||
|
skyboxPipelineCI.FragmentShader = skyboxFS;
|
||||||
|
skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList;
|
||||||
|
skyboxPipelineCI.TargetInfo.ColorTargetDescriptions = &colorTargetDesc;
|
||||||
|
skyboxPipelineCI.TargetInfo.NumColorTargets = 1;
|
||||||
|
skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT;
|
||||||
|
skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true;
|
||||||
|
skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid;
|
||||||
|
skyboxPipelineCI.RasterizerState.CullMode = CullMode::None;
|
||||||
|
skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise;
|
||||||
|
skyboxPipelineCI.DepthStencilState.EnableDepthTest = true;
|
||||||
|
skyboxPipelineCI.DepthStencilState.EnableDepthWrite = false;
|
||||||
|
skyboxPipelineCI.DepthStencilState.CompareOperation = CompareOperation::LessOrEqual;
|
||||||
|
|
||||||
|
g_SkyboxRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, skyboxPipelineCI);
|
||||||
|
if (g_SkyboxRenderer.Pipeline == nullptr)
|
||||||
|
{
|
||||||
|
LogError(LogCategory::Graphics, "Failed to create skybox pipeline!");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skyboxVS) DestroyShader(graphicsDevice, skyboxVS);
|
||||||
|
if (skyboxFS) DestroyShader(graphicsDevice, skyboxFS);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownSkyboxRenderer()
|
||||||
|
{
|
||||||
|
if (g_SkyboxRenderer.Pipeline)
|
||||||
|
{
|
||||||
|
DestroyGraphicsPipeline(g_SkyboxRenderer.Device, g_SkyboxRenderer.Pipeline);
|
||||||
|
g_SkyboxRenderer.Pipeline = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_SkyboxRenderer = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSkybox(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, const Matrix& viewProjection)
|
||||||
|
{
|
||||||
|
if (!g_SkyboxRenderer.Pipeline)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PushData pushData = {};
|
||||||
|
pushData.ViewProjection = viewProjection;
|
||||||
|
pushData.MeshIndex = 0;
|
||||||
|
pushData.TransformsBufferIndex = 0;
|
||||||
|
pushData.BufferIndex = 0;
|
||||||
|
|
||||||
|
BindGraphicsPipeline(pass, g_SkyboxRenderer.Pipeline);
|
||||||
|
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
|
||||||
|
SetPushConstants(cmdList, ShaderStage::Fragment, 0, sizeof(pushData) / 4, &pushData);
|
||||||
|
DrawPrimitives(pass, 3, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ALLOW_SHADER_HOT_RELOAD
|
||||||
|
void ReloadSkyboxShaders()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
@@ -59,8 +59,11 @@
|
|||||||
.Libraries = {
|
.Libraries = {
|
||||||
'JulietApp-Lib-$Platform$-$BuildConfigName$',
|
'JulietApp-Lib-$Platform$-$BuildConfigName$',
|
||||||
'Juliet-Lib-$Platform$-$BuildConfigName$',
|
'Juliet-Lib-$Platform$-$BuildConfigName$',
|
||||||
'Game-Lib-$Platform$-$BuildConfigName$',
|
'Game-Lib-$Platform$-$BuildConfigName$'
|
||||||
'ImGui-Lib-$Platform$-$BuildConfigName$'
|
}
|
||||||
|
If ( .BuildConfigName != 'Release' )
|
||||||
|
{
|
||||||
|
^Libraries + { 'ImGui-Lib-$Platform$-$BuildConfigName$' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
#ifdef global
|
||||||
|
#undef global
|
||||||
|
#endif
|
||||||
|
#include <algorithm>
|
||||||
|
#include <ios>
|
||||||
|
#include <iosfwd>
|
||||||
|
#define global static
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#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>
|
||||||
@@ -21,15 +36,42 @@
|
|||||||
#include <Graphics/GraphicsConfig.h>
|
#include <Graphics/GraphicsConfig.h>
|
||||||
#include <Graphics/GraphicsPipeline.h>
|
#include <Graphics/GraphicsPipeline.h>
|
||||||
#include <Graphics/Mesh.h>
|
#include <Graphics/Mesh.h>
|
||||||
|
#include <Graphics/MeshRenderer.h>
|
||||||
#include <Graphics/RenderPass.h>
|
#include <Graphics/RenderPass.h>
|
||||||
|
#include <Graphics/SkyboxRenderer.h>
|
||||||
#include <Graphics/VertexData.h>
|
#include <Graphics/VertexData.h>
|
||||||
#include <Juliet.h>
|
|
||||||
|
|
||||||
#ifdef JULIET_ENABLE_IMGUI
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool ShowMemoryDebugger = false;
|
static bool ShowMemoryDebugger = false;
|
||||||
|
static bool animateCubes = true;
|
||||||
|
static bool animateLights = true;
|
||||||
|
static bool animateCamera = true;
|
||||||
|
|
||||||
|
static bool freeCameraMode = false;
|
||||||
|
static float camYaw = 0.0f;
|
||||||
|
static float camPitch = 0.0f;
|
||||||
|
static Juliet::Vector3 camPos = { 25.0f, 0.0f, 12.5f };
|
||||||
|
|
||||||
|
static float animateCubesTime = 0.0f;
|
||||||
|
static float animateLightsTime = 0.0f;
|
||||||
|
static float animateCameraTime = 0.0f;
|
||||||
|
|
||||||
|
static float redLightRadius = 10.0f;
|
||||||
|
static float redLightIntensity = 5.0f;
|
||||||
|
static float redLightColor[3] = { 1.0f, 0.2f, 0.2f };
|
||||||
|
static bool redLightFollowsCamera = false;
|
||||||
|
|
||||||
|
static bool enableGlobalLight = true;
|
||||||
|
static float globalLightDir[3] = { 0.5f, -1.0f, -0.5f };
|
||||||
|
static float globalLightColor[3] = { 1.0f, 0.95f, 0.8f };
|
||||||
|
static float globalAmbientIntensity = 0.2f;
|
||||||
|
|
||||||
|
static float blueLightRadius = 15.0f;
|
||||||
|
static float blueLightIntensity = 8.0f;
|
||||||
|
static float blueLightColor[3] = { 0.2f, 0.2f, 1.0f };
|
||||||
|
|
||||||
// TODO : Replace with message box from framework + call main and not winmain + subsystem
|
// TODO : Replace with message box from framework + call main and not winmain + subsystem
|
||||||
// TODO : Think how to do the draw pipeline.
|
// TODO : Think how to do the draw pipeline.
|
||||||
@@ -43,13 +85,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*);
|
||||||
@@ -63,18 +98,21 @@ 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()
|
void JulietApplication::Init(NonNullPtr<Arena>)
|
||||||
{
|
{
|
||||||
Log(LogLevel::Message, LogCategory::Tool, "Initializing Juliet Application...");
|
Log(LogLevel::Message, LogCategory::Tool, "Initializing Juliet Application...");
|
||||||
|
|
||||||
Log(LogLevel::Message, LogCategory::Tool, "%s", CStr(GetBasePath()));
|
Log(LogLevel::Message, LogCategory::Tool, "%s", CStr(GetBasePath()));
|
||||||
|
|
||||||
GraphicsConfig config;
|
GraphicsConfig config;
|
||||||
#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);
|
||||||
@@ -85,43 +123,6 @@ void JulietApplication::Init()
|
|||||||
{
|
{
|
||||||
AttachToWindow(GraphicsDevice, MainWindow);
|
AttachToWindow(GraphicsDevice, MainWindow);
|
||||||
{
|
{
|
||||||
// Create graphics pipeline
|
|
||||||
String entryPoint = WrapString("main");
|
|
||||||
ShaderCreateInfo shaderCI = {};
|
|
||||||
shaderCI.EntryPoint = entryPoint;
|
|
||||||
|
|
||||||
// TODO: Assets management that handles path to assets or something.
|
|
||||||
String shaderPath = WrapString("../../Assets/compiled/Triangle.vert.dxil");
|
|
||||||
shaderCI.Stage = ShaderStage::Vertex;
|
|
||||||
Shader* vertexShader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
|
|
||||||
|
|
||||||
shaderPath = WrapString("../../Assets/compiled/SolidColor.frag.dxil");
|
|
||||||
shaderCI.Stage = ShaderStage::Fragment;
|
|
||||||
Shader* fragmentShader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
|
|
||||||
|
|
||||||
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;
|
|
||||||
pipelineCI.DepthStencilState.EnableDepthTest = true;
|
|
||||||
pipelineCI.DepthStencilState.EnableDepthWrite = true;
|
|
||||||
pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;
|
|
||||||
|
|
||||||
GraphicsPipeline = CreateGraphicsPipeline(GraphicsDevice, pipelineCI);
|
|
||||||
if (GraphicsPipeline == nullptr)
|
|
||||||
{
|
|
||||||
LogError(LogCategory::Game, "Failed to create graphics pipeline!");
|
|
||||||
Running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Depth Buffer
|
// Create Depth Buffer
|
||||||
TextureCreateInfo depthCI = {};
|
TextureCreateInfo depthCI = {};
|
||||||
depthCI.Type = TextureType::Texture_2D;
|
depthCI.Type = TextureType::Texture_2D;
|
||||||
@@ -139,55 +140,38 @@ void JulietApplication::Init()
|
|||||||
Running = false;
|
Running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Buffers - Using StructuredBuffer for bindless SRV access in shader
|
constexpr int kGridSize = 10;
|
||||||
BufferCreateInfo bufferCI = {};
|
constexpr float kSpacing = 2.5f;
|
||||||
bufferCI.Size = 1024;
|
constexpr float kOffset = (kGridSize - 1) * kSpacing * 0.5f;
|
||||||
bufferCI.Usage = BufferUsage::StructuredBuffer; // SRV for ResourceDescriptorHeap access
|
|
||||||
StructuredBuffer = CreateGraphicsBuffer(GraphicsDevice, bufferCI);
|
|
||||||
|
|
||||||
TransferBufferCreateInfo transferCI = {};
|
for (int row = 0; row < kGridSize; ++row)
|
||||||
transferCI.Size = 1024;
|
|
||||||
transferCI.Usage = TransferBufferUsage::Upload;
|
|
||||||
TransferBuffer = CreateGraphicsTransferBuffer(GraphicsDevice, transferCI);
|
|
||||||
|
|
||||||
// Upload Static Data for Test
|
|
||||||
if (TransferBuffer && StructuredBuffer)
|
|
||||||
{
|
{
|
||||||
void* data = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
for (int col = 0; col < kGridSize; ++col)
|
||||||
if (data)
|
|
||||||
{
|
{
|
||||||
Matrix projection = PerspectiveFov(60.0f * (3.14159f / 180.0f), 1200.0f / 800.0f, 0.1f, 1000.0f);
|
MeshID cube = AddCube();
|
||||||
Matrix view = LookAt({ 30.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f });
|
float x = static_cast<float>(col) * kSpacing - kOffset;
|
||||||
Matrix model = Matrix::Identity();
|
float y = static_cast<float>(row) * kSpacing - kOffset;
|
||||||
Matrix mvp = projection * view * model;
|
|
||||||
|
|
||||||
MemCopy(data, &mvp, sizeof(Matrix));
|
float seed = static_cast<float>(row * kGridSize + col);
|
||||||
UnmapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
Matrix rotation = MatrixRotation(seed * 0.73f, seed * 1.17f, seed * 0.53f);
|
||||||
|
SetMeshTransform(cube, MatrixTranslation(x, y, 0.0f) * rotation);
|
||||||
CommandList* initCmd = AcquireCommandList(GraphicsDevice);
|
|
||||||
CopyBuffer(initCmd, StructuredBuffer, TransferBuffer, 256);
|
|
||||||
TransitionBufferToReadable(initCmd, StructuredBuffer);
|
|
||||||
SubmitCommandLists(initCmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CubeArena = ArenaAllocate({ .ReserveSize = Kilobytes(1llu), .CommitSize = Kilobytes(1llu) } JULIET_DEBUG_PARAM("CubeArena"));
|
// Start with some default test lights
|
||||||
CubeMesh = CreateCubeMesh(CubeArena);
|
PointLight redLight = {};
|
||||||
// CubeMesh = CreateQuadMesh(CubeArena);
|
redLight.Position = { 5.0f, 5.0f, 2.0f };
|
||||||
|
redLight.Radius = redLightRadius;
|
||||||
|
redLight.Color = { redLightColor[0], redLightColor[1], redLightColor[2] };
|
||||||
|
redLight.Intensity = redLightIntensity;
|
||||||
|
RedLightID = AddPointLight(redLight);
|
||||||
|
|
||||||
if (vertexShader)
|
PointLight blueLight = {};
|
||||||
{
|
blueLight.Position = { -5.0f, 0.0f, 2.0f };
|
||||||
DestroyShader(GraphicsDevice, vertexShader);
|
blueLight.Radius = blueLightRadius;
|
||||||
}
|
blueLight.Color = { blueLightColor[0], blueLightColor[1], blueLightColor[2] };
|
||||||
if (fragmentShader)
|
blueLight.Intensity = blueLightIntensity;
|
||||||
{
|
BlueLightID = AddPointLight(blueLight);
|
||||||
DestroyShader(GraphicsDevice, fragmentShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Running == false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
||||||
@@ -208,8 +192,6 @@ void JulietApplication::Shutdown()
|
|||||||
{
|
{
|
||||||
Log(LogLevel::Message, LogCategory::Tool, "Shutting down Juliet Application...");
|
Log(LogLevel::Message, LogCategory::Tool, "Shutting down Juliet Application...");
|
||||||
|
|
||||||
ArenaRelease(CubeArena);
|
|
||||||
|
|
||||||
if (GameCode.IsValid)
|
if (GameCode.IsValid)
|
||||||
{
|
{
|
||||||
Game.Shutdown();
|
Game.Shutdown();
|
||||||
@@ -220,14 +202,7 @@ void JulietApplication::Shutdown()
|
|||||||
{
|
{
|
||||||
DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline);
|
DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline);
|
||||||
}
|
}
|
||||||
if (StructuredBuffer)
|
|
||||||
{
|
|
||||||
DestroyGraphicsBuffer(GraphicsDevice, StructuredBuffer);
|
|
||||||
}
|
|
||||||
if (TransferBuffer)
|
|
||||||
{
|
|
||||||
DestroyGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
|
||||||
}
|
|
||||||
if (DepthBuffer)
|
if (DepthBuffer)
|
||||||
{
|
{
|
||||||
DestroyTexture(GraphicsDevice, DepthBuffer);
|
DestroyTexture(GraphicsDevice, DepthBuffer);
|
||||||
@@ -253,8 +228,39 @@ void JulietApplication::Shutdown()
|
|||||||
|
|
||||||
void JulietApplication::Update()
|
void JulietApplication::Update()
|
||||||
{
|
{
|
||||||
|
static LARGE_INTEGER frequency = {};
|
||||||
|
static LARGE_INTEGER lastTime = {};
|
||||||
|
if (frequency.QuadPart == 0)
|
||||||
|
{
|
||||||
|
QueryPerformanceFrequency(&frequency);
|
||||||
|
QueryPerformanceCounter(&lastTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER currentTime;
|
||||||
|
QueryPerformanceCounter(¤tTime);
|
||||||
|
float deltaTime = static_cast<float>(currentTime.QuadPart - lastTime.QuadPart) / static_cast<float>(frequency.QuadPart);
|
||||||
|
lastTime = currentTime;
|
||||||
|
|
||||||
|
CameraTime += deltaTime;
|
||||||
|
|
||||||
|
static float fpsTimer = 0.0f;
|
||||||
|
static int fpsFrames = 0;
|
||||||
|
fpsTimer += deltaTime;
|
||||||
|
fpsFrames++;
|
||||||
|
if (fpsTimer >= 0.5f)
|
||||||
|
{
|
||||||
|
float fps = static_cast<float>(fpsFrames) / fpsTimer;
|
||||||
|
float ms = (fpsTimer / static_cast<float>(fpsFrames)) * 1000.0f;
|
||||||
|
char title[64];
|
||||||
|
snprintf(title, sizeof(title), "Juliet | %.1f FPS | %.2f ms", static_cast<double>(fps), static_cast<double>(ms));
|
||||||
|
SetWindowTitle(MainWindow, WrapString(title));
|
||||||
|
fpsTimer = 0.0f;
|
||||||
|
fpsFrames = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool reloadShaders = false;
|
bool reloadShaders = false;
|
||||||
static bool reloadShadersDebounce = false;
|
static bool reloadShadersDebounce = false;
|
||||||
|
static bool f1Debounce = false;
|
||||||
|
|
||||||
SystemEvent evt;
|
SystemEvent evt;
|
||||||
while (GetEvent(evt))
|
while (GetEvent(evt))
|
||||||
@@ -280,14 +286,216 @@ void JulietApplication::Update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool firstFreeFrame = false;
|
||||||
|
|
||||||
|
if (IsKeyDown(ScanCode::F1))
|
||||||
|
{
|
||||||
|
if (!f1Debounce)
|
||||||
|
{
|
||||||
|
freeCameraMode = !freeCameraMode;
|
||||||
|
if (freeCameraMode)
|
||||||
|
{
|
||||||
|
firstFreeFrame = true;
|
||||||
|
}
|
||||||
|
f1Debounce = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f1Debounce = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confine and hide the mouse for Free Camera mode
|
||||||
|
if (freeCameraMode)
|
||||||
|
{
|
||||||
#ifdef JULIET_ENABLE_IMGUI
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
ImGui::ShowDemoWindow();
|
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
HWND hwnd = GetForegroundWindow();
|
||||||
|
if (hwnd)
|
||||||
|
{
|
||||||
|
RECT rect;
|
||||||
|
GetClientRect(hwnd, &rect);
|
||||||
|
POINT ptCenterClient = { (rect.right - rect.left) / 2, (rect.bottom - rect.top) / 2 };
|
||||||
|
|
||||||
|
if (!firstFreeFrame)
|
||||||
|
{
|
||||||
|
POINT currentPos;
|
||||||
|
GetCursorPos(¤tPos);
|
||||||
|
ScreenToClient(hwnd, ¤tPos);
|
||||||
|
|
||||||
|
float deltaX = static_cast<float>(currentPos.x - ptCenterClient.x);
|
||||||
|
float deltaY = static_cast<float>(currentPos.y - ptCenterClient.y);
|
||||||
|
|
||||||
|
float sensitivity = 0.005f;
|
||||||
|
// Plus because the mouse is inverted inherently by windows to screen coordinate
|
||||||
|
camYaw += deltaX * sensitivity;
|
||||||
|
camPitch -= deltaY * sensitivity;
|
||||||
|
|
||||||
|
camPitch = std::min(camPitch, 1.5f);
|
||||||
|
camPitch = std::max(camPitch, -1.5f);
|
||||||
|
}
|
||||||
|
firstFreeFrame = false;
|
||||||
|
|
||||||
|
POINT ptCenterScreen = ptCenterClient;
|
||||||
|
ClientToScreen(hwnd, &ptCenterScreen);
|
||||||
|
SetCursorPos(ptCenterScreen.x, ptCenterScreen.y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freeCameraMode)
|
||||||
|
{
|
||||||
|
float speed = 10.0f * deltaTime;
|
||||||
|
if ((GetKeyModState() & KeyMod::Shift) != KeyMod::None)
|
||||||
|
{
|
||||||
|
speed *= 3.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 forward = { cosf(camYaw) * cosf(camPitch), sinf(camYaw) * cosf(camPitch), sinf(camPitch) };
|
||||||
|
Vector3 right = { cosf(camYaw + 1.5708f), sinf(camYaw + 1.5708f), 0.0f };
|
||||||
|
Vector3 up = { 0.0f, 0.0f, 1.0f };
|
||||||
|
|
||||||
|
if (IsKeyDown(ScanCode::W))
|
||||||
|
{
|
||||||
|
camPos = camPos + forward * speed;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(ScanCode::S))
|
||||||
|
{
|
||||||
|
camPos = camPos - forward * speed;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(ScanCode::D))
|
||||||
|
{
|
||||||
|
camPos = camPos + right * speed;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(ScanCode::A))
|
||||||
|
{
|
||||||
|
camPos = camPos - right * speed;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(ScanCode::E))
|
||||||
|
{
|
||||||
|
camPos = camPos + up * speed;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(ScanCode::Q))
|
||||||
|
{
|
||||||
|
camPos = camPos - up * speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animateCubes)
|
||||||
|
{
|
||||||
|
animateCubesTime += deltaTime;
|
||||||
|
}
|
||||||
|
if (animateLights)
|
||||||
|
{
|
||||||
|
animateLightsTime += deltaTime;
|
||||||
|
}
|
||||||
|
if (animateCamera)
|
||||||
|
{
|
||||||
|
animateCameraTime += deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JULIET_ENABLE_IMGUI
|
||||||
|
ImGui::Begin("Debug Controls");
|
||||||
|
ImGui::Checkbox("Animate Cubes", &animateCubes);
|
||||||
|
ImGui::Checkbox("Animate Lights", &animateLights);
|
||||||
|
ImGui::Checkbox("Animate Camera", &animateCamera);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Global Light");
|
||||||
|
ImGui::Checkbox("Enable Global Light", &enableGlobalLight);
|
||||||
|
if (enableGlobalLight)
|
||||||
|
{
|
||||||
|
ImGui::SliderFloat3("Direction", globalLightDir, -1.0f, 1.0f);
|
||||||
|
ImGui::ColorEdit3("Color", globalLightColor);
|
||||||
|
ImGui::SliderFloat("Ambient Intensity", &globalAmbientIntensity, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Red Point Light");
|
||||||
|
ImGui::ColorEdit3("Red Color", redLightColor);
|
||||||
|
ImGui::SliderFloat("Red Radius", &redLightRadius, 1.0f, 50.0f);
|
||||||
|
ImGui::SliderFloat("Red Intensity", &redLightIntensity, 0.0f, 50.0f);
|
||||||
|
ImGui::Checkbox("Red Light Follows Camera", &redLightFollowsCamera);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Blue Point Light");
|
||||||
|
ImGui::ColorEdit3("Blue Color", blueLightColor);
|
||||||
|
ImGui::SliderFloat("Blue Radius", &blueLightRadius, 1.0f, 50.0f);
|
||||||
|
ImGui::SliderFloat("Blue Intensity", &blueLightIntensity, 0.0f, 50.0f);
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ArenaClear(GameScratchArena);
|
||||||
|
|
||||||
|
Vector3 redLightPos = { 5.0f, 5.0f, 2.0f };
|
||||||
|
Vector3 blueLightPos = { -5.0f, 0.0f, 2.0f };
|
||||||
|
|
||||||
|
if (animateLights || animateLightsTime > 0.0f)
|
||||||
|
{
|
||||||
|
redLightPos = { cosf(animateLightsTime * 2.0f) * 5.0f, sinf(animateLightsTime * 2.0f) * 5.0f, 2.0f };
|
||||||
|
blueLightPos = { -5.0f, cosf(animateLightsTime) * 3.0f, 2.0f };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redLightFollowsCamera)
|
||||||
|
{
|
||||||
|
Camera cam = GetDebugCamera();
|
||||||
|
redLightPos = cam.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPointLightPosition(RedLightID, redLightPos);
|
||||||
|
SetPointLightPosition(BlueLightID, blueLightPos);
|
||||||
|
|
||||||
|
SetPointLightColor(RedLightID, { redLightColor[0], redLightColor[1], redLightColor[2] });
|
||||||
|
SetPointLightRadius(RedLightID, redLightRadius);
|
||||||
|
SetPointLightIntensity(RedLightID, redLightIntensity);
|
||||||
|
|
||||||
|
SetPointLightColor(BlueLightID, { blueLightColor[0], blueLightColor[1], blueLightColor[2] });
|
||||||
|
SetPointLightRadius(BlueLightID, blueLightRadius);
|
||||||
|
SetPointLightIntensity(BlueLightID, blueLightIntensity);
|
||||||
|
|
||||||
|
// Animate the 100 cubes (10x10 grid)
|
||||||
|
constexpr int kGridSize = 10;
|
||||||
|
constexpr float kSpacing = 2.5f;
|
||||||
|
constexpr float kOffset = (kGridSize - 1) * kSpacing * 0.5f;
|
||||||
|
|
||||||
|
for (int row = 0; row < kGridSize; ++row)
|
||||||
|
{
|
||||||
|
for (int col = 0; col < kGridSize; ++col)
|
||||||
|
{
|
||||||
|
MeshID cube = static_cast<MeshID>(row * kGridSize + col); // Assuming they were added first
|
||||||
|
float x = static_cast<float>(col) * kSpacing - kOffset;
|
||||||
|
float y = static_cast<float>(row) * kSpacing - kOffset;
|
||||||
|
|
||||||
|
float seed = static_cast<float>(cube);
|
||||||
|
float timeZ = animateCubesTime * 2.0f + seed * 0.5f;
|
||||||
|
float z = 0.0f;
|
||||||
|
|
||||||
|
float scaleF = 1.0f;
|
||||||
|
Matrix rotation = MatrixIdentity();
|
||||||
|
|
||||||
|
if (animateCubes || animateCubesTime > 0.0f)
|
||||||
|
{
|
||||||
|
z = sinf(timeZ) * 1.5f; // Oscillate up and down
|
||||||
|
scaleF = 1.0f + sinf(animateCubesTime * 1.5f + seed) * 0.3f; // Pulse scale
|
||||||
|
rotation = MatrixRotation(animateCubesTime * 1.2f + seed * 0.73f, animateCubesTime * 0.8f + seed * 1.17f,
|
||||||
|
animateCubesTime * 0.5f + seed * 0.53f);
|
||||||
|
}
|
||||||
|
Matrix scale = MatrixScale(scaleF, scaleF, scaleF);
|
||||||
|
|
||||||
|
SetMeshTransform(cube, MatrixTranslation(x, y, z) * rotation * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@@ -301,27 +509,7 @@ void JulietApplication::Update()
|
|||||||
WaitUntilGPUIsIdle(GraphicsDevice);
|
WaitUntilGPUIsIdle(GraphicsDevice);
|
||||||
|
|
||||||
#if ALLOW_SHADER_HOT_RELOAD
|
#if ALLOW_SHADER_HOT_RELOAD
|
||||||
String entryPoint = WrapString("main");
|
ReloadMeshRendererShaders();
|
||||||
ShaderCreateInfo shaderCI = {};
|
|
||||||
shaderCI.EntryPoint = entryPoint;
|
|
||||||
String shaderPath = WrapString("../../Assets/compiled/Triangle.vert.dxil");
|
|
||||||
shaderCI.Stage = ShaderStage::Vertex;
|
|
||||||
Shader* vertexShader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
|
|
||||||
|
|
||||||
shaderPath = WrapString("../../Assets/compiled/SolidColor.frag.dxil");
|
|
||||||
shaderCI.Stage = ShaderStage::Fragment;
|
|
||||||
Shader* fragmentShader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
|
|
||||||
|
|
||||||
UpdateGraphicsPipelineShaders(GraphicsDevice, GraphicsPipeline, vertexShader, fragmentShader);
|
|
||||||
|
|
||||||
if (vertexShader)
|
|
||||||
{
|
|
||||||
DestroyShader(GraphicsDevice, vertexShader);
|
|
||||||
}
|
|
||||||
if (fragmentShader)
|
|
||||||
{
|
|
||||||
DestroyShader(GraphicsDevice, fragmentShader);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,76 +549,28 @@ void JulietApplication::Update()
|
|||||||
ArenaClear(GameScratchArena);
|
ArenaClear(GameScratchArena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JulietApplication::OnPreRender(CommandList* cmd)
|
void JulietApplication::OnPreRender(CommandList* /*cmd*/) {}
|
||||||
{
|
|
||||||
index_t index = 0;
|
|
||||||
|
|
||||||
// Buffer uploads
|
|
||||||
if (StructuredBuffer && TransferBuffer)
|
|
||||||
{
|
|
||||||
void* ptr = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
Vertex* vertices = static_cast<Vertex*>(ptr);
|
|
||||||
|
|
||||||
// // 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
|
|
||||||
|
|
||||||
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, StructuredBuffer, TransferBuffer, CubeMesh->IndexByteOffset + (CubeMesh->IndexCount * sizeof(uint16)));
|
|
||||||
TransitionBufferToReadable(cmd, StructuredBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
||||||
{
|
{
|
||||||
BindGraphicsPipeline(pass, GraphicsPipeline);
|
PushData pushData = {};
|
||||||
|
|
||||||
uint32 descriptorIndex = GetDescriptorIndex(GraphicsDevice, StructuredBuffer);
|
|
||||||
|
|
||||||
struct PushData
|
|
||||||
{
|
|
||||||
Matrix ViewProjection;
|
|
||||||
uint32 BufferIndex;
|
|
||||||
} pushData = {};
|
|
||||||
pushData.BufferIndex = descriptorIndex;
|
|
||||||
pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera());
|
pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera());
|
||||||
|
|
||||||
SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
|
if (enableGlobalLight)
|
||||||
|
{
|
||||||
|
pushData.GlobalLightDirection = Normalize({ globalLightDir[0], globalLightDir[1], globalLightDir[2] });
|
||||||
|
pushData.GlobalLightColor = { globalLightColor[0], globalLightColor[1], globalLightColor[2] };
|
||||||
|
pushData.GlobalAmbientIntensity = globalAmbientIntensity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pushData.GlobalLightDirection = { 0.0f, -1.0f, 0.0f };
|
||||||
|
pushData.GlobalLightColor = { 0.0f, 0.0f, 0.0f };
|
||||||
|
pushData.GlobalAmbientIntensity = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
SetIndexBuffer(cmd, StructuredBuffer, IndexFormat::UInt16, CubeMesh->IndexCount, CubeMesh->IndexByteOffset);
|
RenderSkybox(pass, cmd, pushData.ViewProjection);
|
||||||
// DrawIndexedPrimitives(pass, static_cast<uint32>(CubeMesh->IndexCount), 1, 0, 0, 0);
|
RenderMeshes(pass, cmd, pushData);
|
||||||
|
|
||||||
DrawIndexedPrimitives(pass, static_cast<uint32>(CubeMesh->IndexCount), 1,
|
|
||||||
static_cast<uint32>(CubeMesh->IndexOffset), static_cast<uint32>(CubeMesh->VertexOffset), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
|
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
|
||||||
@@ -455,21 +595,33 @@ DepthStencilTargetInfo* JulietApplication::GetDepthTargetInfo()
|
|||||||
|
|
||||||
Camera JulietApplication::GetDebugCamera()
|
Camera JulietApplication::GetDebugCamera()
|
||||||
{
|
{
|
||||||
static float time = 0.0f;
|
if (freeCameraMode)
|
||||||
time += 0.016f;
|
{
|
||||||
|
Camera cam = {};
|
||||||
float orbitSpeed = 0.5f;
|
cam.Position = camPos;
|
||||||
float currentOrbitTime = time * orbitSpeed;
|
cam.Target = camPos + Vector3{ cosf(camYaw) * cosf(camPitch), sinf(camYaw) * cosf(camPitch), sinf(camPitch) };
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// --- Adjusted for 1-Meter Scale ---
|
// --- Adjusted for 1-Meter Scale ---
|
||||||
float baseRadius = 2.5f; // Hover 2.5 meters away (down from 15.0f)
|
float baseRadius = 25.0f; // Increased to see 10x10 cube grid
|
||||||
|
|
||||||
float radius = baseRadius;
|
float radius = baseRadius;
|
||||||
/* Uncomment for active zoom
|
|
||||||
float zoomAmplitude = 1.0f; // Oscillate between 1.5m and 3.5m away
|
if (animateCamera || animateCameraTime > 0.0f)
|
||||||
float zoomSpeed = 0.8f;
|
{
|
||||||
radius = baseRadius + (sinf(time * zoomSpeed) * zoomAmplitude);
|
float orbitSpeed = 0.5f;
|
||||||
*/
|
float currentOrbitTime = animateCameraTime * orbitSpeed;
|
||||||
|
|
||||||
|
float zoomAmplitude = 15.0f;
|
||||||
|
float zoomSpeed = 0.5f;
|
||||||
|
radius = baseRadius + (sinf(animateCameraTime * zoomSpeed) * zoomAmplitude);
|
||||||
|
|
||||||
float zHeight = radius * 0.5f; // Keep a nice downward viewing angle
|
float zHeight = radius * 0.5f; // Keep a nice downward viewing angle
|
||||||
|
|
||||||
Camera cam = {};
|
Camera cam = {};
|
||||||
@@ -484,6 +636,20 @@ Camera JulietApplication::GetDebugCamera()
|
|||||||
return cam;
|
return cam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float zHeight = radius * 0.5f; // Keep a nice downward viewing angle
|
||||||
|
|
||||||
|
Camera cam = {};
|
||||||
|
cam.Position = { radius, 0.0f, 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;
|
||||||
|
}
|
||||||
|
|
||||||
bool JulietApplication::IsRunning()
|
bool JulietApplication::IsRunning()
|
||||||
{
|
{
|
||||||
return Running;
|
return Running;
|
||||||
@@ -498,15 +664,15 @@ JulietApplication& GetEditorApplication()
|
|||||||
return EditorApplication;
|
return EditorApplication;
|
||||||
}
|
}
|
||||||
|
|
||||||
int JulietMain(int, wchar_t**)
|
int JulietMain(int argc, wchar_t** argv)
|
||||||
{
|
{
|
||||||
if (__argc > 1)
|
if (argc > 1)
|
||||||
{
|
{
|
||||||
for (int i = 1; i < __argc; ++i)
|
for (int i = 1; i < argc; ++i)
|
||||||
{
|
{
|
||||||
if (strcmp(__argv[i], "-autoclose") == 0 && (i + 1 < __argc))
|
if (wcscmp(argv[i], L"-autoclose") == 0 && (i + 1 < argc))
|
||||||
{
|
{
|
||||||
int frames = atoi(__argv[i + 1]);
|
int frames = _wtoi(argv[i + 1]);
|
||||||
EditorApplication.SetAutoCloseFrameCount(frames);
|
EditorApplication.SetAutoCloseFrameCount(frames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,7 +682,7 @@ int JulietMain(int, wchar_t**)
|
|||||||
|
|
||||||
// Pause here to not close the console window immediatly on stop
|
// Pause here to not close the console window immediatly on stop
|
||||||
// Only pause if not in auto-close mode
|
// Only pause if not in auto-close mode
|
||||||
if (EditorApplication.GetAutoCloseFrameCount() == -1)
|
if (EditorApplication.GetAutoCloseFrameCount() == -1 && !Debug::IsDebuggerPresent())
|
||||||
{
|
{
|
||||||
system("PAUSE");
|
system("PAUSE");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Juliet
|
|||||||
class JulietApplication : public Juliet::IApplication
|
class JulietApplication : public Juliet::IApplication
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void Init() override;
|
void Init(Juliet::NonNullPtr<Juliet::Arena> arena) override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
bool IsRunning() override;
|
bool IsRunning() override;
|
||||||
@@ -42,18 +42,13 @@ class JulietApplication : public Juliet::IApplication
|
|||||||
Juliet::GraphicsDevice* GraphicsDevice = {};
|
Juliet::GraphicsDevice* GraphicsDevice = {};
|
||||||
Juliet::HotReloadCode GameCode = {};
|
Juliet::HotReloadCode GameCode = {};
|
||||||
Juliet::GraphicsPipeline* GraphicsPipeline = {};
|
Juliet::GraphicsPipeline* GraphicsPipeline = {};
|
||||||
Juliet::GraphicsBuffer* StructuredBuffer = {};
|
|
||||||
Juliet::GraphicsTransferBuffer* TransferBuffer = {};
|
|
||||||
Juliet::Texture* DepthBuffer = {};
|
Juliet::Texture* DepthBuffer = {};
|
||||||
|
|
||||||
Juliet::Mesh* CubeMesh = {};
|
|
||||||
Juliet::Arena* CubeArena = nullptr;
|
|
||||||
|
|
||||||
Juliet::Arena* GameArena = nullptr;
|
Juliet::Arena* GameArena = nullptr;
|
||||||
Juliet::Arena* GameScratchArena = nullptr;
|
Juliet::Arena* GameScratchArena = nullptr;
|
||||||
|
|
||||||
int AutoCloseFrameCount = -1;
|
int AutoCloseFrameCount = -1;
|
||||||
bool Running = false;
|
bool Running = false;
|
||||||
|
float CameraTime = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
JulietApplication& GetEditorApplication();
|
JulietApplication& GetEditorApplication();
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
[2026-02-16 16:02:02.4149977] Starting Unit Tests...
|
|
||||||
Running Paged Memory Arena Tests...
|
|
||||||
[2026-02-16 16:02:02.4153152] Allocating from W:\Classified\Juliet\Juliet\src\Core\Memory\MemoryArenaTests.cpp : 23l
|
|
||||||
[2026-02-16 16:02:02.4154229] Allocating from W:\Classified\Juliet\Juliet\src\Core\Memory\MemoryArena.cpp : 181l
|
|
||||||
[2026-02-16 16:02:02.4264282] Allocating from W:\Classified\Juliet\Juliet\src\Core\Memory\MemoryArenaTests.cpp : 122l
|
|
||||||
[2026-02-16 16:02:02.4266593] Allocating from W:\Classified\Juliet\Juliet\src\Core\Memory\MemoryArenaTests.cpp : 141l
|
|
||||||
All Paged MemoryArena tests passed.
|
|
||||||
[2026-02-16 16:02:02.4268147] Allocating from Juliet/include\Core/Container/Vector.h : 22l
|
|
||||||
[2026-02-16 16:02:02.4269590] Allocating from Juliet/include\Core/Container/Vector.h : 22l
|
|
||||||
[2026-02-16 16:02:02.4270984] Allocating from Juliet/include\Core/Container/Vector.h : 22l
|
|
||||||
[2026-02-16 16:02:02.4272310] Allocating from Juliet/include\Core/Container/Vector.h : 22l
|
|
||||||
[2026-02-16 16:02:02.4273792] Allocating from W:\Classified\Juliet\Juliet\src\UnitTest\Container\VectorUnitTest.cpp : 152l
|
|
||||||
[2026-02-16 16:02:02.4275180] Allocating from W:\Classified\Juliet\Juliet\src\UnitTest\Container\VectorUnitTest.cpp : 212l
|
|
||||||
[2026-02-16 16:02:02.4276613] Allocating from W:\Classified\Juliet\Juliet\src\UnitTest\Container\VectorUnitTest.cpp : 231l
|
|
||||||
[2026-02-16 16:02:02.4277980] Allocating from W:\Classified\Juliet\Juliet\src\UnitTest\Container\VectorUnitTest.cpp : 258l
|
|
||||||
[2026-02-16 16:02:02.4279316] Allocating from W:\Classified\Juliet\Juliet\src\UnitTest\Container\VectorUnitTest.cpp : 275l
|
|
||||||
[2026-02-16 16:02:02.4280555] Unit Tests Completed Successfully.
|
|
||||||
[2026-02-16 16:02:02.4281360] Allocating from W:\Classified\Juliet\Juliet\src\Core\HAL\Display\Display.cpp : 26l
|
|
||||||
[2026-02-16 16:02:02.4282502] Allocating from Juliet/include\Core/Container/Vector.h : 22l
|
|
||||||
[2026-02-16 16:02:02.4283584] Initializing Juliet Application...
|
|
||||||
[2026-02-16 16:02:02.4284436] w:\Classified\Juliet\bin\x64Clang-Debug\
|
|
||||||
[2026-02-16 16:02:02.6190578] Allocating from W:\Classified\Juliet\Juliet\src\Graphics\D3D12\D3D12GraphicsDevice.cpp : 709l
|
|
||||||
[2026-02-16 16:02:02.6205209] D3D12 Driver Infos:
|
|
||||||
[2026-02-16 16:02:02.6206266] D3D12 Adapter: AMD Radeon RX 5700 XT
|
|
||||||
[2026-02-16 16:02:02.6206942] D3D12 Driver Version: 32.0.21041.1000
|
|
||||||
[2026-02-16 16:02:02.7715117] DX12: D3D12Device Created: 000001AE0FCD6AC0
|
|
||||||
[2026-02-16 16:02:02.7716961] DX12: Debug Info Logger Initialized
|
|
||||||
[2026-02-16 16:02:02.7759926] Allocating from W:\Classified\Juliet\Juliet\src\Graphics\D3D12\D3D12Common.cpp : 52l
|
|
||||||
[2026-02-16 16:02:02.7762940] Allocating from W:\Classified\Juliet\Juliet\src\Graphics\D3D12\D3D12Common.cpp : 52l
|
|
||||||
[2026-02-16 16:02:02.7764796] Allocating from W:\Classified\Juliet\Juliet\src\Graphics\D3D12\D3D12Common.cpp : 52l
|
|
||||||
[2026-02-16 16:02:02.7767423] Allocating from W:\Classified\Juliet\Juliet\src\Graphics\D3D12\D3D12Common.cpp : 52l
|
|
||||||
[2026-02-16 16:02:02.7769776] Allocating from W:\Classified\Juliet\Juliet\src\Graphics\D3D12\D3D12DescriptorHeap.cpp : 15l
|
|
||||||
[2026-02-16 16:02:02.7862548] Allocating from W:\Classified\Juliet\Juliet\src\Core\HAL\Display\Display.cpp : 83l
|
|
||||||
[2026-02-16 16:02:02.8281025] CreateBuffer: Device=000001AE0FCD6AC0, Size=1024, Type=Base Use=StructuredBuffer
|
|
||||||
[2026-02-16 16:02:02.8287554] -> SRV DescriptorIndex=1
|
|
||||||
[2026-02-16 16:02:02.8288672] CreateBuffer: Device=000001AE0FCD6AC0, Size=1024, Type=TransferUpload Use=None
|
|
||||||
[2026-02-16 16:02:02.8304524] Allocating from W:\Classified\Juliet\JulietApp\main.cpp : 174l
|
|
||||||
[2026-02-16 16:02:02.8306076] Allocating from W:\Classified\Juliet\Juliet\src\Core\HotReload\HotReload.cpp : 14l
|
|
||||||
[2026-02-16 16:02:02.8561774] Allocating from W:\Classified\Juliet\JulietApp\main.cpp : 200l
|
|
||||||
[2026-02-16 16:02:02.8563269] Allocating from W:\Classified\Juliet\JulietApp\main.cpp : 201l
|
|
||||||
Game Arena Allocated: 000001AE56E00080
|
|
||||||
Door is Opened
|
|
||||||
Rock has 100 health points
|
|
||||||
[2026-02-16 16:02:02.8565687] CreateBuffer: Device=000001AE0FCD6AC0, Size=458752, Type=Base Use=StructuredBuffer
|
|
||||||
[2026-02-16 16:02:02.8575789] -> SRV DescriptorIndex=2
|
|
||||||
[2026-02-16 16:02:02.8576717] CreateBuffer: Device=000001AE0FCD6AC0, Size=458752, Type=TransferUpload Use=None
|
|
||||||
[2026-02-16 16:02:02.8583558] Allocating from W:\Classified\Juliet\Juliet\src\Core\ImGui\ImGuiService.cpp : 44l
|
|
||||||
ImGuiRenderer_Initialize: device=000001AE2B1AC730, g_ImGuiState=00007FFE66A66140, Initialized=0
|
|
||||||
[2026-02-16 16:02:02.8634723] CreateBuffer: Device=000001AE0FCD6AC0, Size=262144, Type=TransferUpload Use=None
|
|
||||||
ImGuiService: Running Unit Tests...
|
|
||||||
TestImGui: Context Verified.
|
|
||||||
TestImGui: IO Verified. Backend: imgui_impl_win32
|
|
||||||
TestImGui: Version Verified: 1.92.6 WIP
|
|
||||||
TestImGui: Fonts Verified.
|
|
||||||
TestImGui: Fonts Built Status: 1
|
|
||||||
TestImGui: Font Atlas Verified.
|
|
||||||
TestImGui: Style Verified.
|
|
||||||
TestImGui: About to DrawList check.
|
|
||||||
ImGui tests passed (Exhaustive).
|
|
||||||
[2026-02-16 16:02:02.8744932] CreateBuffer: Device=000001AE0FCD6AC0, Size=101400, Type=Base Use=StructuredBuffer
|
|
||||||
[2026-02-16 16:02:02.8754236] -> SRV DescriptorIndex=4
|
|
||||||
[2026-02-16 16:02:02.8755349] CreateBuffer: Device=000001AE0FCD6AC0, Size=101400, Type=TransferUpload Use=None
|
|
||||||
[2026-02-16 16:02:02.8762446] CreateBuffer: Device=000001AE0FCD6AC0, Size=20258, Type=Base Use=IndexBuffer
|
|
||||||
[2026-02-16 16:02:02.8768422] CreateBuffer: Device=000001AE0FCD6AC0, Size=20258, Type=TransferUpload Use=None
|
|
||||||
[2026-02-16 16:02:02.8797340] CreateBuffer: Device=000001AE0FCD6AC0, Size=101400, Type=Base Use=StructuredBuffer
|
|
||||||
[2026-02-16 16:02:02.8805045] -> SRV DescriptorIndex=5
|
|
||||||
[2026-02-16 16:02:02.8806249] CreateBuffer: Device=000001AE0FCD6AC0, Size=101400, Type=TransferUpload Use=None
|
|
||||||
[2026-02-16 16:02:02.8812642] CreateBuffer: Device=000001AE0FCD6AC0, Size=20258, Type=Base Use=IndexBuffer
|
|
||||||
[2026-02-16 16:02:02.8819564] CreateBuffer: Device=000001AE0FCD6AC0, Size=20258, Type=TransferUpload Use=None
|
|
||||||
[2026-02-16 16:02:03.7970638] Auto-closing application as requested.
|
|
||||||
[2026-02-16 16:02:03.8504471] Shutting down Juliet Application...
|
|
||||||
Shutting down game...
|
|
||||||
[2026-02-16 16:02:03.8768023] Juliet App shutdown Completed
|
|
||||||
62
misc/ship.bat
Normal file
62
misc/ship.bat
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
REM ============================================================
|
||||||
|
REM ship.bat - Build clang-Release and prepare Ship/ folder
|
||||||
|
REM ============================================================
|
||||||
|
|
||||||
|
set ROOT=%~dp0..
|
||||||
|
set BUILD_DIR=%ROOT%\bin\x64Clang-Release
|
||||||
|
set SHIP_DIR=%ROOT%\Ship
|
||||||
|
|
||||||
|
REM Step 0: Build Shader Compiler
|
||||||
|
echo [Ship] Building Shader Compiler...
|
||||||
|
call "%~dp0fbuild" JulietShaderCompiler-x64Clang-Release -cache
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [Ship] SHADER COMPILER BUILD FAILED
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Step 1: Compile shaders
|
||||||
|
echo [Ship] Compiling shaders...
|
||||||
|
call "%~dp0recompile_shaders.bat"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [Ship] SHADER COMPILATION FAILED
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Step 2: Build clang-Release
|
||||||
|
echo [Ship] Building clang-Release...
|
||||||
|
call "%~dp0fbuild" clang-Release -cache
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [Ship] BUILD FAILED
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Step 3: Prepare Ship folder
|
||||||
|
echo [Ship] Preparing Ship folder: %SHIP_DIR%
|
||||||
|
|
||||||
|
if exist "%SHIP_DIR%" rd /s /q "%SHIP_DIR%"
|
||||||
|
mkdir "%SHIP_DIR%"
|
||||||
|
|
||||||
|
REM Copy only the required binaries
|
||||||
|
echo [Ship] Copying binaries...
|
||||||
|
copy "%BUILD_DIR%\JulietApp.exe" "%SHIP_DIR%\" >nul
|
||||||
|
copy "%BUILD_DIR%\Juliet.dll" "%SHIP_DIR%\" >nul
|
||||||
|
copy "%BUILD_DIR%\Game.dll" "%SHIP_DIR%\" >nul
|
||||||
|
|
||||||
|
REM Copy compiled shaders into Assets\Shaders\
|
||||||
|
echo [Ship] Copying shaders...
|
||||||
|
mkdir "%SHIP_DIR%\Assets\Shaders"
|
||||||
|
copy "%ROOT%\Assets\compiled\*.dxil" "%SHIP_DIR%\Assets\Shaders\" >nul
|
||||||
|
del "%SHIP_DIR%\Assets\Shaders\ImGui*.dxil" >nul 2>&1
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo [Ship] Done!
|
||||||
|
echo [Ship] Ship folder: %SHIP_DIR%
|
||||||
|
echo.
|
||||||
|
echo [Ship] Contents:
|
||||||
|
dir /b "%SHIP_DIR%"
|
||||||
|
echo.
|
||||||
|
echo [Ship] Shaders:
|
||||||
|
dir /b "%SHIP_DIR%\Assets\Shaders"
|
||||||
Reference in New Issue
Block a user