Header menu logo Mibo

Rendering 2D

2D rendering in Mibo lives in Mibo.Elmish.Graphics2D.

The core building blocks are:

Minimal 2D renderer

open Mibo.Elmish.Graphics2D

let view (ctx: GameContext) (model: Model) (buffer: RenderBuffer<RenderCmd2D>) =
  Draw2D.sprite model.PlayerTex model.PlayerRect
  |> Draw2D.atLayer 10<RenderLayer>
  |> Draw2D.submit buffer

let program =
  Program.mkProgram init update
  |> Program.withRenderer (Batch2DRenderer.create view)

Render layers

RenderLayer is an int unit-of-measure.

If you enable sorting (default), the renderer sorts the buffer by layer each frame.

Cameras

The 2D renderer responds to SetCamera commands.

let cam = Camera2D.create model.CamPos model.Zoom viewportSize

Draw2D.camera cam 0<RenderLayer> buffer

Multi-camera in 2D

You can switch cameras multiple times in a single frame by emitting multiple camera/view commands and grouping your draws under each camera.

The built-in 2D renderer supports the same multi-camera “amenities” as 3D:

Example (two viewports, two cameras):

let leftVp = Viewport(0, 0, viewportSize.X / 2, viewportSize.Y)
let rightVp = Viewport(viewportSize.X / 2, 0, viewportSize.X / 2, viewportSize.Y)

Draw2D.viewport leftVp 0<RenderLayer> buffer
Draw2D.clear (ValueSome Color.CornflowerBlue) false 1<RenderLayer> buffer
Draw2D.camera leftCam 2<RenderLayer> buffer
// left-side sprites...

Draw2D.viewport rightVp 10<RenderLayer> buffer
Draw2D.clear (ValueSome Color.DarkSlateGray) false 11<RenderLayer> buffer
Draw2D.camera rightCam 12<RenderLayer> buffer
// right-side sprites...

Note on ordering: if Batch2DConfig.SortCommands = true (the default), only layer ordering is guaranteed (commands within the same layer may reorder). For stateful sequences (viewport/clear/camera/effect), either:

Configuration

If you need custom SpriteBatch settings (blend, sampler, clear color, etc):

Batch2DRenderer.createWithConfig
  { Batch2DConfig.defaults with
      ClearColor = ValueSome Color.Black
      SamplerState = SamplerState.PointClamp }
  view

You can also change key SpriteBatch state within a frame via commands:

Custom GPU work (escape hatch)

The built-in 2D SpriteBatch renderer exposes DrawCustom for “do whatever you want” rendering.

Draw2D.custom
  (fun ctx ->
     // Raw GPU work (primitives, render targets, post-effects, etc.)
     // Note: SpriteBatch is ended before this runs, and restarted after.
     ())
  50<RenderLayer>
  buffer

If you need a fully bespoke pipeline, you can still implement your own IRenderer<'Model> and add it with Program.withRenderer.

See also: Rendering overview (overall renderer composition) and Camera.

val view: ctx: 'a -> model: 'b -> buffer: 'c -> 'd
val ctx: 'a
val model: 'b
val buffer: 'c
val program: obj
val cam: obj
val leftVp: obj
val rightVp: obj
union case ValueOption.ValueSome: 'T -> ValueOption<'T>

Type something to start searching.