DOOM Source Release: The Portable Engine That Outlived Its Own Machine

Inside `linuxdoom-1.10`, the split between system code and game code, the 35 Hz heartbeat, and the fixed-point tricks that made a 1993 shooter a permanent portability benchmark.

10 min read • View on GitHub • More from id-software

A split mechanical engine on a white background. One side shows a small bundle of plugs, cables, and interchangeable gearboxes, while the other side shows a larger clockwork core driving a miniature battlefield and timing wheel. The composition explains that DOOM’s platform code can be swapped without disturbing the simulation underneath.
DOOM’s source release reads like a lesson in separation of concerns. The shell changes. The engine keeps turning.
Key Takeaways

The surprise in the `linuxdoom-1.10` tree is not that it runs a famous game. It is that the code was already organized like a portability kit. The platform-facing pieces live in the `i_` files, while the game’s logic, physics, and rendering sit behind them like a core that can be carried to a new machine with surprisingly little surgery.

Here it is, at long last. The DOOM source code is released for your non-profit use. You still need real DOOM data to work with this code. If you don't actually own a real copy of one of the DOOMs, you should still be able to find them at software stores.

John Carmack, Lead Programmer, id Software · DOOM Open Source Release README.txt

A Game Engine Built to Be Moved

The source release matters because it exposed an engine that was designed for reuse before “engine” was a fashionable word in games. `i_main.c` is basically a wrapper around `D_DoomMain()`. That is the tell. The executable starts in the platform layer, hands off immediately, and lets the rest of the program pretend the machine beneath it is just another replaceable part.

DOOM does not think in frames first. It thinks in tics. That is why one command stream can power live play, demos, and network sync.

The `i_` Files Are the Secret

The architecture split is almost comically elegant. The `i_` files handle video, sound, input, and OS glue. Everything else assumes those chores are someone else’s problem. That boundary made the Linux release valuable to porters because they only had to rewrite the shell, not reassemble the brain.

int main(int argc, char **argv)
{
    D_DoomMain();
    return 0;
}

That tiny handoff is the whole story in miniature. The code is not modular in the abstract, it is modular in the way that matters under deadline and on weak hardware. Replace the interface layer, keep the simulation stable, and the game still behaves like DOOM.

35 Hz: The Game’s True Pulse

Modern engines often let rendering define the rhythm. DOOM does the opposite. Its heartbeat is the 35 Hz tic rate, and the core loop advances one simulation step at a time. That choice makes the game feel locked, repeatable, and exact, which is why demo playback and multiplayer can reuse the same command stream instead of trying to reconstruct intent from rendered frames.

DOOM tic loopModern frame-driven engine
Simulation advances on fixed ticsSimulation often follows render cadence
Input becomes a command recordInput is usually sampled per frame
Demo playback can replay the same commandsPlayback often needs special capture logic
Network play stays deterministic when rules matchNetwork code may compensate for variable frame timing

The point is not nostalgia. The point is that fixed timing turns a game into a machine that can be reproduced. If you can replay the same commands, you can study, port, speedrun, and debug the same behavior across wildly different systems.

A close-up of a circular chain of linked object cards on a white background. Each card represents a moving entity such as a monster, projectile, or effect token. A timing metronome sits beneath the chain at 35 Hz, while one token is removed and another snaps in immediately, illustrating the thinker system’s fast insertion and deletion.
DOOM keeps active objects in a lightweight thinker list. The engine updates only what is alive, then moves on at the next tic.

How DOOM Cheats Physics Without Feeling Cheap

The code cheats in the best possible way. It uses fixed-point math instead of floating point, which mattered on machines that could not afford expensive arithmetic. The world is also “2.5D” rather than fully 3D. Floors, ceilings, and heights create the illusion of space, while the underlying simulation stays compact enough to move fast.

DOOM’s approachWhat that buys
Fixed-point arithmeticPredictable speed on weak CPUs
Thinker list for active objectsFast iteration over monsters and projectiles
2.5D level modelA convincing 3D feel with simpler math
Deterministic state updatesReliable demos, replays, and ports

That is the broader pattern across the codebase. DOOM avoids expensive generality wherever it can. It keeps the moving pieces small, explicit, and easy to replay. The result is not a toy engine. It is a brutally efficient one.

Why the Linux Release Became a Source-Port Factory

We couldn't release the dos code because of a copyrighted sound library we used (wow, was that a mistake -- I write my own sound code now)

John Carmack, Lead Programmer, id Software · DOOM Open Source Release README.txt

The Linux release was not a compromise in spirit. It was the codebase most legally available to publish, and it still contained the essential architecture. That was enough. Once people had the engine, they could retarget it, modernize it, and disagree about how much of the original experience should survive.

Port styleWhat it tries to preserveWhat it adds
Chocolate DoomOriginal timing, limits, feelVery little beyond faithful execution
Crispy DoomVanilla behaviorHigher resolutions, widescreen, limit removal
GZDoomThe Doom lineageHardware acceleration, scripting, major feature growth

That spectrum is the legacy of the release. The original code became a reference point, then a bargaining chip, then a shared language. Every port has to answer the same question: are you preserving DOOM, or extending it?

What Every Modern Port Is Really Arguing About

The source-port ecosystem is not just a family tree. It is a long-running debate about boundaries. Purist ports defend the original machine. Feature-rich ports treat the engine as a living substrate. The source release made both positions possible, which is why the code still matters long after the original hardware vanished.