Castlevania: Lament of Innocence — native Windows port

Castlevania: Lament of Innocence is a native Windows port of the PlayStation 2 game made by static recompilation.

README

Castlevania: Lament of Innocence — native Windows port

An unofficial, native Windows port of the PlayStation 2 game Castlevania: Lament of Innocence, made by static recompilation: the game's MIPS code is translated to C++ and compiled into a regular Windows program, instead of being emulated instruction by instruction.

This repository and its releases contain no game code or data. You need your own copy of the game. The launcher builds the game's code on your PC from your own disc image.

Status: early work in progress. The game boots, plays its intro and renders on the GPU, but it currently crashes (black screen) when the intro text ends. It is not playable yet.

ROADMAP.md tracks, part by part, what of the PS2 already runs natively and what is still emulated.

Supported disc

ReleaseCastlevania: Lament of Innocence, USA (NTSC-U)
SerialSLUS-20733, version 1.01
FormatA full disc image (.iso)

The launcher identifies the disc by its boot executable (SLUS_207.33, SHA-1 317b2271be7f24842c4b357c70599219389c004d) and turns away other releases and versions with a message.

Playing

Requirements
  • Windows 10 or 11, 64-bit
  • A graphics card with Direct3D 12 or Vulkan support and at least 6 GB of video memory
  • About 3.5 GB of disk space: the build copies the game's files off the disc image, which you can delete afterwards
  • Nothing else to install: the compiler the launcher uses is in the download
Getting started
  1. Download CastlevaniaLoI-<version>-win64.zip from the Releases page and extract it anywhere.

  2. Run CastlevaniaLoI.exe. The launcher opens.

  3. Choose disc image… and pick your .iso. It shows Disc verified when the disc is supported.

  4. Build the game. This happens once and takes about a minute: the launcher copies the game's files off the disc image, translates the game's code to C++ and compiles it into game.dll, with progress and a log.

  5. Set the graphics options if you like, then Play. The same options can be changed while playing with F10:

    • graphics API: Vulkan (the default) or Direct3D 12, applied after a restart;
    • internal resolution: 1x to 6x, labelled with the resolution each gives, from about 480p to about 2880p (5K). 5x is the first to reach 4K;
    • vsync;
    • aspect ratio: 4:3 or 16:9;
    • fullscreen;
    • anti-aliasing: FXAA;
    • upscaling filter: the default one, or an FSR-style edge-adaptive one for when the window is larger than the internal resolution;
    • sharpening, bloom, colour (brightness, contrast, saturation, gamma), debanding, CRT (scanlines, optional curvature), vignette and film grain.

    With every effect off, the picture is exactly what it was without them.

  6. From then on you can skip the launcher: the build also makes Castlevania - Lament of Innocence.exe beside CastlevaniaLoI.exe, which starts the game straight away with your settings (pin it, or make a shortcut to it). Run CastlevaniaLoI.exe to change the settings outside the game or to build again.

Widescreen is real 16:9: the 3D view gets wider instead of stretched (PCSX2's widescreen patch by arapapa, with nemesis2000's fix that keeps movies 4:3). The menus, text and the game's 2D pictures (logos, the title) keep their 4:3 shape, centred; the in-game HUD keeps its shape too but moves to the top-left corner; fades and full-screen effects still cover the whole picture. Switching it needs no new build, and works while playing (F10).

Third-person camera (Camera, Player camera): in place of the game's fixed cameras, a camera behind Leon that the right stick turns, as in Curse of Darkness, with its distance, rotation speed and inverted axes in the same options. The left stick then walks relative to it. R1 switches between it and the game's own camera while playing (R2 still blocks), and the right stick goes back to the game (the item menu) while the game's camera is on. The camera can pass through walls, and the game's scripted cameras haven't all been checked with it.

After the build the game plays from those copied files: the disc image is no longer needed, to play or to build again, and you can move or delete it. After an update of the port, the launcher asks you to build the game again (the new version needs a game.dll made for it); that rebuild uses the copied files too.

Controls

A game controller (Xbox, PlayStation or any controller SDL recognizes) works as a PS2 pad. Keyboard:

PS2KeyPS2Key
D-pad / left stickArrow keysL1 / R1Q / W
CrossZL2 / R21 / 2
CircleXStartEnter
SquareASelectBackspace
TriangleSFullscreen on/offF11

Other keys:

Key
F8Shows or hides the on-screen stats: frame rate and the shortest and longest gap between frames (about 16.7 ms both when smooth), CPU and GPU load, how idle each emulation thread is, memory, queued audio
F5Quick save: the whole machine state, to savestates\quick.state beside the executable
F6Quick load of that state
F10Opens or closes the graphics options; the game pauses while they're open

Quick saves are separate from the game's own memory card saves and are overwritten by every F5. They are tied to this build: a state from an older version may not load. A developer build run from inside the repository keeps them in the repository's .savestates\ folder instead, which git ignores and clean builds leave alone.

Files

Everything stays in the extracted folder:

saves\memcard1.ps2The memory card, in PCSX2's .ps2 format: the launcher's Import from PCSX2... and Export... bring a card in from PCSX2 (keeping the current one as saves\memcard1-<date>.ps2) or copy it out
savestates\quick.stateThe F5 quick save
logs\build.log, logs\game.logThe game build's log and the game's own log
Castlevania - Lament of Innocence.exeStarts the game right away, without the launcher (made by the build)
settings.iniThe launcher's settings
game\data\The game's files, copied off your disc image by the build (about 2.9 GB): the game reads its data from these
game\, game.dllWhat the launcher built from your disc. Delete them to build again (from the disc image, as game\data\ goes too)
Antivirus warnings

The programs are not code-signed (this is a free hobby project), so Windows may show Windows protected your PC on the first start: More info, then Run anyway. Some antivirus programs are wary of a program that compiles code and then loads it, which is what the launcher does. All of its source is in this repository. Download the port only from this repository's Releases page.

How it works

your disc ──► launcher ──► eerecomp ──► C++ ──► clang ──► game.dll ──► CastlevaniaLoI.exe runs it
               (checks     (MIPS R5900                                  (PS2 runtime: GS on the GPU,
                the disc)   to C++)                                      IPU, SPU2, IOP, pads)
  • ps2-web-recomp by snuri00 does the heavy lifting. eerecomp translates the Emotion Engine's MIPS code to C++, and vurecomp does the same for the game's VU1 and VU0 microcode (this port added VU0). Its runtime provides the rest of the PS2: a GS renderer on the GPU (wgpu: Direct3D 12 or Vulkan), the IPU (video), SPU2 (sound), the IOP and the memory card. This port adds Windows support on top of it.
  • The IOP, the PS2's second processor, runs the game's sound drivers: modules on the disc (IOP\*.IRX). The controller driver (PADMAN.IRX) and the memory card drivers (MCMAN.IRX and MCSERV.IRX, with the card's file system) are native code in the runtime instead. This port adds ioprecomp, which translates the others to C++ too: the build relocates each module to the address it always loads at (iop.txt), and the runtime uses that code when the module loads there unchanged, else its interpreter. The IOP's kernel is the runtime's own native code.
  • CastlevaniaLoI.exe holds the launcher and the runtime, with no game code inside. It exports the runtime for game.dll to use.
  • game.dll holds the translated game code, built on the player's PC by a trimmed llvm-mingw (Clang and LLD) that ships in the release's compiler\ folder.
  • The game's configuration (src\config\) is what this port knows about the disc: its hash, the code entry points that static analysis misses, and recipes that rebuild the VU1 and VU0 microcode images out of the disc's own executable (vu1.txt, vu0.txt), and the IOP modules to translate with their load addresses (iop.txt), so no game bytes are ever stored here. It also lists code patches (code-patches.txt, like PCSX2's .pnach ones): a translated game cannot be patched by writing its memory, so the translator builds each patched instruction both ways and the runtime picks one, here the widescreen patch when Widescreen is on.

Building from source

Requirements
  • Windows 10 or 11, 64-bit
  • Git
  • An internet connection for the first build, which downloads the tools (about 270 MB)

No Visual Studio, WSL or MSYS2 is needed: every tool comes from the build scripts.

Build
git clone <this repository>
cd <repository folder>
build.bat
ScriptWhat it makes
build.batA developer build in output\debug\CastlevaniaLoI: optimized, with .pdb debug files (Visual Studio and WinDbg show function names and source lines) and a console window with the logs. Rebuilding keeps what testing left there (game.dll, saves, settings).
clean-build.batbuild.bat from nothing, as a fresh clone gets it: deletes tools\ and output\ first (game.dll, saves and settings in output\debug go too). It stops if tools\ps2-web-recomp has changes not saved into the patch.
release.bat [version]A clean build for the Releases page: output\release\CastlevaniaLoI-<version>-win64.zip.

Run output\debug\CastlevaniaLoI\CastlevaniaLoI.exe and use the launcher as a player would.

The tools folder

On the first build, src\scripts\fetch-tools.ps1 fills tools\, which git ignores, at pinned versions, checking each download against its SHA-256:

FolderWhat
tools\llvm-mingwllvm-mingw 20261020: Clang, LLD and the MinGW (UCRT) headers and libraries
tools\cmake, tools\ninjaCMake 4.4.5 and Ninja 1.13.2
tools\wgpu-nativewgpu-native v29.0.1.1, the renderer's graphics library
tools\SDL2SDL 2.32.10: window, input, sound
tools\imguiDear ImGui v1.93.0: the launcher's interface and the in-game F10 menu
tools\dxcDirectX Shader Compiler v1.9.2609: compiles the renderer's shaders on Direct3D 12 (dxcompiler.dll ships beside the executable)
tools\ps2-web-recompps2-web-recomp, cloned at commit e026b97, with src\patches\ps2-web-recomp.patch applied

A folder already there is left alone; delete it to fetch it again.

Changing the recompiler or the runtime

The code in tools\ps2-web-recomp is upstream's plus this port's patch. That patch adds the Windows window and GPU surface, the MinGW build, the runner / game.dll split and the launcher hook-up. To change it:

  1. Edit files in tools\ps2-web-recomp and build with build.bat.
  2. Save the changes into the patch: powershell -File src\scripts\update-patch.ps1
  3. Commit src\patches\ps2-web-recomp.patch.

If a git pull brings a different patch, the build stops and asks you to delete tools\ps2-web-recomp, so that it is fetched again with the new patch. It never overwrites code that has not been saved into the patch.

Finding more of the game's code

Static analysis cannot find every function a game calls through pointers. When the game reaches code that was not translated, the runtime records the address. src\scripts\explore.ps1 runs the game headless, adds the addresses it found to src\config\entries.txt, translates and builds again, and repeats until a run finds nothing new. It also records the VU1 and VU0 microcode the game uploads into src\config\vu1.txt and vu0.txt.

powershell -File src\scripts\explore.ps1 -Frames 3600 -Rounds 8

It expects the disc image at the repository's root as Castlevania Lament of Innocence.iso (or pass -Iso <path>). Its work files go to output\explore: the disc's executable, the translated C++, recorded microcode, frame captures every 300 frames and logs. They stay out of git because they are the game's.

Repository layout
build.bat, clean-build.bat, release.bat
                         the build entry points
ROADMAP.md               what runs natively and what is still emulated, part by part
src\launcher\            the launcher and the game builder (launcher.cpp, builder.cpp)
src\config\              what the port knows about the disc: hash, entry points, VU recipes, code patches
src\patches\             this port's changes to ps2-web-recomp
src\scripts\             compile.cmd, assemble.ps1, fetch-tools.ps1, update-patch.ps1, explore.ps1
src\cmake\               the CMake toolchain file for llvm-mingw
tools\                   downloaded tools and libraries (not in git)
output\                  everything the scripts build (not in git)

Credits

  • snuri00/ps2-web-recomp (MIT): the recompiler and PS2 runtime this port is built on
  • llvm-mingw by Martin Storsjö: Clang, LLD and MinGW for Windows (Apache 2.0 with LLVM exceptions, and the MinGW-w64 licenses)
  • wgpu-native (MIT / Apache 2.0)
  • SDL (zlib)
  • Dear ImGui by Omar Cornut (MIT)
  • DirectX Shader Compiler by Microsoft (LLVM Release License and MIT; only dxcompiler.dll ships): compiles the renderer's shaders on Direct3D 12
  • jmafort/CastlevaniaCOD-PC, the native port of Curse of Darkness: the model for how this port is distributed, with a launcher that builds the game from the player's own copy

Each release carries these licenses in its licenses\ folder.

Legal

This is a personal, non-commercial fan project. It is not affiliated with, endorsed or sponsored by Konami or Sony. Castlevania is a trademark of Konami Digital Entertainment. No game code, assets or data are distributed: you must own the game to use this port.