Compare commits
53 Commits
0a75554071
...
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 | |||
| dfd7279e84 | |||
| 5a22a172a6 | |||
| 6260d9aacf | |||
| be113fa89d | |||
| 96169123dd | |||
| 5337d4cb66 | |||
| c6552d2def | |||
| 6a6f34516c | |||
| 536f6c5c60 | |||
| f73b8284bb | |||
| 679edf48ed | |||
| 0876ed8205 | |||
| 16c3a6052f | |||
| 76f094de4f | |||
| f58a856308 | |||
| 0a2310d18f | |||
| 1d2b48c89e | |||
| 3edd23996e | |||
| 6f4fc75b66 | |||
| 84fe295e18 | |||
| 84f82ba478 | |||
| 4d66261c9f | |||
| 45ef1134f7 |
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
4
External/ImGui.vcxproj
vendored
4
External/ImGui.vcxproj
vendored
@@ -196,7 +196,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;imgui;imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;imgui;imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -226,7 +226,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;imgui;imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;imgui;imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
|
|||||||
2
External/Imgui
vendored
2
External/Imgui
vendored
Submodule External/Imgui updated: 21d3299e58...acdaaef625
@@ -47,15 +47,18 @@ namespace Game
|
|||||||
requires EntityConcept<EntityType>
|
requires EntityConcept<EntityType>
|
||||||
EntityType* MakeEntity(EntityManager& manager, float x, float y)
|
EntityType* MakeEntity(EntityManager& manager, float x, float y)
|
||||||
{
|
{
|
||||||
auto* arena = Juliet::GetGameArena();
|
auto* arena = manager.Arena;
|
||||||
EntityType* result = Juliet::ArenaPushType<EntityType>(arena, ConstString("EntityType"));
|
EntityType* result = Juliet::ArenaPushStruct<EntityType>(arena);
|
||||||
Entity* base = result->Base = Juliet::ArenaPushType<Entity>(arena, ConstString("Entity"));
|
Entity base;
|
||||||
base->X = x;
|
base.X = x;
|
||||||
base->Y = y;
|
base.Y = y;
|
||||||
base->Derived = result;
|
base.Derived = result;
|
||||||
base->Kind = EntityType::Kind;
|
base.Kind = EntityType::Kind;
|
||||||
|
manager.Entities.PushBack(base);
|
||||||
|
|
||||||
RegisterEntity(manager, base);
|
result->Base = manager.Entities.Back();
|
||||||
|
|
||||||
|
RegisterEntity(manager, &base);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,16 @@ namespace Game
|
|||||||
|
|
||||||
EntityID EntityManager::ID = 0;
|
EntityID EntityManager::ID = 0;
|
||||||
|
|
||||||
void InitEntityManager() {}
|
void InitEntityManager(Juliet::NonNullPtr<Juliet::Arena> arena)
|
||||||
|
{
|
||||||
|
Manager.Arena = arena.Get();
|
||||||
|
Manager.Entities.Create(arena JULIET_DEBUG_PARAM("Entities"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownEntityManager()
|
||||||
|
{
|
||||||
|
Manager.Entities.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
EntityManager& GetEntityManager()
|
EntityManager& GetEntityManager()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Core/Container/Vector.h>
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
@@ -10,10 +11,14 @@ namespace Game
|
|||||||
struct EntityManager
|
struct EntityManager
|
||||||
{
|
{
|
||||||
static EntityID ID;
|
static EntityID ID;
|
||||||
// May be this should contains the allocator for each entity types
|
|
||||||
|
Juliet::Arena* Arena;
|
||||||
|
// TODO: Should be a pool
|
||||||
|
Juliet::VectorArena<Entity, 1024> Entities;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitEntityManager();
|
void InitEntityManager(Juliet::NonNullPtr<Juliet::Arena> arena);
|
||||||
|
void ShutdownEntityManager();
|
||||||
EntityManager& GetEntityManager();
|
EntityManager& GetEntityManager();
|
||||||
void RegisterEntity(EntityManager& manager, Entity* entity);
|
void RegisterEntity(EntityManager& manager, Entity* entity);
|
||||||
} // namespace Game
|
} // namespace Game
|
||||||
|
|||||||
@@ -257,7 +257,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -317,7 +317,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Juliet\src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Juliet\src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -347,7 +347,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Juliet\src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Juliet\src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -377,7 +377,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Game;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Game;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -407,7 +407,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Game;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\Juliet\include;..\Game;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Game
|
|||||||
|
|
||||||
using namespace Juliet;
|
using namespace Juliet;
|
||||||
|
|
||||||
extern "C" JULIET_API void GameInit(GameInitParams* /*params*/)
|
extern "C" JULIET_API void GameInit(GameInitParams* params)
|
||||||
{
|
{
|
||||||
// Example allocation in GameArena
|
// Example allocation in GameArena
|
||||||
struct GameState
|
struct GameState
|
||||||
@@ -40,7 +40,7 @@ extern "C" JULIET_API void GameInit(GameInitParams* /*params*/)
|
|||||||
int Score;
|
int Score;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* gameState = ArenaPushType<GameState>(GetGameArena(), ConstString("GameState"));
|
auto* gameState = ArenaPushStruct<GameState>(params->GameArena);
|
||||||
gameState->TotalTime = 0.0f;
|
gameState->TotalTime = 0.0f;
|
||||||
gameState->Score = 0;
|
gameState->Score = 0;
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ extern "C" JULIET_API void GameInit(GameInitParams* /*params*/)
|
|||||||
using namespace Game;
|
using namespace Game;
|
||||||
|
|
||||||
// Entity Use case
|
// Entity Use case
|
||||||
InitEntityManager();
|
InitEntityManager(params->GameArena);
|
||||||
auto& manager = GetEntityManager();
|
auto& manager = GetEntityManager();
|
||||||
Door* door = MakeEntity<Door>(manager, 10.0f, 2.0f);
|
Door* door = MakeEntity<Door>(manager, 10.0f, 2.0f);
|
||||||
door->IsOpened = true;
|
door->IsOpened = true;
|
||||||
@@ -69,6 +69,10 @@ extern "C" JULIET_API void GameInit(GameInitParams* /*params*/)
|
|||||||
extern "C" JULIET_API void __cdecl GameShutdown()
|
extern "C" JULIET_API void __cdecl GameShutdown()
|
||||||
{
|
{
|
||||||
printf("Shutting down game...\n");
|
printf("Shutting down game...\n");
|
||||||
|
|
||||||
|
using namespace Game;
|
||||||
|
|
||||||
|
ShutdownEntityManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JULIET_API void __cdecl GameUpdate([[maybe_unused]] float deltaTime)
|
extern "C" JULIET_API void __cdecl GameUpdate([[maybe_unused]] float deltaTime)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.22823.1
|
VisualStudioVersion = 14.0.22823.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
@@ -7,11 +7,6 @@ EndProject
|
|||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Game", "Game\Game.vcxproj", "{B1D040D0-6C94-4F93-BC2A-7F5284B7D434}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Game", "Game\Game.vcxproj", "{B1D040D0-6C94-4F93-BC2A-7F5284B7D434}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JulietApp", "JulietApp\JulietApp.vcxproj", "{1DEE51CA-6C94-4F93-BC2A-7F5284B7D434}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JulietApp", "JulietApp\JulietApp.vcxproj", "{1DEE51CA-6C94-4F93-BC2A-7F5284B7D434}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{AB9C7E88-6C94-4F93-BC2A-7F5284B7D434} = {AB9C7E88-6C94-4F93-BC2A-7F5284B7D434}
|
|
||||||
{C16FFE36-6C94-4F93-BC2A-7F5284B7D434} = {C16FFE36-6C94-4F93-BC2A-7F5284B7D434}
|
|
||||||
{B1D040D0-6C94-4F93-BC2A-7F5284B7D434} = {B1D040D0-6C94-4F93-BC2A-7F5284B7D434}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Juliet", "Juliet\Juliet.vcxproj", "{AB9C7E88-6C94-4F93-BC2A-7F5284B7D434}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Juliet", "Juliet\Juliet.vcxproj", "{AB9C7E88-6C94-4F93-BC2A-7F5284B7D434}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -72,18 +72,21 @@
|
|||||||
<CustomBuild Include="include\Core\HAL\Keyboard\KeyCode.h" />
|
<CustomBuild Include="include\Core\HAL\Keyboard\KeyCode.h" />
|
||||||
<CustomBuild Include="include\Core\HAL\Keyboard\ScanCode.h" />
|
<CustomBuild Include="include\Core\HAL\Keyboard\ScanCode.h" />
|
||||||
<CustomBuild Include="include\Core\HAL\Mouse\Mouse.h" />
|
<CustomBuild Include="include\Core\HAL\Mouse\Mouse.h" />
|
||||||
|
<CustomBuild Include="include\Core\HAL\OS\OS.h" />
|
||||||
<CustomBuild Include="include\Core\HotReload\HotReload.h" />
|
<CustomBuild Include="include\Core\HotReload\HotReload.h" />
|
||||||
<CustomBuild Include="include\Core\ImGui\ImGuiService.h" />
|
<CustomBuild Include="include\Core\ImGui\ImGuiService.h" />
|
||||||
<CustomBuild Include="include\Core\ImGui\ImGuiTests.h" />
|
<CustomBuild Include="include\Core\ImGui\ImGuiTests.h" />
|
||||||
<CustomBuild Include="include\Core\JulietInit.h" />
|
<CustomBuild Include="include\Core\JulietInit.h" />
|
||||||
<CustomBuild Include="include\Core\Logging\LogManager.h" />
|
<CustomBuild Include="include\Core\Logging\LogManager.h" />
|
||||||
<CustomBuild Include="include\Core\Logging\LogTypes.h" />
|
<CustomBuild Include="include\Core\Logging\LogTypes.h" />
|
||||||
|
<CustomBuild Include="include\Core\Main.h" />
|
||||||
<CustomBuild Include="include\Core\Math\MathUtils.h" />
|
<CustomBuild Include="include\Core\Math\MathUtils.h" />
|
||||||
<CustomBuild Include="include\Core\Math\Matrix.h" />
|
<CustomBuild Include="include\Core\Math\Matrix.h" />
|
||||||
<CustomBuild Include="include\Core\Math\Shape.h" />
|
<CustomBuild Include="include\Core\Math\Shape.h" />
|
||||||
<CustomBuild Include="include\Core\Math\Vector.h" />
|
<CustomBuild Include="include\Core\Math\Vector.h" />
|
||||||
<CustomBuild Include="include\Core\Memory\Allocator.h" />
|
<CustomBuild Include="include\Core\Memory\Allocator.h" />
|
||||||
<CustomBuild Include="include\Core\Memory\MemoryArena.h" />
|
<CustomBuild Include="include\Core\Memory\MemoryArena.h" />
|
||||||
|
<CustomBuild Include="include\Core\Memory\MemoryArenaDebug.h" />
|
||||||
<CustomBuild Include="include\Core\Memory\ScratchArena.h" />
|
<CustomBuild Include="include\Core\Memory\ScratchArena.h" />
|
||||||
<CustomBuild Include="include\Core\Memory\Utils.h" />
|
<CustomBuild Include="include\Core\Memory\Utils.h" />
|
||||||
<CustomBuild Include="include\Core\Networking\IPAddress.h" />
|
<CustomBuild Include="include\Core\Networking\IPAddress.h" />
|
||||||
@@ -105,14 +108,17 @@
|
|||||||
<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" />
|
||||||
<CustomBuild Include="src\Core\Common\CoreUtils.cpp" />
|
<CustomBuild Include="src\Core\Common\CoreUtils.cpp" />
|
||||||
<CustomBuild Include="src\Core\Common\String.cpp" />
|
<CustomBuild Include="src\Core\Common\String.cpp" />
|
||||||
|
<CustomBuild Include="src\Core\Container\Vector.cpp" />
|
||||||
<CustomBuild Include="src\Core\HAL\Display\Display.cpp" />
|
<CustomBuild Include="src\Core\HAL\Display\Display.cpp" />
|
||||||
<CustomBuild Include="src\Core\HAL\Display\Display_Private.h" />
|
<CustomBuild Include="src\Core\HAL\Display\Display_Private.h" />
|
||||||
<CustomBuild Include="src\Core\HAL\Display\DisplayDevice.h" />
|
<CustomBuild Include="src\Core\HAL\Display\DisplayDevice.h" />
|
||||||
@@ -140,6 +146,9 @@
|
|||||||
<CustomBuild Include="src\Core\HAL\IO\IOStream.cpp" />
|
<CustomBuild Include="src\Core\HAL\IO\IOStream.cpp" />
|
||||||
<CustomBuild Include="src\Core\HAL\IO\IOStream_Private.h" />
|
<CustomBuild Include="src\Core\HAL\IO\IOStream_Private.h" />
|
||||||
<CustomBuild Include="src\Core\HAL\IO\Win32\Win32IOStream.cpp" />
|
<CustomBuild Include="src\Core\HAL\IO\Win32\Win32IOStream.cpp" />
|
||||||
|
<CustomBuild Include="src\Core\HAL\OS\OS.cpp" />
|
||||||
|
<CustomBuild Include="src\Core\HAL\OS\OS_Private.h" />
|
||||||
|
<CustomBuild Include="src\Core\HAL\OS\Win32\Win32OS.cpp" />
|
||||||
<CustomBuild Include="src\Core\HAL\Win32.h" />
|
<CustomBuild Include="src\Core\HAL\Win32.h" />
|
||||||
<CustomBuild Include="src\Core\HotReload\HotReload.cpp" />
|
<CustomBuild Include="src\Core\HotReload\HotReload.cpp" />
|
||||||
<CustomBuild Include="src\Core\HotReload\Win32\Win32HotReload.cpp" />
|
<CustomBuild Include="src\Core\HotReload\Win32\Win32HotReload.cpp" />
|
||||||
@@ -150,8 +159,8 @@
|
|||||||
<CustomBuild Include="src\Core\Math\Math_Private.h" />
|
<CustomBuild Include="src\Core\Math\Math_Private.h" />
|
||||||
<CustomBuild Include="src\Core\Math\MathRound.cpp" />
|
<CustomBuild Include="src\Core\Math\MathRound.cpp" />
|
||||||
<CustomBuild Include="src\Core\Memory\Allocator.cpp" />
|
<CustomBuild Include="src\Core\Memory\Allocator.cpp" />
|
||||||
<CustomBuild Include="src\Core\Memory\EngineArena.h" />
|
|
||||||
<CustomBuild Include="src\Core\Memory\MemoryArena.cpp" />
|
<CustomBuild Include="src\Core\Memory\MemoryArena.cpp" />
|
||||||
|
<CustomBuild Include="src\Core\Memory\MemoryArenaDebug.cpp" />
|
||||||
<CustomBuild Include="src\Core\Memory\MemoryArenaTests.cpp" />
|
<CustomBuild Include="src\Core\Memory\MemoryArenaTests.cpp" />
|
||||||
<CustomBuild Include="src\Core\Memory\ScratchArena.cpp" />
|
<CustomBuild Include="src\Core\Memory\ScratchArena.cpp" />
|
||||||
<CustomBuild Include="src\Core\Networking\NetworkPacket.cpp" />
|
<CustomBuild Include="src\Core\Networking\NetworkPacket.cpp" />
|
||||||
@@ -213,8 +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\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>
|
||||||
@@ -336,7 +352,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -366,7 +382,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;IMGUI_API=__declspec(dllexport);</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4365 /wd5219 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -396,7 +412,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;include;src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;include;src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
@@ -426,7 +442,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64Clang-Debug|x64'">
|
||||||
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
<NMakeBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache $(ProjectName)-$(Configuration)</NMakeBuildCommandLine>
|
||||||
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
<NMakeReBuildCommandLine>cd $(SolutionDir) & misc\fbuild -ide -dist -monitor -cache -clean $(ProjectName)-$(Configuration)</NMakeReBuildCommandLine>
|
||||||
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
<NMakePreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32_LEAN_AND_MEAN;WIN32;_WIN32;__WINDOWS__;_HAS_EXCEPTIONS=0;WIN64;DEBUG;PROFILING_ENABLED;JULIET_ENABLE_IMGUI;JULIET_DEBUG;JULIET_EXPORT;JULIET_WIN32;</NMakePreprocessorDefinitions>
|
||||||
<NMakeIncludeSearchPath>..\;include;src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
<NMakeIncludeSearchPath>..\;include;src;..\External\imgui;..\External\imgui\backends;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared;</NMakeIncludeSearchPath>
|
||||||
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
<AdditionalOptions>/std:c++20 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 </AdditionalOptions>
|
||||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(SolutionDir)\bin\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||||
|
|||||||
@@ -64,6 +64,9 @@
|
|||||||
<CustomBuild Include="include\Core\HAL\Mouse\Mouse.h">
|
<CustomBuild Include="include\Core\HAL\Mouse\Mouse.h">
|
||||||
<Filter>include\Core\HAL\Mouse</Filter>
|
<Filter>include\Core\HAL\Mouse</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="include\Core\HAL\OS\OS.h">
|
||||||
|
<Filter>include\Core\HAL\OS</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="include\Core\HotReload\HotReload.h">
|
<CustomBuild Include="include\Core\HotReload\HotReload.h">
|
||||||
<Filter>include\Core\HotReload</Filter>
|
<Filter>include\Core\HotReload</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -82,6 +85,9 @@
|
|||||||
<CustomBuild Include="include\Core\Logging\LogTypes.h">
|
<CustomBuild Include="include\Core\Logging\LogTypes.h">
|
||||||
<Filter>include\Core\Logging</Filter>
|
<Filter>include\Core\Logging</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="include\Core\Main.h">
|
||||||
|
<Filter>include\Core</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="include\Core\Math\MathUtils.h">
|
<CustomBuild Include="include\Core\Math\MathUtils.h">
|
||||||
<Filter>include\Core\Math</Filter>
|
<Filter>include\Core\Math</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -100,6 +106,9 @@
|
|||||||
<CustomBuild Include="include\Core\Memory\MemoryArena.h">
|
<CustomBuild Include="include\Core\Memory\MemoryArena.h">
|
||||||
<Filter>include\Core\Memory</Filter>
|
<Filter>include\Core\Memory</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="include\Core\Memory\MemoryArenaDebug.h">
|
||||||
|
<Filter>include\Core\Memory</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="include\Core\Memory\ScratchArena.h">
|
<CustomBuild Include="include\Core\Memory\ScratchArena.h">
|
||||||
<Filter>include\Core\Memory</Filter>
|
<Filter>include\Core\Memory</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -163,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>
|
||||||
@@ -172,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>
|
||||||
@@ -186,6 +201,9 @@
|
|||||||
<CustomBuild Include="src\Core\Common\String.cpp">
|
<CustomBuild Include="src\Core\Common\String.cpp">
|
||||||
<Filter>src\Core\Common</Filter>
|
<Filter>src\Core\Common</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="src\Core\Container\Vector.cpp">
|
||||||
|
<Filter>src\Core\Container</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="src\Core\HAL\Display\Display.cpp">
|
<CustomBuild Include="src\Core\HAL\Display\Display.cpp">
|
||||||
<Filter>src\Core\HAL\Display</Filter>
|
<Filter>src\Core\HAL\Display</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -267,6 +285,15 @@
|
|||||||
<CustomBuild Include="src\Core\HAL\IO\Win32\Win32IOStream.cpp">
|
<CustomBuild Include="src\Core\HAL\IO\Win32\Win32IOStream.cpp">
|
||||||
<Filter>src\Core\HAL\IO\Win32</Filter>
|
<Filter>src\Core\HAL\IO\Win32</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="src\Core\HAL\OS\OS.cpp">
|
||||||
|
<Filter>src\Core\HAL\OS</Filter>
|
||||||
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="src\Core\HAL\OS\OS_Private.h">
|
||||||
|
<Filter>src\Core\HAL\OS</Filter>
|
||||||
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="src\Core\HAL\OS\Win32\Win32OS.cpp">
|
||||||
|
<Filter>src\Core\HAL\OS\Win32</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="src\Core\HAL\Win32.h">
|
<CustomBuild Include="src\Core\HAL\Win32.h">
|
||||||
<Filter>src\Core\HAL</Filter>
|
<Filter>src\Core\HAL</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
@@ -297,10 +324,10 @@
|
|||||||
<CustomBuild Include="src\Core\Memory\Allocator.cpp">
|
<CustomBuild Include="src\Core\Memory\Allocator.cpp">
|
||||||
<Filter>src\Core\Memory</Filter>
|
<Filter>src\Core\Memory</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
<CustomBuild Include="src\Core\Memory\EngineArena.h">
|
<CustomBuild Include="src\Core\Memory\MemoryArena.cpp">
|
||||||
<Filter>src\Core\Memory</Filter>
|
<Filter>src\Core\Memory</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
<CustomBuild Include="src\Core\Memory\MemoryArena.cpp">
|
<CustomBuild Include="src\Core\Memory\MemoryArenaDebug.cpp">
|
||||||
<Filter>src\Core\Memory</Filter>
|
<Filter>src\Core\Memory</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
<CustomBuild Include="src\Core\Memory\MemoryArenaTests.cpp">
|
<CustomBuild Include="src\Core\Memory\MemoryArenaTests.cpp">
|
||||||
@@ -486,6 +513,15 @@
|
|||||||
<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">
|
||||||
|
<Filter>src\UnitTest\Container</Filter>
|
||||||
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="src\UnitTest\RunUnitTests.cpp">
|
||||||
|
<Filter>src\UnitTest</Filter>
|
||||||
|
</CustomBuild>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="include\Core\Application">
|
<Filter Include="include\Core\Application">
|
||||||
@@ -552,6 +588,11 @@
|
|||||||
<UniqueIdentifier>{4c7d6b5f-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{4c7d6b5f-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="include\Core\HAL\OS">
|
||||||
|
<UniqueIdentifier>{8d491e18-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="include\Core\HotReload">
|
<Filter Include="include\Core\HotReload">
|
||||||
<UniqueIdentifier>{fe4e9898-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{fe4e9898-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
@@ -622,6 +663,11 @@
|
|||||||
<UniqueIdentifier>{f763d340-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{f763d340-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="src\Core\Container">
|
||||||
|
<UniqueIdentifier>{3e286bee-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="src\Core\HAL\Display">
|
<Filter Include="src\Core\HAL\Display">
|
||||||
<UniqueIdentifier>{82da0982-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{82da0982-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
@@ -672,6 +718,16 @@
|
|||||||
<UniqueIdentifier>{37523cd5-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{37523cd5-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="src\Core\HAL\OS">
|
||||||
|
<UniqueIdentifier>{d679d621-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="src\Core\HAL\OS\Win32">
|
||||||
|
<UniqueIdentifier>{f6713825-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="src\Core\HotReload">
|
<Filter Include="src\Core\HotReload">
|
||||||
<UniqueIdentifier>{35231af8-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{35231af8-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
@@ -742,4 +798,14 @@
|
|||||||
<UniqueIdentifier>{0fd13bb0-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
<UniqueIdentifier>{0fd13bb0-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="src\UnitTest\Container">
|
||||||
|
<UniqueIdentifier>{3fba0971-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="src\UnitTest">
|
||||||
|
<UniqueIdentifier>{a650fa16-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -8,5 +8,6 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
enum class JulietInit_Flags : uint8;
|
enum class JulietInit_Flags : uint8;
|
||||||
|
|
||||||
|
struct Arena;
|
||||||
extern JULIET_API void StartApplication(IApplication& app, JulietInit_Flags flags);
|
extern JULIET_API void StartApplication(IApplication& app, JulietInit_Flags flags);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
struct RenderPass;
|
struct RenderPass;
|
||||||
@@ -7,12 +9,13 @@ namespace Juliet
|
|||||||
struct Texture;
|
struct Texture;
|
||||||
struct ColorTargetInfo;
|
struct ColorTargetInfo;
|
||||||
struct DepthStencilTargetInfo;
|
struct DepthStencilTargetInfo;
|
||||||
|
struct Arena;
|
||||||
|
|
||||||
class IApplication
|
class IApplication
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IApplication() = default;
|
virtual ~IApplication() = default;
|
||||||
virtual void Init() = 0;
|
virtual void Init(NonNullPtr<Arena> arena) = 0;
|
||||||
virtual void Shutdown() = 0;
|
virtual void Shutdown() = 0;
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
virtual bool IsRunning() = 0;
|
virtual bool IsRunning() = 0;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ using int64 = int64_t;
|
|||||||
using Byte = std::byte;
|
using Byte = std::byte;
|
||||||
|
|
||||||
using size_t = std::size_t;
|
using size_t = std::size_t;
|
||||||
|
using index_t = size_t;
|
||||||
|
|
||||||
struct ByteBuffer
|
struct ByteBuffer
|
||||||
{
|
{
|
||||||
@@ -24,6 +25,8 @@ struct ByteBuffer
|
|||||||
size_t Size;
|
size_t Size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ptrdiff_t = decltype(static_cast<int*>(nullptr) - static_cast<int*>(nullptr));
|
||||||
|
|
||||||
using FunctionPtr = auto (*)(void) -> void;
|
using FunctionPtr = auto (*)(void) -> void;
|
||||||
|
|
||||||
// Limits
|
// Limits
|
||||||
|
|||||||
@@ -4,22 +4,72 @@
|
|||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <bit>
|
||||||
|
#include <cassert>
|
||||||
|
#include <concepts>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#define global static
|
||||||
|
|
||||||
|
// 1. Stringify helpers
|
||||||
|
#define JULIET_STR(x) #x
|
||||||
|
#define JULIET_TOSTRING(x) JULIET_STR(x)
|
||||||
|
|
||||||
|
// 2. Define the pragma operator based on compiler
|
||||||
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
|
#define JULIET_PRAGMA(x) _Pragma(#x)
|
||||||
|
#define JULIET_SUPPRESS_MSVC(id)
|
||||||
|
#define JULIET_SUPPRESS_CLANG(str) JULIET_PRAGMA(clang diagnostic ignored str)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define JULIET_PRAGMA(x) __pragma(x)
|
||||||
|
#define JULIET_SUPPRESS_MSVC(id) JULIET_PRAGMA(warning(disable : id))
|
||||||
|
#define JULIET_SUPPRESS_CLANG(str)
|
||||||
|
#else
|
||||||
|
#define JULIET_PRAGMA(x)
|
||||||
|
#define JULIET_SUPPRESS_MSVC(id)
|
||||||
|
#define JULIET_SUPPRESS_CLANG(str)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 3. The Agnostic "Push/Pop"
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define JULIET_WARNING_PUSH JULIET_PRAGMA(clang diagnostic push)
|
||||||
|
#define JULIET_WARNING_POP JULIET_PRAGMA(clang diagnostic pop)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define JULIET_WARNING_PUSH JULIET_PRAGMA(warning(push))
|
||||||
|
#define JULIET_WARNING_POP JULIET_PRAGMA(warning(pop))
|
||||||
|
#else
|
||||||
|
#define JULIET_WARNING_PUSH
|
||||||
|
#define JULIET_WARNING_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// MSVC specific intrinsic
|
||||||
|
#define JULIET_PLATFORM_BREAK() (__nop(), __debugbreak())
|
||||||
|
#elif defined(__clang__) || defined(__GNUC__)
|
||||||
|
// Clang/GCC specific intrinsic
|
||||||
|
#define JULIET_PLATFORM_BREAK() __builtin_trap()
|
||||||
|
#else
|
||||||
|
#include <signal.h>
|
||||||
|
#define JULIET_PLATFORM_BREAK() raise(SIGTRAP)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
#if JULIET_DEBUG
|
||||||
#define JULIET_ASSERT_INTERNAL(expression, message) \
|
#define JULIET_ASSERT_INTERNAL(expression, message) \
|
||||||
__pragma(warning(push)) __pragma(warning(disable : 4127)) __pragma(warning(disable : 4548)) do \
|
JULIET_WARNING_PUSH \
|
||||||
|
JULIET_SUPPRESS_CLANG("-Wextra-semi-stmt") \
|
||||||
|
JULIET_SUPPRESS_MSVC(4127) \
|
||||||
|
JULIET_SUPPRESS_MSVC(4548) \
|
||||||
{ \
|
{ \
|
||||||
if (!(expression)) \
|
if (!(expression)) [[unlikely]] \
|
||||||
{ \
|
{ \
|
||||||
Juliet::JulietAssert(#expression, message); \
|
Juliet::JulietAssert(#expression, message); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
while (0) \
|
JULIET_WARNING_POP \
|
||||||
__pragma(warning(pop))
|
static_assert(true, "")
|
||||||
|
|
||||||
#define AssertHR(hr_expression, message) \
|
#define AssertHR(hr_expression, message) \
|
||||||
do \
|
do \
|
||||||
@@ -64,6 +114,8 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define Restrict __restrict
|
||||||
|
|
||||||
template <class Function>
|
template <class Function>
|
||||||
class DeferredFunction
|
class DeferredFunction
|
||||||
{
|
{
|
||||||
@@ -100,4 +152,46 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern JULIET_API void Free(ByteBuffer& buffer);
|
extern JULIET_API void Free(ByteBuffer& buffer);
|
||||||
|
|
||||||
|
template <std::integral T>
|
||||||
|
[[nodiscard]] constexpr T AlignPow2(T x, T alignment)
|
||||||
|
{
|
||||||
|
// Safety Check:
|
||||||
|
Assert(std::has_single_bit(static_cast<size_t>(alignment)));
|
||||||
|
|
||||||
|
return (x + alignment - 1) & ~(alignment - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void Swap(T* Restrict a, T* Restrict b)
|
||||||
|
{
|
||||||
|
T temp = std::move(*a);
|
||||||
|
*a = std::move(*b);
|
||||||
|
*b = std::move(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to another file dedicated to those
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define COMPILER_CLANG 1
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define COMPILER_MSVC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Undef anything not defined
|
||||||
|
#if !defined(COMPILER_CLANG)
|
||||||
|
#define COMPILER_CLANG 0
|
||||||
|
#endif
|
||||||
|
#if !defined(COMPILER_MSVC)
|
||||||
|
#define COMPILER_MSVC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if COMPILER_MSVC
|
||||||
|
#define AlignOf(T) __alignof(T)
|
||||||
|
#elif COMPILER_CLANG
|
||||||
|
#define AlignOf(T) __alignof(T)
|
||||||
|
#elif COMPILER_GCC
|
||||||
|
#define AlignOf(T) __alignof__(T)
|
||||||
|
#else
|
||||||
|
#error AlignOf not defined for this compiler.
|
||||||
|
#endif
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OtherType>
|
template <typename OtherType>
|
||||||
@@ -26,13 +26,13 @@ namespace Juliet
|
|||||||
NonNullPtr(const NonNullPtr<OtherType>& otherPtr)
|
NonNullPtr(const NonNullPtr<OtherType>& otherPtr)
|
||||||
: InternalPtr(otherPtr.Get())
|
: InternalPtr(otherPtr.Get())
|
||||||
{
|
{
|
||||||
Assert(InternalPtr && "Fatal Error: Assigned a non null ptr using another NonNullPtr but its was null.");
|
Assert(InternalPtr, "Fatal Error: Assigned a non null ptr using another NonNullPtr but its was null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assignment
|
// Assignment
|
||||||
NonNullPtr& operator=(Type* ptr)
|
NonNullPtr& operator=(Type* ptr)
|
||||||
{
|
{
|
||||||
Assert(ptr && "Tried to assign a null pointer to a NonNullPtr!");
|
Assert(ptr, "Tried to assign a null pointer to a NonNullPtr!");
|
||||||
InternalPtr = ptr;
|
InternalPtr = ptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -48,25 +48,25 @@ namespace Juliet
|
|||||||
// Accessors
|
// Accessors
|
||||||
operator Type*() const
|
operator Type*() const
|
||||||
{
|
{
|
||||||
Assert(InternalPtr && "NonNullPtr: Internal Pointer is Null");
|
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
|
||||||
return InternalPtr;
|
return InternalPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* Get() const
|
Type* Get() const
|
||||||
{
|
{
|
||||||
Assert(InternalPtr && "NonNullPtr: Internal Pointer is Null");
|
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
|
||||||
return InternalPtr;
|
return InternalPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type& operator*() const
|
Type& operator*() const
|
||||||
{
|
{
|
||||||
Assert(InternalPtr && "NonNullPtr: Internal Pointer is Null");
|
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,5 +107,5 @@ namespace Juliet
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
NonNullPtr(T) -> NonNullPtr<T>;
|
NonNullPtr(T*) -> NonNullPtr<T>;
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
#include <Core/Math/MathUtils.h>
|
#include <Core/Math/MathUtils.h>
|
||||||
#include <Core/Memory/Utils.h>
|
#include <Core/Memory/Utils.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
|
struct Arena;
|
||||||
|
|
||||||
#define ConstString(str) { const_cast<char*>((str)), sizeof(str) - 1 }
|
#define ConstString(str) { const_cast<char*>((str)), sizeof(str) - 1 }
|
||||||
#define CStr(str) ((str).Data)
|
#define CStr(str) ((str).Data)
|
||||||
#define InplaceString(name, size) \
|
#define InplaceString(name, size) \
|
||||||
@@ -38,6 +41,20 @@ namespace Juliet
|
|||||||
size_t Capacity;
|
size_t Capacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StringListNode
|
||||||
|
{
|
||||||
|
StringListNode* Next;
|
||||||
|
String Content;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringList
|
||||||
|
{
|
||||||
|
StringListNode* First;
|
||||||
|
StringListNode* Last;
|
||||||
|
size_t NodeCount;
|
||||||
|
size_t Size;
|
||||||
|
};
|
||||||
|
|
||||||
constexpr uint32 kInvalidUTF8 = 0xFFFD;
|
constexpr uint32 kInvalidUTF8 = 0xFFFD;
|
||||||
|
|
||||||
inline size_t StringLength(String str)
|
inline size_t StringLength(String str)
|
||||||
@@ -140,6 +157,7 @@ namespace Juliet
|
|||||||
extern JULIET_API bool ConvertString(StringEncoding from, StringEncoding to, String src, StringBuffer& dst, bool nullTerminate);
|
extern JULIET_API bool ConvertString(StringEncoding from, StringEncoding to, String src, StringBuffer& dst, bool nullTerminate);
|
||||||
extern JULIET_API bool ConvertString(String from, String to, String src, StringBuffer& dst, bool nullTerminate);
|
extern JULIET_API bool ConvertString(String from, String to, String src, StringBuffer& dst, bool nullTerminate);
|
||||||
|
|
||||||
|
JULIET_API String StringCopy(NonNullPtr<Arena> arena, String str);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
|
|||||||
@@ -1,12 +1,240 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
// TODO : Create my own Vector class based on https://github.com/niklas-ourmachinery/bitsquid-foundation/blob/master/collection_types.h
|
template <typename Type, size_t ReserveSize = 16, bool AllowRealloc = false>
|
||||||
template <typename T>
|
struct VectorArena
|
||||||
class Vector : public std::vector<T>
|
|
||||||
{
|
{
|
||||||
|
void Create(JULIET_DEBUG_PARAM_FIRST(const char* name = nullptr))
|
||||||
|
{
|
||||||
|
Assert(!Arena);
|
||||||
|
static_assert(AllowRealloc == false);
|
||||||
|
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
Count = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
Reserve(ReserveSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Create(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* name = nullptr))
|
||||||
|
{
|
||||||
|
Assert(!Arena);
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
|
||||||
|
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
Count = 0;
|
||||||
|
Arena = arena.Get();
|
||||||
|
InternalArena = false;
|
||||||
|
|
||||||
|
Reserve(ReserveSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy()
|
||||||
|
{
|
||||||
|
if (InternalArena)
|
||||||
|
{
|
||||||
|
ArenaRelease(Arena);
|
||||||
|
}
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
Count = 0;
|
||||||
|
Capacity = 0;
|
||||||
|
Arena = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reserve(size_t newCapacity)
|
||||||
|
{
|
||||||
|
if (newCapacity > Capacity)
|
||||||
|
{
|
||||||
|
if (Data == nullptr)
|
||||||
|
{
|
||||||
|
Data = ArenaPushArray<Type>(Arena, newCapacity JULIET_DEBUG_PARAM(Name));
|
||||||
|
}
|
||||||
|
else if constexpr (AllowRealloc)
|
||||||
|
{
|
||||||
|
if (!InternalArena)
|
||||||
|
{
|
||||||
|
DataFirst = Data =
|
||||||
|
static_cast<Type*>(ArenaReallocate(Arena, Data, Capacity * sizeof(Type), newCapacity * sizeof(Type),
|
||||||
|
AlignOf(Type), true JULIET_DEBUG_PARAM("VectorRealloc")));
|
||||||
|
DataLast = Data + Count - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Capacity = newCapacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize(size_t newCount)
|
||||||
|
{
|
||||||
|
if (newCount == Count)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newCount > Capacity)
|
||||||
|
{
|
||||||
|
Reserve(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Count = newCount;
|
||||||
|
|
||||||
|
if (Count > 0)
|
||||||
|
{
|
||||||
|
DataFirst = Data;
|
||||||
|
DataLast = Data + Count - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Assert(Arena);
|
||||||
|
|
||||||
|
if (Count + 1 > Capacity)
|
||||||
|
{
|
||||||
|
Reserve(Capacity == 0 ? ReserveSize : Capacity * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* entry = Data + Count;
|
||||||
|
*entry = value;
|
||||||
|
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
DataFirst = entry;
|
||||||
|
}
|
||||||
|
DataLast = entry;
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushBack(Type&& value)
|
||||||
|
{
|
||||||
|
Assert(Arena);
|
||||||
|
|
||||||
|
if (Count + 1 > Capacity)
|
||||||
|
{
|
||||||
|
Reserve(Capacity == 0 ? ReserveSize : Capacity * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* entry = Data + Count;
|
||||||
|
*entry = std::move(value);
|
||||||
|
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
DataFirst = entry;
|
||||||
|
}
|
||||||
|
DataLast = entry;
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveAtFast(index_t index)
|
||||||
|
{
|
||||||
|
Assert(Arena);
|
||||||
|
Assert(index < Count);
|
||||||
|
Assert(Count > 0);
|
||||||
|
|
||||||
|
Type* elementAdr = DataFirst + index;
|
||||||
|
|
||||||
|
// Swap DataLast and element
|
||||||
|
if (DataLast != elementAdr)
|
||||||
|
{
|
||||||
|
Swap(DataLast, elementAdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
--DataLast;
|
||||||
|
--Count;
|
||||||
|
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
Assert(Arena);
|
||||||
|
|
||||||
|
if (InternalArena)
|
||||||
|
{
|
||||||
|
ArenaClear(Arena);
|
||||||
|
Data = nullptr;
|
||||||
|
Capacity = 0;
|
||||||
|
Reserve(ReserveSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFirst = DataLast = nullptr;
|
||||||
|
Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const { return Count == 0; }
|
||||||
|
|
||||||
|
// C++ Accessors for loop supports and Index based access
|
||||||
|
Type& operator[](size_t index) { return DataFirst[index]; }
|
||||||
|
const Type& operator[](size_t index) const { return DataFirst[index]; }
|
||||||
|
|
||||||
|
Type* begin() { return DataFirst; }
|
||||||
|
Type* end() { return DataFirst + Count; }
|
||||||
|
|
||||||
|
const Type* begin() const { return DataFirst; }
|
||||||
|
const Type* end() const { return DataFirst + Count; }
|
||||||
|
|
||||||
|
Type* First() { return DataFirst; }
|
||||||
|
Type* Front() { return DataFirst; }
|
||||||
|
Type* Last() { return DataLast; }
|
||||||
|
Type* Back() { return DataLast; }
|
||||||
|
|
||||||
|
size_t Size() const { return Count; }
|
||||||
|
|
||||||
|
Arena* Arena;
|
||||||
|
Type* DataFirst;
|
||||||
|
Type* DataLast;
|
||||||
|
Type* Data;
|
||||||
|
size_t Count;
|
||||||
|
size_t Capacity;
|
||||||
|
bool InternalArena : 1;
|
||||||
|
JULIET_DEBUG_ONLY(const char* Name = "VectorArena";)
|
||||||
};
|
};
|
||||||
|
static_assert(std::is_standard_layout_v<VectorArena<int>>,
|
||||||
|
"VectorArena must have a standard layout to remain POD-like.");
|
||||||
|
static_assert(std::is_trivially_copyable_v<VectorArena<int>>,
|
||||||
|
"VectorArena must be trivially copyable (no custom destructors/assignment).");
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/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
|
||||||
|
|||||||
42
Juliet/include/Core/HAL/OS/OS.h
Normal file
42
Juliet/include/Core/HAL/OS/OS.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Graphics/D3D12/D3D12Buffer.h>
|
||||||
|
#include <Juliet.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
Byte* OS_Reserve(size_t size);
|
||||||
|
bool OS_Commit(Byte* ptr, size_t size);
|
||||||
|
void OS_Release(Byte* ptr, size_t size);
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
Type* OS_Reserve(size_t size)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Type*>(OS_Reserve(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
bool OS_Commit(Type* ptr, size_t size)
|
||||||
|
{
|
||||||
|
return OS_Commit(reinterpret_cast<Byte*>(ptr), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void OS_Release(Type* ptr, size_t size)
|
||||||
|
{
|
||||||
|
OS_Release(reinterpret_cast<Byte*>(ptr), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Memory
|
||||||
|
|
||||||
|
namespace Debug
|
||||||
|
{
|
||||||
|
JULIET_API bool IsDebuggerPresent();
|
||||||
|
} // namespace Debug
|
||||||
|
|
||||||
|
using EntryPointFunc = int (*)(int, wchar_t**);
|
||||||
|
JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
|
||||||
|
} // namespace Juliet
|
||||||
@@ -9,6 +9,8 @@ namespace Juliet
|
|||||||
|
|
||||||
struct HotReloadCode
|
struct HotReloadCode
|
||||||
{
|
{
|
||||||
|
Arena* Arena;
|
||||||
|
|
||||||
String DLLFullPath;
|
String DLLFullPath;
|
||||||
String LockFullPath;
|
String LockFullPath;
|
||||||
String TransientDLLName;
|
String TransientDLLName;
|
||||||
@@ -26,8 +28,7 @@ namespace Juliet
|
|||||||
bool IsValid : 1;
|
bool IsValid : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern JULIET_API void InitHotReloadCode(HotReloadCode& code, String dllName,
|
extern JULIET_API void InitHotReloadCode(HotReloadCode& code, String dllName, String transientDllName, String lockFilename);
|
||||||
String transientDllName, String lockFilename);
|
|
||||||
extern JULIET_API void ShutdownHotReloadCode(HotReloadCode& code);
|
extern JULIET_API void ShutdownHotReloadCode(HotReloadCode& code);
|
||||||
|
|
||||||
extern JULIET_API void LoadCode(HotReloadCode& code);
|
extern JULIET_API void LoadCode(HotReloadCode& code);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ namespace Juliet
|
|||||||
All = 0xFb
|
All = 0xFb
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryArena;
|
struct Arena;
|
||||||
|
|
||||||
struct GameInitParams
|
struct GameInitParams
|
||||||
{
|
{
|
||||||
MemoryArena* GameArena;
|
Arena* GameArena;
|
||||||
MemoryArena* ScratchArena;
|
Arena* ScratchArena;
|
||||||
};
|
};
|
||||||
|
|
||||||
void JulietInit(JulietInit_Flags flags);
|
void JulietInit(JulietInit_Flags flags);
|
||||||
|
|||||||
@@ -1,49 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
// TODO : Juliet strings
|
// TODO : Juliet strings
|
||||||
#include <string>
|
|
||||||
// TODO Juliet Containers + Allocators...
|
// TODO Juliet Containers + Allocators...
|
||||||
#include <chrono>
|
// TODO: Juliet chrono, because it prevents me from doing #define global static
|
||||||
#include <deque>
|
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
enum class LogLevel : uint8;
|
enum class LogLevel : uint8;
|
||||||
enum class LogCategory : uint8;
|
enum class LogCategory : uint8;
|
||||||
|
|
||||||
class LogManager final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LogManager();
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
bool GetIsInitialized() const { return IsInitialized; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
std::string Value;
|
|
||||||
std::chrono::system_clock::time_point Time;
|
|
||||||
LogLevel Level;
|
|
||||||
LogCategory Category;
|
|
||||||
|
|
||||||
Entry(std::string& value, LogLevel level, LogCategory category);
|
|
||||||
};
|
|
||||||
std::deque<Entry> Entries;
|
|
||||||
bool IsInitialized : 1;
|
|
||||||
|
|
||||||
friend void Log(LogLevel level, LogCategory category, const char* fmt, va_list args);
|
|
||||||
void AddEntry(Entry&& entry);
|
|
||||||
static void OutputLog(Entry& entry);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void JULIET_API InitializeLogManager();
|
extern void JULIET_API InitializeLogManager();
|
||||||
extern void JULIET_API ShutdownLogManager();
|
extern void JULIET_API ShutdownLogManager();
|
||||||
|
|
||||||
|
extern void JULIET_API LogScopeBegin();
|
||||||
|
// TODO everything that happened in there to export them to file or something
|
||||||
|
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
|
||||||
|
|||||||
46
Juliet/include/Core/Main.h
Normal file
46
Juliet/include/Core/Main.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/HAL/OS/OS.h>
|
||||||
|
|
||||||
|
extern int JulietMain(int, wchar_t**);
|
||||||
|
|
||||||
|
#if JULIET_WIN32
|
||||||
|
#ifndef WINAPI
|
||||||
|
#define WINAPI __stdcall
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UNICODE
|
||||||
|
int wmain(int argc, wchar_t** argv)
|
||||||
|
{
|
||||||
|
return Juliet::Bootstrap(JulietMain, argc, argv);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
return Juliet::Bootstrap(JulietMain, argc, argv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
typedef struct HINSTANCE__* HINSTANCE;
|
||||||
|
typedef char* LPSTR;
|
||||||
|
typedef wchar_t* PWSTR;
|
||||||
|
|
||||||
|
#if UNICODE
|
||||||
|
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrev, PWSTR szCmdLine, int sw)
|
||||||
|
#else
|
||||||
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
(void)hInst;
|
||||||
|
(void)hPrev;
|
||||||
|
(void)szCmdLine;
|
||||||
|
(void)sw;
|
||||||
|
|
||||||
|
return Juliet::Bootstrap(JulietMain, __argc, __wargv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "Only windows main is implemented"
|
||||||
|
#endif
|
||||||
@@ -24,6 +24,18 @@ namespace Juliet
|
|||||||
return lhs < rhs ? rhs : lhs;
|
return lhs < rhs ? rhs : lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
constexpr Type ClampTop(Type value, Type X)
|
||||||
|
{
|
||||||
|
return Min(value, X);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
constexpr Type ClampBottom(Type value, Type X)
|
||||||
|
{
|
||||||
|
return Max(value, X);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
constexpr Type Clamp(Type val, Type min, Type max)
|
constexpr Type Clamp(Type val, Type min, Type max)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ namespace Juliet
|
|||||||
struct Matrix
|
struct Matrix
|
||||||
{
|
{
|
||||||
float m[4][4];
|
float m[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
static Matrix Identity()
|
[[nodiscard]] inline Matrix MatrixIdentity()
|
||||||
{
|
{
|
||||||
Matrix result = {};
|
Matrix result = {};
|
||||||
result.m[0][0] = 1.0f;
|
result.m[0][0] = 1.0f;
|
||||||
@@ -19,7 +20,7 @@ namespace Juliet
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix operator*(const Matrix& rhs) const
|
[[nodiscard]] inline Matrix operator*(const Matrix& lhs, const Matrix& rhs)
|
||||||
{
|
{
|
||||||
Matrix result = {};
|
Matrix result = {};
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
@@ -28,13 +29,78 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
for (int k = 0; k < 4; ++k)
|
for (int k = 0; k < 4; ++k)
|
||||||
{
|
{
|
||||||
result.m[i][j] += m[i][k] * rhs.m[k][j];
|
result.m[i][j] += lhs.m[i][k] * rhs.m[k][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixTranslation(float x, float y, float z)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][3] = x;
|
||||||
|
result.m[1][3] = y;
|
||||||
|
result.m[2][3] = z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixScale(float x, float y, float z)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][0] = x;
|
||||||
|
result.m[1][1] = y;
|
||||||
|
result.m[2][2] = z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotationX(float radians)
|
||||||
|
{
|
||||||
|
float c = cosf(radians);
|
||||||
|
float s = sinf(radians);
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[1][1] = c;
|
||||||
|
result.m[1][2] = -s;
|
||||||
|
result.m[2][1] = s;
|
||||||
|
result.m[2][2] = c;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotationY(float radians)
|
||||||
|
{
|
||||||
|
float c = cosf(radians);
|
||||||
|
float s = sinf(radians);
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][0] = c;
|
||||||
|
result.m[0][2] = s;
|
||||||
|
result.m[2][0] = -s;
|
||||||
|
result.m[2][2] = c;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotationZ(float radians)
|
||||||
|
{
|
||||||
|
float c = cosf(radians);
|
||||||
|
float s = sinf(radians);
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
result.m[0][0] = c;
|
||||||
|
result.m[0][1] = -s;
|
||||||
|
result.m[1][0] = s;
|
||||||
|
result.m[1][1] = c;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MatrixTranslate(Matrix& m, const Vector3& v)
|
||||||
|
{
|
||||||
|
m.m[0][3] += v.x;
|
||||||
|
m.m[1][3] += v.y;
|
||||||
|
m.m[2][3] += v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixRotation(float x, float y, float z)
|
||||||
|
{
|
||||||
|
return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z);
|
||||||
|
}
|
||||||
|
|
||||||
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
|
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
|
||||||
{
|
{
|
||||||
@@ -83,4 +149,46 @@ namespace Juliet
|
|||||||
result.m[3][3] = 0.0f;
|
result.m[3][3] = 0.0f;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline Matrix MatrixInverse(const Matrix& m)
|
||||||
|
{
|
||||||
|
Matrix out = {};
|
||||||
|
|
||||||
|
float m00 = m.m[0][0], m01 = m.m[0][1], m02 = m.m[0][2], m03 = m.m[0][3];
|
||||||
|
float m10 = m.m[1][0], m11 = m.m[1][1], m12 = m.m[1][2], m13 = m.m[1][3];
|
||||||
|
float m20 = m.m[2][0], m21 = m.m[2][1], m22 = m.m[2][2], m23 = m.m[2][3];
|
||||||
|
float m30 = m.m[3][0], m31 = m.m[3][1], m32 = m.m[3][2], m33 = m.m[3][3];
|
||||||
|
|
||||||
|
out.m[0][0] = m11 * m22 * m33 - m11 * m23 * m32 - m21 * m12 * m33 + m21 * m13 * m32 + m31 * m12 * m23 - m31 * m13 * m22;
|
||||||
|
out.m[1][0] = -m10 * m22 * m33 + m10 * m23 * m32 + m20 * m12 * m33 - m20 * m13 * m32 - m30 * m12 * m23 + m30 * m13 * m22;
|
||||||
|
out.m[2][0] = m10 * m21 * m33 - m10 * m23 * m31 - m20 * m11 * m33 + m20 * m13 * m31 + m30 * m11 * m23 - m30 * m13 * m21;
|
||||||
|
out.m[3][0] = -m10 * m21 * m32 + m10 * m22 * m31 + m20 * m11 * m32 - m20 * m12 * m31 - m30 * m11 * m22 + m30 * m12 * m21;
|
||||||
|
|
||||||
|
out.m[0][1] = -m01 * m22 * m33 + m01 * m23 * m32 + m21 * m02 * m33 - m21 * m03 * m32 - m31 * m02 * m23 + m31 * m03 * m22;
|
||||||
|
out.m[1][1] = m00 * m22 * m33 - m00 * m23 * m32 - m20 * m02 * m33 + m20 * m03 * m32 + m30 * m02 * m23 - m30 * m03 * m22;
|
||||||
|
out.m[2][1] = -m00 * m21 * m33 + m00 * m23 * m31 + m20 * m01 * m33 - m20 * m03 * m31 - m30 * m01 * m23 + m30 * m03 * m21;
|
||||||
|
out.m[3][1] = m00 * m21 * m32 - m00 * m22 * m31 - m20 * m01 * m32 + m20 * m02 * m31 + m30 * m01 * m22 - m30 * m02 * m21;
|
||||||
|
|
||||||
|
out.m[0][2] = m01 * m12 * m33 - m01 * m13 * m32 - m11 * m02 * m33 + m11 * m03 * m32 + m31 * m02 * m13 - m31 * m03 * m12;
|
||||||
|
out.m[1][2] = -m00 * m12 * m33 + m00 * m13 * m32 + m10 * m02 * m33 - m10 * m03 * m32 - m30 * m02 * m13 + m30 * m03 * m12;
|
||||||
|
out.m[2][2] = m00 * m11 * m33 - m00 * m13 * m31 - m10 * m01 * m33 + m10 * m03 * m31 + m30 * m01 * m13 - m30 * m03 * m11;
|
||||||
|
out.m[3][2] = -m00 * m11 * m32 + m00 * m12 * m31 + m10 * m01 * m32 - m10 * m02 * m31 - m30 * m01 * m12 + m30 * m02 * m11;
|
||||||
|
|
||||||
|
out.m[0][3] = -m01 * m12 * m23 + m01 * m13 * m22 + m11 * m02 * m23 - m11 * m03 * m22 - m21 * m02 * m13 + m21 * m03 * m12;
|
||||||
|
out.m[1][3] = m00 * m12 * m23 - m00 * m13 * m22 - m10 * m02 * m23 + m10 * m03 * m22 + m20 * m02 * m13 - m20 * m03 * m12;
|
||||||
|
out.m[2][3] = -m00 * m11 * m23 + m00 * m13 * m21 + m10 * m01 * m23 - m10 * m03 * m21 - m20 * m01 * m13 + m20 * m03 * m11;
|
||||||
|
out.m[3][3] = m00 * m11 * m22 - m00 * m12 * m21 - m10 * m01 * m22 + m10 * m02 * m21 + m20 * m01 * m12 - m20 * m02 * m11;
|
||||||
|
|
||||||
|
float det = m00 * out.m[0][0] + m01 * out.m[1][0] + m02 * out.m[2][0] + m03 * out.m[3][0];
|
||||||
|
|
||||||
|
if (det != 0.0f)
|
||||||
|
{
|
||||||
|
float invDet = 1.0f / det;
|
||||||
|
for (int r = 0; r < 4; ++r)
|
||||||
|
for (int c = 0; c < 4; ++c)
|
||||||
|
out.m[r][c] *= invDet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -2,120 +2,102 @@
|
|||||||
|
|
||||||
#include <Core/Common/CoreTypes.h>
|
#include <Core/Common/CoreTypes.h>
|
||||||
#include <Core/Common/CoreUtils.h>
|
#include <Core/Common/CoreUtils.h>
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
#include <Core/Common/String.h>
|
#include <Core/Common/String.h>
|
||||||
#include <Core/Memory/Utils.h>
|
#include <Core/Memory/Utils.h>
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
#include <typeinfo> // Added for typeid
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
|
constexpr global uint64 g_Arena_Default_Reserve_Size = Megabytes(64);
|
||||||
|
constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64);
|
||||||
|
constexpr global uint64 k_ArenaHeaderSize = 128;
|
||||||
|
|
||||||
// --- Paged Memory Architecture ---
|
struct ArenaFreeNode;
|
||||||
struct ArenaAllocation
|
|
||||||
{
|
|
||||||
size_t Offset;
|
|
||||||
size_t Size;
|
|
||||||
String Tag;
|
|
||||||
ArenaAllocation* Next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MemoryBlock
|
|
||||||
{
|
|
||||||
static constexpr uint32 kMagic = 0xAA55AA55;
|
|
||||||
uint32 Magic;
|
|
||||||
MemoryBlock* Next; // Next block in the chain (Arena) or FreeList (Pool)
|
|
||||||
size_t TotalSize; // Total size of this block (including header)
|
|
||||||
size_t Used; // Offset relative to the start of Data
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
#if JULIET_DEBUG
|
||||||
ArenaAllocation* FirstAllocation = nullptr;
|
struct ArenaDebugInfo;
|
||||||
uint64 Pad; // Ensure 16-byte alignment (Size 40 -> 48)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Data follows immediately.
|
struct Arena
|
||||||
// We use a helper to access it to avoid C++ flexible array warning issues if strict
|
{
|
||||||
uint8* GetData() { return reinterpret_cast<uint8*>(this + 1); }
|
Arena* Previous;
|
||||||
const uint8* GetData() const { return reinterpret_cast<const uint8*>(this + 1); }
|
Arena* Current;
|
||||||
|
|
||||||
|
uint64 BasePosition;
|
||||||
|
uint64 Position;
|
||||||
|
uint64 Alignment;
|
||||||
|
|
||||||
|
uint64 CommitSize;
|
||||||
|
uint64 ReserveSize;
|
||||||
|
|
||||||
|
uint64 Committed;
|
||||||
|
uint64 Reserved;
|
||||||
|
|
||||||
|
Arena* FreeBlockLast;
|
||||||
|
|
||||||
|
ArenaFreeNode* FreeNodes;
|
||||||
|
|
||||||
|
bool AllowRealloc : 1;
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(uint16 LostNodeCount;)
|
||||||
|
JULIET_DEBUG_ONLY(bool CanReserveMore : 1;)
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(Arena* GlobalNext;)
|
||||||
|
JULIET_DEBUG_ONLY(Arena* GlobalPrev;)
|
||||||
|
JULIET_DEBUG_ONLY(ArenaDebugInfo* FirstDebugInfo;)
|
||||||
|
JULIET_DEBUG_ONLY(const char* Name;)
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Arena) <= k_ArenaHeaderSize);
|
||||||
|
|
||||||
|
struct TempArena
|
||||||
|
{
|
||||||
|
Arena* Arena;
|
||||||
|
index_t Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryPool
|
struct ArenaParams
|
||||||
{
|
{
|
||||||
void* BaseAddress = nullptr;
|
uint64 ReserveSize = g_Arena_Default_Reserve_Size;
|
||||||
size_t TotalSize = 0;
|
uint64 CommitSize = g_Arena_Default_Commit_Size;
|
||||||
MemoryBlock* FreeList = nullptr;
|
|
||||||
|
|
||||||
[[nodiscard]] MemoryBlock* AllocateBlock(size_t minCapacity);
|
// True: All push will be 32 bytes minimum
|
||||||
void FreeBlock(MemoryBlock* block);
|
bool AllowRealloc = false;
|
||||||
|
|
||||||
|
// When false, will assert if a new block is reserved.
|
||||||
|
JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryArena
|
[[nodiscard]] JULIET_API Arena* ArenaAllocate(const ArenaParams& params JULIET_DEBUG_ONLY(, const char* name),
|
||||||
|
const std::source_location& loc = std::source_location::current());
|
||||||
|
JULIET_API void ArenaRelease(NonNullPtr<Arena> arena);
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||||
|
[[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));
|
||||||
|
JULIET_API void ArenaPopTo(NonNullPtr<Arena> arena, size_t position);
|
||||||
|
JULIET_API void ArenaPop(NonNullPtr<Arena> arena, size_t amount);
|
||||||
|
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
||||||
|
[[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr<Arena> arena);
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* tag = nullptr))
|
||||||
{
|
{
|
||||||
MemoryPool* BackingPool;
|
return static_cast<Type*>(
|
||||||
MemoryBlock* CurrentBlock;
|
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_PARAM(tag ? tag : typeid(Type).name())));
|
||||||
MemoryBlock* FirstBlock;
|
|
||||||
// Marker behavior is now tricky with pages.
|
|
||||||
// Simple Marker = { Block*, Offset }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ArenaMarker
|
|
||||||
{
|
|
||||||
MemoryBlock* Block;
|
|
||||||
size_t Offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
JULIET_API void MemoryArenaCreate(MemoryArena* arena, MemoryPool* pool);
|
|
||||||
JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, String tag);
|
|
||||||
JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, String tag);
|
|
||||||
JULIET_API bool ArenaPop(MemoryArena* arena, void* ptr, size_t size);
|
|
||||||
JULIET_API void ArenaReset(MemoryArena* arena);
|
|
||||||
JULIET_API ArenaMarker ArenaGetMarker(MemoryArena* arena);
|
|
||||||
JULIET_API void ArenaResetToMarker(MemoryArena* arena, ArenaMarker marker);
|
|
||||||
|
|
||||||
// --- Global Arenas & Management ---
|
|
||||||
|
|
||||||
// Returns a global arena that resets every frame.
|
|
||||||
JULIET_API MemoryArena* GetScratchArena();
|
|
||||||
|
|
||||||
// Persistent game arena.
|
|
||||||
JULIET_API MemoryArena* GetGameArena();
|
|
||||||
|
|
||||||
// Internal engine function to reset the scratch arena.
|
|
||||||
JULIET_API void ScratchArenaReset();
|
|
||||||
|
|
||||||
// Internal engine function to initialize memory arenas.
|
|
||||||
void MemoryArenasInit();
|
|
||||||
|
|
||||||
// Internal engine function to shutdown memory arenas.
|
|
||||||
void MemoryArenasShutdown();
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline T* ArenaPushType(MemoryArena* arena, String tag)
|
|
||||||
{
|
|
||||||
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T), alignof(T), tag));
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
MemSet(result, 0, sizeof(T));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename Type>
|
||||||
inline T* ArenaPushArray(MemoryArena* arena, size_t count, String tag)
|
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count JULIET_DEBUG_PARAM(const char* tag = nullptr))
|
||||||
{
|
{
|
||||||
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T) * count, alignof(T), tag));
|
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)),
|
||||||
|
true JULIET_DEBUG_PARAM(tag ? tag : typeid(Type).name())));
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
MemSet(result, 0, sizeof(T) * count);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
TempArena ArenaTempBegin(NonNullPtr<Arena> arena);
|
||||||
inline T* ArenaRealloc(MemoryArena* arena, T* oldPtr, size_t oldCount, size_t newCount, String tag)
|
void ArenaTempEnd(TempArena temp);
|
||||||
{
|
|
||||||
return static_cast<T*>(Juliet::ArenaRealloc(arena, static_cast<void*>(oldPtr), sizeof(T) * oldCount,
|
|
||||||
sizeof(T) * newCount, alignof(T), tag));
|
|
||||||
}
|
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
50
Juliet/include/Core/Memory/MemoryArenaDebug.h
Normal file
50
Juliet/include/Core/Memory/MemoryArenaDebug.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Juliet.h>
|
||||||
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Core/Common/String.h>
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
struct Arena;
|
||||||
|
struct MemoryBlock;
|
||||||
|
|
||||||
|
// Arena (Struct)
|
||||||
|
struct ArenaDebugInfo
|
||||||
|
{
|
||||||
|
const char* Tag;
|
||||||
|
size_t Offset;
|
||||||
|
size_t Size;
|
||||||
|
ArenaDebugInfo* Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// MemoryArena (Pool-based)
|
||||||
|
struct ArenaAllocation
|
||||||
|
{
|
||||||
|
size_t Offset;
|
||||||
|
size_t Size;
|
||||||
|
String Tag;
|
||||||
|
ArenaAllocation* Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Arena (Struct)
|
||||||
|
void DebugRegisterArena(NonNullPtr<Arena> arena);
|
||||||
|
void DebugUnregisterArena(NonNullPtr<Arena> arena);
|
||||||
|
void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name);
|
||||||
|
bool IsDebugInfoArena(const Arena* arena); // To prevent recursion
|
||||||
|
void DebugArenaFreeBlock(Arena* block); // To clear all debug infos in a block
|
||||||
|
void DebugArenaRemoveAllocation(Arena* block, size_t oldOffset);
|
||||||
|
void DebugArenaPopTo(Arena* block, size_t newPosition);
|
||||||
|
void DebugArenaAddDebugInfo(Arena* block, size_t size, size_t offset, const char* tag);
|
||||||
|
|
||||||
|
// MemoryArena (Pool-based)
|
||||||
|
void DebugFreeArenaAllocations(MemoryBlock* blk);
|
||||||
|
void DebugArenaAddAllocation(MemoryBlock* blk, size_t size, size_t offset, String tag);
|
||||||
|
void DebugArenaRemoveLastAllocation(MemoryBlock* blk);
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,7 +19,71 @@ namespace Juliet
|
|||||||
return size ? *left - *right : 0;
|
return size ? *left - *right : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: homemade versions
|
// Single linked list
|
||||||
|
void SingleLinkedListPushNext(auto*& stackTop, auto* node)
|
||||||
|
{
|
||||||
|
node->Next = stackTop;
|
||||||
|
stackTop = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleLinkedListPushPrevious(auto*& stackTop, auto* node)
|
||||||
|
{
|
||||||
|
node->Previous = stackTop;
|
||||||
|
stackTop = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleLinkedListPopNext(auto*& stackTop)
|
||||||
|
{
|
||||||
|
stackTop = stackTop->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename SingleLinkedListType>
|
||||||
|
struct SingleLinkedListNode
|
||||||
|
{
|
||||||
|
SingleLinkedListType* Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Double linked list
|
||||||
|
template <typename QueueType, typename QueueTypeNode>
|
||||||
|
void Enqueue(QueueType& queue, QueueTypeNode* node)
|
||||||
|
{
|
||||||
|
if (queue.First == nullptr)
|
||||||
|
{
|
||||||
|
queue.First = queue.Last = node;
|
||||||
|
node->Next = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queue.Last->Next = node, queue.Last = node;
|
||||||
|
node->Next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.Nodecount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QueueType>
|
||||||
|
struct QueueNode
|
||||||
|
{
|
||||||
|
QueueType* Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DECLARE_QUEUE(type) \
|
||||||
|
struct type##Queue \
|
||||||
|
{ \
|
||||||
|
type* First; \
|
||||||
|
type* Last; \
|
||||||
|
size_t Nodecount; \
|
||||||
|
size_t Size; \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SLLQueuePush(f, l, n) SLLQueuePush_NZ(0, f, l, n, next)
|
||||||
|
|
||||||
|
#define SLLQueuePush_NZ(nil, f, l, n, next) \
|
||||||
|
(CheckNil(nil, f) ? ((f) = (l) = (n), SetNil(nil, (n)->next)) : ((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
|
||||||
|
|
||||||
|
// TODO: homemade versions
|
||||||
#define MemSet memset
|
#define MemSet memset
|
||||||
#define MemCopy memcpy
|
#define MemCopy memcpy
|
||||||
|
|
||||||
|
#define MemoryZero(dst, size) MemSet(dst, 0, size)
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
|
// TODO Use VectorArena
|
||||||
|
template <typename T>
|
||||||
|
class Vector : public std::vector<T>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
class NetworkPacket
|
class NetworkPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Memory/MemoryArena.h>
|
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
|
||||||
namespace Juliet::Debug
|
namespace Juliet::Debug
|
||||||
{
|
{
|
||||||
JULIET_API void DebugDrawMemoryArena();
|
JULIET_API void DebugDrawMemoryArena();
|
||||||
} // namespace Juliet::Debug
|
} // namespace Juliet::Debug
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Juliet
|
|||||||
struct Engine
|
struct Engine
|
||||||
{
|
{
|
||||||
IApplication* Application = nullptr;
|
IApplication* Application = nullptr;
|
||||||
|
Arena* PlatformArena = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitializeEngine(JulietInit_Flags flags);
|
void InitializeEngine(JulietInit_Flags flags);
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -21,8 +21,14 @@
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define JULIET_DEBUG 1
|
#define JULIET_DEBUG 1
|
||||||
|
#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_PARAM_FIRST(...)
|
||||||
|
#define JULIET_DEBUG_PARAM(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Manual override to disable ImGui
|
// Manual override to disable ImGui
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ namespace Juliet
|
|||||||
Log(LogLevel::Error, LogCategory::Core, "--- ASSERTION FAILED ---");
|
Log(LogLevel::Error, LogCategory::Core, "--- ASSERTION FAILED ---");
|
||||||
Log(LogLevel::Error, LogCategory::Core, "Expression: %s", expression);
|
Log(LogLevel::Error, LogCategory::Core, "Expression: %s", expression);
|
||||||
Log(LogLevel::Error, LogCategory::Core, "Message: %s", message);
|
Log(LogLevel::Error, LogCategory::Core, "Message: %s", message);
|
||||||
Log(LogLevel::Error, LogCategory::Core, "Location: %s(%u): %s",
|
Log(LogLevel::Error, LogCategory::Core, "Location: %s(%u): %s", location.file_name(), location.line(),
|
||||||
location.file_name(),
|
|
||||||
location.line(),
|
|
||||||
location.function_name());
|
location.function_name());
|
||||||
|
|
||||||
if (handleResult < 0)
|
if (handleResult < 0)
|
||||||
@@ -26,14 +24,7 @@ namespace Juliet
|
|||||||
|
|
||||||
Log(LogLevel::Error, LogCategory::Core, "-------------------------");
|
Log(LogLevel::Error, LogCategory::Core, "-------------------------");
|
||||||
|
|
||||||
if (IsDebuggerPresent())
|
JULIET_PLATFORM_BREAK();
|
||||||
{
|
|
||||||
__debugbreak();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Free(ByteBuffer& buffer)
|
void Free(ByteBuffer& buffer)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <Core/Common/String.h>
|
#include <Core/Common/String.h>
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <Core/Memory/Utils.h>
|
#include <Core/Memory/Utils.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -487,4 +488,15 @@ namespace Juliet
|
|||||||
|
|
||||||
return ConvertString(sourceFormat, destFormat, src, dst, nullTerminate);
|
return ConvertString(sourceFormat, destFormat, src, dst, nullTerminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String StringCopy(NonNullPtr<Arena> arena, String str)
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
result.Size = str.Size;
|
||||||
|
result.Data = static_cast<char*>(ArenaPush(arena, str.Size + 1, alignof(char), true JULIET_DEBUG_ONLY(, "String")));
|
||||||
|
MemCopy(result.Data, str.Data, str.Size);
|
||||||
|
result.Data[result.Size] = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
5
Juliet/src/Core/Container/Vector.cpp
Normal file
5
Juliet/src/Core/Container/Vector.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include <Core/Container/Vector.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -2,16 +2,16 @@
|
|||||||
#include <Core/HAL/Display/Display_Private.h>
|
#include <Core/HAL/Display/Display_Private.h>
|
||||||
#include <Core/HAL/Display/DisplayDevice.h>
|
#include <Core/HAL/Display/DisplayDevice.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
#include <Core/Memory/Allocator.h>
|
||||||
#include <Core/Memory/EngineArena.h>
|
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <format>
|
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
DisplayDevice* g_CurrentDisplayDevice = nullptr;
|
DisplayDevice* g_CurrentDisplayDevice = nullptr;
|
||||||
}
|
|
||||||
|
void DestroyPlatformWindow(index_t windowIndex);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace Internal::Display
|
namespace Internal::Display
|
||||||
{
|
{
|
||||||
@@ -23,13 +23,15 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(!g_CurrentDisplayDevice);
|
Assert(!g_CurrentDisplayDevice);
|
||||||
|
|
||||||
|
Arena* arena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Display System"));
|
||||||
|
|
||||||
DisplayDevice* candidateDevice = nullptr;
|
DisplayDevice* candidateDevice = nullptr;
|
||||||
DisplayDeviceFactory* candidateFactory = nullptr;
|
DisplayDeviceFactory* candidateFactory = nullptr;
|
||||||
for (DisplayDeviceFactory* factory : Internal::Display::Factories)
|
for (DisplayDeviceFactory* factory : Internal::Display::Factories)
|
||||||
{
|
{
|
||||||
if (factory)
|
if (factory)
|
||||||
{
|
{
|
||||||
candidateDevice = factory->CreateDevice();
|
candidateDevice = factory->CreateDevice(arena);
|
||||||
if (candidateDevice)
|
if (candidateDevice)
|
||||||
{
|
{
|
||||||
candidateFactory = factory;
|
candidateFactory = factory;
|
||||||
@@ -42,6 +44,7 @@ namespace Juliet
|
|||||||
Assert(candidateDevice);
|
Assert(candidateDevice);
|
||||||
|
|
||||||
g_CurrentDisplayDevice = candidateDevice;
|
g_CurrentDisplayDevice = candidateDevice;
|
||||||
|
g_CurrentDisplayDevice->Arena = arena;
|
||||||
g_CurrentDisplayDevice->Name = candidateFactory->Name;
|
g_CurrentDisplayDevice->Name = candidateFactory->Name;
|
||||||
|
|
||||||
if (!g_CurrentDisplayDevice->Initialize(g_CurrentDisplayDevice))
|
if (!g_CurrentDisplayDevice->Initialize(g_CurrentDisplayDevice))
|
||||||
@@ -58,15 +61,17 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroy all Windows that are still alive
|
// Destroy all Windows that are still alive
|
||||||
if (g_CurrentDisplayDevice->MainWindow)
|
for (index_t idx = g_CurrentDisplayDevice->Windows.Size(); idx-- > 0;)
|
||||||
{
|
{
|
||||||
DestroyPlatformWindow(g_CurrentDisplayDevice->MainWindow);
|
DestroyPlatformWindow(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_CurrentDisplayDevice->Shutdown(g_CurrentDisplayDevice);
|
g_CurrentDisplayDevice->Shutdown(g_CurrentDisplayDevice);
|
||||||
// Free anything that was freed by the shutdown and then free the display
|
// Free anything that was freed by the shutdown and then free the display
|
||||||
// no op for now
|
// no op for now
|
||||||
g_CurrentDisplayDevice->Free(g_CurrentDisplayDevice);
|
g_CurrentDisplayDevice->Free(g_CurrentDisplayDevice);
|
||||||
|
|
||||||
|
ArenaRelease(g_CurrentDisplayDevice->Arena);
|
||||||
g_CurrentDisplayDevice = nullptr;
|
g_CurrentDisplayDevice = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,49 +79,59 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(g_CurrentDisplayDevice->CreatePlatformWindow);
|
Assert(g_CurrentDisplayDevice->CreatePlatformWindow);
|
||||||
|
|
||||||
MemoryArena* arena = GetEngineArena();
|
Window window = {};
|
||||||
auto window = ArenaPushType<Window>(arena, ConstString("Window"));
|
window.Arena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Window"));
|
||||||
if (!window)
|
window.Width = width;
|
||||||
|
window.Height = height;
|
||||||
|
|
||||||
|
window.Title = StringCopy(window.Arena, WrapString(title));
|
||||||
|
|
||||||
|
g_CurrentDisplayDevice->Windows.PushBack(window);
|
||||||
|
|
||||||
|
auto* pWindow = g_CurrentDisplayDevice->Windows.Last();
|
||||||
|
if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, pWindow))
|
||||||
{
|
{
|
||||||
return nullptr;
|
ArenaRelease(window.Arena);
|
||||||
}
|
|
||||||
window->Width = width;
|
|
||||||
window->Height = height;
|
|
||||||
|
|
||||||
auto titleLen = StringLength(title);
|
|
||||||
auto buffer = ArenaPushArray<char>(arena, titleLen, ConstString("Window Title Array"));
|
|
||||||
MemCopy(buffer, title, titleLen);
|
|
||||||
|
|
||||||
window->Title.Data = buffer;
|
|
||||||
window->Title.Size = titleLen;
|
|
||||||
|
|
||||||
g_CurrentDisplayDevice->MainWindow = window;
|
|
||||||
if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, window))
|
|
||||||
{
|
|
||||||
// Note: We don't "free" from arena easily, but since this is catastrophic
|
|
||||||
// and persistent, we just leak the small amount of arena space or handle it if we had a marker.
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : make SHOW optional on creation with a flag
|
// TODO : make SHOW optional on creation with a flag
|
||||||
g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, window);
|
g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, pWindow);
|
||||||
|
|
||||||
return window;
|
return pWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyPlatformWindow(NonNullPtr<Window> window)
|
namespace
|
||||||
{
|
{
|
||||||
Assert(g_CurrentDisplayDevice->MainWindow == window.Get());
|
void DestroyPlatformWindow(index_t windowIndex)
|
||||||
|
{
|
||||||
|
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
|
||||||
|
Window* window = &windows[windowIndex];
|
||||||
|
|
||||||
HideWindow(window);
|
HideWindow(window);
|
||||||
|
|
||||||
// We don't free from arena, these are persistent until shutdown.
|
|
||||||
window->Title.Data = nullptr;
|
|
||||||
window->Title.Size = 0;
|
|
||||||
|
|
||||||
g_CurrentDisplayDevice->DestroyPlatformWindow(g_CurrentDisplayDevice, window);
|
g_CurrentDisplayDevice->DestroyPlatformWindow(g_CurrentDisplayDevice, window);
|
||||||
|
|
||||||
g_CurrentDisplayDevice->MainWindow = nullptr;
|
ArenaClear(window->Arena);
|
||||||
|
ArenaRelease(window->Arena);
|
||||||
|
|
||||||
|
windows.RemoveAtFast(windowIndex);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void DestroyPlatformWindow(NonNullPtr<Window> window)
|
||||||
|
{
|
||||||
|
// Find and destroy
|
||||||
|
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
|
||||||
|
for (index_t idx = windows.Size(); idx-- > 0;)
|
||||||
|
{
|
||||||
|
Window& windowRef = windows[idx];
|
||||||
|
if (windowRef.ID == window->ID)
|
||||||
|
{
|
||||||
|
DestroyPlatformWindow(idx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowWindow(NonNullPtr<Window> window)
|
void ShowWindow(NonNullPtr<Window> window)
|
||||||
@@ -134,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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Container/Vector.h>
|
||||||
#include <Core/HAL/Display/Window.h>
|
#include <Core/HAL/Display/Window.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -10,6 +11,8 @@ namespace Juliet
|
|||||||
// Acts as a singleton after Initialize has been called and is freed in Shutdown.
|
// Acts as a singleton after Initialize has been called and is freed in Shutdown.
|
||||||
struct DisplayDevice
|
struct DisplayDevice
|
||||||
{
|
{
|
||||||
|
Arena* Arena;
|
||||||
|
|
||||||
const char* Name = "Unknown";
|
const char* Name = "Unknown";
|
||||||
|
|
||||||
// Initialize all subsystems needed for the device to works
|
// Initialize all subsystems needed for the device to works
|
||||||
@@ -22,18 +25,18 @@ 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);
|
||||||
|
|
||||||
// TODO : Use vector
|
VectorArena<Window> Windows;
|
||||||
Window* MainWindow = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DisplayDeviceFactory
|
struct DisplayDeviceFactory
|
||||||
{
|
{
|
||||||
const char* Name = "Unknown";
|
const char* Name = "Unknown";
|
||||||
DisplayDevice* (*CreateDevice)(void);
|
DisplayDevice* (*CreateDevice)(Arena* arena);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO : Support more platforms
|
// TODO : Support more platforms
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#include <Core/HAL/Display/DisplayDevice.h>
|
#include <Core/HAL/Display/DisplayDevice.h>
|
||||||
#include <Core/HAL/Display/Win32/Win32DisplayEvent.h>
|
#include <Core/HAL/Display/Win32/Win32DisplayEvent.h>
|
||||||
#include <Core/HAL/Display/Win32/Win32Window.h>
|
#include <Core/HAL/Display/Win32/Win32Window.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
|
||||||
#include <Core/Memory/EngineArena.h>
|
|
||||||
#include <Core/Memory/Utils.h>
|
|
||||||
|
|
||||||
namespace Juliet::Win32
|
namespace Juliet::Win32
|
||||||
{
|
{
|
||||||
@@ -14,11 +11,14 @@ namespace Juliet::Win32
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void Shutdown(NonNullPtr<DisplayDevice> /*self*/) {}
|
void Shutdown(NonNullPtr<DisplayDevice> /*self*/) {}
|
||||||
void Free(NonNullPtr<DisplayDevice> /*self*/) {}
|
void Free(NonNullPtr<DisplayDevice> device)
|
||||||
|
|
||||||
DisplayDevice* CreateDevice()
|
|
||||||
{
|
{
|
||||||
auto device = ArenaPushType<DisplayDevice>(GetEngineArena(), ConstString("DisplayDevice"));
|
device->Windows.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayDevice* CreateDevice(Arena* arena)
|
||||||
|
{
|
||||||
|
auto device = ArenaPushStruct<DisplayDevice>(arena);
|
||||||
|
|
||||||
if (!device)
|
if (!device)
|
||||||
{
|
{
|
||||||
@@ -33,9 +33,12 @@ 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(arena JULIET_DEBUG_PARAM("Display Windows"));
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -14,9 +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
|
||||||
{
|
{
|
||||||
@@ -29,20 +30,15 @@ namespace Juliet::Win32
|
|||||||
{
|
{
|
||||||
if (auto* displayDevice = GetDisplayDevice())
|
if (auto* displayDevice = GetDisplayDevice())
|
||||||
{
|
{
|
||||||
auto* window = displayDevice->MainWindow;
|
for (auto& window : displayDevice->Windows)
|
||||||
// TODO : use a vector
|
|
||||||
// for (Window* window : displayDevice->MainWindow)
|
|
||||||
{
|
{
|
||||||
if (window)
|
auto state = static_cast<Window32State*>(window.State);
|
||||||
{
|
|
||||||
auto state = static_cast<Window32State*>(window->State);
|
|
||||||
if (state && state->Handle == handle)
|
if (state && state->Handle == handle)
|
||||||
{
|
{
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -151,14 +147,15 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
// Wait until the window state is created before doing anything
|
// Wait until the window state is created before doing anything
|
||||||
auto* windowState = GetWindowStateFromHandle(handle);
|
auto* windowState = GetWindowStateFromHandle(handle);
|
||||||
if (!windowState)
|
if (!windowState)
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
#include <Core/HAL/Display/Win32/Win32Window.h>
|
#include <Core/HAL/Display/Win32/Win32Window.h>
|
||||||
#include <Core/HAL/Display/Window.h>
|
#include <Core/HAL/Display/Window.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
#include <Core/Memory/Allocator.h>
|
||||||
#include <Core/Memory/EngineArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <Core/Memory/Utils.h>
|
|
||||||
|
|
||||||
namespace Juliet::Win32
|
namespace Juliet::Win32
|
||||||
{
|
{
|
||||||
@@ -14,7 +13,7 @@ namespace Juliet::Win32
|
|||||||
|
|
||||||
bool SetupWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window, HWND handle)
|
bool SetupWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window, HWND handle)
|
||||||
{
|
{
|
||||||
auto state = ArenaPushType<Window32State>(GetEngineArena(), ConstString("Window32State"));
|
auto* state = ArenaPushStruct<Window32State>(window->Arena);
|
||||||
|
|
||||||
window->State = state;
|
window->State = state;
|
||||||
state->Handle = handle;
|
state->Handle = handle;
|
||||||
@@ -23,18 +22,15 @@ namespace Juliet::Win32
|
|||||||
|
|
||||||
state->IsMouseTracked = false;
|
state->IsMouseTracked = false;
|
||||||
|
|
||||||
// TODO Use SetProp to associate data to the window handle. Could be used to fetch it from the WinProc
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CleanUpWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window)
|
void CleanUpWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window)
|
||||||
{
|
{
|
||||||
if (auto* state = static_cast<Window32State*>(window->State))
|
auto* state = static_cast<Window32State*>(window->State);
|
||||||
{
|
Assert(state);
|
||||||
ReleaseDC(state->Handle, state->HDC);
|
ReleaseDC(state->Handle, state->HDC);
|
||||||
DestroyWindow(state->Handle);
|
DestroyWindow(state->Handle);
|
||||||
}
|
|
||||||
window->State = nullptr;
|
window->State = nullptr;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -63,8 +59,8 @@ namespace Juliet::Win32
|
|||||||
|
|
||||||
int x = CW_USEDEFAULT, y = CW_USEDEFAULT;
|
int x = CW_USEDEFAULT, y = CW_USEDEFAULT;
|
||||||
const int w = window->Width, h = window->Height;
|
const int w = window->Width, h = window->Height;
|
||||||
HWND handle = CreateWindowExA(styleEx, WindowClassPtr, "JULIET TODO PASS TITLE", style, x, y, w, h, nullptr,
|
HWND handle = CreateWindowExA(styleEx, WindowClassPtr, window->Title.Data, style, x, y, w, h, nullptr, nullptr,
|
||||||
nullptr, instance, nullptr);
|
instance, nullptr);
|
||||||
|
|
||||||
PumpEvents(self);
|
PumpEvents(self);
|
||||||
|
|
||||||
@@ -96,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
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
WindowID ID;
|
WindowID ID;
|
||||||
WindowState* State;
|
WindowState* State;
|
||||||
|
Arena* Arena;
|
||||||
|
|
||||||
int32 Width;
|
int32 Width;
|
||||||
int32 Height;
|
int32 Height;
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
#include <chrono>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include <Core/HAL/Display/DisplayDevice.h>
|
#include <Core/HAL/Display/DisplayDevice.h>
|
||||||
#include <Core/HAL/Event/SystemEvent.h>
|
#include <Core/HAL/Event/SystemEvent.h>
|
||||||
|
|
||||||
|
#pragma push_macro("global")
|
||||||
|
#undef global
|
||||||
|
#include <chrono>
|
||||||
|
#pragma pop_macro("global")
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
37
Juliet/src/Core/HAL/OS/OS.cpp
Normal file
37
Juliet/src/Core/HAL/OS/OS.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include <Core/HAL/OS/OS.h>
|
||||||
|
#include <Core/HAL/OS/OS_Private.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
Byte* OS_Reserve(size_t size)
|
||||||
|
{
|
||||||
|
return Internal::OS_Reserve(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OS_Commit(Byte* ptr, size_t size)
|
||||||
|
{
|
||||||
|
return Internal::OS_Commit(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OS_Release(Byte* ptr, size_t size)
|
||||||
|
{
|
||||||
|
Internal::OS_Release(ptr, size);
|
||||||
|
}
|
||||||
|
} // namespace Memory
|
||||||
|
|
||||||
|
namespace Debug
|
||||||
|
{
|
||||||
|
bool IsDebuggerPresent()
|
||||||
|
{
|
||||||
|
return Internal::IsDebuggerPresent();
|
||||||
|
}
|
||||||
|
} // namespace Debug
|
||||||
|
|
||||||
|
int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv)
|
||||||
|
{
|
||||||
|
return Internal::OS_Main(entryPointFunc, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
20
Juliet/src/Core/HAL/OS/OS_Private.h
Normal file
20
Juliet/src/Core/HAL/OS/OS_Private.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
namespace Memory::Internal
|
||||||
|
{
|
||||||
|
Byte* OS_Reserve(size_t size);
|
||||||
|
bool OS_Commit(Byte* ptr, size_t size);
|
||||||
|
void OS_Release(Byte* ptr, size_t size);
|
||||||
|
} // namespace Memory::Internal
|
||||||
|
|
||||||
|
namespace Debug::Internal
|
||||||
|
{
|
||||||
|
bool IsDebuggerPresent();
|
||||||
|
} // namespace Debug::Internal
|
||||||
|
namespace Internal
|
||||||
|
{
|
||||||
|
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
|
||||||
|
}
|
||||||
|
} // namespace Juliet
|
||||||
97
Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp
Normal file
97
Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include <Core/Common/CoreTypes.h>
|
||||||
|
#include <Core/Common/CoreUtils.h>
|
||||||
|
#include <Core/HAL/OS/OS.h>
|
||||||
|
#include <Core/HAL/OS/OS_Private.h>
|
||||||
|
#include <Core/HAL/Win32.h>
|
||||||
|
#include <Core/Logging/LogManager.h>
|
||||||
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
global RIO_EXTENSION_FUNCTION_TABLE w32_rio_functions = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Memory::Internal
|
||||||
|
{
|
||||||
|
Byte* OS_Reserve(size_t size)
|
||||||
|
{
|
||||||
|
auto* result = static_cast<Byte*>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OS_Commit(Byte* ptr, size_t size)
|
||||||
|
{
|
||||||
|
bool result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != nullptr);
|
||||||
|
|
||||||
|
Assert(size <= static_cast<size_t>(MaxValueOf<DWORD>()));
|
||||||
|
|
||||||
|
if (w32_rio_functions.RIORegisterBuffer != nullptr && w32_rio_functions.RIODeregisterBuffer != nullptr)
|
||||||
|
{
|
||||||
|
w32_rio_functions.RIODeregisterBuffer(
|
||||||
|
w32_rio_functions.RIORegisterBuffer(reinterpret_cast<PCHAR>(ptr), static_cast<DWORD>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OS_Release(Byte* ptr, size_t size)
|
||||||
|
{
|
||||||
|
// size not used on windows
|
||||||
|
std::ignore = size;
|
||||||
|
|
||||||
|
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
} // namespace Memory::Internal
|
||||||
|
|
||||||
|
namespace Debug::Internal
|
||||||
|
{
|
||||||
|
bool IsDebuggerPresent()
|
||||||
|
{
|
||||||
|
return ::IsDebuggerPresent();
|
||||||
|
}
|
||||||
|
} // namespace Debug::Internal
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Used to handle a crash/exception
|
||||||
|
LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* exceptionPtrs)
|
||||||
|
{
|
||||||
|
(void)exceptionPtrs;
|
||||||
|
// See for more info https://github.com/EpicGamesExt/raddebugger/blob/master/src/os/core/win32/os_core_win32.c
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace Internal
|
||||||
|
{
|
||||||
|
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv)
|
||||||
|
{
|
||||||
|
SetUnhandledExceptionFilter(&ExceptionFilter);
|
||||||
|
|
||||||
|
// Allow only one instance to be launched.
|
||||||
|
CreateMutex(nullptr, false, L"Local\\Juliet.App");
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
|
MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a dummy socket to access RIO functions. Those will be used to do fine memory management
|
||||||
|
{
|
||||||
|
WSADATA WinSockData;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &WinSockData);
|
||||||
|
GUID guid = WSAID_MULTIPLE_RIO;
|
||||||
|
DWORD rio_byte = 0;
|
||||||
|
SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
|
||||||
|
reinterpret_cast<void**>(&w32_rio_functions), sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr);
|
||||||
|
closesocket(Sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = entryPointFunc(argc, argv);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Juliet
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
#define WINVER _WIN32_WINNT
|
#define WINVER _WIN32_WINNT
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NOIME
|
#define NOIME
|
||||||
@@ -66,6 +66,11 @@
|
|||||||
#define NOTAPE
|
#define NOTAPE
|
||||||
#define ANSI_ONLY
|
#define ANSI_ONLY
|
||||||
|
|
||||||
|
// Keep includes in that order
|
||||||
|
#include <WinSock2.h>
|
||||||
|
|
||||||
|
#include <MSWSock.h>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#undef min
|
#undef min
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
#include <Core/HotReload/HotReload.h>
|
#include <Core/HotReload/HotReload.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 <Core/Memory/EngineArena.h>
|
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <Core/Thread/Thread.h>
|
#include <Core/Thread/Thread.h>
|
||||||
|
|
||||||
@@ -13,6 +11,8 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
void InitHotReloadCode(HotReloadCode& code, String dllName, String transientDllName, String lockFilename)
|
void InitHotReloadCode(HotReloadCode& code, String dllName, String transientDllName, String lockFilename)
|
||||||
{
|
{
|
||||||
|
code.Arena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Hot Reload"));
|
||||||
|
|
||||||
// Get the app base path and build the dll path from there.
|
// Get the app base path and build the dll path from there.
|
||||||
String basePath = GetBasePath();
|
String basePath = GetBasePath();
|
||||||
size_t basePathLength = StringLength(basePath);
|
size_t basePathLength = StringLength(basePath);
|
||||||
@@ -24,7 +24,8 @@ namespace Juliet
|
|||||||
// TODO: Add path composition into filesystem + string format + string builder
|
// TODO: Add path composition into filesystem + string format + string builder
|
||||||
const size_t dllFullPathLength =
|
const size_t dllFullPathLength =
|
||||||
basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings
|
basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings
|
||||||
code.DLLFullPath.Data = ArenaPushArray<char>(GetEngineArena(), dllFullPathLength, ConstString("DLLFullPath"));
|
|
||||||
|
code.DLLFullPath.Data = static_cast<char*>(ArenaPush(code.Arena, dllFullPathLength, alignof(char), true JULIET_DEBUG_ONLY(, "DLL Path")));
|
||||||
int writtenSize = snprintf(CStr(code.DLLFullPath), dllFullPathLength, "%s%s", CStr(basePath), CStr(dllName));
|
int writtenSize = snprintf(CStr(code.DLLFullPath), dllFullPathLength, "%s%s", CStr(basePath), CStr(dllName));
|
||||||
if (writtenSize < static_cast<int>(dllFullPathLength) - 1)
|
if (writtenSize < static_cast<int>(dllFullPathLength) - 1)
|
||||||
{
|
{
|
||||||
@@ -37,7 +38,7 @@ namespace Juliet
|
|||||||
// Lock filename path
|
// Lock filename path
|
||||||
const size_t lockPathLength =
|
const size_t lockPathLength =
|
||||||
basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings
|
basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings
|
||||||
code.LockFullPath.Data = ArenaPushArray<char>(GetEngineArena(), lockPathLength, ConstString("LockFullPath"));
|
code.LockFullPath.Data = static_cast<char*>(ArenaPush(code.Arena, lockPathLength, alignof(char), true JULIET_DEBUG_ONLY(, "Lock File Path")));
|
||||||
writtenSize = snprintf(CStr(code.LockFullPath), lockPathLength, "%s%s", CStr(basePath), CStr(lockFilename));
|
writtenSize = snprintf(CStr(code.LockFullPath), lockPathLength, "%s%s", CStr(basePath), CStr(lockFilename));
|
||||||
if (writtenSize < static_cast<int>(lockPathLength) - 1)
|
if (writtenSize < static_cast<int>(lockPathLength) - 1)
|
||||||
{
|
{
|
||||||
@@ -59,6 +60,8 @@ namespace Juliet
|
|||||||
// Arena memory persists until engine shutdown
|
// Arena memory persists until engine shutdown
|
||||||
code.LockFullPath.Size = 0;
|
code.LockFullPath.Size = 0;
|
||||||
// Arena memory persists until engine shutdown
|
// Arena memory persists until engine shutdown
|
||||||
|
|
||||||
|
ArenaRelease(code.Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReloadCode(HotReloadCode& code)
|
void ReloadCode(HotReloadCode& code)
|
||||||
|
|||||||
@@ -56,7 +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)
|
||||||
auto tempDllPath = ArenaPushArray<char>(GetScratchArena(), tempDllMaxBufferSize, ConstString("tempDllPath"));
|
TempArena temp = ArenaTempBegin(code.Arena);
|
||||||
|
auto tempDllPath = ArenaPushArray<char>(temp.Arena, tempDllMaxBufferSize);
|
||||||
|
|
||||||
for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt)
|
for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt)
|
||||||
{
|
{
|
||||||
@@ -96,6 +97,7 @@ namespace Juliet
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ArenaTempEnd(temp);
|
||||||
|
|
||||||
code.Dll = LoadDynamicLibrary(tempDllPath);
|
code.Dll = LoadDynamicLibrary(tempDllPath);
|
||||||
if (code.Dll)
|
if (code.Dll)
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
#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>
|
||||||
|
|
||||||
#include <Core/Memory/EngineArena.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
// Forward declare implementation functions from backends
|
// Forward declare implementation functions from backends
|
||||||
@@ -24,34 +24,16 @@ namespace Juliet::ImGuiService
|
|||||||
|
|
||||||
// Dedicated Paged Arena for ImGui
|
// Dedicated Paged Arena for ImGui
|
||||||
// Sharing the same underlying Engine Pool for blocks, but separate Arena chain.
|
// Sharing the same underlying Engine Pool for blocks, but separate Arena chain.
|
||||||
MemoryArena g_ImGuiArena;
|
Arena* g_ImGuiArena = {};
|
||||||
|
|
||||||
void* ImGuiAllocWrapper(size_t size, void* /*user_data*/)
|
void* ImGuiAllocWrapper(size_t size, void* /*user_data*/)
|
||||||
{
|
{
|
||||||
// Store size in header to allow Pop
|
return ArenaPush(g_ImGuiArena, size, 8, false JULIET_DEBUG_ONLY(, "ImGuiAlloc"));
|
||||||
// Align total size to 16 to avoid padding issues with ArenaPop LIFO check
|
|
||||||
size_t actualSize = size + 16;
|
|
||||||
actualSize = (actualSize + 15) & ~static_cast<size_t>(15);
|
|
||||||
|
|
||||||
// We do save the size when we push so we can pop exactly the size.
|
|
||||||
if (void* ptr = ArenaPush(&g_ImGuiArena, actualSize, 16, ConstString("ImGui")))
|
|
||||||
{
|
|
||||||
// Write size at start
|
|
||||||
*static_cast<size_t*>(ptr) = actualSize;
|
|
||||||
return static_cast<uint8*>(ptr) + 16;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiFreeWrapper(void* ptr, void* /*user_data*/)
|
void ImGuiFreeWrapper(void* /*ptr*/, void* /*user_data*/)
|
||||||
{
|
{
|
||||||
Assert(ptr);
|
// TODO : Free list of imgui elements.
|
||||||
|
|
||||||
uint8* originalPtr = static_cast<uint8*>(ptr) - 16;
|
|
||||||
size_t actualSize = *reinterpret_cast<size_t*>(originalPtr);
|
|
||||||
|
|
||||||
// Attempt LIFO Pop
|
|
||||||
ArenaPop(&g_ImGuiArena, originalPtr, actualSize);
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -60,7 +42,7 @@ namespace Juliet::ImGuiService
|
|||||||
Assert(!g_Initialized);
|
Assert(!g_Initialized);
|
||||||
|
|
||||||
// Initialize ImGui Arena using Engine Pool
|
// Initialize ImGui Arena using Engine Pool
|
||||||
MemoryArenaCreate(&g_ImGuiArena, GetEngineArena()->BackingPool);
|
g_ImGuiArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "ImGui"));
|
||||||
|
|
||||||
// Setup Allocator
|
// Setup Allocator
|
||||||
ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr);
|
ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr);
|
||||||
@@ -121,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
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <Core/HAL/Display/Display_Private.h>
|
#include <Core/HAL/Display/Display_Private.h>
|
||||||
#include <Core/HAL/Filesystem/Filesystem_Private.h>
|
#include <Core/HAL/Filesystem/Filesystem_Private.h>
|
||||||
#include <Core/JulietInit.h>
|
#include <Core/JulietInit.h>
|
||||||
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -41,11 +42,6 @@ namespace Juliet
|
|||||||
|
|
||||||
void JulietInit(JulietInit_Flags flags)
|
void JulietInit(JulietInit_Flags flags)
|
||||||
{
|
{
|
||||||
// Mandatory systems
|
|
||||||
MemoryArenasInit();
|
|
||||||
|
|
||||||
InitFilesystem();
|
|
||||||
|
|
||||||
// Optional systems
|
// Optional systems
|
||||||
if ((flags & JulietInit_Flags::Display) != JulietInit_Flags::None)
|
if ((flags & JulietInit_Flags::Display) != JulietInit_Flags::None)
|
||||||
{
|
{
|
||||||
@@ -62,9 +58,6 @@ namespace Juliet
|
|||||||
DecrementSystemRefCount(JulietInit_Flags::Display);
|
DecrementSystemRefCount(JulietInit_Flags::Display);
|
||||||
ShutdownDisplaySystem();
|
ShutdownDisplaySystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownFilesystem();
|
|
||||||
MemoryArenasShutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdarg>
|
|
||||||
|
|
||||||
// Begin Todo JULIET debug output
|
// Begin Todo JULIET debug output
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <Core/Memory/MemoryArena.h>
|
||||||
|
|
||||||
#ifdef JULIET_WIN32
|
#ifdef JULIET_WIN32
|
||||||
#include <Core/HAL/Win32.h>
|
#include <Core/HAL/Win32.h>
|
||||||
@@ -13,61 +13,62 @@
|
|||||||
#endif
|
#endif
|
||||||
// End Todo
|
// End Todo
|
||||||
|
|
||||||
|
// TODO Juliet chrono
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
LogManager LogManagerSingleton;
|
struct LogsEntry : public QueueNode<LogsEntry>
|
||||||
constexpr size_t kLogBufferSize = 1024;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
LogManager::Entry::Entry(std::string& value, LogLevel level, LogCategory category)
|
|
||||||
: Value(value)
|
|
||||||
, Level(level)
|
|
||||||
, Category(category)
|
|
||||||
{
|
{
|
||||||
// TODO Juliet clock
|
String Value;
|
||||||
Time = std::chrono::system_clock::now();
|
std::chrono::system_clock::time_point Time;
|
||||||
|
LogLevel Level;
|
||||||
|
LogCategory Category;
|
||||||
|
};
|
||||||
|
DECLARE_QUEUE(LogsEntry);
|
||||||
|
|
||||||
|
// TODO: Debug level per category
|
||||||
|
const bool kPrintDebugLog = false;
|
||||||
|
|
||||||
|
// A log scope accumulates log until end of scope.
|
||||||
|
// Can be used to accumulate then write in a log file each frame.
|
||||||
|
struct LogScope
|
||||||
|
{
|
||||||
|
LogScope* Next;
|
||||||
|
size_t Position;
|
||||||
|
LogsEntryQueue Entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Logs contains the current scopes and the arena
|
||||||
|
struct Logs
|
||||||
|
{
|
||||||
|
Arena* Arena = nullptr;
|
||||||
|
LogScope* TopScope = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Logs* ActiveLog = nullptr;
|
||||||
|
|
||||||
|
Logs* LogAllocate()
|
||||||
|
{
|
||||||
|
Arena* arena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "Log Manager"));
|
||||||
|
Logs* logs = ArenaPushStruct<Logs>(arena);
|
||||||
|
logs->Arena = arena;
|
||||||
|
return logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager::LogManager()
|
void LogRelease(NonNullPtr<Logs> logs)
|
||||||
: IsInitialized(false)
|
|
||||||
{
|
{
|
||||||
|
ArenaRelease(logs->Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogManager::Init()
|
void OutputLog(LogsEntry& entry)
|
||||||
{
|
|
||||||
IsInitialized = true;
|
|
||||||
|
|
||||||
Log(LogLevel::Message, LogCategory::Engine, "Initializing Log Manager");
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogManager::Shutdown()
|
|
||||||
{
|
|
||||||
Log(LogLevel::Message, LogCategory::Engine, "Shutting down Log Manager");
|
|
||||||
|
|
||||||
Entries.clear();
|
|
||||||
|
|
||||||
IsInitialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogManager::AddEntry(Entry&& entry)
|
|
||||||
{
|
|
||||||
if (Entries.size() >= kLogBufferSize)
|
|
||||||
{
|
|
||||||
Entries.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
Entries.push_back(std::move(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogManager::OutputLog(Entry& entry)
|
|
||||||
{
|
{
|
||||||
// TODO Juliet Output io for each platform
|
// TODO Juliet Output io for each platform
|
||||||
|
|
||||||
// {:%F} is YYYY-MM-DD, {:%T} is HH:MM:SS.ffffff
|
// {:%F} is YYYY-MM-DD, {:%T} is HH:MM:SS.ffffff
|
||||||
std::string timestamp = std::format("[{:%F %T}] ", entry.Time);
|
std::string timestamp = std::format("[{:%F %T}] ", entry.Time);
|
||||||
std::string fullMessage = timestamp + entry.Value + "\n";
|
std::string fullMessage = timestamp + CStr(entry.Value) + "\n";
|
||||||
|
|
||||||
#ifdef JULIET_WIN32
|
#ifdef JULIET_WIN32
|
||||||
OutputDebugStringA(fullMessage.c_str());
|
OutputDebugStringA(fullMessage.c_str());
|
||||||
@@ -75,6 +76,25 @@ namespace Juliet
|
|||||||
printf("%s", fullMessage.c_str());
|
printf("%s", fullMessage.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PushLogEntry(NonNullPtr<Logs> logs, String value, LogLevel level, LogCategory category)
|
||||||
|
{
|
||||||
|
Arena* arena = logs->Arena;
|
||||||
|
String str = StringCopy(arena, value);
|
||||||
|
|
||||||
|
// Push onto the current scope
|
||||||
|
LogsEntry* newEntry = ArenaPushStruct<LogsEntry>(arena);
|
||||||
|
newEntry->Time = std::chrono::system_clock::now();
|
||||||
|
newEntry->Level = level;
|
||||||
|
newEntry->Category = category;
|
||||||
|
newEntry->Value = str;
|
||||||
|
|
||||||
|
Enqueue(logs->TopScope->Entries, newEntry);
|
||||||
|
logs->TopScope->Entries.Size += sizeof(LogsEntry) + str.Size;
|
||||||
|
|
||||||
|
OutputLog(*newEntry);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void InitializeLogManager()
|
void InitializeLogManager()
|
||||||
{
|
{
|
||||||
#ifdef JULIET_WIN32
|
#ifdef JULIET_WIN32
|
||||||
@@ -82,16 +102,45 @@ namespace Juliet
|
|||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LogManagerSingleton.Init();
|
ActiveLog = LogAllocate();
|
||||||
|
LogScopeBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownLogManager()
|
void ShutdownLogManager()
|
||||||
{
|
{
|
||||||
LogManagerSingleton.Shutdown();
|
LogScopeEnd();
|
||||||
|
LogRelease(ActiveLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogScopeBegin()
|
||||||
|
{
|
||||||
|
Assert(ActiveLog != nullptr);
|
||||||
|
|
||||||
|
size_t position = ArenaPos(ActiveLog->Arena);
|
||||||
|
LogScope* scope = ArenaPushStruct<LogScope>(ActiveLog->Arena);
|
||||||
|
scope->Position = position;
|
||||||
|
SingleLinkedListPushNext(ActiveLog->TopScope, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogScopeEnd()
|
||||||
|
{
|
||||||
|
Assert(ActiveLog != nullptr);
|
||||||
|
|
||||||
|
LogScope* scope = ActiveLog->TopScope;
|
||||||
|
Assert(scope != nullptr);
|
||||||
|
|
||||||
|
SingleLinkedListPopNext(ActiveLog->TopScope);
|
||||||
|
|
||||||
|
ArenaPopTo(ActiveLog->Arena, scope->Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
||||||
|
|
||||||
@@ -104,12 +153,12 @@ namespace Juliet
|
|||||||
|
|
||||||
while (std::getline(ss, individualLine, '\n'))
|
while (std::getline(ss, individualLine, '\n'))
|
||||||
{
|
{
|
||||||
LogManager::Entry entry(individualLine, level, category);
|
// Logs can happen before the active log is set, in that case, we can write to the console but not register the entry.
|
||||||
LogManagerSingleton.OutputLog(entry);
|
// One case is the Arena Allocate that calls logs and will happen before the logs are properly set because logs need to allocate an arena.
|
||||||
|
if (ActiveLog != nullptr)
|
||||||
if (LogManagerSingleton.GetIsInitialized())
|
|
||||||
{
|
{
|
||||||
LogManagerSingleton.AddEntry(std::move(entry));
|
String julietstr = WrapString(individualLine.c_str());
|
||||||
|
PushLogEntry(ActiveLog, julietstr, level, category);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,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;
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Core/Memory/MemoryArena.h>
|
|
||||||
|
|
||||||
namespace Juliet
|
|
||||||
{
|
|
||||||
// Persistent engine-only arena.
|
|
||||||
// Not exported to the Game DLL.
|
|
||||||
MemoryArena* GetEngineArena();
|
|
||||||
} // namespace Juliet
|
|
||||||
@@ -1,428 +1,341 @@
|
|||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
#include <Core/Memory/Allocator.h>
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
|
#include <Core/Memory/MemoryArenaDebug.h>
|
||||||
#include <Core/Memory/Utils.h>
|
#include <Core/Memory/Utils.h>
|
||||||
|
|
||||||
#include <algorithm> // For std::max
|
#include <algorithm> // For std::max
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/HAL/OS/OS.h>
|
||||||
|
#include <Core/Logging/LogTypes.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
namespace UnitTest
|
// TODO Get page size from os kernel call (dwPageSize)
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
extern void TestMemoryArena();
|
constexpr uint64 k_PageSize = Kilobytes(4);
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
// --- MemoryPool Implementation ---
|
struct ArenaFreeNode
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
static void FreeDebugAllocations(MemoryBlock* blk)
|
|
||||||
{
|
{
|
||||||
if (!blk) return;
|
ArenaFreeNode* Next;
|
||||||
ArenaAllocation* curr = blk->FirstAllocation;
|
ArenaFreeNode* Previous;
|
||||||
while (curr)
|
index_t Position;
|
||||||
{
|
size_t Size;
|
||||||
ArenaAllocation* next = curr->Next;
|
};
|
||||||
SafeFree(curr);
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
blk->FirstAllocation = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Simple First-Fit Allocator
|
|
||||||
MemoryBlock* MemoryPool::AllocateBlock(size_t minCapacity)
|
|
||||||
{
|
|
||||||
// Require space for Header + Data
|
|
||||||
size_t totalUnalignedSize = sizeof(MemoryBlock) + minCapacity;
|
|
||||||
size_t requiredSize = (totalUnalignedSize + 15) & ~static_cast<size_t>(15);
|
|
||||||
|
|
||||||
MemoryBlock** prevPtr = &FreeList;
|
|
||||||
MemoryBlock* curr = FreeList;
|
|
||||||
|
|
||||||
while (curr)
|
|
||||||
{
|
|
||||||
if (curr->TotalSize >= requiredSize)
|
|
||||||
{
|
|
||||||
// Match
|
|
||||||
// Check if we can split this block?
|
|
||||||
if (curr->TotalSize >= requiredSize + sizeof(MemoryBlock) + 16)
|
|
||||||
{
|
|
||||||
// Split
|
|
||||||
size_t remainingSize = curr->TotalSize - requiredSize;
|
|
||||||
|
|
||||||
MemoryBlock* nextBlock = reinterpret_cast<MemoryBlock*>((uint8*)curr + requiredSize);
|
|
||||||
nextBlock->Magic = MemoryBlock::kMagic;
|
|
||||||
nextBlock->TotalSize = remainingSize;
|
|
||||||
nextBlock->Used = 0;
|
|
||||||
nextBlock->Next = curr->Next;
|
|
||||||
|
|
||||||
// Update FreeList to point to the new remaining block instead of curr
|
|
||||||
*prevPtr = nextBlock;
|
|
||||||
|
|
||||||
// Update curr to be the allocated chunk
|
|
||||||
curr->TotalSize = requiredSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Take the whole block
|
|
||||||
*prevPtr = curr->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
curr->Next = nullptr;
|
|
||||||
curr->Used = 0;
|
|
||||||
curr->Magic = MemoryBlock::kMagic;
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
curr->FirstAllocation = nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
if (curr->TotalSize > sizeof(MemoryBlock))
|
|
||||||
{
|
|
||||||
MemSet(curr->GetData(), 0xCD, curr->TotalSize - sizeof(MemoryBlock));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
prevPtr = &curr->Next;
|
|
||||||
curr = curr->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Out of Memory in Pool
|
|
||||||
Assert(false, "MemoryPool exhausted!");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MemoryPool::FreeBlock(MemoryBlock* block)
|
|
||||||
{
|
|
||||||
if (!block)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert(block->Magic == MemoryBlock::kMagic);
|
|
||||||
|
|
||||||
// Poison Header and Data in Debug
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
FreeDebugAllocations(block);
|
|
||||||
// 0xDD = Dead Data
|
|
||||||
MemSet(block->GetData(), 0xDD, block->TotalSize - sizeof(MemoryBlock));
|
|
||||||
block->Magic = 0xDEADBEEF;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Insert at Head of FreeList (Simplest, no coalescing yet)
|
|
||||||
block->Next = FreeList;
|
|
||||||
FreeList = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- MemoryArena Implementation ---
|
|
||||||
|
|
||||||
void MemoryArenaCreate(MemoryArena* arena, MemoryPool* pool)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
Assert(pool);
|
|
||||||
arena->BackingPool = pool;
|
|
||||||
arena->CurrentBlock = nullptr;
|
|
||||||
arena->FirstBlock = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overload for backward compatibility / tests if needed, but we should switch to using Pools.
|
|
||||||
// NOTE: The previous signature was (Arena*, void* backing, size_t).
|
|
||||||
// We are changing the API.
|
|
||||||
|
|
||||||
void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, [[maybe_unused]] String tag)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
Assert(arena->BackingPool);
|
|
||||||
|
|
||||||
// Default Block Size (e.g., 64KB or 1MB? Let's use 16KB for granular tests,
|
|
||||||
// or larger for prod. Let's make it dynamic or standard constant.
|
|
||||||
constexpr size_t kDefaultBlockSize = 64 * 1024; // 64KB pages
|
|
||||||
|
|
||||||
// Alignment check
|
|
||||||
Assert((alignment & (alignment - 1)) == 0);
|
|
||||||
|
|
||||||
if (!arena->CurrentBlock)
|
|
||||||
{
|
|
||||||
// Initial Allocation
|
|
||||||
size_t allocSize = std::max(size, kDefaultBlockSize);
|
|
||||||
arena->CurrentBlock = arena->BackingPool->AllocateBlock(allocSize);
|
|
||||||
arena->FirstBlock = arena->CurrentBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try allocation in CurrentBlock
|
|
||||||
MemoryBlock* blk = arena->CurrentBlock;
|
|
||||||
size_t currentAddr = reinterpret_cast<size_t>(blk->GetData()) + blk->Used;
|
|
||||||
size_t alignmentOffset = 0;
|
|
||||||
|
|
||||||
size_t mask = alignment - 1;
|
|
||||||
if (currentAddr & mask)
|
|
||||||
{
|
|
||||||
alignmentOffset = alignment - (currentAddr & mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blk->Used + alignmentOffset + size > blk->TotalSize - sizeof(MemoryBlock))
|
|
||||||
{
|
|
||||||
// Overflow! Request new block.
|
|
||||||
// Strict minimum: what we need now.
|
|
||||||
// Better: Max(Default, size) to avoid repeating large allocs for tiny overflow?
|
|
||||||
size_t allocSize = std::max(size, kDefaultBlockSize);
|
|
||||||
MemoryBlock* newBlock = arena->BackingPool->AllocateBlock(allocSize);
|
|
||||||
|
|
||||||
// Link
|
|
||||||
blk->Next = newBlock;
|
|
||||||
arena->CurrentBlock = newBlock;
|
|
||||||
blk = newBlock;
|
|
||||||
|
|
||||||
// Recalc for new block (Used should be 0)
|
|
||||||
currentAddr = reinterpret_cast<size_t>(blk->GetData());
|
|
||||||
alignmentOffset = 0;
|
|
||||||
// newBlock check
|
|
||||||
if (currentAddr & mask)
|
|
||||||
{
|
|
||||||
alignmentOffset = alignment - (currentAddr & mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit
|
|
||||||
blk->Used += alignmentOffset;
|
|
||||||
void* ptr = blk->GetData() + blk->Used;
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
ArenaAllocation* node = (ArenaAllocation*)Malloc(sizeof(ArenaAllocation));
|
|
||||||
node->Offset = blk->Used;
|
|
||||||
node->Size = size;
|
|
||||||
node->Tag = tag;
|
|
||||||
node->Next = nullptr;
|
|
||||||
|
|
||||||
if (!blk->FirstAllocation) blk->FirstAllocation = node;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArenaAllocation* t = blk->FirstAllocation;
|
|
||||||
while(t->Next) t = t->Next;
|
|
||||||
t->Next = node;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
blk->Used += size;
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, String tag)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
Assert(oldPtr);
|
|
||||||
Assert(newSize != 0);
|
|
||||||
|
|
||||||
// Optimized Case: Expanding the LAST allocation in the Current Block
|
|
||||||
MemoryBlock* blk = arena->CurrentBlock;
|
|
||||||
uint8* oldBytes = static_cast<uint8*>(oldPtr);
|
|
||||||
|
|
||||||
// Is oldPtr inside current block?
|
|
||||||
if (oldBytes >= blk->GetData() && oldBytes < blk->GetData() + blk->TotalSize - sizeof(MemoryBlock))
|
|
||||||
{
|
|
||||||
// Is it the last one?
|
|
||||||
if (oldBytes + oldSize == blk->GetData() + blk->Used)
|
|
||||||
{
|
|
||||||
// Can we expand?
|
|
||||||
if (blk->Used + (newSize - oldSize) <= blk->TotalSize - sizeof(MemoryBlock))
|
|
||||||
{
|
|
||||||
// Yes, expand in place
|
|
||||||
blk->Used += (newSize - oldSize);
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
{
|
|
||||||
ArenaAllocation* t = blk->FirstAllocation;
|
|
||||||
while (t && t->Next) t = t->Next;
|
|
||||||
if (t) t->Size += (newSize - oldSize);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return oldPtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: Copy
|
|
||||||
void* newPtr = ArenaPush(arena, newSize, alignment, tag);
|
|
||||||
MemCopy(newPtr, oldPtr, std::min(oldSize, newSize));
|
|
||||||
return newPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ArenaPop(MemoryArena* arena, void* ptr, size_t size)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
Assert(ptr);
|
|
||||||
Assert(size);
|
|
||||||
|
|
||||||
MemoryBlock* blk = arena->CurrentBlock;
|
|
||||||
Assert(blk);
|
|
||||||
|
|
||||||
uint8* ptrBytes = static_cast<uint8*>(ptr);
|
|
||||||
uint8* currentTop = blk->GetData() + blk->Used;
|
|
||||||
|
|
||||||
// Check if this pointer is exactly at the top of the stack (LIFO)
|
|
||||||
if (ptrBytes + size == currentTop)
|
|
||||||
{
|
|
||||||
// Yes, we can just rewind the Used pointer
|
|
||||||
blk->Used -= size;
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
{
|
|
||||||
ArenaAllocation* t = blk->FirstAllocation;
|
|
||||||
ArenaAllocation* prev = nullptr;
|
|
||||||
while (t && t->Next) { prev = t; t = t->Next; }
|
|
||||||
if (t) {
|
|
||||||
SafeFree(t);
|
|
||||||
if (prev) prev->Next = nullptr;
|
|
||||||
else blk->FirstAllocation = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArenaReset(MemoryArena* arena)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
Assert(arena->FirstBlock);
|
|
||||||
|
|
||||||
// Keep FirstBlock, Free the rest.
|
|
||||||
MemoryBlock* curr = arena->FirstBlock->Next;
|
|
||||||
while (curr)
|
|
||||||
{
|
|
||||||
MemoryBlock* next = curr->Next;
|
|
||||||
arena->BackingPool->FreeBlock(curr);
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena->FirstBlock->Next = nullptr;
|
|
||||||
arena->FirstBlock->Used = 0;
|
|
||||||
arena->CurrentBlock = arena->FirstBlock;
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
// Poison First Block
|
|
||||||
FreeDebugAllocations(arena->FirstBlock);
|
|
||||||
MemSet(arena->FirstBlock->GetData(), 0xCD, arena->FirstBlock->TotalSize - sizeof(MemoryBlock));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ArenaMarker ArenaGetMarker(MemoryArena* arena)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
return { arena->CurrentBlock, arena->CurrentBlock ? arena->CurrentBlock->Used : 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArenaResetToMarker(MemoryArena* arena, ArenaMarker marker)
|
|
||||||
{
|
|
||||||
Assert(arena);
|
|
||||||
if (!marker.Block)
|
|
||||||
{
|
|
||||||
// If marker block is null, it might mean "start" or "empty".
|
|
||||||
// But if the arena has blocks, this is suspicious.
|
|
||||||
// If the arena was empty when marker was taken, this is valid.
|
|
||||||
ArenaReset(arena);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free blocks *after* the marker block
|
|
||||||
MemoryBlock* curr = marker.Block->Next;
|
|
||||||
while (curr)
|
|
||||||
{
|
|
||||||
MemoryBlock* next = curr->Next;
|
|
||||||
arena->BackingPool->FreeBlock(curr);
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
marker.Block->Next = nullptr;
|
|
||||||
marker.Block->Used = marker.Offset;
|
|
||||||
arena->CurrentBlock = marker.Block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Global Arenas ---
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
MemoryPool g_ScratchMemory;
|
static_assert(sizeof(ArenaFreeNode) == 32, "ArenaFreeNode should be 32 bytes and not more");
|
||||||
MemoryPool g_EngineMemory;
|
constexpr size_t k_ArenaFreeNodeSize = sizeof(ArenaFreeNode);
|
||||||
MemoryPool g_GameMemory;
|
|
||||||
|
|
||||||
MemoryArena g_ScratchArena;
|
|
||||||
MemoryArena g_EngineArena;
|
|
||||||
MemoryArena g_GameArena;
|
|
||||||
|
|
||||||
// Backing Buffers
|
|
||||||
void* g_ScratchBuffer = nullptr;
|
|
||||||
void* g_EngineBuffer = nullptr;
|
|
||||||
void* g_GameBuffer = nullptr;
|
|
||||||
|
|
||||||
constexpr size_t kScratchSize = Megabytes(64);
|
|
||||||
constexpr size_t kEngineSize = Megabytes(256);
|
|
||||||
constexpr size_t kGameSize = Megabytes(512);
|
|
||||||
|
|
||||||
void InitPool(MemoryPool* pool, void* buffer, size_t size)
|
|
||||||
{
|
|
||||||
pool->BaseAddress = buffer;
|
|
||||||
pool->TotalSize = size;
|
|
||||||
|
|
||||||
// Create one giant initial block
|
|
||||||
Assert(size > sizeof(MemoryBlock));
|
|
||||||
MemoryBlock* block = static_cast<MemoryBlock*>(buffer);
|
|
||||||
block->Magic = MemoryBlock::kMagic;
|
|
||||||
block->Next = nullptr;
|
|
||||||
block->TotalSize = size;
|
|
||||||
block->Used = 0;
|
|
||||||
|
|
||||||
pool->FreeList = block;
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MemoryArena* GetScratchArena()
|
// https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c
|
||||||
{
|
|
||||||
return &g_ScratchArena;
|
|
||||||
}
|
|
||||||
MemoryArena* GetEngineArena()
|
|
||||||
{
|
|
||||||
return &g_EngineArena;
|
|
||||||
}
|
|
||||||
MemoryArena* GetGameArena()
|
|
||||||
{
|
|
||||||
return &g_GameArena;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScratchArenaReset()
|
Arena* ArenaAllocate(const ArenaParams& params JULIET_DEBUG_ONLY(, const char* name), const std::source_location& loc)
|
||||||
{
|
{
|
||||||
ArenaReset(&g_ScratchArena);
|
Log(LogLevel::Message, LogCategory::Core, "Allocating from %s : %ul", loc.file_name(), loc.line());
|
||||||
}
|
|
||||||
|
|
||||||
void MemoryArenasInit()
|
Byte* baseMem = nullptr;
|
||||||
{
|
|
||||||
g_ScratchBuffer = Malloc(kScratchSize);
|
|
||||||
g_EngineBuffer = Malloc(kEngineSize);
|
|
||||||
g_GameBuffer = Malloc(kGameSize);
|
|
||||||
|
|
||||||
InitPool(&g_ScratchMemory, g_ScratchBuffer, kScratchSize);
|
uint64 reserve_size = AlignPow2(params.ReserveSize, k_PageSize);
|
||||||
InitPool(&g_EngineMemory, g_EngineBuffer, kEngineSize);
|
uint64 commit_size = AlignPow2(params.CommitSize, k_PageSize);
|
||||||
InitPool(&g_GameMemory, g_GameBuffer, kGameSize);
|
|
||||||
|
|
||||||
MemoryArenaCreate(&g_ScratchArena, &g_ScratchMemory);
|
// TODO: handle large pages
|
||||||
MemoryArenaCreate(&g_EngineArena, &g_EngineMemory);
|
baseMem = Memory::OS_Reserve(reserve_size);
|
||||||
MemoryArenaCreate(&g_GameArena, &g_GameMemory);
|
Memory::OS_Commit(baseMem, commit_size);
|
||||||
|
|
||||||
|
Arena* arena = reinterpret_cast<Arena*>(baseMem);
|
||||||
|
arena->Current = arena;
|
||||||
|
|
||||||
|
arena->CommitSize = commit_size;
|
||||||
|
arena->ReserveSize = reserve_size;
|
||||||
|
|
||||||
|
arena->Committed = commit_size;
|
||||||
|
arena->Reserved = reserve_size;
|
||||||
|
|
||||||
|
arena->BasePosition = 0;
|
||||||
|
arena->Position = k_ArenaHeaderSize;
|
||||||
|
|
||||||
|
arena->FreeNodes = nullptr;
|
||||||
|
arena->AllowRealloc = params.AllowRealloc;
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
#if JULIET_DEBUG
|
||||||
UnitTest::TestMemoryArena();
|
arena->CanReserveMore = params.CanReserveMore;
|
||||||
|
arena->FirstDebugInfo = nullptr;
|
||||||
|
|
||||||
|
DebugArenaSetDebugName(arena, name);
|
||||||
|
DebugRegisterArena(arena);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArenaRelease(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
// Release active blocks (Current chain)
|
||||||
|
for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous)
|
||||||
|
{
|
||||||
|
previous = node->Previous;
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(DebugUnregisterArena(node);)
|
||||||
|
JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);)
|
||||||
|
|
||||||
|
Memory::OS_Release(node, node->Reserved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag))
|
||||||
|
{
|
||||||
|
// Assert(IsPowerOfTwo(align));
|
||||||
|
Arena* current = arena->Current;
|
||||||
|
size_t positionPrePush = AlignPow2(current->Position, align);
|
||||||
|
size_t positionPostPush = positionPrePush + size;
|
||||||
|
|
||||||
|
if (arena->AllowRealloc)
|
||||||
|
{
|
||||||
|
size = Max(size, k_ArenaFreeNodeSize);
|
||||||
|
|
||||||
|
for (ArenaFreeNode* freeNode = current->FreeNodes; freeNode != nullptr; freeNode = freeNode->Next)
|
||||||
|
{
|
||||||
|
if (size <= freeNode->Size)
|
||||||
|
{
|
||||||
|
index_t position = freeNode->Position;
|
||||||
|
size_t remainingSize = freeNode->Size - size;
|
||||||
|
if (remainingSize < k_ArenaFreeNodeSize)
|
||||||
|
{
|
||||||
|
ArenaFreeNode* previous = freeNode->Previous;
|
||||||
|
ArenaFreeNode* next = freeNode->Next;
|
||||||
|
if (previous)
|
||||||
|
{
|
||||||
|
previous->Next = next;
|
||||||
|
}
|
||||||
|
if (next)
|
||||||
|
{
|
||||||
|
next->Previous = previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
if (remainingSize > 0)
|
||||||
|
{
|
||||||
|
++current->LostNodeCount;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else
|
||||||
void MemoryArenasShutdown()
|
|
||||||
{
|
{
|
||||||
// Technically we should free blocks?
|
freeNode->Position += size;
|
||||||
// But since we own the giant buffers, we can just free them.
|
|
||||||
SafeFree(g_ScratchBuffer);
|
|
||||||
SafeFree(g_EngineBuffer);
|
|
||||||
SafeFree(g_GameBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* result = reinterpret_cast<Byte*>(current) + position;
|
||||||
|
if (shouldBeZeroed)
|
||||||
|
{
|
||||||
|
MemoryZero(result, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If allowed and needed, add a new block and chain it to the arena.
|
||||||
|
if (current->Reserved < positionPostPush /* flags : chaining allowed */)
|
||||||
|
{
|
||||||
|
Assert(arena->CanReserveMore);
|
||||||
|
|
||||||
|
Arena* newBlock = nullptr;
|
||||||
|
{
|
||||||
|
Arena* prev_block;
|
||||||
|
for (newBlock = arena->FreeBlockLast, prev_block = nullptr; newBlock != nullptr;
|
||||||
|
prev_block = newBlock, newBlock = newBlock->Previous)
|
||||||
|
{
|
||||||
|
if (newBlock->Reserved >= AlignPow2(newBlock->Position, align) + size)
|
||||||
|
{
|
||||||
|
if (prev_block)
|
||||||
|
{
|
||||||
|
prev_block->Previous = newBlock->Previous;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arena->FreeBlockLast = newBlock->Previous;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newBlock == nullptr)
|
||||||
|
{
|
||||||
|
size_t reserveSize = current->ReserveSize;
|
||||||
|
size_t commitSize = current->CommitSize;
|
||||||
|
|
||||||
|
if (size + k_ArenaHeaderSize > reserveSize)
|
||||||
|
{
|
||||||
|
reserveSize = AlignPow2(size + k_ArenaHeaderSize, align);
|
||||||
|
commitSize = AlignPow2(size + k_ArenaHeaderSize, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
newBlock =
|
||||||
|
ArenaAllocate({ .ReserveSize = reserveSize, .CommitSize = commitSize } JULIET_DEBUG_ONLY(, arena->Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
newBlock->BasePosition = current->BasePosition + current->Reserved;
|
||||||
|
SingleLinkedListPushPrevious(arena->Current, newBlock);
|
||||||
|
|
||||||
|
current = newBlock;
|
||||||
|
positionPrePush = AlignPow2(current->Position, align);
|
||||||
|
positionPostPush = positionPrePush + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sizeToZero = 0;
|
||||||
|
if (shouldBeZeroed)
|
||||||
|
{
|
||||||
|
sizeToZero = Min(current->Committed, positionPostPush) - positionPrePush;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If needed commit new pages
|
||||||
|
if (current->Committed < positionPostPush)
|
||||||
|
{
|
||||||
|
size_t commitPostAligned = positionPostPush + current->CommitSize - 1;
|
||||||
|
commitPostAligned -= commitPostAligned % current->CommitSize;
|
||||||
|
size_t commitPostClamped = ClampTop(commitPostAligned, current->Reserved);
|
||||||
|
size_t commitSize = commitPostClamped - current->Committed;
|
||||||
|
Byte* commitPtr = reinterpret_cast<Byte*>(current) + current->Committed;
|
||||||
|
|
||||||
|
// TODO commit_large
|
||||||
|
Memory::OS_Commit(commitPtr, commitSize);
|
||||||
|
|
||||||
|
current->Committed = commitPostClamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push on the current block
|
||||||
|
void* result = nullptr;
|
||||||
|
if (current->Committed >= positionPostPush)
|
||||||
|
{
|
||||||
|
result = reinterpret_cast<Byte*>(current) + positionPrePush;
|
||||||
|
current->Position = positionPostPush;
|
||||||
|
if (sizeToZero != 0)
|
||||||
|
{
|
||||||
|
MemoryZero(result, sizeToZero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == nullptr) [[unlikely]]
|
||||||
|
{
|
||||||
|
Log(LogLevel::Error, LogCategory::Core, "Fatal Allocation Failure - Unexpected allocation failure");
|
||||||
|
Assert(false, "Fatal Allocation Failure - Unexpected allocation failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(if (!IsDebugInfoArena(arena)) { DebugArenaAddDebugInfo(current, size, positionPrePush, tag); })
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize, size_t align,
|
||||||
|
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag))
|
||||||
|
{
|
||||||
|
void* result = ArenaPush(arena, newSize, align, shouldBeZeroed JULIET_DEBUG_ONLY(, tag));
|
||||||
|
|
||||||
|
// Find the correct block to release
|
||||||
|
Arena* block = nullptr;
|
||||||
|
for (block = arena->Current; block != nullptr; block = block->Previous)
|
||||||
|
{
|
||||||
|
if ((reinterpret_cast<Byte*>(block) < static_cast<Byte*>(oldPtr)) &&
|
||||||
|
(static_cast<Byte*>(oldPtr) <= (reinterpret_cast<Byte*>(block) + block->Reserved)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert(block != nullptr);
|
||||||
|
|
||||||
|
// Copy old to new
|
||||||
|
MemCopy(result, oldPtr, std::min(oldSize, newSize));
|
||||||
|
|
||||||
|
// Zero the old memory
|
||||||
|
MemoryZero(oldPtr, oldSize);
|
||||||
|
|
||||||
|
if (oldSize >= sizeof(ArenaFreeNode))
|
||||||
|
{
|
||||||
|
ArenaFreeNode* freeNode = static_cast<ArenaFreeNode*>(oldPtr);
|
||||||
|
ptrdiff_t posPtr = static_cast<Byte*>(oldPtr) - reinterpret_cast<Byte*>(block);
|
||||||
|
index_t position = static_cast<index_t>(posPtr);
|
||||||
|
freeNode->Position = position;
|
||||||
|
freeNode->Size = oldSize;
|
||||||
|
|
||||||
|
// Insert at head of the free list
|
||||||
|
freeNode->Next = block->FreeNodes;
|
||||||
|
freeNode->Previous = nullptr;
|
||||||
|
if (block->FreeNodes)
|
||||||
|
{
|
||||||
|
block->FreeNodes->Previous = freeNode;
|
||||||
|
}
|
||||||
|
block->FreeNodes = freeNode;
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
// Remove the debug info for the old allocation (since it's now free)
|
||||||
|
size_t oldOffset = static_cast<size_t>(static_cast<Byte*>(oldPtr) - reinterpret_cast<Byte*>(block));
|
||||||
|
DebugArenaRemoveAllocation(block, oldOffset);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArenaPopTo(NonNullPtr<Arena> arena, size_t position)
|
||||||
|
{
|
||||||
|
size_t clampedPosition = ClampBottom(k_ArenaHeaderSize, position);
|
||||||
|
Arena* current = arena->Current;
|
||||||
|
|
||||||
|
for (Arena* previous = nullptr; current->BasePosition >= clampedPosition; current = previous)
|
||||||
|
{
|
||||||
|
previous = current->Previous;
|
||||||
|
current->Position = k_ArenaHeaderSize;
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(DebugArenaFreeBlock(current);)
|
||||||
|
|
||||||
|
SingleLinkedListPushPrevious(arena->FreeBlockLast, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
arena->Current = current;
|
||||||
|
size_t newPosition = clampedPosition - current->BasePosition;
|
||||||
|
Assert(newPosition <= current->Position);
|
||||||
|
current->Position = newPosition;
|
||||||
|
|
||||||
|
JULIET_DEBUG_ONLY(DebugArenaPopTo(current, newPosition);)
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArenaPop(NonNullPtr<Arena> arena, size_t amount)
|
||||||
|
{
|
||||||
|
size_t oldPosition = ArenaPos(arena);
|
||||||
|
size_t newPosition = oldPosition;
|
||||||
|
if (amount < oldPosition)
|
||||||
|
{
|
||||||
|
newPosition = oldPosition - amount;
|
||||||
|
}
|
||||||
|
ArenaPopTo(arena, newPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArenaClear(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
ArenaPopTo(arena, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ArenaPos(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
Arena* current = arena->Current;
|
||||||
|
size_t position = current->BasePosition + current->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
|
||||||
|
|||||||
156
Juliet/src/Core/Memory/MemoryArenaDebug.cpp
Normal file
156
Juliet/src/Core/Memory/MemoryArenaDebug.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#include <Core/Memory/MemoryArena.h> // For Arena definition
|
||||||
|
#include <Core/Memory/MemoryArenaDebug.h>
|
||||||
|
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
Arena* g_ArenaGlobalHead = nullptr;
|
||||||
|
Arena* g_DebugInfoArena = nullptr;
|
||||||
|
ArenaDebugInfo* g_DebugInfoFreeList = nullptr;
|
||||||
|
ArenaAllocation* g_ArenaAllocationFreeList = nullptr;
|
||||||
|
|
||||||
|
// --- Internal Helpers ---
|
||||||
|
static ArenaDebugInfo* AllocDebugInfo()
|
||||||
|
{
|
||||||
|
if (g_DebugInfoFreeList)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo* info = g_DebugInfoFreeList;
|
||||||
|
g_DebugInfoFreeList = info->Next;
|
||||||
|
info->Next = nullptr;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_DebugInfoArena)
|
||||||
|
{
|
||||||
|
// Create a dedicated arena for debug info
|
||||||
|
g_DebugInfoArena = ArenaAllocate(
|
||||||
|
{ .ReserveSize = Megabytes(16), .CommitSize = Kilobytes(64) } JULIET_DEBUG_ONLY(, "Debug Info Arena"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ArenaPushStruct<ArenaDebugInfo>(g_DebugInfoArena);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeDebugInfo(ArenaDebugInfo* info)
|
||||||
|
{
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
info->Next = g_DebugInfoFreeList;
|
||||||
|
g_DebugInfoFreeList = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRegisterArena(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
// Add to Global List
|
||||||
|
// Note: Not thread safe, assuming single thread for now as per context
|
||||||
|
if (g_ArenaGlobalHead)
|
||||||
|
{
|
||||||
|
g_ArenaGlobalHead->GlobalPrev = arena;
|
||||||
|
}
|
||||||
|
arena->GlobalNext = g_ArenaGlobalHead;
|
||||||
|
arena->GlobalPrev = nullptr;
|
||||||
|
g_ArenaGlobalHead = arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugUnregisterArena(NonNullPtr<Arena> arena)
|
||||||
|
{
|
||||||
|
// Remove from Global List
|
||||||
|
if (arena->GlobalPrev)
|
||||||
|
{
|
||||||
|
arena->GlobalPrev->GlobalNext = arena->GlobalNext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_ArenaGlobalHead = arena->GlobalNext;
|
||||||
|
}
|
||||||
|
if (arena->GlobalNext)
|
||||||
|
{
|
||||||
|
arena->GlobalNext->GlobalPrev = arena->GlobalPrev;
|
||||||
|
}
|
||||||
|
arena->GlobalPrev = nullptr;
|
||||||
|
arena->GlobalNext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name)
|
||||||
|
{
|
||||||
|
arena->Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDebugInfoArena(const Arena* arena)
|
||||||
|
{
|
||||||
|
return arena == g_DebugInfoArena;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugArenaFreeBlock(Arena* block)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo* info = block->FirstDebugInfo;
|
||||||
|
while (info)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo* nextInfo = info->Next;
|
||||||
|
FreeDebugInfo(info);
|
||||||
|
info = nextInfo;
|
||||||
|
}
|
||||||
|
block->FirstDebugInfo = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugArenaRemoveAllocation(Arena* block, size_t oldOffset)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo** prevInfo = &block->FirstDebugInfo;
|
||||||
|
ArenaDebugInfo* info = block->FirstDebugInfo;
|
||||||
|
|
||||||
|
while (info)
|
||||||
|
{
|
||||||
|
if (info->Offset == oldOffset) // Found it
|
||||||
|
{
|
||||||
|
*prevInfo = info->Next;
|
||||||
|
FreeDebugInfo(info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevInfo = &info->Next;
|
||||||
|
info = info->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugArenaPopTo(Arena* block, size_t newPosition)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo** prevInfo = &block->FirstDebugInfo;
|
||||||
|
ArenaDebugInfo* info = block->FirstDebugInfo;
|
||||||
|
while (info)
|
||||||
|
{
|
||||||
|
if (info->Offset >= newPosition)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo* toFree = info;
|
||||||
|
*prevInfo = info->Next; // Unlink
|
||||||
|
info = info->Next; // Advance
|
||||||
|
FreeDebugInfo(toFree);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prevInfo = &info->Next;
|
||||||
|
info = info->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugArenaAddDebugInfo(Arena* block, size_t size, size_t offset, const char* tag)
|
||||||
|
{
|
||||||
|
ArenaDebugInfo* info = AllocDebugInfo();
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
info->Tag = tag ? tag : "Untagged";
|
||||||
|
info->Size = size;
|
||||||
|
info->Offset = offset;
|
||||||
|
info->Next = block->FirstDebugInfo;
|
||||||
|
block->FirstDebugInfo = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena* GetGlobalArenaListHead()
|
||||||
|
{
|
||||||
|
return g_ArenaGlobalHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,68 +7,169 @@
|
|||||||
|
|
||||||
namespace Juliet::UnitTest
|
namespace Juliet::UnitTest
|
||||||
{
|
{
|
||||||
|
struct TestStruct
|
||||||
|
{
|
||||||
|
uint8 First;
|
||||||
|
uint16 Second;
|
||||||
|
};
|
||||||
// Need access to internal Pool functions? They are in the header now!
|
// Need access to internal Pool functions? They are in the header now!
|
||||||
// MemoryPool is declared in header.
|
// MemoryPool is declared in header.
|
||||||
void TestMemoryArena()
|
void TestMemoryArena()
|
||||||
{
|
{
|
||||||
printf("Running Paged Memory Arena Tests...\n");
|
printf("Running Paged Memory Arena Tests...\n");
|
||||||
|
|
||||||
// Setup Pool and Arena for Pop Tests
|
// New Arena!
|
||||||
size_t testPoolSize = Megabytes(1);
|
ArenaParams param{ .ReserveSize = Megabytes(64llu), .CommitSize = Kilobytes(64llu) };
|
||||||
void* testBacking = Calloc(1, testPoolSize);
|
Arena* testArena = ArenaAllocate(param JULIET_DEBUG_ONLY(, "Test Arena"));
|
||||||
MemoryPool pool;
|
|
||||||
pool.BaseAddress = testBacking;
|
size_t pos = ArenaPos(testArena);
|
||||||
pool.TotalSize = testPoolSize;
|
Assert(pos == k_ArenaHeaderSize);
|
||||||
pool.FreeList = nullptr;
|
|
||||||
|
TestStruct* myStruct = ArenaPushStruct<TestStruct>(testArena);
|
||||||
|
Assert(myStruct->First == 0);
|
||||||
|
Assert(myStruct->Second == 0);
|
||||||
|
pos = ArenaPos(testArena);
|
||||||
|
Assert(pos == k_ArenaHeaderSize + sizeof(TestStruct));
|
||||||
|
|
||||||
|
TestStruct* myStruct2 = ArenaPushStruct<TestStruct>(testArena);
|
||||||
|
Assert(myStruct2->First == 0);
|
||||||
|
Assert(myStruct2->Second == 0);
|
||||||
|
|
||||||
|
myStruct->First = 5;
|
||||||
|
myStruct->Second = 125;
|
||||||
|
myStruct2->First = 5;
|
||||||
|
myStruct2->Second = 125;
|
||||||
|
|
||||||
|
ArenaClear(testArena);
|
||||||
|
pos = ArenaPos(testArena);
|
||||||
|
Assert(pos == k_ArenaHeaderSize);
|
||||||
|
|
||||||
|
myStruct = ArenaPushStruct<TestStruct>(testArena);
|
||||||
|
Assert(myStruct->First == 0);
|
||||||
|
Assert(myStruct->Second == 0);
|
||||||
|
pos = ArenaPos(testArena);
|
||||||
|
Assert(pos == k_ArenaHeaderSize + sizeof(TestStruct));
|
||||||
|
|
||||||
|
TestStruct* myStruct3 = ArenaPushStruct<TestStruct>(testArena);
|
||||||
|
Assert(myStruct3->First == 0);
|
||||||
|
Assert(myStruct3->Second == 0);
|
||||||
|
pos = ArenaPos(testArena);
|
||||||
|
Assert(pos == k_ArenaHeaderSize + sizeof(TestStruct) * 2);
|
||||||
|
|
||||||
|
ArenaClear(testArena);
|
||||||
|
|
||||||
|
// TEST COMMIT
|
||||||
|
// Push more than the default commit size
|
||||||
|
uint8* myArray = ArenaPushArray<uint8>(testArena, 100'000);
|
||||||
|
*myArray = 5;
|
||||||
|
Assert(*myArray == 5);
|
||||||
|
bool isCommitSizeSame = testArena->Committed == (2 * param.CommitSize);
|
||||||
|
Assert(isCommitSizeSame);
|
||||||
|
ArenaClear(testArena);
|
||||||
|
|
||||||
|
// Push again above default commit size
|
||||||
|
myArray = ArenaPushArray<uint8>(testArena, 100'000);
|
||||||
|
// Shoud be zero again
|
||||||
|
Assert(*myArray == 0);
|
||||||
|
// Should not have commited more
|
||||||
|
isCommitSizeSame = testArena->Current->Committed == (2 * param.CommitSize);
|
||||||
|
Assert(isCommitSizeSame);
|
||||||
|
ArenaClear(testArena);
|
||||||
|
|
||||||
|
// TEST RESERVE
|
||||||
|
size_t posPreBigArray = ArenaPos(testArena);
|
||||||
|
size_t reservedSizePreBigArray = testArena->Current->Reserved;
|
||||||
|
|
||||||
|
size_t arraySize = Megabytes(100llu);
|
||||||
|
myArray = ArenaPushArray<uint8>(testArena, arraySize);
|
||||||
|
|
||||||
|
// Align and support the header size because we need to allocate a new block + header
|
||||||
|
size_t reserve_size = AlignPow2(arraySize + k_ArenaHeaderSize, AlignOf(uint8));
|
||||||
|
Assert(reserve_size == testArena->Current->Position);
|
||||||
|
Assert(reservedSizePreBigArray == testArena->Current->BasePosition);
|
||||||
|
|
||||||
|
// TODO Get page size from os kernel call (dwPageSize)
|
||||||
|
constexpr uint64 k_PageSizeUnitTest = Kilobytes(4);
|
||||||
|
size_t reserve_sizeAlignToPage = AlignPow2(reserve_size, k_PageSizeUnitTest);
|
||||||
|
|
||||||
|
bool isReserveSizeSame = testArena->Current->Reserved == reserve_sizeAlignToPage;
|
||||||
|
Assert(isReserveSizeSame);
|
||||||
|
Assert(testArena->Current->Reserved == testArena->Current->Committed);
|
||||||
|
|
||||||
|
size_t basePos = ArenaPos(testArena);
|
||||||
|
Assert(basePos == reserve_size + testArena->Current->BasePosition);
|
||||||
|
|
||||||
|
myStruct = ArenaPushStruct<TestStruct>(testArena);
|
||||||
|
|
||||||
|
// Should not delete the current block because we only delete the struct
|
||||||
|
ArenaPopTo(testArena, basePos);
|
||||||
|
Assert(testArena->Current->Previous != nullptr);
|
||||||
|
|
||||||
|
// Should still not delete the current block. We only remove the array
|
||||||
|
ArenaPop(testArena, arraySize);
|
||||||
|
Assert(testArena->Current->Previous != nullptr);
|
||||||
|
// We should only have the header remaining
|
||||||
|
Assert(testArena->Current->Position == k_ArenaHeaderSize);
|
||||||
|
|
||||||
|
// This one should delete the block
|
||||||
|
ArenaPopTo(testArena, posPreBigArray);
|
||||||
|
Assert(testArena->Current->Previous == nullptr);
|
||||||
|
|
||||||
|
ArenaRelease(testArena);
|
||||||
|
|
||||||
// Initialize FreeList (Simulate pool)
|
|
||||||
size_t blockSize = Kilobytes(128);
|
|
||||||
size_t numBlocks = testPoolSize / blockSize;
|
|
||||||
uint8* ptr = static_cast<uint8*>(testBacking);
|
|
||||||
for (size_t i = 0; i < numBlocks; ++i)
|
|
||||||
{
|
{
|
||||||
MemoryBlock* blk = reinterpret_cast<MemoryBlock*>(ptr + i * blockSize);
|
// Test reallocate
|
||||||
blk->Magic = MemoryBlock::kMagic;
|
Arena* arena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_ONLY(, "Test Realloc"));
|
||||||
blk->TotalSize = blockSize;
|
char* charArray = ArenaPushArray<char>(arena, 128);
|
||||||
blk->Used = 0;
|
char* secondCharArray = ArenaPushArray<char>(arena, 128);
|
||||||
blk->Next = pool.FreeList;
|
char* thirdCharArray = ArenaPushArray<char>(arena, 128);
|
||||||
pool.FreeList = blk;
|
|
||||||
|
secondCharArray = static_cast<char*>(ArenaReallocate(arena, secondCharArray, 128, 256, alignof(char), true JULIET_DEBUG_ONLY(, "ReallocChar")));
|
||||||
|
|
||||||
|
char* fourthCharArray = ArenaPushArray<char>(arena, 128);
|
||||||
|
|
||||||
|
Assert(charArray);
|
||||||
|
Assert(secondCharArray);
|
||||||
|
Assert(thirdCharArray);
|
||||||
|
Assert(fourthCharArray);
|
||||||
|
|
||||||
|
ArenaRelease(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryArena arena;
|
{
|
||||||
MemoryArenaCreate(&arena, &pool);
|
// Test Reallocate Shrink (Buffer Overflow Bug Check)
|
||||||
|
Arena* arena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_ONLY(, "Test Shrink"));
|
||||||
|
|
||||||
// 5. Arena Pop
|
size_t largeSize = 100;
|
||||||
// Align sizes to 16 to avoid padding issues during Pop
|
char* large = ArenaPushArray<char>(arena, largeSize);
|
||||||
void* pop1 = ArenaPush(&arena, 5008, 16, ConstString("Pop1"));
|
MemSet(large, 'A', largeSize);
|
||||||
|
|
||||||
void* pop2 = ArenaPush(&arena, 208, 16, ConstString("Pop2"));
|
size_t smallSize = 50;
|
||||||
// Pop Middle (Should Fail)
|
char* smallData = static_cast<char*>(ArenaReallocate(arena, large, largeSize, smallSize, alignof(char), true JULIET_DEBUG_ONLY(, "ResizeSmall")));
|
||||||
bool res1 = ArenaPop(&arena, pop1, 5008);
|
|
||||||
Assert(res1 == false);
|
|
||||||
|
|
||||||
// Pop Top (Should Success)
|
for (size_t i = 0; i < smallSize; ++i)
|
||||||
bool res2 = ArenaPop(&arena, pop2, 208); // 200->208
|
{
|
||||||
Assert(res2 == true);
|
Assert(smallData[i] == 'A');
|
||||||
|
}
|
||||||
|
|
||||||
// Verify Used space is back to pop1 end
|
// Allocate next block (should be immediately after 'small')
|
||||||
Assert(arena.CurrentBlock->Used == ArenaGetMarker(&arena).Offset); // This usage of GetMarker is valid if marker was implicit?
|
// Don't zero it, if overflow happened it will contain 'A's
|
||||||
// Actually we didn't take a marker.
|
char* next = static_cast<char*>(ArenaPush(arena, 50, alignof(char), false JULIET_DEBUG_ONLY(, "OverflowCheck")));
|
||||||
// We can verify by allocating pop3. It should overwrite pop2 location.
|
|
||||||
void* pop3 = ArenaPush(&arena, 16, 16, ConstString("Pop3"));
|
|
||||||
Assert(pop3 == pop2);
|
|
||||||
|
|
||||||
// Cleanup popped items from stack logic for reset...
|
bool corrupted = false;
|
||||||
// Pop pop3
|
for(size_t i = 0; i < 50; ++i)
|
||||||
ArenaPop(&arena, pop3, 16);
|
{
|
||||||
// Pop pop1
|
if (next[i] == 'A')
|
||||||
ArenaPop(&arena, pop1, 5008);
|
{
|
||||||
Assert(arena.CurrentBlock->Used == 0); // Should be effectively 0
|
corrupted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
printf("[Success] Arena Pop\n");
|
Assert(!corrupted);
|
||||||
|
|
||||||
// Cleanup
|
ArenaRelease(arena);
|
||||||
SafeFree(testBacking);
|
}
|
||||||
|
|
||||||
printf("All Paged MemoryArena tests passed.\n");
|
printf("All Paged MemoryArena tests passed.\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,11 @@
|
|||||||
// Windows uses a non standard header to define its socket types.
|
// Windows uses a non standard header to define its socket types.
|
||||||
// Because of that we need to include those in this header.
|
// Because of that we need to include those in this header.
|
||||||
// TODO : implement for other platforms
|
// TODO : implement for other platforms
|
||||||
#if JULIET_WIN32
|
// #if JULIET_WIN32
|
||||||
|
// #include <WinSock2.h>
|
||||||
#include <WinSock2.h>
|
// #else
|
||||||
|
// // UNIMPLEMENT_SOCKETS
|
||||||
#else
|
// #endif
|
||||||
// UNIMPLEMENT_SOCKETS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Juliet::SocketImpl
|
namespace Juliet::SocketImpl
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <Core/HAL/Win32.h>
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Logging/LogTypes.h>
|
#include <Core/Logging/LogTypes.h>
|
||||||
#include <Core/Networking/Socket.h>
|
#include <Core/Networking/Socket.h>
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
#include <Core/Common/String.h>
|
#include <Core/Common/String.h>
|
||||||
#include <Core/Memory/EngineArena.h>
|
#include <Core/Container/Vector.h>
|
||||||
|
#include <Core/Memory/MemoryArena.h> // Added for Arena definition
|
||||||
|
#include <Core/Memory/MemoryArenaDebug.h>
|
||||||
#include <Engine/Debug/MemoryDebugger.h>
|
#include <Engine/Debug/MemoryDebugger.h>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#if JULIET_DEBUG
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
Arena* GetGlobalArenaListHead();
|
||||||
|
} // namespace Juliet
|
||||||
|
|
||||||
namespace Juliet::Debug
|
namespace Juliet::Debug
|
||||||
{
|
{
|
||||||
@@ -17,153 +25,189 @@ namespace Juliet::Debug
|
|||||||
bool ScrollListToSelected = false;
|
bool ScrollListToSelected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArenaDebugState& GetState(const String& name)
|
struct PagedArenaDebugState
|
||||||
{
|
{
|
||||||
// Simple static map-like storage using standard map would be better but we minimize deps.
|
float Zoom = 1.0f;
|
||||||
// Just use a few static vars since we have known 3 arenas.
|
ArenaDebugInfo* SelectedAlloc = nullptr;
|
||||||
static ArenaDebugState s_GameState;
|
bool ScrollVisualToSelected = false;
|
||||||
static ArenaDebugState s_EngineState;
|
bool ScrollListToSelected = false;
|
||||||
static ArenaDebugState s_ScratchState;
|
};
|
||||||
|
|
||||||
if (StringCompare(name, ConstString("Game Arena")) == 0)
|
struct PagedArenaStateEntry
|
||||||
{
|
{
|
||||||
return s_GameState;
|
const Arena* Arena;
|
||||||
}
|
PagedArenaDebugState State;
|
||||||
if (StringCompare(name, ConstString("Engine Arena")) == 0)
|
};
|
||||||
|
|
||||||
|
// Static Vector for lookup
|
||||||
|
VectorArena<PagedArenaStateEntry> s_PagedArenaStates;
|
||||||
|
|
||||||
|
PagedArenaDebugState& GetPagedArenaState(const Arena* arena)
|
||||||
{
|
{
|
||||||
return s_EngineState;
|
if (s_PagedArenaStates.Arena == nullptr)
|
||||||
}
|
{
|
||||||
return s_ScratchState;
|
s_PagedArenaStates.Create(JULIET_DEBUG_ONLY("DebugState States"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
for (auto& entry : s_PagedArenaStates)
|
||||||
// Generate a stable color from a string tag
|
|
||||||
uint32 GetColorForTag(const String& tag)
|
|
||||||
{
|
{
|
||||||
uint32 hash = 0;
|
if (entry.Arena == arena)
|
||||||
size_t len = tag.Size;
|
|
||||||
const char* s = tag.Data;
|
|
||||||
// Simple FNV-1a style hash
|
|
||||||
for (size_t i = 0; i < len; ++i)
|
|
||||||
{
|
{
|
||||||
hash = hash * 65599 + (uint8)s[i];
|
return entry.State;
|
||||||
}
|
}
|
||||||
// Use hash to pick a Hue
|
}
|
||||||
|
|
||||||
|
PagedArenaStateEntry newEntry;
|
||||||
|
newEntry.Arena = arena;
|
||||||
|
// Default construct state
|
||||||
|
newEntry.State = PagedArenaDebugState();
|
||||||
|
|
||||||
|
s_PagedArenaStates.PushBack(newEntry);
|
||||||
|
return s_PagedArenaStates.Last()->State;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a unique color per allocation, using tag + offset + size
|
||||||
|
// so entries with same tag name get distinct colors
|
||||||
|
uint32 GetColorForAllocation(const char* tag, size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
uint32 hash = 2166136261u;
|
||||||
|
if (tag)
|
||||||
|
{
|
||||||
|
for (const char* s = tag; *s; ++s)
|
||||||
|
{
|
||||||
|
hash ^= static_cast<uint8>(*s);
|
||||||
|
hash *= 16777619u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mix in offset and size to differentiate same-tag entries
|
||||||
|
hash ^= static_cast<uint32>(offset);
|
||||||
|
hash *= 16777619u;
|
||||||
|
hash ^= static_cast<uint32>(size);
|
||||||
|
hash *= 16777619u;
|
||||||
|
|
||||||
float h = static_cast<float>(hash % 360) / 360.0f;
|
float h = static_cast<float>(hash % 360) / 360.0f;
|
||||||
return ImColor::HSV(h, 0.7f, 0.8f);
|
float s = 0.5f + static_cast<float>((hash >> 12) % 30) / 100.0f;
|
||||||
|
float v = 0.65f + static_cast<float>((hash >> 20) % 25) / 100.0f;
|
||||||
|
return ImColor::HSV(h, s, v);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void DrawMemoryArena(String name, const MemoryArena& arena, [[maybe_unused]] ArenaAllocation* currentHighlight,
|
void DrawPagedArena(const Arena* arena)
|
||||||
[[maybe_unused]] ArenaAllocation*& outNewHighlight)
|
|
||||||
{
|
{
|
||||||
ArenaDebugState& state = GetState(name);
|
ImGui::PushID(arena);
|
||||||
|
const char* name = (arena->Name && arena->Name[0] != '\0') ? arena->Name : "Unnamed Arena";
|
||||||
|
PagedArenaDebugState& state = GetPagedArenaState(arena);
|
||||||
|
|
||||||
if (ImGui::CollapsingHeader(CStr(name), ImGuiTreeNodeFlags_DefaultOpen))
|
if (ImGui::CollapsingHeader(name))
|
||||||
{
|
{
|
||||||
ImGui::PushID(CStr(name));
|
// Collect Blocks (Pages) in order (Oldest -> Newest)
|
||||||
|
// Arena->Previous chain goes Newest -> Oldest.
|
||||||
|
static VectorArena<const Arena*> blocks;
|
||||||
|
if (blocks.Arena == nullptr)
|
||||||
|
{
|
||||||
|
blocks.Create(JULIET_DEBUG_ONLY("DebugState Blocks"));
|
||||||
|
}
|
||||||
|
blocks.Clear();
|
||||||
|
|
||||||
|
for (const Arena* curr = arena->Current; curr != nullptr; curr = curr->Previous)
|
||||||
|
{
|
||||||
|
blocks.PushBack(curr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse manually
|
||||||
|
size_t count = blocks.Count;
|
||||||
|
for (size_t i = 0; i < count / 2; ++i)
|
||||||
|
{
|
||||||
|
const Arena* temp = blocks[i];
|
||||||
|
blocks[i] = blocks[count - 1 - i];
|
||||||
|
blocks[count - 1 - i] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate Stats
|
// Calculate Stats
|
||||||
size_t totalCapacity = 0;
|
size_t totalCapacity = 0;
|
||||||
size_t totalUsed = 0;
|
size_t totalUsed = 0;
|
||||||
size_t blockCount = 0;
|
|
||||||
|
|
||||||
MemoryBlock* curr = arena.FirstBlock;
|
for (const Arena* blk : blocks)
|
||||||
while (curr)
|
|
||||||
{
|
{
|
||||||
totalCapacity += curr->TotalSize;
|
totalCapacity += blk->Reserved;
|
||||||
totalUsed += curr->Used;
|
totalUsed += blk->Position;
|
||||||
blockCount++;
|
|
||||||
curr = curr->Next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Used: %zu / %zu bytes (%zu blocks)", totalUsed, totalCapacity, blockCount);
|
ImGui::Text("Used: %zu / %zu bytes (%zu pages)", totalUsed, totalCapacity, blocks.Size());
|
||||||
|
ImGui::SliderFloat("Zoom", &state.Zoom, 0.1f, 1000000.0f, "%.2f", ImGuiSliderFlags_Logarithmic);
|
||||||
|
|
||||||
// Zoom Control
|
// --- Visual View ---
|
||||||
ImGui::SliderFloat("Zoom", &state.Zoom, 0.1f, 1000.0f, "%.2f");
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
// --- Visual View (Scrollable + Zoom) ---
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Visual Map");
|
ImGui::Text("Visual Map");
|
||||||
|
|
||||||
// Calculate Dynamic Height
|
|
||||||
// Height = blockCount * (blockHeight + spacing) + padding
|
|
||||||
// Constrain between minHeight and maxHeight
|
|
||||||
float blockHeight = 24.0f;
|
float blockHeight = 24.0f;
|
||||||
float blockSpacing = 4.0f;
|
float blockSpacing = 4.0f;
|
||||||
// Add extra padding to avoid vertical scrollbar triggering due to varying style padding
|
float requiredVisHeight = static_cast<float>(blocks.Size()) * (blockHeight + blockSpacing) + 30.0f;
|
||||||
float requiredVisHeight = (float)blockCount * (blockHeight + blockSpacing) + 30.0f;
|
// constrains
|
||||||
if (requiredVisHeight > 300.0f) requiredVisHeight = 300.0f;
|
if (requiredVisHeight > 300.0f)
|
||||||
if (requiredVisHeight < 50.0f) requiredVisHeight = 50.0f;
|
{
|
||||||
|
requiredVisHeight = 300.0f;
|
||||||
|
}
|
||||||
|
if (requiredVisHeight < 50.0f)
|
||||||
|
{
|
||||||
|
requiredVisHeight = 50.0f;
|
||||||
|
}
|
||||||
|
|
||||||
// Use ImGuiWindowFlags_NoScrollbar if we fit?
|
|
||||||
// No, we want horizontal scrollbar. If we provide just enough height, vertical shouldn't show.
|
|
||||||
if (ImGui::BeginChild("VisualMap", ImVec2(0, requiredVisHeight), true,
|
if (ImGui::BeginChild("VisualMap", ImVec2(0, requiredVisHeight), true,
|
||||||
ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar))
|
ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar))
|
||||||
{
|
{
|
||||||
ImGui::SetScrollY(0.0f); // Lock Vertical Scroll to separate Zoom from Scroll
|
ImGui::SetScrollY(0.0f);
|
||||||
|
|
||||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||||
float availWidth = ImGui::GetContentRegionAvail().x;
|
float availWidth = ImGui::GetContentRegionAvail().x;
|
||||||
ImVec2 startPos = ImGui::GetCursorScreenPos();
|
ImVec2 startPos = ImGui::GetCursorScreenPos();
|
||||||
|
|
||||||
// Reserve space for the virtual width FIRST to satisfy layout
|
|
||||||
// Also reserve explicit height > window height to ensure Child captures MouseWheel (stops bubbling)
|
|
||||||
float virtualWidth = availWidth * state.Zoom;
|
float virtualWidth = availWidth * state.Zoom;
|
||||||
if (virtualWidth < availWidth) virtualWidth = availWidth;
|
if (virtualWidth < availWidth)
|
||||||
|
{
|
||||||
|
virtualWidth = availWidth;
|
||||||
|
}
|
||||||
ImGui::Dummy(ImVec2(virtualWidth, requiredVisHeight + 1.0f));
|
ImGui::Dummy(ImVec2(virtualWidth, requiredVisHeight + 1.0f));
|
||||||
|
|
||||||
bool isMapHovered = ImGui::IsWindowHovered();
|
bool isMapHovered = ImGui::IsWindowHovered();
|
||||||
|
|
||||||
// Interaction Logic
|
// Zoom with pivot
|
||||||
// 1. Zoom with Pivot
|
|
||||||
if (isMapHovered)
|
if (isMapHovered)
|
||||||
{
|
{
|
||||||
float wheel = ImGui::GetIO().MouseWheel;
|
float wheel = ImGui::GetIO().MouseWheel;
|
||||||
if (wheel != 0.0f)
|
if (wheel != 0.0f)
|
||||||
{
|
{
|
||||||
// Pivot Logic
|
|
||||||
float mouseXScreen = ImGui::GetMousePos().x;
|
float mouseXScreen = ImGui::GetMousePos().x;
|
||||||
float activeScrollX = ImGui::GetScrollX();
|
float activeScrollX = ImGui::GetScrollX();
|
||||||
|
|
||||||
// Viewport Left
|
|
||||||
float viewportLeft = ImGui::GetWindowPos().x;
|
float viewportLeft = ImGui::GetWindowPos().x;
|
||||||
float mouseRelViewport = mouseXScreen - viewportLeft;
|
float mouseRelViewport = mouseXScreen - viewportLeft;
|
||||||
|
|
||||||
// Current Ratio
|
|
||||||
float virtualWidthOld = std::max(availWidth * state.Zoom, availWidth);
|
float virtualWidthOld = std::max(availWidth * state.Zoom, availWidth);
|
||||||
float mouseContentPos = activeScrollX + mouseRelViewport;
|
float mouseContentPos = activeScrollX + mouseRelViewport;
|
||||||
float ratio = mouseContentPos / virtualWidthOld;
|
float ratio = mouseContentPos / virtualWidthOld;
|
||||||
|
|
||||||
// Apply Zoom
|
|
||||||
state.Zoom += wheel * 0.2f * state.Zoom;
|
state.Zoom += wheel * 0.2f * state.Zoom;
|
||||||
if (state.Zoom < 0.1f) state.Zoom = 0.1f;
|
state.Zoom = std::max(state.Zoom, 0.1f);
|
||||||
if (state.Zoom > 1000.0f) state.Zoom = 1000.0f;
|
state.Zoom = std::min(state.Zoom, 1000000.0f);
|
||||||
|
|
||||||
// New Ratio
|
|
||||||
float virtualWidthNew = std::max(availWidth * state.Zoom, availWidth);
|
float virtualWidthNew = std::max(availWidth * state.Zoom, availWidth);
|
||||||
|
|
||||||
// flNewScroll + MouseRel = Ratio * NewWidth
|
|
||||||
float desiredScrollX = (ratio * virtualWidthNew) - mouseRelViewport;
|
float desiredScrollX = (ratio * virtualWidthNew) - mouseRelViewport;
|
||||||
ImGui::SetScrollX(desiredScrollX);
|
ImGui::SetScrollX(desiredScrollX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Pan (Left, Right, or Middle Mouse)
|
// Pan
|
||||||
if (isMapHovered && (ImGui::IsMouseDragging(ImGuiMouseButton_Left) || ImGui::IsMouseDragging(ImGuiMouseButton_Right) ||
|
if (isMapHovered && (ImGui::IsMouseDragging(ImGuiMouseButton_Left) || ImGui::IsMouseDragging(ImGuiMouseButton_Right) ||
|
||||||
ImGui::IsMouseDragging(ImGuiMouseButton_Middle)))
|
ImGui::IsMouseDragging(ImGuiMouseButton_Middle)))
|
||||||
{
|
{
|
||||||
ImGui::SetScrollX(ImGui::GetScrollX() - ImGui::GetIO().MouseDelta.x);
|
ImGui::SetScrollX(ImGui::GetScrollX() - ImGui::GetIO().MouseDelta.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Jump to Selected (Sync from List)
|
// Jump to Selected (Sync from List)
|
||||||
if (state.ScrollVisualToSelected && state.SelectedAlloc)
|
if (state.ScrollVisualToSelected && state.SelectedAlloc)
|
||||||
{
|
{
|
||||||
MemoryBlock* searchBlk = arena.FirstBlock;
|
for (const Arena* searchBlk : blocks)
|
||||||
while (searchBlk)
|
|
||||||
{
|
{
|
||||||
ArenaAllocation* search = searchBlk->FirstAllocation;
|
ArenaDebugInfo* search = searchBlk->FirstDebugInfo;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
while (search)
|
while (search)
|
||||||
{
|
{
|
||||||
@@ -178,64 +222,173 @@ namespace Juliet::Debug
|
|||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
float virtualWidthLocal = std::max(availWidth * state.Zoom, availWidth);
|
float virtualWidthLocal = std::max(availWidth * state.Zoom, availWidth);
|
||||||
size_t dataSize = searchBlk->TotalSize - sizeof(MemoryBlock);
|
if (searchBlk->Reserved > 0)
|
||||||
if (dataSize > 0)
|
|
||||||
{
|
{
|
||||||
double scale = (double)virtualWidthLocal / (double)dataSize;
|
double scale =
|
||||||
float xStart = (float)((double)state.SelectedAlloc->Offset * scale);
|
static_cast<double>(virtualWidthLocal) / static_cast<double>(searchBlk->Reserved);
|
||||||
|
float xStart = static_cast<float>(static_cast<double>(state.SelectedAlloc->Offset) * scale);
|
||||||
// Scroll to center xStart
|
|
||||||
float centerOffset = availWidth * 0.5f;
|
float centerOffset = availWidth * 0.5f;
|
||||||
ImGui::SetScrollX(xStart - centerOffset);
|
ImGui::SetScrollX(xStart - centerOffset);
|
||||||
}
|
}
|
||||||
state.ScrollVisualToSelected = false; // Consumed
|
state.ScrollVisualToSelected = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
searchBlk = searchBlk->Next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryBlock* blk = arena.FirstBlock;
|
|
||||||
ImVec2 pos = startPos;
|
ImVec2 pos = startPos;
|
||||||
|
for (const Arena* blk : blocks)
|
||||||
int bIdx = 0;
|
|
||||||
while (blk)
|
|
||||||
{
|
{
|
||||||
// Draw Block Frame
|
ImGui::PushID(blk);
|
||||||
ImVec2 rectMin = pos;
|
ImVec2 rectMin = pos;
|
||||||
auto rectMax = ImVec2(pos.x + virtualWidth, pos.y + blockHeight);
|
ImVec2 rectMax = ImVec2(pos.x + virtualWidth, pos.y + blockHeight);
|
||||||
|
|
||||||
// Border Color
|
dl->AddRect(rectMin, rectMax, IM_COL32(100, 100, 100, 255));
|
||||||
ImU32 borderColor = (uint32)ImColor::HSV(((float)bIdx * 0.1f), 0.0f, 0.7f);
|
|
||||||
dl->AddRect(rectMin, rectMax, borderColor);
|
|
||||||
|
|
||||||
size_t dataSize = blk->TotalSize - sizeof(MemoryBlock);
|
size_t dataSize = blk->Reserved - k_ArenaHeaderSize;
|
||||||
if (dataSize > 0)
|
if (dataSize > 0)
|
||||||
{
|
{
|
||||||
double scale = (double)virtualWidth / (double)dataSize;
|
double scale = static_cast<double>(virtualWidth) / static_cast<double>(blk->Reserved);
|
||||||
|
|
||||||
ArenaAllocation* alloc = blk->FirstAllocation;
|
// Draw Arena Header
|
||||||
while (alloc)
|
|
||||||
{
|
{
|
||||||
float xStart = pos.x + (float)((double)alloc->Offset * scale);
|
float hdrWidth = static_cast<float>(static_cast<double>(k_ArenaHeaderSize) * scale);
|
||||||
float width = (float)((double)alloc->Size * scale);
|
hdrWidth = std::max(hdrWidth, 1.0f);
|
||||||
|
ImVec2 hMin(pos.x, pos.y + 1);
|
||||||
|
ImVec2 hMax(pos.x + hdrWidth, pos.y + blockHeight - 1);
|
||||||
|
dl->AddRectFilled(hMin, hMax, IM_COL32(40, 60, 120, 255));
|
||||||
|
|
||||||
|
if (hdrWidth > 30.0f)
|
||||||
|
{
|
||||||
|
const char* hdrLabel = "Header";
|
||||||
|
ImVec2 textSize = ImGui::CalcTextSize(hdrLabel);
|
||||||
|
if (hdrWidth >= textSize.x + 4.0f)
|
||||||
|
{
|
||||||
|
float textX = hMin.x + (hdrWidth - textSize.x) * 0.5f;
|
||||||
|
float textY = hMin.y + (blockHeight - 2.0f - textSize.y) * 0.5f;
|
||||||
|
dl->AddText(ImVec2(textX, textY), IM_COL32(180, 200, 255, 255), hdrLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::IsMouseHoveringRect(hMin, hMax) && ImGui::IsWindowHovered())
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::TextColored(ImVec4(0.5f, 0.6f, 0.9f, 1.0f), "Arena Header");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Size: %zu bytes", k_ArenaHeaderSize);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw Allocations
|
||||||
|
ArenaDebugInfo* info = blk->FirstDebugInfo;
|
||||||
|
size_t expectedOffset = k_ArenaHeaderSize;
|
||||||
|
while (info)
|
||||||
|
{
|
||||||
|
// Draw alignment padding gap if present (only for small gaps that are actual alignment)
|
||||||
|
if (info->Offset > expectedOffset)
|
||||||
|
{
|
||||||
|
size_t padSize = info->Offset - expectedOffset;
|
||||||
|
constexpr size_t k_MaxAlignmentPadding = 256;
|
||||||
|
float padXStart = pos.x + static_cast<float>(static_cast<double>(expectedOffset) * scale);
|
||||||
|
float padWidth = static_cast<float>(static_cast<double>(padSize) * scale);
|
||||||
|
|
||||||
|
if (padSize <= k_MaxAlignmentPadding && padWidth >= 1.0f)
|
||||||
|
{
|
||||||
|
ImVec2 pMin(padXStart, pos.y + 1);
|
||||||
|
ImVec2 pMax(padXStart + padWidth, pos.y + blockHeight - 1);
|
||||||
|
|
||||||
|
// Clip
|
||||||
|
if (pMin.x < rectMin.x)
|
||||||
|
{
|
||||||
|
pMin.x = rectMin.x;
|
||||||
|
}
|
||||||
|
if (pMax.x > rectMax.x)
|
||||||
|
{
|
||||||
|
pMax.x = rectMax.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw hatched pattern (diagonal lines) - clipped to visible area
|
||||||
|
float visLeft = ImGui::GetWindowPos().x;
|
||||||
|
float visRight = visLeft + ImGui::GetWindowSize().x;
|
||||||
|
float clippedLeft = std::max(pMin.x, visLeft);
|
||||||
|
float clippedRight = std::min(pMax.x, visRight);
|
||||||
|
|
||||||
|
dl->AddRectFilled(pMin, pMax, IM_COL32(30, 30, 30, 200));
|
||||||
|
if (clippedLeft < clippedRight)
|
||||||
|
{
|
||||||
|
float step = 6.0f;
|
||||||
|
float startX = clippedLeft - (pMax.y - pMin.y);
|
||||||
|
startX = pMin.x + step * std::floor((startX - pMin.x) / step);
|
||||||
|
if (startX < pMin.x)
|
||||||
|
{
|
||||||
|
startX = pMin.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineCount = 0;
|
||||||
|
for (float lx = startX; lx < clippedRight && lineCount < 500; lx += step, ++lineCount)
|
||||||
|
{
|
||||||
|
float ly0 = pMin.y;
|
||||||
|
float lx1 = lx + (pMax.y - pMin.y);
|
||||||
|
float ly1 = pMax.y;
|
||||||
|
if (lx1 > pMax.x)
|
||||||
|
{
|
||||||
|
ly1 = pMin.y + (pMax.x - lx);
|
||||||
|
lx1 = pMax.x;
|
||||||
|
}
|
||||||
|
dl->AddLine(ImVec2(lx, ly0), ImVec2(lx1, ly1), IM_COL32(80, 80, 80, 180));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Label when zoomed
|
||||||
|
if (padWidth > 30.0f)
|
||||||
|
{
|
||||||
|
const char* padLabel = "Pad";
|
||||||
|
ImVec2 textSize = ImGui::CalcTextSize(padLabel);
|
||||||
|
if (padWidth >= textSize.x + 4.0f)
|
||||||
|
{
|
||||||
|
float textX = pMin.x + (padWidth - textSize.x) * 0.5f;
|
||||||
|
float textY = pMin.y + (blockHeight - 2.0f - textSize.y) * 0.5f;
|
||||||
|
dl->AddText(ImVec2(textX, textY), IM_COL32(120, 120, 120, 255), padLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::IsMouseHoveringRect(pMin, pMax) && ImGui::IsWindowHovered())
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "Alignment Padding");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Size: %zu bytes", padSize);
|
||||||
|
ImGui::Text("Offset: %zu - %zu", expectedOffset, info->Offset);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expectedOffset = info->Offset + info->Size;
|
||||||
|
|
||||||
|
ImGui::PushID(info);
|
||||||
|
float xStart = pos.x + static_cast<float>(static_cast<double>(info->Offset) * scale);
|
||||||
|
float width = static_cast<float>(static_cast<double>(info->Size) * scale);
|
||||||
width = std::max(width, 1.0f);
|
width = std::max(width, 1.0f);
|
||||||
|
|
||||||
auto aMin = ImVec2(xStart, pos.y + 1);
|
ImVec2 aMin(xStart, pos.y + 1);
|
||||||
auto aMax = ImVec2(xStart + width, pos.y + blockHeight - 1);
|
ImVec2 aMax(xStart + width, pos.y + blockHeight - 1);
|
||||||
|
|
||||||
// Clip visually to block bounds (simplistic)
|
// Clip to block bounds
|
||||||
if (aMin.x < rectMin.x) aMin.x = rectMin.x;
|
if (aMin.x < rectMin.x)
|
||||||
if (aMax.x > rectMax.x) aMax.x = rectMax.x;
|
{
|
||||||
|
aMin.x = rectMin.x;
|
||||||
ImU32 color = GetColorForTag(alloc->Tag);
|
}
|
||||||
|
if (aMax.x > rectMax.x)
|
||||||
bool isSelected = (state.SelectedAlloc == alloc);
|
{
|
||||||
bool isHovered = (currentHighlight == alloc);
|
aMax.x = rectMax.x;
|
||||||
|
}
|
||||||
if (isSelected || isHovered)
|
|
||||||
|
ImU32 color = GetColorForAllocation(info->Tag, info->Offset, info->Size);
|
||||||
|
bool isSelected = (state.SelectedAlloc == info);
|
||||||
|
|
||||||
|
if (isSelected)
|
||||||
{
|
{
|
||||||
// Highlight
|
|
||||||
dl->AddRectFilled(aMin, aMax, IM_COL32_WHITE);
|
dl->AddRectFilled(aMin, aMax, IM_COL32_WHITE);
|
||||||
dl->AddRect(aMin, aMax, IM_COL32_BLACK);
|
dl->AddRect(aMin, aMax, IM_COL32_BLACK);
|
||||||
}
|
}
|
||||||
@@ -244,115 +397,132 @@ namespace Juliet::Debug
|
|||||||
dl->AddRectFilled(aMin, aMax, color);
|
dl->AddRectFilled(aMin, aMax, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw Text if zoomed enough and fits
|
// Draw text label when zoomed enough
|
||||||
if (width > 20.0f) // Threshold width to attempt drawing text
|
if (width > 20.0f && info->Tag)
|
||||||
{
|
{
|
||||||
// Need to check actual text size
|
const char* tagStr = info->Tag;
|
||||||
ImVec2 textSize = ImGui::CalcTextSize(alloc->Tag.Data, alloc->Tag.Data + alloc->Tag.Size);
|
size_t tagLen = 0;
|
||||||
|
while (tagStr[tagLen] != '\0')
|
||||||
|
{
|
||||||
|
++tagLen;
|
||||||
|
}
|
||||||
|
ImVec2 textSize = ImGui::CalcTextSize(tagStr, tagStr + tagLen);
|
||||||
if (width >= textSize.x + 4.0f)
|
if (width >= textSize.x + 4.0f)
|
||||||
{
|
{
|
||||||
// Center text
|
|
||||||
float textX = aMin.x + (width - textSize.x) * 0.5f;
|
float textX = aMin.x + (width - textSize.x) * 0.5f;
|
||||||
float textY = aMin.y + (blockHeight - 2.0f - textSize.y) * 0.5f;
|
float textY = aMin.y + (blockHeight - 2.0f - textSize.y) * 0.5f;
|
||||||
|
|
||||||
// Contrast color
|
|
||||||
ImU32 textColor = IM_COL32_BLACK;
|
ImU32 textColor = IM_COL32_BLACK;
|
||||||
dl->AddText(ImVec2(textX, textY), textColor, alloc->Tag.Data,
|
dl->AddText(ImVec2(textX, textY), textColor, tagStr, tagStr + tagLen);
|
||||||
alloc->Tag.Data + alloc->Tag.Size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::IsMouseHoveringRect(aMin, aMax) && ImGui::IsWindowHovered())
|
if (ImGui::IsMouseHoveringRect(aMin, aMax) && ImGui::IsWindowHovered())
|
||||||
{
|
{
|
||||||
outNewHighlight = alloc;
|
|
||||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
|
|
||||||
{
|
|
||||||
state.SelectedAlloc = alloc;
|
|
||||||
state.ScrollListToSelected = true; // Sync to list
|
|
||||||
state.ScrollVisualToSelected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("Tag: %.*s", (int)alloc->Tag.Size, alloc->Tag.Data);
|
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", info->Tag);
|
||||||
ImGui::Text("Size: %zu bytes", alloc->Size);
|
ImGui::Separator();
|
||||||
ImGui::Text("Offset: %zu", alloc->Offset);
|
ImGui::Text("Size: %zu bytes", info->Size);
|
||||||
|
ImGui::Text("Offset: %zu", info->Offset);
|
||||||
|
|
||||||
uint8* dataPtr = blk->GetData() + alloc->Offset;
|
// Hex data dump (first 16 bytes)
|
||||||
|
ImGui::Separator();
|
||||||
|
uint8* dataPtr = reinterpret_cast<uint8*>(const_cast<Arena*>(blk)) + info->Offset;
|
||||||
ImGui::Text("Data: ");
|
ImGui::Text("Data: ");
|
||||||
for (int i = 0; i < 16 && i < (int)alloc->Size; ++i)
|
for (int i = 0; i < 16 && i < static_cast<int>(info->Size); ++i)
|
||||||
{
|
{
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("%02X", dataPtr[i]);
|
ImGui::Text("%02X", dataPtr[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
|
||||||
|
|
||||||
alloc = alloc->Next;
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
|
||||||
|
{
|
||||||
|
state.SelectedAlloc = info;
|
||||||
|
state.ScrollListToSelected = true;
|
||||||
|
state.ScrollVisualToSelected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos.y += blockHeight + 4;
|
info = info->Next;
|
||||||
blk = blk->Next;
|
ImGui::PopID();
|
||||||
bIdx++;
|
}
|
||||||
|
|
||||||
|
// Draw Free Nodes (Holes) if Realloc is enabled
|
||||||
|
if (arena->AllowRealloc && blk->FreeNodes)
|
||||||
|
{
|
||||||
|
ArenaFreeNode* freeNode = blk->FreeNodes;
|
||||||
|
while (freeNode)
|
||||||
|
{
|
||||||
|
float fxStart = pos.x + static_cast<float>(static_cast<double>(freeNode->Position) * scale);
|
||||||
|
float fWidth = static_cast<float>(static_cast<double>(freeNode->Size) * scale);
|
||||||
|
|
||||||
|
ImVec2 fMin(fxStart, pos.y + 1);
|
||||||
|
ImVec2 fMax(fxStart + fWidth, pos.y + blockHeight - 1);
|
||||||
|
|
||||||
|
dl->AddRectFilled(fMin, fMax, IM_COL32(50, 50, 50, 200));
|
||||||
|
|
||||||
|
freeNode = freeNode->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.y += blockHeight + blockSpacing;
|
||||||
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
// Final spacing
|
|
||||||
ImGui::Dummy(ImVec2(0, pos.y - startPos.y));
|
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
// --- Tree View (Scrollable) ---
|
// --- Tree View (Allocations List) ---
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::TreeNode("Allocations List"))
|
if (ImGui::TreeNode("Allocations List"))
|
||||||
{
|
{
|
||||||
// Calculate item count for Dynamic Height
|
// Calculate item count for dynamic height
|
||||||
int totalAllocCount = 0;
|
int totalAllocCount = 0;
|
||||||
MemoryBlock* countBlk = arena.FirstBlock;
|
for (const Arena* blk : blocks)
|
||||||
while (countBlk)
|
|
||||||
{
|
|
||||||
// Add 1 for Block Node
|
|
||||||
totalAllocCount++;
|
|
||||||
// If Block Node is Open? We don't know if we don't query it.
|
|
||||||
// But actually we are inside a Child window inside the TreeNode.
|
|
||||||
// We want the Child Window to be sized appropriately.
|
|
||||||
|
|
||||||
// Simplification: Just count ALL allocations to assume "expanded" state or just use a max cap.
|
|
||||||
// User wants "Grow until 25 elements".
|
|
||||||
// This implies if we have 5 items, height is small. If 100, height is capped at 25.
|
|
||||||
// We'll just count total allocations + blocks as a rough estimate of potential height.
|
|
||||||
ArenaAllocation* countAlloc = countBlk->FirstAllocation;
|
|
||||||
while (countAlloc)
|
|
||||||
{
|
{
|
||||||
totalAllocCount++;
|
totalAllocCount++;
|
||||||
countAlloc = countAlloc->Next;
|
ArenaDebugInfo* countInfo = blk->FirstDebugInfo;
|
||||||
|
while (countInfo)
|
||||||
|
{
|
||||||
|
totalAllocCount++;
|
||||||
|
countInfo = countInfo->Next;
|
||||||
}
|
}
|
||||||
countBlk = countBlk->Next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float lineHeight = ImGui::GetTextLineHeightWithSpacing();
|
float lineHeight = ImGui::GetTextLineHeightWithSpacing();
|
||||||
float currentNeededHeight = (float)totalAllocCount * lineHeight;
|
float currentNeededHeight = static_cast<float>(totalAllocCount) * lineHeight;
|
||||||
float maxHeight = lineHeight * 25.0f;
|
float maxHeight = lineHeight * 25.0f;
|
||||||
|
|
||||||
float listHeight = currentNeededHeight;
|
float listHeight = currentNeededHeight;
|
||||||
if (listHeight > maxHeight) listHeight = maxHeight;
|
if (listHeight > maxHeight)
|
||||||
if (listHeight < lineHeight) listHeight = lineHeight; // Min 1 line
|
{
|
||||||
|
listHeight = maxHeight;
|
||||||
|
}
|
||||||
|
if (listHeight < lineHeight)
|
||||||
|
{
|
||||||
|
listHeight = lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::BeginChild("AllocList", ImVec2(0, listHeight), true))
|
if (ImGui::BeginChild("AllocList", ImVec2(0, listHeight), true))
|
||||||
{
|
{
|
||||||
MemoryBlock* blk = arena.FirstBlock;
|
|
||||||
int blkIdx = 0;
|
int blkIdx = 0;
|
||||||
while (blk)
|
for (const Arena* blk : blocks)
|
||||||
{
|
{
|
||||||
if (ImGui::TreeNode((void*)blk, "Block %d (%zu bytes)", blkIdx, blk->TotalSize))
|
if (ImGui::TreeNode(reinterpret_cast<const void*>(blk), "Page %d (%zu bytes, pos %zu)",
|
||||||
|
blkIdx, blk->Reserved, blk->Position))
|
||||||
{
|
{
|
||||||
ArenaAllocation* alloc = blk->FirstAllocation;
|
ArenaDebugInfo* info = blk->FirstDebugInfo;
|
||||||
while (alloc)
|
if (!info)
|
||||||
{
|
{
|
||||||
bool isSelected = (state.SelectedAlloc == alloc);
|
ImGui::TextDisabled("No allocations");
|
||||||
bool isHovered = (currentHighlight == alloc);
|
}
|
||||||
|
while (info)
|
||||||
|
{
|
||||||
|
bool isSelected = (state.SelectedAlloc == info);
|
||||||
|
|
||||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
|
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
|
||||||
if (isSelected || isHovered)
|
if (isSelected)
|
||||||
{
|
{
|
||||||
flags |= ImGuiTreeNodeFlags_Selected;
|
flags |= ImGuiTreeNodeFlags_Selected;
|
||||||
}
|
}
|
||||||
@@ -360,36 +530,29 @@ namespace Juliet::Debug
|
|||||||
if (isSelected && state.ScrollListToSelected)
|
if (isSelected && state.ScrollListToSelected)
|
||||||
{
|
{
|
||||||
ImGui::SetScrollHereY();
|
ImGui::SetScrollHereY();
|
||||||
state.ScrollListToSelected = false; // Consumed
|
state.ScrollListToSelected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color Square
|
// Color Square
|
||||||
ImU32 color = GetColorForTag(alloc->Tag);
|
ImU32 color = GetColorForAllocation(info->Tag, info->Offset, info->Size);
|
||||||
ImGui::ColorButton("##color", ImColor(color),
|
ImGui::ColorButton("##color", ImColor(color),
|
||||||
ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop,
|
ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop,
|
||||||
ImVec2(12, 12));
|
ImVec2(12, 12));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
// Use implicit string length from String struct
|
ImGui::TreeNodeEx(info, flags, "[%zu] %s (%zu bytes)", info->Offset, info->Tag, info->Size);
|
||||||
ImGui::TreeNodeEx(alloc, flags, "[%zu] %.*s (%zu bytes)", alloc->Offset,
|
|
||||||
(int)alloc->Tag.Size, alloc->Tag.Data, alloc->Size);
|
|
||||||
|
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
{
|
{
|
||||||
state.SelectedAlloc = alloc;
|
state.SelectedAlloc = info;
|
||||||
state.ScrollVisualToSelected = true; // Sync to visual
|
state.ScrollVisualToSelected = true;
|
||||||
state.ScrollListToSelected = false;
|
state.ScrollListToSelected = false;
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
|
||||||
outNewHighlight = alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
alloc = alloc->Next;
|
info = info->Next;
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
blk = blk->Next;
|
|
||||||
blkIdx++;
|
blkIdx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,35 +560,58 @@ namespace Juliet::Debug
|
|||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
#else
|
}
|
||||||
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Compile with JULIET_DEBUG for Memory Visualization");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
ArenaAllocation* s_ConfirmedHovered = nullptr;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void DebugDrawMemoryArena()
|
void DebugDrawMemoryArena()
|
||||||
{
|
{
|
||||||
#if JULIET_DEBUG
|
|
||||||
// Cross-frame hover state
|
// Cross-frame hover state
|
||||||
static ArenaAllocation* s_ConfirmedHovered = nullptr;
|
|
||||||
ArenaAllocation* frameHovered = nullptr;
|
ArenaAllocation* frameHovered = nullptr;
|
||||||
#else
|
|
||||||
ArenaAllocation* s_ConfirmedHovered = nullptr;
|
|
||||||
ArenaAllocation* frameHovered = nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ImGui::Begin("Memory Debugger"))
|
if (ImGui::Begin("Memory Debugger"))
|
||||||
{
|
{
|
||||||
DrawMemoryArena(ConstString("Game Arena"), *GetGameArena(), s_ConfirmedHovered, frameHovered);
|
if (ImGui::BeginTabBar("ArenaTabs"))
|
||||||
DrawMemoryArena(ConstString("Engine Arena"), *GetEngineArena(), s_ConfirmedHovered, frameHovered);
|
{
|
||||||
|
if (ImGui::BeginTabItem("Paged Arenas"))
|
||||||
|
{
|
||||||
|
Arena* head = GetGlobalArenaListHead();
|
||||||
|
if (!head)
|
||||||
|
{
|
||||||
|
ImGui::Text("No active paged arenas.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (Arena* a = head; a != nullptr; a = a->GlobalNext)
|
||||||
|
{
|
||||||
|
// Skip test and internal debug arenas
|
||||||
|
if (a->Name)
|
||||||
|
{
|
||||||
|
bool isTest = (a->Name[0] == 'T' && a->Name[1] == 'e' && a->Name[2] == 's' && a->Name[3] == 't');
|
||||||
|
bool isDebugInfo =
|
||||||
|
(a->Name[0] == 'D' && a->Name[1] == 'e' && a->Name[2] == 'b' && a->Name[3] == 'u' &&
|
||||||
|
a->Name[4] == 'g' && a->Name[5] == ' ' && a->Name[6] == 'I');
|
||||||
|
if (isTest || isDebugInfo)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DrawPagedArena(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
s_ConfirmedHovered = frameHovered;
|
s_ConfirmedHovered = frameHovered;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
} // namespace Juliet::Debug
|
} // namespace Juliet::Debug
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#include <Core/Common/CoreUtils.h>
|
#include <Core/Common/CoreUtils.h>
|
||||||
|
#include <Core/HAL/Filesystem/Filesystem_Private.h>
|
||||||
#include <Core/JulietInit.h>
|
#include <Core/JulietInit.h>
|
||||||
#include <Core/Logging/LogManager.h>
|
#include <Core/Logging/LogManager.h>
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#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
|
||||||
@@ -16,6 +19,13 @@
|
|||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
|
#if JULIET_DEBUG
|
||||||
|
namespace UnitTest
|
||||||
|
{
|
||||||
|
extern void RunUnitTests();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
Engine EngineInstance;
|
Engine EngineInstance;
|
||||||
@@ -29,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
|
||||||
@@ -65,6 +85,8 @@ namespace Juliet
|
|||||||
if (device)
|
if (device)
|
||||||
{
|
{
|
||||||
DebugDisplay_Shutdown(device);
|
DebugDisplay_Shutdown(device);
|
||||||
|
ShutdownSkyboxRenderer();
|
||||||
|
ShutdownMeshRendererGraphics();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,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);
|
||||||
@@ -128,20 +153,36 @@ 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
|
||||||
|
UnitTest::RunUnitTests();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InitFilesystem();
|
||||||
|
|
||||||
JulietInit(flags);
|
JulietInit(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownEngine()
|
void ShutdownEngine()
|
||||||
{
|
{
|
||||||
JulietShutdown();
|
JulietShutdown();
|
||||||
|
|
||||||
|
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();
|
||||||
@@ -153,6 +194,9 @@ namespace Juliet
|
|||||||
ShutdownDependentSystems();
|
ShutdownDependentSystems();
|
||||||
|
|
||||||
EngineInstance.Application->Shutdown();
|
EngineInstance.Application->Shutdown();
|
||||||
|
|
||||||
|
ShutdownMeshRenderer();
|
||||||
|
|
||||||
EngineInstance.Application = nullptr;
|
EngineInstance.Application = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,9 +213,6 @@ namespace Juliet
|
|||||||
|
|
||||||
// Render tick
|
// Render tick
|
||||||
RenderFrame();
|
RenderFrame();
|
||||||
|
|
||||||
// Reset scratch arena at end of frame
|
|
||||||
ScratchArenaReset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ namespace Juliet::D3D12
|
|||||||
case BufferUsage::ConstantBuffer: return "ConstantBuffer";
|
case BufferUsage::ConstantBuffer: return "ConstantBuffer";
|
||||||
case BufferUsage::StructuredBuffer: return "StructuredBuffer";
|
case BufferUsage::StructuredBuffer: return "StructuredBuffer";
|
||||||
case BufferUsage::IndexBuffer: return "IndexBuffer";
|
case BufferUsage::IndexBuffer: return "IndexBuffer";
|
||||||
case BufferUsage::VertexBuffer: return "VertexBuffer";
|
|
||||||
}
|
}
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@@ -62,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;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case D3D12BufferType::Base:
|
|
||||||
{
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
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.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE;
|
|
||||||
break;
|
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)
|
||||||
|
{
|
||||||
|
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
||||||
|
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
}
|
}
|
||||||
case BufferUsage::ConstantBuffer:
|
else if (isUpload)
|
||||||
{
|
{
|
||||||
if (d3d12Driver->GPUUploadHeapSupported)
|
if (d3d12Driver->GPUUploadHeapSupported)
|
||||||
{
|
{
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
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;
|
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)
|
else
|
||||||
{
|
{
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE; // Or appropriate flags
|
// Must be a static buffer (Base type)
|
||||||
|
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case D3D12BufferType::TransferDownload:
|
|
||||||
{
|
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
|
||||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
heapFlags = D3D12_HEAP_FLAG_NONE;
|
|
||||||
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
|
||||||
|
|
||||||
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,6 +173,7 @@ namespace Juliet::D3D12
|
|||||||
|
|
||||||
if (usage == BufferUsage::ConstantBuffer)
|
if (usage == BufferUsage::ConstantBuffer)
|
||||||
{
|
{
|
||||||
|
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
||||||
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
||||||
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
||||||
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
||||||
@@ -209,13 +181,25 @@ namespace Juliet::D3D12
|
|||||||
else if (usage == BufferUsage::StructuredBuffer)
|
else if (usage == BufferUsage::StructuredBuffer)
|
||||||
{
|
{
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
|
||||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
srvDesc.Buffer.FirstElement = 0;
|
srvDesc.Buffer.FirstElement = 0;
|
||||||
|
|
||||||
|
if (stride > 0)
|
||||||
|
{
|
||||||
|
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
srvDesc.Buffer.NumElements = static_cast<uint32>(size / stride);
|
||||||
|
srvDesc.Buffer.StructureByteStride = static_cast<uint32>(stride);
|
||||||
|
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||||
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
|
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
|
||||||
srvDesc.Buffer.StructureByteStride = 0;
|
srvDesc.Buffer.StructureByteStride = 0;
|
||||||
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
|
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
|
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
|
||||||
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
|
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user