The Wind Waker - Static Recompilation
The Legend of Zelda: The Wind Waker
OriginGameCube
TechnologyStatic recompilation (native C/C++)
Available forWindows, Linux, macOS
View official projectAbout the project
The Legend of Zelda: The Wind Waker, conocido en Japón como Zelda no Densetsu: Kaze no Takuto , es un videojuego de acción-aventura de 2002 desarrollado por la filial EAD y distribuido por Nintendo para la videoconsola Nintendo GameCube. Es el décimo lanzamiento de la franquicia The Legend of Zelda y la precuela directa de The Legend of Zelda: Phantom Hourglass, de Nintendo DS.
7 versions of The Legend of Zelda: The Wind Waker
You're viewing: The Wind Waker - Static Recompilation
The Wind Waker - Static Recompilationgithub.com/sp00nznet/ww
BlueWake (The Wind Waker)github.com/chrissotraidis/bluewake
Deep Sea (Wind Waker, 60 fps)github.com/AH64-dll/DeepSea
The Legend of Zelda: The Wind Wakergithub.com/zeldaret/tww
The Legend of Zelda: The Wind Waker (elliotttate)github.com/elliotttate/Wind-Waker-Recomp
The Legend of Zelda: The Wind Waker (WindowWaker)github.com/MaskeZenY/WindowWaker
Wind Waker (Nintendo Switch)github.com/centollOS/SwitchWakerOfficial project information
The Wind Waker - Static Recompilation
A static recompilation of a GameCube game to native PC.
This project takes The Legend of Zelda: The Wind Waker (GameCube, 2002) and statically recompiles its PowerPC 750CXe (Gekko) machine code into native x86-64 C code that runs directly on Windows 11. No emulator. No compatibility layer. Just the Great Sea, running natively.

Wind Waker island geometry, running in a native Win32 window. No Dolphin, no
emulator: the game's own PowerPC code was translated to C ahead of time, and its
GX draw calls go out through our own D3D11 backend. Terrain, fence posts and
textures are read from a real disc image at runtime -- Stage.arc and
Room44.arc, Yaz0-decompressed, J3D/BDL parsed, CMPR textures decoded, shaded
by HLSL generated from the game's TEV stage configuration.
Honest caveat: this is the renderer, not the game. The frame loop is being driven by us rather than by the title screen's own state machine, and the black spiral is a water/skybox texture we still map wrong.
What Is Static Recompilation?
Unlike an emulator that interprets or dynamically translates instructions at runtime, static recompilation translates the entire game binary ahead of time into compilable C source code. Each PowerPC instruction becomes a C expression:
// Original GameCube PowerPC:
// addi r3, r4, 0x20
// lwz r5, 0x10(r6)
// bl some_function
// Recompiled native C:
ctx->r[3] = (int32_t)ctx->r[4] + 0x20;
ctx->r[5] = MEM_READ32(ctx->r[6] + 0x10);
some_function(ctx, mem);
The generated C code compiles with any modern compiler (MSVC, Clang, GCC) and runs at full native speed with all compiler optimizations applied.
Architecture
+-----------------+
| Wind Waker |
| DOL/REL |
| (PowerPC 750) |
+--------+--------+
|
+--------v--------+
| ww_recompiler |
| PPC Disasm -> |
| CFG Builder -> |
| C Code Gen |
+--------+--------+
|
+--------v--------+
| Recompiled .cpp |
| (x86-64 native) |
+--------+--------+
|
+--------------+--------------+
| | |
+--------v------+ +----v----+ +-------v------+
| GX Runtime | | Audio | | Input |
| (D3D11) | | (DSP | | (XInput / |
| TEV -> HLSL | | ADPCM) | | Keyboard) |
| Texture decode| | XAudio2 | | GC Pad map |
+---------------+ +---------+ +--------------+
Components
| Component | Description | Status |
|---|---|---|
| DOL Parser | Parses GameCube executable format (7 text + 11 data sections) | Done |
| REL Parser | Parses relocatable modules (actors, scenes) | Done |
| PPC Disassembler | Decodes all Gekko instructions including Paired Singles | Done |
| CFG Builder | Identifies functions and basic blocks from binary | Done |
| PPC-to-C Emitter | Translates each PPC instruction to C code | Done |
| Runtime | CPU context (GPR/FPR/PS/CR/SPR), memory, function dispatch | Done |
| Function Table | Auto-generated registration of all 8,148 functions for indirect dispatch | Done |
| GX Graphics | GameCube GX API -> Direct3D 11 translation | In Progress |
| TEV Shader Gen | Generates HLSL shaders from TEV stage configurations | In Progress |
| Texture Decoder | Decodes GC texture formats (I4/I8/IA/RGB565/RGB5A3/CMPR) | Done |
| Audio | DSP ADPCM decoder, voice mixer | In Progress |
| Input | Keyboard/XInput -> GameCube pad mapping | Done |
| OS Functions | Replacement implementations for Dolphin OS calls (heap, DVD, VI, CARD, threads) | In Progress |
Supported Instructions
The disassembler and recompiler handle the full Gekko instruction set:
- Integer: ADD, SUB, MUL, DIV, CMP, AND, OR, XOR, shift, rotate
- Floating Point: Single and double precision arithmetic, compare, convert
- Paired Singles: The Gekko's SIMD extension — PS_ADD, PS_MUL, PS_MADD, PS_MERGE, quantized load/store, etc.
- Load/Store: All sizes (byte/half/word/float/double), indexed, update, multiple, byte-reversed
- Branch: Direct, conditional, to LR/CTR, with/without link
- System: SPR access (LR, CTR, XER, GQR), CR manipulation, cache ops, sync
Requirements
- Game: A legally obtained copy of The Wind Waker (GZLE01 - US version)
- Windows 11 with a DirectX 11 compatible GPU
- CMake 3.20+
- Visual Studio 2022 or compatible C++20 compiler
Building
# Configure
cmake -B build -G "Visual Studio 17 2022" -A x64
# Build the recompiler tool
cmake --build build --target ww_recompiler --config Release
# Recompile the game (you need the DOL extracted from your ISO)
./build/lib/gcrecomp/Release/gcrecomp_recompiler.exe main.dol \
--extra-funcs extra_funcs.txt --output recompiled/
python tools/patches.py apply # re-apply the 14 hand edits to generated code
# IMPORTANT: After recompiling, apply patches to recompiled source:
# See "Recompiled Source Patches" section below for the full list.
# At minimum: recomp_0018.cpp (display init), recomp_0063.cpp (bump alloc),
# recomp_0066.cpp (VI wait, assert), recomp_0006.cpp (GX sync),
# recomp_0000.cpp (exception handler), recomp_0067.cpp (camera GX),
# recomp_0075.cpp (DVD read), recomp_0074.cpp (async DVD),
# recomp_0080.cpp (bctr tail call), recomp_0001.cpp (heap),
# recomp_0064.cpp (JKR resource lookup)
# Build the game runtime + recompiled code
cmake --build build --target ww_launcher --config Release
# Run (place your GZLE01 ISO as ww.iso in the project directory)
./build/Release/ww_launcher.exe
# Or specify paths explicitly:
./build/Release/ww_launcher.exe main.dol --iso /path/to/game.iso
Controls
| Input | Action |
|---|---|
| WASD | Move Link |
| Mouse / Arrow Keys | Camera |
| Space | A — Roll, Talk, Grab |
| Left Shift | B — Sword |
| E | X — Item Slot 1 |
| Q | Y — Item Slot 2 |
| R | Z — Target Lock |
| Tab | R — Shield |
| F | L Trigger |
| Enter | Start / Pause |
| ESC | Quit |
XInput gamepads are also supported with standard button mapping.
How It Works
1. Parse the DOL
The GameCube executable (DOL) contains up to 7 code sections and 11 data sections, all big-endian. We parse these and build a flat memory image.
2. Disassemble
Every 4-byte word in code sections is decoded into a structured instruction. The Gekko is a PowerPC 750CXe with ~200 base instructions plus ~50 Paired Singles SIMD extensions.
3. Build Control Flow Graph
We identify function boundaries by scanning for bl (branch-and-link)
instructions, then trace execution flow to find basic blocks. Each function
becomes a C function.
4. Emit C Code
Each instruction becomes a C expression operating on a PPCContext struct
that mirrors the Gekko's register file. Memory accesses go through
big-endian read/write helpers.
5. Replace OS & Hardware
GameCube OS calls (memory allocation, DVD access, timing) are intercepted and replaced with native implementations. GX graphics calls are translated to Direct3D 11. Audio is decoded from DSP ADPCM and played via XAudio2.
Project Status
The recompiler can process the full Wind Waker DOL, generate C code for all discovered functions, and the runtime provides the hardware abstraction needed to run it. The game renders textured 3D scene geometry from actual disc data through a GX→D3D11 translation pipeline at 60fps.
Recompiler Statistics
| Metric | Value |
|---|---|
| DOL Size | 4.16 MB |
| Entry Point | 0x80003140 |
| Functions Discovered | 8,148 |
| Total Instructions | 348,958 |
| Instruction Coverage | 99.99% (1 unknown encoding) |
| Output Files | 41 translation units + registration table |
| Supported Instruction Classes | Integer, Float, Paired Singles, Load/Store, Branch, CR, System |
The recompiler achieves near-perfect instruction coverage across the full Gekko ISA, including all Paired Singles SIMD instructions and quantized load/store operations with GQR-based dequantization.
Runtime Status
The game is rendering textured 3D geometry from actual game data at 60fps:
- All 41 translation units compile with MSVC (C++20)
- DOL loaded, all 100 static constructors complete
- Game framework (
fapGm_Create) initialized successfully - Main game loop running at ~60 FPS with full
fapGm_Executedispatch - J3D/BDL model parser — extracts geometry, textures, and materials from Nintendo's binary model format
- Indexed triangle rendering — SHP1 display lists parsed, triangle strips/fans converted, vertex indices resolved
- CMPR texture decoding — 17 textures decoded (DXT1 variant) and bound via GX pipeline
- Per-batch material binding — INF1 scene graph maps shapes to materials to textures
- Multi-model scene — island terrain (5,946 verts, 8 batches) + ocean water (1,194 verts, 8 batches)
- TEV shader pipeline — texture * vertex color modulation, compiled and cached per-state
- Full D3D11 draw path — vertex buffer upload, pixel shader, blending, depth test, present
- Orbiting camera — perspective projection with automatic rotation around the island
- JKR archive mount system — proper JKRMemArchive objects in emulated memory with working vtable, linked into sVolumeList
- Stage.arc Yaz0 decompressed (59KB → 299KB), Room44.arc loaded (714KB), stage.dzs parsed
- 16 hardware-dependent functions patched in recompiled source
Loaded Archives (sea_T — Great Sea)
Stage.arc (59KB Yaz0 → 299KB decompressed):
tex/cloudtx_01.bti 4,128 bytes Cloud texture
tex/cloudtx_02.bti 4,128 bytes Cloud texture
tex/cloudtx_03.bti 4,128 bytes Cloud texture
dzs/stage.dzs 4,608 bytes Stage data (13 chunks)
dat/event_list.dat 227,804 bytes Event scripts
bdl/vr_back_cloud.bdl 40,096 bytes Skybox cloud model
bdl/vr_kasumi_mae.bdl 3,808 bytes Skybox haze model
bdl/vr_sky.bdl 6,496 bytes Skybox model
bdl/vr_uso_umi.bdl 3,072 bytes Sea surface model
Room44.arc (714KB raw RARC):
dzr/room.dzr 10,880 bytes Room data/actors
dzb/room.dzb 121,504 bytes Room collision mesh
dat/m128.amp 35,456 bytes Lightmap
dat/m128.bti 21,568 bytes Lightmap texture
dat/s128.bti 7,264 bytes Shadow texture
btk/model1.btk 2,784 bytes Texture animation
bdl/model.bdl 399,872 bytes Main room model (390KB)
bdl/model1.bdl 111,296 bytes Secondary room model
bdl/model3.bdl 3,360 bytes Tertiary room model
stage.dzs Chunk Table (13 chunks):
STAG (1) Stage settings RTBL (50) Room table
EVNT (1) Event data MULT (2) Spawn multipliers
EnvR (50) Environment registers Colo (5) Color settings
Pale (33) Palette entries Virt (31) Virtual light settings
RPAT (4) Room paths RPPN (30) Path points
ACTR (2) Actor placements RCAM (1) Camera
RARO (1) RARC override
What Works
| System | Status |
|---|---|
| Static constructors (100/100) | Working |
| Game framework (fapGm) | Working — full layer dispatch every frame |
| DVD/ISO file access | Working — FST parsed, both archives loaded from disc |
| Yaz0 decompression | Working — 59KB → 299KB decompressed correctly |
| RARC archive parsing | Working — 18 files across 2 archives |
| J3D/BDL model parsing | Working — VTX1, SHP1, INF1, TEX1 sections extracted |
| Indexed geometry rendering | Working — display list parsing, strip/fan→triangle conversion |
| CMPR texture decoding | Working — 17 textures decoded and bound to GX pipeline |
| Per-batch materials | Working — INF1 scene graph maps shapes to textures |
| TEV shader generation | Working — HLSL shaders compiled and cached per-state |
| D3D11 draw pipeline | Working — vertex buffers, pixel shaders, blending, depth |
| Multi-model scene | Working — terrain (opaque) + water (translucent alpha blend) |
| DZS stage data parsing | Working — 13 chunks, full chunk table decoded |
| Memory allocation | Working — bump allocator replaces JKR heap |
| JKR archive mounting | Working — JKRMemArchive objects in emulated memory, sVolumeList linked |
| getGlbResource / findVolume | Working — searches mounted archives, returns real JKR objects |
| Time Base (TB) register | Working — host QueryPerformanceCounter scaled to 40.5MHz |
| VI (Video Interface) HLE | Working — VIInit, VIWaitForRetrace (60Hz), VIFlush, framebuffer |
| CARD (Memory Card) HLE | Working — host FS backed (memcard_a/, memcard_b/), full read/write |
| Init stubs (OSInit, DVDInit, etc.) | Working — boot-time SDK calls satisfied |
| PPC helpers (ppc_helpers.h) | Working — CNTLZW, ROTL32, MFTBL/U, PSQ load/store from gcrecomp |
| HW register HLE | Working — VI line counter, SI/DI status, rate-limited logging |
Framework Process System
The game's multi-threaded framework (fopMsgM/fapGm) is now operational:
- 9 processes dispatching every frame — root layer (0x0007), scene (0x0015), room manager (0x0017), environment (0x0028), camera (0x00A9), 3 scene sub-processes (0x01B5/0x01BA/0x01BB), and timing controller (0x01BC)
- Both execute and draw phases run — fn_table[2] and fn_table[3] dispatched via 3-level callback chain through the per-frame layer iteration
- Frame gate bypassed — VRetrace check always returns 0 without interrupts; we call dispatch sub-functions directly, skipping the gate
- Execution queue populated — process nodes at +0x34 linked into 0x803BCD60, with 16 priority lists iterated by func_802450D0
- Dolphin reference state loaded — 1170 global values from game info/SDA globals plus 831 scalar template values across 8 process types captured during Dolphin gameplay
- Scene state = 0 (active), matching Dolphin runtime
Process execute methods run but don't yet modify game state because process objects lack internal pointer state (set during construction, which is stubbed due to JKR archive dependencies).
Current Focus
Two systems are end-to-end functional:
- Rendering: ISO → Yaz0 → RARC → BDL → J3D parse → GX → D3D11 → 60fps
- Framework dispatch: fapGm per-frame → layer iteration → per-process execute+draw
The main blocker is the process creation chain: the original create functions (e.g., func_80022CEC) depend on JKR archive mounting, which requires a background thread and properly initialized heap system. Process objects are constructed with correct headers and scalar state from Dolphin captures, but lack the internal pointer state that the real create functions would initialize.
Next Steps
- Implement JKR archive mounting — the main blocker for the entire process creation chain. Every process create function (actors, camera, environment) loads resources from JKR archives during construction. Without a working JKRMemArchive mount system, processes can be allocated but not properly initialized.
- Get past the title screen — requires enough of the framework (scene transitions, input dispatch, UI rendering) to handle the title/file-select flow
- Connect game camera — the camera process has 610 values from Dolphin including position/FOV; use these to replace the hardcoded orbiting camera
- Actor spawning — parse room.dzr actor placements and create actor processes
- MAT3 material parsing — full TEV stage configuration from J3D materials
Standing on the Shoulders of Giants
This project builds on incredible work by the community:
- zeldaret/tww — Wind Waker decompilation project providing invaluable symbol maps and architectural understanding
- zeldaret/tp — Twilight Princess decompilation; the shared Nintendo "ZeldaFramework" code (
f_pc_*,f_op_*,f_ap_*) is nearly verbatim with WW and is our canonical reference for framework struct layouts - TwilitRealm/dusk (Dusklight) — TP source port whose decomp headers we vendor under
docs/dusk-ref/(CC0) as a reverse-engineering reference for the framework we recompile - Aurora — Source-level GC/Wii compatibility layer (different translation strategy than ours, but a model for cross-platform GX/DVD/PAD host services)
- N64Recomp — Pioneered the static recompilation approach for N64 games
- Dolphin — The gold standard GameCube/Wii emulator, whose GX shader generation code informs our TEV implementation
- decomp-toolkit — GameCube binary analysis tools
- powerpc-rs — Fuzz-tested PPC750 disassembler reference
License
MIT. See LICENSE. The recompiler and runtime library it builds on, gcrecomp, is MIT as well.
That is deliberate, and it is the point of the project. Every other GameCube static recompilation stack is a Dolphin derivative and therefore GPL: DolRecomp and ModernGekko are GPLv3, and everything built on them inherits that. Writing our own GX, OS, and hardware layers from scratch is slower than vendoring an emulator, and it is the only way to end up with a permissively licensed toolchain — one that can be embedded in a commercial port, shipped on a console, or used by a preservation project that cannot take GPL.
Keeping that claim defensible means treating other emulators as black boxes: we observe behaviour (memory dumps, traces, framebuffer output) and never read an implementation and reimplement from it.
Third-party material vendored here: docs/dusk-ref/ carries decomp headers from
TwilitRealm/dusk under CC0.
Legal
This project does not include any copyrighted game assets or code. You must provide your own legally obtained copy of The Legend of Zelda: The Wind Waker.
Part of sp00nznet
Built with the same static recompilation methodology as our other projects. The Great Sea has never been closer.
"The wind... it is blowing." — The King of Red Lions