Libultraship (LUS) Porting Guide

Libultraship (LUS) is a library designed to facilitate PC ports of Nintendo 64 games. It is not a recompilation tool; rather, it allows developers to build a game’s original source code (derived from decompilation) on modern hardware by providing a header-compatible wrapper around modern reimplementations of N64 SDK functions.

In essence, LUS acts as “compile-time WINE” for the N64.


Supported Platforms

LUS supports the following platforms and rendering backends:

Platform Rendering Backends
Windows OpenGL, Direct3D 11
macOS OpenGL, Metal
Linux OpenGL
iOS OpenGL, Metal
Android OpenGL ES
OpenBSD OpenGL

Prerequisites

  1. A Game Decompilation: You must have the source code of the game (e.g., Star Fox 64, Banjo-Kazooie) ready to build.
  2. Template Project: Use Ghostship as your reference. This is the standard example project used by existing ports to handle CMake configurations and asset management. Ghostship is a separate repository and is not included in this one.

The Porting Process

Phase 1: The “Stub” Build

The initial goal is not a playable game, but simply a functional executable that links against LUS.

  1. Setup:
  2. Header Replacement:
  3. Compile & Fix:

Phase 2: Runtime & Logic

Once the executable exists, the game will likely crash immediately or behave erratically.

  1. Debugging: Use breakpoints to trace the logic and fix crashes as they arise.
  2. Microcode (UCode): Verify the game’s graphics microcode.

Phase 3: Assets (The Fork in the Road)

You have two options for handling game assets (textures, models, etc.):

Option B: The Simple Method

Phase 4: Audio

Audio is generally the last step. It requires significant effort to hook into LUS’s audio system once the rest of the game is stable.

LUS only exposes PC audio drivers — it does not interface with N64 audio. The available audio backends are:

Your port is responsible for implementing the game’s audio pipeline and routing its output through one of these drivers.


Build Configuration Options

Key CMake options that porters should be aware of:

Option Default Description
GBI_UCODE F3DEX_GBI_2 Graphics microcode variant (F3DEX_GBI_2, F3DEX_GBI, F3DLP_GBI)
INCLUDE_MPQ_SUPPORT OFF Enable OTR/MPQ archive support (via StormLib)
NON_PORTABLE OFF Build a non-portable version
DISABLE_DLL_LOADER OFF Disable dynamic library/script loading
LUS_BUILD_TESTS OFF Build unit tests

LUS Architecture

Bridge Pattern

LUS uses a “bridge” pattern to connect N64 SDK function calls to modern implementations. Bridge modules exist for audio, graphics, controllers, resources, events, scripting, console variables, crash handling, and window management. When porting, you interact with these bridges through the standard N64 SDK API — LUS routes calls to the appropriate modern backend automatically.

The bridge implementations live in src/libultraship/bridge/.

Directory Structure

Understanding the LUS codebase is helpful for debugging and contribution:

Directory Description
src/libultraship/ Contains N64-specific code including the libultra reimplementation (libultra/), bridge layers to modern backends (bridge/), controller support, window management, and logging.
src/ship/ Platform-agnostic code: resource/archive management, audio backends (SDL, CoreAudio, WASAPI), controller abstractions, configuration, scripting/DLL loading, security/keystore, and utility functions.
src/fast/ The Fast3D Renderer. Interprets N64 display lists as commands for modern GPUs. Supports OpenGL, Direct3D 11, and Metal backends.
include/ Public headers mirroring the src/ structure. The main entry point is libultraship/libultraship.h.