The purpose of doomgeneric is to make porting Doom easier. Doom is already very portable, but with doomgeneric you can port it with just a few functions.
You need a WAD file (game data) to run Doom. The shareware version (doom1.wad) is included in the iwads/ folder.
For MIDI music support, a SoundFont file is included in the sounds/ folder:
gzdoom.sf2- GZDoom Classic SoundFont (3.1MB)
doomgeneric/
├── iwads/
│ └── doom1.wad # Doom shareware WAD
├── sounds/
│ └── gzdoom.sf2 # GZDoom Classic SoundFont
├── doomgeneric/ # Core Doom source code
└── platforms/ # Platform-specific implementations
├── sdl/ # SDL2 (cross-platform)
├── terminal/ # Terminal rendering (notcurses + SDL audio)
├── wasm/ # Standalone WebAssembly module
├── xlib/ # X11 (Linux)
├── linuxvt/ # Linux framebuffer
├── freebsd/ # FreeBSD with X11
├── emscripten/ # WebAssembly (browser)
├── djgpp/ # DOS with Allegro
├── soso/ # SoSo OS
└── sosox/ # SoSo OS with Nano-X
Each platform folder contains:
Makefile- Build configurationmain.c- Platform-specific implementation
From the project root directory:
# Build for a specific platform (using convenience targets)
make sdl
make terminal
# Or using PLATFORM variable
make PLATFORM=sdl
# Run
./platforms/sdl/bin/doomgeneric -iwad ./iwads/doom1.wad
# Run with MIDI music (SDL platforms)
SDL_SOUNDFONTS=$(pwd)/sounds/gzdoom.sf2 ./platforms/sdl/bin/doomgeneric -iwad ./iwads/doom1.wad
# Terminal platform with sound
SDL_SOUNDFONTS=$(pwd)/sounds/gzdoom.sf2 ./platforms/terminal/bin/doomgeneric -iwad ./iwads/doom1.wad| Platform | Description | Requirements |
|---|---|---|
sdl |
SDL2 rendering + sound | SDL2, SDL2_mixer |
terminal |
Terminal rendering with notcurses | notcurses, SDL2, SDL2_mixer |
wasm |
Standalone WebAssembly module | wasi-sdk |
xlib |
X11 rendering | X11 |
linuxvt |
Linux framebuffer | Linux |
freebsd |
FreeBSD with X11 | X11 |
emscripten |
WebAssembly (browser) | Emscripten SDK |
djgpp |
DOS | DJGPP, Allegro |
soso |
SoSo OS | musl-clang |
sosox |
SoSo OS with Nano-X | musl-clang, Nano-X |
-
Create a new folder under
platforms/:mkdir platforms/myplatform
-
Create
main.cimplementing these functions:Required functions:
Function Description DG_InitInitialize your platform (create window, framebuffer, etc.) DG_DrawFrameFrame is ready in DG_ScreenBuffer. Copy it to screen.DG_SleepMsSleep for given milliseconds DG_GetTicksMsReturn ticks since launch in milliseconds DG_GetKeyProvide keyboard events DG_SetWindowTitle(Optional) Set window title DG_Log(Optional) Handle log output. Default prints to stdout. Sound support (optional):
For sound effects and music, add
-DFEATURE_SOUNDto CFLAGS and include the appropriate sound modules in your build:Module Files Description SDL Sound i_sdlsound.cSound effects via SDL2_mixer SDL Music i_sdlmusic.cMIDI music via SDL2_mixer (requires SoundFont) Allegro Sound i_allegrosound.cSound effects via Allegro Allegro Music i_allegromusic.cMusic via Allegro These modules define
DG_sound_moduleandDG_music_modulewhich are used by the engine. -
Basic main loop structure:
#include "doomgeneric.h" // Implement DG_* functions here... int main(int argc, char **argv) { doomgeneric_Create(argc, argv); while (1) { doomgeneric_Tick(); } return 0; }
-
Create a
Makefile(use an existing one as template):# Directories SRCDIR=../../doomgeneric OBJDIR=./build BINDIR=./bin CC=clang CFLAGS+=-I$(SRCDIR) # ... add your platform flags OUTPUT=$(BINDIR)/doomgeneric SRC_DOOM = dummy.o am_map.o ... # (copy from existing Makefile) SRC_ENTRY = main.o # ... rest of Makefile rules
-
Build and test:
cd platforms/myplatform make ./bin/doomgeneric -iwad ../../iwads/doom1.wad
The wasm platform compiles DOOM to a standalone WebAssembly module that can be embedded in any host language (JavaScript, Rust, Go, Python, etc.).
# Install wasi-sdk from https://github.com/WebAssembly/wasi-sdk/releases
# Extract to /opt/wasi-sdk or set WASI_SDK environment variable
make wasm
# Output: platforms/wasm/bin/doomgeneric.wasmThe WASM module imports these functions from the host (module: env):
Video/Input (required):
| Import | Signature | Description |
|---|---|---|
DG_Init |
() -> void |
Initialize the platform |
DG_DrawFrame |
() -> void |
Render frame from screen buffer |
DG_SleepMs |
(ms: i32) -> void |
Sleep for milliseconds |
DG_GetTicksMs |
() -> i32 |
Get ticks since start |
DG_GetKey |
(pressed: *i32, key: *u8) -> i32 |
Get keyboard input |
DG_SetWindowTitle |
(title: *u8) -> void |
Set window title |
DG_Log |
(msg: *u8) -> void |
Handle log output |
Sound (optional - return 0/stub if not implementing):
| Import | Signature | Description |
|---|---|---|
DG_InitSound |
(samplerate: i32) -> i32 |
Init sound, return 1 on success |
DG_ShutdownSound |
() -> void |
Shutdown sound |
DG_StartSound |
(id, channel, vol, sep: i32, data: *u8, len: i32) -> i32 |
Play sound effect |
DG_StopSound |
(channel: i32) -> void |
Stop sound on channel |
DG_SoundIsPlaying |
(channel: i32) -> i32 |
Check if channel is playing |
Music (optional - return 0/stub if not implementing):
| Import | Signature | Description |
|---|---|---|
DG_InitMusic |
() -> i32 |
Init music, return 1 on success |
DG_ShutdownMusic |
() -> void |
Shutdown music |
DG_SetMusicVolume |
(volume: i32) -> void |
Set volume (0-127) |
DG_PauseMusic |
() -> void |
Pause music |
DG_ResumeMusic |
() -> void |
Resume music |
DG_PlayMusic |
(data: *u8, len: i32, loop: i32) -> void |
Play MIDI data |
DG_StopMusic |
() -> void |
Stop music |
DG_MusicIsPlaying |
() -> i32 |
Check if music is playing |
The WASM module exports these functions:
| Export | Signature | Description |
|---|---|---|
doomgeneric_Create |
(argc: i32, argv: i32) |
Initialize DOOM |
doomgeneric_Tick |
() -> void |
Run one game tick |
DG_ScreenBuffer |
() -> i32 |
Get pointer to pixel buffer |
DG_GetScreenWidth |
() -> i32 |
Get screen width (320) |
DG_GetScreenHeight |
() -> i32 |
Get screen height (200) |
doom_malloc |
(size: i32) -> i32 |
Allocate memory |
doom_free |
(ptr: i32) -> void |
Free memory |
DG_ScreenBuffer returns a pointer to a 320x200 array of 32-bit ARGB pixels.
See LICENSE file.