Fury³

June 15, 2026 · View on GitHub

   ███████╗██╗   ██╗██████╗ ██╗   ██╗██████╗
   ██╔════╝██║   ██║██╔══██╗╚██╗ ██╔╝╚════██╗
   █████╗  ██║   ██║██████╔╝ ╚████╔╝  █████╔╝
   ██╔══╝  ██║   ██║██╔══██╗  ╚██╔╝   ╚═══██╗
   ██║     ╚██████╔╝██║  ██║   ██║   ██████╔╝
   ╚═╝      ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═════╝
        outrun the fury · 1995 · reborn

A from-the-binary static recompilation of Fury³ (1995) — Microsoft's Windows 95 launch-era arcade flight shooter — into clean, native, modern C.

No DOSBox. No Win32s. No emulation. We disassemble the original 645 KB executable, lift it to C, shim its handful of OS calls onto SDL2, and rebuild it as a real program you can compile and run on Windows 11, Linux, or a Raspberry Pi.

Part of the pcrecomp family of PC static-recompilation projects (civ · elfish · gta · recoil · crimsonskies · black & white · …).


It runs — from title to flying the canyon

The recompiled binary boots straight through Microsoft's original front-end and into the mission. These are captured live from the recompiled FURY3.EXE (no emulator):

New Game / titleMission briefingEnemy tactical intros
Title screenMission briefingEnemy tactical intro
The animated Microsoft Fury³ title.The 3D briefing — starfield, the rotating Bion sphere, story crawl.Per-enemy tactical briefings with the live 3D scene.
Fly-inFlying the canyon
Fly-in to the canyonFlying the canyon
The approach into the level — the voxel landscape.Live flight: textured terrain, water, and the full HUD (objective, distance, weapon, sector, shield bar, radar).

The full pipeline runs natively: boot → title → New Game → 3D briefing → enemy tactical intros → fly-in → flying the canyon, all rendered through the original voxel/span rasterizer with shading, textures and HUD.


Modern frontend — SDL2 + Dear ImGui menu

An optional SDL2 + Dear ImGui frontend (build with -DFURY3_SDL=ON, or bash build_sdl.sh) wraps the game in a resizable window with an in-game menu bar — File (New Game · Save/Load State · settings), Video (scale · nearest/linear filter · v-sync · fullscreen · scanlines), Audio (volume · mute), and Controls, all persisted to fury3_config.ini. Press F1 in-game to toggle it.

Menu over the gameControls — keyboard + Xbox-controller binding
Menu barControls binding

The Controls panel binds every flight action — pitch, roll, yaw, throttle, fire, afterburner, slide — to a keyboard key and an Xbox-style gamepad button (click a cell, press the input; analog-stick option + dead-zone for pitch/roll). Real joysticks/gamepads also work directly: the WINMM joyGetPos path is wired to the host's real joystick, so a physical flight stick drives the analog controls. (The plain Win32/GDI build remains the default; the SDL frontend is opt-in.)


Why Fury³?

Fury³ was Microsoft's flagship game for the Windows 95 era — a six-degrees-of-freedom canyon-blasting shooter built by Terminal Reality on the same voxel-landscape "fury" engine that powered Terminal Velocity and later Hellbender. It came on the disc that taught a generation of PCs what "multimedia" meant. Then Win32s, GDI, and waveOut aged out from under it, and it became a pain to run.

But here's the thing that makes it a perfect recompilation target — we cracked open the binary and it is astonishingly clean:

FormatPE32, i386, Windows GUI
Size645,120 bytes — a single self-contained FURY3.EXE
Code~383 KB in .text (one .text section, no packing, no DRM)
LinkerMicrosoft Link 2.55 (1995) — early, predictable codegen
Built1995-08-14 — three weeks before Windows 95 shipped
OS surface160 imports across just 5 DLLs

And those five DLLs are the whole story:

GDI32     →  CreateDIBSection + StretchBlt          the entire renderer is a
             SetDIBColorTable + CreatePalette        software rasterizer that draws
                                                      into a memory DIB, then blits it
USER32    →  window, message loop, keyboard/mouse    input + window
KERNEL32  →  file I/O, memory, GetPrivateProfile*    files + the .INI config
WINMM     →  waveOut* (raw PCM streaming)            audio
comdlg32  →  GetOpenFileName  (3 calls)              load/save dialog

There is no DirectDraw, no WinG, no DCI, no DirectSound — nothing exotic. The 3D engine renders the world into an off-screen 8-bit DIB and StretchBlts it to the window. That means the entire operating-system dependency of this game maps onto a few hundred lines of SDL2:

  • the DIB framebuffer → an SDL_Texture we upload each frame
  • the palette → SDL_SetPaletteColors
  • waveOut PCM → SDL_AudioStream
  • the message loop → SDL_PollEvent

The hard part of the game — the renderer, the physics, the AI, the mission logic — is self-contained 386 code with no OS entanglement. That's exactly what static recompilation eats for breakfast.


Status

🟢 Playable — boots to flight. The recompiled binary runs the whole pipeline natively, no emulator: boot → title → New Game → 3D briefing → enemy tactical intros → fly-in → flying the canyon, rendered through the original voxel/span rasterizer with shading, textures and HUD. It took nine lifter fixes to get here (fs: segments, ret stack cleanup, flag-operand snapshots, intra-function jump tables, repne scasb/strlen, the global x87 FPU stack, the FPU st(i) index base, and the fstp st(i) pop semantics) — every one pushed back upstream to the shared pcrecomp toolbox.

PhaseWhatState
0Reconnaissance — PE analysis, import map, engine ID✅ done
1Disassembly — IDA + disasm32 function recovery✅ done
2Classification — call graph, subsystems, hot path✅ done
3Lift to C — 1,945 funcs → C, compiles to objects✅ done
4Shim layer — runtime + 160 import bridges✅ done
5Build & link — single exe, 0 errors✅ done
6Bring-up — boots through CRT/WinMain/window into main loop✅ done
7First pixels — real I/O + assets + DIB render✅ done
8Playable — input, New Game, briefing, flying the canyon✅ done
9Frontend — SDL2 + Dear ImGui menu, real joystick✅ done

The full diary of how each phase was solved is in docs/PROGRESS.md.

Known limitations

  • Audio is stubbed. The game's mixer runs on a waveOut worker thread; wiring it up needs thread-local CPU/FPU register state in the recomp, which isn't in place yet.
  • Save/Load State is exposed in the SDL menu but not wired — recomp save states need a re-entrant snapshot of sim memory + CPU/FPU state.
  • Conservative carry-flag model. The lifter tracks CF in a running variable that cmp/sub/add don't publish into. Making it precise deterministically breaks the New-Game → briefing transition (the recomp sits in a self-consistent equilibrium), so it's left conservative; the one gameplay-affecting case (the cheat reader) is host-shimmed. See docs/PROGRESS.md.
  • Intermittent dt=0 freeze on roughly 1 run in 5 — the briefing occasionally stalls before flight; relaunching clears it.

How it works

This repo doesn't ship game assets — bring your own original FURY3.EXE and data files. What lives here is the machinery that turns that binary into source:

fury3/
  analysis/        the target binary + raw analysis artifacts (gitignored)
  config/          pe_analysis.json and pipeline configuration
  docs/            PLAN.md (the approach) + PROGRESS.md (the diary) + PHASE*.md
  src/recomp/gen/  (generated) lifted C — produced by run_lift.py
  src/runtime/     hand-written runtime + import shims + SDL frontend
  run_lift.py      driver: IDA bounds → lift32 → src/recomp/gen/
  gen_imports.py   generates the 160 import bridges
  CMakeLists.txt   build (GDI default; -DFURY3_SDL=ON for the SDL/imgui frontend)

The recompilation pipeline, all from the shared pcrecomp toolbox:

FURY3.EXE
   │  pe_analyze.py            ← Phase 0 (done): sections, imports, entry point
   ▼
   │  disasm32.py              ← Phase 1: recursive-descent x86-32 disassembly
   ▼
   │  callgraph + bounds       ← Phase 2: function recovery, classification
   ▼
   │  lift32.py                ← Phase 3: x86 → readable C, one function at a time
   ▼
   │  compat/ (GDI→SDL2 …)     ← Phase 4: replace the 5 DLLs with a thin shim
   ▼
CMake + your C compiler        ← Phase 5+: build, link, run

Read the full battle plan in docs/PLAN.md.


Building

You provide your own legally-obtained FURY3.EXE (this repo ships no game code or assets). Generate the C, then build.

# 1. lift the binary to C  (needs Python 3.11 + capstone; IDA bounds are vendored)
py -3.11 run_lift.py          # -> src/recomp/gen/recomp_*.c
py -3.11 gen_imports.py       # -> src/runtime/imports_gen.c

# 2a. plain Win32 / GDI build (default)
cmake -B build -G Ninja
cmake --build build
./build/fury3 analysis/FURY3.EXE --run

# 2b. SDL2 + Dear ImGui frontend (windowed + in-game menu / controls)
cmake -B build -G Ninja -DFURY3_SDL=ON      # or: bash build_sdl.sh
cmake --build build

The game also needs its data (the POD archives unpacked via tools/extract_pod.py); point the runtime at them as described in docs/PLAN.md.


The full phase-by-phase progress diary lives in docs/PROGRESS.md.


License

Tooling and original code in this repo: MIT. Fury³ and all its assets are property of their respective owners; none are included here. This is a preservation and interoperability project.


"everything old is new again." — built with stubbornness by sp00nznet