Quake II app icon

A fork of yquake2 5.11 tuned for seven old Macs spanning 1999 to 2019. It's the sister project to QuakeSpasm for old Macs: same machines, same test rack, same trick of bundling four chip-specific builds (G3, G4, G5 and Intel) into one app. On top of the 5.11 base come bullet and blood marks on the walls, edge-smoothing, fog, the underwater wobble, and faster monster animation using AltiVec — mostly ported from KMQuake2 and yquake2 rather than written from scratch. The same app loads different settings on each Mac depending on which model it spots when it starts.

It's a personal project: I love Quake and I collect and tinker with old Macs. My part is the setup and testing — the build, deploy and benchmark scripts, and the per-machine settings. The engine and config changes were made mostly with AI (Claude), which I directed and checked against real benchmarks on the machines.

There's also an Apple Watch companion: a cvar-gated patch streams the player's live health, ammo and objectives off the Mac so the watch can render Quake II's help computer on your wrist. It's off by default and adds nothing to the normal build.

# First build vs current

Two builds on the same machines, both running the same recorded demo (demo1.dm2). The "first build" column is v1.0.0: plain yquake2 5.11 with just enough changes to compile on Lion. The "with features" column is v2.0.0, the build where all the visual features went on (the current release is v2.5.1, which added crisp stencil shadows across the PowerPC machines). The "Floor" column is the lowest frame rate I'll accept on each machine before the game stops feeling smooth.

Machine First 640 Now 640 Δ First 1024 Now 1024 Δ Floor
imac-2019 709.20 711.75 +0% 701.60 726.40 +4% 60 ✓
mini-intel 59.40 222.80 +275% 80.80 100.30 +24% 60 ✓
mini-g4 126.90 100.45 −21% 99.15 56.80 * −43% 60 ✓
sawtooth 95.00 72.90 −23% 82.90 65.45 −21% 60 ✓
quicksilver 72.40 70.70 −2% 68.50 68.60 +0% 60 ✓
yosemite 65.15 46.20 −29% 31.60 25.20 −20% 20 ✓

* mini-g4 1024 is the worst observed after hours of continuous benching, thermal degradation on the G4. Cool-machine numbers are around 97 fps. The iMac G5 isn't in this table because it only runs its native 1440×900 (its Leopard driver hangs on a mode switch); there it holds around 47 fps with everything on, a deliberate choice to keep the visuals rather than chase frames.

The big jump is the mini-intel, up 275%, and that came from a single line of code. macOS was making the game wait for the monitor to refresh 60 times a second even though I'd told it not to, which pinned the frame rate at 60. One line (an SDL call telling it not to wait) and the cap was gone.

The drops are the price of the new graphics: decals, fog, the wobble you see underwater, smoother textures, shadows under the monsters and more, all added one at a time. The G3 lost 20–29% because its 1999 graphics chip can only colour in so many pixels a second, and every effect eats into that budget. The same effects barely touch the 2019 iMac, which has power to spare. Every machine still clears its floor. On the G3 the lower number is deliberate: I prefer the richer picture, and it stays playable above its 20 fps floor.

Quake II on yosemite, a 1999 PowerMac G3 with an ATI Rage 128: BFG ball mid-flight with hyperblaster spray and a Strogg in the corridor
yosemite: 1999 PowerMac G3 / Rage 128
Quake II on sawtooth, a 1999 PowerMac G4 AGP with a GeForce2 MX: BFG ball with red decal sparks around a Strogg
sawtooth: 1999 PowerMac G4 AGP / GeForce2 MX
Quake II on quicksilver, a 2001 PowerMac G4 with a Radeon 9000: Gladiator in a gold-lit room with the BFG raised
quicksilver: 2001 PowerMac G4 / Radeon 9000
Quake II on mini-g4, a 2005 Mac mini G4 with a Radeon 9200: Gladiator in a gold-lit room with the BFG raised
mini-g4: 2005 Mac mini G4 / Radeon 9200
Quake II on mini-intel, a 2007 Mac mini Core 2 Duo with a GMA 950 on Lion: Strogg running across a warmly lit corridor
mini-intel: 2007 Mac mini / GMA 950 / Lion
Quake II on sawtooth: Gladiator getting hit by the Super Shotgun, red bullet-impact decals spraying off the body
sawtooth: Super Shotgun hit, decal spray

# Get the build

The current release is v2.5.1, which added crisp stencil shadows across the PowerPC machines.

Bundle Runs on
Quake2-OldMac-v2.5.1.dmg All seven benched Macs (Panther 10.3.9 → Sequoia 15.7)

The one universal app runs unchanged on everything from Panther 10.3.9 to Sequoia 15.7. When it launches, macOS picks the right build for that Mac's chip, then the game checks which model of Mac it's on and loads that machine's own settings file from inside the app. It doesn't come with the actual game data (the .pak files), so you bring those from your own copy on Steam, GOG, or an old retail CD.

# The bench

Machine Year CPU GPU macOS
yosemite 1999 PowerMac G3 B&W, 449 MHz ATI Rage 128, 16 MB 10.3.9 Panther
sawtooth 1999 PowerMac G4 AGP, 500 MHz 7400 NVIDIA GeForce2 MX, 32 MB 10.4.11 Tiger
quicksilver 2001 PowerMac G4, 733 MHz 7450 Radeon 9000 Pro, 64 MB 10.4.11 Tiger
mini-g4 2005 Mac mini G4, 1.25 GHz 7447A Radeon 9200, 32 MB 10.4.11 Tiger
imac-g5 2005 iMac G5, 2.0 GHz 970FX Radeon 9600, 128 MB 10.5.8 Leopard
mini-intel 2007 Mac mini, 2.33 GHz Core 2 Duo Intel GMA 950, 64 MB shared 10.7.5 Lion
imac-2019 2019 iMac 27", 3.7 GHz i5-9600K Radeon Pro 580X, 8 GB 15.7 Sequoia

# Architecture

An Ubuntu workstation drives all seven Macs over the network (ssh). The Lion mini is where everything gets built: it holds the compiler toolchains for the G3 (10.3.9 SDK), the G4 (10.4u SDK with AltiVec), the G5 (10.5 SDK) and Lion's Intel chips (x86_64).

Architecture diagram showing Ubuntu workstation orchestrating seven Mac bench targets via the Lion mini cross-build host
Architecture: Ubuntu orchestrator drives seven Macs via the Lion mini cross-build host

Four toolchain passes build four versions of the program, one per chip (G3, G4, G5 and Intel), and Apple's lipo tool glues them into a single universal file inside Quake2.app. No fancy build servers or containers, just rsync, ssh and scp on top of make.

Build pipeline diagram showing four toolchains (g3, g4, g5 SDKs and lion clang) converging through lipo into one fat binary
Build pipeline: four toolchain passes, four CPU-specific binaries, one universal file

The test loop is the same on every machine: copy the new build over, launch it with timedemo demo1.dm2, read the result out of the log, and write a row to a running spreadsheet tagged with the code version.

Bench loop showing deploy, launch with timedemo, poll qconsole.log, parse fps, append to results.csv
Bench loop: deploy, launch timedemo, parse fps, append to CSV

# Frames per second across the rack

timedemo demo1.dm2 at commit 00530b6a. Three runs per cell, reported figure is the middle one.

Machine 640×480 1024×768 Floor Settings applied
imac-2019 711.75 726.40 60 everything on (the GPU is never the limit), MSAA
mini-intel 222.80 100.30 60 full-res textures, anisotropic filtering, fog, underwater warp, world decals, MSAA
mini-g4 100.45 56.80 60 full-res textures, anisotropic filtering, dynamic lights, fog, underwater warp, world decals, MSAA
sawtooth 72.90 65.45 60 full-res textures, anisotropic filtering, light halos, fog, underwater warp, world decals
quicksilver 70.70 68.60 60 full-res textures, anisotropic filtering, dynamic lights, fog, underwater warp, world decals, MSAA
yosemite 46.20 25.20 20 full-res textures, anisotropic filtering, monster shadows, fog, underwater warp, world decals

quicksilver sits at about 71 fps at both sizes: that's its screen's refresh rate, and the game is waiting for it rather than being held back by the graphics. So there's still room there for more effects. The iMac G5 isn't in the table because it only runs its native 1440×900, where it holds around 47 fps with everything on.

# Tech stack

C OpenGL 1.x AltiVec PowerPC Apple gcc 4.0.1 Apple clang SDL 1.2 stb_image Bash ssh + rsync