RECOMPWATCHER

Portage PC natif · PlayStation 2

The Lord of the Rings: The Third Age

playable to the first battle

A native Windows, Linux and macOS port of The Lord of the Rings: The Third Age (NTSC-U, SLUS-21027), made by statically recompiling the game's PlayStation 2 code to C++.

Console d'origine
PlayStation 2
Référence
SLUS-21027
Région
NTSC-U
Fonctionne sous
Windows · Linux · macOS
Langage
C++
Dernière mise à jour
1 nov. 2026

Options

Lire la documentationLe README du projet, plus basVérifier votre disqueVotre exemplaire est-il la version prise en charge ?Voir l'avancement7 étapes franchies sur 12Ouvrir le dépôt ↗github.com/TheBozos/TLOTR_TTA_Recomp
TéléchargerAucune version publiée pour l'instant. Elles apparaîtront ici dès la première.

Aucune donnée du jeu n'est fournie : il vous faut votre propre exemplaire.

Vérification du disque

Votre exemplaire est-il pris en charge ?

Le portage est construit sur une version précise du jeu. Déposez l'exécutable du jeu (SLUS_210.27), un dossier copié depuis le disque ou l'image complète du disque (.iso / .bin) pour vérifier la vôtre.

Tous ces fichiers

  • SLUS_210.27SHA-1 d88ded370592…

Déposez des fichiers n'importe où sur la page

    Vérifié sur votre ordinateur : les fichiers sont lus par votre navigateur et ne sont jamais envoyés. Seuls les fichiers utiles au portage sont lus dans une image disque.

    Étapes

    7 sur 12 franchies· 2 en cours

    Étapes au fil du tempsFranchiesPrévues
    01726 oct. 20264 nov. 20267/ 12
    Afficher en tableau
    DateFranchiesEn coursPrévuesCouches natives
    26 oct. 2026019—
    27 oct. 20263110—
    27 oct. 20264111—
    27 oct. 20265112—
    28 oct. 20266213—
    29 oct. 20269216—
    29 oct. 202610216—
    29 oct. 202611217—
    29 oct. 202672123 / 5
    29 oct. 202672123 / 6
    29 oct. 202672124 / 6
    30 oct. 202672125 / 7
    30 oct. 202672123 / 6
    • Map the stripped main ELF (Ghidra function map, SDK functions from the fork's signature database)
    • Recompile it and link the generated code with the PS2Recomp runtime (Windows)
    • Boot: EE kernel, the game's own IOP modules, EA's heap, first frames on screen
    • Loading, memory card check, legal screen
    • Movies, title screen
    • New Game, the intro cinematic
    • First battle
    • The first battle played and won; the first chapter
    • Sound and music (the driver runs; not checked by ear yet)
    • Saving to the memory card
    • Linux and macOS builds
    • Full speed, widescreen, higher resolution

    Portage natif

    3 couches natives sur 6· 2 en cours

    • IOP modules (sound, streaming, pad, memory card) recompiled to C++, none interpreted
    • Game time, sound and IOP on the PC's clock
    • No paraLLEl-GS: OpenGL on the GPU
    • Frame loop on the PC's clock in game and menus (PS2X_FRAME_CAP, default 60; movies still on the vblank)
    • The two hottest VU1 programs (the 3D strips, 0x460 and 0x268) translated to C++, no VU interpreter (TTA_VU1_PORT=0: sandbox)
    • Native draws from the game's data, no GIF packet and no GS front end

    Tiré de la liste du README du projet.

    Avancement

    Historique du statut

    1. Début du projet

    Captures d'écran

    • Berethor facing three Black Riders in the forest cinematic, drawn without the emulated VU1Berethor facing three Black Riders in the forest cinematic, drawn without the emulated VU1
    • A Black Rider raising its sword in a misty forest, in-engineA Black Rider raising its sword in a misty forest, in-engine
    • The Scenes menu after the first battle: Nazgul Agenda, scene 2 of 109, unlockedThe Scenes menu after the first battle: Nazgul Agenda, scene 2 of 109, unlocked
    • The first battle: Berethor facing two Black Riders, with the Attack / Taunt Foe / Skip menu, turn portraits and HPThe first battle: Berethor facing two Black Riders, with the Attack / Taunt Foe / Skip menu, turn portraits and HP
    • An in-engine scene: a dark horse in a misty forest, drawn by the native OpenGL rendererAn in-engine scene: a dark horse in a misty forest, drawn by the native OpenGL renderer
    • The title screen: The Lord of the Rings: The Third Age logo over a dark blue background, with New Game, Load Game and MoreThe title screen: The Lord of the Rings: The Third Age logo over a dark blue background, with New Game, Load Game and More
    • The attract movie: two characters on a forest path at duskThe attract movie: two characters on a forest path at dusk
    • The loading screen: the One Ring with its glowing inscription and an Elvish-style line of textThe loading screen: the One Ring with its glowing inscription and an Elvish-style line of text
    • A message box: Checking memory card (PS2) in MEMORY CARD slot 1A message box: Checking memory card (PS2) in MEMORY CARD slot 1
    • The Lord of the Rings: The Third Age logo above the copyright noticeThe Lord of the Rings: The Third Age logo above the copyright notice
    • The EA GAMES Challenge Everything boot movieThe EA GAMES Challenge Everything boot movie
    • The loading screen with a garbled line of textThe loading screen with a garbled line of text
    Taille réelle ↗
    ← → pour naviguer · Échap pour fermerBalayez pour naviguer

    README.md

    Voir sur GitHub ↗

    La documentation du projet est en anglais.

    Platform Compiler Based on Status

    Important

    No game files are included: no ELF, IRX modules, data archives, or code generated from them. You need your own copy of the North American release, PS2 ID SLUS-21027. The port is built against that disc's executable:

    File SHA-1
    SLUS_210.27 d88ded370592114169fa18f0ff73b9f610a94bd0

    Status

    Plays from the boot to the first battle; not playable through yet. Windows comes first, then Linux and macOS.

    Milestone
    Map the stripped main ELF (Ghidra function map, SDK functions from the fork's signature database) ✅
    Recompile it and link the generated code with the PS2Recomp runtime (Windows) ✅
    Boot: EE kernel, the game's own IOP modules, EA's heap, first frames on screen ✅
    Loading, memory card check, legal screen ✅
    Movies, title screen ✅
    New Game, the intro cinematic ✅
    First battle ✅
    The first battle played and won; the first chapter 🔧
    Sound and music (the driver runs; not checked by ear yet) 🔧
    Saving to the memory card ⏳
    Linux and macOS builds ⏳
    Full speed, widescreen, higher resolution ⏳

    Native port (no PS2 hardware emulation left, not even a small part: the shared goal of the fork's ports). Native means the game's draws built straight from its own data (vertices, matrices, materials), with no GIF packet, no GS state machine and no copy of GS memory in between.

    Layer
    IOP modules (sound, streaming, pad, memory card) recompiled to C++, none interpreted ✅
    Game time, sound and IOP on the PC's clock ✅
    No paraLLEl-GS: OpenGL on the GPU ✅
    Frame loop on the PC's clock in game and menus (PS2X_FRAME_CAP, default 60; movies still on the vblank) 🔧
    The two hottest VU1 programs (the 3D strips, 0x460 and 0x268) translated to C++, no VU interpreter (TTA_VU1_PORT=0: sandbox) 🔧
    Native draws from the game's data, no GIF packet and no GS front end ⏳

    Still emulation, to remove:

    • GS front end and gsWrites. Every draw, the C++ ports' included, still carries the PS2 register writes of its packet (TEX0, CLUT loads, ALPHA, TEST, ...) and the GS front end replays them through its state machine; the OpenGL back end takes textures, CLUTs and targets from that GS state.
    • VU1 sandbox. Every VU1 program but 0x460 and 0x268 (the characters: 8df1e059 0x10 / 0x190 / 0x1F8, d43b1a88 0x620, ...) runs as VU1 microcode in the native adapter's sandbox, with VU memory, flags and XGKICK packets.
    • CPU copy of GS memory. Every texture upload is swizzled pixel by pixel into a CPU copy of GS memory and mirrored to a GPU texture (6.8 MB a frame in battle).
    • VIF1 unpacks, VU0 microcode (0xA80, the mesh math), the movies' vblank pacing.

    ✅ works · 🔧 in progress · ⏳ not reached yet

    docs/RECOMP_NOTES.md records how the port is brought up, every fix and how it was found, and what remains open.

    Screenshots

    Berethor facing three Black Riders in the forest cinematic, drawn without the emulated VU1

    2026-10-29. The Black Riders' cinematic with the VU1 sandbox (now the default): no VU1 program runs on the emulated VU1 unit, the native adapter runs each one in a sandbox and hands what it draws to the OpenGL renderer in GS order, replaying each packet's GS register writes. That is still emulation (VU1 microcode, GS state machine), see above. The first battle, its scene unlock and the film clip after it match the VU1 path, at the same frame rates (19.5 in battle).

    A Black Rider raising its sword in a misty forest, in-engine The Scenes menu after the first battle: Nazgul Agenda, scene 2 of 109, unlocked

    2026-10-29. The first battle played to its end with the Cross button alone (a pad script): the Black Riders' cinematic, the scene it unlocks (Nazgul Agenda, 2/109) and the film clip that follows, in one 11-minute run.

    The first battle: Berethor facing two Black Riders, with the Attack / Taunt Foe / Skip menu, turn portraits and HP

    2026-10-29. The first battle (Berethor against two Black Riders), reached with the defaults only: the native OpenGL renderer, the IOP modules recompiled, the game on the PC's clock. What crashed the intro cinematic in most runs was CD reads completing at once; they now take drive-like time.

    An in-engine scene: a dark horse in a misty forest, drawn by the native OpenGL renderer

    2026-10-29. After New Game: the in-engine intro cinematic, the game's own 3D drawn by the native OpenGL renderer.

    The title screen: The Lord of the Rings: The Third Age logo over a dark blue background, with New Game, Load Game and More The attract movie: two characters on a forest path at dusk

    2026-10-28. The title screen, after the EA GAMES and New Line Cinema movies; the attract movie plays and returns to it. The movies end the way the game signals it (its no-data callback returns 0), fork tlotr/mpeg-nodata-end.

    The loading screen: the One Ring with its glowing inscription and an Elvish-style line of text A message box: Checking memory card (PS2) in MEMORY CARD slot 1 The Lord of the Rings: The Third Age logo above the copyright notice The EA GAMES Challenge Everything boot movie

    2026-10-27. The loading screen, the memory card check, the legal screen and the first boot movie, drawn by the recompiled code. The disc is read through the game's own IOP sound and streaming module, and the VU1 microprograms run AOT-compiled (with exact MAC/status flags for now). The white band on the right is outside the 516-pixel-wide area the game draws in this build.

    2026-10-26: first frames

    The loading screen with a garbled line of text

    The ring of the loading screen turned, but its text was garbled and the game never read the disc.

    Goal

    A fully playable The Third Age as a native executable on Windows, Linux and macOS, from the intro to the end of the campaign. Accuracy first; once it is playable, widescreen and higher internal resolution.

    How it works

    disc files (game/) ──► Ghidra (headless, EE extension) + ExportPS2Functions ──► recomp/ghidra/tta_functions.csv
                       ──► ps2_analyzer (SCE SDK signatures) ──► recomp/tta_slus21027.toml (stubs, entry points)
                                               │
                         ps2_recomp ──► C++ (one file per function, generated/) · ps2_vu_aot ──► VU microcode (generated/vu1/)
                         tools/iop_recomp.py ──► the IRX modules as C++ (generated/iop/, scripts/iop_recomp.sh)
                                               │
                     CMakeLists.txt ──► PS2Recomp runtime + generated code + runtime/ (TTA's overrides)
                                               │
       PS2Recomp runtime: EE kernel HLE · DMAC · GIF + native OpenGL GS renderer · VIF/VU · IPU ─┼─► ps2EntryRunner
       PS2Recomp IOP:     the game's IRX as recompiled code · SPU2 on the PC's clock · SIO2
    
    • The retail executable is stripped. Ghidra with the Emotion Engine extension maps its functions, and ps2_analyzer names the Sony SDK functions that have runtime handlers from the fork's signature database (102 at first pass).
    • PS2Recomp turns every function into C++ and emits the address-indexed function table.
    • The top-level CMakeLists.txt builds the fork's runtime, swaps its placeholder function table for the generated one and links everything into ps2EntryRunner.
    • runtime/tta_overrides.cpp holds the game-specific bindings and defaults (native GS renderer, recompiled IOP modules, COP0 Count on the PC's clock, drive-like CD timing); runtime/tta_native.cpp the native rendering work.

    The PS2Recomp fork lives in PS2Recomp/ (git submodule, TheBozos/PS2Recomp), shared with the Twisted Metal: Black, Valkyrie Profile 2 and Drakengard recompilations.

    Requirements

    • Windows 10/11 with MSYS2 (UCRT64), Linux, or macOS
    • CMake 3.21+, Ninja, GCC 13+ or Clang with C++20
    • FFmpeg development libraries (libavcodec, libavformat, libavutil, libswresample, libswscale) and pkg-config
    • bsdtar (libarchive) to extract the disc, Python 3
    • To regenerate the function map: Ghidra 12 with the Emotion Engine extension and a JDK 21
    • A CPU with AVX2 (the runtime is built for x86-64-v3)
    • Your own copy of SLUS-21027 (check the hash above)

    Build and run

    git clone --recurse-submodules https://github.com/TheBozos/TLOTR_TTA_Recomp.git
    cd TLOTR_TTA_Recomp
    scripts/extract_iso.sh "/path/to/Lord of the Rings, The - The Third Age (USA).iso"   # disc files -> game/
    scripts/build_tools.sh                                   # ps2_recomp, ps2_analyzer, ps2_vu_aot -> build/tools
    GHIDRA_INSTALL_DIR=/path/to/ghidra scripts/ghidra.sh     # only to regenerate recomp/ghidra/tta_functions.csv
    scripts/recomp.sh                                        # ELF + recomp/tta_slus21027.toml -> generated/
    scripts/iop_recomp.sh                                    # boots once, recompiles the IRX modules -> generated/iop/
    scripts/build_runtime.sh                                 # runtime + generated code -> build/game
    scripts/run.sh                                           # ps2EntryRunner game/SLUS_210.27

    Windows

    The same scripts run in an MSYS2 UCRT64 shell, with MSYS2's GCC (MSVC is not supported for this port).

    pacman -S --needed mingw-w64-ucrt-x86_64-{gcc,cmake,ninja,pkgconf,ffmpeg,libarchive,python} git

    scripts/stage_dlls.sh copies the DLLs the runner needs next to ps2EntryRunner.exe, so it can also be started outside the MSYS2 shell.

    scripts/analyze.sh regenerates the TOML from scratch; it discards manual edits, so diff before committing.

    Sharing the machine with other ports

    Several PS2Recomp ports are developed on the same machine and share a two-slot bench lock (the fork's tools/bench_lock.sh): a game run takes one slot, a build or a timed run takes both, in arrival order.

    scripts/bench_lock.sh take 15 "boot check"           # a game run: one slot
    scripts/bench_lock.sh take 20 "full rebuild" alone   # a build or a timed run: the whole bench
    scripts/bench_lock.sh release

    Legal

    This project contains no code or data from the game. You must own the game to use it. The Lord of the Rings: The Third Age is a trademark of its respective owners; this project is not affiliated with or endorsed by them.