TMD Format - niemasd/PyFF7 GitHub Wiki
The TMD format contains 3D modeling data which is compatible with the PlayStation expanded graphics library (libgs). The data in a TMD file is a set of graphics primitives—polygons, lines, etc.—that make up a 3D object. A single TMD file can contain data for one or more 3D objects.
This wiki and this code might be a useful reference. Maybe this code too. Actually, the file linked here is the most helpful.
A TMD file's header gives general information about the TMD file. It is 12 bytes in size.
- This is an unsigned integer and seems to always equal 65 (i.e.,
0x41
) in Final Fantasy VII
- This is an unsigned integer indicating if addresses are explicit (1) or relative to the start (0)
- This seems to always equal 0 in Final Fantasy VII
- This is an unsigned integer denoting the number of objects in this TMD file
- It seems to always be at most 5,000
A TMD file's object table stores information about the objects contained within the TMD. Each object has the following structure and is 28 bytes in size:
- This is an unsigned integer indicating the start offset of the vertex list for this object
- This is an unsigned integer indicating the number of vertices in the vertex list for this object
- This is an unsigned integer indicating the start offset of the normal list for this object
- This is an unsigned integer indicating the number of normals in the normal list for this object
- This is an unsigned integer indicating the start offset of the primitive list for this object
- This is an unsigned integer indicating the number of primitives in the primitive list for this object
- This is a signed integer, and 2 raised to its value is the scale value
- If this is 0, the scaling value is 20 = 1
- If this is 2, the scaling value is 22 = 4
- If this is -1, the scaling value is 2-1 = 0.5
- It seems to always be 0 in Final Fantasy VII
Each primitive has the following structure and is ??? bytes in size:
- This is an unsigned integer denoting the size of 2D drawing primitives that are generated by intermediate processing
- This is an unsigned integer denoting the size of the packet data section
- This is an unsigned integer whose bits represent various flags in the following format:
00000GFL
- The 5 left-most (i.e., most significant) bits are all 0
- The next bit is the GRD flag
- This is only valid for the polygon not textured, subjected to light source calculation
- 1 = Gradation polygon
- 0 = Single-color polygon
- The next bit is the FCE flag
- This is only valid when the Code value refers to a polygon (see Primitive Mode section)
- 1 = Double-faced polygon
- 0 = Single-faced polygon
- The right-most (i.e., least significant) bit is the LGT flag
- 1 = Light source calculation not carried out
- 0 = Light source calculation carried out
- This is an unsigned integer whose bits are in the following format:
CCCOOOOO
- The 3 left-most (i.e., most significant) bits represent this primitive's Code
-
000
= 0 = UNKNOWN!!! Final Fantasy VII has primitives like this, though!!! Not in Sony documentation -
001
= 1 = Polygon (triangle, quadrilateral) -
010
= 2 = Straight line -
011
= 3 = Sprite
-
- The 5 right-most (i.e., least significant) bits represent this primitive's Option
- See each primitive type's description for information of what's in the Option bits
- The 3 left-most (i.e., most significant) bits represent this primitive's Code
Each vertex has the following structure and is 8 bytes in size:
- This is a signed integer denoting the X coordinate of this vertex
- This is a signed integer denoting the Y coordinate of this vertex
- This is a signed integer denoting the Z coordinate of this vertex
- This is unused padding
Each normal has the following structure and is 8 bytes in size:
- This is a signed integer denoting the X coordinate of this normal
- This is a signed integer denoting the Y coordinate of this normal
- This is a signed integer denoting the Z coordinate of this normal
- This is unused padding
There are many different types of primitives, and each must be handled in its own way. Recall that the Code byte of a primitive is in the format CCCOOOOO
, where the 3 left-most (i.e., most significant) bits, CCC
, are the Code, and the 5 right-most (i.e., least significant) bits, OOOOO
, are the Option.
Some primitives in Final Fantasy VII have Code = 000
= 0, but this is not documented in the Sony PlayStation TMD format description. Need to figure out how to decode these primitives.
When Code = 001
= 1, the primitive is a polygon (i.e., triangle or quadrilateral). Polygons have the following bits in their Mode byte:
- The 3 left-most (i.e., most significant) bits are the Code (
001
) - The next bit is the Shading Mode (IIP) flag
- 0 = Flat Shading
- 1 = Gouraud Shading
- The next bit determines if this is a 3-vertex (i.e., triangle) or 4-vertex (i.e., quadrilateral) polygon
- 0 = 3-vertex (i.e., triangle)
- 1 = 4-vertex (i.e., quadrilateral)
- The next bit is the Texture Specification (TME) flag
- 0 = Off
- 1 = On
- The next bit is the Translucency Processing (ABE) flag
- 0 = Off
- 1 = On
- The right-most (i.e., least significant) bit is the Brightness Calculation (TGE) flag
- 0 = On = Brightness is calculated at the time of texture mapping
- 1 = Off = Draw texture as-is
When Code = 010
= 2, the primitive is a straight line. Straight lines have the following bits in their Mode byte:
- The 3 left-most (i.e., most significant) bits are the Code (
010
) - The next bit is the Gradation (IIP) flag
-
0
= Gradation Off (Monochrome) -
1
= Gradation On
-
- The next 2 bits are
0
- The next bit is the Translucency Processing (ABE) flag
-
0
= Off -
1
= On
-
- The right-most (i.e., least significant) bit is
0
When Code = 011
= 3, the primitive is a sprite. Sprites have the following bits in their Mode byte:
- The 3 left-most (i.e., most significant) bits are the Code (
011
) - The next 2 bits denote the size of the sprite
-
00
= Free Size (specified in the primitive data by W and H) -
01
= 1 by 1 -
10
= 8 by 8 -
11
= 16 by 16
-
- The next bit is
1
- The next bit is the Translucency Processing (ABE) flag
-
0
= Off -
1
= On
-
- The right-most (i.e., least significant) bit is
0
-
File Header
- 4 bytes (Version)
- 4 bytes (Flags)
- 4 bytes (Number of Objects, nO)
-
Object Table (nO entries)
-
Object 1
- 4 bytes (Vertex List Start)
- 4 bytes (Vertex List Length, nV)
- 4 bytes (Normal List Start)
- 4 bytes (Normal List Length, nN)
- 4 bytes (Primitive List Start)
- 4 bytes (Primitive List Length, nP)
- 4 bytes (Scaling Factor)
- ...
-
Object nO
- ...
-
Object 1
-
Primitive Data
-
Primitive 1
- 1 byte (olen)
- 1 byte (ilen)
- 1 byte (Flag)
- 1 byte (Mode)
- ...
-
Primitive 1
-
Vertex Data
-
Vertex 1
- 2 bytes (X Coordinate)
- 2 bytes (Y Coordinate)
- 2 bytes (Z Coordinate)
- 2 bytes (Padding)
- ...
-
Vertex 1
-
Normal Data
-
Normal 1
- 2 bytes (X Coordinate)
- 2 bytes (Y Coordinate)
- 2 bytes (Z Coordinate)
- 2 bytes (Padding)
- ...
-
Normal 1