Skip to content

Commit c60b436

Browse files
authored
Merge pull request #1 from AngelMunoz/fix/single-directional-light
feat: shadow atlas with multi-light support and performance improvements
2 parents c8c5d04 + 06e16c6 commit c60b436

204 files changed

Lines changed: 6302 additions & 3738 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ The core abstractions of the library MUST NOT incur performance penalties for us
2323
- Prefer structs over classes unless struct size is too large.
2424
- Prefer object expressions to classes.
2525
- Avoid heap allocations in hot paths.
26+
- If implementing an interface, use a struct instead of a class or object expression if that object is going to be in a hot path
2627
- Favor arrays and spans over lists.
2728
- Favor ArrayPool over allocating new arrays where possible.
2829
- Favor functional programming patterns but allow mutable state when necessary for performance.
@@ -60,3 +61,47 @@ Each section may contain the following categories:
6061
- Security
6162

6263
When adding entries to the changelog, make sure to follow format and categories.
64+
65+
## raylib-cs / F# Quirks
66+
67+
### DisableRuntimeMarshalling + void* Bug
68+
69+
The project uses `[<DisableRuntimeMarshalling>]`. This affects how `SetShaderValue` and similar FFI calls work:
70+
71+
- **DO NOT** pass raw `int`, `float32`, `Vector3` etc. directly as `void*` arguments. The runtime treats the value itself as a pointer address (e.g., passing `1` reads from address `0x1`, causing access violations).
72+
- **ALWAYS** use `fixed + NativePtr.toVoidPtr` for scalar/vec3/vec4 uniforms:
73+
74+
```fsharp
75+
let setShaderInt (shader: Shader) (loc: int) (value: int) =
76+
use p = fixed &value
77+
Raylib.SetShaderValue(shader, loc, NativePtr.toVoidPtr p, ShaderUniformDataType.Int)
78+
```
79+
80+
- **EXCEPTION**: `SetShaderValueMatrix` takes `Matrix4x4` directly (not `void*`) — this works correctly.
81+
- **EXCEPTION**: `Rlgl.SetUniform` (raw rlgl) also requires `fixed + NativePtr.toVoidPtr`.
82+
83+
### Matrix Conventions
84+
85+
#### System.Numerics vs raylib struct layout
86+
87+
`Matrix4x4` in System.Numerics stores rows contiguously in memory: `m00 m01 m02 m03 m10 m11 m12 m13 ...`
88+
89+
raylib's `rlMatrix` stores columns contiguously: `m0 m4 m8 m12 m1 m5 m9 m13 ...`
90+
91+
`rlMatrixToFloatV` reorders from raylib's struct layout to GLSL column-major order (fields m0→m1→m2→...→m15). This means:
92+
- `SetShaderValueMatrix` and the batch's `glUniformMatrix4fv` both go through `rlMatrixToFloatV`**they match**.
93+
- Do NOT manually blit a `Matrix4x4` to float arrays — use `rlMatrixToFloatV` for correct conversion.
94+
95+
#### Vector4.Transform vs GLSL mat*vec
96+
97+
- `Vector4.Transform(v, M)` computes `v * M^T` (transposed convention)
98+
- GLSL `M * v` computes `M * v` (standard convention)
99+
- These give **different results** on the same matrix. Do not mix them.
100+
- For uniform passing, `SetShaderValueMatrix` handles conversion via `rlMatrixToFloatV` — this is correct regardless.
101+
102+
#### VP Matrix Capture
103+
104+
When capturing the View-Projection matrix for shadow mapping:
105+
- **MUST** capture inside `BeginMode3D` using `Rlgl.GetMatrixModelview() * Rlgl.GetMatrixProjection()`
106+
- This matches what the batch computes for `mvp` (for identity model transforms)
107+
- Precomputing VP outside `BeginMode3D` or using `Matrix4x4.CreateLookAt * CreatePerspectiveFieldOfView` may produce different results due to raylib's internal matrix adjustments

CHANGELOG.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
- Render context uses camera state (BeginCamera/EndCamera) instead of hardcoding.
1616
- Configurable `maxPointLights` and `ShadowConfig` for CSM cascades.
1717
- `RenderBuffer3D` with `IDisposable` for `ArrayPool` return.
18-
1918
- Initial port of Mibo from MonoGame to raylib-cs.
2019
- Core: `RaylibGame` runtime loop integrating Elmish architecture with raylib lifecycle.
2120
- Core: `Program` module for configuring init, update, renderers, and services.
@@ -25,7 +24,7 @@
2524
- Rendering: `Batch3DRenderer` for 3D rendering with custom Phong shader and lighting.
2625
- Rendering: 2D lighting system (ambient, point, directional lights with CPU accumulation).
2726
- Rendering: 3D lighting system (ambient, directional, point lights with GPU Phong shader).
28-
- Rendering: Post-processing pipeline with `PostProcessConfig` and embedded GLSL shaders.
27+
- Rendering: Post-processing pipeline with multi-pass `PostProcessPass` and embedded GLSL shaders.
2928
- Rendering: Default shader library (`DefaultShaders.fs`) with Phong and tint shaders.
3029
- Rendering: `ModelHelper.setMaterialShader` for patching model material shaders (required by raylib).
3130
- Input: `InputMap` and `ActionState` types for semantic input mapping.
@@ -34,7 +33,20 @@
3433
- Time: `FixedStep` configuration for deterministic physics/simulation steps.
3534
- Animation: `Mibo.Animation` module for 2D sprite animation with `SpriteSheet.fromFrames`, `SpriteSheet.fromGrid`, `AnimatedSprite.update`, and layer-sorted rendering via `RenderCmd2D.DrawSprite`.
3635
- Code-first level design: `Mibo.Layout` and `Mibo.Layout3D` modules for 2D and 3D grid-based levels (planned).
37-
3836
- Documentation: Official documentation site with guides for all modules.
3937
- Sample: 2D Platformer with procedural terrain, sprite animation, day/night cycle, and dynamic lighting.
4038
- Sample: 3D Platformer with procedural levels, custom Phong shader, camera-relative controls, and day/night GPU lighting.
39+
40+
### Changed
41+
42+
- ThreeDSample: Minimap rendering now bakes blocks into a CPU-side `Image` + GPU `Texture2D` instead of emitting ~1600 individual `FillRect` commands per frame. The texture is rebuilt every N frames and drawn as a single `Sprite`, reducing per-frame draw calls from ~1600 to 5 (1 sprite + player marker + direction line + border).
43+
- ThreeDSample: Refactored `MinimapView` into proper MVU module (`Minimap`) with `MinimapModel`, `system`, and `view`. Block collection and texture baking moved from the view function into the update pipeline.
44+
- ThreeDSample: Moved text overlay from `View.fs` `DrawImmediate` escape hatch to a proper `Diagnostics` 2D module with `Command2D.text`. Both minimap and diagnostics share a single 2D renderer.
45+
- ThreeDSample: Sun/moon cycle now uses model time instead of hardcoded noon. Arc distance scales with loaded world size via `arcRadius`.
46+
- ThreeDSample: Mushroom light collection moved from `View.fs` to `mushroomLightSystem`. Lights stored as `PointLight3D` on the model, `CastsShadows = false` for performance.
47+
- ThreeDSample: Pre-computed lighting state (`LightingModel`) stored on `GameModel`, populated by `lightingSystem`. View reads from model instead of computing DayNight values.
48+
49+
### Removed
50+
51+
- Dead code cleanup: removed unused `PostProcessConfig` type, `Renderer2D.createWithConfig`, `Renderer3D.createWithConfig`, and empty `RenderCommand.fs`/`RenderContext.fs` stub files.
52+
- ThreeDSample: Removed dead `DayNight.State`, `DayNight.initial`, `DayNight.update` (never used).
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup><Compile Include="Program.fs" />
9+
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Raylib-cs" Version="8.0.0" />
14+
</ItemGroup>
15+
16+
</Project>

0 commit comments

Comments
 (0)