Does anyone know where I can get the specifications for the .mdl "model" files used by Quake?

Experts Exchange Solution brought to you by

Enjoy your complimentary solution view.

Get every solution instantly with Premium.
Start your 7-day free trial.

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trialA 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.

4.3.0 Alias Model Header

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

scalar_t radius; // Model radius, maybe useless now.

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]

} 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.

C++

From novice to tech pro — start learning today.

Experts Exchange Solution brought to you by

Enjoy your complimentary solution view.

Get every solution instantly with Premium.
Start your 7-day free trial.

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.

4.3.0 Alias Model Header

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

scalar_t radius; // Model radius, maybe useless now.

vec3_t offsets; // (?)Inte