Article by Felix Jones

Is the Original Doom faking a 3D world?

Whether Doom is truly a "3D game" is an arguable topic as the physics of Doom and the level data of Doom are both undeniably 2D, but the player-view of the game world looks to be 3D projection.

I am on the side that Doom is a 3D game and frankly I've seen too many people get into this debate without any technical information backing their argument.

Even worse is that some people have based their arguments on incorrect information and assumptions, as recently posted in a worryingly popular YouTube video (Let's not come up with Theories about this Game and actually look at the computer science behind it!).

By understanding how Doom works underneath I believe we can better argue our case for (or against) Doom being a true 3D game.

Building a 2-Dimensional World

This here is E1M1 after I loaded it up in the Doom Builder level editor.

The main data structure in a Doom map is the sector; a structure made up of multiple lines in a loop (linedefs), with each line geometrically defined by two vertices. You can find these over in the r_defs.h file.

Here I've stripped out the meta data, leaving only the crucial map layout definition:


/*====================
    r_defs.h
 ====================*/

typedef struct {
    fixed_t x;
    fixed_t y;
} vertex_t;

typedef struct line_s {
    vertex_t *  v1;
    vertex_t *  v2;
    /* ... */
    sector_t *  frontsector;    /* Lines also store their parent sectors */
    sector_t *  backsector;
    /* ... */
} line_t;

typedef	struct {
    /* ... */
    int         linecount;
    line_t **   lines;  /* Lines can be shared between sectors */
} sector_t;
    

With these three structures, 2D geometry can be defined as sectors connected to other sectors by their lines.

Back in 1993 the developers would use a BSP compiler program to generate the BSP culling tree and add all the meta data needed for the game's runtime.

From knowing the way levels are built, a lot of people will then go on to claim that this is why Doom is secretly a 2-dimensional game trying to do some kind of smoke-and-mirrors trickery. Now that we know what makes the world inside Doom stick together, the next step is drawing it in 3D.

Rendering a 3-Dimensional World

Within r_main.c is the function that draws the 3D world of Doom; void R_RenderPlayerView( player_t * player );.

R_RenderPlayerView calls the following functions in order:


/*====================
    r_main.c
 ====================*/

void R_RenderPlayerView( player_t * _player ) {
    R_SetupFrame( _player );    /* Orders you a pizza or something */

    R_ClearClipSegs();  /* Resets the line clipping */
    R_ClearDrawSegs();  /* Resets the line segments (upper, lower, solid) */
    R_ClearPlanes();    /* Resets the sector planes (floor, ceiling) */
    R_ClearSprites();   /* Resets the sprite list */

    R_RenderBSPNode( numnodes - 1 );    /* Draws all visible lines, builds line clipping */
    R_DrawPlanes();                     /* Draws all visible sector floors/ceilings */
    R_DrawMasked();                     /* Draws all sprites in the sprite list (includes segment middles) */
}
    

R_RenderBSPNode, R_DrawPlanes and R_DrawMasked perform the rendering. R_SetupFrame is an empty function.

This is E1M2's opening screen being rendered by each of these functions.

Everything is drawn out. Ceilings are high, floors are low, walls are perpendicular to the floor and things get pretty darn small over in the distance. That has to be 3D, right?