We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now

x

# .MDL File Spec

on
Medium Priority
385 Views
Does anyone know where I can get the specifications for the .mdl "model" files used by Quake?
Comment
Watch Question

## View Solution Only

Commented:
A Model file contains:

1.A skin texture, that describes the color of the skin and clothes of the creature, or whatever it can be wearing.
2.A list of skin vertices, that are just the position of vertices on the skin texture.
3.A list of triangles, the describe the general shape of the model.
4.A list of animation frames.
Each frame holds a list of the 3D vertices and the index of the precalculated vertex normal.

Here is the format of the .MDL file header:

typedef struct
{ long id;                     // 0x4F504449 = "IDPO"
long version;                // Version = 3
vec3_t scale;                // Scale factor, for x,y,z
vec3_t origin;               // Model origin: point for x=0,y=0,z=0
vec3_t offsets;              // (?)Inte

Not the solution you were looking for? Getting a personalized solution is easy.

Commented:
This got cut off.  reposting...

Commented:

A Model file contains:

1.A skin texture, that describes the color of the skin and clothes of the creature, or whatever it can be wearing.
2.A list of skin vertices, that are just the position of vertices on the skin texture.
3.A list of triangles, the describe the general shape of the model.
4.A list of animation frames.
Each frame holds a list of the 3D vertices and the index of the precalculated vertex normal.

Here is the format of the .MDL file header:

typedef struct
{ long id;                     // 0x4F504449 = "IDPO"
long version;                // Version = 3
vec3_t scale;                // Scale factor, for x,y,z
vec3_t origin;               // Model origin: point for x=0,y=0,z=0
vec3_t offsets;              // (?)Integer offsets
long numskins ;              // the number of skin textures
long skinwidth;              // Width of skin texture
//           must be multiple of 8
long skinheight;             // Height of skin texture
//           must be multiple of 8
long numverts;               // Number of vertices
long numtris;                // Number of triangles surfaces
long numframes;              // Number of frames
long unknown;                // 0
} mdl_t;

The size of this header is 0x4C bytes (76).

4.3.1 Alias Model Skin

This is simply a flat picture, stored as a collection of 8-bit color indexes.

At offset baseskin = 0x4C in the .MDL file you will find:

typedef struct
{ long        unknown;         // Always 0
u_char skin[skinwidth*skinheight]; // the skin picture
} skin_t skins[numskins];      // numskins pictures

There might be more than on skin texture, as indicated by numskins. They all have the same size.

It is suspected that color index 0xFF represents a transparent area, like in level textures.

Note that the skin pictures are a bit particular: as a matter of fact, they are not made of one piece, but of at least two pieces: one for the front of the model,
the other for the back of the model.

Actually, there may be as many pieces as there are independent parts in the model, and even more for special animations.

Note that the back skin of a given sprite part must be on the same height, but translated width/2, relatively to the front skin part. The back skin part must
also be inverted along the vertical axis.

This design is used to allow the correct rendering of a seamless skin texture, using Skin Vertices with onseam == 1, on the skin border.

4.3.2 Alias Model Skin Vertices

A .MDL file is made of a list of vertices. To each of these vertices corresponds a 3D position, a normal, and a position on the skin picture, for texture
mapping.

The list of skin vertices indicates only the position on texture picture, not the 3D position. That's because for a given vertex, the position on skin is constant,
while the position in 3D space varies with the animation.

The list of skin vertices is made of these structures:

typedef struct
{ long onseam;                 // 0 or 1
long s;                      // position, horizontally
//  in range [0,skinwidth[
long t;                      // position, vertically
//  in range [0,skinheight[
} stvert_t;

onseam is a boolean, and if non zero it means that the vertex is on the boundary between the skin part that is applied on the front of the sprite, and the skin
part that is applied on the back of the sprites (i.e. on the edge).

s and t are (X,Y) position on the skin picture.

At offset baseverts = baseskin + (4 + skinwidth * skinheight) * numskins in the .MDL file, you will find:

stvert_t vertices[numverts];

4.3.3 Alias Model Triangles

An Alias Model is made of a set of triangle facets, with vertices at the boundaries.

Only vertices index are stored in triangles. the normal vector of the surface is reconstituted from the vertex position.

Here is the structure of triangles:

typedef struct
{ long facesfront;             // boolean
long vertices[3];            // Index of 3 triangle vertices
// in range [0,numverts[
} itriangle_t;

The boolean facesfront indicates if the triangle is part of the front or the back skin. 1 means that it is on the front skin, 0 means that it is on the back skin,
so any skin vertex that is on seam must have its horizontal value increased by skinwidth/2, so as to find its correct position on the back skin.

Note that the index of a given vertex is the same in the skin vertex table and in the frame table.

At offset basetri = baseverts + numverts * sizeof(stvert_t) in the .MDL file, you will find:

itriangle_t triangles[numtris];

4.3.4 Alias Model Frames

An Alias Model contains a set of animation frames, which can be used in relation with the behavior of the modeled entity, so as to display it in various
postures (walking, attacking, spreading its guts all over the place...).

The frame vertices

Each frame vertex is defined by a 3D position and a normal for each of the vertices in the model.

typedef struct
{ u_char packedposition[3];    // X,Y,Z coordinate, packed on 0-255
u_char lightnormalindex;     // index of the vertex normal
} trivertx_t;

To get the real X coordinate, from the packed coordinates, multiply the X coordinate by the X scaling factor, and add the X origin. Both the scaling factor
and the origin can be found in the Model Header.

The currently suggested formula for calculating positions is:

vec3_t real[i] = ( scale[i] *  packedposition[i] ) + origin[i]

Where scale, and origin can be found as vectors in the Model Header.

The Light Normal Indexes

The lightnormalindex field is used to represent the vertex normal vector. The normal vector of a given vertex is the average of the normal vectors of all
the faces that contain this vertex.

This information is necessary to calculate the Gouraud shading of the faces, but actually a crude estimation of the actual vertex normal is sufficient. That's why,
to save space and to reduce the number of computations needed, it has been chosen to approximate each vertex normal.

The ordinary values of lightnormalindex are comprised between 0 and 161, and directly map into the index of one of the 162 precalculated normal
vectors that can be found in Appendix B.

However, value 255 of lightnormalindex is a bit special, in the sense that a vertex taged with that value will always look dark, whatever the light level
around.

Experiments show that value 255 should be used for dull object, while values from 162 to 254 could be used for bright object, however it could just be an
artifact, don't rely on it.

The frames

The beginning of the frames can be found in the .MDL file, at offset baseframes = basetri + numtris * sizeof(itriangle_t);.

The size of each frames is sizeframe = 0xC + numverts * trivertx_t;.

The frame fram can be found in the .MDL file at offset baseframe = baseframes + sizeframe * fram, with fram in the range [0,numframes[.

Each frame is a structure made of a header and an array:

typedef struct
{ long       unknown;          // Always zero
trivertx_t min;              // minimum values of X,Y,Z
trivertx_t max;              // maximum values of X,Y,Z
trivertx_t frame[numverts];  // array of vertices
} frame_t;

The number of vertices is numverts, and to each of the vertex declared here corresponds a Skin Vertex with the same index.

The frame header contains two vertex definitions, min and max, that define a bounding box around the whole frame: all the other vertices must be inside that
bounding box.

However, that bounding box is only used for collision detection, so if you make it smaller than it should be the model will still display fine, but you can get very
close to it before hitting it.

To get the floating point values corresponding to min and max, treat them as if they were ordinary vertex positions.

Unknown fields

The first filed of the header is always zero, and there's no explanation for it. It cannot be a time stamp, since frame animations is in fact coded in the Code
lump.

The lightnormalindex of min and max have irrelevant values, and are apparently not used. They only pad the structure to 4 bytes.

Commented:
Thanks a lot, could you now just send me that info by e-mail to waldroni@lr.net?  That would be appreciated
##### Thanks for using Experts Exchange.

• View three pieces of content (articles, solutions, posts, and videos)
• Ask the experts questions (counted toward content limit)
• Customize your dashboard and profile