Skip to content

Commit 76f57e4

Browse files
committed
feat(dsl): add builder pattern for all render struct types
Add create + withX pipeline builders following Material3D/Camera3D pattern: 2D: SpriteState, TextState, Particle2D, AmbientLight2D, DirectionalLight2D, PointLight2D, Occluder2D 3D: AmbientLight3D, DirectionalLight3D, PointLight3D, SpotLight3D Each module provides create (required args, sensible defaults) and withX modifiers for optional fields. Enables ergonomic pipelines: PointLight3D.create (pos, 6.0f) |> PointLight3D.withColor (Color(255uy, 200uy, 120uy)) |> Draw3D.addPointLight
1 parent d41e2ce commit 76f57e4

5 files changed

Lines changed: 261 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Added
66

7+
- Builder DSL for all render struct types: `create` + `withX` pipeline for `SpriteState`, `TextState`, `Particle2D`, `AmbientLight2D`, `DirectionalLight2D`, `PointLight2D`, `Occluder2D`, `AmbientLight3D`, `DirectionalLight3D`, `PointLight3D`, `SpotLight3D`. Follows `Material3D` / `Camera3D` pattern.
78
- 3D rendering pipeline with CSM shadow maps (4-layer architecture: Renderer3D → Pipeline → Context → Commands).
89
- `ClusteredForwardPipeline` with Cook-Torrance PBR shading, CSM shadow mapping, and material caching.
910
- `Material3D` struct with PBR fields (albedo, roughness, metallic, normal, emission, opacity, tiling) and `fromRaylibMaterial` conversion.

src/Mibo.Raylib/Graphics2D/Command2D.fs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,77 @@ module Command2D =
566566

567567
let inline clear (layer: int<RenderLayer>) (color: Color) =
568568
Command2D.Clear(color, layer)
569+
570+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Command2D.SpriteState"/>.</summary>
571+
module SpriteState =
572+
573+
/// <summary>Creates a sprite state with required fields. Defaults: Origin=Zero, Rotation=0, Color=White, Layer=0.</summary>
574+
let create
575+
(texture: Texture2D, dest: Rectangle, source: Rectangle)
576+
: Command2D.SpriteState =
577+
{
578+
Texture = texture
579+
Dest = dest
580+
Source = source
581+
Origin = Vector2.Zero
582+
Rotation = 0.0f
583+
Color = Color.White
584+
Layer = 0<RenderLayer>
585+
}
586+
587+
let inline withOrigin (v: Vector2) (s: Command2D.SpriteState) = {
588+
s with
589+
Origin = v
590+
}
591+
592+
let inline withRotation (v: float32) (s: Command2D.SpriteState) = {
593+
s with
594+
Rotation = v
595+
}
596+
597+
let inline withColor (v: Color) (s: Command2D.SpriteState) = {
598+
s with
599+
Color = v
600+
}
601+
602+
let inline withLayer (v: int<RenderLayer>) (s: Command2D.SpriteState) = {
603+
s with
604+
Layer = v
605+
}
606+
607+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Command2D.TextState"/>.</summary>
608+
module TextState =
609+
610+
/// <summary>Creates a text state with required fields. Defaults: FontSize=20, Spacing=1, Color=White, Layer=0.</summary>
611+
let create
612+
(font: Font, text: string, position: Vector2)
613+
: Command2D.TextState =
614+
{
615+
Font = font
616+
Text = text
617+
Position = position
618+
FontSize = 20.0f
619+
Spacing = 1.0f
620+
Color = Color.White
621+
Layer = 0<RenderLayer>
622+
}
623+
624+
let inline withFontSize (v: float32) (s: Command2D.TextState) = {
625+
s with
626+
FontSize = v
627+
}
628+
629+
let inline withSpacing (v: float32) (s: Command2D.TextState) = {
630+
s with
631+
Spacing = v
632+
}
633+
634+
let inline withColor (v: Color) (s: Command2D.TextState) = {
635+
s with
636+
Color = v
637+
}
638+
639+
let inline withLayer (v: int<RenderLayer>) (s: Command2D.TextState) = {
640+
s with
641+
Layer = v
642+
}

src/Mibo.Raylib/Graphics2D/Lighting/LightTypes.fs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,65 @@ type Occluder2D = {
5757
/// <summary>End point of the occluder segment in world space.</summary>
5858
P2: Vector2
5959
}
60+
61+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Lighting.AmbientLight2D"/>.</summary>
62+
module AmbientLight2D =
63+
64+
/// <summary>Creates an ambient light with the given color.</summary>
65+
let create(color: Color) : AmbientLight2D = { Color = color }
66+
67+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Lighting.DirectionalLight2D"/>.</summary>
68+
module DirectionalLight2D =
69+
70+
/// <summary>Creates a directional light. Defaults: Color=White, Intensity=1, CastsShadows=true.</summary>
71+
let create(direction: Vector2) : DirectionalLight2D = {
72+
Direction = direction
73+
Color = Color.White
74+
Intensity = 1.0f
75+
CastsShadows = true
76+
}
77+
78+
let inline withColor (v: Color) (l: DirectionalLight2D) = { l with Color = v }
79+
80+
let inline withIntensity (v: float32) (l: DirectionalLight2D) = {
81+
l with
82+
Intensity = v
83+
}
84+
85+
let inline withCastsShadows (v: bool) (l: DirectionalLight2D) = {
86+
l with
87+
CastsShadows = v
88+
}
89+
90+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Lighting.PointLight2D"/>.</summary>
91+
module PointLight2D =
92+
93+
/// <summary>Creates a point light. Defaults: Color=White, Intensity=1, Falloff=2, CastsShadows=false.</summary>
94+
let create(position: Vector2, radius: float32) : PointLight2D = {
95+
Position = position
96+
Color = Color.White
97+
Intensity = 1.0f
98+
Radius = radius
99+
Falloff = 2.0f
100+
CastsShadows = false
101+
}
102+
103+
let inline withColor (v: Color) (l: PointLight2D) = { l with Color = v }
104+
105+
let inline withIntensity (v: float32) (l: PointLight2D) = {
106+
l with
107+
Intensity = v
108+
}
109+
110+
let inline withFalloff (v: float32) (l: PointLight2D) = { l with Falloff = v }
111+
112+
let inline withCastsShadows (v: bool) (l: PointLight2D) = {
113+
l with
114+
CastsShadows = v
115+
}
116+
117+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Lighting.Occluder2D"/>.</summary>
118+
module Occluder2D =
119+
120+
/// <summary>Creates an occluder from two endpoints.</summary>
121+
let create(p1: Vector2, p2: Vector2) : Occluder2D = { P1 = p1; P2 = p2 }

src/Mibo.Raylib/Graphics2D/Lighting/ParticleTypes.fs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,24 @@ type Particle2D = {
2525
/// <summary>Tint color. Alpha controls transparency.</summary>
2626
Color: Color
2727
}
28+
29+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics2D.Lighting.Particle2D"/>.</summary>
30+
module Particle2D =
31+
32+
/// <summary>Creates a particle with required fields. Defaults: Rotation=0, SourceRect=empty, Color=White.</summary>
33+
let create(position: Vector2, size: Vector2) : Particle2D = {
34+
Position = position
35+
Size = size
36+
Rotation = 0.0f
37+
SourceRect = Rectangle(0.0f, 0.0f, 0.0f, 0.0f)
38+
Color = Color.White
39+
}
40+
41+
let inline withRotation (v: float32) (p: Particle2D) = { p with Rotation = v }
42+
43+
let inline withSourceRect (v: Rectangle) (p: Particle2D) = {
44+
p with
45+
SourceRect = v
46+
}
47+
48+
let inline withColor (v: Color) (p: Particle2D) = { p with Color = v }

src/Mibo.Raylib/Graphics3D/Light3D.fs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@ type AmbientLight3D = {
1212
Intensity: float32
1313
}
1414

15+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics3D.AmbientLight3D"/>.</summary>
16+
module AmbientLight3D =
17+
18+
/// <summary>Creates an ambient light. Defaults: Intensity=1.</summary>
19+
let create(color: Color) : AmbientLight3D = {
20+
Color = color
21+
Intensity = 1.0f
22+
}
23+
24+
let inline withIntensity (v: float32) (l: AmbientLight3D) = {
25+
l with
26+
Intensity = v
27+
}
28+
1529
/// <summary>Directional light configuration for 3D scenes.</summary>
1630
[<Struct>]
1731
type DirectionalLight3D = {
@@ -32,6 +46,29 @@ type DirectionalLight3D = {
3246
CastsShadows: bool
3347
}
3448

49+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics3D.DirectionalLight3D"/>.</summary>
50+
module DirectionalLight3D =
51+
52+
/// <summary>Creates a directional light. Defaults: Color=White, Intensity=1, CastsShadows=true.</summary>
53+
let create(direction: Vector3) : DirectionalLight3D = {
54+
Direction = direction
55+
Color = Color.White
56+
Intensity = 1.0f
57+
CastsShadows = true
58+
}
59+
60+
let inline withColor (v: Color) (l: DirectionalLight3D) = { l with Color = v }
61+
62+
let inline withIntensity (v: float32) (l: DirectionalLight3D) = {
63+
l with
64+
Intensity = v
65+
}
66+
67+
let inline withCastsShadows (v: bool) (l: DirectionalLight3D) = {
68+
l with
69+
CastsShadows = v
70+
}
71+
3572
/// <summary>Point light configuration for 3D scenes.</summary>
3673
[<Struct>]
3774
type PointLight3D = {
@@ -61,6 +98,30 @@ type PointLight3D = {
6198
ShadowBias: float32 voption
6299
}
63100

101+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics3D.PointLight3D"/>.</summary>
102+
module PointLight3D =
103+
104+
/// <summary>Creates a point light. Defaults: Color=White, CastsShadows=false, ShadowBias=None.</summary>
105+
let create(position: Vector3, radius: float32) : PointLight3D = {
106+
Position = position
107+
Color = Color.White
108+
Radius = radius
109+
CastsShadows = false
110+
ShadowBias = ValueNone
111+
}
112+
113+
let inline withColor (v: Color) (l: PointLight3D) = { l with Color = v }
114+
115+
let inline withCastsShadows (v: bool) (l: PointLight3D) = {
116+
l with
117+
CastsShadows = v
118+
}
119+
120+
let inline withShadowBias (v: float32) (l: PointLight3D) = {
121+
l with
122+
ShadowBias = ValueSome v
123+
}
124+
64125
/// <summary>Spot light configuration for cone-shaped lights with distance attenuation.</summary>
65126
[<Struct>]
66127
type SpotLight3D = {
@@ -97,3 +158,45 @@ type SpotLight3D = {
97158
/// </remarks>
98159
ShadowBias: float32 voption
99160
}
161+
162+
/// <summary>Convenience builders for <see cref="T:Mibo.Elmish.Graphics3D.SpotLight3D"/>.</summary>
163+
module SpotLight3D =
164+
165+
/// <summary>Creates a spot light. Defaults: Color=White, Intensity=1, InnerCutoff=0.5, OuterCutoff=0.7, CastsShadows=false, ShadowBias=None.</summary>
166+
let create
167+
(position: Vector3, direction: Vector3, radius: float32)
168+
: SpotLight3D =
169+
{
170+
Position = position
171+
Direction = direction
172+
Color = Color.White
173+
Intensity = 1.0f
174+
Radius = radius
175+
InnerCutoff = 0.5f
176+
OuterCutoff = 0.7f
177+
CastsShadows = false
178+
ShadowBias = ValueNone
179+
}
180+
181+
let inline withColor (v: Color) (l: SpotLight3D) = { l with Color = v }
182+
183+
let inline withIntensity (v: float32) (l: SpotLight3D) = {
184+
l with
185+
Intensity = v
186+
}
187+
188+
let inline withCutoff (inner: float32) (outer: float32) (l: SpotLight3D) = {
189+
l with
190+
InnerCutoff = inner
191+
OuterCutoff = outer
192+
}
193+
194+
let inline withCastsShadows (v: bool) (l: SpotLight3D) = {
195+
l with
196+
CastsShadows = v
197+
}
198+
199+
let inline withShadowBias (v: float32) (l: SpotLight3D) = {
200+
l with
201+
ShadowBias = ValueSome v
202+
}

0 commit comments

Comments
 (0)