4.1 KiB
Asset System
Source: src/dusk/asset/
Overview
All game assets are packed into a single ZIP archive named dusk.dsk
(ASSET_FILE_NAME). The asset system loads entries from this archive
asynchronously on a background thread, caches them, and provides
synchronous blocking access when an asset is required immediately.
Key limits
| Constant | Value | Meaning |
|---|---|---|
ASSET_LOADING_COUNT_MAX |
4 | Concurrent in-flight loads |
ASSET_ENTRY_COUNT_MAX |
128 | Cached entries |
Top-level API (asset.h)
errorret_t assetInit(); // Open dusk.dsk, start background thread
void assetUpdate(); // Dispatch completed-load callbacks (main thread)
errorret_t assetDispose(); // Wait for loads, close archive
assetentry_t *assetGetEntry(
const char_t *path,
assetloadertype_t type,
assetloaderinput_t *input
); // Get (or create) a cache entry; does NOT start loading
errorret_t assetRequireLoaded(assetentry_t *entry);
// Block the calling thread until this entry is fully loaded.
// Only safe to call from the main thread.
void assetLock(assetentry_t *entry);
void assetUnlock(assetentry_t *entry);
// Reference counting. Lock before using loaded data; unlock when done.
// The entry will not be evicted while locked.
Asset entry states
Each cache entry goes through a state machine:
IDLE -> QUEUED -> READING (async) -> PROCESSING (sync, main thread) -> LOADED
-> ERROR
- READING runs on the background loader thread (file I/O).
- PROCESSING runs on the main thread (GPU uploads, parsing finalization).
- Once LOADED, data is available in
entry->data.
Loader types
Loader types are registered in the ASSET_LOADER_CALLBACKS[] table.
Each type implements three callbacks: loadSync, loadAsync, dispose.
assetloadertype_t |
Data read | Description |
|---|---|---|
ASSET_LOADER_TYPE_TEXTURE |
STB image | Loads image bytes async, creates GPU texture sync |
ASSET_LOADER_TYPE_TILESET |
.dtf binary |
Custom tile format (magic, version, grid, UVs) |
ASSET_LOADER_TYPE_MESH |
.stl |
STL mesh with configurable axis orientation |
ASSET_LOADER_TYPE_JSON |
yyjson | Up to 256 KB; parsed async |
ASSET_LOADER_TYPE_LOCALE |
Gettext .po |
PO parser with plural-form expression evaluation |
ASSET_LOADER_TYPE_SCRIPT |
JS source | JerryScript module |
Adding a new loader type
- Add an enum value before
_COUNTinassetloadertype_t(src/dusk/asset/loader/assetloader.h). - Add fields to the input/loading/output unions in
assetloader.h. - Implement
assetXxxLoaderSync,assetXxxLoaderAsync, andassetXxxDisposeinsrc/dusk/asset/loader/xxx/. - Register the three callbacks in
ASSET_LOADER_CALLBACKS[]insrc/dusk/asset/loader/assetloader.c. - If user-facing, create a JS module and a
.d.tsfile (seeCLAUDE.md).
Asset batch (assetbatch.h)
assetbatch_t groups multiple asset requests into a single logical
load. All entries in the batch start loading concurrently. The batch
fires a completion callback once every entry has reached LOADED (or
ERROR).
assetbatch_t batch;
assetBatchInit(&batch, entries, count, onComplete, user);
assetBatchStart(&batch);
// ... later, after assetUpdate() fires the callback ...
assetBatchDispose(&batch);
Usage pattern
// 1. Get or create the cache entry (no I/O yet).
assetentry_t *tex = assetGetEntry(
"textures/hero.png",
ASSET_LOADER_TYPE_TEXTURE,
NULL
);
assetLock(tex);
// 2. Option A -- non-blocking: check tex->state each frame.
// Option B -- blocking (main thread only):
errorChain(assetRequireLoaded(tex));
// 3. Use the loaded data.
texture_t *t = &tex->data.texture;
// 4. Release when done.
assetUnlock(tex);
Error macros (inside loader implementations)
assetLoaderErrorThrow("msg %d", val); // errorThrow equivalent
assetLoaderErrorChain(someCall()); // errorChain equivalent
Use these instead of the bare error macros inside loader callbacks so that failures include the loader context in the stack trace.