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

4.3 KiB

Architecture

Platform abstraction

Every subsystem that differs across platforms (display, input, asset loading, save, time, network, log) follows the same pattern:

  1. src/dusk/<subsystem>/<subsystem>platform.h — included by the public header. Contains #include "path/to/platform-specific-header.h" resolved by the build system include path.
  2. src/dusk{platform}/<subsystem>/<subsystem>platform.h — the actual platform-specific header included above (e.g. src/duskgl/display/framebuffer/framebufferplatform.h).
  3. The shared header (src/dusk/<subsystem>/<subsystem>.h) #errors at compile time if the platform doesn't define the expected macros/types.

The active platform backends are selected by DUSK_TARGET_SYSTEM in CMake, which includes cmake/targets/<system>.cmake. That file sets compile definitions (DUSK_LINUX, DUSK_SDL2, DUSK_OPENGL, …) and links platform libraries.

Platform source directories:

  • src/duskgl/ — OpenGL rendering (used on Linux and as the GL layer for SDL2)
  • src/dusksdl2/ — SDL2 window/input/time (Linux desktop)
  • src/dusklinux/ — Linux filesystem/save/network
  • src/duskdolphin/ — GameCube & Wii (GX renderer, libogc)
  • src/duskpsp/ — PSP (GU renderer, PSPSDK)
  • src/duskvita/ — PS Vita

Subsystem lifecycle

All subsystems follow init → update (per frame) → dispose. Engine initialization order matters and is centralized in engine.c:

systemInit → timeInit → consoleInit → inputInit → assetInit →
localeManagerInit → displayInit → uiInit → uiTextboxInit →
cutsceneInit → rpgInit → networkInit → sceneInit

Dispose runs in reverse. Each call uses errorChain() to propagate failures.

Error handling

Functions that can fail return errorret_t (a code + pointer to thread-local error state). Three core macros:

errorThrow("message %s", arg);        // sets error, returns from current function
errorChain(someCall());               // if someCall() fails, propagates and returns
errorOk();                            // returns success

Check with errorIsOk(ret) / errorIsNotOk(ret). The error state carries file/function/line info for a stack-like trace.

Fixed-point math

fixed_t is int32_t with Q24.8 format (8 fractional bits, ~0.004 resolution). Use it for all world/game values:

fixed_t x = FIXED(1.5);              // compile-time literal
fixed_t y = fixedFromI32(3);         // runtime conversion
fixed_t z = fixedMul(x, y);          // arithmetic
float_t f = fixedToFloat(z);         // only where float is needed (e.g. GL uniforms)

Code generation from CSV

Several subsystems define their data in CSV files and have corresponding Python tools that generate C headers at build time (via CMake add_custom_command):

CSV Tool Output
src/dusk/input/input.csv tools/input/csv/ input action enum + names
src/dusk/display/color.csv tools/color/csv/ color constants
src/dusk/rpg/item/item.csv tools/item/csv/ item enum + metadata
src/dusk/rpg/story/storyflag.csv tools/story/csv/ story flag enum + initial values

Generated headers are written to build-<target>/generated/ and included via target_include_directories.

Asset system

Assets are packed into dusk.dsk (a zip archive) at build time from the assets/ directory. At runtime asset.c opens the archive and serves files from it.

Loading is asynchronous: assetLock() registers a load request; the background thread calls the appropriate loader; call assetRequireLoaded() to block until ready. assetUnlock() / assetUnlockEntry() releases the entry so it can be reclaimed.

Loaders are registered per type (assetloadertype_t) and live under src/dusk/asset/loader/. Platform-specific asset init (finding the .dsk file) is in src/dusk{platform}/asset/.

Display subsystem

The display system is currently organized around immediate GPU-style rendering: mesh_t (vertex buffers), shader_t (GLSL on GL / TEV state on Dolphin), texture_t, and framebuffer_t. See display-refactor.md for the planned move to a render-queue model (needed for a future Saturn port).

The spritebatch_t (display/spritebatch/) accumulates 2D quads and flushes in batches — the primary 2D drawing primitive used by the RPG layer.