Skip to content
Chris edited this page Jun 16, 2026 · 4 revisions

MDL is an internal model format used by Rockstar Leeds games. Do not confuse it with other MDL files used by other video games. This format is used in GTA Liberty City Stories, GTA Vice City Stories, and Manhunt 2.

The format is tightly bound to the game platform, such as PSP or PS2. In other words, unlike the DFF format used in previous GTA games before RenderWare was acquired by EA Games, MDL is not cross-platform.

Contents

  1. General information
  2. Structure
    1. MDL dump-container header
    2. MDL header
    3. Clump:Struct
      1. Clump:FrameList:Struct
    4. Clump:TextureList:Struct
    5. Clump:GeometryHeader:Struct
    6. Atomic
    7. Material list
      1. MDL version
      2. WRLD version
      3. DTZ version
  3. Geometry list
    1. PS2 version
    2. PSP version
  4. Manhunt 2 MDL version
    1. File structure
    2. PC version geometry

General information

The PSP version of MDL was researched by J-Fox, who also wrote a program that reads the structure of MDL files and renders geometry, UV coordinates, and textures from *.chk files. Like many other tools for GTA: LCS and GTA: VCS, J-Fox did not publicly release this program.

The PS2 version of MDL was researched by AK-73, also known as Alex. He wrote a unique 3D Studio Max script for importing any *.mdl file from the PS2 version. For more information about the script, see the article about the MDL importer.

Structure

All *.mdl files have a global header and an Atomic header. The remaining sections of an *.mdl file are strictly platform-specific: PSP or PS2.

MDL dump-container header

0x00  4b: signature "ldm"
0x04  4b: 0
0x08  4b: size of the MDL dump-container
0x0C  4b: size of the data inside the MDL container
0x10  4b: pointer to the Pointer Reallocation table
          This table contains pointers to all pointers in the file, so they can be converted
          from local pointers to global pointers in memory.
0x14  4b: number of pointers in the Pointer Reallocation table
0x18  4b: pointer to the Methods table
          The Methods table is divided into two sections.
0x1C  2b: number of pointers in the first section of the Methods table
          Virtual methods. Used only in DTZ.
0x1E  2b: number of pointers in the second section of the Methods table
          Rendering methods. Present in MDL and DTZ. Points to a special field in Atomic.

MDL header

The MDL header is not unique. It is a prebuilt header whose data, after the game loads the MDL and converts every pointer in the file to an absolute value, is transferred into the corresponding fields of the binary IDE inside the DTZ.

Header of an MDL containing simple objects

0x0  Xb: array of pointers to model Atomics.
         The number of pointers, meaning the number of separate models, is defined in the model IDE.

Header of an MDL containing a vehicle model

The only difference between the LCS and VCS headers is the larger array of pointers to primary-color materials.

Liberty City Stories version
0x0   4b: pointer to Clump
0x4   4b: number of extras
0x8   4b: pointer to an array of pointers to extra model Atomics
0xC   100b: 25 pointers to materials recolored by the primary color
0x70  100b: 25 pointers to materials recolored by the secondary color
Vice City Stories version
0x0   4b: pointer to Clump
0x4   4b: number of extras
0x8   4b: pointer to an array of pointers to extra model Atomics
0xC   120b: 30 pointers to materials recolored by the primary color
0x84  100b: 25 pointers to materials recolored by the secondary color

Header of an MDL containing a ped model

0x0  4b: pointer to collision data. Usually embedded in the MDL.
0x4  4b: pointer to Clump

Header of an MDL containing cutscene peds or objects

0x0  16b: Clump

Clump:Struct

Contains a sub-section called the Clump-Atomic cycle, used to cycle through all Atomics belonging to this Clump. It is also used to bind an Atomic to a Clump. An equivalent sub-section is present in Atomic.

It is important to note that vehicle extras are loaded separately and do not belong to the model Clump. They do not participate in the Clump-Atomic cycle.

0x0  4b: section ID
0x4  4b: jump to the main frame, or Root Frame

Clump-Atomic cycle sub-section:
0x8  4b: pointer to the Clump-Atomic cycle sub-section of the first Atomic.
          If there are no Atomics, this points to itself.
0xC  4b: pointer to the Clump-Atomic cycle sub-section of the last Atomic.
          If there are no Atomics, this points to itself.

Clump:FrameList:Struct

Contains a sub-section called the Frame-Atomic cycle, used to cycle through Atomics belonging to this Frame. It is also used to bind an Atomic, and therefore geometry, to a Frame. An equivalent sub-section is present in Atomic.

Liberty City Stories PS2 version

0x0  4b: section type
0x4  4b: offset to the parent frame, or Parent Frame

Frame-Atomic cycle sub-section:
0x8  4b: pointer to the Frame-Atomic cycle sub-section of the first Atomic.
          If no Atomics are attached, this points to itself.
0xC  4b: pointer to the Frame-Atomic cycle sub-section of the last Atomic.
          If no Atomics are attached, this points to itself.

0x10  64b: matrix4x4: transformation matrix for the Frame and the geometry attached to it,
           relative to the parent Frame.
           To calculate the global transform of the Frame, multiply this matrix by the
           parent Frame matrix.
0x50  64b: matrix4x4: global transformation matrix for the Frame or the geometry attached to it.
           In LCS, skinned models usually have an identity matrix here.
0x90  4b: pointer to the lower-level frame, or Child Frame
0x94  4b: pointer to the frame at the same hierarchy level, or Sibling Frame
0x98  4b: pointer to the main frame, or Root Frame
0x9C  4b: bone ID.
          Used only for ped models and cutscene objects. In all other cases, this is -1.
0xA0  4b: pointer to bone parameters.
          Used only for ped models and cutscene objects.
0xA4  4b: pointer to the frame name
0xA8  4b: model information-node ID.
          Used only in vehicle models.

Liberty City Stories PSP, Vice City Stories PSP, and Vice City Stories PS2 versions

0x0  4b: section type
0x4  4b: offset to the parent frame, or Parent Frame

Frame-Atomic cycle sub-section:
0x8  4b: pointer to the Frame-Atomic cycle sub-section of the first Atomic.
          If no Atomics are attached, this points to itself.
0xC  4b: pointer to the Frame-Atomic cycle sub-section of the last Atomic.
          If no Atomics are attached, this points to itself.

0x10  64b: matrix4x4: transformation matrix for the Frame and the geometry attached to it,
           relative to the parent Frame.
           To calculate the global transform of the Frame, multiply this matrix by the
           parent Frame matrix.
0x50  64b: matrix4x4: global transformation matrix for the Frame or the geometry attached to it.
           In LCS, skinned models usually have an identity matrix here.
0x90  4b: pointer to the lower-level frame, or Child Frame
0x94  4b: pointer to the frame at the same hierarchy level, or Sibling Frame
0x98  4b: pointer to the main frame, or Root Frame
0x9C  4b: alignment
0xA0  4b: bone ID.
          Used only for LCS ped models and cutscene objects. In all other cases, this is -1.
          In VCS, this field is unused and equals 0.
0xA4  4b: pointer to bone parameters.
          Used only for ped models and cutscene objects.
0xA8  4b: pointer to the frame name
0xAC  4b: model information-node ID.
          Used only in vehicle models.

Vehicle information-node IDs in Liberty City Stories

0  - simple frame
1  - wheel_rf_dummy
2  - wheel_rm_dummy
3  - wheel_rb_dummy
4  - wheel_lf_dummy
5  - wheel_lm_dummy
6  - wheel_lb_dummy
7  - bump_front_dummy
8  - bump_rear_dummy
9  - wing_rf_dummy
10 - wing_rr_dummy
11 - door_rf_dummy
12 - door_rr_dummy
13 - wing_lf_dummy
14 - wing_lr_dummy
15 - door_lf_dummy
16 - door_lr_dummy
17 - bonnet_dummy
18 - boot_dummy
19 - windscreen_dummy

Vehicle information-node IDs in Vice City Stories

0  - simple frame
1  - unknown
2  - wheel_rf_dummy
3  - wheel_rm_dummy
4  - wheel_rb_dummy
5  - wheel_lf_dummy
6  - wheel_lm_dummy
7  - wheel_lb_dummy
8  - door_rf_dummy
9  - door_rr_dummy
10 - door_lf_dummy
11 - door_lr_dummy
12 - bump_front_dummy
13 - bump_rear_dummy
14 - wing_rf_dummy
15 - wing_lf_dummy
16 - wing_rr_dummy
17 - wing_lr_dummy
18 - bonnet_dummy
19 - boot_dummy
20 - windscreen_dummy

Clump:TextureList:Struct

4b: section type
4b: 0
4b: 1
4b: pointer to Clump:TextureList:String
4b: number of textures
4b: number of textures, repeated
4b: pointer to the inverse bone-matrix table
4b: alignment, AAAAAAAA

Clump:GeometryHeader:Struct

4b float: X coordinate of the model bounding sphere
4b float: Y coordinate of the model bounding sphere
4b float: Z coordinate of the model bounding sphere
4b float: radius of the model bounding sphere
4b: model size + material count.
    The first 12 bits are the material count, and the remaining 20 bits are the size.
4b: flag used by the game engine to determine which additional vertex-parameter sections
    are present in the model, such as normals, prelight, skinning, and UV mapping.
2b: total vertex count in the model
2b: offset to the first tri-strip
12b: 6x2b bounding box:
     MinX, MinY, MinZ, MaxX, MaxY, MaxZ as signed shorts.
     These are decoded the same way as vertex coordinates, using ScaleFactor and TranslateFactor.
4b float: X coordinate multiplier, ScaleFactorX
4b float: Y coordinate multiplier, ScaleFactorY
4b float: Z coordinate multiplier, ScaleFactorZ
4b float: X coordinate offset, TranslateFactorX
4b float: Y coordinate offset, TranslateFactorY
4b float: Z coordinate offset, TranslateFactorZ

Atomic

0x0  4b: section type
0x4  4b: pointer to the parent Frame

Frame-Atomic cycle sub-section:
0x8  4b: pointer to the Frame-Atomic cycle sub-section of the next Atomic.
          If this is the last Atomic, it points to the Frame-Atomic cycle of the Frame.
0xC  4b: pointer to the Frame-Atomic cycle sub-section of the previous Atomic.
          If this is the first Atomic, it points to the Frame-Atomic cycle of the Frame.

0x10  4b: may contain any value
0x14  4b: offset to geometry
0x18  4b: offset to Clump

Clump-Atomic cycle sub-section:
0x1C  4b: pointer to the Clump-Atomic cycle sub-section of the next Atomic.
           If this is the last Atomic, it points to the Clump-Atomic cycle of the Clump.
           If it is not attached to a Clump, this is 0.
0x20  4b: pointer to the Clump-Atomic cycle sub-section of the previous Atomic.
           If this is the first Atomic, it points to the Clump-Atomic cycle of the Clump.
           If it is not attached to a Clump, this is 0.

0x24  4b: rendering method ID
0x28  2b: IDE ID, set by the engine. Usually -1 in the file.
0x2A  2b: parameters for breakable or detachable vehicle parts
0x2C  4b: pointer to bone parameters.
           Used only for ped models and cutscene objects.
0x30  4b: may contain any value

Material list

MDL version

12b: point3 X Y Z, unused
4b: U multiplier
4b: V multiplier
4b: material color, unused
4b: jump to the beginning of the tri-strips, relative to the geometry section
2b: number of tri-strips in the material
2b: texture number from TextureList

WRLD version

This exists only in *.wrld files. Compared to the *.mdl version, it is compressed for faster reading and to save console memory. Instead of texture names, it contains texture IDs, or hashes.

PS2 WRLD version header

[2b int] number of materials
[2b int] size of the material section

PSP WRLD version header

[4b int] number of materials
[4b float] unknown. Usually 0 for LODs.

LCS PS2 geometry-list row length: 22 bytes

[2b int]        texture ID
[2b int]        tri-strip size.
                Requires a logical AND with 0x7FFF, because the first bit is a backface-culling flag.
[2b half float] U multiplier
[2b half float] V multiplier
[2b]            unknown, possibly flags
[12b 6x signed int] bounding box

VCS PS2 geometry-list row length: 24 bytes

[4b int]        tri-strip size.
                Must be divided by 2 as integer division.
                If the division leaves a remainder of 1, backface culling is enabled for the current tri-strip.
[2b int]        texture ID
[2b half float] U multiplier
[2b half float] V multiplier
[2b]            unknown, possibly flags
[12b 6x signed int] bounding box

LCS PSP geometry-list row length: 10 bytes or 24 bytes

The row can have two possible lengths: 10 bytes or 24 bytes. This is determined using the float in the header. If the float is not 0, the row length is 24 bytes. If the float is 0, the row length is 10 bytes.

[2b int]        texture ID
[2b int]        vertex count in the tri-strip.
                Requires a logical AND with 0x7FFF, because the first bit is a backface-culling flag.
[2b half float] U multiplier
[2b half float] V multiplier
[2b]            unknown, possibly flags
[2b]            unknown, possibly flags. This section may be absent.
[12b 6x signed int] bounding box. This section may be absent.

VCS PSP geometry-list row length: 24 bytes

[2b int]        texture ID
[2b int]        vertex count in the tri-strip.
                Requires a logical AND with 0x7FFF, because the first bit is a backface-culling flag.
[2b half float] U multiplier
[2b half float] V multiplier
[2b]            unknown, possibly flags
[2b]            unknown, possibly flags
[12b 6x signed int] bounding box

The bounding-box coordinates are decoded the same way as tri-strip coordinates: divide each integer by 32768, then multiply by the model scaling value.

The U and V multipliers are half-precision floating-point values.

DTZ version

These are MDL files embedded inside a DTZ file. The format does not differ in any way, so the MDL importer can read a DTZ as an MDL and import models from it.

Geometry list

Tri-strips are a series of connected triangles and vertices. They are used in games from this series specifically for fast rendering.

PS2 version

All model geometry is divided into tri-strips. Tri-strip support is also present in GTA: SA DFF files.

Reading the first tri-strip in an MDL begins immediately after the material list. The beginning of a tri-strip is marked by the flag 6C018000. After the flag, the vertex count of the tri-strip is repeated twice. Then comes the technical sector 40404020, which is needed by the engine. It is not important for importing the model.

After that come the actual blocks containing model elements.

Block 79: Geometry

Contains all vertex coordinates in the tri-strip. One coordinate is encoded as a signed short, 2 bytes, and is calculated like this:

CoordX = (CoordX as Float) / 32768 * ScaleFactorX + TranslateFactorX

Y and Z are calculated the same way.

The block size is:

block header, 4 bytes + XYZ, 6 bytes * vertex count in the tri-strip

The geometry block ends with the technical block 50505020, which is needed by the engine. It is not important for importing the model.

Block 76: UV

Contains all UV-mapping coordinates in the tri-strip. One coordinate is encoded as an unsigned byte, 1 byte. It is calculated by dividing by 255 for models from WRLD/LVZ, or by dividing by 128 for MDL.

The block size is:

block header, 4 bytes + UV, 2 bytes * vertex count in the tri-strip

Block 6F: Stories prelight

Contains RGBA vertex prelight data. It is used only in GTA LCS and GTA VCS. It is stored in 16-bit RGBA 5551 format.

The block size is:

block header, 4 bytes + RGBA, 2 bytes * vertex count in the tri-strip

Block 6E: Manhunt 2 prelight

Contains RGBA vertex prelight data. It is used only in Manhunt 2. Each color channel is encoded as one byte. It must be read as BGRA.

The block size is:

block header, 4 bytes + RGBA, 4 bytes * vertex count in the tri-strip

Block 6A: Normals

Contains all normal-vector coordinates in the tri-strip. One coordinate is encoded as a signed byte, 1 byte, and is calculated by dividing by 127.

The block size is:

block header, 4 bytes + XYZ, 3 bytes * vertex count in the tri-strip

Block 6C: Skinning

Contains the vertex-weight table used for animation. Each influence consists of a bone ID and a weight:

bone ID: 1 byte, divide by 4 using integer division
weight: 3 bytes

Each vertex contains 4 bone IDs. In other words, each vertex is controlled by 4 bones during animation.

The block size is:

block header, 4 bytes + ((id_weight, 4 bytes * 4) * vertex count in the tri-strip)

Reading the next tri-strip begins immediately after the tri-strip end flag, 14000006. The total number of tri-strips in the model is also stored in the Clump.

PSP version

Information will be added later.

This part of the article is unfinished. You can help the project by correcting and expanding it.

The geometry is an array of tri-strips, UV coordinates, prelight, and normals.

WRLD geometry

The number of vertices in a tri-strip is stored in the material row.

The first tri-strip begins immediately after the material list.

tri-strip size = vertex count * one vertex-array row

In WRLD, one vertex-array row is 10 bytes.

Each next tri-strip begins after the end of the previous one.

One vertex-array row is 10 bytes:

2b: UV.
    Coordinates are calculated the same way as on PS2.
2b: VCol.
    The prelight calculation is the same as on PS2.
2b: xCoord.
    Calculated using WRLD scaling.
2b: yCoord.
    Calculated using WRLD scaling.
2b: zCoord.
    Calculated using WRLD scaling.

Manhunt 2 MDL version

The Manhunt 2 MDL version has a similar structure on all platforms except Wii. It can be easily converted to any other version by simply transforming the format in which the game stores model geometry.

An MDL can contain either one model or several models. The reading principle is described below.

The PS2 and PSP MDL versions have the .DFF extension.

File structure

Main header

Header 1 has the typical structure used in all files on the engine. It differs only by signature. See the section about the main MDL header structure.

MDL header and model-reading cycle

This is a loop that reads each separate model.

Header size: 8 bytes.

4b: jump to the first row of the model-search cycle
4b: jump to the last row of the model-search cycle

Model-search cycle row:

4b: offset to the next sub-model
4b: offset to the previous sub-model
4b: offset to the current sub-model

When jumping to the offset of the current sub-model, the game reads one more intermediate offset, which finally leads to the geometry-reading cycle of the current sub-model.

PC version geometry

Header

Header size: 180 bytes.

4b: offset to the list of used textures.
    The first texture receives index 0, the second receives index 1, and so on.
4b: number of textures used in the model
4b: offset to bones for the current model.
    If this is 0, the model has no attached bones.
4b: unknown
4b: unknown, usually 1
12b: padding
4b: signature, 0x45D454
4b: model size
4b: unknown, usually 0
4b: number of materials in the model
4b: number of polygon indices.
    Polygon count = polygon index count / 3.
16b: 4 floats: X, Y, Z, and bounding-sphere radius
12b: 3 floats, usually 1.0, 1.0, 1.0
4b: number of vertices in the model
12b: padding
4b: stride for reading one vertex
44b: unknown data.
     Changing or zeroing these bytes has no visible effect in-game.
4b: vertex parameters.
    The game uses these parameters to determine which sections are present in the vertices,
    such as Normals, VCol, Skin, and so on.
32b: unknown data.
     Changing or zeroing these bytes has no visible effect in-game.

Material list

Located immediately after the header. Material-row length: 44 bytes.

24b: 6 floats: bounding box
2b: number of polygon indices for the current material.
    Polygon count = polygon index count for the current material / 3.
2b: texture ID
2b: number of polygon indices to skip before starting to read the required indices
    for the current material.
14b: unknown.
     Changing or zeroing these bytes has no visible effect in-game.

Polygon indices

The polygon-index table is located immediately after the material list. Each index is 2 bytes. The number of indices is specified in the header.

Vertex structure and attached parameters

Unlike DFF, where all vertex parameters are stored in separate tables, the PC-version MDL reads all parameters immediately after the vertex coordinates.

The vertex-row size is determined by the vertex parameters in the header.

Approximate structural order of vertex parameters in the PC-version MDL:

12b: 3 floats: X, Y, Z
20b: skinning:
     4 floats [4b] for weights, 4 bytes [1b] for bone IDs
8b: normals:
    3 words [2b] for X, Y, Z normal components, then 2b = 0
4b: VCol.
    Stored as BGRA, not RGBA.
8b: UV1, 2 floats
8b: UV2, 2 floats.
    Usually found in character models. This is the unwrap for bloodstain textures on the body.

Related GTA Stories formats

File formats:

.anim
.at3
.cam
.chk/.xtx
.col2
.cut
.dtz
.ifp
.img/.dir
.irx
.gxt
.lvz
.mdl
.pss
.raw/.sdt
.scm
.vb
.wrld

Tools:

Apache
Console Texture Explorer (PSP/PS2)
GTA Stories IMG Tool
GTA Stories Texture Viewer
GTA Stories Texture Explorer
GTA Stories RAW Editor
GXT Editor
JPCSP
MDL importer
MF Audio
PCSX2
PPSSPP
Stories WRLD Tool
GTA Stories Map Converter v1.0
UMD Gen
YAIE

Clone this wiki locally