MDL file format (FSX)

From FSDeveloper Wiki
Jump to: navigation, search

This document describes the structure of FsX MDL files. This document is mainly useful for people who want to read or decode these MDL files in a tool.

Compared to the Fs2004 MDL format there are quite a few changes. One of the biggest is that aircraft and scenery MDL files now have the same format. At the moment the knowledge in this document mainly comes from evaluating simple scenery objects, so it is certainly not yet complete. If you have anything to add, please do so.

MDL sections

The MDL file uses the RIFF format, this means that the file consists of different sections. Each section starts with a four character label, followed by the size of the content in bytes (this size is thus without the length of the header itself). The table below shows how the different section can be nested.

Name Description Parent section
RIFF General RIFF section (covers entire file) None
MDLN Object friendly name RIFF
PARA Parameters Block RIFF
CRAS Object crashbox RIFF
BBOX Object boundingbox RIFF
RADI Object radius RIFF
MDLD Exterior Node Root RIFF
TEXT Texture list MDLD
MATE Material list MDLD
INDE Triangle index list MDLD
VERB Vertex buffer list MDLD
VERT Vertex list VERB
TANS Tangent Space list (?) VERB
BMAP Bone Map (?) VERB
SKIN Skin weight list (?) VERB
TRAN Static transformation matrices MDLD
AMAP Animation Map MDLD
SCEN Scenegraph Node Root MDLD
SGAL Scenegraph Animation Linkage MDLD
SGVL Scenegraph Visibility Linkage MDLD
SGJC Scenegraph Joint Constraints MDLD
SGBR Scenegraph Bone Reference MDLD
PART Part list LODE
ANIB Animation Block MDLD
PLAL Platform List MDLD
PLAT Platform PLAL
REFL Attachpoint List MDLD
REFP Attach point REFL
ATTO Attached objects list MDLD
SHAM Shadow Model Root RIFF

The main RIFF section itself has one additional parameter, this is a four character string that indicates the type of RIFF MDL file. For an FsX MDL file the value should always be MDLX.

AMAP,SCEN,SGAL,SGJC,SGBR needs same amount of element.

The following subsection show more details about the content of these different sections.


This the FS MDL object header. It seems to contain of an integer that always has the value of 123456 (purpose unnknown) and a float value of 10 that the BglScan utility identifies as the Model Version.


This section stores the object GUID. The GUID is stored in the following parts:

unsigned long data1
unsigned short data2
unsigned short data3
unsigned char data4[8]

In hexadecimal form the GUID is then written as:



This section contains a string with the friendly name of the object.


Unknown at the moment.


This is the ParamsBlock section, containing parameter block data.


This section stores the crashtree of the object. It has first two unknown integer values, then there are 3 float values giving the front lower left corner of the object, then 3 float values giving the length, height, and width, then the number of nodes in the tree as integer, and then the branches of the tree, which are all integer values (instead of bytes which had been used in FS2004). If the value of a cell is -1 the cell is solid, if it is -2 the cell is free, every other value is the offset of the octet of the next lower node in the branch.


This section stores the bounding box of the object in the following format:

float xmin
float ymin
float zmin
float xmax
float ymax
float zmax


This section stores the radius of the object as a float.


This section contains the actual data defining the object.


This section contains the list of all textures of the object. Each texture is given as a 64 character string. Unlike the Fs2004 format no additional parameters are stored in the texture list, only the texture name.


This section contains a list of all materials of the object. Each material is defined by a 120 byte long record. The definition of this record is given below:

int    material_flags
int    material_flags_2
int    diffuse_texture_index
int    detail_texture_index
int    bumpmap_texture_index
int    specular_texture_index
int    emissive_texture_index
int    reflection_texture_index
int    fresnel_texture_index
float  diffuse_color_R
float  diffuse_color_G
float  diffuse_color_B
float  diffuse_color_A
float  specular_color_R
float  specular_color_G
float  specular_color_B
float  specular_color_A
float  specular_power
float  detail_map_scale
float  bump_map_scale
float  reflection_scale 
float  precipitation_offset
float  specular_map_power_scale
float  specular_bloom_floor
float  ambient_light_scale
int    source_blend
int    destination_blend
int    alpha_test_function
float  alpha_test_threshold
float  final_alpha_multiply

material_flags is a bitmask:

0x00000001: material is specular
0x00000002: material has a diffuse texture (diffuse color is only used as a fallback)
0x00000004: material has a bumpmap texture
0x00000008: material has a specular texture
0x00000010: material has a detail texture
0x00000020: material has a reflection texture
0x00000040: Use global environment map as reflection
0x00000080: material has an emissive texture (for night)
0x00000100: material has a FresnelRamp texture: Reflection
0x00000200: material has a FresnelRamp texture: Diffuse
0x00000400: material has a FresnelRamp texture: Specular
0x00000800: Apply offset to start of Precipitation
0x00001000: Take into account Precipitation
0x00002000: Blend environment by inverse of diffuse alpha
0x00004000: Blend environment by specular map alpha
0x00008000: Assume vertical normal
0x00010000: Z-Write alpha
0x00020000: No Z Write
0x00040000: Bloom material by copying
0x00080000: Bloom material modulating by alpha
0x00100000: Volume shadow
0x00200000: No shadow
0x00400000: Z-Test Alpha
0x00800000: Emissive Mode: Blend
0x01000000: Set final alpha value at render time
0x04000000: Skinned mesh
0x08000000: Allow bloom
0x10000000: Allow emissive bloom
0x20000000: Blend diffuse by diffuse alpha
0x40000000: Blend diffuse by inverse of specular map alpha
0x80000000: Prelit vertices

material_flags_2 is a bitmask:

0x00000001: Blend constant
0x00000002: Force Texture Address Wrap
0x00000004: Force Texture Address Clamp
0x00000008: Double sided
0x00000010: Emissive Mode: AdditiveNightOnlyUserControlled
0x00000020: Emissive Mode: BlendUserControlled
0x00000040: Emissive Mode: MultiplyBlend
0x00000080: Emissive Mode: MultiplyBlendUserControlled
0x00000100: Emissive Mode: Additive
0x00000200: Emissive Mode: AdditiveUserControlled

The source_blend and destination_blend parameters seem to use the following enumeration:

 1 zero
 2 one
 3 srcColor
 4 invSrcColor
 5 srcAlpha
 6 invSrcAlpha
 7 destAlpha
 8 invDestAlpha
 9 destColor
10 invDestColor

The alpha_test_function parameter seems to use the following enumeration:

1 never
2 less
3 equal
4 lessEqual
5 greater
6 notEqual
7 greaterEqual
8 always


This section contains of a lot of triangles, each given by three short values. These values are the indices of the vertices to use. In the PART list an offset is specified for these indices, so the first vertex of a part seems to be zero always.


This section gives the vertex buffer of the object.


This section contains a list of vertices of the object. Each vertex is given by a 32 byte record. The definition of this record is given below:

float position_x
float position_y
float position_z
float normal_x
float normal_y
float normal_z
float texture_mapping_x
float texture_mapping_y

Multiple VERT sections followed by correspondent TANS and optional BREF / SKIN sections can be defined inside VERB buffer.


This section contains tangent space list data for correspondent VERT section. The first parameter of this list is UINT, which represents tangent space list index within VERB buffer (0x00000000 for first section, 0x00000001 for second and so on). Then for each vertex in correspondent VERT section two vectors are given that define a plane that is tangent to the vertex (these vectors are defined as three floats). This data only seems to be set for textured polygons, untextured polygons have null vectors defined here.


This section contains bone map reference data for correspondent VERT section. The first parameter of this list is UINT, which represents bone map index within VERB buffer. The rest, is an array of long values, which is mapped to nodes with SGBR section (BMAP[i]==SGBR[node index]).


This section contains skin weights and bone index list reference data for correspondent VERT section. The first parameter of this list is UINT, which represents skin weight list index within VERB buffer. The rest represents skin weight data for each vertex in correspondent VERT section. Format is: 4 unsigned chars for bone index list in BMAP section, then 4 unsigned chars for bone weight list (0-255 mapped to 0.0-1.0).


This section stores the static transformation matrices. Each matrix is defined by 16 floats. For a definition of these matrices see the [1]


Visualization List: This section contains the list of the visualization state sections of the object: Default visible / Not default visible.


Visualization Default Sim: This section contains the "Sim" and "Lag" parameters string of the visualization state of the object visible by default, with the format: "Variable#Units[#Bias][#Lag]" ([] means optional parameters). Please refer to "modeldef.xml" file on FSX SDK.


Visualization Not Default Sim: Same of VISS above, refering the object NOT visible by default.


Visualization Default Code: This section contains the "Lag" and "Code" parameters string of the visualization state of the object visible by default, with the format: "[#Lag#]Code" ([] means optional parameters). Observe that CR(0x0D), LF(0x0A) and SPACE(0x20) are part of the string. Please refer to "modeldef.xml" file on FSX SDK.


Visualization Not Default Code: Same of VISC above, refering the object NOT visible by default.


int  Transformation type  (1= Static Node , 2=Animated Node)
int  TRAN section

This section contains animation map data. It contains the same amount of entries as the scenegraph and each entry consists of two integers. The first one is the transformation type, 1 for static nodes(-1 in SGAL section), 2 for animated nodes, while the last one points to the transformation matrix from the TRAN section to use.


This section defines the scenegraph this is refered to from the PART section. Each entry contains the following values:

short child_node_index
short peer_node_index
short amap_offset
short unknown (usually 0)

This section defines the tree for how the parts are linked. (There is a data in PART section to point which scenegraph to use.) To define the tree also uses the number count from the data set from top -1 means no more data.

Example1 :

Number=0 , child_node_index=1 ,peer_node_index=-1
Number=1 , child_node_index=-1 ,peer_node_index=-1

Example2 :


Number=0 , child_node_index=1 ,peer_node_index=-1
Number=1 , child_node_index=-1 ,peer_node_index=2
Number=2 , child_node_index=-1 ,peer_node_index=-1


This is the scenegraph animation linkage section. The value is -1 for no animation or else the number of the animation to use. This animation is defined in the XANS section.


This is the scenegraph visibility linkage section.


This scenegraph section contains IK joint constraint data.


This is the scenegraph bone reference section. One short value for each node, which is equal to BMAP values, or -1 if node is not a bone.


This section defines the LOD table of the object. It is followed by a LODE section for each LOD level in the object.


This section defines a LOD level for the object. It contains an int that indicates the value of this LOD. The default value if only one LOD is used in the object is 100. This section is followed by a PART section for each part in this LOD level.


This section defines an object part. The part definition contains the following parameters:

int  type (1 = Triangle List, 2 = Triangle Fan, 3 = Triangle Strip)
int  scenegraph_reference
int  material_index
int  vertex_buffer_index
int  vertex_offset
int  vertex_count  
int  index_offset
int  index_count
int  mouse_rectangle_ref (?)

vertex_buffer_index tells which VERT structure inside the VERB section is to be used.

The index_offset and index_count are given in indices, so it should be divided by three to get a triangle offset and count.


Animation block section. Data type is uint8.


The animation header. It only contains a version number as a float.


data from modeldef.xml

 byte guid[16]
 single animation length?
 char type[16] "Sim"
 char typeParam[9] "AutoPlay"
= XANS =

This section contains the following data:

 int animation type
 int animation ID
 single animation length
== XANK ==

This section contains the actual keys of the animation. Each key consists of:

 byte type
 single time

Then for translations:

 single x
 single y
 single z

Or for rotations (type 4):

 single q0
 single q1
 single q2
 single q3


Platform list. Contains a number of PLAT entries.



int  surface
  8=SNOW, 9=ICE, 10=URBAN, 11=FOREST
int  scenegraph_reference
int  number_of_vertices (usually 3)
int  (x, y, z) * number_of_vertices


Attachpoint list. Contains a number of REFP entries.



int  scenegraph_reference
int  name_length
byte name (zero-terminated)


The ATTO section defines the attached objects and relates them to a certain attachpoint (by name). Below the data structure for the different types of attached objects are listed. Both effects and library objects have the following basic information:

 dd unknown
 dw type
 dw length
 dw offset attachpoint name
 dw unknown
 dd unknown
 dd unknown
 dd unknown
 dd unknown


Effects have type 4. The "header" is followed by a string that contains the effect filename and the parameters. These are separated by null characters. After that is the string with the attachpoint name that this effect uses.

Library object

Library objects have type 2. The "header" is followed by the GUID of the object. Following the GUID is the scale of the object as a single precision float. After that is the string with the attachpoint name that this effect uses.


This section contains the model used for shadow calculations. It can contain the same section as the normal external model.