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) = ()