Rendering Optimizations in Lighthouse: How HarbourMasters Optimizes Banjo-Kazooie for Modern GPUs

Lighthouse employs eight distinct rendering optimizations—including adjustable draw-distance scaling, padded frustum culling, and stable insertion sorting—to eliminate overdraw and reduce CPU overhead when running the 1998 Nintendo 64 classic on contemporary graphics hardware.

The HarbourMasters/Lighthouse project is a reverse-engineered PC port of Banjo-Kazooie that transforms the original fixed-function console renderer into a scalable modern engine. These rendering optimizations for modern GPUs allow the game to leverage increased fill-rate, memory bandwidth, and compute power while preserving the authentic visual experience.

Adjustable Draw-Distance and Level-of-Detail Control

Lighthouse exposes per-user control over visibility distance through the port_drawDistanceMul multiplier. This cvar scales both the cull distance and LOD thresholds, letting the engine render farther objects only when users request higher settings.

In src/port/Patches/GraphicsPatches.cpp, the engine checks this multiplier before submitting geometry to the GPU. Disabling LOD entirely via Graphics.DisableLOD removes the mip-map and geometry-simplification step, useful for GPUs with ample memory that can handle full-detail models at any distance.

// Increase draw distance (max = 6)
CVarSetInteger(CVAR_DRAW_DISTANCE, 4);   // 4× normal distance

// Turn off Level-of-Detail (LOD) culling
CVarSetInteger(CVAR_DISABLE_LOD, 1);

Enhanced Occlusion Culling for Level Geometry

The GEOCULL_CONSUMER_ENHANCEMENT system in GraphicsPatches.cpp extends the original portal-culling with custom rules for specific geometry. When draw-distance is maximized, this forces certain portal-cull geometry—such as the stonehenge structure in Mumbo's Mountain—to remain visible, preventing hidden geometry from being unnecessarily processed.

This enhancement addresses edge cases where aggressive culling would break visual continuity in expanded view distances.

Padded Frustum Culling with Cached Plane Computation

The src/port/Patches/PerfPatches.cpp file implements padded frustum culling to reduce per-object cull checks. The key technique:

  • Frustum planes are widened by kDrawDistCullPadDeg (configurable padding in degrees)
  • Plane equations are recomputed only when the camera moves
  • Far-away objects stay visible without triggering expensive per-object checks

This cuts draw call submission overhead significantly on CPU-bound systems.

Stable Insertion Sort for Cube Prop Rendering

Lighthouse replaces the original $__cube_sort routine with a stable insertion sort that executes in a single pass on already-sorted data. As implemented in PerfPatches.cpp, this optimization dramatically reduces sorting overhead each frame—critical for scenes with many interactive props.

The stability guarantee preserves correct draw-order for transparent and overlapping objects.

Optimized Per-Vertex Lighting Calculations

The light re-color optimization in PerfPatches.cpp avoids costly square-root operations through early-out logic:

// Pseudocode of the optimization pattern:
if (light_outside_fade_range) {
    // Skip sqrtf entirely
    distance_sq = raw_distance_squared;
} else {
    // Only compute sqrt when actually needed
    attenuation = sqrtf(distance_sq);
}

This reduces per-vertex lighting cost, particularly in scenes with many dynamic lights.

Snow Particle Rotation Caching

Particle-heavy scenes like Freezeezy Peak benefit from trigonometric caching. The sHaveTrig flag in PerfPatches.cpp caches sine and cosine values for camera rotation, reusing them across all snowflakes rather than computing four trig calls per particle per frame.

Mirror Pass Culling Corrections

Horizontal mirror effects in the original game required special handling. In src/port/Patches/MirrorPatches.cpp, Lighthouse applies mirroring via projection matrix scaling and inverts the interpreter's cross-product sign to maintain correct culling. This prevents spurious discard of mirrored geometry that would otherwise disappear due to winding-order changes.

TLUT State Isolation for Rom-Hack Compatibility

Rom-hack models can leak texture lookup table (TLUT) state between draws. The port_modelRenderResetTLUT function in GraphicsPatches.cpp restores the default palette before each model draw, preventing unnecessary texture state changes that would force GPU pipeline stalls.

Enabling and Tuning Optimizations

All rendering optimizations expose console variables (cvars) reachable from Settings → Developer or via lighthouse.cfg.json. Changes register through RegisterShipInitFunc objects and take effect after restart.

Example configuration:

// Maximum draw distance with padded frustum
CVarSetInteger(CVAR_DRAW_DISTANCE, 6);

// Rare: disable stale-tile fix for Freezeezy Peak lobby door
CVarSetInteger(CVAR_FP_LOBBY_DOOR_TILE, 0);

For profiling culling decisions, the debug UI in src/port/DevTools/OcclusionDebug.cpp visualizes bounding volumes and cull results.

Summary

  • Draw-distance scaling (port_drawDistanceMul) and LOD control adapt workload to user preference and GPU capability
  • Padded frustum culling with camera-movement-triggered recomputation eliminates redundant per-object checks
  • Stable insertion sort replaces quadratic prop sorting with linear-time behavior on sorted data
  • Lighting and particle optimizations remove expensive square-root and trigonometric operations from hot paths
  • Mirror culling fixes and TLUT reset maintain correctness for special rendering modes and modded content

These techniques in GraphicsPatches.cpp, PerfPatches.cpp, and MirrorPatches.cpp collectively allow Lighthouse to scale from modest integrated graphics to high-end discrete GPUs while maintaining the original game's aesthetic.

Frequently Asked Questions

How do I maximize draw distance in Lighthouse?

Set CVAR_DRAW_DISTANCE to 6 via the console or configuration file. This enables the maximum 6× multiplier and activates padded frustum planes. According to the HarbourMasters/Lighthouse source code, values above 6 are clamped to prevent excessive overdraw.

Will disabling LOD improve or hurt performance?

It depends on your GPU. Disabling LOD via CVAR_DISABLE_LOD removes geometry simplification and mip-map selection, increasing vertex and texture bandwidth. Modern GPUs with abundant VRAM and compute headroom often show improved visual clarity with minimal frame-time impact; older or integrated graphics may stall on the additional workload.

What causes the Freezeezy Peak lobby door to flicker, and how do I fix it?

The original game contains a stale-tile bug in this area. Lighthouse applies a fix by default, but in rare cases this conflicts with certain rom-hacks. Set CVAR_FP_LOBBY_DOOR_TILE to 0 in lighthouse.cfg.json to disable the patch, as documented in GraphicsPatches.cpp.

Where can I verify that culling optimizations are working correctly?

Use the occlusion debug interface in src/port/DevTools/OcclusionDebug.cpp. This renders bounding volumes and color-codes culled versus visible geometry, letting you confirm that padded frustum planes and portal extensions behave as expected with your specific camera angles and draw-distance settings.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →