Reference · Engine
Town and event-area assembly
partialfrom#27#28#96#97#112#218#260
A town's scene file (town01 is Mac Anu) holds each piece in its own
space: the floor, building and detail pieces of every district overlap at
the origin. The game assembles them from tables in gcmn.prg. One C++
class per town (ROOTTOWN01-05) and per event area (EVENTAREA01...)
builds its pieces from those tables and draws them itself.
The port's piney-gen (placement::statics) reads the tables into the
build as data, and crates/piney-data/src/statics holds their types.
Static models
STATIC_MODEL_INFO 0x14 bytes, e.g. RT_MODELTABLE00 (32 rows), EA_MODELTABLE01
+0x00 int type the draw pass: 1 floor, 2 obj, 3 obj2 (0 other)
+0x04 char * modelname an MDL_ object in the scene file
+0x08 int postype 0 none, 1 a DummyPos, 2 a DummyPosRot
+0x0c char * posname the DMY_ object that gives the position
+0x10 float clip drawn only within this distance of the camera
- Construction.
STATICMODEL::STATICMODEL(0x005cffd0) looks the model up by name and copies the dummy's position; for postype 2 it also copies the rotation. - Drawing.
STATICMODEL::Draw(0x005d01c0) buildssceVu0UnitMatrixthensceVu0TransMatrix(position)and draws it. The rotation is not applied, so a piece is its model translated to its dummy. It computes the distance to the camera and never uses it:clipculls nothing. - Mac Anu. In
RT_MODELTABLE00,MDL_floor_NN,MDL_obj_NNandMDL_obj2_NNall sit atDMY_floor_NNpos: district 01 at (0, 9600, 0), 03 at (−6000, 0, 0), 04 at (6000, 0, 0), and so on. The LOD copiesMDL_obj_02lodand_05lodshare their districts' dummies and replace rows 8 and 11 when the camera is far enough south (below). - Which pieces draw.
ROOTTOWN01::DrawFloor(0x00422ba0) walks its 32STATICMODELs and draws those of type 1, skipping districts byclip[3](this+0x1b0..+0x1b8), whichROOTTOWN01::Drawsets each frame from the camera eye:clip[0]on the gate plaza,clip[1]on the south plaza,clip[2]beyond y 1600 (0x44c8 << 16). The rules are on the field game page and incrates/piney-world/src/town01.rs, whoseMacAnu::selectgives what the game'sDrawgives for any camera eye (run side by side in eemu,tools/test_world_rs.py).
type is the draw pass: ROOTTOWN01::DrawFloor, DrawObj and DrawObj2
(0x00422ba0, 0x004224c0, 0x00422900) draw the rows whose type is 1, 2 and
3, and DrawObj2 draws the static objects of type 3 too. In Mac Anu,
ROOTTOWN01::Draw (0x00423b10) draws the type-0 rows itself: the static
objects of type 0 (the ships) first, the model rows of type 0 (the tower
MDL_sr1tow01) last. Dun Loireag's ROOTTOWN02 (0x004240c0, Draw
0x004266a0) draws its 20 rows by type without clip rules, its static
objects of types 2 and 3 in DrawObj and DrawObj2, and the model rows
of type 0 last (it has none): Dun Loireag. The other
classes' type-0 rows have not been traced. The port carries type as DrawPass, and postype
with posname as Position (none, a DummyPos or a DummyPosRot by name).
Static objects
STATIC_OBJ_INFO 0x18 bytes, e.g. RT_OBJTABLE00 (11 rows)
+0x00 int type
+0x04 char * clumpname a CMP_ clump, or NULL
+0x08 char * anmname the ANM_ animation that moves it
+0x0c int postype as above
+0x10 char * posname
+0x14 float clip
STATICOBJECT::STATICOBJECT (0x005cf9b0) creates the animation, or the
clump when the row names no animation. It sets its root matrix with
ccCoord::SetMatrix_PosRotZYX(position, rotation) from the dummy (T Rx Ry
Rz, the rotation turned to radians when the chunk is decoded), so one
animation can stand at several dummies. STATICOBJECT::Draw draws within
clip of the camera eye (in the ground plane) and steps the animation
only then. piney_data::statics places both (ModelTable::place,
StaticObj::root); piney-world's town builds each root as the game
stores it (sceVu0RotMatrix of the dummy's radians, pi * deg / 180 as
Decode_DummyPosRot converts them, then the position), matching the
game's matrices bit for bit. Mac Anu's six flags are
ANM_sr1fla1_a at DMY_sr1fla1_01pos..06pos, and its two ships are
ANM_sr1shi1_a at DMY_sr1shi01/02. STATICOBJECT::Draw advances the
animation, then draws the animation and the clump.
The files a town loads
Each constructor asks ccStream::GetCCSAdrs for its scene files by name.
piney-gen (placement::statics) reads the names out of the code: the
$a0 string built just before each call.
| class | files |
|---|---|
ROOTTOWN01 | town01d or town01, wat1 |
ROOTTOWN02 | town02d or town02, town_z |
ROOTTOWN03 | town03d or town03 |
ROOTTOWN04 | town04d or town04, town_z |
ROOTTOWN05 | town05, town_z |
EVENTAREA02, 04-07 | the area's file, town_z |
EVENTAREAB0 | one of se1_5, se2_3, se2_4, se3_2, se3_4, se4_3, se4_5, se4_7, se4_8 |
EVENTAREAB0 picks its stage by game.field (fields 1-8; field 8 adds
se4_8), through the constructor's jump table: the story maps.
The d files are the towns in crisis. ROOTTOWN01 (0x004215a4) takes
town01d when saveData+0x6772 - the crisis byte - is set and town01
otherwise, and keeps the stream at this+0x1a4. wat1 is loaded either
way; it holds the canal water, one plane (MDL_wat00, x ±7,800, y −8,700
to 8,100, about 100 below the streets) with 15 morph targets for its waves.
The constructor makes three ccAnms of ANM_sr1wat1_a (named by the
global wateranmname), duplicates OBJ_wat00 in each, and roots all three
at the identity (the constants at 0x005d4a90 and 0x005d4aa0 are all zeros
with w = 1). town_z holds no models: its seven Eff chunks are the lens
flare's EFF_sflenz_1-6 and the clouds' EFF_srzsmo1, each with its
texture (Dun Loireag).
The three waters are all drawn in Mac Anu and Dun Loireag: water 0 with
the frame-buffer copy behind it (the refraction), waters 1 and 2 with their
UVs scrolled, water 1 in U and water 2 in V (Dun Loireag).
ROOTTOWN01's constructor also builds the sky CMP_sr1bac1 and, in
town01d, CMP_sr1dat1_1-3 itself; DrawBG draws them at the origin:
the sky on objLayer, the three over it on WORLD_MAN's layers at +0x49c,
+0x4a0 and +0x4a4 (priorities -80, -70, -60), MAT_sr1dat1_2 scrolled in U
and MAT_sr1dat1_3 in U and V by 0.002 a frame
(crates/piney-world/src/town01.rs, CRISIS_SKY). ROOTTOWN03-05
(Carmina Gade, Fort Ouph, Lia Fail) are on their page;
their DrawMap is on the minimap page.
The tables
placement::statics finds every *MODELTABLE* and *OBJTABLE* object in
gcmn.prg: 16 model tables (172 rows) and 11 object tables. It matches
each to the DATA.BIN members holding every object it names:
| table | scenes |
|---|---|
RT_MODELTABLE00, 02-05 | town01-town05, with the d variants of 01-04 |
EA_MODELTABLE01... | se1_1, se1_2, se2_1, se2_6, se3_5_1, se1_7_1, se1_7_2, se1_5, se1_6 |
EA_MODELTABLE02 and 0202 both fit se1_2: the two blocks of area 15's
map, the holy ground and the church, which EVENTAREA02::ChangeBlock
builds in turn (area 15's story map).
Unknown
- What the first water copy's different
Duplicateflag (8200 against 8192) changes.