A software renderer written from scratch in Go, in the spirit of the original Quake engine.
An esker is a ridge of sand and gravel left behind by a river that ran beneath a glacier — a landform made of a path. Northern Minnesota is full of them.
left = x- right = x+ up = y+ down = y- forward = z- back = z+
1 unit = 1 meter
Every pixel goes through math I derived myself. There is no graphics API doing 3D work here: Ebitengine provides a window and a way to push a buffer of bytes onto the screen, and nothing else. That is the same role DirectDraw played for WinQuake in 1996.
The point is not to produce a fast or complete engine. The point is to understand the pipeline well enough to rebuild it from nothing — transforms, projection, clipping, rasterization, depth, texture mapping — with the reasoning behind each stage worked out on paper first.
- Performance parity with anything modern
- OpenGL, Vulkan, or any hardware 3D path
- Being a usable game engine
- Copying the Quake source (reading it is fine, and mostly comes after the fact)
Derive what follows from the math. Read the source for what doesn't.
The transform pipeline, projection, clipping, depth buffering, and rasterization are all consequences of linear algebra and analytic geometry, so those get worked out from first principles. BSP trees, the potentially-visible set, and the Pentium FDIV interleave were solutions to a specific machine and a specific deadline — those get read about, understood, and then reimplemented in my own terms.
Each milestone puts something on screen.
- Project setup, Ebitengine window
- Owned framebuffer — byte slice,
SetPixel, blit once per frame - Clear to color, plot a pixel, pin down coordinate system orientation
- Line drawing (Bresenham)
-
Vec3,Mat4— port up a dimension from the existing 2D library - Hardcoded cube: 8 vertices, 12 edges
- Model → world → view → screen, drawing after each stage
- Perspective projection
- Free-look camera (WASD + mouse)
- Milestone: fly around a wireframe cube
- Triangle rasterization, flat-shaded
- Backface culling
- Depth buffer
- Near-plane clipping
- Milestone: solid cube that correctly occludes itself
- Mesh loading from file -- kind of done
- Affine texture mapping — done wrong deliberately, to see the warping
- Perspective-correct texture mapping
- Static lighting — face normals, dot product against a light direction
- Milestone: a textured, lit room to walk through
- Load a real Quake
.bspmap - BSP traversal for draw order
- Collision — player AABB, sliding along planes
- Gravity, jumping, movement feel
- Milestone: Quake movement in a Quake map
- Go — the language I know well enough to spend my debugging attention on the math instead of the memory
- Ebitengine — window and blit target only
- Michael Abrash, Graphics Programming Black Book — the contemporaneous account of these problems being solved
- id Software, Quake source (GPL, 1999) — read after getting stuck, not before
MIT

