Reference ยท Formats
DBnnMOD.BIN, a database's models
Covers6
US /DATA/DB22/DB22MOD.BINUS SLUS_006.50:0x80044b74US SLUS_006.50:0x80044d00US SLUS_006.50:0x80044c98US SLUS_006.50:0x80010000US SLUS_006.50:0x80031b84A database's models (DB22: 215): character parts, props, furniture.
Loaded by load_models(db) (0x80044d00, file 242 + db), drawn by the
hand-written model renderer (0x80010000) through an object's draw
(0x80031b84 and others).
Layout
Little-endian.
u32 0xc0de0001
u16 count, u16 pad
u32 at[count] low 21 bits: offset from the table's end;
high 11: the model's id, ascending; 0xffffffff: none
model
+0x00 u32 link
+0x04 u32 unknown_04 the loader writes the index here
+0x08 u16 radius the culling test's (0x80031834)
+0x0a u16 unknown_0a
+0x0c u32 bounds_at 16 bytes (s16 x, y, z, pad twice)
+0x10 u16 vertices
+0x12 u16 colours
+0x14 u32 vertices_at s16 x, y, z, w each
+0x18 u32 colours_at r, g, b, pad each (none when colours is 0)
+0x1c u32 faces_at
faces: sections u16 kind, u16 count, records
0x20 F3 0x28 F4 u32 flags, u8 v[4], u8 r, g, b, code 12 bytes
0x30 G3 0x38 G4 u32 flags, u8 v[4], u8 colour index[4] 12 bytes
0x24 FT3 0x2c FT4 u32 flags, u8 v[4], u8 r, g, b, pad,
0x34 GT3 0x3c GT4 u8 u0, v0, u16 clut, u8 u1, v1, u16 tpage,
u8 u2, v2, u3, v3 24 bytes
0xff the end
The loader (0x80044c98) turns the four offsets into pointers and writes
the index at +0x04. Everything else names a model by id, not by table
position: model(id) (0x80044b74) binary-searches the table's high 11
bits. Hierarchy parts (through 0x80044e7c) and templates use it. Ids and
positions agree in DB22 only up to 78 (position 79 holds id 102).
The search's upper bound starts at the count, not the count less one, and
it ends by looking at its last two candidates; an id it misses gives
offset 0, the first model stored. Models::get follows it and is checked
against the original for every id 0-2047 of every MOD file. DB22's LP
names models 519, 761, 818, 819 and 905, which only other databases have;
those objects get offset 0 and the class-0 constructor hides them (see
lp). The face kinds are the GPU's primitive codes, which the
renderer switches on.
Measured
All 6286 models in the 31 readable MOD files parse to their last byte with these sizes (DB08MOD.BIN has no 0xc0de0001). Faces by kind: G3 95689, FT3 72490, F3 38346, G4 7123, FT4 6199, GT3 5220, F4 1594, GT4 231.
Drawing
An object's model is at object +0x88; draw_object (0x80031b84) sets the
GTE to its transform (0x8001eb4c), tests the model's radius, and calls the
renderer with the depth buckets (0x800ce238) and the context at 0x800de3b0;
the projected vertices go to the scratchpad when the model has fewer than
126, to a buffer otherwise. Character textures are in CHARACTR.RAW,
which main loads to VRAM (576, 256), 384 x 256, beside the database's A.RAW.
The renderer (0x80010000, hand-written) builds each packet's code from
the face kind, ORs in (flags & 0x80) << 18 (bit 7 makes the face
semi-transparent) and the word at context +0x48, and ORs the word at
+0x4c into the tpage word. An untextured semi-transparent face is
preceded by a draw mode (0x800106c0), E1 0x200 | (flags & 0x60), whose
blend is the flags' bits 5-6. A textured one blends by its page. The
opening's lens splash (model 1039, flags 0x80) is the case seen.
The face test (0x80010174 and kin):
- A face whose three projected vertices share an outside flag (the AND of their words, bits 16-20) is dropped.
- Flags bits 8-9 pick the depth that sorts it into the ordering table: neither, the average (AVSZ3, kept under 16000); bit 8, the farthest vertex; bit 9 alone, the nearest. The depth is then shifted right 2.
- Flag bit 0 skips the back-face test (NCLIP), so the face shows from both sides. The opening's milk spray (model 953) and hair strands use it.
Unknown
- The vertex's fourth halfword, the bounds block,
unknown_0a, and the face flags' other bits. - How GT faces' colours and the lighting combine (the renderer was not read past the vertex pass).