Header menu logo Mibo

Rendering in Mibo

Mibo’s rendering story is intentionally simple:

This keeps drawing as data submission, which composes nicely as projects grow.

Renderers are just IRenderer<'Model>

A renderer is anything that implements:

type IRenderer<'Model> =
    abstract member Draw: GameContext * 'Model * GameTime -> unit

You add renderers with:

Program.withRenderer (fun game -> myRenderer :> IRenderer<Model>)

Multiple renderers can be added (e.g. 3D world + 2D UI). They run in the order they were added.

The RenderBuffer pattern

Instead of drawing immediately inside update, you typically:

  1. allocate a buffer (owned by the renderer)
  2. clear it each frame
  3. call your view to fill it
  4. optionally sort it
  5. execute the commands

The built-in renderers follow this pattern, and custom renderers can too.

Writing your own renderer

If you have a custom draw pipeline (special post-processing, instancing, debug overlays, etc), implement IRenderer<'Model>.

Minimal example:

type MyRenderer(game: Game) =
    interface IRenderer<Model> with
        member _.Draw(ctx, model, gameTime) =
            // use ctx.GraphicsDevice, ctx.Content, etc
            // draw based on model
            ()

Then install it:

Program.mkProgram init update
|> Program.withRenderer (fun game -> MyRenderer(game) :> IRenderer<Model>)

Built-in renderers

Mibo includes:

See the dedicated pages:

type IRenderer<'Model> = abstract Draw: 'b * 'Model * 'c -> unit
'Model
type unit = Unit
Multiple items
type MyRenderer = interface obj new: game: obj -> MyRenderer override Draw: ctx: 'a * model: 'b * gameTime: 'c -> unit

--------------------
new: game: obj -> MyRenderer
val game: obj
val ctx: 'a
val model: 'b
val gameTime: 'c

Type something to start searching.