Skip to content

render

This package implements a batched 2D rendering pipeline. It serves as the primary interface for drawing sprites, text and geometric primitives, automatically handling coordinate space transformations and draw call batching.

Features:

  • Automated asset pipeline: Utilizes a build-time generated texture atlas and auto-generated sprite and font enums (SpriteName and FontName in bonsai:generated package) for type-safe, optimized asset access.
  • Batched rendering: Automatically batches draw calls (up to MAX_QUADS) to minimize GPU overhead, with manual control via flushBatch.
  • Coordinate systems: Easy switching between world space (gameplay) and screen space (UI) using helper functions: setWorldSpace and setScreenSpace.
  • Text drawing: Integrated TTF font support with utilities like drawTextWithDropShadow and drawTextSimple.
  • Scissoring: Built-in support for clipping regions via ScissorState.

ATLAS_PATH :: "bonsai/core/render/atlas/atlas.png"

Path relative to project root pointing to the generated sprite atlas.


Atlas :: struct {
view: sokol_gfx.View,
image: sokol_gfx.Image,
}

Represents the global sprite atlas.


BINDING_GLOBAL_UNIFORMS :: 0

Constants prefixed with BINDING define the binding index used for uniform data. By default 0 is occupied by ShaderGlobals and 1 is left for custom shader uniform data.


CLEAR_COLOR :: colors.BLACK

Default clear color (background).


Canvas :: struct {
image: sokol_gfx.Image,
depthImage: sokol_gfx.Image,
readerView: sokol_gfx.View,
attachments: sokol_gfx.Attachments,
sampler: sokol_gfx.Sampler,
id: CanvasId,
size: gmath.Vector2,
}

Wraps all data needed for each Canvas object. Each has unique CanvasId. Shouldn’t be modified directly.


CanvasId :: distinct i32

A handle used to identify a loaded Canvas


CoordSpace :: struct {
projectionMatrix: gmath.Matrix4,
cameraMatrix: gmath.Matrix4, // Model matrix of the camera
viewProjectionMatrix: gmath.Matrix4, // Projection * Inverse(Camera) (view matrix)
}

Defines the matrices used for coordinate transformation in a render pass.


DEFAULT_UV :: gmath.Vector4 {
0, 0, 1, 1
}

Default UV coordinates covering the full texture (0,0 to 1,1).


DrawFrame :: struct {
reset: struct {
// Dynamic arrays of quads bucketed by DrawLayer
quads: [DrawLayer][dynamic]Quad,
// The active coordinate space (camera, projection)
coordSpace: CoordSpace,
// Current layer being drawn to
activeDrawLayer: DrawLayer,
// Current scissor/clipping rectangle
activeScissor: gmath.Rectangle,
// Global flags applied to all subsequent quads in the batch
activeFlags: QuadFlags,
// Shader uniform data
shaderData: ShaderGlobals,
// Tracks which layers need Y-sorting
sortedLayers: bit_set[DrawLayer],
},
}

A container for all data required to render a single frame.


DrawLayer :: enum u8 {
nil,
background,
shadow,
playspace,
vfx,
ui,
tooltip,
pauseMenu,
top,
}

Defines the rendering order (Z-sorting).


Font :: struct {
texture: sokol_gfx.Image,
view: sokol_gfx.View,
characterData: [96]stb_truetype.bakedchar,
name: string,
}

Represents a loaded and baked font ready for rendering.


LOCATION_POSITION :: 0

Constants prefixed with LOCATION define the memory layout relation between the CPU Vertex struct and the GPU shader attributes (layout(location = X)).


MAX_QUADS :: 8192

Maximum number of quads per batch flush.


Quad :: [4]Vertex

A visual quad composed of 4 vertices.


QuadFlags :: enum u8 {
flag1 = (1 << 0),
flag2 = (1 << 1),
}

Bit flags for special rendering behaviors in the shader.


RenderContext :: struct {
passAction: sokol_gfx.Pass_Action,
inPass: bool,
bindings: sokol_gfx.Bindings,
shaders: [dynamic]Shader,
defaultShaderId: ShaderId,
activeShaderId: ShaderId,
customUniformsData: [1024]byte,
customUniformsSize: uint,
canvases: [dynamic]Canvas,
defaultCanvasId: CanvasId,
activeCanvasId: CanvasId,
defaultCanvasSampler: sokol_gfx.Sampler,
}

Internal context holding the global Sokol GFX state. Manages active bindings (atlas/font) and stores the list of loaded Shaders


ScissorState :: struct {
enabled: bool,
coordinates: gmath.Vector4,
}

Tracks the state of the scissor test (clipping).


Shader :: struct {
pipeline: sokol_gfx.Pipeline,
id: ShaderId,
}

Wraps a compiled Sokol pipeline and its ID.


ShaderDescriptionFunction :: proc (backend: sokol_gfx.Backend) -> sokol_gfx.Shader_Desc //

Function signature for the auto-generated shader descriptors created by sokol-shdc.


ShaderGlobals :: struct #align (16) {
uViewProjectionMatrix: gmath.Matrix4,
}

Uniform block data uploaded to the GPU for the global shader state.


ShaderId :: distinct i32

A handle used to identify a loaded Shader


Vertex :: struct #packed {
position: gmath.Vector3,
color: gmath.Vector4,
uv: gmath.Vector2,
localUv: gmath.Vector2,
size: gmath.Vector2,
textureIndex: u8,
drawLayer: u8,
quadFlags: QuadFlags, // u8
_: [1]u8, // Padding to align next Vector4 to 4 byte boundary
colorOverride: gmath.Vector4,
parameters: gmath.Vector4,
}

Represents a single vertex in the sprite batcher.


clearScissor :: proc ()

Disables the scissor test.


destroyCanvas :: proc (id: CanvasId)

Destroys the GPU resources associated with the Canvas.


drawCanvas :: proc (
id: CanvasId,
position: gmath.Vector2 = {0, 0},
rotation: f32 = 0.0,
pivot: gmath.Pivot = .bottomLeft,
scale: gmath.Vector2 = {1, 1},
size: Maybe(gmath.Vector2) = nil,
transform := gmath.Matrix4(1),
color := colors.WHITE,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws the contents of a Canvas onto the screen (or current target) at the given position. This triggers an immediate batch flush because it requires switching textures.


drawCircle :: proc (
center: gmath.Vector2,
radius: f32,
color: gmath.Color,
segments: uint = 32,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws a filled circle.


drawCircleLines :: proc (
center: gmath.Vector2,
radius: f32,
color: gmath.Color,
segments: uint = 32,
thickness: f32 = 1.0,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws the outline of a circle using line segments. Internally it just calls the drawRegularPolygonLines function with a high default count of segments.


drawLine :: proc (
start: gmath.Vector2,
end: gmath.Vector2,
color: gmath.Color,
thickness: f32 = 1.0,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws a line between start and end with a specified thickness.


drawPolygon :: proc (
points: []gmath.Vector2,
color: gmath.Color,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws a filled generic polygon. Expects points to be listed in a counter-clockwise order.


drawPolygonLines :: proc (
points: []gmath.Vector2,
color: gmath.Color,
thickness: f32 = 1.0,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws the outline of a polygon. Expects points to be listed in a counter-clockwise order.


drawQuadProjected :: proc (
positions: [4]gmath.Vector2,
colors: [4]gmath.Color,
uvs: [4]gmath.Vector2,
textureIndex: u8,
quadSize: gmath.Vector2,
colorOverride: gmath.Color,
drawLayer: DrawLayer = DrawLayer.nil,
flags: QuadFlags,
parameters := gmath.Vector4{},
sortKey: f32 = 0.0,
)

Core function for pushing a quad into the draw list.


drawRectangle :: proc (
rectangle: gmath.Rectangle,
rotation: f32 = 0.0, // in radians
sprite := generated.SpriteName.nil,
uv := DEFAULT_UV,
color := colors.WHITE,
colorOverride := gmath.Color{},
drawLayer := DrawLayer.nil,
flags := QuadFlags{},
parameters := gmath.Vector4{},
cropTop: f32 = 0.0,
cropLeft: f32 = 0.0,
cropBottom: f32 = 0.0,
cropRight: f32 = 0.0,
sortKey: f32 = 0.0,
isCullingEnabled := false,
)

Draws a simple Rectangle.


drawRectangleLines :: proc (
rectangle: gmath.Rectangle,
color: gmath.Color,
thickness: f32 = 1.0,
rotation: f32 = 0.0, // in radians
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
isCullingEnabled := false,
)

Draws the outline of a Rectangle. The border grows outwards from the rectangle edges.


drawRectangleTransform :: proc (
transform: gmath.Matrix4,
size: gmath.Vector2,
sprite := generated.SpriteName.nil,
uv := DEFAULT_UV,
textureIndex: u8 = 0,
animationIndex := 0,
color := colors.WHITE,
colorOverride := gmath.Color{},
drawLayer := DrawLayer.nil,
flags := QuadFlags{},
parameters := gmath.Vector4{},
cropTop: f32 = 0.0,
cropLeft: f32 = 0.0,
cropBottom: f32 = 0.0,
cropRight: f32 = 0.0,
sortKey: f32 = 0.0,
)

Low-level function that pushes the final quad vertex data to the batcher.


drawRegularPolygon :: proc (
center: gmath.Vector2,
radius: f32,
sides: uint,
color: gmath.Color,
rotation: f32 = 0.0,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws a filled regular N-gon.


drawRegularPolygonLines :: proc (
center: gmath.Vector2,
radius: f32,
sides: uint,
color: gmath.Color,
thickness: f32 = 1.0,
rotation: f32 = 0.0,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws the outline of a regular N-gon.


drawSprite :: proc {
_drawSpriteVector3Rotation,
_drawSpriteF32Rotation,
}

Main function for drawing game entities. Supports rotation, animations, pivoting and camera culling. Accepts either a f32 or a Vector3 as the rotation. If a f32 is provided, the sprite is rotated on the Z axis.


drawSpriteInRectangle :: proc (
sprite: generated.SpriteName,
position: gmath.Vector2,
size: gmath.Vector2,
transform := gmath.Matrix4(1),
color := colors.WHITE,
colorOverride := gmath.Color{},
drawLayer := DrawLayer.nil,
flags := QuadFlags(0),
paddingPercent: f32 = 0.1,
)

Helper to draw a sprite scaled to fit inside a target rectangle. Maintains aspect ratio (letterboxing).


drawText :: drawTextWithDropShadow

Default text drawing alias (includes drop shadow).


drawTextSimple :: proc {
_drawTextSimpleVector3Angle,
_drawTextSimpleF32Angle,
}

Draws text without a drop shadow. Retrieves the font using the automatically generated FontName enum. Accepts either a f32 or a Vector3 as the rotation. If a f32 is provided, the text is rotated on the Z axis.


drawTextSimpleFont :: proc {
_drawTextSimpleFontVector3Angle,
_drawTextSimpleFontF32Angle,
}

Internal primitive for drawing a single line of text. Calculates layout, pivots, and batches the quads. Accepts either a f32 or a Vector3 as the rotation. If a f32 is provided, the text is rotated on the Z axis.


drawTextWithDropShadow :: proc {
_drawTextWithDropShadowVector3Angle,
_drawTextWithDropShadowF32Angle,
}

Draws text with a hard-coded drop shadow for contrast**. Retrieves the font using the automatically generated FontName enum. Accepts either a f32 or a Vector3 as the rotation. If a f32 is provided, the text is rotated on the Z axis.


drawTriangle :: proc (
point1, point2, point3: gmath.Vector2,
color: gmath.Color,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws a filled triangle. Expects points to be listed in a counter-clockwise order.


drawTriangleLines :: proc (
point1, point2, point3: gmath.Vector2,
color: gmath.Color,
thickness: f32 = 1.0,
drawLayer := DrawLayer.nil,
sortKey: f32 = 0.0,
)

Draws a triangle outline. Expects points to be listed in a counter-clockwise order.


flushBatch :: proc ()

Flushes all queued quads to the GPU. Sorts layers if necessary. Warns when MAX_QUADS is exceeded.


getAtlasUv :: proc (sprite: generated.SpriteName) -> gmath.Vector4

Helper to retrieve texture info from SpriteName.


getCanvasSpace :: proc (width, height: f32) -> CoordSpace

Calculates the coordinate space for a custom Canvas. Called internally by setCanvas.


getDrawFrame :: proc () -> ^DrawFrame

Returns a pointer to the current frame’s draw data.


getFont :: proc (fontName: generated.FontName, size: uint) -> (Font, bool)

Retrieves or loads a font for a specific size. Caches the result to avoid re-baking the bitmap every frame.


getRenderContext :: proc () -> ^RenderContext

Returns a pointer to the RenderContext struct.


getScreenSpace :: proc () -> CoordSpace

Calculates the coordinate space for UI/Screen elements.


getScreenSpaceProjectionMatrix :: proc () -> gmath.Matrix4

Generates the projection matrix for the UI. Handles aspect ratio scaling to ensure the UI fits within the design resolution (GAME_WIDTH/GAME_HEIGHT).


getSpriteSize :: proc (sprite: generated.SpriteName) -> gmath.Vector2

Helper to retrieve size from SpriteName.


getTextSize :: proc (fontName: generated.FontName, fontSize: uint, text: string) -> gmath.Vector2

Calculates the total dimension (width, height) of a string if it were rendered.


getViewportPivot :: proc (pivot: gmath.Pivot) -> gmath.Vector2

Helper to get specific screen/viewport coordinates based on a Pivot (anchoring).

Returns a Vector2 position.


getViewportRectangle :: proc () -> gmath.Rectangle

Helper that calculates and creates a Rectangle containing the current viewport in Screen Space. Uses ScaleMode internally in its calculations.


getWorldSpace :: proc () -> CoordSpace

Calculates the coordinate space for the main gameplay world. Creates a View-Projection matrix based on the camera’s position and zoom.


loadShader :: proc (descriptionFunction: ShaderDescriptionFunction) -> ShaderId

Creates a new ShaderId from a sokol-shdc generated description function. This function enforces the framework’s standard vertex layout to ensure compatibility with batching.


resetDrawFrame :: proc ()

Resets the DrawFrame (clears quads, resets camera) and sets the shader to default.


setCanvas :: proc (
id: CanvasId = _renderContext.defaultCanvasId,
clear: bool = true,
clearColor: Maybe(gmath.Color) = nil,
)

Sets the current Canvas (render target). Defaults to screen space canvas.

Arguments:

  • CanvasId: Handle linked to the targeted Canvas. Returned by the loadCanvas function.
  • ‘clear’: if true - clears contents of the canvas, if false - preserves previously drawn content.
  • clearColor: Clear (background) color, takes effect only if clear is true.

setClearColor :: proc (col: gmath.Vector4)

Sets the background clear color.


setCoordSpace :: proc {
_setCoordSpaceValue,
_setCoordSpaceDefault,
}

Sets the coordinate space (projection/camera matrices).

Arguments:


setCustomUniforms :: proc (data: rawptr, size: uint)

Uploads custom uniform data to the currently active shader. This triggers a batch flush to ensure previous sprites are drawn with old uniforms.


setFontTexture :: proc (view: sokol_gfx.View)

Changes the active font texture view.


setScissorCoordinates :: proc (coordinates: gmath.Vector4)

Sets the scissor (clipping) rectangle. Flushes the batch if the scissor state changes.


setScissorRectangle :: proc (rectangle: gmath.Rectangle)

Maps a screen-space rectangle to a screen-space scissor rectangle. Used for clipping rendering to specific regions (masking).


setScreenSpace :: proc ()

Flushes the current batch and switches coordinate space to screen space (UI). Sets the active draw layer to DrawLayer.ui.


setShader :: proc (id: ShaderId = _renderContext.defaultShaderId)

Sets the active shader pipeline for subsequent draw calls. Flushes the current batch if the shader changes.

Arguments:


setTexture :: proc (view: sokol_gfx.View)

Changes the active main texture view.


setWorldSpace :: proc ()

Flushes the current batch and switches coordinate space to world space (gameplay). Sets the active draw layer to DrawLayer.background.


shutdown :: proc ()

Cleans up all rendering resources. Called internally by main.odin.


swapchain: = sokol_glue.swapchain()

loadCanvas :: proc(width: i32, height: i32) -> CanvasId {