BMD and BDL

From CloudModding TWW Wiki
Jump to: navigation, search

BMD and BDL are the two formats that store model data in Nintendo games for the GameCube and the Wii. It first appeared in Luigi's Mansion, where it was used only for effects and jewels. BMD was then used as the only model format in Super Mario Sunshine, and The Wind Waker introduced the BDL format. The most recent game to use this model format is probably Super Mario Galaxy 2.

BMD and BDL are almost entirely the same. BDL is an extension of BMD with an additional section for material FIFO instructions called MDL3. MDL3 is likely used for making rendering more efficient.

Standard Padding String

All J3D formats, including models and animations, use a standard string for padding data to the nearest 8 or 32 bytes. The most complete copy of this string is shown below.

This is padding data to alig

File Header

The header contains basic data about the model, including its type, the size of the file, and the section count.

//0x20/32 bytes long
/*0x00*/ char[4] Magic; // 'J3D2'
/*0x04*/ char[4] ModelType; // 'bmd3' for BMD, 'bdl4' for BDL
/*0x08*/ int FileSize;
/*0x0C*/ int ChunkCount; // 8 for BMD, 9 for BDL
/*0x10*/ char[4] Svr3Magic; // 'SVR3'
// From 0x14 to 0x20 is an array of padding bytes with the value 0xFF/-1.

The model format contains an extra chunk in the header called SVR3. The purpose of this chunk is unknown, since it is filled with 0xFF/-1 bytes. SVR1, possibly an earlier version of this chunk, is sometimes found in the animation formats.

Scenegraph (INF1)

The scenegraph is a flattened hierarchy of joints, materials, and geometry data. It is used to determine the joint hierarchy, as well as the order in which to render the different parts of the geometry. It consists of a header followed by the hierarchy data.

Header

The header contains the size of the chunk, the number of geometry groups, and the number of vertexes in the mesh.

// 0x18/24 bytes long
/*0x00*/ char[4] Magic; // 'INF1'
/*0x04*/ int Size; // Size of the chunk
/*0x06*/ short Unknown1;
/*0x08*/ short Padding; // 0xFFFF/-1
/*0x0C*/ int PacketCount;
/*0x10*/ int VertexCount; //Number of vertexes in VTX1 section
/*0x14*/ int HierarchyDataOffset; //Offset from start of INF1 Chunk

Hierarchy Data

The hierarchy is made up of nodes that give the node type and an index for the associated data, if necessary. A node looks like this:

// 0x4/4 bytes long
/*0x00*/ HierarchyDataTypes Type //See Hierarchy Node Types below
/*0x02*/ short Index //Index into Joint, Material, or Shape/Batch table.

The INF1 chunk is padded to the nearest 8 bytes by the standard padding string after the last node, which has a node type of 0x00.

Hierarchy Node Types

There are 6 node types - 3 for manipulating the hierarchy (Finish, New Node, and End Node) and 3 for actual model data (Joint, Material, Shape/Batch).

Type Name Meaning
0x00 Finish Ends the hierarchy
0x01 New Node Creates a child of the previous node
0x02 End Node Closes the current child node and returns to the parent node
0x10 Joint Adds a joint to the hierarchy
0x11 Material Adds a material to the hierarchy
0x12 Shape/Batch Adds geometry data to the hierarchy

Vertex Attributes (VTX1)

This chunk defines vertexes and the attributes associated with them. A vertex always includes position data, but it may also include UVs for texturing, normals for lighting, or vertex colors. All of this data is stored here.

The chunk has a header, which is followed by the definitions of each vertex attribute that is defined within the chunk. After these definitions are banks holding the data for each attribute.

Header

// 0x40/64 bytes long
/*0x00*/ char[4] Magic; // 'VTX1'
/*0x04*/ int Size; //Total bytes of chunk
/*0x08*/ int VertexFormatOffset; //Offset to VertexFormats from VTX1 chunk start.
/*0x0C*/ int[13] VertexDataOffsets; //13 offsets to Vertex data. 0 if no data. Relative to VTX1Header start.

Vertex Attributes

Each vertex attribute gives its type, a component count, and a data type. It may also include a decimal point value to use for compressed data types.

// 0x10/16 bytes long
/*0x00*/ int AttributeType; //Defines what type of attribute this is
/*0x04*/ int ComponentCount; //Meaning depends on DataType (see gx.h: "CompCount")
/*0x08*/ int DataType; //What type of data is stored
/*0x0C*/ byte DecimalPoint; //Number of mantissa bits for fixed point numbers (position of decimal point)
/*0x0D*/ byte[3] Padding; // All 3 are 0xFF/-1

This area of the chunk is padded to the nearest 32 bytes with the padding string. For example, if there are only 3 attributes in the list, there are 16 bytes of the padding string after the last attribute, filling the space where a 4th attribute would go.

Attribute Types

Type Name Meaning
0x00 Position Matrix  ?
0x01 Tex Matrix 0  ?
0x02 Tex Matrix 1  ?
0x03 Tex Matrix 2  ?
0x04 Tex Matrix 3  ?
0x05 Tex Matrix 4  ?
0x06 Tex Matrix 5  ?
0x07 Tex Matrix 6  ?
0x08 Tex Matrix 7  ?
0x09 Position Position of the vertex in space
0x0A Normal Normal for the vertex used for lighting calculations
0x0B Color 0 Vertex color for color slot 0
0x0C Color 1 Vertex color for color slot 1
0x0D Tex 0 UV coordinates for texture 0
0x0E Tex 1 UV coordinates for texture 1
0x0F Tex 2 UV coordinates for texture 2
0x10 Tex 3 UV coordinates for texture 3
0x11 Tex 4 UV coordinates for texture 4
0x12 Tex 5 UV coordinates for texture 5
0x13 Tex 6 UV coordinates for texture 6
0x14 Tex 7 UV coordinates for texture 7
0x15 Position Matrix Array  ?
0x16 Normal Matrix Array  ?
0x17 Texture Matrix Array  ?
0x18 Light Matrix Array  ?
0x19 Normal/Binormal/Tangent  ?
0x1A Max Attribute  ?
0xFF Null Attribute Terminate the attribute list. There are no more attributes.

Data Types

There are two versions of the list of data types. The first version is for primitive data types such as bytes and shorts, while the other version is for how vertex colors are stored. Thus, the attributes Color 0 and Color 1 use a value from the Colors data type table, while everything else uses the Primitives table.

Primitives:

Type Name
0x00 Unsigned Byte
0x01 Signed Byte
0x02 Unsigned Short (int16)
0x03 Signed Short (int16)
0x04 Float (single)

Colors:

Type Name
0x00 RGB565
0x01 RGB8
0x02 RGBX8
0x03 RGBA4
0x04 RGBA6
0x05 RGBA8

Data Banks

The last portion of this chunk is made up of the data banks holding the data for the vertex attributes. Each bank is located at the corresponding offset in the chunk's header, and is stored in the data type specified in the vertex attribute definition. Each data bank is aligned to the nearest 8 bytes with the standard padding string.

Skinning Envelopes (EVP1)

This chunk defines data for weighted skinning, allowing multiple bones to move one set of geometry data. It is heavily reliant on multiple layers of indexes, which makes it complex and hard to follow.

It is made up of a header followed by an array of bytes that indicate the number of bones that influence a particular packet of geometry. After this is the index data array, which identifies those bones by their indexes. The influence that each bone has on the packet of geometry is scaled by a weight, and these weights are stored as floats in a bank that follows the index data array. Finally, each bone has a 3x4 inverse bind matrix, which transforms the vertexes from the bind pose to where they would be if their bones were positioned at (0,0,0).

Header

// 0x1C/28 bytes long
/*0x00*/ char[4] Magic; // 'EVP1'
/*0x04*/ int Size;
/*0x08*/ short IndexCount;
/*0x0A*/ short Padding; // 0xFFFF/-1
/*0x0C*/ int IndexCountOffset;
/*0x10*/ int IndexDataOffset;
/*0x14*/ int WeightOffset;
/*0x18*/ int InverseMatrixOffset;

Index Count Array

This gives the number of bones that influence a particular packet of geometry data. In order to get the correct count for the desired packet, you must use the index obtained from the weight check chunk (DRW1) to access this array.

// 1 byte long
/*0x00*/ byte BoneCount; 

Index Data Array

The next step in getting the weights for a packet of geometry data is figuring out which bones interact with the packet. This is defined in this section of the chunk.

This is one of the most confusing parts. The index of the first relevant bone ID in this array isn't stored anywhere. In order to get the index of this ID, we must add up all of the bone counts in the Index Count Array above up to the count for the packet that we are looking up, and then divide that sum by 2. The result is the index of the first bone ID in the Index Data Array for the packet.

We divide the sum by 2 because the bone IDs are stored as shorts (int16). The sum is the total number of bone IDs in the array up to the first ID that we need; dividing by 2, the size of a short, gives us the index in the array of the ID that we need.

Weights

These weights are used to scale the influence of each bone that affects the packet of geometry data. The weights of each bone should add up to a sum of 1; otherwise, the vertexes do not move with the bones correctly.

The index of the first weight to use for the packet is given by the index of the bone IDs in the Index Data Array above. For example, if the indexes for the bone IDs in the Index Data Array are 3 and 4, that means that the packet of geometry data uses weights 3 and 4, as well.

// 4 bytes long
/*0x00*/ float Weight;

Inverse Bind Matrices

This is the easiest part of the skinning process. It is simply a 3x4 matrix that is used to transform each vertex from the binding pose to a coordinate space where the bone is at (0,0,0). The indexes of the matrices to use are simply the bone IDs obtained from the Index Data Array.

The matrices are stored as an array of floats.

// 0x30/48 bytes long
// To-do: figure out row/column layout of matrices

Weight Check Data (DRW1)

This chunk determines if a packet of geometry data needs to grab skinning data from the envelope chunk (EVP1), or if the packet just moves 1:1 with a single bone. It is made up of a header, followed by the partial weight array and the index array.

Header

// 0x14/20 bytes long
/*0x00*/ char[4] Magic; // 'DRW1'
/*0x04*/ int Size;
/*0x08*/ short ElementCount;
/*0x0A*/ short Padding;
/*0x0C*/ int PartialWeightArrayOffset;
/*0x10*/ int IndexArrayOffset;

Partial Weight Array

This is an array of boolean values, which the packet indexes into based on its position matrix index.

// 1 byte long
/*0x00*/ bool IsPartiallyWeighted;

If the bool is false, that means that the packet moves 1:1 with a single bone without being weighted. The bone to use is indicated by the bone ID found in the Index Array at the same index as the bool - that is, the position matrix index of the packet.

If the bool is true, that means that the packet has weighted skinning data stored in the envelope chunk (EVP1). The index of the packet's bone count in EVP1's Index Count Array is indicated by the index in the Index Array at the same index as the bool - that is, the position matrix index of the packet.

Index Array

// 2 bytes long
/*0x00*/ short Index;

For every bool in the Partial Weight Array that is false, there is the ID of a bone to use for the packet's movement.

For every bool in the Partial Weight Array that is true, there is an index to a count in EVP1's Index Count Array.

Joint Data (JNT1)

This chunk defines joint data, including position, scale, rotation, and names. It has a header followed by the joint data and a string table.

Header

// 0x18/24 bytes long
/*0x00*/ char[4] Magic; //'JNT1'
/*0x04*/ int Size; //Total bytes of chunk
/*0x08*/ short SectionCount; //How many joints there are
/*0x0A*/ short Padding;
/*0x0C*/ int JointEntryOffset; //Relative to JNT1Header start
/*0x10*/ int StringIdTable; //There are SectionCount ushorts at this point.
/*0x14*/ int StringTableOffset; //Names of Joints

Joint Data

This is the actual joint data. It includes scaling, rotation, and translation data for the joint, as well as a bounding sphere radius and bounding box information.

// 0x40/64 bytes long
/*0x00*/ short Unknown1; //Always 0, 1 or 2
/*0x02*/ short Padding; //0x00FF in Mario, not always in Zelda
/*0x04*/ float ScaleX;
/*0x08*/ float ScaleY;
/*0x0C*/ float ScaleZ;
/*0x10*/ short RotationX; //-32768 = -180 deg, 32767 = 180 deg. float degrees = ((float)rotShort * 180.0f) / 32767.0f;
/*0x12*/ short RotationY;
/*0x14*/ short RotationZ;
/*0x16*/ short Padding;
/*0x18*/ float TranslationX;
/*0x1C*/ float TranslationY;
/*0x20*/ float TranslationZ;
/*0x24*/ float BoundingSphereRadius;
/*0x28*/ float BBoxMinX;
/*0x2C*/ float BBoxMinY;
/*0x30*/ float BBoxMinZ;
/*0x34*/ float BBoxMaxX;
/*0x38*/ float BBoxMaxY;
/*0x3C*/ float BBoxMaxZ;

String Table

To-do

Geometry Data (SHP1)

SHP1 stores the geometry data for the model. The data is split into "batches", with each batch having multiple "packets." Each batch can have different vertex attributes active, which translates into the actual geometry data differing in vertex structure between batches.

The chunk begins with a header. This contains counts and offsets to each section of the data. After this is the batch data, defining batches with a bounding sphere radius, a bounding box, and an offset to the attributes that the batch uses. An index table, the attribute table, the matrix table, the geometry data, the matrix data, and the packet location data follow.

Header

// 0x2C/44 bytes long
/*0x00*/ int char[4] Magic; // 'SHP1'
/*0x04*/ int ChunkSize; // Total bytes of chunk
/*0x08*/ short SectionCount; // How many batches there are
/*0x0A*/ short Padding; // 0xFFFF/-1
/*0x0C*/ int BatchDataOffset; // Offset to Batch's  (Relative to SHP1Header start)
/*0x10*/ int IndexTableOffset; // Offset into IndexTable... seen in other things here too.
/*0x14*/ int Unknown1; // Seems to usually be zero
/*0x18*/ int BatchAttribsOffset; // Offset to BatchAttribs
/*0x1C*/ int MatrixTableOffset; // Offset to MatrixTable
/*0x20*/ int PacketDataOffset; // Offset to the actual primitive data
/*0x24*/ int MatrixDataOffset; // Offset to MatrixData
/*0x28*/ int PacketLocationOffset;

Batch Data

Batches define sets of packets. A batch defines a bounding box and a bounding sphere. It also determines how many packets it contains, and what set of vertex attributes are enabled for the packets.

// 0x28/40 bytes long
/*0x00*/ short Unknown;
/*0x02*/ short PacketCount; // How many packets to this Batch
/*0x04*/ short AttributesOffset; // Relative to SHP1Header.BatchAttribsOffset
/*0x06*/ short MatrixDataOffset; // Index to 'PacketCount' consecutive indexes
/*0x08*/ short PacketDataOffset; // Index to first packet ('PacketCount' consecutive Indexes)
/*0x0A*/ short Padding;
/*0x0C*/ float BoundingSphereRadius;
/*0x10*/ float BBoxMinX;
/*0x14*/ float BBoxMinY;
/*0x18*/ float BBoxMinZ;
/*0x1C*/ float BBoxMaxX;
/*0x20*/ float BBoxMaxY;
/*0x24*/ float BBoxMaxZ;

The AttributesOffset variable is the offset to the first vertex attribute to enable for the batch. After this first attribute is enabled, the next is enabled, and so on, until an attribute with the type 0xFF (null attribute) is encountered.

Index Table

This is an array of shorts that counts up from 0 to the number of batches - 1. Its purpose is currently unknown. It's padded to the nearest 32 bytes with the standard padding string.

Vertex Attributes

This is a list of the vertex attributes that are enabled for each batch. They are stored similarly to the attributes in the VTX1 chunk, but they consist of only the attribute type and the data type. This data type refers to the type of the index into the VTX1 data banks, and not the type of the data itself. Because of this, the data type for these attributes is typically a signed short (0x03).

// 8 bytes long
/*0x00*/ int AttributeType;
/*0x04*/ int DataType;

For information on what values AttributeType and DataType can be, see Attribyte Types and Data Types in the VTX1 section.

Matrix Table

This section stores indexes that are used to access the Partial Weight Array in the DRW1 chunk. A vertex accesses this table using the value that it has for the position matrix vertex attribute, if it has one.

// 2 bytes long
/*0x00*/ short PartialWeightArrayIndex;

This section has an oddity. If a batch contains more than one packet, the index referenced by a vertex's position matrix index may end up being 0xFFFF/-1. If this is the case, then that means that the position matrix index must be walked back through the table to find the first value that isn't 0xFFFF/-1. In other words, if the value in the matrix table is -1, that means that the last valid index must be used.

Packet Data

This is the actual geometry data. Each packet has a primitive type, a vertex count, and then the vertex data.

// Header is 3 bytes, vertex data varies in length
/*0x00*/ byte PrimitiveType;
/*0x01*/ short VertexCount;

Each vertex consists of an index corresponding to the active vertex attributes. For example, if a batch has the position, color 1, and tex 1 attributes active, one vertex would have an index into the position data bank, the color 1 data bank, and the tex 1 data bank.

Primitives are padded to the nearest 8 bytes with zero-value bytes.

Primitive Types

Below are the primitive types supported by the GameCube's GPU. Note that although some of them exist, they may not be used in practice. It appears that BMD and BDL most often use Triangle Strips, and rarely Triangle Fans.

Type Name
0x80 Quads
0x90 Triangles
0x98 Triangle Strips
0xA0 Triangle Fans
0xA8 Lines
0xB0 Line Strips
0xB8 Points

Matrix Data

Not much is known about this section. It needs to be investigated more.

// 8 bytes long
/*0x00*/ short Unknown;
/*0x02*/ short Count; // `Count` many consecutive indexes into MatrixTable
/*0x04*/ int Indexoffset; // Relative to ??

Packet Location Data

This gives the size and location of every packet in the model.

// 4 bytes long
/*0x00*/ int Size; //Size in bytes of the packet 
/*0x04*/ int Offset; //Offset relative to `SHP1Header.PacketDataOffset`

Note that the offset given by the location data is relative to the start of the packet data - that is, the value of PacketDataOffset in the SHP1's header.

Material Data (MAT3)

To-do

FIFO Data (MDL3)

MDL3 is only found in the BDL format, and contains FIFO instructions. While the exact purpose of this chunk isn't known, it is assumed that it's used to speed up rendering by offering pre-compiled material data to feed to the GameCube's GPU.

It begins with a header, which is followed by a listing of the offset and size of each packet of FIFO instructions. After this is the instruction data itself, and then a set of offsets that identify blocks of instructions within the packets. It ends with a string table that gives a name to each packet of instructions. This name typically matches the name of a material found in MAT3.

Header

// 0x24/36 bytes long
/*0x00*/ char[4] Magic; // 'MDL3'
/*0x04*/ int Size;
/*0x08*/ short EntryCount;
/*0x0A*/ short Padding; // 0xFFFF/-1
/*0x0C*/ int PacketOffset; // Packet Location Data
/*0x10*/ int SubPacketLocationOffset; // Sub-packet Location Offset
/*0x14*/ int MatrixIndexOffset; // Matrix Index Offset
/*0x18*/ int Unknown0Offset; // Unknown0 Offset
/*0x1C*/ int IndexesOffset; 
/*0x20*/ int StringTableOffset; //See JNT1

The header is padded to the nearest 32 bytes with the standard padding string.

Packet Listing

This gives the size and offset of a packet of FIFO instructions. The offset is relative to the start of the packet's entry in the listing, rather than the start of the listing itself or the start of the MDL3 chunk.

// 4 bytes long
/*0x00*/ int Offset;
/*0x04*/ int Size;

The listing is padded to the nearest 32 bytes with the standard padding string.

Packet Data

This is a set of FIFO instructions that affect specific areas of the GameCube's FIFO system. Each packet is split into sub-packets based on the area that the instructions at that offset in the packet work on. The offsets to these sub-packets are stored in the Sub-Packet Location Data, defined below.

There are two kinds of FIFO instructions found in a packet: BP and XF. They can be differentiated by their first byte, which is an opcode as interpreted by the GameCube. This opcode is 0x61 for BP commands, and 0x10 for XF commands.

BP Command:

// 5 bytes long
/*0x00*/ byte OpcodeID; // 0x61 for BP commands
/*0x01*/ byte RegisterAddress; // The address of the register to modify
/*0x02*/ byte RegisterValue1;
/*0x03*/ byte RegisterValue2; // RegisterValue1/2/3 are really part of 1, 24-bit value
/*0x04*/ byte RegisterValue3;

The 3 RegisterValue variables are meant to be read together as a single 24-bit value, and this value is what is placed into the register specified by RegisterAddress. What effect this value has on the GPU is determined by the address of the register that is modified.

XF Command:

// Header is 5 bytes long; data is variable length
/*0x00*/ byte OpcodeID; // 0x10 for XF commands
/*0x01*/ short DataLengthMultiplierMinus1;
/*0x03*/ short RegisterAddress;
/*0x05*/ byte[(DataLengthMultiplierMinus1 + 1) * 4] Data;

For whatever reason, the length of the data that the command uses isn't stored; instead, it stores a multiplier that must be multiplied by 4 to get the actual data length. To make this even more odd, DataLengthMultiplierMinus1 must have 1 added to it before it can be used, as shown in the array definition for the Data variable.

It is currently unknown how the data stored in the command is used, but the effect that it has on the GameCube's GPU is based on the RegisterAddress that the command gives.

Sub-Packet Location Data

This needs to be investigated.

This gives the offsets within a packet of blocks of instructions that affect specific parts of the material that this packet belongs to. Exactly what these blocks do is not yet known, but we do currently have a general understanding of what they affect, as shown in the layout below.

// 0x10/16 bytes long
/*0x00*/ short ChannelColorOffset;
/*0x02*/ short ChannelControlOffset;
/*0x04*/ short TextureGenOffset;
/*0x06*/ short TextureOffset;
/*0x08*/ short TevOffset;
/*0x0A*/ short PixelOffset;
/*0x0C*/ int Padding;

Unknown Section 2 ("Matrix Index Offset")

This needs to be investigated.

It appears to consist of at least a float and an int. However, the float is typically very small, casting doubt on the idea that it is a valid float.

// 8 bytes long
/*0x00*/ float MaybeFloat;
/*0x04*/ int MaybeInt;

The "default" value appears to be:

3C F3 CF 00 00 F3 CF 3C

This value is found in the majority of files, sometimes alongside other values.

Unknown Section 3

This needs to be investigated.

It is an array of bytes, padded to the nearest 8 with the standard padding string.

The byte seems to match the value of the Flag at 0x00 of the material that the packet is associated with - either a value of 1 or 4. What this means is currently unknown.

String Table

To-do

Texture Data (TEX1)

This chunk contains the images used for textures in materials. It is made up of a header and embedded BTI images.

Header

// 0x14/20 bytes long
/*0x00*/ char[4] Magic; // 'TEX1'
/*0x04*/ int Size;
/*0x08*/ short TextureCount; // Number of textures
/*0x0A*/ short Padding; // Usually 0xFFFF/-1
/*0x0C*/ int TextureHeaderOffset; // TextureCount bti image headers are stored here. Relative to TEX1Header start.
/*0x10*/ int StringTableOffset; // Stores one filename for each texture. Relative to TEX1Header start.

Embedded BTI Images

These are the actual textures. Information about embedded images can be found in the article about the BTI format.

String Table

To-do