Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

.MDL File Spec

Posted on 1997-08-26
4
Medium Priority
?
347 Views
Last Modified: 2012-06-21
Does anyone know where I can get the specifications for the .mdl "model" files used by Quake?
0
Comment
Question by:IsaacW
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
4 Comments
 
LVL 4

Accepted Solution

by:
md041797 earned 400 total points
ID: 1168174
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.

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
0
 
LVL 4

Expert Comment

by:md041797
ID: 1168175
This got cut off.  reposting...
0
 
LVL 4

Expert Comment

by:md041797
ID: 1168176
Find more info at http://www.cybernet.dk/users/jensh/quake/qkspec31.html#MD1


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.

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]; // 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.

0
 

Author Comment

by:IsaacW
ID: 1168177
Thanks a lot, could you now just send me that info by e-mail to waldroni@lr.net?  That would be appreciated
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses

670 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question