Skip to content

Track and world ​

How a track is loaded (0x471000-0x474000, 0x474000-0x48a000) and what the port has of it (src/game/track.c, src/game/world.c).

Files ​

A track <name> lives in the tracks' directory (GameData\Track\ in the installed game; the exe reads the directory through the pointer at 0x65b2b8, which is set at startup by code not located yet: the exe contains no such string). Track_Load 0x471ad0 joins the directory and the race's track name (0x657444) and hands the path to Track_LoadWorld 0x487650, which reads, in order:

FileRead byPort
<name>.crpthe chunk-data loader (UDataFile_load 0x59f6a0)yes
camera animations (root CmAn items)0x471660, 0x4717b0yes
the track renderer (root materials, render methods)0x44a520, 0x44a6b0pending (3D renderer)
<name>_fstart.scn, _bstart.scn, _st<n>.scn, other *.scnScene_LoadStarts 0x46cc00, Scene_LoadStartScenes 0x46d550, Scene_LoadSkillTest 0x46d280pending
animdefs.txt0x47ed00, WMidGround_ParseObjectDefs 0x47ea60pending
the articles (root Arti articles)World_BuildBundles 0x487940yes (the article bundles, object list)
<name>.edgTrack_LoadEdges 0x488000 (from 0x487940)pending
visibility walls (root Vis item)0x4889d0yes
simulation data (root SimD, SimT)0x47fbd0, 0x47ff20pending
<name>.jnc0x480f20pending

The track's chunk tree ​

The root is a Trak record. Its items: CmAn (5 camera animations), Desc (descriptions), RMth (render methods), SimD/SimT, Vis (visibility walls), mt + index (materials; +0x28 is the texture, the name of an entry of <name>.fsh read as a little-endian u32, or 0) and sn. Its articles are all Arti, one per piece of the track, named like RD1136C (1 PRIMARY) (road) or CNK0000L (1 BUSHCLIFF_BACK1_SECONDARY CHP1) (scenery chunk). An article's items: Name, Base, the geometry (vt, nm, uv, df, pr lists, see docs/formats.md), and for placed objects tr (a 4x4 matrix), Anim, Anqt.

The Base item (0x70, 0x7c or 0x88 bytes in the data; the world reads its first 0x48):

OffsetWhat
+0x00flags: 0x8000 scene prototype, 0x6000 mid-ground (0x2000 solid), others not read here
+0x14, +0x20bounding box min, max
+0x2c, +0x3cbounding sphere centre (+0x38 is w = 1), radius
+0x44object type (four characters as stored, e.g. DFLT), for prototypes and instances

Bundles ​

The world (BWorld, 0x3c bytes, global 0x628960) keeps the tree and splits the articles into bundles, R3DTypes::W3DObjectBundle (0x30 bytes, ctor 0x489090): vtable, two flags, the drawing object (+0x8), the collision object (+0xc), the entry count (+0x18) and entries (+0x1c, 8 bytes each: flags and the article), the kind (Arti), a serial number (counter 0x5d0608) and the world's context (the track renderer, BWorld +0xc). WArticleBundle (0x34) adds a 64-byte lookup cache per entry (+0x30, 0x477ca0/0x477cd0): the article, the end of its items and seven {record, id} pairs for the ids of the table at 0x5e5084 (vt nm uv df Base pr ef), so repeated lookups of the same item don't search again (0x43c620, 0x43c650).

World_BuildBundles gives the array of all articles to each bundle's load (vtable slot 1) in this order; a load takes the articles it is for by clearing them from the array:

BundleLoadTakesNotes
WSceneBundle (0x4c)0x482680nothing (copies)prototypes: tr + Base 0x8000; then 64 instance slots (or as many as the scene has geometry elements, 0x46d910, when that isn't 0), each first a DFLT placeholder at y = 9999 (0x482bb0)
WInstanceBundle (0x44)0x478130tr without 0x8000each instance's record (0x38: position, 3x3 rotation, type, a byte of its object definition) from its tr matrix (0x539ab0); with a running Anim item the record stays at the origin; keeps a copy of the prototypes like the scene
WAnimBundle (0x38)0x477780an Anqt iteman animation per entry (0x4713f0)
WMidGroundBundle (0x34)0x47cba0Base & 0x6000entry flag 0x400000 without 0x2000
WStaticBundle (0x34)0x4833a0everything left
WLineBundle0x479890(the line set, not articles)pending

The prototypes stay in the array (the instance bundle doesn't take them), so the anim bundle takes the animated ones and the static bundle the rest. Every track has the same 70 prototypes, 29 of them animated.

Then every entry of every bundle becomes an object of the world's object list (8 bytes: bundle, a flag, the entry index; 0x489760, 0x488d20): the list the renderer and the queries walk. The port keeps it in BWorld.objects.

Per track (articles: scene slots / instances / animated / mid-ground / static, visibility walls):

TrackArticlesInstAnimMidStaticWalls
alps1752111321511458275
autobahn13124035147109062
canyon15805129131487185
castle267110132412497403
coastal76821316864848
farmland1139723025101280
foothills13324829271228112
forest11726829211054175
industrial18154737501681160
monaco1-5507-6698-222924-29439-59497
skidpad27602932440

Visibility walls ​

Vis holds 0x18-byte records, two points each. 0x4872a0 turns a record into a wall in the ground plane: a flag (the first point's y isn't 0), the first point's x and z, the delta to the second, the length squared and its inverse (1.0 at 0x5b24a8 over it). The walls are line-of-sight blockers, not a renderer's visibility list: 0x488ac0 answers whether the line from a point to another crosses an enabled wall (per-wall disable flags at BWorld +0x30), in one mode any wall, in the other only raised ones; the crossing test is 0x489bf0 (both parameters in [0, 1], parallel lines never cross). Its caller is 0x47f8a0. Drawing visibility is the renderer's sphere test against the view (EAGL, docs/re/eagl.md), on each object's bounding sphere.

What a renderer uses ​

BWorld.objects[i] is {bundle, flag, index}; bundle->entries[index].article is the article, whose items are the geometry (UData_find(article, 'vt ') and friends) and WArticleBundle_base / WArticleBundle_sphere give the bounds. Materials are the root's mt items; their texture is an entry of <name>.fsh (loaded with UTIL_loadshape, converted by RTex_ConvertShape 0x44d6b0). Instances carry their placement in WInstanceBundle.placed[index] (position and rotation), scene slots in WSceneBundle.placed.

OpenNFSPU is released under the GPL-3.0. Need for Speed: Porsche Unleashed is © 2000 Electronic Arts; Porsche is a trademark of Dr. Ing. h.c. F. Porsche AG. OpenNFSPU contains no original code or assets and is not affiliated with them: it runs the game from your own copy. It runs on gasm.