File Formats - OpenJPOG/org.equinoxscripts.ojpog.io GitHub Wiki
Common Data Formats
Null-terminated string: ASCII string terminated with a zero-byte.
Fixed length string: An ASCII string encoded in a fixed number of bytes. Respect null termination.
Quaternion: Four 32-bit floats laid out as X,Y,Z,W.
Matrix: Sixteen 32-bit floats laid out in row-major order.
Vector3: Three 32-bit floats laid out as X,Y,Z
Vector2: Two 32-bit floats laid out as X,Y
Notes
An offset of ~~
means assume tight packing; this element starts after the previous one.
Toshi Model Driver (.TMD)
The TMD format starts with an 8 byte fixed length string. Magic is "TMDL".
TMD Header
The TMD header starts at byte 8 and is made of 52 bytes.
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Remaining bytes in file |
+4 | 8 byte fixed string | Category / lookup table for animations. |
+12 | uint64 | Magic Value. Typically one of a couple values. |
+20 | uint32 | lodDataOffset = value + 60 |
+24 | uint32 | Salt used to encrypt file offsets. |
+28 | uint32 | Unknown value. |
+32 | uint32 | Unknown value. |
+36 | zero*16 | 16 zeroes |
Address encryption
To convert an encrypted address to an offset from the beginning of the file take: fileAddress = 60 + encryptedAddress - saltUsedForEncryptingOffsets
Scene Block
The scene block starts at byte 60+4, and has a size of the uint32
located at +60
from the beginning of the file.
Offset | Type | Meaning |
---|---|---|
+0 | uint16 | Number of nodes |
+2 | uint16 | Unknown |
+4 | uint16 | Number of animations |
+6 | uint16 | Unknown |
+8 | zero*44 | 44 zeroes |
+52 | uint32 | Encrypted address of the auxiliary node data |
+56 (Optional) | uint32 | Encrypted address of the node data block * |
+56 / +60 | uint32 | Encrypted address of the animation pointer block* |
* If the decrypted address of the auxiliary node data is 0x7C
it is assumed that there is no auxiliary node data. Then the decrypted address of the node data is assumed to be 0x7C
also, and the encrypted address of the animation pointer table is located at +56
instead of +60
.
Node Auxiliary Data (Optional)
Starting from the decrypted address of the auxiliary node data read one int32
for each node.
Node Data Block
The node data block starts at the decrypted address from the scene block, and extends for 0xB0 * numNodes
bytes. Node 0 is then located at +0
, and node 1 at +0xB0
inside the block. The node ID is the node's position in the zero-indexed array.
Node Format
Offset | Type | Meaning |
---|---|---|
+0 | quaternion | Fallback rotation, used when the animation doesn't provide one |
+16 | matrix | Bind pose of the node, in world space |
+80 | matrix | Inverse of the bind pose of the node, in world space |
+144 | byte | Length of the name string |
+145 | 15 byte fixed string | Node name |
+160 | int16 | ID of parent node, -1 if no parent exists |
+162 | uint16 | If non-zero this node can ignore updates. Non-updated bones may only appear after all updated bones. |
+164 | vector3 | Fallback translation, used when the animation doesn't provide one |
Animation Pointer Block
The node data block starts at the decrypted address from the scene block, and extends for 4 * numAnimations
bytes. Read one uint32
for each animation; this is the encrypted address of that animation.
Animation Data Block
Starting at a decrypted animation address from the animation pointer block read 0x20 + numNodes*4
bytes.
Offset | Type | Meaning |
---|---|---|
+0 | byte | Name length |
+1 | 15 byte fixed string | Animation Name |
+16 | uint32 | Composite animation (added on top of others) |
+20 | uint32 | Is sound played? |
+24 | uint32 | Number of channels in animation |
+28 | 32 bit float | Duration in seconds |
+32 | uint32[numNodes] | Encrypted address for each node's channel in this animation. Channel zero is for node zero. |
Animation Channel Block
Starting at a decrypted animation channel address from a animation data block read an unknown number of bytes.
Offset | Type | Meaning |
---|---|---|
+0 | uint16 | (value&1) == UseTranslation, (value&2) == UseChannel |
+2 | uint16 | Frame count |
+4 | frame[frameCount] | Keyframes in this animation |
Keyframe
Offset | Type | Meaning |
---|---|---|
+0 | 32 bit float | Timestamp |
+4 | uint16 | Translation key used in the lookup table |
+6 | uint16 | Rotation key used in the lookup table |
Levels-of-Detail Block
The levels of detail block starts at the offset specified in the header and extends for an undefined number of bytes.
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Number of levels |
+4 | uint32 | Unknown value |
+8 | level[numLevels] | LOD Level Data |
Level-of-Detail
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Number of meshes in this level |
+4 | 32 bit float | Level of detail distance? |
+8 | 4x 32 bit float | Unknown |
+24 | mesh[numMesh] | Mesh Data |
Mesh Data
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Number of pieces in this mesh |
+4 | uint32 | Total number of indices in the triangle strip for all pieces |
+8 | uint32 | Total number of vertices |
+12 | 32 byte fixed string | Material name |
+44 | meshPiece[numPieces] | Piece Data |
Mesh Piece
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Total number of indices in this piece's triangle strip. |
+4 | uint32 | Total number of vertices store in this piece's data. |
+8 | uint32 | Total number of nodes this mesh is skinned to. |
+12 | uint32 | Highest vertex number this piece references. |
+16 | vector3 | Center of the bounding box for this piece. (max+min)/2 |
+28 | vector3 | Extent of the bounding box for this piece. (max-min)/2 |
+40 | uint32[numNodesSkinnedTo] | The IDs of the nodes that this mesh is skinned to. Element zero is the node ID of bone zero, etc. |
~~ | vertex[numVertices] | The vertices defined in this piece. This accumulate inside the mesh, not in the mesh piece. |
~~ | int16[numIndices] | The indices that make this piece's triangle strip. Note these reference the mesh's vertices and are numbered accordingly. |
Mesh Vertex
Offset | Type | Meaning |
---|---|---|
+0 | vector3 | Position |
+12 | vector3 | Normal |
+24 | byte[4] | Each byte is a boneWeight = value / 0xFF |
+28 | byte[4] | Each byte is a boneID = value / 3 |
+32 | vector2 | Texture Coordinate |
Toshi Keyframe Library (.TKL)
Offset | Type | Meaning |
---|---|---|
+0 | 4 byte fixed string | Must be "TPKL" |
+4 | byte[4] | Always empty |
+8 | uint32 | Remaining bytes in file (=bytes in LUT + 44) |
+12 | 6 byte fixed string | The name of this keyframe table/lookup table. |
+18 | byte[10] | Unknown |
+28 | uint32 | Number of position values |
+32 | uint32 | Number of rotation values |
+36 | byte[16] | Unknown |
+52 | uint32 | Number of bytes in the LUT |
+56 | vector3[numPosValues] | Position lookup table |
~~ | quaternion[numRotValues] | Rotation lookup table |
Toshi Material Library (.TML)
Offset | Type | Meaning |
---|---|---|
+0 | 4 byte fixed string | Must be "TML1" |
+4 | uint32 | Unknown |
+8 | uint32 | Number of textures |
+12 | texture[numTextures] | Textures |
~~ | uint32 | Number of materials |
~~ | 32 byte fixed string [numMaterials] |
LUT for material names |
~~ | material[numMaterials] | Materials |
TML Material
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Index in the material name LUT for this materials' name. |
+4 | uint16 | Unknown |
+6 | uint16 | Number of textures that make up this material |
+8 | uint32[numTextures] | The texture IDs of the textures that make up this texture. |
TML Texture
Offset | Type | Meaning |
---|---|---|
+0 | uint32 | Texture ID |
+4 | uint32 | Data size |
+8 | byte[8] | Unknown |
+16 | tmlFormat | Texture format |
+18 | uint16 | texture width |
+20 | uint16 | texture height |
+22 | byte[6] | Unknown |
+28 | byte[dataSize] | Image data according to the tmlFormat ; raster formats use row-major order. |
TML Texture Format
Value | Description |
---|---|
0 | RGBA_8888 |
2 | ARGB_1555 |
6 | DDS File |
7 | ARGB_4444 |
9 | ARGB_2222 |
Notes
- The order of the materials and textures seems extremely finicky so any solution shouldn't mess with it too much.