/terminal-doom

Fork of doomgeneric to support the Kitty graphics protocol

Primary LanguageCGNU General Public License v2.0GPL-2.0

terminal-doom

This fork of the amazing doomgeneric project adds support for the Kitty graphics protocol. As a result, Doom-based games now plays smoothly in modern terminals.

doom1.wad is included in the repository; other wad files are available on various online sites.

doomtty.mp4

Building on macOS

You may need to run brew install sdl && brew install --cask xquartz before compiling (addition step if you want sound, see next section)

Clone the repository and run make from the doomgeneric subdirectory to produce the doomgeneric executable.

Run it in a good terminal; tested in 👻, kitty and wezterm on macOS.

Sound support

Run brew install sdl2_mixer and uncomment the relevant lines from the Makefile... yes this will be improved.

Then run make clean && make

Building on Linux

Not tested properly on Linux yet, but feel free to try:

Install SDL and build with make -f Makefile.linux

May be slow or not work at all.

How does this even work?

While the Kitty graphics protocol is primarily intended to display images, modern terminals and computers are fast, with high memory bandwidth, simd support, and discrete GPUs. There's plenty of juice available to run this classic game smoothly over a text protocol.

Here's how it works: on every frame, doomgeneric calls DG_DrawFrame. Our job is to turn the pixel data into a base64 encoded payload. This payload is then split into 4K chunks, each chunk wrapped by the Kitty protocol envelope. Actually, some terminals work without chunking, which is even faster, but that's not spec compliant and e.g. Kitty itself fails without chunking (thanks to rockorager for pointing this out)

With the encoded message ready, we now:

  1. Set synchronized output (mode 2026)
  2. Clear the screen
  3. Display the frame by sending the Kitty graphics message
  4. Reset synchronized output to flush updates to screen
  5. Handle any keyboard input

This sequence repeats for every frame. While this is enough to run Doom smoothly in a modern terminal, there are many optimizations that can be done. This includes smarter screen clearing (only clear cells that the game occupies), and using SIMD for base64 encoding.

Supported games

These should all work:

doom2.wad
plutonia.wad
tnt.wad
doom.wad
doom1.wad
chex.wad
hacx.wad
freedm.wad
freedoom2.wad
freedoom1.wad

The remainder of the README is verbatime from doomgeneric:

doomgeneric

The purpose of doomgeneric is to make porting Doom easier. Of course Doom is already portable but with doomgeneric it is possible with just a few functions.

To try it you will need a WAD file (game data). If you don't own the game, shareware version is freely available (doom1.wad).

porting

Create a file named doomgeneric_yourplatform.c and just implement these functions to suit your platform.

  • DG_Init
  • DG_DrawFrame
  • DG_SleepMs
  • DG_GetTicksMs
  • DG_GetKey
Functions Description
DG_Init Initialize your platfrom (create window, framebuffer, etc...).
DG_DrawFrame Frame is ready in DG_ScreenBuffer. Copy it to your platform's screen.
DG_SleepMs Sleep in milliseconds.
DG_GetTicksMs The ticks passed since launch in milliseconds.
DG_GetKey Provide keyboard events.
DG_SetWindowTitle Not required. This is for setting the window title as Doom sets this from WAD file.

main loop

At start, call doomgeneric_Create().

In a loop, call doomgeneric_Tick().

In simplest form:

int main(int argc, char **argv)
{
    doomgeneric_Create(argc, argv);

    while (1)
    {
        doomgeneric_Tick();
    }
    
    return 0;
}

sound

Sound is much harder to implement! If you need sound, take a look at SDL port. It fully supports sound and music! Where to start? Define FEATURE_SOUND, assign DG_sound_module and DG_music_module.

platforms

Ported platforms include Windows, X11, SDL, emscripten. Just look at (doomgeneric_win.c, doomgeneric_xlib.c, doomgeneric_sdl.c). Makefiles provided for each platform.

emscripten

You can try it directly here: https://ozkl.github.io/doomgeneric/

emscripten port is based on SDL port, so it supports sound and music! For music, timidity backend is used.

Windows

Windows

X11 - Ubuntu

Ubuntu

X11 - FreeBSD

FreeBSD

SDL

SDL