Help wanted across the whole project. OpenUG2 has grown beyond what one maintainer can reasonably research, implement and test alone. Contributors and future maintainers are welcome across asset formats, rendering, physics, racing, AI, tooling, documentation and platform support. See Help Wanted — community roadmap #5 and the contribution areas below, or join the community Discord.
An open, from-scratch reimplementation of the Need for Speed: Underground 2 engine. It reads the original game's data files directly — no Wine, no box64, no x86 emulation — parses the geometry, textures and racing lines, and runs a native racing scene: a textured car you drive around a real circuit against AI opponents, with laps and standings.
Portable across x86 and ARM (Linux, macOS, Windows; desktop OpenGL and OpenGL ES). In the spirit of OpenMW / OpenRW / OpenRCT2: the engine is open source; you bring your own copy of the game.
⚠️ OpenUG2 contains no game assets and no EA code. You need a legally acquired copy of NFS: Underground 2 and point the engine at its data directory. Not affiliated with, authorized, or endorsed by Electronic Arts — see Legal Notice & Disclaimer.
OpenUG2 is an early clean-room engine prototype, not yet a finished or drop-in replacement for the original game. The asset → render → drive → race pipeline works, but only selected content has been verified end to end.
Recent captures of racing, the map editor, vehicle detail, texture filtering, the modification UI and world lighting. These show work in progress; AI passing, HUD presentation, fountain animation, sea quality and shop lighting still need work.
| Native map editor | Circuit race — 4K capture |
|---|---|
![]() |
![]() |
| Rainy fountain plaza — 4K, maximum vehicle detail | Red shop vinyl selection |
|---|---|
![]() |
![]() |
| Vehicle detail | ImGui modification menu |
|---|---|
![]() |
![]() |
| Vehicle detail | Road detail |
|---|---|
![]() |
![]() |
| Street lighting — first view | Street lighting — second view |
|---|---|
![]() |
![]() |
| Building sign and street materials | Waterfront and bridge |
|---|---|
![]() |
![]() |
Known defects are tracked alongside the progress. For example, #6 documents a reproducible world-surface artifact with its own capture and acceptance criteria.
In a debug build, open Modification → Graphics (Red shop) → Vinyl to
search the current car’s designs, apply one immediately or remove it with
None. The catalogue matches --vinyl list; --vinyl NAME still selects
a design at launch. Changing cars clears the vinyl and loads that car’s catalogue.
- Track assets — parses
STREAM*.BUNscenery and object transforms, emits road/terrain material ranges per submesh, resolves regional and shared TPK textures, and batches the result for OpenGL. L4RA and L4RB are the current single-region reference maps. - Scene recovery — corrupt source vertices no longer delete an otherwise valid object wholesale. This restores shipped traffic, warning, median and airport signs at their authored transforms.
- Car rendering — loads
GEOMETRY.BINandTEXTURES.BIN, selects real per-part material slots and UVs, and renders body paint, glass, lights, badges and other parts without the old forced-black roof treatment. - Vehicle contact — four wheel locations probe the world independently and feed a sprung body-height/orientation model. Walls use a mesh narrow phase and resolve along the contacted face instead of an enclosing AABB axis.
- Stance — every car now ships lowered by default. The clearance limit is measured against the body shell alone; the rim and brake slices reach hub height, and counting them made the engine think each car was already on the deck, so nothing could be lowered. Tyres stay on the road surface, and Vehicle Diagnostics → body lowering still tunes it per car.
- Vehicle modification — body parts, full kits, rims, paint, rim paint and neon are selectable live from the ImGui developer menu, with per-car asset inventories and reversible stock fallbacks.
- Driving — keyboard-controlled arcade acceleration, braking, steering, handbrake and surface-dependent grip. Per-car source records provide mass, torque, gearbox and steering values; measured geometry supplies lateral grip and load transfer.
- Open-world traffic — traffic and roaming racers follow authored road points through steering and speed targets. Player and AI share suspension, airborne momentum and landing response; the camera reacts to landing impact. Spawns require road support, clearance and an off-screen location.
- Racing — source event types, grids, continuous courses, ordered checkpoints and laps drive physics-based opponents. Circuit, sprint, drag, drift, Street X and URL have distinct prototype rules; road events retain ambient traffic. Drag uses discrete lane changes/manual shifts and drift uses measured slip. Event decoding does not guarantee every course can finish.
- Map editor — a separate native ImGui tool edits collision boundaries,
objects, AI paths, races, lighting, shops and districts, with viewport handles,
undo/redo and review exports. Reviewed collision corrections are compiled into
the game; arbitrary editor projects are not loaded by gameplay. See
tools/MAP_EDITOR.md. - Timing and diagnostics — driving and contacts advance at a fixed 60 Hz,
with interpolated rendering and chase-camera movement. The ImGui Race Log
records telemetry;
.marks a problem and saves its nearby actor snapshot. - World visibility — production uses the
ordinarytier, whose view range follows the active fog (about 933 m with the current settings). Developer UI and provisional HUD elements are hidden by default and toggled with1.
- Vehicle handling is still an arcade approximation, not NFSU2-equivalent.
Stock mass, RPM limits, torque curve, steering response and drivetrain, plus
four source power/gearbox levels, are read from each car's
GLOBAL/GLOBALB.BUNrecord. The engine does not yet simulate a full drivetrain or decoded brake, tyre and suspension upgrade packages. - Traffic junction selection, route-end queues and collision impulses remain provisional. Short deterministic drives pass, but long-session traffic flow and retail handling fidelity are not yet established.
- Race coverage is incomplete. Some routes still stop under normal collision, and the passing planner can make opponents weave between sides. Fitted-car, player/traffic interaction and full-career verification remain open.
- The opt-in driving/race HUD and event rules are prototypes; a production-quality front end and career progression remain missing.
- Some race-specific
ZCV_/ZCS_set-dressing definitions are decoded without a proven world-placement or mesh-linkage rule. - The experimental
--tier fullpanorama pass still exposes opaque authored backdrop sheets as hard-edged bands at some headings. It is not the default. - Vehicle presentation still needs a complete tyre/rim render pass and further visual validation across cars. The misplaced stock spoiler is now attached to its trunk socket. The ImGui modification flow now covers bumpers, skirts, hoods, spoilers, exhausts, lights, full body kits, rims, paint, neon and a searchable vinyl catalogue in the Red / Graphics shop. Multiple vinyl layers, decals, mirrors, wide-body kits, rim sizing and individual performance packages are still missing, as are ownership, money, purchases and saving.
- Lighting fidelity is still evolving: installed headlight/taillight styles now
scale emissive output,
L/Jdrive low/high and flash beams, andNgives a small nitro headroom with stretched tail glow and soft screen-corner haze. Street/district lamps now draw as camera-facing flares of near-constant screen size instead of the authored 10 m influence radius, which used to intersect the lamp post, the ground and nearby walls and leave hard-edged bright slabs wherever the depth test cut the quad. The authored light shafts no longer render as solid black wedges hanging off the buildings: theirSFX_LIGHT_BEAMAtexture does not decode from the offset its record names, and an untextured world batch is now skipped instead of drawn as a flat grey slab. Recovering that texture's real data offset is still open. Road-closure lights still need material/group attribution. Wet-road sheen, sparse puddles, reflections and screen rain droplets are implemented, with further fidelity and performance work remaining. - Collision support and attribution still need whole-map driving validation. Reviewed STREAML4RA model-wide corrections retain visuals and ground; their exact local boundaries need revalidation for different asset editions.
- The northern mountain-road route needs a source-level visibility audit; after that, the selected-route direction arrow must be recovered from authored route/HUD data rather than guessed from the diagnostic map.
--track ALLcurrently unions incompatible city/event bundles that overlap in the same coordinates. It is useful for research, but is not a valid playable open-world composition.
Developer references:
docs/DEVELOPER_GUIDE.md— architecture, ownership, runtime data flow, invariants, tests and agent workflow.docs/FORMATS.md— evidence-labelled file layouts, parser contracts and clean-room format notes.docs/VEHICLE_CUSTOMIZATION.mdanddocs/GAME_FLOW.md— the shop/modification surface and the retail game-flow contract behind it.
Needs SDL2 and zlib.
# macOS: brew install sdl2
# Debian/Ubuntu: sudo apt install libsdl2-dev zlib1g-dev
make # desktop build -> ./nfsu2
make gles # OpenGL ES 2.0 build (embedded/mobile ARM)
make debug # desktop build + Dear ImGui developer menu (dev only)
⚠️ Customization, modifications and engine internals live behindmake debug. A plainmakebuild compiles the panel out completely:1only toggles the provisional pixel-font HUD, and there is no way to reach the shops or diagnostics. If you want to change rims, body kits, paint, neon or lighting, or inspect anything the engine has parsed, you must build withmake debugand open the panel with1. See Developer menu (ImGui) below.
Cross-compiling for another ARM target is just the compiler swap, e.g.
CC=aarch64-linux-gnu-gcc make gles.
Build with make debug, run the engine, then press 1 to open the
NFSU2 Master Inspector (Dear ImGui, vendored under third_party/). This is
where every modification, diagnostic and tuning control lives. Plain make
builds compile the panel out entirely, so none of this is reachable there —
1 gives you only the provisional viewport HUD.
| Tab | What you get |
|---|---|
| Modification | The vehicle shop surface. Live car selector (swaps the vehicle without restarting the world or losing your pose) plus colour-coded Underground 2 shop subtabs. |
| Vehicle Diagnostics | Per-car wheel stance (axle, track, ride, body lowering), live handling readouts, engine-cover and car-part inspection, mesh inspector, wheel spin/steer demo. |
| Lighting & Environment | Night mode, headlight beam preview, beam pitch/reach/intensity, lens opacity, headlight shadows, street/district flare size and brightness, chase-camera distance/height/stiffness, ambient/diffuse/fog. |
| World & Entities | Live traffic density (0–16 cars, default 4), active traffic/racer counts, loaded track selector, scenery semantics census, nearby world chunks, decoded ZCV_/ZCS_ entity definitions, UV checker, HUD toggle. |
| Placement Marks | Report a misplaced object by driving to it. Live probe readout (world XYZ, the ground selector's surface height and category, the covering chunk's asset name, district), then F9 marks the defect and F10 marks where it should be. Marks carry a note, list colour-coded, and go to the clipboard or placement_marks.txt — and every mark is echoed to stdout, so nothing is lost if the session ends. |
| Engine Telemetry | FPS and frame time, draw calls, car/track mesh counts, active district, camera and car coordinates, heading and speed, free camera. |
| Navigation & Races | Top-down nav graph drawn from the authored route files, district colouring, right-click GPS routing, the shipped race-event catalog, and freeroam/race mode switching with a live race HUD. |
The Modification subtabs follow the retail shop colours:
| Subtab | Working today |
|---|---|
| Body (green) | Front/rear bumpers, skirts, hood, headlight and taillight assemblies, spoiler, exhaust, roof scoop; full body-kit presets; wheel brand and rim style from the CARS/WHEELS library. |
| Specialties (yellow) | Trunk audio, neon underglow (on/off, colour, intensity). |
| Graphics (red) | Body paint with clear-coat, highlight and reflection controls, plus streetlight paint shine and local city reflections (Medium/High vehicle detail); Low uses a square vehicle shadow, Medium/High project the model silhouette; rim paint with chrome/OEM/gunmetal presets. |
| Performance (blue) | Source power-curve and transmission levels, applied live; exact ECU/engine/turbo product mapping and the remaining packages are still being decoded. |
| Safe House (purple) | Read-only list of installed parts; ownership and saving are not implemented. |
Changes are free and instant — this is a preview surface, not career progression.
Parts a car does not ship are shown as unavailable rather than substituted, and
you have to stop the car before swapping parts. Full design notes are in
docs/VEHICLE_CUSTOMIZATION.md and
docs/GAME_FLOW.md.
For reproducible documentation captures, --devui opens the panel at launch so
--shot can grab it:
./nfsu2 DATA --car SKYLINE --devui --chase 8,1.6 --shot docs/panel.pngPoint it at your NFS: Underground 2 data directory (the folder containing
TRACKS/, CARS/, …):
./nfsu2 /path/to/nfsu2/data
# or:
make run DATA=/path/to/nfsu2/dataThe normal command opens the current L4RA open-world reference. The engine derives a start district from the selected STREAM bundle and places the car on the nearest safe authored road; no internal world-mode or spawn flag is needed.
# Open-world reference (STREAML4RA is the default)
./nfsu2 DATA
# Another single-region world / sprint reference
./nfsu2 DATA --car ECLIPSE --track STREAML4RB --event 4201
# Closed-circuit reference (uses the currently verified circuit loader)
./nfsu2 DATA --car HUMMER --track STREAML4RA \
--circuit ROUTESL4RA/Paths4175.bin--car NAME— a folder underCARS/(needs aGEOMETRY.BIN).--track NAME— a singleSTREAM*.BUNunderTRACKS/, such asSTREAML4RAorSTREAML4RB. Selecting one automatically enables the instance-driven moving neighborhood.ALLstill exists for diagnostics but is not a supported gameplay composition.--circuit PATH— a closed-loopPaths*.binunderTRACKS/.--event ID— start a shipped race event such as L4RB sprint4201.--tier ordinary— production renderer and the default.--tier fullis an experimental panorama path with known visual defects.--chase D,H— chase-camera distance and height in metres, e.g.--chase 9,1.8. Useful for framing captures without touching the ImGui sliders.--devui— open the developer menu at launch (make debugbuilds only), so a--shotcapture includes the panel.
The old --world2 option remains accepted for scripts, but it is now only a
backward-compatible alias. --spawn start|X,Y and --heading DEG are developer
overrides for reproducible audits; ordinary players and new contributors do not
need them.
It boots directly into the selected authored free-roam pose. The temporary
three-entry menu was removed because it was not the retail Underground 2
frontend; the asset-backed menu is documented in
docs/FRONTEND_ASSETS.md and is the next frontend
milestone.
Controls: driving — W/S throttle/brake, A/D steer, Space handbrake (breaks rear
grip for drifts), hold right mouse and drag to orbit the car (press F for map free flight: WASD, Q/E, Shift for speed), L high beam, J headlight flash
(racer invitations are not implemented yet), N nitro, 1 developer menu (the ImGui Master Inspector, in
make debug builds), F6 cycle rim style
(once per press), K cycle body kit, Esc quit. Cars
collide and building contact is confirmed against source mesh faces before the
car is pushed. The orbit camera stays above the car and retracts around scenery.
--shot out.png renders one frame to a PNG and exits.
The default resolution is 1920×1080. Screenshots and visual race/drive audits
render in a hidden, fixed-size GL window, so desktop window limits do not shrink
the PNG. Use --resolution 3840x2160 for 4K captures, or --resolution 960x600
for older reference dimensions. An unsupported capture size fails explicitly.
Interactive windows remain resizable and may be constrained by the display;
the log reports the actual drawable size. Existing capture scripts inherit the
1080p default. make render-resolution-test DATA=.. checks real PNG dimensions
(requires game data and a working GL display).
src/
main.c orchestrator: setup, game loop, input, race flow, HUD
nfsu2.h single-header asset parser (chunk formats — the ground truth)
world.* World: region scene assembly, texture binding, per-mesh bounds
for culling, grid-accelerated ground/contact queries
render.* Renderer: GL objects, shaders, matrices, bitmap font, screenshot
physics.* car kinematics (real units, NFSU2-tuned), wall + car collision
ai.* racing-line opponents, circuit loading
audio.* procedural engine/road/skid synth (no audio assets)
resource.* file mapping + track/car/circuit discovery
debug.* optional Dear ImGui dev overlay (`make debug`)
world_mesh.* batch uploader for the world render debug pipeline
attrib.h generic GLOBAL AttribSys diagnostic reader
tools/ Python utilities used to reverse-engineer & inspect the data formats
docs/ engine/developer guide and evidence-labelled format reference
Current execution order starts with the vehicle and its player-facing systems, then moves outward to world correctness and race systems:
- Vehicle foundation and presentation — complete tyre/rim rendering, validate stock spoiler attachments, and verify body transforms, wheel/contact placement and measured handling behaviour.
- Vehicle operations and modification flow — the Modification tab and its Body, Performance, Graphics and Car Specialties subtabs exist, and vehicle assets swap without restarting the world. What is left: persistent per-car selections, ownership/money/saving, multiple vinyl layers and decals, and real performance packages. See the customization and in-place switching design and the game flow reference.
- Vehicle/world lighting fidelity — verify model-derived headlight transforms and grounded neon first, then attribute district/fixture lights, road-closure guidance lights and the measured wet/rainy asphalt path.
- Open-world collision attribution — classify overlapping/duplicate instance meshes and false barriers before changing collision thresholds.
- Northern mountain-road visibility — recover the missing ROAD/TERRAIN coverage and verify route continuity without hiding the gap with draw range.
- Route guidance — recover the selected-route direction arrow from the authored route/HUD data after the underlying road coverage is trustworthy.
- Production race opponents — add and validate AI opponents on L4RA first, then L4RB sprint events, with race-state and HUD evidence.
- In-game driving frontend — add the production HUD for speed/RPM/gear gauges, mini-map/route state, race position and open-world money visibility; money must be hidden while an active race HUD is shown.
- Retail front end — integrate the decoded menu assets and flow after the vehicle, world-render, gameplay and in-game HUD foundations above are stable.
Each item needs a focused issue, evidence and an acceptance test. The existing
physics discipline still applies: replace a stand-in only when the source field
or a clear behavioural requirement is understood. ALL is not the reference
playable map; revisit its bundle composition only after individual regions are
correct.
OpenUG2 needs contributors and maintainers across the entire project. Its reverse engineering, engine work, validation and platform coverage are too broad for one person to sustain alone. Start with Help Wanted — community roadmap #5, or open a focused issue before beginning a large change.
Join the OpenUG2 community Discord to follow development, share feedback, ask questions and coordinate contributions. Developers, testers, documentation writers and curious NFS fans are welcome; you do not need to write code to help. Keep reproducible bugs and proposed changes in GitHub issues so they remain easy to track.
High-value contribution areas:
- Formats and asset pipeline — document unknown chunks, animated
ANM_*data, race set-dressing placement, texture/material records and safe parser fixtures. - World and rendering — verify individual bundles, restore missing authored scenery including the northern mountain roads, improve visibility/culling, and identify the structural rule behind panorama, detail-tier and lighting selection.
- Vehicle dynamics — tyre/contact behaviour, weight transfer, drivetrain and powertrain data, suspension presentation and NFSU2-style camera feedback.
- Racing and AI — production race opponents on the verified circuit and sprint paths, route following, event coverage, respawn/recovery, race HUD semantics and start/finish flow.
- Front end, audio and usability — in-game driving/race HUD, a real menu flow, settings, controls, sound design and accessible diagnostics.
- Portability and quality — OpenGL ES, Windows/Linux/ARM coverage, deterministic parser/physics tests, profiling, documentation and reproducible bug reports.
- This is a clean-room reimplementation. Never commit or paste EA assets, executables, decompiled/disassembled output, copyrighted game code or data extracted from a retail installation.
- Keep changes small and evidence-driven. Measure the production path before changing it; audit-only work must not silently alter behaviour.
- Document newly proven format facts in
docs/FORMATS.md. - Keep architectural changes and subsystem invariants current in
docs/DEVELOPER_GUIDE.md. - Build with zero warnings, keep the boot self-tests passing and keep
make glescompiling. - Include deterministic evidence: parser/test output for data changes and same-pose before/after PNGs for rendering changes.
- Do not treat
--track ALLas proof of valid placement or gameplay.
Format reverse-engineering builds on prior community work, used as references (all code here is independent):
- yugecin/nfsu2-re — a superb, detailed NFSU2 reverse-engineering project; the chunk-container format was confirmed against its documentation. Big thanks for the great work.
- Nikki — TPK / texture header reference.
- OpenNFSTools — JDLZ algorithm reference.
- PryHUB — GLOBALB car-record and powertrain-upgrade layout reference, revalidated against the local retail data.
- vgmstream — Gnsu20 / EA-XAS v0 format reference.
- noclip.website — Jasper St.
Pierre (magcius) and contributors, especially the
Need for Speed: Most Wanted viewer.
Its separation of model identity, instance placement and region loading
informed our Underground 2 placement investigation. Thank you for making
this work publicly available. Used as a research/architecture reference,
not copied code: U2 layouts and the implementation are independently checked
against U2 data. Reference revision and scope are recorded in
docs/FORMATS.md.
See docs/FORMATS.md for details.
Bundled dependency (dev builds only): Dear ImGui
by Omar Cornut — MIT-licensed, vendored under third_party/imgui/.
OpenUG2 is an open-source, non-profit game engine recreation project built from scratch using OpenGL. It does not contain any copyrighted material, assets, or original code from Electronic Arts (EA). To run this engine, users must possess a legally acquired copy of Need for Speed Underground 2. "Need for Speed" and "Underground" are registered trademarks of Electronic Arts. This project is not affiliated with, authorized, or endorsed by Electronic Arts.
The engine reads the formats of an existing game you already own, in the spirit
of interoperability projects like OpenMW and OpenRW — it ships no game data
(models, textures, audio, maps, or speed2.exe); you supply your own. All such
files are excluded from the repository (see .gitignore).
- OpenUG2 engine code is MIT-licensed — see
LICENSE. - Bundled dependency Dear ImGui (dev builds only) is MIT-licensed — see
third_party/imgui/LICENSE.txt. - The reverse-engineering references credited above are independent third-party projects; no code from them is copied here.











