After the RFRM Header, the first section of the file is SKHD in SMDL, and WDHD in WMDL. Following those extra sections, all three formats start with a header.
Offset
|
Size
|
Description
|
0x0
|
24
|
"HEAD" Chunk Descriptor
|
0x18
|
4
|
Unknown
|
0x1C
|
4
|
Unknown
|
0x20
|
4
|
Unknown
|
0x24
|
4
|
Unknown
|
0x28
|
4
|
Unknown
|
0x2C
|
24
|
Axis-aligned bounding box
|
0x30
|
4
|
Extra data flag
|
If the ending flag is 1, then a large chunk of extra data follows before the next section begins; otherwise, the HEAD section ends.
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
Chunk Descriptor
|
1
|
SKHD Chunk Descriptor
|
Data type is SKHD
|
0x18
|
u32
|
1
|
Unknown
|
|
0x1C
|
End of Skinned Model Header
|
Type
|
Count
|
Name
|
Notes
|
u8
|
1
|
Unknown
|
|
Render Octree
|
1
|
Render Octree
|
|
u32
|
1
|
Unknown AABox Count
|
|
AABox
|
Unknown AABox Count
|
Unknown AABox Array
|
|
u32
|
1
|
Unknown Float Count
|
|
float
|
Unknown Float Count
|
Unknown Float Array
|
|
Render Octree
This seems to be an updated version of the AROT format seen in previous Retro games.
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
FourCC
|
1
|
Magic
|
Always AROT (Area Octree)
|
0x4
|
u32
|
1
|
Unknown
|
Always 1. Version number?
|
0x8
|
u32
|
1
|
Unknown
|
|
0xC
|
u32
|
1
|
Unknown
|
|
0x10
|
u32
|
1
|
Unknown
|
|
0x14
|
AABox
|
1
|
Octree Bounding Box
|
Bounds of the entire octree; matches the bounding box from the main model header.
|
0x2C
|
u32
|
1
|
Unknown Count A
|
|
0x30
|
u32
|
Unknown Count A
|
Unknown Array A
|
|
|
u32
|
1
|
Unknown Count B
|
|
|
u8
|
Unknown Count B
|
Unknown Array B
|
|
|
u32
|
1
|
Unknown AABox Count
|
|
|
AABox
|
Unknown AABox Count
|
Unknown AABox Array
|
|
Material Data
The MTRL section has a 32-bit material count, then lays out its materials one after the other. Materials are composed of basically a MTRL asset ID which contains the shader the material is rendered with, then per-instance material parameters (textures, scalar/color parameters, etc).
Type
|
Count
|
Name
|
Notes
|
string
|
1
|
Material Name
|
Zero-terminated string
|
Asset ID (MTRL)
|
1
|
Material Shader Asset ID
|
Points to the MTRL file containing the shader for this material.
|
FourCC
|
1
|
Material Type
|
Can be PHNG (Phong), LAMB (Lambert), SURF (Surface), FURM (Fur), or REFL (Reflect). REFL may be unused.
|
u32
|
1
|
Material Flags
|
Bitfield used to toggle various settings on the material. None of the flags are known.
|
u32
|
1
|
Parameter Count
|
Count of parameters in this material definition.
|
Material Parameter
|
Parameter Count
|
Parameter Array
|
|
Material Parameter
Each parameter has a fourCC parameter ID as well as a parameter type enum. There are five possible parameter types that each have a different layout in the file.
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
FourCC
|
1
|
Parameter ID
|
|
0x4
|
u32
|
1
|
Parameter Type
|
Determines what type of data this parameter contains. Can be either 0, 1, 2, 4, or 5. (Note: 3 is an invalid value, not an unused type.)
|
0x8
|
|
|
Parameter Data
|
Structure and size varies depending on Parameter Type. See below.
|
Type 0: Texture Token Data
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
Asset ID (TXTR)
|
1
|
Texture ID
|
Texture asset ID.
|
0x10
|
Texture Usage Info
|
1
|
Texture Usage Info
|
Note: Not present if the TXTR asset ID is invalid.
|
End of Texture Token Data
|
Type 1: Color Data
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
Color4f
|
1
|
Color Value
|
|
0x10
|
End of Color Data
|
Type 2: Scalar Data
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
float
|
1
|
Scalar Value
|
|
0x4
|
End of Scalar Data
|
Type 4: Layered Texture Data
Type 5: Int4 Data
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
u32
|
4
|
Int4 Value
|
|
0x10
|
End of Int4 Data
|
Texture Usage Info
Offset
|
Type
|
Count
|
Name
|
Notes
|
0x0
|
u32
|
1
|
Unknown
|
|
0x4
|
u32
|
1
|
Unknown
|
|
0x8
|
u32
|
1
|
Unknown
|
|
0xC
|
u32
|
1
|
Unknown
|
|
0x10
|
u32
|
1
|
Unknown
|
|
0x14
|
End of Texture Usage Info
|
Meshes
The MESH section does what the name suggests: it defines submeshes. The MESH section header is as follows:
Offset
|
Size
|
Description
|
0x0
|
24
|
MESH Chunk Descriptor
|
0x18
|
4
|
Submesh count
|
0x1C
|
End of MESH header
|
Each submesh definition is structured as follows:
Offset
|
Size
|
Description
|
0x0
|
4
|
Unknown; always 3?
|
0x4
|
2
|
Material ID
|
0x6
|
1
|
Vertex buffer ID
|
0x7
|
1
|
Index buffer ID
|
0x8
|
4
|
Start index
|
0xC
|
4
|
Index count
|
0x10
|
4
|
Unknown
|
0x14
|
1
|
Unknown; usually seems to be either 0 or 1, possibly a bool value
|
0x15
|
End of submesh definition
|
Vertex Buffers
The VBUF section defines vertex buffers; each buffer can have different vertex types, with different strides and attributes.
Offset
|
Size
|
Description
|
0x0
|
24
|
VBUF Chunk Descriptor
|
0x18
|
4
|
Vertex buffer count
|
0x1C
|
End of VBUF header
|
Vertex Buffer
Offset
|
Size
|
Description
|
0x0
|
4
|
Vertex count
|
0x4
|
4
|
Attrib count (AC)
|
0x8
|
0x14 × AC
|
Vertex attributes
|
End of vertex buffer
|
Vertex Attribute
Offset
|
Size
|
Description
|
0x0
|
4
|
Unknown
|
0x4
|
4
|
Offset
|
0x8
|
4
|
Stride
|
0xC
|
4
|
Unknown
|
0x10
|
4
|
Unknown (likely attrib type/format)
|
0x14
|
End of attribute
|
Index Buffers
Just like how the VBUF section defines vertex buffers, the IBUF section defines index buffers. Each index buffer only has one value associated with it, so it's fairly simple, and you generally will only see one or two index buffers per file.
Offset
|
Size
|
Description
|
0x0
|
24
|
IBUF Chunk Descriptor
|
0x18
|
4
|
Index buffer count
|
0x1C
|
End of IBUF header
|
Index Buffer
Offset
|
Size
|
Description
|
0x0
|
4
|
Format (1 means unsigned short; 2 means unsigned long)
|
0x4
|
End of index buffer
|
GPU Data
The GPU section contains raw buffer data that's fed to the GPU. It's essentially just a giant blob with all the vertex and index buffers laid out next to each other. The tricky part is, all the buffer data is LZSS-compressed, and the metadata needed to decompress it is stored in the pak rather than in the files themselves; not only that, but that metadata is also the only way to distinguish the different buffers from each other.
As such, this section can't be read correctly if the model file is unpacked and completely left as-is; it needs to be either read directly from the pak, or the metadata needs to be added to the file in some way. A good unpacker should append the metadata to the end of the file; a pre-decompressed file needs the buffer sizes or offsets inserted into the file data somewhere.
The pak metadata for the model formats contains mainly information related to the size and layout of the GPU section, and the metadata required to locate and decompress specific buffers within it.
Offset
|
Size
|
Description
|
0x0
|
4
|
Unknown; always 4?
|
0x4
|
4
|
GPU section offset
|
0x8
|
4
|
GPU chunk count (CC)
|
0xC
|
8 × CC
|
GPU chunk definitions
|
-
|
4
|
Compressed vertex buffer count (VC)
|
-
|
0x10 × VC
|
Vertex buffer definitions
|
-
|
4
|
Compressed index buffer count (IC)
|
-
|
0x10 × IC
|
Index buffer definitions
|
End of pak metadata
|
GPU Chunk
For large models, the GPU section might be split up into multiple chunks, rather than read as one data buffer; all offsets into the GPU section will be relative to the start of the chosen chunk.
Offset
|
Size
|
Description
|
0x0
|
4
|
Size
|
0x4
|
4
|
Offset
|
0x8
|
End of GPU chunk definition
|
Compressed Buffer
The format for compressed buffer definitions is the same regardless of buffer type (vertex/index).
Offset
|
Size
|
Description
|
0x0
|
4
|
GPU chunk index
|
0x4
|
4
|
Start offset (relative to the start of the chosen GPU chunk)
|
0x8
|
4
|
Compressed size
|
0xC
|
4
|
Decompressed size
|
0x10
|
End of compressed buffer definition
|