Skip to content

Releases: matthewdeaves/old-mac-quakespasm

v1.13 — online multiplayer, weapon damage decals, lightning & axe fixes

06 Jun 17:01

Choose a tag to compare

v1.13 — online multiplayer, weapon damage decals, lightning & axe fixes

The first gameplay-feature release on top of the perf/visual tuning baseline.
One fat universal binary (PowerPC G3 + G4 + G5 + Intel x86_64) that runs from
Mac OS X 10.3.9 Panther through modern macOS, picking the right code slice and
per-machine config automatically at launch.

━━ ONLINE MULTIPLAYER ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Browse → join → auto-download → play, end to end:

• In-menu server browser via a DPMaster master-server query — live public
servers listed with name, current map, player count and ping, so you can
join without a manual connect <ip>.
• In-protocol UDP auto-download of any map or asset the server is running
that you don't have (QSS / DarkPlaces style — no TLS, no curl, no new
libraries). Joining pulls the content, then drops you straight in.
• Gated and safe by default: allow_download is 0 until you opt in.

Verified end-to-end against the public denver.quakeone.com server, with a
PowerPC Mac and an Intel Mac sharing the same live match — a 449 MHz G3 on
Panther can play online with a 2019 iMac.

━━ WEAPON DAMAGE DECALS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Every weapon now leaves a fitting mark on walls, floors and ceilings:

• Shotgun / super shotgun → bullet holes
• Nailgun → small pocks, super nailgun → bigger pocks
• Axe → slash gashes
• Spikes (Scrag / Spawn) → scorch stars
• Grenades / rockets → burn scars
• Lightning gun → lightning scars

Ported from the sister Quake 2 port's BSP fragment clipper (Sutherland–Hodgman
projection onto the surfaces around each impact). Runtime-gated via r_decals,
with cvars for max count, lifetime and fade.

━━ RENDERING & GAMEPLAY FIXES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Lightning bolt now renders its bright light-blue colour on every GPU in
the fleet (it was dark on the Radeon 9200 and GMA 950). The bolt's bright
core lives in fullbright-palette texels the model loader splits into a
separate additive mask the old draw path wasn't emitting; beams now draw
fullbright-unlit (base + additive core) on a single GL 1.1 path every
driver renders identically. Root-cause trail in docs/LIGHTNING_BOLT_DEBUG.md.
• Axe chops leave a slash, not a bullet mark — the active-weapon network
stat truncates IT_AXE to 0 in standard Quake, so the axe is now detected
from its viewmodel (protocol-independent).
• Viewmodel no longer flashes black, and emissive light/lava texels no
longer flicker black on the GMA 950 (alias state-cache reset before the
viewmodel; gl_fullbright_zbias armed on mini-intel).

Hardware-verified on mini-intel (GMA 950) and mini-g4 (Radeon 9200); the
release DMG is content-verified byte-for-byte and production-smoke-tested.

v1.12 — Watch tactical-computer feed on every Mac

04 Jun 17:13

Choose a tag to compare

Fix: the Apple Watch / iPhone "tactical computer" companion now works fleet-wide

Previously only the imac-g5 and mini-intel per-machine cfgs armed the watchlink
feed, so the companion HUD received no data on the G3, the G4s, or any Mac
whose model isn't in the per-machine map — watch_host stayed at its off
default ("").

This release puts Bonjour auto-discovery (watch_host "auto") in all four
per-arch baselines (ppc750=G3, ppc7400=G4, ppc970=G5, x86_64=Intel). Per
host.c the per-arch cfg runs after config.cfg and the per-machine overlay
leaves watch_host untouched, so this covers every Mac of each arch
including models not in the machine map — with a single knob. The wrist now
"just works" on any supported Mac with no console command. Discovery is
time-bounded (~30 s) and inert during demos, so a phoneless game costs nothing.

No engine code changed — the binary is byte-for-byte identical to v1.11; only
the staged config differs. DMG built and content-verified on Tiger (mini-g4).

Companion app: https://github.com/matthewdeaves/quake2-tactical-watch

v1.11 — Apple Watch tactical-computer companion (watchlink) + R300/PPC fixes

04 Jun 16:36

Choose a tag to compare

Live Apple Watch tactical-computer support plus two PowerPC rendering fixes.

New

  • watchlink — a cvar-gated UDP/JSON feed of live player state (health, armor, ammo, weapon, powerups, pickups, damage) to a wrist-worn tactical computer. An iPhone relays it over the LAN to an Apple Watch HUD with damage haptics. Off by default (watch_host ""); point it at a host or use watch_host "auto" for Bonjour discovery. Debug with nc -ul 27999. See docs/WATCHLINK.md.
    • Companion app (iPhone relay + watchOS): https://github.com/matthewdeaves/quake2-tactical-watch
    • Forwards local-player pickup/vocal sounds (incl. ammo/backpack/key pickups) and mirrors svc_damage into the vitals heartbeat so a dropped event still buzzes the wrist.
    • Stays inert during benchmarks/timedemos; dedups repeated centerprints.

Fixes

  • iMac G5 (R300 / Leopard): black light & emissive textures. The Radeon 9600 driver mis-renders the additive fullbright glow pass; the G5 bundle config now sets gl_fullbrights 0 so self-lit texels render via the base texture (correct, and closer to software Quake).
  • AltiVec horizontal-mipmap downscaler loaded the wrong 16-byte group when the input was 16-aligned, duplicating pixels and blurring distant surfaces. Fixed with a proper independent unaligned load.

Verified

  • DMG content-verified byte-for-byte vs source (Tiger-built UDZO, mounts Panther→modern).
  • DMG-installed + smoke-tested on the G4 mini (Tiger, Radeon 9200): world rendered, 52.3 fps.

One fat image (ppc750 + ppc7400 + ppc970 + x86_64) installs on every supported Mac, G3 Panther through modern Intel.

v1.10 — in-engine sysreport + Option-gated settings GUI

01 Jun 11:16

Choose a tag to compare

Community spec/benchmark collector + Option-gated settings GUI

This release adds two ways for players to help tune the port for their machine — both built into the engine, nothing extra to install.

sysreport — one-command spec sheet + benchmark

Open the console (~) and type sysreport (or use the new GUI's Run Benchmark button). It runs the timedemo grid silently and writes two files to the Desktop to email back:

  • quakespasm-sysreport-<model>.txthw.model, CPU / cores / clock / bus / L2, RAM, AltiVec, OS + Darwin; GL_VENDOR/RENDERER/VERSION + GPU chipset / VRAM / native resolution; storage (drive model, SSD-vs-spinning via Medium-Type or random-read IOPS, sequential read/write); the exact cvar settings the benchmark ran under; the benchmark results; and a ready-to-paste results.csv row.
  • …​.log — the console log for the run.

sysreport [runs] [demos] overrides the grid (sysreport 1 1 = quick smoke).

Option-gated settings GUI

A normal launch boots straight into the game with the machine's tuned defaults. Hold Option at startup (or pass -launcher) to get a grouped settings panel — Display / Textures / Water / Lighting / Performance / View — with the control type matched to each setting (checkbox, slider, popup), hover tooltips, and values preset from this machine's config. Only changed values are applied as overrides, so the per-machine tuning stays intact. A Run Benchmark button launches straight into a silent sysreport.

Notes

  • Universal binary: ppc750 (Panther) + ppc7400 (Tiger) + ppc970 (Leopard) + x86_64 (Lion+).
  • Validated on the fleet (G3 / G4 / G5 / Intel). Bench/screenshot scripts unaffected (they pass -nolauncher).

v1.9 — experimental GL1 surface batcher (off by default) + deploy tooling

31 May 22:15

Choose a tag to compare

What's new in v1.9

No change to default rendering behavior — every machine's shipping configuration is byte-identical to v1.8. This release stamps the port version into the binary, adds an off-by-default experimental rendering knob, and fixes a dev-tooling paper-cut.

  • The binary now self-identifies as the port release. It previously reported only the upstream engine version ("QuakeSpasm 0.97.0"), so a fresh install was indistinguishable from any prior one. It now reads "QuakeSpasm 0.97.0-oldmac-v1.9" in the console, window title, and -version, stamped automatically by the build from the git release tag.
  • New gl_surfbatch cvar (default 0 / off). An experimental GL 1.x fixed-function surface batcher: when enabled, it coalesces consecutive same-lightmap world surfaces into a single glDrawElements call (a back-port of the technique the Quake II sister port uses, and of a batcher QuakeSpasm already has but only on the modern GLSL path that never runs on this hardware). It was benched same-machine across the whole fleet and came out neutral-to-slightly-negative — G3 demo2 −4.8%, Lion demo1 −4.2%, G4/G5 neutral — because the Rage 128's immediate-mode fast path beats indexed draws over an un-cached vertex pool. So it ships off, fully toggleable. Flip with gl_surfbatch 1 (rebuilds the world vertex pool on the next map load). Full per-machine A/B table in docs/KNOBS.md.
  • Dev tooling: deploy-dmg.sh now removes previously-shipped release DMGs from a bench machine before installing the new one, so they no longer accumulate across releases.

Why the experimental knob ships anyway

The batcher doesn't pay on this fleet, but the plumbing it adds — an auto-built, arch-independent client vertex pool that any draw path can index, gated behind a runtime cvar — is reusable foundation. As more techniques get back-ported from the Quake II sister port, this configurable groundwork is positioned to enable gains on other/future hardware where the draw-call-overhead trade-off lands differently (a GL-1.x target with a driver that handles indexed client arrays well). Shipping it off-by-default and documented keeps the lever available without touching what works today.

Same universal binary as before: PowerPC G3 + G4/AltiVec + G5/970 + Intel x86_64, with per-machine visual/perf config auto-selected at launch. DMG verified installing + production-launching on G3 Panther (Rage 128), G4 Tiger (Radeon 9200), G5 Leopard (Radeon 9600), and Intel Lion (GMA 950), with contents byte-identical to source.

Install

Mount the DMG, copy Quakespasm.app + quakespasm.pak into a folder, add your own id1/pak0.pak (+ pak1.pak for registered), and double-click. Supported: Mac OS X 10.3.9 Panther (G3) → modern Intel macOS.

v1.8 — G3 default 800x600 + video-mode lock on fragile GPUs

31 May 14:55

Choose a tag to compare

What's new in v1.8

Fixes a G3 (Rage 128 / Panther) crash and hardens the fragile-GPU machines against in-game resolution switches.

  • G3 now boots at its intended 800×600 default. Previously the engine booted at 1024×768 (a config layering bug left the 800×600 default as a phantom that never reached the live display mode).
  • In-game resolution switching is now locked on the G3 (Rage 128) and iMac G5 / PowerPC G5 (ATI R300). A live fullscreen resolution switch hard-crashes the Rage 128 driver and hard-hangs the R300. The video menu, alt-enter, and vid_restart are inert on these machines — the only mode-set is the safe one at boot. Power users can re-enable with vid_unlock at the console if their GPU tolerates it (e.g. a GeForce-equipped Power Mac G5 tower).
  • G4 (Tiger) and Intel (Lion+) are unchanged — their GPUs switch modes fine.

Engine change is performance-neutral. Same universal binary as before: PowerPC G3 + G4/AltiVec + G5/970 + Intel x86_64, with per-machine visual/perf config auto-selected at launch.

Install

Mount the DMG, copy Quakespasm.app + quakespasm.pak into a folder, add your own id1/pak0.pak (+ pak1.pak for registered), and double-click. Supported: Mac OS X 10.3.9 Panther (G3) → modern Intel macOS.

v1.7 — iMac G5 / PowerPC G5 (Leopard 10.5.8) support

31 May 12:14

Choose a tag to compare

The fleet grows to seven Macs — the iMac G5 (PowerMac8,2, 2.0 GHz PowerPC 970, ATI Radeon 9600, Mac OS X 10.5.8 Leopard) is now a fully supported target. (Validated end-to-end on hardware, including the normal Finder-launch path.)

Highlights

  • 4th fat-binary slice (ppc970) + a dedicated Leopard-built SDL 1.2.15 alongside the Panther slice — the one .app runs natively across G3 Panther → G4 Tiger → G5 Leopard → Intel Lion → modern macOS (dyld picks the right slice per machine).
  • Fixed a full-OS GPU hang. The Radeon 9600's Leopard GLSL driver locks the GPU (and the whole machine) on QuakeSpasm's OpenGL 2.0 / GLSL / VBO path. The engine detects ATI R300 renderers (Radeon 9500–9800) and forces the proven GL 1.x fixed-function path. -atigl overrides.
  • Native-panel-resolution fullscreen (1440×900 on the 17", 1680×1050 on the 20") via a same-mode display capture — no resolution switch (which the R300 can't survive). Applies on a normal launch, not just benchmarks.
  • 100 / 74 / 86 fps (demo1 / demo2 / demo3) at native 1440×900 fullscreen, 32-bit color, full visual stack.
  • Best-effort iMac G4 native-res support also added (untested — no iMac G4 in the fleet; falls back safely if unrecognised).

Install

One disk image installs on every supported Mac (built on Panther, mounts from 10.3.9 → modern). Open the .dmg, drag Quakespasm.app + quakespasm.pak next to your id1/ (with pak0.pak, or pak0.pak + pak1.pak for the registered game), and double-click.

🤖 Generated with Claude Code

v1.6 — code-review visual round (stencil shadows, MSAA, smooth lightstyles)

29 May 15:11

Choose a tag to compare

One disk image for every Mac. Built on Panther, so QuakeSpasm-OldMac-v1.6.dmg (attached below) mounts on everything from Mac OS X 10.3.9 through modern macOS, and the Quakespasm.app inside is a fat binary (PPC G3 + PPC G4/AltiVec + Intel x86_64) that runs native on each.

Install

  1. Download QuakeSpasm-OldMac-v1.6.dmg below and open it.
  2. Drag Quakespasm.app and quakespasm.pak into a folder, e.g. ~/Desktop/quake/.
  3. Put your Quake data in an id1 subfolder there: id1/pak0.pak (shareware) or pak0.pak + pak1.pak (registered — Steam/GOG).
  4. Double-click Quakespasm.app.

Modern macOS quarantines the unsigned app — right-click → Open, or xattr -dr com.apple.quarantine ~/Desktop/quake/Quakespasm.app. (Not needed on Panther / Tiger / Lion.)

What's new in v1.6 — visual-quality round from a full code review + bench audit

  • 24-bit depth + stencil drop-shadows on Quicksilver (Radeon 9000) and the 2019 iMac. r_shadows finally gets its stencil self-intersection mask — it was silently disabled by the default 16-bit framebuffer. ~3% cost on Quicksilver, stays above 60 fps.
  • 8× MSAA on the 2019 iMac (vid_fsaa 8) — spends its huge headroom on anti-aliased edges. Includes an engine fix so vid_fsaa actually applies via the per-machine config.
  • Smooth lightstyles (r_lerplightstyles) on the Radeon G4s + iMac — torches and pulsing lights ramp smoothly instead of stepping at 10 Hz; deliberate hard flicker (strobes / fluorescent) is preserved. ~0–1.5% cost.
  • -g3clbrush — optional client-array brush path for the G3 (default off; benched neutral, kept as a lever).
  • Per-machine gating: the Mac mini G4 stays at 16-bit (its Radeon 9200 wedges creating a 32-bit fullscreen context) and 1024×768.
  • New scripts/make-dmg.sh produces this one-image-for-all-Macs .dmg.

Full per-knob detail in docs/KNOBS.md; gated/reverted experiments in MISTAKES.md.

v1.5 — Q2-borrow round + bench methodology fix

24 May 09:40

Choose a tag to compare

Cross-pollinated features from the Q2 sister port, plus a bench-methodology fix that produces more honest fps numbers (turns out v11.1's cells were artificially high — see "Bench methodology fix" below).

What's new

  • gl_fog cvar family (CVAR_ARCHIVE; default off) — cvar-driven fallback fog for maps that don't ship _fog in worldspawn, so vanilla id1 maps pick up an atmospheric tint when set in per-machine autoexec. New cvars: gl_fog / gl_fog_density / gl_fog_red / gl_fog_green / gl_fog_blue. Map-shipped fog and the fog console command always win when present; fog 0 from console truly disables (tracked via internal fog_explicit flag, reset on map load). Adapted from yquake2-ppc commit c3d1de3.

  • r_waterwarp is now a magnitude scale (CVAR_NONE → CVAR_ARCHIVE). The cvar used to be a boolean; now it doubles as a 0..1 dial — r_waterwarp 0.5 halves the underwater wobble, 0 disables, 1 is the historical full-magnitude effect (default unchanged). The CVAR_ARCHIVE flip lets per-machine autoexec persist a non-default value.

  • gl_texture_anisotropy 2 added to yosemite autoexec as a silent no-op on the current Panther R128 driver, defensive in case a future driver build exposes ARB_filter_anisotropic.

  • README "Sister project" section + icon bumped 120→200 px for visual consistency with the Q2 README.

Bench methodology fix

bench.sh previously passed -noarchautoexec, which correctly skipped the CFBundle per-machine autoexec layer. But it also meant the per-machine visual stack (shadows, dlights, translucent water, dynamic light distance, etc.) didn't apply during bench. So historical README "after" cells like yosemite demo1 1024 = 17.35 fps reflected vanilla engine defaults — not what the deployed .app actually renders for a real user.

The fix stages the per-arch + per-machine autoexec as a temp id1/autoexec.cfg on the target before each run; quake.rc's exec autoexec.cfg loads it before stuffcmds, so bench's +vid_width N +vid_height M cmdline still wins for resolution control. EXIT trap removes the staged file so normal launches fall back to the bundle path cleanly.

v1.5 real-conditions baseline

demo1, 3 runs each, median of runs 2 & 3:

Machine 1024×768 640×480
Yosemite (G3 / Rage 128) 17.55 36.50
Sawtooth (G4 / GeForce2 MX) 40.45 55.80
Quicksilver (G4 / Radeon 9000) 65.75 71.35
Mac mini G4 (G4 / Radeon 9200) 51.40 89.65
Mac mini Intel (Lion / GMA 950) 76.25 172.45

All four G4 / Lion machines are slightly faster than the v11.1 numbers because the per-machine autoexec ships more performance optimizations than visual costs.

Yosemite at its ship resolution (800×600) with full visual stack — translucent water, alias drop-shadows, emissive-fullbright dlights, classic warp, trilinear:

Demo fps
demo1 (water-heavy e1m3 Necropolis) 27.15
demo2 25.40
demo3 (dlight-heavy) 30.05

All cells comfortably above the 20-fps playability floor. The 17.55 fps at 1024×768 is a stress test, not the play target.

Install

Drop Quakespasm.app next to your own id1/pak0.pak (shareware) or id1/pak0.pak + id1/pak1.pak (registered). Anywhere on disk — Desktop, Applications, a project folder — works. The .app finds its game folder by walking up from its own image path, not by cwd.

$HOME/Desktop/quake/
  Quakespasm.app/
  quakespasm.pak       ← from this zip
  id1/
    pak0.pak           ← bring your own
    pak1.pak           ← bring your own (registered)

Modern macOS quarantines unsigned bundles — right-click → Open, or xattr -dr com.apple.quarantine $HOME/Desktop/quake/Quakespasm.app.

Compatibility

Same fat binary as v1.4 — ppc750 + ppc7400 + x86_64. Runs on:

  • B&W G3 PowerMac (10.3.9 Panther)
  • G4 PowerMacs (10.4.11 Tiger)
  • Lion Intel (10.7+)
  • Modern macOS (10.13+ via x86_64 slice; 11.0+ runs under Rosetta on Apple Silicon)

Pre-Lion Intel Macs (32-bit kernel) are not supported.

🤖 Generated with Claude Code

v1.4 — Self-contained .app bundle (per-machine configs in Resources/)

11 May 21:26

Choose a tag to compare

One fat universal binary, six retro Macs spanning 23 years (1999 G3 → 2019 i5 iMac).

This release is a packaging improvement, not a perf round — same Round v11.1 binary as v1.3-round-v11, but the per-machine autoexec configs that were previously shipped in id1/ alongside your game data now ship inside Quakespasm.app/Contents/Resources/. The .app is now a self-contained distribution unit.

Drop-in install

  1. Download quakespasm-fat-app-v0.97.0.zip
  2. Unzip → you get Quakespasm.app + quakespasm.pak
  3. Put both in any folder (e.g. ~/Desktop/quake/, ~/Applications/, or wherever)
  4. Create an id1/ folder next to Quakespasm.app and drop your registered pak0.pak + pak1.pak from a paid Quake install (Steam / GOG / original CD) into it
  5. Double-click Quakespasm.app

That's it. No autoexec cfg shuffle. The fat binary still holds three slices (ppc_750 G3, ppc_7400 G4 + AltiVec, x86_64 Lion+) — dyld picks the right one at launch, then host.c reads sysctl hw.model and loads the right per-machine autoexec from Contents/Resources/ via CFBundle. Hand-tuned visual stack on each machine, zero per-target setup.

Modern macOS (Big Sur+) will quarantine the unsigned bundle — either right-click → Open, or xattr -dr com.apple.quarantine Quakespasm.app.

What's new vs v1.3

No binary perf change — same Round v11.1 engine, same bench numbers. The change is in how the per-machine config layer is delivered:

  • Old: deploy script copied autoexec-yosemite.cfg, autoexec-sawtooth.cfg, etc. into id1/ alongside your pak0.pak. The engine used Quake's exec FILE.cfg command to load them from the gamedir filesystem. Users had to keep both the .app and the bundled cfg files together for the per-machine dispatch to work.
  • New: cfgs ship inside Quakespasm.app/Contents/Resources/. The engine loads them via CoreFoundation's CFBundle API (QS_ExecConfigFromBundle in host.c). The .app is now self-contained — you only need to provide id1/pak0.pak (your own game data) alongside it.

Per-arch baseline (autoexec-ppc750.cfg / autoexec-ppc7400.cfg / autoexec-x86_64.cfg) picked at compile time via __VEC__ / __ppc__ / __x86_64__. Per-machine overlay (autoexec-<machine>.cfg) picked at runtime via sysctlbyname("hw.model", ...). Both layers travel inside the .app bundle.

Bench reference (carried forward from v1.3, no change)

Machine OS GPU demo1 1024 demo3 1024
yosemite (PowerMac1,1, 1999, G3 449 MHz) Panther 10.3.9 Rage 128 16 MB 16.95 19.90
sawtooth (PowerMac3,1, 1999, G4 500 MHz) Tiger 10.4.11 GeForce2 MX 32 MB 40.25 46.90
quicksilver (PowerMac3,5, 2001, G4 733 MHz) Tiger 10.4.11 Radeon 9000 Pro 64 MB 62.75 84.05
mini-g4 (PowerMac10,1, 2005, G4 1.25 GHz) Tiger 10.4.11 Radeon 9200 32 MB 48.45 65.60
mini-intel (Macmini2,1, 2007, C2D 2.33 GHz) Lion 10.7.5 GMA 950 64 MB 72.85 44.60
imac-2019 (iMac19,1, 2019, i5-9600K) Sequoia 15.7.5 Radeon Pro 580X 8 GB 1610.95 1575.15

Full breakdown: see v1.3 release notes.