enDjinn (a play on “engine” and the invisible helper of myth) is a small, Dreamcast-first C runtime and build system. It handles recurring KOS/PVR boilerplate while keeping the Dreamcast rendering model visible: applications work with modes, PVR render lists, controllers, textures, fonts, sound, and VMU/rumble devices rather than a generic cross-platform scene API.
- A frame loop that owns PVR scene setup and teardown.
- A stack of
enj_mode_tgame modes, including activation callbacks and soft reset support. - Render-list callbacks for opaque, punch-through, and translucent PVR lists.
- Controller state transitions, abstract controllers, rumble, and VMU hooks.
- Build-time conversion of supported texture, TrueType font, and sound assets.
- A built-in quick font (
qfont) for fast text rendering, plus generated proportional.enjfontfiles. dctraceanddcprofprofiling helpers.
The examples are the best source of working, feature-specific code.
enDjinn expects an active KallistiOS environment. The repository’s
environ.sh is a local convenience script for its configured
toolchain location; use your own KOS environ.sh if it lives elsewhere.
Create a project with code/, optionally assets/, a local.cfg.mk, and a
Makefile symlink to base_link.mk:
mkdir -p my-game/code
cd my-game
ln -s /path/to/enDjinn/base_link.mk Makefile
printf 'ENJ_INJECT_QFONT:=1\n' > local.cfg.mkThen build from the project directory with make. The default Dreamcast
target is bin/<project-name>.elf. make bin/<project-name>.cdi creates a
CDI image, and make bin/<project-name>.bin creates a raw binary.
The minimal application is the hello example:
#include <enDjinn/enj_enDjinn.h>
void render(void *__unused) {
enj_qfont_write("Hello, enDjinn!", 20, 20, PVR_LIST_PT_POLY);
}
void update(void *__unused) {
enj_render_list_add(PVR_LIST_PT_POLY, render, NULL);
}
int main(__unused int argc, __unused char **argv) {
enj_state_init_defaults();
if (enj_state_startup() != 0) return -1;
enj_mode_t mode = {.name = "Main", .mode_updater = update};
enj_mode_push(&mode);
enj_state_run();
return 0;
}Call enj_state_init_defaults(), then enj_state_startup(), push at least
one mode, and call enj_state_run(). A mode’s mode_updater is called every
frame. It should update its state and register renderer callbacks with
enj_render_list_add(); enDjinn invokes each callback in the matching PVR
phase.
The mode stack is LIFO: push a pause/menu mode over the game, then call
enj_mode_flag_end_current() to end it on the next loop iteration and resume
the previous mode. on_activation_fn is called when a revealed mode becomes
active. Use enj_mode_soft_reset_target_set() to choose where the default
Start+A+B+X+Y soft-reset combination returns.
By default, source code is read from code/, textures from assets/texture,
fonts from assets/fonts, and sound effects from assets/sfx. Generated
Dreamcast assets are placed under cdrom/<project-name>/ unless overridden.
Texture conversion is selected by the directory below assets/texture:
pal4, pal8, pal4_vq_tw, pal8_vq_tw, rgb565_vq_tw, and
argb1555_vq_tw are supported. PAL4 and PAL8 textures are always twiddled by
the hardware format; the _vq_tw variants additionally enable VQ compression.
TrueType files in assets/fonts/<pixel-height>/ become .enjfont files. Sound
files in the supported ADPCM or PCM directory layouts become .dca files. The
sound converter must be installed as dcaconv on PATH, or supplied as
SOUNDMACHINE=/path/to/dcaconv. Builds never clone dependencies.
Put project-specific overrides in local.cfg.mk. The most useful current
variables are:
| Variable | Purpose |
|---|---|
ENJ_TARGET |
dreamcast (default), pc-endjinn, or web-endjinn. |
ENJ_BASENAME |
Output/project name; defaults to the current directory name. |
ENJ_CODEDIR |
C source directory; defaults to ./code. |
ENJ_ROMDIR |
CD-ROM asset root; defaults to cdrom. |
ENJ_BUILDDIR, ENJ_BINDIR |
Object and output directories; default to build and bin. |
ENJ_LDLIBS |
Extra libraries passed to the Dreamcast link step. |
ENJ_PAL4_PVRTEX_FLAGS, ENJ_PAL8_PVRTEX_FLAGS |
Extra pvrtex flags for uncompressed palettized textures. |
ENJ_PAL4_VQ_TW_PVRTEX_FLAGS, ENJ_PAL8_VQ_TW_PVRTEX_FLAGS |
Extra pvrtex flags for VQ-compressed palettized textures. |
SOUNDMACHINE |
Path to the required dcaconv executable. |
ENJ_CFLAGS |
Additional C compiler flags. |
OPTLEVEL |
Optimisation level passed as -O; default is g. |
ENJ_DEBUG |
Enables ENJ_DEBUG_PRINT and Dreamcast debug instrumentation. |
ENJ_FSAA |
Enables FSAA and changes ENJ_XSCALE accordingly. |
ENJ_FRAME_RATE |
Enables a frame-rate deadline when set to a positive value. |
ENJ_WEB_SIMD |
Set to 1 to compile and link web-endjinn with WebAssembly SIMD128; defaults to 0. |
ENJ_USE_SH4ZAM |
Set to 1 to build and link the optional SH4ZAM integration for the selected target. |
SH4ZAM_DIR |
Optional path to the SH4ZAM source tree when automatic discovery is unsuitable. |
ENJ_INJECT_QFONT |
Builds and embeds the built-in quick font. |
ENJ_ADD_LOGO_TEXTURE |
Adds enDjinn logo textures to the generated assets. |
When ENJ_USE_SH4ZAM=1, enDjinn builds SH4ZAM natively with CMake for
pc-endjinn, compiles its software implementation with Emscripten for
web-endjinn, and compiles its SH-4 implementation with KOS for dreamcast.
The integration is disabled by default; applications that use shz_* APIs
should enable it in local.cfg.mk. Set SH4ZAM_DIR explicitly or place the
source tree next to the application or enDjinn, or under third_party/ or
vendor/ in the application.
Set ENJ_WEB_SIMD=1 to pass -msimd128 to every WebAssembly compilation and
the final link, including optional integrations such as SH4ZAM. Leave it at
the default 0 when producing a scalar compatibility build.
Run make cfg_info in a project directory to inspect the resolved build
configuration, and make auto_variables to inspect generated asset and
object lists. make assets generates the same declared asset blobs for either
selected backend without linking an executable.
Set ENJ_TARGET=pc-endjinn to compile the supported runtime subset against
SDL2 and Vulkan/MoltenVK. It recompiles the same application against
KOS-shaped compatibility headers and links PC implementations of the required
KOS symbols; it is not a binary-only replacement for an already compiled
Dreamcast executable. This is a development backend, not a full Dreamcast
emulator.
From an enDjinn application directory:
make ENJ_TARGET=pc-endjinn
./build/pc-endjinn/my-gameThe executable name defaults to the application directory name.
The backend supports the geometry, texture and palette formats used by the examples, PCM sound effects, keyboard and SDL controllers, host save-file storage, and screen-space modifier masks. Rumble, VMU LCD output, and some PVR state remain unsupported. See the PC backend README for setup and usage and the support matrix for exact coverage.
Set ENJ_TARGET=web-endjinn to compile the same application and generated
assets to WebAssembly with Emscripten, SDL2, and WebGL 2:
make ENJ_TARGET=web-endjinn
emrun build/web-endjinn/my-game.htmlThe browser target reuses the PC backend's input, audio, filesystem, and PVR packet decoding shims. Its KOS-compatible sleep shim yields the unchanged engine loop to the browser through Emscripten Asyncify. See the browser backend README for details.
The repository includes profilers/dctrace.py, profilers/dcprof/, and
helper scripts under profilers/. Set ENJ_DCTRACE or ENJ_DCPROF in
local.cfg.mk to include the corresponding Dreamcast-side instrumentation.