BMD/BDL (File Format): Difference between revisions

From Luma's Workshop
Jump to navigation Jump to search
m (Add section headers)
(→‎Index Buffer Formats: Note about the matrix types)
 
(20 intermediate revisions by the same user not shown)
Line 31: Line 31:
|}
|}


== Information (INF1) ==
== INF1 - Scene Information ==
The '''Inf'''ormation section hosts a hierarchy of Joints, Materials, and Shapes, which are used to render the model.
The '''Inf'''ormation section hosts a hierarchy of Joints, Materials, and Shapes, which are used to render the model.
{| class="wikitable"
{| class="wikitable"
Line 45: Line 45:
| 0x0A || Int16 || Padding (0xFFFF)
| 0x0A || Int16 || Padding (0xFFFF)
|-
|-
| 0x0C || Int32 || Matrix Group Count
| 0x0C || Int32 || Matrix Group Data Count<br/>Referring to the Matrix Group Data in [[#SHP1_-_Shape_Information|SHP1]]<br/><small>Stored in a variable by the game, but not used to dictate the actual number of Matrix Groups.</small>
|-
|-
| 0x10 || Int32 || Vertex Count
| 0x10 || Int32 || Vertex Count<br/>Always equals the number of entries in the [[#VTX1_-_Vertex_Data|VTX1]] "POSITION" [[#Vertex%20Buffer%20Formats|data buffer]]<br/><small>Stored in a variable by the game, but never used for anything. The game reads Vertex Data directly from the [[#Vertex%20Buffer%20Formats|data buffer]]s without bounds checking.</small>
|-
| 0x14 || Int32 || Relative offset to the [[#Scene%20Hierarchy|Scene Hierarchy]]
|}
|}


Line 95: Line 97:
> ''Note: Changing the load flags by changing the code doesn't seem to do much.''
> ''Note: Changing the load flags by changing the code doesn't seem to do much.''


== VTX1 ==
=== Scene Hierarchy ===
Each model is constructed using a Scene Hierarchy. This simply determines the order of bones (in turn, defining the parent/child relations), material assignments, and Shape assignments.
 
Each node consists of the following:
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || UInt16 || Node Type.<br/>0x00 = Marks the end of the node list<br/>0x01 = Creates a new child of the previous node<br/>0x02 = Finishes the child node and returns ownership to the previous node<br/>0x10 = Joint Assignment node. "Data" holds the Joint ID (index into JNT1)<br/>0x11 = Material assignment. "Data" holds the Material ID (index into MAT3)<br/>0x12 = Shape Assignment. "Data" holds the Shape ID (index into SHP1)
|-
| 0x02 || UInt16 || A Data value. Used by some nodes to index into other chunks. Usage depends on the node type.
|}
 
The node list is padded to the nearest 32.
 
 
== VTX1 - Vertex Data ==
The '''V'''er'''t'''e'''x''' Data section contains the actual number values used for the properties of the geometry. It also includes the information on how the values are formatted.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || String || Always '''VTX1''' (ASCII)
|-
| 0x04 || Int32 || The total size of this chunk
|-
| 0x08 || Int32 || Buffer Format list offset
|-
| 0x0C || Int32 || "POSITION" data buffer offset<br/>0 if not used.
|-
| 0x10 || Int32 || "NORMAL" data buffer offset<br/>0 if not used.
|-
| 0x14 || Int32 || "TANGENT" data buffer offset<br/>0 if not used.
|-
| 0x18 || Int32 || "COLOR_0" data buffer offset<br/>0 if not used.
|-
| 0x1C || Int32 || "COLOR_1" data buffer offset<br/>0 if not used.
|-
| 0x20 || Int32 || "TEXCOORD_0" data buffer offset<br/>0 if not used.
|-
| 0x24 || Int32 || "TEXCOORD_1" data buffer offset<br/>0 if not used.
|-
| 0x28 || Int32 || "TEXCOORD_2" data buffer offset<br/>0 if not used.
|-
| 0x2C || Int32 || "TEXCOORD_3" data buffer offset<br/>0 if not used.
|-
| 0x30 || Int32 || "TEXCOORD_4" data buffer offset<br/>0 if not used.
|-
| 0x34 || Int32 || "TEXCOORD_5" data buffer offset<br/>0 if not used.
|-
| 0x38 || Int32 || "TEXCOORD_6" data buffer offset<br/>0 if not used.
|-
| 0x3C || Int32 || "TEXCOORD_7" data buffer offset<br/>0 if not used.
|}
 
=== Vertex Buffer Formats ===
Each of the Buffers in this section have a format descriptor. This allows different types of data storage, allowing for smaller files.
 
Each format descriptor contains an Attribute Target, a Component Count, a Data Type, and a Mantissa shifter (to allow floats to be stored as smaller datatypes compared to FLOAT).<br/>Only one descriptor can exist for each attribute.
 
The Attribute Target tells the game what this buffer is used for.
{| class="wikitable"
|+ Attribute Targets
|-
! Value !! Name !! Description
|-
| 0x00000009 || POSITION || This buffer represents the positions of vertices in the model. Basically required for all visual models.
|-
| 0x0000000A || NORMAL || This buffer represents vertex normals, used for the engine's vertex shading. Not needed if no material requires it.
|-
| 0x0000000B || COLOR_0 || This buffer is available for Vertex Colors.
|-
| 0x0000000C || COLOR_1 || This buffer is available for Vertex Colors.
|-
| 0x0000000D || TEXCOORD_0 || This buffer is available for Texture Coordinates.
|-
| 0x0000000E || TEXCOORD_1 || This buffer is available for Texture Coordinates.
|-
| 0x0000000F || TEXCOORD_2 || This buffer is available for Texture Coordinates.
|-
| 0x00000010 || TEXCOORD_3 || This buffer is available for Texture Coordinates.
|-
| 0x00000011 || TEXCOORD_4 || This buffer is available for Texture Coordinates.
|-
| 0x00000012 || TEXCOORD_5 || This buffer is available for Texture Coordinates.
|-
| 0x00000013 || TEXCOORD_6 || This buffer is available for Texture Coordinates.
|-
| 0x00000014 || TEXCOORD_7 || This buffer is available for Texture Coordinates.
|-
| 0x00000019 || TANGENT || ''Currently unknown exactly what goes in here.''
|-
| 0x000000FF || List End || A buffer using this target will end the descriptor list.
|}
 
The component count tells the game how many parts of the component that there are. Note that the values are considered based on the attribute target they're assigned to.
{| class="wikitable"
|+ Component Count
|-
! Value !! Name !! Description
|-
| 0x00000000 || POSITION_XY || ''Unknown''
|-
| 0x00000001 || POSITION_XYZ || Represents a position in 3D space with 3 values: X, Y, and Z.
|-
|colspan="3"|
|-
| 0x00000000 || NORMAL_XYZ || Represents a normal vector in 3D space with 3 values: X, Y, and Z.
|-
| 0x00000001 || NORMAL_NBT || ''Unknown''
|-
| 0x00000002 || NORMAL_NBT3 || ''Unknown''
|-
|colspan="3"|
|-
| 0x00000000 || COLOR_RGB || Represents a color value with only Red, Green, and Blue values.
|-
| 0x00000001 || COLOR_RGBA || Represents a color value with Red, Green, Blue, and Alpha values.
|-
|colspan="3"|
|-
| 0x00000000 || TEXCOORD_S || ''Unknown''
|-
| 0x00000001 || TEXCOORD_ST || Represents a UV texture coordinate with 2 values: X and Y.
|}
 
The Data Type tells the game how many bytes each value is, in the sense that an Int32 is 4 bytes, a Int16 is 2 bytes, a Float is 4 bytes, etc.<br/>Note that the Color values have a different set of options.
{| class="wikitable"
|+ Data Types
|-
! Value !! Name !! Description
|-
| 0x00000000 || UInt8 || 1 byte per value (0 to 255)
|-
| 0x00000001 || Int8 || 1 byte per value (-128 to 127)
|-
| 0x00000002 || UInt16 || 2 bytes per value (0 to 65535)
|-
| 0x00000003 || Int16 || 2 bytes per value (-32,768 to 32,767)
|-
| 0x00000004 || Float || 4 bytes per value
|-
|colspan="3"|
|-
| 0x00000000 || RGB565 || 2 bytes per color
|-
| 0x00000001 || RGB8 || 3 bytes per color
|-
| 0x00000002 || RGBX8 || 3 bytes per color
|-
| 0x00000003 || RGBA4 || 2 bytes per color
|-
| 0x00000004 || RGBA6 || 4 bytes per color
|-
| 0x00000005 || RGBA8 || 4 bytes per color
|}
> ''Note: Both games require colors to be 4 bytes wide at all times, so changing from RGBA8 is worthless.''
 
 
 
== EVP1 - Skinning Envelopes ==
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || String || Always '''EVP1''' (ASCII)
|-
| 0x04 || Int32 || The total size of this chunk
|-
| 0x08 || Int16 || The number of Envelopes stored.
|-
| 0x0A || Int16 || Padding (0xFFFF)
|-
| 0x0C || Int32 || Envelope Size Table offset
|-
| 0x10 || Int32 || Envelope Joint Index Table offset
|-
| 0x14 || Int32 || Envelope Weight Table offset
|-
| 0x18 || Int32 || Inverse Bind Matrix Table offset
|}
This section is padded to the nearest 32.
 
=== Envelope Size Table ===
This table simply consists of an array of UInt8, where each value dictates how many entries are in a given Envelope.
 
=== Envelope Joint Index Table ===
This table consists of the actual [[#JNT1_-_Joint_Hierarchy|JNT1]] index values. Each value is a UInt16, and are ordered directly based on the Envelope Size Table. (The first Envelope's values come directly after each other, then the second envelope's values, etc.)
 
=== Envelope Weight Table ===
This table consists of joint weighting values which determine how much of an effect the given Joint Index has on this envelope. Each value is a Float, and are ordered directly based on the Envelope Size Table. (The first Envelope's values come directly after each other, then the second envelope's values, etc.)
 
This table ends with padding to the nearest 4th byte so the Floats that come after are aligned correctly.
 
=== Inverse Bind Matrix Table ===
This table contains Inverse Bind Matrices for each joint in [[#JNT1_-_Joint_Hierarchy|JNT1]]. The EVP1 section itself contains no size of this table, but the number of Inverse Bind Matrices is always equal to the amount of Joints in the model.<br/>Each entry is a 3 Row 4 Column Matrix (Mtx34), and is stored as 3 Vector4 values.
 
== DRW1 - Skinning Assignments ==
This section contains a map which redirects skinning information to the correct location: either JNT1 (Single Matrix) or EVP1 (Multi-Matrix)<br/>The Destination Type list and Destination ID list must be equal in length.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || String || Always '''DRW1''' (ASCII)
|-
| 0x04 || Int32 || The total size of this chunk
|-
| 0x08 || Int16 || The number of Entries stored.
|-
| 0x0A || Int16 || Padding (0xFFFF)
|-
| 0x0C || Int32 || Destination Type list offset
|-
| 0x10 || Int32 || Destination ID list offset
|}
 
=== Destination Type List ===
This is an array of bytes that dictates the destination type. It is ordered so that all the '''Joint'''s come first, and all the '''Envelope'''s second.
{| class="wikitable"
|-
! Value !! Name !! Description
|-
| 0x00 || Joint || Redirects to a Joint within [[#JNT1_-_Joint_Hierarchy|JNT1]]
|-
| 0x01 || Envelope || Redirects to an Envelope in [[#EVP1_-_Skinning_Envelopes|EVP1]]
|}
It's worth noting that Nintendo's development tools had a bug in it where all the '''Envelope''' entries were duplicated. Some JSystem games do not care about this, but certain games try to explicitly ignore this data, and therefore require the wasteful duplicate data.
 
=== Destination ID List ===
This is an array of UInt16 that simply dictate an index into the provided section.
 
DRW1 ends with padding to the nearest 32.
 
== JNT1 - Joint Hierarchy ==
The '''J'''oi'''nt''' Hierarchy section defines the rigging skeleton of a model. There can only be one skeleton per model.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || String || Always '''JNT1''' (ASCII)
|-
| 0x04 || Int32 || The total size of this chunk
|-
| 0x08 || Int16 || The number of Joints stored.
|-
| 0x0A || Int16 || Padding (0xFFFF)
|-
| 0x0C || Int32 || Joint Data table offset
|-
| 0x10 || Int32 || Remap table offset
|-
| 0x14 || Int32 || Name table offset<br/><small>0 if not present.</small>
|}
 
=== Joint Data ===
Each joint includes positional data and a bounding box which is used by the game for determining rendering range automatically.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || Int16 || Matrix Type
|-
| 0x01 || UInt8 || Parent Scale inheritance<br/>0 = Follow parent joint's scale<br/>1 = Ignore parent joint's scale
|-
| 0x02 || UInt8 || Padding (0xFF)
|-
| 0x04 || Float || Scale X
|-
| 0x08 || Float || Scale Y
|-
| 0x0C || Float || Scale Z
|-
| 0x10 || Int16 || Rotation X
|-
| 0x12 || Int16 || Rotation Y
|-
| 0x14 || Int16 || Rotation Z
|-
| 0x16 || Int16 || Padding (0xFFFF)
|-
| 0x18 || Float || Translation X
|-
| 0x1C || Float || Translation Y
|-
| 0x20 || Float || Translation Z
|-
| 0x24 || Float || Bounding Sphere<br/>Should encapsulate all vertices that the joint affects
|-
| 0x28 || Float || Bounding Box Minimum X
|-
| 0x2C || Float || Bounding Box Minimum Y
|-
| 0x30 || Float || Bounding Box Minimum Z
|-
| 0x34 || Float || Bounding Box Maximum X
|-
| 0x38 || Float || Bounding Box Maximum Y
|-
| 0x3C || Float || Bounding Box Maximum Z
|}
Rotation is stored between -0x7FFF and 0x7FFF, which ranges -180 degrees and 180 degrees.
 
== SHP1 - Shape Information==
The '''Sh'''a'''p'''e Information section determines how to use the data in the [[#VTX1_-_Vertex_Data|VTX1]] section to create shapes.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || String || Always '''SHP1''' (ASCII)
|-
| 0x04 || Int32 || The total size of this chunk
|-
| 0x08 || Int16 || The number of Shapes stored.
|-
| 0x0A || Int16 || Padding (0xFFFF)
|-
| 0x0C || Int32 || Shape Init Data offset
|-
| 0x10 || Int32 || Remap table offset
|-
| 0x14 || Int32 || Name table offset<br/><small>0 if not present, which it usually isn't.</small>
|-
| 0x18 || Int32 || Vertex Index Attribute table offset
|-
| 0x1C || Int32 || Weight Index table offset
|-
| 0x20 || Int32 || Primitive Data offset
|-
| 0x24 || Int32 || Matrix Group Data offset (entry count must equal the entry count of the GXDisplayList group table)
|-
| 0x28 || Int32 || Matrix Group Definition table offset
|}
 
=== Shape Data ===
Each shape denotes a Matrix Calculation type, which is used for Billboarding, as well as multi-joint skinning.<br/>A shape also hosts a collection of Matrix Groups. If the geometry needs to be weighted to more than 10 [[#DRW1_-_Skinning_Assignments|DRW1]] matrices, more than one Matrix Group is needed.<br/>A single Matrix Group can have multiple Primitives in it, but these Primitives must share the same set of [[#DRW1_-_Skinning_Assignments|DRW1]] matrices.
 
<small>TODO: Figure out what happens in the event that more than 10 are needed (such as one vertex being weighted to 11 bones). Is it just straight up not allowed?</small>
 
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || UInt8 || Matrix Type
 
* 0 = Single Joint
 
* 1 = Billboard Joint
 
* 2 = Billboard Joint (Y axis only)
 
* 3 = Multiple Joints
|-
| 0x01 || UInt8 || Padding (0xFF)
|-
| 0x02 || Int16 || Matrix Group count
|-
| 0x04 || Int16 || Vertex Index Attribute offset<br/>Relative to the Vertex Index Attribute Table offset defined in SHP1
|-
| 0x06 || Int16 || Matrix Group Data index
|-
| 0x08 || Int16 || First Matrix Group Definition index
|-
| 0x0A || Int16 || Padding (0xFFFF)
|-
| 0x0C || Float || Bounding Sphere
|-
| 0x10 || Float || Bounding Box Minimum X
|-
| 0x14 || Float || Bounding Box Minimum Y
|-
| 0x18 || Float || Bounding Box Minimum Z
|-
| 0x1C || Float || Bounding Box Maximum X
|-
| 0x20 || Float || Bounding Box Maximum Y
|-
| 0x24 || Float || Bounding Box Maximum Z
|}
 
=== Vertex Index Attribute Table ===
 
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || Int32 || An [[#Index%20Buffer%20Formats|index buffer]] attribute target
|-
| 0x04 || Int32 || An [[#Index%20Buffer%20Formats|index buffer]] type
|}
 
==== Index Buffer Formats ====
Each of the Buffers in this section have a format descriptor. This allows different types of data storage, allowing for smaller files.
 
These attributes line up with either a direct value that is stored in the shape, or an index into a [[#VTX1_-_Vertex_Data|VTX1]] [[#Vertex%20Buffer%20Formats|data buffer]].<br/>Only one indexer can exist for each attribute.
 
The Attribute Target tells the game what this index buffer is used for.
{| class="wikitable"
|+ Attribute Targets
|-
! Value !! Name !! Description
|-
| 0x00000000 || POSITION_MATRIX || This is a direct list of indices into the Matrix Group's Weight collection. Required for Shapes that use Multiple Joint skinning.
|-
| 0x00000001 || TEXTURE_0_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000002 || TEXTURE_1_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000003 || TEXTURE_2_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000004 || TEXTURE_3_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000005 || TEXTURE_4_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000006 || TEXTURE_5_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000007 || TEXTURE_6_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000008 || TEXTURE_7_MATRIX || ''Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.''
|-
| 0x00000009 || POSITION || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "POSITION" buffer. Required.
|-
| 0x0000000A || NORMAL || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "NORMAL" buffer
|-
| 0x0000000B || COLOR_0 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "COLOR_0" buffer
|-
| 0x0000000C || COLOR_1 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "COLOR_1" buffer
|-
| 0x0000000D || TEXCOORD_0 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_0" buffer
|-
| 0x0000000E || TEXCOORD_1 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_1" buffer
|-
| 0x0000000F || TEXCOORD_2 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_2" buffer
|-
| 0x00000010 || TEXCOORD_3 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_3" buffer
|-
| 0x00000011 || TEXCOORD_4 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_4" buffer
|-
| 0x00000012 || TEXCOORD_5 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_5" buffer
|-
| 0x00000013 || TEXCOORD_6 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_6" buffer
|-
| 0x00000014 || TEXCOORD_7 || This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TEXCOORD_7" buffer
|-
| 0x00000019 || TANGENT || ''This indexes into the [[#VTX1_-_Vertex_Data|VTX1]] "TANGENT" buffer, but we don't yet know what that buffer does.''
|-
| 0x000000FF || List End || A buffer using this target will end the descriptor list.
|}
 
The Data Type of an Index Buffer determines the size of each Index. Direct Buffers can only be 1 byte per value.
{| class="wikitable"
|+ Data Types
|-
! Value !! Name !! Description
|-
| 0x00000000 || None || Only used for the List End
|-
| 0x00000001 || Direct || 1 byte per value. Only used for data that is not stored within [[#VTX1_-_Vertex_Data|VTX1]]<br/>Needs to be divided by 3 for some reason...
|-
| 0x00000002 || UInt8 || 1 byte per value (0 to 255). Indexes a buffer in [[#VTX1_-_Vertex_Data|VTX1]].
|-
| 0x00000003 || UInt16 || 2 bytes per value (0 to 65535). Indexes a buffer in [[#VTX1_-_Vertex_Data|VTX1]].
|}
 
=== Primitive Data ===
This chunk contains raw primitives. These are what hold the index buffers.<br/>The Index Buffers are ordered the same way the Index Buffer Attributes are ordered. For example, POSITION (UInt16), NORMAL (UInt16), COLOR_0 (UInt8), TEXCOORD_0 (UInt16), would result in the following byte structure: '''PPPP NNNN C0 TXC0'''<br/>This repeats for each vertex in the primitive.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || Uint8 || Primitive Type
 
* 0x80 = Individual Quads


== EVP1 ==
* 0x90 = Individual Triangles


== DRW1 ==
* 0x98 = Triangle Strip


== JNT1 ==
* 0xA0 = Triangle Fan


== SHP1 ==
* 0xA8 = Individual Lines


== MAT2 ==
* 0xB0 = Line Strip


== MAT3 ==
* 0xB8 = Individual Points
 
<small>TODO: Figure out if Quads, Lines, Line Strips, and Points work.</small><br/><small>TODO: Figure out if "Quad Strips" exist at 0x88.</small>
|-
| 0x04 || Int16 || Vertex Count
|}
Each Matrix Group's primitive collection MUST be padded to the nearest 32. The game dies if you don't.


== MDL3 ==
=== Matrix Group Definition Table ===
This table defines a list of Matrix Groups for each Shape. A Shape can have multiple Matrix Groups, but only stores the index of the first one. This means that all the Matrix Groups for a given Shape must come directly one after another.<br/>It contains only two values: The size of all Primitive Data within this group, and an offset to the first Primitive (relative to the Primitive Data offset defined in SHP1).
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || Int32 || Primitive Data size
|-
| 0x04 || Int32 || First Primitive offset
|}
 
=== Matrix Group Data Table ===
This table contains definitions of sub-segments inside the Weight Index Table. How these values are used differs based on the shape matrix calculation type, but official files generally set both usages up correctly regardless.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || Int16 || [[#DRW1_-_Skinning_Assignments|DRW1]] Matrix ID<br/>This is only used with Single Joint shape matrix calculation.
|-
| 0x02 || Int16 || Matrix Count<br/>This is only used with Multiple Joint shape matrix calculation.
|-
| 0x04 || Int32 || Starting Weight Index<br/>This is only used with Multiple Joint shape matrix calculation.
|}
 
=== Weight Index Table ===
This table contains several indices into [[#DRW1_-_Skinning_Assignments|DRW1]].<br/>Each index is a Signed 16 value.<br/>The values may also contain 0xFFFF, which indicates that the last used index should be used instead.<br/>Matrix Groups can select a segment of these indices (up to 10) for use. A Matrix Group must not start with 0xFFFF.
 
== MAT2 - Material List (Old) ==
Technically supported by the game, but not known to be used by any model.
 
== MAT3 - Material List ==
Contains information for '''Mat'''erials to fill the rendered geometry with.
 
== MDL3 - Display List ==
Contains raw material GX opcodes to speed up rendering.
 
== TEX1 - Texture Data ==
The '''Tex'''ture Information section holds several embedded [[BTI_(File_Format)|BTI]] files that [[#MAT3_-_Material_List|MAT3]] can reference by index for texture assignment.
{| class="wikitable"
|-
! Offset !! Type !! Description
|-
| 0x00 || String || Always '''TEX1''' (ASCII)
|-
| 0x04 || Int32 || The total size of this chunk
|-
| 0x08 || Int16 || The number of [[BTI_(File_Format)|BTI]] files stored.
|-
| 0x0A || Int16 || Padding (0xFFFF)
|-
| 0x0C || Int32 || [[BTI_(File_Format)|BTI]] Header Table Offset
|-
| 0x10 || Int32 || Name table offset
|}


== TEX1 ==
The texture data locations are defined by the [[BTI_(File_Format)|BTI]] headers (which themselves are located directly one after another at the Header Table)<br/>
This structure allows multiple textures that have the same visual data to have their headers point to just one block of visual data. In other words, two identical textures can be "compressed" into one while still having their own properties (wrapping, filtering, etc.)

Latest revision as of 18:44, 1 June 2026

This page is in progress and may contain incomplete information or editor's notes.

BMD (Binary Model) and BDL (Binary Display List) are two 3D model formats used in Super Mario Galaxy and Super Mario Galaxy 2, among a few other Wii and GameCube games, such as Super Mario Sunshine.

These two formats hold the same data, except BDL contains an additional set of data which is used for faster rendering speeds.

Super Mario Galaxy & Super Mario Galaxy 2 contain J3DLoader versions 21 and 26.

File Header

Offset Type Description
0x00 String The magic that tells the game which format this file is. (ASCII)
J3D2bmd2 for BMD (J3DLoader V21)
J3D2bmd3 for BMD (J3DLoader v26)
J3D2bdl4 for BDL (J3DLoader v26)
0x08 Int32 The total size of the file
0x0C Int32 The number of chunks present in this file.
8 for BMD
9 for BDL

Subversion Header

This part of the header is not used, and can be anything.

Offset Type Description
0x00 String A 4 character value representing the Subversion. Usually SVR3 for SMG/2.
0x04 Byte[12] Twelve bytes of padding. Usually these are 0xFF

INF1 - Scene Information

The Information section hosts a hierarchy of Joints, Materials, and Shapes, which are used to render the model.

Offset Type Description
0x00 String Always INF1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int16 J3DLoader Flags
0x0A Int16 Padding (0xFFFF)
0x0C Int32 Matrix Group Data Count
Referring to the Matrix Group Data in SHP1
Stored in a variable by the game, but not used to dictate the actual number of Matrix Groups.
0x10 Int32 Vertex Count
Always equals the number of entries in the VTX1 "POSITION" data buffer
Stored in a variable by the game, but never used for anything. The game reads Vertex Data directly from the data buffers without bounds checking.
0x14 Int32 Relative offset to the Scene Hierarchy

J3DLoader Flags

The J3DLoader contains several flags which affect how models are handled. There are more than what are shown here, however, those must be applied by the game itself in the code.

Value Description
0b0000000000000000 No flags applied (TODO: Check if this defaults to basic matrix calculation)
0b0000000000000001 Use Autodesk Softimage matrix calculation
0b0000000000000010 Use Autodesk Maya matrix calculation
0b0000000000000100 Use Basic matrix calculation
0b0000000000001000 UNKNOWN
0b0000000000010000 UseImmidiateMtx (needs research)
0b0000000000100000 UsePostTexMtx (needs research)
0b0000000001000000 UNKNOWN
0b0000000010000000 UNKNOWN
0b0000000100000000 NoMatrixTransform (needs research)
0b0000001000000000 UNKNOWN
0b0000010000000000 UNKNOWN
0b0000100000000000 UNKNOWN
0b0001000000000000 UNKNOWN
0b0010000000000000 DoBdlMaterialCalc
0b0100000000000000 NoBdlMaterialPatch - If set, skips the call to J3DModelLoader::readPatchedMaterial.
0b1000000000000000 UNKNOWN

For all BMD files, the game always includes load flags Material_PE_Full, Material_UseIndirect, UseUniqueMaterials, and UNKNOWN_21.
For all BDL files, the game always includes load flags Material_UseIndirect, and UseUniqueMaterials.

> Note: Changing the load flags by changing the code doesn't seem to do much.

Scene Hierarchy

Each model is constructed using a Scene Hierarchy. This simply determines the order of bones (in turn, defining the parent/child relations), material assignments, and Shape assignments.

Each node consists of the following:

Offset Type Description
0x00 UInt16 Node Type.
0x00 = Marks the end of the node list
0x01 = Creates a new child of the previous node
0x02 = Finishes the child node and returns ownership to the previous node
0x10 = Joint Assignment node. "Data" holds the Joint ID (index into JNT1)
0x11 = Material assignment. "Data" holds the Material ID (index into MAT3)
0x12 = Shape Assignment. "Data" holds the Shape ID (index into SHP1)
0x02 UInt16 A Data value. Used by some nodes to index into other chunks. Usage depends on the node type.

The node list is padded to the nearest 32.


VTX1 - Vertex Data

The Vertex Data section contains the actual number values used for the properties of the geometry. It also includes the information on how the values are formatted.

Offset Type Description
0x00 String Always VTX1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int32 Buffer Format list offset
0x0C Int32 "POSITION" data buffer offset
0 if not used.
0x10 Int32 "NORMAL" data buffer offset
0 if not used.
0x14 Int32 "TANGENT" data buffer offset
0 if not used.
0x18 Int32 "COLOR_0" data buffer offset
0 if not used.
0x1C Int32 "COLOR_1" data buffer offset
0 if not used.
0x20 Int32 "TEXCOORD_0" data buffer offset
0 if not used.
0x24 Int32 "TEXCOORD_1" data buffer offset
0 if not used.
0x28 Int32 "TEXCOORD_2" data buffer offset
0 if not used.
0x2C Int32 "TEXCOORD_3" data buffer offset
0 if not used.
0x30 Int32 "TEXCOORD_4" data buffer offset
0 if not used.
0x34 Int32 "TEXCOORD_5" data buffer offset
0 if not used.
0x38 Int32 "TEXCOORD_6" data buffer offset
0 if not used.
0x3C Int32 "TEXCOORD_7" data buffer offset
0 if not used.

Vertex Buffer Formats

Each of the Buffers in this section have a format descriptor. This allows different types of data storage, allowing for smaller files.

Each format descriptor contains an Attribute Target, a Component Count, a Data Type, and a Mantissa shifter (to allow floats to be stored as smaller datatypes compared to FLOAT).
Only one descriptor can exist for each attribute.

The Attribute Target tells the game what this buffer is used for.

Attribute Targets
Value Name Description
0x00000009 POSITION This buffer represents the positions of vertices in the model. Basically required for all visual models.
0x0000000A NORMAL This buffer represents vertex normals, used for the engine's vertex shading. Not needed if no material requires it.
0x0000000B COLOR_0 This buffer is available for Vertex Colors.
0x0000000C COLOR_1 This buffer is available for Vertex Colors.
0x0000000D TEXCOORD_0 This buffer is available for Texture Coordinates.
0x0000000E TEXCOORD_1 This buffer is available for Texture Coordinates.
0x0000000F TEXCOORD_2 This buffer is available for Texture Coordinates.
0x00000010 TEXCOORD_3 This buffer is available for Texture Coordinates.
0x00000011 TEXCOORD_4 This buffer is available for Texture Coordinates.
0x00000012 TEXCOORD_5 This buffer is available for Texture Coordinates.
0x00000013 TEXCOORD_6 This buffer is available for Texture Coordinates.
0x00000014 TEXCOORD_7 This buffer is available for Texture Coordinates.
0x00000019 TANGENT Currently unknown exactly what goes in here.
0x000000FF List End A buffer using this target will end the descriptor list.

The component count tells the game how many parts of the component that there are. Note that the values are considered based on the attribute target they're assigned to.

Component Count
Value Name Description
0x00000000 POSITION_XY Unknown
0x00000001 POSITION_XYZ Represents a position in 3D space with 3 values: X, Y, and Z.
0x00000000 NORMAL_XYZ Represents a normal vector in 3D space with 3 values: X, Y, and Z.
0x00000001 NORMAL_NBT Unknown
0x00000002 NORMAL_NBT3 Unknown
0x00000000 COLOR_RGB Represents a color value with only Red, Green, and Blue values.
0x00000001 COLOR_RGBA Represents a color value with Red, Green, Blue, and Alpha values.
0x00000000 TEXCOORD_S Unknown
0x00000001 TEXCOORD_ST Represents a UV texture coordinate with 2 values: X and Y.

The Data Type tells the game how many bytes each value is, in the sense that an Int32 is 4 bytes, a Int16 is 2 bytes, a Float is 4 bytes, etc.
Note that the Color values have a different set of options.

Data Types
Value Name Description
0x00000000 UInt8 1 byte per value (0 to 255)
0x00000001 Int8 1 byte per value (-128 to 127)
0x00000002 UInt16 2 bytes per value (0 to 65535)
0x00000003 Int16 2 bytes per value (-32,768 to 32,767)
0x00000004 Float 4 bytes per value
0x00000000 RGB565 2 bytes per color
0x00000001 RGB8 3 bytes per color
0x00000002 RGBX8 3 bytes per color
0x00000003 RGBA4 2 bytes per color
0x00000004 RGBA6 4 bytes per color
0x00000005 RGBA8 4 bytes per color

> Note: Both games require colors to be 4 bytes wide at all times, so changing from RGBA8 is worthless.


EVP1 - Skinning Envelopes

Offset Type Description
0x00 String Always EVP1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int16 The number of Envelopes stored.
0x0A Int16 Padding (0xFFFF)
0x0C Int32 Envelope Size Table offset
0x10 Int32 Envelope Joint Index Table offset
0x14 Int32 Envelope Weight Table offset
0x18 Int32 Inverse Bind Matrix Table offset

This section is padded to the nearest 32.

Envelope Size Table

This table simply consists of an array of UInt8, where each value dictates how many entries are in a given Envelope.

Envelope Joint Index Table

This table consists of the actual JNT1 index values. Each value is a UInt16, and are ordered directly based on the Envelope Size Table. (The first Envelope's values come directly after each other, then the second envelope's values, etc.)

Envelope Weight Table

This table consists of joint weighting values which determine how much of an effect the given Joint Index has on this envelope. Each value is a Float, and are ordered directly based on the Envelope Size Table. (The first Envelope's values come directly after each other, then the second envelope's values, etc.)

This table ends with padding to the nearest 4th byte so the Floats that come after are aligned correctly.

Inverse Bind Matrix Table

This table contains Inverse Bind Matrices for each joint in JNT1. The EVP1 section itself contains no size of this table, but the number of Inverse Bind Matrices is always equal to the amount of Joints in the model.
Each entry is a 3 Row 4 Column Matrix (Mtx34), and is stored as 3 Vector4 values.

DRW1 - Skinning Assignments

This section contains a map which redirects skinning information to the correct location: either JNT1 (Single Matrix) or EVP1 (Multi-Matrix)
The Destination Type list and Destination ID list must be equal in length.

Offset Type Description
0x00 String Always DRW1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int16 The number of Entries stored.
0x0A Int16 Padding (0xFFFF)
0x0C Int32 Destination Type list offset
0x10 Int32 Destination ID list offset

Destination Type List

This is an array of bytes that dictates the destination type. It is ordered so that all the Joints come first, and all the Envelopes second.

Value Name Description
0x00 Joint Redirects to a Joint within JNT1
0x01 Envelope Redirects to an Envelope in EVP1

It's worth noting that Nintendo's development tools had a bug in it where all the Envelope entries were duplicated. Some JSystem games do not care about this, but certain games try to explicitly ignore this data, and therefore require the wasteful duplicate data.

Destination ID List

This is an array of UInt16 that simply dictate an index into the provided section.

DRW1 ends with padding to the nearest 32.

JNT1 - Joint Hierarchy

The Joint Hierarchy section defines the rigging skeleton of a model. There can only be one skeleton per model.

Offset Type Description
0x00 String Always JNT1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int16 The number of Joints stored.
0x0A Int16 Padding (0xFFFF)
0x0C Int32 Joint Data table offset
0x10 Int32 Remap table offset
0x14 Int32 Name table offset
0 if not present.

Joint Data

Each joint includes positional data and a bounding box which is used by the game for determining rendering range automatically.

Offset Type Description
0x00 Int16 Matrix Type
0x01 UInt8 Parent Scale inheritance
0 = Follow parent joint's scale
1 = Ignore parent joint's scale
0x02 UInt8 Padding (0xFF)
0x04 Float Scale X
0x08 Float Scale Y
0x0C Float Scale Z
0x10 Int16 Rotation X
0x12 Int16 Rotation Y
0x14 Int16 Rotation Z
0x16 Int16 Padding (0xFFFF)
0x18 Float Translation X
0x1C Float Translation Y
0x20 Float Translation Z
0x24 Float Bounding Sphere
Should encapsulate all vertices that the joint affects
0x28 Float Bounding Box Minimum X
0x2C Float Bounding Box Minimum Y
0x30 Float Bounding Box Minimum Z
0x34 Float Bounding Box Maximum X
0x38 Float Bounding Box Maximum Y
0x3C Float Bounding Box Maximum Z

Rotation is stored between -0x7FFF and 0x7FFF, which ranges -180 degrees and 180 degrees.

SHP1 - Shape Information

The Shape Information section determines how to use the data in the VTX1 section to create shapes.

Offset Type Description
0x00 String Always SHP1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int16 The number of Shapes stored.
0x0A Int16 Padding (0xFFFF)
0x0C Int32 Shape Init Data offset
0x10 Int32 Remap table offset
0x14 Int32 Name table offset
0 if not present, which it usually isn't.
0x18 Int32 Vertex Index Attribute table offset
0x1C Int32 Weight Index table offset
0x20 Int32 Primitive Data offset
0x24 Int32 Matrix Group Data offset (entry count must equal the entry count of the GXDisplayList group table)
0x28 Int32 Matrix Group Definition table offset

Shape Data

Each shape denotes a Matrix Calculation type, which is used for Billboarding, as well as multi-joint skinning.
A shape also hosts a collection of Matrix Groups. If the geometry needs to be weighted to more than 10 DRW1 matrices, more than one Matrix Group is needed.
A single Matrix Group can have multiple Primitives in it, but these Primitives must share the same set of DRW1 matrices.

TODO: Figure out what happens in the event that more than 10 are needed (such as one vertex being weighted to 11 bones). Is it just straight up not allowed?

Offset Type Description
0x00 UInt8 Matrix Type
  • 0 = Single Joint
  • 1 = Billboard Joint
  • 2 = Billboard Joint (Y axis only)
  • 3 = Multiple Joints
0x01 UInt8 Padding (0xFF)
0x02 Int16 Matrix Group count
0x04 Int16 Vertex Index Attribute offset
Relative to the Vertex Index Attribute Table offset defined in SHP1
0x06 Int16 Matrix Group Data index
0x08 Int16 First Matrix Group Definition index
0x0A Int16 Padding (0xFFFF)
0x0C Float Bounding Sphere
0x10 Float Bounding Box Minimum X
0x14 Float Bounding Box Minimum Y
0x18 Float Bounding Box Minimum Z
0x1C Float Bounding Box Maximum X
0x20 Float Bounding Box Maximum Y
0x24 Float Bounding Box Maximum Z

Vertex Index Attribute Table

Offset Type Description
0x00 Int32 An index buffer attribute target
0x04 Int32 An index buffer type

Index Buffer Formats

Each of the Buffers in this section have a format descriptor. This allows different types of data storage, allowing for smaller files.

These attributes line up with either a direct value that is stored in the shape, or an index into a VTX1 data buffer.
Only one indexer can exist for each attribute.

The Attribute Target tells the game what this index buffer is used for.

Attribute Targets
Value Name Description
0x00000000 POSITION_MATRIX This is a direct list of indices into the Matrix Group's Weight collection. Required for Shapes that use Multiple Joint skinning.
0x00000001 TEXTURE_0_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000002 TEXTURE_1_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000003 TEXTURE_2_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000004 TEXTURE_3_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000005 TEXTURE_4_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000006 TEXTURE_5_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000007 TEXTURE_6_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000008 TEXTURE_7_MATRIX Uses the Direct type. Seems to break models that use it, and no official models in either galaxy game use it.
0x00000009 POSITION This indexes into the VTX1 "POSITION" buffer. Required.
0x0000000A NORMAL This indexes into the VTX1 "NORMAL" buffer
0x0000000B COLOR_0 This indexes into the VTX1 "COLOR_0" buffer
0x0000000C COLOR_1 This indexes into the VTX1 "COLOR_1" buffer
0x0000000D TEXCOORD_0 This indexes into the VTX1 "TEXCOORD_0" buffer
0x0000000E TEXCOORD_1 This indexes into the VTX1 "TEXCOORD_1" buffer
0x0000000F TEXCOORD_2 This indexes into the VTX1 "TEXCOORD_2" buffer
0x00000010 TEXCOORD_3 This indexes into the VTX1 "TEXCOORD_3" buffer
0x00000011 TEXCOORD_4 This indexes into the VTX1 "TEXCOORD_4" buffer
0x00000012 TEXCOORD_5 This indexes into the VTX1 "TEXCOORD_5" buffer
0x00000013 TEXCOORD_6 This indexes into the VTX1 "TEXCOORD_6" buffer
0x00000014 TEXCOORD_7 This indexes into the VTX1 "TEXCOORD_7" buffer
0x00000019 TANGENT This indexes into the VTX1 "TANGENT" buffer, but we don't yet know what that buffer does.
0x000000FF List End A buffer using this target will end the descriptor list.

The Data Type of an Index Buffer determines the size of each Index. Direct Buffers can only be 1 byte per value.

Data Types
Value Name Description
0x00000000 None Only used for the List End
0x00000001 Direct 1 byte per value. Only used for data that is not stored within VTX1
Needs to be divided by 3 for some reason...
0x00000002 UInt8 1 byte per value (0 to 255). Indexes a buffer in VTX1.
0x00000003 UInt16 2 bytes per value (0 to 65535). Indexes a buffer in VTX1.

Primitive Data

This chunk contains raw primitives. These are what hold the index buffers.
The Index Buffers are ordered the same way the Index Buffer Attributes are ordered. For example, POSITION (UInt16), NORMAL (UInt16), COLOR_0 (UInt8), TEXCOORD_0 (UInt16), would result in the following byte structure: PPPP NNNN C0 TXC0
This repeats for each vertex in the primitive.

Offset Type Description
0x00 Uint8 Primitive Type
  • 0x80 = Individual Quads
  • 0x90 = Individual Triangles
  • 0x98 = Triangle Strip
  • 0xA0 = Triangle Fan
  • 0xA8 = Individual Lines
  • 0xB0 = Line Strip
  • 0xB8 = Individual Points

TODO: Figure out if Quads, Lines, Line Strips, and Points work.
TODO: Figure out if "Quad Strips" exist at 0x88.

0x04 Int16 Vertex Count

Each Matrix Group's primitive collection MUST be padded to the nearest 32. The game dies if you don't.

Matrix Group Definition Table

This table defines a list of Matrix Groups for each Shape. A Shape can have multiple Matrix Groups, but only stores the index of the first one. This means that all the Matrix Groups for a given Shape must come directly one after another.
It contains only two values: The size of all Primitive Data within this group, and an offset to the first Primitive (relative to the Primitive Data offset defined in SHP1).

Offset Type Description
0x00 Int32 Primitive Data size
0x04 Int32 First Primitive offset

Matrix Group Data Table

This table contains definitions of sub-segments inside the Weight Index Table. How these values are used differs based on the shape matrix calculation type, but official files generally set both usages up correctly regardless.

Offset Type Description
0x00 Int16 DRW1 Matrix ID
This is only used with Single Joint shape matrix calculation.
0x02 Int16 Matrix Count
This is only used with Multiple Joint shape matrix calculation.
0x04 Int32 Starting Weight Index
This is only used with Multiple Joint shape matrix calculation.

Weight Index Table

This table contains several indices into DRW1.
Each index is a Signed 16 value.
The values may also contain 0xFFFF, which indicates that the last used index should be used instead.
Matrix Groups can select a segment of these indices (up to 10) for use. A Matrix Group must not start with 0xFFFF.

MAT2 - Material List (Old)

Technically supported by the game, but not known to be used by any model.

MAT3 - Material List

Contains information for Materials to fill the rendered geometry with.

MDL3 - Display List

Contains raw material GX opcodes to speed up rendering.

TEX1 - Texture Data

The Texture Information section holds several embedded BTI files that MAT3 can reference by index for texture assignment.

Offset Type Description
0x00 String Always TEX1 (ASCII)
0x04 Int32 The total size of this chunk
0x08 Int16 The number of BTI files stored.
0x0A Int16 Padding (0xFFFF)
0x0C Int32 BTI Header Table Offset
0x10 Int32 Name table offset

The texture data locations are defined by the BTI headers (which themselves are located directly one after another at the Header Table)
This structure allows multiple textures that have the same visual data to have their headers point to just one block of visual data. In other words, two identical textures can be "compressed" into one while still having their own properties (wrapping, filtering, etc.)