This commit is contained in:
2026-06-18 14:59:21 -05:00
parent 6135d60ddc
commit 730a5b2b10
17 changed files with 2825 additions and 415 deletions
+215
View File
@@ -0,0 +1,215 @@
# Display System
Source: `src/dusk/display/`
The display system is the rendering pipeline. It is abstracted across platforms via `displayplatform.h` — see [architecture.md](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](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:
```c
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:
```c
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).
```c
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).
```c
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).
```c
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_UNLIT``SHADER_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`:
```c
shadermaterial_t mat = {
.unlit = {
.color = COLOR_WHITE,
.texture = &myTexture, // NULL for solid color
}
};
shaderSetMaterial(&SHADER_UNLIT, &mat);
```
---
## Texture (`display/texture/`)
```c
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:
```c
// 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.
```c
// 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`:
```c
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`).
```c
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.