Files
dusk/.claude/display.md
T
2026-06-18 14:59:21 -05:00

7.4 KiB
Raw Blame History

Display System

Source: src/dusk/display/

The display system is the rendering pipeline. It is abstracted across platforms via displayplatform.h — see architecture.md for the abstraction pattern. The current concrete backends are OpenGL (src/duskgl/) and GX/Dolphin (src/duskdolphin/).

For the planned render-queue refactor (required for Saturn), see display-refactor.md.


Initialization order

Within the display system, init must follow this order (enforced in engine.c):

displayInit → uiInit → uiTextboxInit

Within displayInit, the platform typically initialises: framebuffer → screen → shader list → textures → spritebatch → text system.


display_t / displaystate_t

display_t DISPLAY is the global display instance (type alias for displayplatform_t).

displaystate_t carries per-draw-call render state flags:

DISPLAY_STATE_FLAG_CULL       // face culling
DISPLAY_STATE_FLAG_DEPTH_TEST // depth testing
DISPLAY_STATE_FLAG_BLEND      // alpha blending

Set state before drawing with displaySetState(state).


Screen (display/screen/)

screen_t SCREEN manages the logical viewport that game content renders into. On dynamic-size platforms (Linux/SDL2) the screen can differ from the native window/framebuffer resolution.

Screen modes:

SCREEN_MODE_BACKBUFFER           — maps 1:1 to backbuffer
SCREEN_MODE_FIXED_SIZE           — fixed pixel dimensions
SCREEN_MODE_ASPECT_RATIO         — fixed aspect, scale to fit
SCREEN_MODE_FIXED_HEIGHT         — fixed height, width scales
SCREEN_MODE_FIXED_WIDTH          — fixed width, height scales
SCREEN_MODE_FIXED_VIEWPORT_HEIGHT — fixed viewport height

The linux target defines DUSK_DISPLAY_SCREEN_HEIGHT=240, producing a 240p fixed-height viewport.

Render loop usage:

screenBind();       // set up viewport, projection
// ... draw game content ...
screenUnbind();
screenRender();     // blit to backbuffer / current framebuffer

SCREEN.width / SCREEN.height are the logical dimensions used for world-to-screen math — always prefer these over the framebuffer dimensions.


Framebuffer (display/framebuffer/)

framebuffer_t FRAMEBUFFER_BACKBUFFER is the platform backbuffer. FRAMEBUFFER_BOUND points to the currently-bound framebuffer (or NULL for backbuffer).

frameBufferInitBackBuffer();                        // called once at startup
frameBufferBind(fb);                                // NULL → backbuffer
frameBufferClear(FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, COLOR_BLACK);
frameBufferGetWidth(fb) / frameBufferGetHeight(fb) / frameBufferGetAspect(fb);

On platforms with DUSK_DISPLAY_SIZE_DYNAMIC, off-screen framebuffers can be created with frameBufferInit(fb, w, h) and disposed with frameBufferDispose(fb). Fixed-resolution platforms (PSP, GameCube) only ever use the backbuffer.


Mesh (display/mesh/)

mesh_t is a vertex buffer. The type is meshplatform_t (e.g. a VAO+VBO on GL, a GX display list on Dolphin).

meshInit(&mesh, MESH_PRIMITIVE_TYPE_TRIANGLES, vertexCount, verticesPtr);
meshFlush(&mesh, offset, count);  // upload CPU vertices → GPU
meshDraw(&mesh, offset, count);   // draw; pass -1 for count to draw all
meshDispose(&mesh);

Key distinction: meshFlush uploads data to GPU memory; meshDraw issues the draw call. For static geometry (chunk meshes) you call meshFlush once on load, then meshDraw every frame. For dynamic geometry (spritebatch) you meshFlush + meshDraw each frame.

meshvertex_t (display/mesh/meshvertex.h) contains:

  • float_t uv[2] — texture coordinates
  • float_t pos[3] — position
  • Optionally color_t color if MESH_ENABLE_COLOR is defined (off by default)

Primitive mesh generators live alongside mesh.h: quad.h, plane.h, cube.h, sphere.h, capsule.h, triprism.h.


Shader (display/shader/)

shader_t is shaderplatform_t (GLSL program on GL, TEV state block on Dolphin).

shaderInit(&shader, &definition);
shaderBind(&shader);
shaderSetMatrix(&shader, "uModel", modelMat);
shaderSetTexture(&shader, "uTexture", &texture);
shaderSetColor(&shader, "uColor", COLOR_WHITE);
shaderSetMaterial(&shader, &material);
shaderDispose(&shader);

Shader list (display/shader/shaderlist.h)

The engine maintains a small set of built-in shaders in SHADER_LIST_DEFS[]. Currently only one is defined:

  • SHADER_LIST_SHADER_UNLITSHADER_UNLIT — unlit textured/colored rendering, used for all world and entity drawing.

shaderListInit() compiles/uploads all built-in shaders and sets shared projection/view matrices. Call once after display init.

Materials (display/shader/shadermaterial.h)

shadermaterial_t is a union of all shader-specific material structs. Currently only shaderunlitmaterial_t:

shadermaterial_t mat = {
  .unlit = {
    .color = COLOR_WHITE,
    .texture = &myTexture,   // NULL for solid color
  }
};
shaderSetMaterial(&SHADER_UNLIT, &mat);

Texture (display/texture/)

textureInit(&texture, width, height, format, data);
textureDispose(&texture);

Width and height must be powers of two (asserted at init time).

textureformat_t is textureformatplatform_t. Supported formats vary by platform; the common ones are TEXTURE_FORMAT_RGBA and TEXTURE_FORMAT_PALETTE.

texturedata_t is a union:

// RGBA:
data.rgbaColors = colorArray;

// Paletted:
data.paletted.indices = indexArray;
data.paletted.palette = &palette;   // palette color count must be power of two

Built-in textures (defined in texture.c, no asset loading needed):

  • TEXTURE_WHITE — 4×4 solid white
  • TEXTURE_TEST — 4×4 black/magenta checkerboard

Palette (display/texture/palette.h)

Up to PALETTE_COUNT (6) global palettes in PALETTES[], each holding up to PALETTE_COLOR_COUNT (255) color_t entries.

Tileset (display/texture/tileset.h)

A tileset slices a texture into a grid of equal-sized tiles. Used by fonts and UI frames. The tileset does not own the texture — it references a texture_t *.


SpriteBatch (display/spritebatch/)

The primary 2D/billboard drawing primitive. Accumulates spritebatchsprite_t quads and flushes them in batches of SPRITEBATCH_FLUSH_COUNT (16) sprites at a time.

// Per frame:
spriteBatchClear();
spriteBatchBuffer(sprites, count, &SHADER_UNLIT, material);  // auto-flushes when batch full
spriteBatchFlush();  // flush remaining

// Low-level: write directly to an external mesh (for baking static geometry):
spriteBatchBufferToMesh(sprites, count, vertices, verticesSize);

spritebatchsprite_t:

typedef struct {
  vec3 min, max;     // 3D bounding box
  vec2 uvMin, uvMax; // texture region
} spritebatchsprite_t;

The global SPRITEBATCH and its vertex backing array SPRITEBATCH_VERTICES[] are defined externally to the struct to satisfy alignment requirements on certain platforms.


Text (display/text/)

Text rendering uses FONT_DEFAULT (loaded during textInit()), which references a texture and a tileset. Characters start at ASCII ! (TEXT_CHAR_START).

textDraw(x, y, "Hello", COLOR_WHITE, &FONT_DEFAULT);
textMeasure("Hello", &FONT_DEFAULT, &outWidth, &outHeight);

// Single-char sprite for manual layout:
spritebatchsprite_t s = textGetSprite(pos, 'A', &FONT_DEFAULT);

font_t holds a texture_t * and a tileset_t * — both are owned by the asset system, not the font struct.