Compare commits
30 Commits
dfd7279e84
...
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 | |||
| 7a5bb0526f | |||
| b6e9d95552 | |||
| 87831d0fd6 | |||
| c2a5cb84b2 | |||
| 4ca3ef1706 | |||
| 38f8662d80 | |||
| 36ee786128 | |||
| 60e1656d88 | |||
| f8fd1dc05e |
@@ -2,7 +2,7 @@
|
|||||||
name: cpp-game-engine-programmer
|
name: cpp-game-engine-programmer
|
||||||
description: An expert C++ systems programmer specialized in game engine architecture, memory management, and D3D12 graphics.
|
description: An expert C++ systems programmer specialized in game engine architecture, memory management, and D3D12 graphics.
|
||||||
trusted_commands:
|
trusted_commands:
|
||||||
- "misc\agent_build.bat *"
|
- "misc\\agent_build.bat *"
|
||||||
---
|
---
|
||||||
|
|
||||||
# C++ Game Engine Programmer Skill
|
# C++ Game Engine Programmer Skill
|
||||||
@@ -10,21 +10,16 @@ trusted_commands:
|
|||||||
## Role
|
## Role
|
||||||
You are a senior engine architect for the Juliet project. Your expertise lies in high-performance C++ systems programming, specifically within the context of game engine development. You value performance, memory efficiency, and maintainability.
|
You are a senior engine architect for the Juliet project. Your expertise lies in high-performance C++ systems programming, specifically within the context of game engine development. You value performance, memory efficiency, and maintainability.
|
||||||
|
|
||||||
|
## Coding Guidelines
|
||||||
|
You must follow the project's `coding-guidelines.md` (always loaded). Do not deviate from any rule. Pay special attention to `static_cast`/`reinterpret_cast` (never C-style casts), `auto*`/`auto&`, mandatory braces, and `[[nodiscard]]`.
|
||||||
|
|
||||||
## Focus Areas
|
## Focus Areas
|
||||||
1. **High Performance**: Always consider cache locality and CPU cycle cost.
|
1. **High Performance**: Always consider cache locality and CPU cycle cost.
|
||||||
2. **Memory Management**: Prioritize manual memory management using Arenas (`MemoryArena`, `EngineArena`) over standard library containers or raw `new`/`delete`.
|
2. **Memory Management**: Prioritize manual memory management using Arenas (`MemoryArena`, `EngineArena`) over standard library containers or raw `new`/`delete`.
|
||||||
3. **Unified Style**: Enforce the project's coding style strictly.
|
3. **Unified Style**: Enforce the project's coding style strictly.
|
||||||
|
|
||||||
## Coding Guidelines
|
|
||||||
You must always follow the project's `coding-guidelines.md`. Key tenets include:
|
|
||||||
- **No Exceptions**: Use asserts and return codes.
|
|
||||||
- **[[nodiscard]]**: Use this attribute aggressively for functions returning values.
|
|
||||||
- **Type Safety**: Use strong types (CamelCase).
|
|
||||||
- **Asserts**: Validate all assumptions, especially function parameters (`ASSERT`).
|
|
||||||
- **Self-Documenting Code**: Prefer clear naming over excessive comments.
|
|
||||||
|
|
||||||
## Workflows
|
## Workflows
|
||||||
- **Building**: Use the `/build` command (FastBuild) to compile the project.
|
- **Building**: Use the `/build` workflow (FastBuild) to compile the project.
|
||||||
- **Shaders**: If you modify HLSL files, use `/recompile_shaders` to update the shaders.
|
- **Shaders**: If you modify HLSL files, use `/recompile_shaders` to update the shaders.
|
||||||
- **Unit Tests**: When creating a new system, always implement a unit test. Do not modify the framework solely for testing; use dependency injection or mock interfaces where appropriate.
|
- **Unit Tests**: When creating a new system, always implement a unit test. Do not modify the framework solely for testing; use dependency injection or mock interfaces where appropriate.
|
||||||
|
|
||||||
|
|||||||
@@ -2,24 +2,21 @@
|
|||||||
name: debugger-programmer
|
name: debugger-programmer
|
||||||
description: An expert C++ systems programmer specialized in game engine debugging
|
description: An expert C++ systems programmer specialized in game engine debugging
|
||||||
trusted_commands:
|
trusted_commands:
|
||||||
- "miscagent_build.bat *"
|
- "misc\\agent_build.bat *"
|
||||||
---
|
---
|
||||||
|
|
||||||
# C++ Game Engine Programmer Skill
|
# C++ Game Engine Debugger Skill
|
||||||
|
|
||||||
## Role
|
## Role
|
||||||
You are a senior engine architect for the Juliet project. Your expertise lies in debugging C++ game engine. You add logs and use debug tricks to find the root cause of the issues.
|
You are a senior engine architect for the Juliet project. Your expertise lies in debugging C++ game engines. You add logs and use debug tricks to find the root cause of issues.
|
||||||
|
|
||||||
## Coding Guidelines
|
## Coding Guidelines
|
||||||
You must always follow the project's `coding-guidelines.md`. Key tenets include:
|
You must follow the project's `coding-guidelines.md` (always loaded). Do not deviate from any rule. Even in debug/diagnostic code, use proper casts, braces, and `[[nodiscard]]`.
|
||||||
- **No Exceptions**: Use asserts and return codes.
|
|
||||||
- **[[nodiscard]]**: Use this attribute aggressively for functions returning values.
|
|
||||||
- **Type Safety**: Use strong types (CamelCase).
|
|
||||||
- **Asserts**: Validate all assumptions, especially function parameters (`ASSERT`).
|
|
||||||
|
|
||||||
## Workflows
|
## Workflows
|
||||||
- **Building**: Use the misc\Agent_build.bat or the /build command to compile the project.
|
- **Building**: Use the `/build` workflow to compile the project.
|
||||||
- **Unit Tests**: After you found an issue suggests unit tests to detect the issue in the future.
|
- **Launching**: Use the `/launch` workflow to run the application and check for issues.
|
||||||
|
- **Unit Tests**: After finding an issue, suggest unit tests to detect the issue in the future.
|
||||||
|
|
||||||
## Tone
|
## Tone
|
||||||
Professional, technical, and precise. Focus on explaining your debugging strategy.
|
Professional, technical, and precise. Focus on explaining your debugging strategy.
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
---
|
---
|
||||||
name: graphics-programmer
|
name: graphics-programmer
|
||||||
description: An expert in 3D rendering, shader development (HLSL), and visual aesthetics, acting as a bridge between technical implementation and artistic vision.
|
description: An expert in 3D rendering, shader development (HLSL), and visual aesthetics, acting as a bridge between technical implementation and artistic vision.
|
||||||
|
trusted_commands:
|
||||||
|
- "misc\\agent_build.bat *"
|
||||||
|
- "misc\\recompile_shaders.bat *"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Graphics Programmer & Tech Artist Skill
|
# Graphics Programmer & Tech Artist Skill
|
||||||
@@ -8,6 +11,13 @@ description: An expert in 3D rendering, shader development (HLSL), and visual ae
|
|||||||
## Role
|
## Role
|
||||||
You are the bridge between code and art for the Juliet project. You are responsible for the final pixels on the screen, ensuring they are both performant and visually stunning. You speak fluent C++ (D3D12) and HLSL.
|
You are the bridge between code and art for the Juliet project. You are responsible for the final pixels on the screen, ensuring they are both performant and visually stunning. You speak fluent C++ (D3D12) and HLSL.
|
||||||
|
|
||||||
|
## Coding Guidelines
|
||||||
|
You must follow the project's `coding-guidelines.md` (always loaded). Do not deviate from any rule. This applies to both C++ (D3D12) code and HLSL shaders.
|
||||||
|
|
||||||
|
### HLSL Specifics
|
||||||
|
- Use meaningful variable names.
|
||||||
|
- Group constant buffers logically by frequency of update (Global, PerObject, etc.).
|
||||||
|
|
||||||
## Focus Areas
|
## Focus Areas
|
||||||
1. **Visual Excellence**: Never settle for "it works." Make it look "premium." Use lighting, shadows, and post-processing to enhance the aesthetic.
|
1. **Visual Excellence**: Never settle for "it works." Make it look "premium." Use lighting, shadows, and post-processing to enhance the aesthetic.
|
||||||
2. **Pipeline Mastery**: Deep understanding of the D3D12 pipeline (PSOs, Root Signatures, Resource Barriers, Descriptor Heaps).
|
2. **Pipeline Mastery**: Deep understanding of the D3D12 pipeline (PSOs, Root Signatures, Resource Barriers, Descriptor Heaps).
|
||||||
@@ -15,16 +25,9 @@ You are the bridge between code and art for the Juliet project. You are responsi
|
|||||||
|
|
||||||
## Workflows
|
## Workflows
|
||||||
- **Shader Iteration**: Use the `/recompile_shaders` workflow immediately after editing any `.hlsl` file to catch syntax errors early.
|
- **Shader Iteration**: Use the `/recompile_shaders` workflow immediately after editing any `.hlsl` file to catch syntax errors early.
|
||||||
|
- **Building**: Use the `/build` workflow to compile C++ changes.
|
||||||
- **Performance**: Be mindful of GPU bandwidth and generic overdraw.
|
- **Performance**: Be mindful of GPU bandwidth and generic overdraw.
|
||||||
- **Debugging**: Think like a frame capture (PIX/RenderDoc). Visualize data (normals, depth, etc.) if unsure.
|
- **Debugging**: Think like a frame capture (PIX/RenderDoc). Visualize data (normals, depth, etc.) if unsure.
|
||||||
|
|
||||||
## Coding Guidelines
|
|
||||||
- **HLSL**:
|
|
||||||
- Use meaningful variable names.
|
|
||||||
- Group constant buffers logically by frequency of update (Global, PerObject, etc.).
|
|
||||||
- **C++ (D3D12)**:
|
|
||||||
- Follow the general `coding-guidelines.md`.
|
|
||||||
- Ensure correct `D3D12_RESOURCE_BARRIER` usage to avoid race conditions.
|
|
||||||
|
|
||||||
## Tone
|
## Tone
|
||||||
Creative, collaborative, and highly technical. You are excited about graphics techniques (PBR, Raytracing, etc.) but grounded in the reality of shipping a performant frame.
|
Creative, collaborative, and highly technical. You are excited about graphics techniques (PBR, Raytracing, etc.) but grounded in the reality of shipping a performant frame.
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
---
|
---
|
||||||
name: video-game-tester
|
name: video-game-tester
|
||||||
description: A rigorous QA specialist and test automation engineer focused on verifying game stability and correctness.
|
description: A rigorous QA specialist and test automation engineer focused on verifying game stability and correctness.
|
||||||
|
trusted_commands:
|
||||||
|
- "misc\\agent_build.bat *"
|
||||||
|
- "misc\\launch.bat *"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Video Game Tester Skill
|
# Video Game Tester Skill
|
||||||
@@ -8,6 +11,9 @@ description: A rigorous QA specialist and test automation engineer focused on ve
|
|||||||
## Role
|
## Role
|
||||||
You are the gatekeeper of quality for the Juliet project. Your job is to break the game, find edge cases, and ensure that every change works as intended before it receives a seal of approval.
|
You are the gatekeeper of quality for the Juliet project. Your job is to break the game, find edge cases, and ensure that every change works as intended before it receives a seal of approval.
|
||||||
|
|
||||||
|
## Coding Guidelines
|
||||||
|
You must follow the project's `coding-guidelines.md` (always loaded). Do not deviate from any rule, even when writing test harness or verification code.
|
||||||
|
|
||||||
## Focus Areas
|
## Focus Areas
|
||||||
1. **Verification**: Never assume a change works. Always run the game.
|
1. **Verification**: Never assume a change works. Always run the game.
|
||||||
2. **Reproduction**: If you find an issue, define clear steps to reproduce it.
|
2. **Reproduction**: If you find an issue, define clear steps to reproduce it.
|
||||||
@@ -17,7 +23,7 @@ You are the gatekeeper of quality for the Juliet project. Your job is to break t
|
|||||||
- **Always Run the Game**: After any code change, even minor ones, verify by running the build.
|
- **Always Run the Game**: After any code change, even minor ones, verify by running the build.
|
||||||
- **Launch Command**: Use the `/launch` workflow.
|
- **Launch Command**: Use the `/launch` workflow.
|
||||||
- **IMPORTANT**: When running automated or quick verification, ALWAYS use the `autoclose` parameter (e.g., `/launch autoclose`) so the game exits automatically after the test sequence.
|
- **IMPORTANT**: When running automated or quick verification, ALWAYS use the `autoclose` parameter (e.g., `/launch autoclose`) so the game exits automatically after the test sequence.
|
||||||
- **Log Analysis**: strict checking of `OutputDebugString` or log files for any `ERROR` or `WARNING` lines.
|
- **Log Analysis**: Strict checking of `misc\agent_output.log` for any `ERROR` or `WARNING` lines after a build or launch.
|
||||||
- **Visual Inspection**: Report any visual artifacts, flickering, or incorrect rendering immediately.
|
- **Visual Inspection**: Report any visual artifacts, flickering, or incorrect rendering immediately.
|
||||||
|
|
||||||
## Reporting
|
## Reporting
|
||||||
|
|||||||
@@ -3,15 +3,19 @@ description: Build the Juliet project using FastBuild
|
|||||||
---
|
---
|
||||||
|
|
||||||
// turbo-all
|
// turbo-all
|
||||||
// @auto-approve: true
|
|
||||||
|
|
||||||
This workflow sets up the Juliet build environment and runs `fbuild`.
|
This workflow builds the Juliet project and writes output to `misc\agent_output.log`.
|
||||||
|
|
||||||
1. To build a specific configuration (e.g., msvc-Debug):
|
1. To build the default (clang-Debug):
|
||||||
`misc\agent_build.bat clang-Debug"`
|
// turbo
|
||||||
|
`misc\agent_build.bat clang 2>&1 | tee misc\agent_output.log`
|
||||||
|
|
||||||
2. To build the default clang:
|
2. To build a specific configuration (e.g., clang-Debug, msvc-Debug):
|
||||||
`misc\agent_build.bat clang"`
|
// turbo
|
||||||
|
`misc\agent_build.bat clang-Debug 2>&1 | tee misc\agent_output.log`
|
||||||
|
|
||||||
3. To see all available targets:
|
3. To see all available targets:
|
||||||
`misc\agent_build.bat -showtargets"`
|
// turbo
|
||||||
|
`misc\agent_build.bat -showtargets 2>&1 | tee misc\agent_output.log`
|
||||||
|
|
||||||
|
4. Check build results by reading `misc\agent_output.log`.
|
||||||
@@ -2,5 +2,12 @@
|
|||||||
description: Launch the Juliet application
|
description: Launch the Juliet application
|
||||||
---
|
---
|
||||||
|
|
||||||
1. Run the launch script
|
// turbo-all
|
||||||
misc\launch.bat autoclose
|
|
||||||
|
This workflow launches the Juliet application and writes output to `misc\agent_output.log`.
|
||||||
|
|
||||||
|
1. Run the launch script:
|
||||||
|
// turbo
|
||||||
|
`misc\launch.bat autoclose 2>&1 | tee misc\agent_output.log`
|
||||||
|
|
||||||
|
2. Check launch results by reading `misc\agent_output.log`.
|
||||||
@@ -4,7 +4,10 @@ description: Recompile shaders for the Juliet project
|
|||||||
|
|
||||||
// turbo-all
|
// turbo-all
|
||||||
|
|
||||||
This workflow recompiles all shaders using the `recompile_shaders.bat` script.
|
This workflow recompiles all shaders and writes output to `misc\agent_output.log`.
|
||||||
|
|
||||||
1. Recompile all shaders:
|
1. Recompile all shaders:
|
||||||
`misc\recompile_shaders.bat"`
|
// turbo
|
||||||
|
`misc\recompile_shaders.bat 2>&1 | tee misc\agent_output.log`
|
||||||
|
|
||||||
|
2. Check shader compilation results by reading `misc\agent_output.log`.
|
||||||
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;
|
||||||
|
|||||||
@@ -8,31 +8,7 @@ struct Input
|
|||||||
|
|
||||||
float4 main(Input input) : SV_Target0
|
float4 main(Input input) : SV_Target0
|
||||||
{
|
{
|
||||||
// Retrieve the texture using SM6.6 bindless syntax
|
|
||||||
// Texture2D texture = ResourceDescriptorHeap[TextureIndex]; (Must cast to Texture2D<float4>)
|
|
||||||
// Wait, ResourceDescriptorHeap indexing returns a wrapper, usually we use Textures[TextureIndex]?
|
|
||||||
// Juliet seems to use `ResourceDescriptorHeap` for Buffers.
|
|
||||||
// Let's check Triangle.vert/frag.
|
|
||||||
|
|
||||||
// In bindless, usually:
|
|
||||||
// Texture2D<float4> tex = ResourceDescriptorHeap[TextureIndex];
|
|
||||||
// SamplerState samp = SamplerDescriptorHeap[0]; // Assuming static sampler or passed index
|
|
||||||
|
|
||||||
// I need to check how Juliet accesses textures.
|
|
||||||
// I'll assume standard SM6.6 usage.
|
|
||||||
Texture2D<float4> tex = ResourceDescriptorHeap[TextureIndex];
|
Texture2D<float4> tex = ResourceDescriptorHeap[TextureIndex];
|
||||||
SamplerState samp = SamplerDescriptorHeap[0]; // Point sampler or Linear? ImGui usually uses Linear.
|
SamplerState samp = SamplerDescriptorHeap[0];
|
||||||
// D3D12GraphicsDevice.cpp created static samplers.
|
|
||||||
// Root signature has Static Samplers.
|
|
||||||
// RegisterSpace 0.
|
|
||||||
// Sampler register 0 is Point/Nearest?
|
|
||||||
// Let's check CreateGraphicsRootSignature in D3D12GraphicsDevice.cpp.
|
|
||||||
// It creates s_nearest at 0.
|
|
||||||
|
|
||||||
// If I want Linear, I might need another sampler or rely on s_nearest for font (pixel art font?)
|
|
||||||
// Default ImGui font is usually antialiased, so Linear is preferred.
|
|
||||||
// But pixel aligned UI...
|
|
||||||
// I will use `SamplerDescriptorHeap[0]` for now.
|
|
||||||
|
|
||||||
return input.Color * tex.Sample(samp, input.UV);
|
return input.Color * tex.Sample(samp, input.UV);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,10 @@ Output main(uint vertexIndex : SV_VertexID)
|
|||||||
{
|
{
|
||||||
Output output;
|
Output output;
|
||||||
|
|
||||||
// Retrieve the vertex buffer using SM6.6 bindless syntax
|
|
||||||
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
||||||
|
|
||||||
// Add VertexOffset for indexed drawing with bindless buffers
|
|
||||||
// (SV_VertexID in indexed draw is raw index from index buffer, doesn't include BaseVertexLocation)
|
|
||||||
uint actualVertexIndex = vertexIndex + VertexOffset;
|
uint actualVertexIndex = vertexIndex + VertexOffset;
|
||||||
|
|
||||||
// ImDrawVert stride = 20 bytes (Vec2 pos + Vec2 uv + uint color)
|
|
||||||
uint stride = 20;
|
uint stride = 20;
|
||||||
uint offset = actualVertexIndex * stride;
|
uint offset = actualVertexIndex * stride;
|
||||||
|
|
||||||
@@ -33,34 +29,12 @@ Output main(uint vertexIndex : SV_VertexID)
|
|||||||
float2 uv = asfloat(buffer.Load2(offset + 8));
|
float2 uv = asfloat(buffer.Load2(offset + 8));
|
||||||
uint col = buffer.Load(offset + 16);
|
uint col = buffer.Load(offset + 16);
|
||||||
|
|
||||||
// Unpack color (uint to float4)
|
|
||||||
// ImGui colors are 0xAABBGGRR (ABGR packed)
|
|
||||||
// We need to unpack to float4.
|
|
||||||
// HLSL unpacks as little endian.
|
|
||||||
// uint 0xAABBGGRR -> byte0=RR, byte1=GG, byte2=BB, byte3=AA
|
|
||||||
float4 c;
|
float4 c;
|
||||||
c.x = float(col & 0xFF) / 255.0f;
|
c.x = float(col & 0xFF) / 255.0f;
|
||||||
c.y = float((col >> 8) & 0xFF) / 255.0f;
|
c.y = float((col >> 8) & 0xFF) / 255.0f;
|
||||||
c.z = float((col >> 16) & 0xFF) / 255.0f;
|
c.z = float((col >> 16) & 0xFF) / 255.0f;
|
||||||
c.w = float((col >> 24) & 0xFF) / 255.0f;
|
c.w = float((col >> 24) & 0xFF) / 255.0f;
|
||||||
|
|
||||||
// Transform
|
|
||||||
// ImGui sends pixel coordinates.
|
|
||||||
// We need to transform to NDC [-1, 1].
|
|
||||||
// PushConstants should contain Scale and Translate.
|
|
||||||
// float2 Scale = 2.0 / DisplaySize
|
|
||||||
// float2 Translate = -1.0 - (DisplayPos * Scale)
|
|
||||||
|
|
||||||
// We will assume PushConstants are float2 Scale, float2 Translate.
|
|
||||||
// Struct in RootConstants.hlsl?
|
|
||||||
// RootConstants.hlsl likely defines `cbuffer PushConstants : register(b0)`.
|
|
||||||
// Let's assume standard push constants usage.
|
|
||||||
// Debug.vert.hlsl used `ViewProjection`.
|
|
||||||
// We need to customize PushConstants or reuse `ViewProjection` slot?
|
|
||||||
// Juliet uses 128 bytes of push constants.
|
|
||||||
// We can map float4 ProjectionMatrix (or similar).
|
|
||||||
|
|
||||||
// Use Scale and Translate from RootConstants
|
|
||||||
output.Position = float4(pos * Scale + Translate, 0.0f, 1.0f);
|
output.Position = float4(pos * Scale + Translate, 0.0f, 1.0f);
|
||||||
output.Color = c;
|
output.Color = c;
|
||||||
output.UV = uv;
|
output.UV = uv;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -10,20 +12,25 @@ Output main(uint vertexIndex : SV_VertexID)
|
|||||||
{
|
{
|
||||||
Output output;
|
Output output;
|
||||||
|
|
||||||
// Retrieve the buffer using SM6.6 bindless syntax
|
|
||||||
// Use BufferIndex from RootConstants (pushed via SetPushConstants)
|
|
||||||
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
||||||
|
|
||||||
// Read position from buffer (Index * stride)
|
uint stride = 40;
|
||||||
// Stride = 2 float (pos) + 4 float (color) = 6 * 4 = 24 bytes ?
|
|
||||||
// Let's assume just position 2D (8 bytes) + Color (16 bytes)
|
|
||||||
uint stride = 24;
|
|
||||||
uint offset = vertexIndex * stride;
|
uint offset = vertexIndex * stride;
|
||||||
|
|
||||||
float2 pos = asfloat(buffer.Load2(offset));
|
float3 pos = asfloat(buffer.Load3(offset));
|
||||||
float4 col = asfloat(buffer.Load4(offset + 8));
|
float3 normal = asfloat(buffer.Load3(offset + 12));
|
||||||
|
float4 col = asfloat(buffer.Load4(offset + 24));
|
||||||
|
|
||||||
output.Position = float4(pos, 0.0f, 1.0f);
|
// Fetch Model Matrix
|
||||||
|
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: 21d3299e58...acdaaef625
@@ -14,7 +14,7 @@ namespace Game
|
|||||||
void InitEntityManager(Juliet::NonNullPtr<Juliet::Arena> arena)
|
void InitEntityManager(Juliet::NonNullPtr<Juliet::Arena> arena)
|
||||||
{
|
{
|
||||||
Manager.Arena = arena.Get();
|
Manager.Arena = arena.Get();
|
||||||
Manager.Entities.Create(arena);
|
Manager.Entities.Create(arena JULIET_DEBUG_PARAM("Entities"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownEntityManager()
|
void ShutdownEntityManager()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -108,9 +108,11 @@
|
|||||||
<CustomBuild Include="include\Graphics\GraphicsConfig.h" />
|
<CustomBuild Include="include\Graphics\GraphicsConfig.h" />
|
||||||
<CustomBuild Include="include\Graphics\GraphicsPipeline.h" />
|
<CustomBuild Include="include\Graphics\GraphicsPipeline.h" />
|
||||||
<CustomBuild Include="include\Graphics\ImGuiRenderer.h" />
|
<CustomBuild Include="include\Graphics\ImGuiRenderer.h" />
|
||||||
|
<CustomBuild Include="include\Graphics\Mesh.h" />
|
||||||
<CustomBuild Include="include\Graphics\RenderPass.h" />
|
<CustomBuild Include="include\Graphics\RenderPass.h" />
|
||||||
<CustomBuild Include="include\Graphics\Shader.h" />
|
<CustomBuild Include="include\Graphics\Shader.h" />
|
||||||
<CustomBuild Include="include\Graphics\Texture.h" />
|
<CustomBuild Include="include\Graphics\Texture.h" />
|
||||||
|
<CustomBuild Include="include\Graphics\VertexData.h" />
|
||||||
<CustomBuild Include="include\Juliet.h" />
|
<CustomBuild Include="include\Juliet.h" />
|
||||||
<CustomBuild Include="Juliet.bff" />
|
<CustomBuild Include="Juliet.bff" />
|
||||||
<CustomBuild Include="src\Core\Application\ApplicationManager.cpp" />
|
<CustomBuild Include="src\Core\Application\ApplicationManager.cpp" />
|
||||||
@@ -220,10 +222,15 @@
|
|||||||
<CustomBuild Include="src\Graphics\Graphics.cpp" />
|
<CustomBuild Include="src\Graphics\Graphics.cpp" />
|
||||||
<CustomBuild Include="src\Graphics\GraphicsDevice.h" />
|
<CustomBuild Include="src\Graphics\GraphicsDevice.h" />
|
||||||
<CustomBuild Include="src\Graphics\ImGuiRenderer.cpp" />
|
<CustomBuild Include="src\Graphics\ImGuiRenderer.cpp" />
|
||||||
|
<CustomBuild Include="src\Graphics\Mesh.cpp" />
|
||||||
<CustomBuild Include="src\UnitTest\Container\VectorUnitTest.cpp" />
|
<CustomBuild Include="src\UnitTest\Container\VectorUnitTest.cpp" />
|
||||||
<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>
|
||||||
|
|||||||
@@ -172,6 +172,9 @@
|
|||||||
<CustomBuild Include="include\Graphics\ImGuiRenderer.h">
|
<CustomBuild Include="include\Graphics\ImGuiRenderer.h">
|
||||||
<Filter>include\Graphics</Filter>
|
<Filter>include\Graphics</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="include\Graphics\Mesh.h">
|
||||||
|
<Filter>include\Graphics</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="include\Graphics\RenderPass.h">
|
<CustomBuild Include="include\Graphics\RenderPass.h">
|
||||||
<Filter>include\Graphics</Filter>
|
<Filter>include\Graphics</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -181,6 +184,9 @@
|
|||||||
<CustomBuild Include="include\Graphics\Texture.h">
|
<CustomBuild Include="include\Graphics\Texture.h">
|
||||||
<Filter>include\Graphics</Filter>
|
<Filter>include\Graphics</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="include\Graphics\VertexData.h">
|
||||||
|
<Filter>include\Graphics</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="include\Juliet.h">
|
<CustomBuild Include="include\Juliet.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -507,6 +513,9 @@
|
|||||||
<CustomBuild Include="src\Graphics\ImGuiRenderer.cpp">
|
<CustomBuild Include="src\Graphics\ImGuiRenderer.cpp">
|
||||||
<Filter>src\Graphics</Filter>
|
<Filter>src\Graphics</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="src\Graphics\Mesh.cpp">
|
||||||
|
<Filter>src\Graphics</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="src\UnitTest\Container\VectorUnitTest.cpp">
|
<CustomBuild Include="src\UnitTest\Container\VectorUnitTest.cpp">
|
||||||
<Filter>src\UnitTest\Container</Filter>
|
<Filter>src\UnitTest\Container</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
|||||||
@@ -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,25 +9,26 @@ 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;
|
||||||
|
|
||||||
// Accessors for Engine Systems
|
// Accessors for Engine Systems
|
||||||
virtual struct Window* GetPlatformWindow() = 0;
|
virtual struct Window* GetPlatformWindow() = 0;
|
||||||
virtual struct GraphicsDevice* GetGraphicsDevice() = 0;
|
virtual struct GraphicsDevice* GetGraphicsDevice() = 0;
|
||||||
|
|
||||||
// Render Lifecycle (Engine-Managed Render Loop)
|
// Render Lifecycle (Engine-Managed Render Loop)
|
||||||
virtual void OnPreRender(CommandList* cmd) = 0;
|
virtual void OnPreRender(CommandList* cmd) = 0;
|
||||||
virtual void OnRender(RenderPass* pass, CommandList* cmd) = 0;
|
virtual void OnRender(RenderPass* pass, CommandList* cmd) = 0;
|
||||||
virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0;
|
virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0;
|
||||||
virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0;
|
virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0;
|
||||||
virtual struct Camera GetDebugCamera() = 0;
|
virtual struct Camera GetDebugCamera() = 0;
|
||||||
};
|
};
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Juliet
|
|||||||
class NonNullPtr
|
class NonNullPtr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NonNullPtr(Type* ptr)
|
inline NonNullPtr(Type* ptr)
|
||||||
: InternalPtr(ptr)
|
: InternalPtr(ptr)
|
||||||
{
|
{
|
||||||
Assert(ptr, "Tried to initialize a NonNullPtr with a null pointer");
|
Assert(ptr, "Tried to initialize a NonNullPtr with a null pointer");
|
||||||
@@ -64,7 +64,7 @@ namespace Juliet
|
|||||||
return *InternalPtr;
|
return *InternalPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* operator->() const
|
inline Type* operator->() const
|
||||||
{
|
{
|
||||||
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
|
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
|
||||||
return InternalPtr;
|
return InternalPtr;
|
||||||
|
|||||||
@@ -9,24 +9,28 @@ namespace Juliet
|
|||||||
template <typename Type, size_t ReserveSize = 16, bool AllowRealloc = false>
|
template <typename Type, size_t ReserveSize = 16, bool AllowRealloc = false>
|
||||||
struct VectorArena
|
struct VectorArena
|
||||||
{
|
{
|
||||||
void Create(JULIET_DEBUG_ONLY(const char* name = "VectorArena"))
|
void Create(JULIET_DEBUG_PARAM_FIRST(const char* name = nullptr))
|
||||||
{
|
{
|
||||||
Assert(!Arena);
|
Assert(!Arena);
|
||||||
static_assert(AllowRealloc == false);
|
static_assert(AllowRealloc == false);
|
||||||
|
|
||||||
DataFirst = DataLast = nullptr;
|
DataFirst = DataLast = nullptr;
|
||||||
Count = 0;
|
Count = 0;
|
||||||
ArenaParams params{ .AllowRealloc = AllowRealloc JULIET_DEBUG_ONLY(, .CanReserveMore = false) };
|
|
||||||
Arena = ArenaAllocate(params JULIET_DEBUG_ONLY(, name));
|
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
|
||||||
|
ArenaParams params{ .AllowRealloc = AllowRealloc JULIET_DEBUG_PARAM(.CanReserveMore = false) };
|
||||||
|
Arena = ArenaAllocate(params JULIET_DEBUG_PARAM(Name));
|
||||||
InternalArena = true;
|
InternalArena = true;
|
||||||
|
|
||||||
Reserve(ReserveSize);
|
Reserve(ReserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Create(NonNullPtr<Arena> arena)
|
void Create(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* name = nullptr))
|
||||||
{
|
{
|
||||||
Assert(!Arena);
|
Assert(!Arena);
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
|
||||||
|
|
||||||
DataFirst = DataLast = nullptr;
|
DataFirst = DataLast = nullptr;
|
||||||
Count = 0;
|
Count = 0;
|
||||||
Arena = arena.Get();
|
Arena = arena.Get();
|
||||||
@@ -53,7 +57,7 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
if (Data == nullptr)
|
if (Data == nullptr)
|
||||||
{
|
{
|
||||||
Data = ArenaPushArray<Type>(Arena, newCapacity);
|
Data = ArenaPushArray<Type>(Arena, newCapacity JULIET_DEBUG_PARAM(Name));
|
||||||
}
|
}
|
||||||
else if constexpr (AllowRealloc)
|
else if constexpr (AllowRealloc)
|
||||||
{
|
{
|
||||||
@@ -61,7 +65,7 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
DataFirst = Data =
|
DataFirst = Data =
|
||||||
static_cast<Type*>(ArenaReallocate(Arena, Data, Capacity * sizeof(Type), newCapacity * sizeof(Type),
|
static_cast<Type*>(ArenaReallocate(Arena, Data, Capacity * sizeof(Type), newCapacity * sizeof(Type),
|
||||||
AlignOf(Type), true JULIET_DEBUG_ONLY(, "VectorRealloc")));
|
AlignOf(Type), true JULIET_DEBUG_PARAM("VectorRealloc")));
|
||||||
DataLast = Data + Count - 1;
|
DataLast = Data + Count - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,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);
|
||||||
@@ -161,13 +193,20 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
|
|
||||||
ArenaClear(Arena);
|
if (InternalArena)
|
||||||
|
{
|
||||||
|
ArenaClear(Arena);
|
||||||
|
Data = nullptr;
|
||||||
|
Capacity = 0;
|
||||||
|
Reserve(ReserveSize);
|
||||||
|
}
|
||||||
|
|
||||||
DataFirst = DataLast = nullptr;
|
DataFirst = DataLast = nullptr;
|
||||||
Data = nullptr;
|
|
||||||
Count = 0;
|
Count = 0;
|
||||||
Capacity = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const { return Count == 0; }
|
||||||
|
|
||||||
// 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]; }
|
||||||
@@ -192,6 +231,7 @@ namespace Juliet
|
|||||||
size_t Count;
|
size_t Count;
|
||||||
size_t Capacity;
|
size_t Capacity;
|
||||||
bool InternalArena : 1;
|
bool InternalArena : 1;
|
||||||
|
JULIET_DEBUG_ONLY(const char* Name = "VectorArena";)
|
||||||
};
|
};
|
||||||
static_assert(std::is_standard_layout_v<VectorArena<int>>,
|
static_assert(std::is_standard_layout_v<VectorArena<int>>,
|
||||||
"VectorArena must have a standard layout to remain POD-like.");
|
"VectorArena must have a standard layout to remain POD-like.");
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -15,7 +16,7 @@ namespace Juliet
|
|||||||
Graphics = 1,
|
Graphics = 1,
|
||||||
Networking = 2,
|
Networking = 2,
|
||||||
Engine = 3,
|
Engine = 3,
|
||||||
Tool = 4,
|
Tool = 4,
|
||||||
Game = 5,
|
Game = 5,
|
||||||
};
|
};
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -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,33 +8,99 @@ 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;
|
||||||
result.m[1][1] = 1.0f;
|
result.m[1][1] = 1.0f;
|
||||||
result.m[2][2] = 1.0f;
|
result.m[2][2] = 1.0f;
|
||||||
result.m[3][3] = 1.0f;
|
result.m[3][3] = 1.0f;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix operator*(const Matrix& rhs) const
|
[[nodiscard]] inline Matrix operator*(const Matrix& lhs, const Matrix& rhs)
|
||||||
|
{
|
||||||
|
Matrix result = {};
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
Matrix result = {};
|
for (int j = 0; j < 4; ++j)
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 4; ++j)
|
for (int k = 0; k < 4; ++k)
|
||||||
{
|
{
|
||||||
for (int k = 0; k < 4; ++k)
|
result.m[i][j] += lhs.m[i][k] * rhs.m[k][j];
|
||||||
{
|
|
||||||
result.m[i][j] += 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
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ namespace Juliet
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(Arena) <= k_ArenaHeaderSize);
|
static_assert(sizeof(Arena) <= k_ArenaHeaderSize);
|
||||||
|
|
||||||
|
struct TempArena
|
||||||
|
{
|
||||||
|
Arena* Arena;
|
||||||
|
index_t Position;
|
||||||
|
};
|
||||||
|
|
||||||
struct ArenaParams
|
struct ArenaParams
|
||||||
{
|
{
|
||||||
uint64 ReserveSize = g_Arena_Default_Reserve_Size;
|
uint64 ReserveSize = g_Arena_Default_Reserve_Size;
|
||||||
@@ -60,7 +66,6 @@ namespace Juliet
|
|||||||
bool AllowRealloc = false;
|
bool AllowRealloc = false;
|
||||||
|
|
||||||
// When false, will assert if a new block is reserved.
|
// When false, will assert if a new block is reserved.
|
||||||
// Useful for Vectors as they are guaranteed to be linear and i wont need to implement memcopy to increase capacity
|
|
||||||
JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;)
|
JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,29 +77,27 @@ namespace Juliet
|
|||||||
// Raw Push, can be used but templated helpers exists below
|
// Raw Push, can be used but templated helpers exists below
|
||||||
[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align,
|
[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align,
|
||||||
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||||
[[nodiscard]] void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize,
|
[[nodiscard]] JULIET_API void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize,
|
||||||
size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||||
void ArenaPopTo(NonNullPtr<Arena> arena, size_t position);
|
JULIET_API void ArenaPopTo(NonNullPtr<Arena> arena, size_t position);
|
||||||
void ArenaPop(NonNullPtr<Arena> arena, size_t amount);
|
JULIET_API void ArenaPop(NonNullPtr<Arena> arena, size_t amount);
|
||||||
void ArenaClear(NonNullPtr<Arena> arena);
|
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
||||||
[[nodiscard]] size_t ArenaPos(NonNullPtr<Arena> arena);
|
[[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr<Arena> arena);
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena)
|
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* tag = nullptr))
|
||||||
{
|
{
|
||||||
return static_cast<Type*>(
|
return static_cast<Type*>(
|
||||||
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_ONLY(, typeid(Type).name())));
|
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_PARAM(tag ? tag : typeid(Type).name())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// #define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0))
|
|
||||||
// #define push_array_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (1))
|
|
||||||
// #define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
|
|
||||||
// #define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
|
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count)
|
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count JULIET_DEBUG_PARAM(const char* tag = nullptr))
|
||||||
{
|
{
|
||||||
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)),
|
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)),
|
||||||
true JULIET_DEBUG_ONLY(, typeid(Type).name())));
|
true JULIET_DEBUG_PARAM(tag ? tag : typeid(Type).name())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TempArena ArenaTempBegin(NonNullPtr<Arena> arena);
|
||||||
|
void ArenaTempEnd(TempArena temp);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ 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);
|
||||||
|
|||||||
@@ -134,13 +134,11 @@ namespace Juliet
|
|||||||
extern JULIET_API void BindGraphicsPipeline(NonNullPtr<RenderPass> renderPass, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
extern JULIET_API void BindGraphicsPipeline(NonNullPtr<RenderPass> renderPass, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
||||||
extern JULIET_API void DrawPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numVertices, uint32 numInstances,
|
extern JULIET_API void DrawPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numVertices, uint32 numInstances,
|
||||||
uint32 firstVertex, uint32 firstInstance);
|
uint32 firstVertex, uint32 firstInstance);
|
||||||
extern JULIET_API void DrawIndexedPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numIndices,
|
extern JULIET_API void DrawIndexedPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numIndices, uint32 numInstances,
|
||||||
uint32 numInstances, uint32 firstIndex, uint32 vertexOffset,
|
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance);
|
||||||
uint32 firstInstance);
|
|
||||||
|
|
||||||
extern JULIET_API void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
|
|
||||||
|
|
||||||
|
|
||||||
|
extern JULIET_API void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
|
||||||
|
IndexFormat format, size_t indexCount, index_t offset);
|
||||||
|
|
||||||
extern JULIET_API void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage,
|
extern JULIET_API void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage,
|
||||||
uint32 rootParameterIndex, uint32 numConstants, const void* constants);
|
uint32 rootParameterIndex, uint32 numConstants, const void* constants);
|
||||||
@@ -166,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
|
||||||
23
Juliet/include/Graphics/Mesh.h
Normal file
23
Juliet/include/Graphics/Mesh.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Math/Matrix.h>
|
||||||
|
#include <Juliet.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
struct Arena;
|
||||||
|
struct Vertex;
|
||||||
|
|
||||||
|
struct Mesh
|
||||||
|
{
|
||||||
|
size_t VertexCount;
|
||||||
|
size_t IndexCount;
|
||||||
|
|
||||||
|
index_t VertexOffset;
|
||||||
|
index_t IndexOffset;
|
||||||
|
|
||||||
|
Matrix Transform = MatrixIdentity();
|
||||||
|
};
|
||||||
|
} // 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
|
||||||
13
Juliet/include/Graphics/VertexData.h
Normal file
13
Juliet/include/Graphics/VertexData.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
float Position[3];
|
||||||
|
float Normal[3];
|
||||||
|
float Color[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
using Index = uint16;
|
||||||
|
} // namespace Juliet
|
||||||
@@ -22,9 +22,13 @@
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define JULIET_DEBUG 1
|
#define JULIET_DEBUG 1
|
||||||
#define JULIET_DEBUG_ONLY(...) __VA_ARGS__
|
#define JULIET_DEBUG_ONLY(...) __VA_ARGS__
|
||||||
|
#define JULIET_DEBUG_PARAM_FIRST(...) __VA_ARGS__
|
||||||
|
#define JULIET_DEBUG_PARAM(...) , __VA_ARGS__
|
||||||
#else
|
#else
|
||||||
#define JULIET_DEBUG 0
|
#define JULIET_DEBUG 0
|
||||||
#define JULIET_DEBUG_ONLY(...)
|
#define JULIET_DEBUG_ONLY(...)
|
||||||
|
#define JULIET_DEBUG_PARAM_FIRST(...)
|
||||||
|
#define JULIET_DEBUG_PARAM(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Manual override to disable ImGui
|
// Manual override to disable ImGui
|
||||||
|
|||||||
@@ -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);
|
||||||
{
|
bool OS_Commit(Byte* ptr, size_t size);
|
||||||
Byte* OS_Reserve(size_t size);
|
void OS_Release(Byte* ptr, size_t size);
|
||||||
bool OS_Commit(Byte* ptr, size_t size);
|
} // namespace Memory::Internal
|
||||||
void OS_Release(Byte* ptr, size_t size);
|
|
||||||
} // namespace 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>()));
|
||||||
|
|
||||||
w32_rio_functions.RIODeregisterBuffer(
|
if (w32_rio_functions.RIORegisterBuffer != nullptr && w32_rio_functions.RIODeregisterBuffer != nullptr)
|
||||||
w32_rio_functions.RIORegisterBuffer(reinterpret_cast<PCHAR>(ptr), static_cast<DWORD>(size)));
|
{
|
||||||
|
w32_rio_functions.RIODeregisterBuffer(
|
||||||
|
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
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ namespace Juliet
|
|||||||
basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */;
|
basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */;
|
||||||
|
|
||||||
// Allocate from Scratch Arena (transient)
|
// Allocate from Scratch Arena (transient)
|
||||||
index_t pos = ArenaPos(code.Arena);
|
TempArena temp = ArenaTempBegin(code.Arena);
|
||||||
auto tempDllPath = ArenaPushArray<char>(code.Arena, tempDllMaxBufferSize);
|
auto tempDllPath = ArenaPushArray<char>(temp.Arena, tempDllMaxBufferSize);
|
||||||
|
|
||||||
for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt)
|
for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt)
|
||||||
{
|
{
|
||||||
@@ -97,7 +97,7 @@ namespace Juliet
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArenaPopTo(code.Arena, pos);
|
ArenaTempEnd(temp);
|
||||||
|
|
||||||
code.Dll = LoadDynamicLibrary(tempDllPath);
|
code.Dll = LoadDynamicLibrary(tempDllPath);
|
||||||
if (code.Dll)
|
if (code.Dll)
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -327,4 +327,15 @@ namespace Juliet
|
|||||||
size_t position = current->BasePosition + current->Position;
|
size_t position = current->BasePosition + current->Position;
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TempArena ArenaTempBegin(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
index_t position = ArenaPos(arena);
|
||||||
|
return { arena.Get(), position };
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArenaTempEnd(TempArena temp)
|
||||||
|
{
|
||||||
|
ArenaPopTo(temp.Arena, temp.Position);
|
||||||
|
}
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ namespace Juliet::D3D12
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case D3D12BufferType::Base: return "Base";
|
case D3D12BufferType::Base: return "Base";
|
||||||
case D3D12BufferType::TransferDownload: return "TransferDownload";
|
case D3D12BufferType::TransferDownload: return "TransferDownload";
|
||||||
case D3D12BufferType::TransferUpload: return "TransferUpload";
|
case D3D12BufferType::TransferUpload: return "TransferUpload";
|
||||||
}
|
}
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@@ -34,11 +34,10 @@ namespace Juliet::D3D12
|
|||||||
{
|
{
|
||||||
switch (usage)
|
switch (usage)
|
||||||
{
|
{
|
||||||
case BufferUsage::None: return "None";
|
case BufferUsage::None: return "None";
|
||||||
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,94 +61,62 @@ namespace Juliet::D3D12
|
|||||||
Free(buffer);
|
Free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, BufferUsage usage, D3D12BufferType type)
|
D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, size_t stride, BufferUsage usage,
|
||||||
|
D3D12BufferType type, bool isDynamic)
|
||||||
{
|
{
|
||||||
auto buffer = static_cast<D3D12Buffer*>(Calloc(1, sizeof(D3D12Buffer)));
|
auto* buffer = static_cast<D3D12Buffer*>(Calloc(1, sizeof(D3D12Buffer)));
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == D3D12BufferType::Base && usage == BufferUsage::None)
|
||||||
|
{
|
||||||
|
Assert(false, "Creating Base buffer with BufferUsage::None is invalid");
|
||||||
|
DestroyBuffer(buffer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Align size for Constant Buffers
|
// Align size for Constant Buffers
|
||||||
if (usage == BufferUsage::ConstantBuffer)
|
if (usage == BufferUsage::ConstantBuffer)
|
||||||
{
|
{
|
||||||
size = (size + 255U) & ~255U;
|
size = (size + 255U) & ~255U;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
|
|
||||||
D3D12_HEAP_PROPERTIES heapProperties = {};
|
D3D12_HEAP_PROPERTIES heapProperties = {};
|
||||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
switch (type)
|
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||||
|
|
||||||
|
// Constant buffers or Dynamic buffers generally need to be uploaded every frame
|
||||||
|
const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer);
|
||||||
|
|
||||||
|
if (type == D3D12BufferType::TransferDownload)
|
||||||
{
|
{
|
||||||
case D3D12BufferType::Base:
|
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
||||||
|
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
}
|
||||||
|
else if (isUpload)
|
||||||
|
{
|
||||||
|
if (d3d12Driver->GPUUploadHeapSupported)
|
||||||
{
|
{
|
||||||
switch (usage)
|
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
||||||
{
|
initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
case BufferUsage::None:
|
|
||||||
{
|
|
||||||
Assert(false, "Creating buffer with invalid usage");
|
|
||||||
DestroyBuffer(buffer);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BufferUsage::IndexBuffer:
|
|
||||||
case BufferUsage::StructuredBuffer:
|
|
||||||
case BufferUsage::VertexBuffer:
|
|
||||||
{
|
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BufferUsage::ConstantBuffer:
|
|
||||||
{
|
|
||||||
if (d3d12Driver->GPUUploadHeapSupported)
|
|
||||||
{
|
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
||||||
}
|
|
||||||
// heapFlags = D3D12_HEAP_FLAG_NONE; // Avoid overwriting if set above
|
|
||||||
if (heapProperties.Type == D3D12_HEAP_TYPE_GPU_UPLOAD)
|
|
||||||
{
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE; // Or appropriate flags
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case D3D12BufferType::TransferDownload:
|
else
|
||||||
{
|
{
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE;
|
|
||||||
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case D3D12BufferType::TransferUpload:
|
|
||||||
{
|
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE;
|
|
||||||
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;
|
||||||
@@ -164,20 +131,24 @@ namespace Juliet::D3D12
|
|||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s", (void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage));
|
Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s",
|
||||||
|
(void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage));
|
||||||
|
|
||||||
ID3D12Resource* handle = nullptr;
|
ID3D12Resource* handle = nullptr;
|
||||||
HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags,
|
HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc,
|
||||||
&desc, initialState, nullptr,
|
initialState, nullptr, IID_ID3D12Resource,
|
||||||
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", (unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type);
|
Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d",
|
||||||
|
(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);
|
||||||
@@ -202,20 +173,33 @@ namespace Juliet::D3D12
|
|||||||
|
|
||||||
if (usage == BufferUsage::ConstantBuffer)
|
if (usage == BufferUsage::ConstantBuffer)
|
||||||
{
|
{
|
||||||
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
||||||
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
||||||
|
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
||||||
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
else if (usage == BufferUsage::StructuredBuffer)
|
else if (usage == BufferUsage::StructuredBuffer)
|
||||||
{
|
{
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
|
||||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
srvDesc.Buffer.FirstElement = 0;
|
srvDesc.Buffer.FirstElement = 0;
|
||||||
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
|
|
||||||
srvDesc.Buffer.StructureByteStride = 0;
|
if (stride > 0)
|
||||||
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
|
{
|
||||||
|
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
srvDesc.Buffer.NumElements = static_cast<uint32>(size / stride);
|
||||||
|
srvDesc.Buffer.StructureByteStride = static_cast<uint32>(stride);
|
||||||
|
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||||
|
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
|
||||||
|
srvDesc.Buffer.StructureByteStride = 0;
|
||||||
|
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
|
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
|
||||||
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
|
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
|
||||||
}
|
}
|
||||||
@@ -230,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)
|
||||||
@@ -245,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)
|
||||||
@@ -273,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());
|
||||||
@@ -305,8 +308,8 @@ namespace Juliet::D3D12
|
|||||||
// We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc.
|
// We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc.
|
||||||
// D3D12 Upload heaps start in GENERIC_READ and cannot transition.
|
// D3D12 Upload heaps start in GENERIC_READ and cannot transition.
|
||||||
|
|
||||||
d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle,
|
d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle, dstOffset, d3d12Src->Handle,
|
||||||
dstOffset, d3d12Src->Handle, srcOffset, size);
|
srcOffset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer)
|
void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer)
|
||||||
|
|||||||
@@ -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)
|
|
||||||
{
|
{
|
||||||
uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue();
|
int32 i = 0;
|
||||||
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
while (i < d3d12Driver->SubmittedCommandListCount)
|
||||||
{
|
{
|
||||||
success &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
|
uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue();
|
||||||
|
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,30 +370,40 @@ namespace Juliet::D3D12
|
|||||||
d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference);
|
d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format)
|
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format,
|
||||||
|
size_t indexCount, index_t offset)
|
||||||
{
|
{
|
||||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||||
auto* d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
auto* d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||||
|
|
||||||
// Transition to INDEX_BUFFER state if needed
|
// Transition to INDEX_BUFFER state if needed
|
||||||
if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_INDEX_BUFFER)
|
if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ)
|
||||||
{
|
{
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
barrier.Transition.pResource = d3d12Buffer->Handle;
|
barrier.Transition.pResource = d3d12Buffer->Handle;
|
||||||
barrier.Transition.StateBefore = d3d12Buffer->CurrentState;
|
barrier.Transition.StateBefore = d3d12Buffer->CurrentState;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
barrier.Transition.StateAfter =
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
||||||
d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier);
|
d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier);
|
||||||
d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_INDEX_BUFFER_VIEW ibView;
|
D3D12_INDEX_BUFFER_VIEW ibView;
|
||||||
ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress();
|
ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset;
|
||||||
ibView.SizeInBytes = static_cast<UINT>(d3d12Buffer->Size);
|
if (format == IndexFormat::UInt16)
|
||||||
ibView.Format = (format == IndexFormat::UInt16) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
{
|
||||||
|
ibView.SizeInBytes = static_cast<UINT>(indexCount * sizeof(uint16));
|
||||||
|
ibView.Format = DXGI_FORMAT_R16_UINT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ibView.SizeInBytes = static_cast<UINT>(indexCount * sizeof(uint32));
|
||||||
|
ibView.Format = DXGI_FORMAT_R32_UINT;
|
||||||
|
}
|
||||||
|
|
||||||
d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView);
|
d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView);
|
||||||
}
|
}
|
||||||
@@ -477,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ namespace Juliet::D3D12
|
|||||||
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
||||||
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
||||||
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
|
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
|
||||||
extern void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
|
extern void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
|
||||||
|
IndexFormat format, size_t indexCount, index_t offset);
|
||||||
extern void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
|
extern void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
|
||||||
uint32 numConstants, const void* constants);
|
uint32 numConstants, const void* constants);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace Juliet::D3D12::Internal
|
|||||||
|
|
||||||
heap->CurrentDescriptorIndex = 0;
|
heap->CurrentDescriptorIndex = 0;
|
||||||
|
|
||||||
heap->FreeIndices.Create(JULIET_DEBUG_ONLY("DescriptorHeap FreeIndices"));
|
heap->FreeIndices.Create(arena JULIET_DEBUG_PARAM("DescriptorHeap Free Indices"));
|
||||||
heap->FreeIndices.Resize(16);
|
heap->FreeIndices.Resize(16);
|
||||||
heap->CurrentFreeIndex = 0;
|
heap->CurrentFreeIndex = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -623,27 +618,6 @@ namespace Juliet::D3D12
|
|||||||
Free(device.Get());
|
Free(device.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: SetViewPort, SetScissorRect, SetBlendConstants, SetStencilReference
|
|
||||||
// are defined in D3D12CommandList.cpp and used directly via D3D12:: namespace
|
|
||||||
|
|
||||||
// BindGraphicsPipeline is now assigned directly from D3D12:: namespace
|
|
||||||
|
|
||||||
// DrawPrimitives is now assigned directly from D3D12:: namespace
|
|
||||||
|
|
||||||
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
|
|
||||||
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance)
|
|
||||||
{
|
|
||||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
|
||||||
d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex,
|
|
||||||
static_cast<INT>(vertexOffset), firstInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitUntilGPUIsIdle, SetPushConstants are now assigned directly from D3D12:: namespace
|
|
||||||
|
|
||||||
// QueryFence, ReleaseFence, CreateShader, DestroyShader are now assigned directly from D3D12:: namespace
|
|
||||||
|
|
||||||
// CreateGraphicsPipeline is assigned directly from D3D12:: namespace
|
|
||||||
|
|
||||||
void DestroyGraphicsPipeline(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> pipeline)
|
void DestroyGraphicsPipeline(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> pipeline)
|
||||||
{
|
{
|
||||||
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||||
@@ -656,8 +630,6 @@ namespace Juliet::D3D12
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer functions are assigned directly from D3D12:: namespace
|
|
||||||
|
|
||||||
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst, NonNullPtr<GraphicsTransferBuffer> src)
|
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst, NonNullPtr<GraphicsTransferBuffer> src)
|
||||||
{
|
{
|
||||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||||
@@ -703,14 +675,12 @@ namespace Juliet::D3D12
|
|||||||
Internal::TextureTransitionToDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST);
|
Internal::TextureTransitionToDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDescriptorIndex wrapper needed to adapt signature from GPUDriver* to GraphicsDevice*
|
|
||||||
uint32 GetDescriptorIndex(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
|
uint32 GetDescriptorIndex(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
|
||||||
{
|
{
|
||||||
auto* driver = static_cast<D3D12Driver*>(device->Driver);
|
auto* driver = static_cast<D3D12Driver*>(device->Driver);
|
||||||
return D3D12::GetDescriptorIndex(driver, buffer);
|
return D3D12::GetDescriptorIndex(driver, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDescriptorIndexTexture provides custom logic to get SRV handle index
|
|
||||||
uint32 GetDescriptorIndexTexture(NonNullPtr<GraphicsDevice> /*device*/, NonNullPtr<Texture> texture)
|
uint32 GetDescriptorIndexTexture(NonNullPtr<GraphicsDevice> /*device*/, NonNullPtr<Texture> texture)
|
||||||
{
|
{
|
||||||
auto* textureContainer = reinterpret_cast<D3D12TextureContainer*>(texture.Get());
|
auto* textureContainer = reinterpret_cast<D3D12TextureContainer*>(texture.Get());
|
||||||
@@ -1042,42 +1012,41 @@ namespace Juliet::D3D12
|
|||||||
device->AcquireSwapChainTexture = AcquireSwapChainTexture;
|
device->AcquireSwapChainTexture = AcquireSwapChainTexture;
|
||||||
device->WaitAndAcquireSwapChainTexture = WaitAndAcquireSwapChainTexture;
|
device->WaitAndAcquireSwapChainTexture = WaitAndAcquireSwapChainTexture;
|
||||||
device->GetSwapChainTextureFormat = GetSwapChainTextureFormat;
|
device->GetSwapChainTextureFormat = GetSwapChainTextureFormat;
|
||||||
device->AcquireCommandList = D3D12::AcquireCommandList;
|
device->AcquireCommandList = AcquireCommandList;
|
||||||
device->SubmitCommandLists = D3D12::SubmitCommandLists;
|
device->SubmitCommandLists = SubmitCommandLists;
|
||||||
|
device->BeginRenderPass = BeginRenderPass;
|
||||||
device->BeginRenderPass = D3D12::BeginRenderPass;
|
device->EndRenderPass = EndRenderPass;
|
||||||
device->EndRenderPass = D3D12::EndRenderPass;
|
device->SetViewPort = SetViewPort;
|
||||||
device->SetViewPort = D3D12::SetViewPort;
|
device->SetScissorRect = SetScissorRect;
|
||||||
device->SetScissorRect = D3D12::SetScissorRect;
|
device->SetBlendConstants = SetBlendConstants;
|
||||||
device->SetBlendConstants = D3D12::SetBlendConstants;
|
device->SetStencilReference = SetStencilReference;
|
||||||
device->SetStencilReference = D3D12::SetStencilReference;
|
device->BindGraphicsPipeline = BindGraphicsPipeline;
|
||||||
device->BindGraphicsPipeline = D3D12::BindGraphicsPipeline;
|
device->DrawPrimitives = DrawPrimitives;
|
||||||
device->DrawPrimitives = D3D12::DrawPrimitives;
|
device->DrawIndexedPrimitives = DrawIndexedPrimitives;
|
||||||
device->DrawIndexedPrimitives = DrawIndexedPrimitives;
|
device->SetIndexBuffer = SetIndexBuffer;
|
||||||
device->SetIndexBuffer = D3D12::SetIndexBuffer;
|
device->WaitUntilGPUIsIdle = WaitUntilGPUIsIdle;
|
||||||
device->WaitUntilGPUIsIdle = D3D12::WaitUntilGPUIsIdle;
|
device->SetPushConstants = SetPushConstants;
|
||||||
|
device->QueryFence = QueryFence;
|
||||||
device->SetPushConstants = D3D12::SetPushConstants;
|
device->ReleaseFence = ReleaseFence;
|
||||||
device->QueryFence = D3D12::QueryFence;
|
device->CreateShader = CreateShader;
|
||||||
device->ReleaseFence = D3D12::ReleaseFence;
|
device->DestroyShader = DestroyShader;
|
||||||
device->CreateShader = D3D12::CreateShader;
|
device->CreateGraphicsPipeline = CreateGraphicsPipeline;
|
||||||
device->DestroyShader = D3D12::DestroyShader;
|
device->DestroyGraphicsPipeline = DestroyGraphicsPipeline;
|
||||||
device->CreateGraphicsPipeline = D3D12::CreateGraphicsPipeline;
|
device->CreateGraphicsBuffer = CreateGraphicsBuffer;
|
||||||
device->DestroyGraphicsPipeline = DestroyGraphicsPipeline;
|
device->DestroyGraphicsBuffer = DestroyGraphicsBuffer;
|
||||||
device->CreateGraphicsBuffer = D3D12::CreateGraphicsBuffer;
|
device->MapGraphicsBuffer = MapBuffer;
|
||||||
device->DestroyGraphicsBuffer = D3D12::DestroyGraphicsBuffer;
|
device->UnmapGraphicsBuffer = UnmapBuffer;
|
||||||
device->CreateGraphicsTransferBuffer = D3D12::CreateGraphicsTransferBuffer;
|
device->CreateGraphicsTransferBuffer = CreateGraphicsTransferBuffer;
|
||||||
device->DestroyGraphicsTransferBuffer = D3D12::DestroyGraphicsTransferBuffer;
|
device->DestroyGraphicsTransferBuffer = DestroyGraphicsTransferBuffer;
|
||||||
device->MapGraphicsTransferBuffer = D3D12::MapBuffer;
|
device->MapGraphicsTransferBuffer = MapBuffer;
|
||||||
device->UnmapGraphicsTransferBuffer = D3D12::UnmapBuffer;
|
device->UnmapGraphicsTransferBuffer = UnmapBuffer;
|
||||||
device->CopyBuffer = CopyBuffer;
|
device->CopyBuffer = CopyBuffer;
|
||||||
device->CopyBufferToTexture = CopyBufferToTexture;
|
device->CopyBufferToTexture = CopyBufferToTexture;
|
||||||
device->TransitionBufferToReadable = D3D12::TransitionBufferToReadable;
|
device->TransitionBufferToReadable = TransitionBufferToReadable;
|
||||||
|
device->GetDescriptorIndex = GetDescriptorIndex;
|
||||||
device->GetDescriptorIndex = GetDescriptorIndex;
|
device->GetDescriptorIndexTexture = GetDescriptorIndexTexture;
|
||||||
device->GetDescriptorIndexTexture = GetDescriptorIndexTexture;
|
device->CreateTexture = CreateTexture;
|
||||||
device->CreateTexture = D3D12::CreateTexture;
|
device->DestroyTexture = DestroyTexture;
|
||||||
device->DestroyTexture = D3D12::DestroyTexture;
|
|
||||||
|
|
||||||
#if ALLOW_SHADER_HOT_RELOAD
|
#if ALLOW_SHADER_HOT_RELOAD
|
||||||
device->UpdateGraphicsPipelineShaders = UpdateGraphicsPipelineShaders;
|
device->UpdateGraphicsPipelineShaders = UpdateGraphicsPipelineShaders;
|
||||||
|
|||||||
@@ -283,4 +283,12 @@ namespace Juliet::D3D12
|
|||||||
|
|
||||||
d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance);
|
d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
|
||||||
|
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance)
|
||||||
|
{
|
||||||
|
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||||
|
d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex,
|
||||||
|
static_cast<INT>(vertexOffset), firstInstance);
|
||||||
|
}
|
||||||
} // namespace Juliet::D3D12
|
} // namespace Juliet::D3D12
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ namespace Juliet::D3D12
|
|||||||
extern void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
extern void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
||||||
extern void DrawPrimitives(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,
|
extern void DrawPrimitives(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,
|
||||||
uint32 firstVertex, uint32 firstInstance);
|
uint32 firstVertex, uint32 firstInstance);
|
||||||
|
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
|
||||||
|
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance);
|
||||||
} // namespace Juliet::D3D12
|
} // namespace Juliet::D3D12
|
||||||
|
|||||||
@@ -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)
|
|
||||||
{
|
{
|
||||||
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
int32 idx = 0;
|
||||||
|
while (idx < d3d12driver->SubmittedCommandListCount)
|
||||||
|
{
|
||||||
|
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,12 +122,19 @@ namespace Juliet::D3D12
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx -= 1)
|
|
||||||
{
|
{
|
||||||
uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue();
|
int32 idx = 0;
|
||||||
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
while (idx < d3d12driver->SubmittedCommandListCount)
|
||||||
{
|
{
|
||||||
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue();
|
||||||
|
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
||||||
|
{
|
||||||
|
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
@@ -180,7 +211,7 @@ namespace Juliet::D3D12
|
|||||||
if (driver->AvailableFenceCount == 0)
|
if (driver->AvailableFenceCount == 0)
|
||||||
{
|
{
|
||||||
HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE,
|
HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE,
|
||||||
IID_ID3D12Fence, reinterpret_cast<void**>(&handle));
|
IID_ID3D12Fence, reinterpret_cast<void**>(&handle));
|
||||||
if (FAILED(result))
|
if (FAILED(result))
|
||||||
{
|
{
|
||||||
LogError(driver->D3D12Device, "Failed to create fence!", result);
|
LogError(driver->D3D12Device, "Failed to create fence!", result);
|
||||||
@@ -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,124 +1,124 @@
|
|||||||
|
#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
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
DXGI_FORMAT JulietToD3D12_TextureFormat[] = {
|
DXGI_FORMAT JulietToD3D12_TextureFormat[] = {
|
||||||
DXGI_FORMAT_UNKNOWN, // INVALID
|
DXGI_FORMAT_UNKNOWN, // INVALID
|
||||||
DXGI_FORMAT_A8_UNORM, // A8_UNORM
|
DXGI_FORMAT_A8_UNORM, // A8_UNORM
|
||||||
DXGI_FORMAT_R8_UNORM, // R8_UNORM
|
DXGI_FORMAT_R8_UNORM, // R8_UNORM
|
||||||
DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM
|
DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM
|
||||||
DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM
|
DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM
|
||||||
DXGI_FORMAT_R16_UNORM, // R16_UNORM
|
DXGI_FORMAT_R16_UNORM, // R16_UNORM
|
||||||
DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM
|
DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM
|
||||||
DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM
|
DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM
|
||||||
DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM
|
DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM
|
||||||
DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM
|
DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM
|
||||||
DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM
|
DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM
|
||||||
DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM
|
DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM
|
||||||
DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM
|
DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM
|
||||||
DXGI_FORMAT_BC1_UNORM, // BC1_UNORM
|
DXGI_FORMAT_BC1_UNORM, // BC1_UNORM
|
||||||
DXGI_FORMAT_BC2_UNORM, // BC2_UNORM
|
DXGI_FORMAT_BC2_UNORM, // BC2_UNORM
|
||||||
DXGI_FORMAT_BC3_UNORM, // BC3_UNORM
|
DXGI_FORMAT_BC3_UNORM, // BC3_UNORM
|
||||||
DXGI_FORMAT_BC4_UNORM, // BC4_UNORM
|
DXGI_FORMAT_BC4_UNORM, // BC4_UNORM
|
||||||
DXGI_FORMAT_BC5_UNORM, // BC5_UNORM
|
DXGI_FORMAT_BC5_UNORM, // BC5_UNORM
|
||||||
DXGI_FORMAT_BC7_UNORM, // BC7_UNORM
|
DXGI_FORMAT_BC7_UNORM, // BC7_UNORM
|
||||||
DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT
|
DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT
|
||||||
DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT
|
DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT
|
||||||
DXGI_FORMAT_R8_SNORM, // R8_SNORM
|
DXGI_FORMAT_R8_SNORM, // R8_SNORM
|
||||||
DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM
|
DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM
|
||||||
DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM
|
DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM
|
||||||
DXGI_FORMAT_R16_SNORM, // R16_SNORM
|
DXGI_FORMAT_R16_SNORM, // R16_SNORM
|
||||||
DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM
|
DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM
|
||||||
DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM
|
DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM
|
||||||
DXGI_FORMAT_R16_FLOAT, // R16_FLOAT
|
DXGI_FORMAT_R16_FLOAT, // R16_FLOAT
|
||||||
DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT
|
DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT
|
||||||
DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT
|
DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT
|
||||||
DXGI_FORMAT_R32_FLOAT, // R32_FLOAT
|
DXGI_FORMAT_R32_FLOAT, // R32_FLOAT
|
||||||
DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT
|
DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT
|
||||||
DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT
|
DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT
|
||||||
DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT
|
DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT
|
||||||
DXGI_FORMAT_R8_UINT, // R8_UINT
|
DXGI_FORMAT_R8_UINT, // R8_UINT
|
||||||
DXGI_FORMAT_R8G8_UINT, // R8G8_UINT
|
DXGI_FORMAT_R8G8_UINT, // R8G8_UINT
|
||||||
DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT
|
DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT
|
||||||
DXGI_FORMAT_R16_UINT, // R16_UINT
|
DXGI_FORMAT_R16_UINT, // R16_UINT
|
||||||
DXGI_FORMAT_R16G16_UINT, // R16G16_UINT
|
DXGI_FORMAT_R16G16_UINT, // R16G16_UINT
|
||||||
DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT
|
DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT
|
||||||
DXGI_FORMAT_R32_UINT, // R32_UINT
|
DXGI_FORMAT_R32_UINT, // R32_UINT
|
||||||
DXGI_FORMAT_R32G32_UINT, // R32G32_UINT
|
DXGI_FORMAT_R32G32_UINT, // R32G32_UINT
|
||||||
DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT
|
DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT
|
||||||
DXGI_FORMAT_R8_SINT, // R8_INT
|
DXGI_FORMAT_R8_SINT, // R8_INT
|
||||||
DXGI_FORMAT_R8G8_SINT, // R8G8_INT
|
DXGI_FORMAT_R8G8_SINT, // R8G8_INT
|
||||||
DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT
|
DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT
|
||||||
DXGI_FORMAT_R16_SINT, // R16_INT
|
DXGI_FORMAT_R16_SINT, // R16_INT
|
||||||
DXGI_FORMAT_R16G16_SINT, // R16G16_INT
|
DXGI_FORMAT_R16G16_SINT, // R16G16_INT
|
||||||
DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT
|
DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT
|
||||||
DXGI_FORMAT_R32_SINT, // R32_INT
|
DXGI_FORMAT_R32_SINT, // R32_INT
|
||||||
DXGI_FORMAT_R32G32_SINT, // R32G32_INT
|
DXGI_FORMAT_R32G32_SINT, // R32G32_INT
|
||||||
DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT
|
DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT
|
||||||
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB
|
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB
|
||||||
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB
|
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB
|
||||||
DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB
|
DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB
|
||||||
DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB
|
DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB
|
||||||
DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB
|
DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB
|
||||||
DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB
|
DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB
|
||||||
DXGI_FORMAT_R16_TYPELESS, // D16_UNORM
|
DXGI_FORMAT_R16_TYPELESS, // D16_UNORM
|
||||||
DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM
|
DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM
|
||||||
DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT
|
DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT
|
||||||
DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT
|
DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT
|
||||||
DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT
|
DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM
|
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB
|
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT
|
||||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT
|
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT
|
||||||
};
|
};
|
||||||
static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) ==
|
static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) ==
|
||||||
ToUnderlying(TextureFormat::Count));
|
ToUnderlying(TextureFormat::Count));
|
||||||
@@ -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,17 +392,27 @@ 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 = {};
|
||||||
D3D12_CLEAR_VALUE* pClearValue = nullptr;
|
D3D12_CLEAR_VALUE* pClearValue = nullptr;
|
||||||
|
|
||||||
if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
|
if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
|
||||||
@@ -426,9 +432,10 @@ 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))
|
||||||
{
|
{
|
||||||
@@ -451,10 +458,11 @@ namespace Juliet::D3D12
|
|||||||
texture->Resource = resource;
|
texture->Resource = resource;
|
||||||
texture->ReferenceCount = 1;
|
texture->ReferenceCount = 1;
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -499,14 +507,14 @@ namespace Juliet::D3D12
|
|||||||
Internal::D3D12Descriptor descriptor;
|
Internal::D3D12Descriptor descriptor;
|
||||||
if (Internal::AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor))
|
if (Internal::AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor))
|
||||||
{
|
{
|
||||||
texture->SRVHandle = D3D12StagingDescriptor{};
|
texture->SRVHandle = D3D12StagingDescriptor{};
|
||||||
texture->SRVHandle.CpuHandleIndex = descriptor.Index;
|
texture->SRVHandle.CpuHandleIndex = descriptor.Index;
|
||||||
texture->SRVHandle.CpuHandle = descriptor.CpuHandle;
|
texture->SRVHandle.CpuHandle = descriptor.CpuHandle;
|
||||||
texture->SRVHandle.Heap = descriptor.Heap;
|
texture->SRVHandle.Heap = descriptor.Heap;
|
||||||
|
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
srvDesc.Format = desc.Format;
|
srvDesc.Format = desc.Format;
|
||||||
|
|
||||||
// Fix SRV format for Depth Buffers (TypeLess -> Typed)
|
// Fix SRV format for Depth Buffers (TypeLess -> Typed)
|
||||||
if (createInfo.Format == TextureFormat::D32_FLOAT)
|
if (createInfo.Format == TextureFormat::D32_FLOAT)
|
||||||
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
||||||
@@ -517,11 +525,11 @@ namespace Juliet::D3D12
|
|||||||
else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT)
|
else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT)
|
||||||
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||||
|
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
srvDesc.Texture2D.MipLevels = numMips;
|
srvDesc.Texture2D.MipLevels = numMips;
|
||||||
srvDesc.Texture2D.PlaneSlice = 0;
|
srvDesc.Texture2D.PlaneSlice = 0;
|
||||||
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
||||||
|
|
||||||
d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle);
|
d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle);
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#include <Core/HAL/Filesystem/Filesystem.h>
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
#include <Core/HAL/IO/IOStream.h>
|
#include <Core/HAL/IO/IOStream.h>
|
||||||
|
#include <Core/ImGui/ImGuiTests.h>
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
#include <Graphics/Graphics.h>
|
#include <Graphics/Graphics.h>
|
||||||
#include <Graphics/GraphicsDevice.h>
|
#include <Graphics/GraphicsDevice.h>
|
||||||
#include <Core/ImGui/ImGuiTests.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
@@ -63,7 +62,6 @@ namespace Juliet
|
|||||||
newDevice->Name = chosenFactory->Name;
|
newDevice->Name = chosenFactory->Name;
|
||||||
return newDevice;
|
return newDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -263,13 +261,14 @@ namespace Juliet
|
|||||||
commandListHeader->Device->SetStencilReference(commandList, reference);
|
commandListHeader->Device->SetStencilReference(commandList, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format)
|
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format,
|
||||||
|
size_t indexCount, index_t offset)
|
||||||
{
|
{
|
||||||
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList.Get());
|
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList.Get());
|
||||||
|
|
||||||
if (commandListHeader->Device->SetIndexBuffer)
|
if (commandListHeader->Device->SetIndexBuffer)
|
||||||
{
|
{
|
||||||
commandListHeader->Device->SetIndexBuffer(commandList, buffer, format);
|
commandListHeader->Device->SetIndexBuffer(commandList, buffer, format, indexCount, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,13 +296,11 @@ namespace Juliet
|
|||||||
|
|
||||||
if (commandListHeader->Device->DrawIndexedPrimitives)
|
if (commandListHeader->Device->DrawIndexedPrimitives)
|
||||||
{
|
{
|
||||||
commandListHeader->Device->DrawIndexedPrimitives(commandList, numIndices, numInstances, firstIndex, vertexOffset, firstInstance);
|
commandListHeader->Device->DrawIndexedPrimitives(commandList, numIndices, numInstances, firstIndex,
|
||||||
|
vertexOffset, firstInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
|
void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
|
||||||
uint32 numConstants, const void* constants)
|
uint32 numConstants, const void* constants)
|
||||||
{
|
{
|
||||||
@@ -374,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)
|
||||||
@@ -382,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);
|
||||||
@@ -399,8 +406,7 @@ namespace Juliet
|
|||||||
headers->Device->CopyBuffer(commandList, dst, src, size, dstOffset, srcOffset);
|
headers->Device->CopyBuffer(commandList, dst, src, size, dstOffset, srcOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst,
|
void CopyBufferToTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Texture> dst, NonNullPtr<GraphicsTransferBuffer> src)
|
||||||
NonNullPtr<GraphicsTransferBuffer> src)
|
|
||||||
{
|
{
|
||||||
auto* headers = reinterpret_cast<CommandListHeader*>(commandList.Get());
|
auto* headers = reinterpret_cast<CommandListHeader*>(commandList.Get());
|
||||||
if (headers->Device->CopyBufferToTexture)
|
if (headers->Device->CopyBufferToTexture)
|
||||||
@@ -409,7 +415,6 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer)
|
void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer)
|
||||||
{
|
{
|
||||||
auto* header = reinterpret_cast<CommandListHeader*>(commandList.Get());
|
auto* header = reinterpret_cast<CommandListHeader*>(commandList.Get());
|
||||||
@@ -426,7 +431,6 @@ namespace Juliet
|
|||||||
return device->GetDescriptorIndexTexture(device, texture);
|
return device->GetDescriptorIndexTexture(device, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DestroyGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
|
void DestroyGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
|
||||||
{
|
{
|
||||||
device->DestroyGraphicsBuffer(buffer);
|
device->DestroyGraphicsBuffer(buffer);
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ namespace Juliet
|
|||||||
void (*SetScissorRect)(NonNullPtr<CommandList> commandList, const Rectangle& viewPort);
|
void (*SetScissorRect)(NonNullPtr<CommandList> commandList, const Rectangle& viewPort);
|
||||||
void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
||||||
void (*SetStencilReference)(NonNullPtr<CommandList> commandList, uint8 reference);
|
void (*SetStencilReference)(NonNullPtr<CommandList> commandList, uint8 reference);
|
||||||
void (*SetIndexBuffer)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
|
void (*SetIndexBuffer)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
|
||||||
|
IndexFormat format, size_t indexCount, index_t offset);
|
||||||
|
|
||||||
void (*BindGraphicsPipeline)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
void (*BindGraphicsPipeline)(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
||||||
void (*DrawPrimitives)(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,
|
void (*DrawPrimitives)(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,
|
||||||
@@ -82,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);
|
||||||
@@ -99,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)
|
||||||
{
|
{
|
||||||
@@ -223,9 +224,7 @@ namespace Juliet
|
|||||||
DestroyShader(device, g_ImGuiState.VertexShader);
|
DestroyShader(device, g_ImGuiState.VertexShader);
|
||||||
}
|
}
|
||||||
if (g_ImGuiState.FragmentShader)
|
if (g_ImGuiState.FragmentShader)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
DestroyShader(device, g_ImGuiState.FragmentShader);
|
DestroyShader(device, g_ImGuiState.FragmentShader);
|
||||||
}
|
}
|
||||||
if (g_ImGuiState.FontTexture)
|
if (g_ImGuiState.FontTexture)
|
||||||
@@ -316,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++)
|
||||||
{
|
{
|
||||||
@@ -344,7 +343,7 @@ namespace Juliet
|
|||||||
TransitionBufferToReadable(cmdList, currentFrame.VertexBuffer);
|
TransitionBufferToReadable(cmdList, currentFrame.VertexBuffer);
|
||||||
|
|
||||||
// SetIndexBuffer transitions from COPY_DEST to INDEX_BUFFER (barrier waits for copy to complete)
|
// SetIndexBuffer transitions from COPY_DEST to INDEX_BUFFER (barrier waits for copy to complete)
|
||||||
SetIndexBuffer(cmdList, currentFrame.IndexBuffer, IndexFormat::UInt16);
|
SetIndexBuffer(cmdList, currentFrame.IndexBuffer, IndexFormat::UInt16, totalIdx, 0);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
BindGraphicsPipeline(renderPass, g_ImGuiState.Pipeline);
|
BindGraphicsPipeline(renderPass, g_ImGuiState.Pipeline);
|
||||||
@@ -379,7 +378,7 @@ namespace Juliet
|
|||||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
if (pcmd->UserCallback != nullptr)
|
if (pcmd->UserCallback != nullptr)
|
||||||
{
|
{
|
||||||
// pcmd->UserCallback(cmd_list, pcmd);
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -404,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);
|
||||||
|
|
||||||
|
|||||||
9
Juliet/src/Graphics/Mesh.cpp
Normal file
9
Juliet/src/Graphics/Mesh.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <Graphics/Mesh.h>
|
||||||
|
|
||||||
|
#include <Core/Memory/MemoryArena.h>
|
||||||
|
#include <Graphics/VertexData.h>
|
||||||
|
|
||||||
|
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,9 +59,12 @@
|
|||||||
.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$' }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.LinkerOutput = '$BinPath$/$Platform$-$BuildConfigName$/$ProjectName$$ExeExtension$'
|
.LinkerOutput = '$BinPath$/$Platform$-$BuildConfigName$/$ProjectName$$ExeExtension$'
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -20,14 +35,43 @@
|
|||||||
#include <Graphics/Graphics.h>
|
#include <Graphics/Graphics.h>
|
||||||
#include <Graphics/GraphicsConfig.h>
|
#include <Graphics/GraphicsConfig.h>
|
||||||
#include <Graphics/GraphicsPipeline.h>
|
#include <Graphics/GraphicsPipeline.h>
|
||||||
|
#include <Graphics/Mesh.h>
|
||||||
|
#include <Graphics/MeshRenderer.h>
|
||||||
#include <Graphics/RenderPass.h>
|
#include <Graphics/RenderPass.h>
|
||||||
#include <Juliet.h>
|
#include <Graphics/SkyboxRenderer.h>
|
||||||
|
#include <Graphics/VertexData.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.
|
||||||
@@ -41,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*);
|
||||||
@@ -61,24 +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
|
||||||
|
|
||||||
struct Vertex
|
void JulietApplication::Init(NonNullPtr<Arena>)
|
||||||
{
|
|
||||||
float Position[2];
|
|
||||||
float Color[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
void JulietApplication::Init()
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
@@ -88,45 +122,7 @@ void JulietApplication::Init()
|
|||||||
if (Running)
|
if (Running)
|
||||||
{
|
{
|
||||||
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;
|
||||||
@@ -144,51 +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 = 256;
|
constexpr float kOffset = (kGridSize - 1) * kSpacing * 0.5f;
|
||||||
bufferCI.Usage = BufferUsage::StructuredBuffer; // SRV for ResourceDescriptorHeap access
|
|
||||||
ConstantBuffer = CreateGraphicsBuffer(GraphicsDevice, bufferCI);
|
|
||||||
|
|
||||||
TransferBufferCreateInfo transferCI = {};
|
for (int row = 0; row < kGridSize; ++row)
|
||||||
transferCI.Size = 256;
|
|
||||||
transferCI.Usage = TransferBufferUsage::Upload;
|
|
||||||
TransferBuffer = CreateGraphicsTransferBuffer(GraphicsDevice, transferCI);
|
|
||||||
|
|
||||||
// Upload Static Data for Test
|
|
||||||
if (TransferBuffer && ConstantBuffer)
|
|
||||||
{
|
{
|
||||||
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, ConstantBuffer, TransferBuffer, 256);
|
|
||||||
TransitionBufferToReadable(initCmd, ConstantBuffer);
|
|
||||||
SubmitCommandLists(initCmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexShader)
|
// Start with some default test lights
|
||||||
{
|
PointLight redLight = {};
|
||||||
DestroyShader(GraphicsDevice, vertexShader);
|
redLight.Position = { 5.0f, 5.0f, 2.0f };
|
||||||
}
|
redLight.Radius = redLightRadius;
|
||||||
if (fragmentShader)
|
redLight.Color = { redLightColor[0], redLightColor[1], redLightColor[2] };
|
||||||
{
|
redLight.Intensity = redLightIntensity;
|
||||||
DestroyShader(GraphicsDevice, fragmentShader);
|
RedLightID = AddPointLight(redLight);
|
||||||
}
|
|
||||||
|
|
||||||
if (Running == false)
|
PointLight blueLight = {};
|
||||||
{
|
blueLight.Position = { -5.0f, 0.0f, 2.0f };
|
||||||
return;
|
blueLight.Radius = blueLightRadius;
|
||||||
}
|
blueLight.Color = { blueLightColor[0], blueLightColor[1], blueLightColor[2] };
|
||||||
|
blueLight.Intensity = blueLightIntensity;
|
||||||
|
BlueLightID = AddPointLight(blueLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
||||||
@@ -198,8 +181,8 @@ void JulietApplication::Init()
|
|||||||
if ((Running = GameCode.IsValid))
|
if ((Running = GameCode.IsValid))
|
||||||
{
|
{
|
||||||
GameInitParams params;
|
GameInitParams params;
|
||||||
params.GameArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Game Arena"));
|
params.GameArena = GameArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Game Arena"));
|
||||||
params.ScratchArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Scratch Arena"));
|
params.ScratchArena = GameScratchArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Scratch Arena"));
|
||||||
Game.Init(¶ms);
|
Game.Init(¶ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,14 +202,7 @@ void JulietApplication::Shutdown()
|
|||||||
{
|
{
|
||||||
DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline);
|
DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline);
|
||||||
}
|
}
|
||||||
if (ConstantBuffer)
|
|
||||||
{
|
|
||||||
DestroyGraphicsBuffer(GraphicsDevice, ConstantBuffer);
|
|
||||||
}
|
|
||||||
if (TransferBuffer)
|
|
||||||
{
|
|
||||||
DestroyGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
|
||||||
}
|
|
||||||
if (DepthBuffer)
|
if (DepthBuffer)
|
||||||
{
|
{
|
||||||
DestroyTexture(GraphicsDevice, DepthBuffer);
|
DestroyTexture(GraphicsDevice, DepthBuffer);
|
||||||
@@ -252,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))
|
||||||
@@ -279,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
|
||||||
|
|
||||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false);
|
#ifdef _WIN32
|
||||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true);
|
HWND hwnd = GetForegroundWindow();
|
||||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
|
if (hwnd)
|
||||||
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 5.0f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
|
{
|
||||||
|
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 }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true);
|
||||||
|
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
|
||||||
|
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 0.5f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
|
||||||
|
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);
|
||||||
|
|
||||||
@@ -300,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,52 +545,32 @@ void JulietApplication::Update()
|
|||||||
Debug::DebugDrawMemoryArena();
|
Debug::DebugDrawMemoryArena();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArenaClear(GameScratchArena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JulietApplication::OnPreRender(CommandList* cmd)
|
void JulietApplication::OnPreRender(CommandList* /*cmd*/) {}
|
||||||
{
|
|
||||||
// Buffer uploads
|
|
||||||
if (ConstantBuffer && TransferBuffer)
|
|
||||||
{
|
|
||||||
void* ptr = MapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
auto vertices = static_cast<Vertex*>(ptr);
|
|
||||||
|
|
||||||
// Triangle 1
|
|
||||||
vertices[0] = { { -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f, 1.0f } }; // Red
|
|
||||||
vertices[1] = { { 0.0f, 0.5f }, { 0.0f, 1.0f, 0.0f, 1.0f } }; // Green
|
|
||||||
vertices[2] = { { 0.5f, -0.5f }, { 0.0f, 0.0f, 1.0f, 1.0f } }; // Blue
|
|
||||||
|
|
||||||
// Triangle 2
|
|
||||||
vertices[3] = { { -0.5f, 0.5f }, { 1.0f, 1.0f, 0.0f, 1.0f } }; // Yellow
|
|
||||||
vertices[4] = { { 0.0f, 0.8f }, { 0.0f, 1.0f, 1.0f, 1.0f } }; // Cyan
|
|
||||||
vertices[5] = { { 0.5f, 0.5f }, { 1.0f, 0.0f, 1.0f, 1.0f } }; // Magenta
|
|
||||||
|
|
||||||
UnmapGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyBuffer(cmd, ConstantBuffer, TransferBuffer, 256);
|
|
||||||
TransitionBufferToReadable(cmd, ConstantBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
||||||
{
|
{
|
||||||
BindGraphicsPipeline(pass, GraphicsPipeline);
|
PushData pushData = {};
|
||||||
|
pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera());
|
||||||
|
|
||||||
uint32 descriptorIndex = GetDescriptorIndex(GraphicsDevice, ConstantBuffer);
|
if (enableGlobalLight)
|
||||||
|
|
||||||
struct PushData
|
|
||||||
{
|
{
|
||||||
float ViewProjection[16];
|
pushData.GlobalLightDirection = Normalize({ globalLightDir[0], globalLightDir[1], globalLightDir[2] });
|
||||||
uint32 BufferIndex;
|
pushData.GlobalLightColor = { globalLightColor[0], globalLightColor[1], globalLightColor[2] };
|
||||||
} pushData = {};
|
pushData.GlobalAmbientIntensity = globalAmbientIntensity;
|
||||||
pushData.BufferIndex = descriptorIndex;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pushData.GlobalLightDirection = { 0.0f, -1.0f, 0.0f };
|
||||||
|
pushData.GlobalLightColor = { 0.0f, 0.0f, 0.0f };
|
||||||
|
pushData.GlobalAmbientIntensity = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
|
RenderSkybox(pass, cmd, pushData.ViewProjection);
|
||||||
|
RenderMeshes(pass, cmd, pushData);
|
||||||
DrawPrimitives(pass, 6, 1, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
|
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
|
||||||
@@ -426,18 +595,58 @@ DepthStencilTargetInfo* JulietApplication::GetDepthTargetInfo()
|
|||||||
|
|
||||||
Camera JulietApplication::GetDebugCamera()
|
Camera JulietApplication::GetDebugCamera()
|
||||||
{
|
{
|
||||||
static float orbitTime = 0.0f;
|
if (freeCameraMode)
|
||||||
orbitTime += 0.016f;
|
{
|
||||||
|
Camera cam = {};
|
||||||
|
cam.Position = camPos;
|
||||||
|
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 ---
|
||||||
|
float baseRadius = 25.0f; // Increased to see 10x10 cube grid
|
||||||
|
|
||||||
|
float radius = baseRadius;
|
||||||
|
|
||||||
|
if (animateCamera || animateCameraTime > 0.0f)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
Camera cam = {};
|
||||||
|
cam.Position = { cosf(currentOrbitTime) * radius, sinf(currentOrbitTime) * radius, zHeight };
|
||||||
|
cam.Target = { 0.0f, 0.0f, 0.0f };
|
||||||
|
cam.Up = { 0.0f, 0.0f, 1.0f };
|
||||||
|
cam.FOV = 1.047f;
|
||||||
|
cam.AspectRatio = 1200.0f / 800.0f;
|
||||||
|
cam.NearPlane = 0.1f;
|
||||||
|
cam.FarPlane = 1000.0f;
|
||||||
|
|
||||||
|
return cam;
|
||||||
|
}
|
||||||
|
|
||||||
|
float zHeight = radius * 0.5f; // Keep a nice downward viewing angle
|
||||||
|
|
||||||
float radius = 30.0f;
|
|
||||||
Camera cam = {};
|
Camera cam = {};
|
||||||
cam.Position = { cosf(orbitTime) * radius, sinf(orbitTime) * radius, 10.0f };
|
cam.Position = { radius, 0.0f, zHeight };
|
||||||
cam.Target = { 0.0f, 0.0f, 0.0f };
|
cam.Target = { 0.0f, 0.0f, 0.0f };
|
||||||
cam.Up = { 0.0f, 0.0f, 1.0f };
|
cam.Up = { 0.0f, 0.0f, 1.0f };
|
||||||
cam.FOV = 1.047f;
|
cam.FOV = 1.047f;
|
||||||
cam.AspectRatio = 1200.0f / 800.0f;
|
cam.AspectRatio = 1200.0f / 800.0f;
|
||||||
cam.NearPlane = 0.1f;
|
cam.NearPlane = 0.1f;
|
||||||
cam.FarPlane = 1000.0f;
|
cam.FarPlane = 1000.0f;
|
||||||
|
|
||||||
return cam;
|
return cam;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,7 +654,6 @@ bool JulietApplication::IsRunning()
|
|||||||
{
|
{
|
||||||
return Running;
|
return Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
JulietApplication EditorApplication;
|
JulietApplication EditorApplication;
|
||||||
@@ -456,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
|
struct Mesh;
|
||||||
struct GraphicsTransferBuffer;
|
struct GraphicsTransferBuffer;
|
||||||
struct GraphicsBuffer;
|
struct GraphicsBuffer;
|
||||||
struct GraphicsDevice;
|
struct GraphicsDevice;
|
||||||
@@ -17,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;
|
||||||
@@ -26,27 +27,28 @@ class JulietApplication : public Juliet::IApplication
|
|||||||
Juliet::GraphicsDevice* GetGraphicsDevice() override { return GraphicsDevice; }
|
Juliet::GraphicsDevice* GetGraphicsDevice() override { return GraphicsDevice; }
|
||||||
|
|
||||||
// Render Lifecycle
|
// Render Lifecycle
|
||||||
void OnPreRender(Juliet::CommandList* cmd) override;
|
void OnPreRender(Juliet::CommandList* cmd) override;
|
||||||
void OnRender(Juliet::RenderPass* pass, Juliet::CommandList* cmd) override;
|
void OnRender(Juliet::RenderPass* pass, Juliet::CommandList* cmd) override;
|
||||||
Juliet::ColorTargetInfo GetColorTargetInfo(Juliet::Texture* swapchainTexture) override;
|
Juliet::ColorTargetInfo GetColorTargetInfo(Juliet::Texture* swapchainTexture) override;
|
||||||
Juliet::DepthStencilTargetInfo* GetDepthTargetInfo() override;
|
Juliet::DepthStencilTargetInfo* GetDepthTargetInfo() override;
|
||||||
Juliet::Camera GetDebugCamera() override;
|
Juliet::Camera GetDebugCamera() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void SetAutoCloseFrameCount(int count) { AutoCloseFrameCount = count; }
|
void SetAutoCloseFrameCount(int count) { AutoCloseFrameCount = count; }
|
||||||
int GetAutoCloseFrameCount() const { return AutoCloseFrameCount; }
|
int GetAutoCloseFrameCount() const { return AutoCloseFrameCount; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Juliet::Window* MainWindow = {};
|
Juliet::Window* MainWindow = {};
|
||||||
Juliet::GraphicsDevice* GraphicsDevice = {};
|
Juliet::GraphicsDevice* GraphicsDevice = {};
|
||||||
Juliet::HotReloadCode GameCode = {};
|
Juliet::HotReloadCode GameCode = {};
|
||||||
Juliet::GraphicsPipeline* GraphicsPipeline = {};
|
Juliet::GraphicsPipeline* GraphicsPipeline = {};
|
||||||
Juliet::GraphicsBuffer* ConstantBuffer = {};
|
Juliet::Texture* DepthBuffer = {};
|
||||||
Juliet::GraphicsTransferBuffer* TransferBuffer = {};
|
Juliet::Arena* GameArena = nullptr;
|
||||||
Juliet::Texture* DepthBuffer = {};
|
Juliet::Arena* GameScratchArena = nullptr;
|
||||||
|
|
||||||
bool Running = false;
|
int AutoCloseFrameCount = -1;
|
||||||
int AutoCloseFrameCount = -1;
|
bool Running = false;
|
||||||
|
float CameraTime = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
JulietApplication& GetEditorApplication();
|
JulietApplication& GetEditorApplication();
|
||||||
|
|||||||
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"
|
||||||
15
test.txt
15
test.txt
@@ -1,15 +0,0 @@
|
|||||||
--- Launching JulietApp.exe ---
|
|
||||||
Platform: x64Clang
|
|
||||||
Config: Debug
|
|
||||||
Running Paged Memory Arena Tests...
|
|
||||||
[2026-02-08 02:56:49.1217020] Allocating from W:\Classified\Juliet\Juliet\src\Core\Memory\MemoryArenaTests.cpp : 23l
|
|
||||||
[2026-02-08 02:56:49.1220553] Allocating from W:\Classified\Juliet\Juliet\src\Core\Memory\MemoryArena.cpp : 99l
|
|
||||||
[Success] Arena Pop
|
|
||||||
All Paged MemoryArena tests passed.
|
|
||||||
[2026-02-08 02:56:49.1319769] Starting Unit Tests...
|
|
||||||
[2026-02-08 02:56:49.1320761] Allocating from Juliet/include\Core/Container/Vector.h : 19l
|
|
||||||
[2026-02-08 02:56:49.1321474] --- ASSERTION FAILED ---
|
|
||||||
[2026-02-08 02:56:49.1321999] Expression: vec[0] == 30
|
|
||||||
[2026-02-08 02:56:49.1322519] Message: No additional information provided.
|
|
||||||
[2026-02-08 02:56:49.1323083] Location: W:\Classified\Juliet\Juliet\src\UnitTest\Container\VectorUnitTest.cpp(45): void __cdecl Juliet::VectorUnitTest(void)
|
|
||||||
[2026-02-08 02:56:49.1323588] -------------------------
|
|
||||||
Reference in New Issue
Block a user