namespace Mibo.Elmish.Graphics2D
open System.Numerics
open Raylib_cs
open Mibo.Elmish
open Mibo.Elmish.Graphics2D.Lighting
///
/// Pipe-friendly drawing DSL. Each function takes a
/// as its last argument, adds the corresponding command, and returns the buffer for chaining.
///
///
///
/// Commands are built via and added to the buffer.
/// Partial application of styling parameters (layer, color, thickness) is supported — bind
/// them once and reuse across multiple draw calls.
///
///
/// Usage:
///
/// buffer
/// |> Draw.beginCamera 0<RenderLayer> worldCamera
/// |> Draw.fillRect (10<RenderLayer>, Color.Red) groundRect
/// |> Draw.fillCircle (10<RenderLayer>, Color.Blue) (center, radius)
/// |> Draw.line (5<RenderLayer>, Color.Green) (p1, p2)
/// |> Draw.endCamera 1000<RenderLayer>
/// |> Draw.drop
///
///
///
[]
module Draw =
// ──────────────────────────────────────────────
// Sprite & Text
// ──────────────────────────────────────────────
/// Draws a sprite from a pre-configured SpriteState.
let inline sprite (state: SpriteState) (buffer: RenderBuffer2D) =
buffer.Add(Command2D.sprite state)
buffer
/// Draws text from a pre-configured TextState.
let inline text (state: Command2D.TextState) (buffer: RenderBuffer2D) =
buffer.Add(Command2D.text state)
buffer
// ──────────────────────────────────────────────
// Rectangles
// ──────────────────────────────────────────────
/// Filled rectangle. (layer, color) can be partially applied.
let inline fillRect
(layer: int, color: Color)
(rect: Rectangle)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.fillRect (layer, color) rect)
buffer
/// Rectangle outline with thickness. (layer, color, thickness) can be partially applied.
let inline rectOutline
(layer: int, color: Color, thickness: float32)
(rect: Rectangle)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.rectOutline (layer, color, thickness) rect)
buffer
/// Filled rounded rectangle. (layer, color, roundness, segments) can be partially applied.
let inline fillRectRounded
(layer: int, color: Color, roundness: float32, segments: int)
(rect: Rectangle)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.fillRectRounded (layer, color, roundness, segments) rect
)
buffer
/// Rounded rectangle outline with thickness. (layer, color, roundness, segments, thickness) can be partially applied.
let inline rectRoundedOutline
(
layer: int,
color: Color,
roundness: float32,
segments: int,
thickness: float32
)
(rect: Rectangle)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.rectRoundedOutline
(layer, color, roundness, segments, thickness)
rect
)
buffer
/// Vertical gradient rectangle. (layer) can be partially applied.
let inline rectGradientV
(layer: int)
(x: int, y: int, w: int, h: int, top: Color, bottom: Color)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.rectGradientV layer (x, y, w, h, top, bottom))
buffer
/// Horizontal gradient rectangle. (layer) can be partially applied.
let inline rectGradientH
(layer: int)
(x: int, y: int, w: int, h: int, left: Color, right: Color)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.rectGradientH layer (x, y, w, h, left, right))
buffer
/// 4-corner gradient rectangle. (layer) can be partially applied.
let inline rectGradient
(layer: int)
(rect: Rectangle, tl: Color, bl: Color, tr: Color, br: Color)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.rectGradient layer (rect, tl, bl, tr, br))
buffer
// ──────────────────────────────────────────────
// Circles & Ellipses
// ──────────────────────────────────────────────
/// Filled circle. (layer, color) can be partially applied.
let inline fillCircle
(layer: int, color: Color)
(center: Vector2, radius: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.fillCircle (layer, color) (center, radius))
buffer
/// Circle outline. (layer, color) can be partially applied.
let inline circleOutline
(layer: int, color: Color)
(center: Vector2, radius: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.circleOutline (layer, color) (center, radius))
buffer
/// Filled circle sector (pie slice). (layer, color) can be partially applied.
let inline circleSector
(layer: int, color: Color)
(
center: Vector2,
radius: float32,
startAngle: float32,
endAngle: float32,
segments: int
)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.circleSector
(layer, color)
(center, radius, startAngle, endAngle, segments)
)
buffer
/// Circle sector outline. (layer, color) can be partially applied.
let inline circleSectorOutline
(layer: int, color: Color)
(
center: Vector2,
radius: float32,
startAngle: float32,
endAngle: float32,
segments: int
)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.circleSectorOutline
(layer, color)
(center, radius, startAngle, endAngle, segments)
)
buffer
/// Gradient circle. (layer) can be partially applied.
let inline circleGradient
(layer: int)
(centerX: int, centerY: int, radius: float32, inner: Color, outer: Color)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.circleGradient layer (centerX, centerY, radius, inner, outer)
)
buffer
/// Filled ring / arc. (layer, color) can be partially applied.
let inline fillRing
(layer: int, color: Color)
(
center: Vector2,
innerR: float32,
outerR: float32,
startAngle: float32,
endAngle: float32,
segments: int
)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.fillRing
(layer, color)
(center, innerR, outerR, startAngle, endAngle, segments)
)
buffer
/// Ring / arc outline. (layer, color) can be partially applied.
let inline ringOutline
(layer: int, color: Color)
(
center: Vector2,
innerR: float32,
outerR: float32,
startAngle: float32,
endAngle: float32,
segments: int
)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.ringOutline
(layer, color)
(center, innerR, outerR, startAngle, endAngle, segments)
)
buffer
/// Filled ellipse. (layer, color) can be partially applied.
let inline fillEllipse
(layer: int, color: Color)
(centerX: int, centerY: int, radiusH: float32, radiusV: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.fillEllipse (layer, color) (centerX, centerY, radiusH, radiusV)
)
buffer
/// Ellipse outline. (layer, color) can be partially applied.
let inline ellipseOutline
(layer: int, color: Color)
(centerX: int, centerY: int, radiusH: float32, radiusV: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.ellipseOutline
(layer, color)
(centerX, centerY, radiusH, radiusV)
)
buffer
// ──────────────────────────────────────────────
// Lines & Curves
// ──────────────────────────────────────────────
/// 1-pixel line. (layer, color) can be partially applied.
let inline line
(layer: int, color: Color)
(start: Vector2, finish: Vector2)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.line (layer, color) (start, finish))
buffer
/// Line with custom thickness. (layer, color, thickness) can be partially applied.
let inline lineThick
(layer: int, color: Color, thickness: float32)
(start: Vector2, finish: Vector2)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.lineThick (layer, color, thickness) (start, finish))
buffer
/// Connected line segments. (layer, color) can be partially applied.
let inline lineStrip
(layer: int, color: Color)
(points: Vector2[])
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.lineStrip (layer, color) points)
buffer
/// Quadratic bezier curve. (layer, color, thickness) can be partially applied.
let inline bezier
(layer: int, color: Color, thickness: float32)
(start: Vector2, control: Vector2, finish: Vector2)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.bezier (layer, color, thickness) (start, control, finish)
)
buffer
// ──────────────────────────────────────────────
// Triangles & Polygons
// ──────────────────────────────────────────────
/// Filled triangle from 3 vertices. (layer, color) can be partially applied.
let inline triangle
(layer: int, color: Color)
(v1: Vector2, v2: Vector2, v3: Vector2)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.triangle (layer, color) (v1, v2, v3))
buffer
/// Filled triangle fan. (layer, color) can be partially applied.
let inline triangleFan
(layer: int, color: Color)
(points: Vector2[])
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.triangleFan (layer, color) points)
buffer
/// Filled triangle strip. (layer, color) can be partially applied.
let inline triangleStrip
(layer: int, color: Color)
(points: Vector2[])
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.triangleStrip (layer, color) points)
buffer
/// Filled regular polygon. (layer, color) can be partially applied.
let inline fillPoly
(layer: int, color: Color)
(center: Vector2, sides: int, radius: float32, rotation: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.fillPoly (layer, color) (center, sides, radius, rotation)
)
buffer
/// Regular polygon outline with thickness. (layer, color, thickness) can be partially applied.
let inline polyOutline
(layer: int, color: Color, thickness: float32)
(center: Vector2, sides: int, radius: float32, rotation: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(
Command2D.polyOutline
(layer, color, thickness)
(center, sides, radius, rotation)
)
buffer
// ──────────────────────────────────────────────
// Camera, Shader, Target
// ──────────────────────────────────────────────
/// Begins a 2D camera transform. (layer) can be partially applied.
let inline beginCamera
(layer: int)
(camera: Camera2D)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.beginCamera layer camera)
buffer
/// Begins a 2D camera with explicit rendering config (viewport, clear). (layer) can be partially applied.
let inline beginCameraWith
(layer: int)
(config: Camera2DConfig)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.beginCameraConfig layer config)
buffer
/// Ends the current 2D camera transform.
let inline endCamera (layer: int) (buffer: RenderBuffer2D) =
buffer.Add(Command2D.endCamera layer)
buffer
/// Begins a shader mode. (layer) can be partially applied.
let inline beginShader
(layer: int)
(shader: Shader)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.beginShader layer shader)
buffer
/// Ends the current shader mode.
let inline endShader (layer: int) (buffer: RenderBuffer2D) =
buffer.Add(Command2D.endShader layer)
buffer
/// Begins rendering to a render texture. (layer) can be partially applied.
let inline beginTarget
(layer: int)
(target: RenderTexture2D)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.beginTarget layer target)
buffer
/// Ends rendering to a render texture.
let inline endTarget (layer: int) (buffer: RenderBuffer2D) =
buffer.Add(Command2D.endTarget layer)
buffer
// ──────────────────────────────────────────────
// Render State
// ──────────────────────────────────────────────
/// Sets the blending mode. (layer) can be partially applied.
let inline setBlend
(layer: int)
(mode: BlendMode)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.setBlend layer mode)
buffer
/// Enables scissor testing. (layer) can be partially applied.
let inline setScissor
(layer: int)
(x: int, y: int, w: int, h: int)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.setScissor layer (x, y, w, h))
buffer
/// Disables scissor testing.
let inline clearScissor (layer: int) (buffer: RenderBuffer2D) =
buffer.Add(Command2D.clearScissor layer)
buffer
/// Sets the line width for subsequent line draws. (layer) can be partially applied.
let inline setLineWidth
(layer: int)
(width: float32)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.setLineWidth layer width)
buffer
/// Sets the viewport rectangle. (layer) can be partially applied.
let inline setViewport
(layer: int)
(x: int, y: int, w: int, h: int)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.setViewport layer (x, y, w, h))
buffer
// ──────────────────────────────────────────────
// Escape Hatches
// ──────────────────────────────────────────────
/// Flushes raylib's batch, exits camera/shader, runs action, restores state. (layer) can be partially applied.
let inline drawImmediate
(layer: int)
(action: unit -> unit)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.drawImmediate layer action)
buffer
/// Clears the current framebuffer to the given color.
let inline clear
(layer: int)
(color: Color)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.clear layer color)
buffer
// ──────────────────────────────────────────────
// Shadow Control
// ──────────────────────────────────────────────
/// Enables shadow casting for the given light context. (layer) can be partially applied.
let inline enableShadows
(layer: int)
(lightCtx: LightContext2D)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.enableShadows layer lightCtx)
buffer
/// Disables shadow casting for the given light context. (layer) can be partially applied.
let inline disableShadows
(layer: int)
(lightCtx: LightContext2D)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.disableShadows layer lightCtx)
buffer
///
/// Enqueues a model-aware post-process pass. The action runs once, after the whole scene
/// renders to an offscreen target; it receives a
/// with the scene texture and must draw a fullscreen quad of it. Emit it conditionally
/// from the view based on game state (e.g. only while a hit-flash is active). Chain
/// multiple passes — they ping-pong in buffer order, the last drawing to the back-buffer.
///
/// Invoked once per frame with the post-process context.
let inline postProcess
([] action: PostProcessContext2D -> unit)
(buffer: RenderBuffer2D)
=
buffer.Add(Command2D.postProcess action)
buffer
/// Terminal function that discards the buffer, silencing the unused-value warning. Does nothing.
let inline drop(_buffer: RenderBuffer2D) = ()