Quake’s model format is defined by the header file modelgen.h, which
id Software shared between its model tool and the game, and by the loader in
model.c; both are in the Quake source code, released under the GPL in 1999.
This page follows them. Numbers are little-endian 32-bit integers and floats unless a
field is marked as bytes. Unlike later formats there are no offsets: every part follows
the one before it, and a reader must walk the skins and frames in order.
Header
84 bytes (mdl_t) at the start of the file.
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | char[4] | ident | IDPO (49 44 50 4F), 0x4F504449 read as an integer |
| 4 | 4 | int32 | version | Always 6 (ALIAS_VERSION); the game stops with an error otherwise |
| 8 | 12 | float32[3] | scale | Multiplier for each packed coordinate, x, y, z |
| 20 | 12 | float32[3] | scale_origin | Added after scaling, x, y, z |
| 32 | 4 | float32 | boundingradius | Radius of a sphere around the model |
| 36 | 12 | float32[3] | eyeposition | Eye position, as set in the model tool |
| 48 | 4 | int32 | numskins | Skin entries, at least 1 |
| 52 | 4 | int32 | skinwidth | Skin width in pixels; must be a multiple of 4 |
| 56 | 4 | int32 | skinheight | Skin height in pixels, at most 480 |
| 60 | 4 | int32 | numverts | Vertices, at least 1 |
| 64 | 4 | int32 | numtris | Triangles, at least 1 |
| 68 | 4 | int32 | numframes | Frame entries, at least 1 |
| 72 | 4 | int32 | synctype | How copies of the model animate; see below |
| 76 | 4 | int32 | flags | Effect flags; see below |
| 80 | 4 | float32 | size | Average size, which the software renderer uses (times 1/11) to decide when to draw the model more simply at a distance |
The software and OpenGL versions of Quake set different limits. WinQuake allows 2000
vertices (MAXALIASVERTS). GLQuake allows 1024 vertices, 2048 triangles,
256 frames and 32 skins (MAXALIASVERTS, MAXALIASTRIS,
MAXALIASFRAMES, MAX_SKINS). Engine ports usually raise
them.
Sync type
| Value | Name | Meaning |
|---|---|---|
| 0 | ST_SYNC | Every copy of the model plays its frame and skin groups in step |
| 1 | ST_RAND | Each copy starts its groups at a random point, so a row of torches does not flicker in unison |
Flags
The flags tell the game what to draw around the model as it moves. They are the
EF_ values in model.h; any combination may be set.
| Bit | Value | Name | Effect |
|---|---|---|---|
| 0 | 1 | EF_ROCKET | Leaves a rocket trail of fire and smoke, and gives off light |
| 1 | 2 | EF_GRENADE | Leaves a smoke trail |
| 2 | 4 | EF_GIB | Leaves a blood trail |
| 3 | 8 | EF_ROTATE | Spins on the spot, for items to pick up |
| 4 | 16 | EF_TRACER | Leaves a green split trail |
| 5 | 32 | EF_ZOMGIB | Leaves a small blood trail |
| 6 | 64 | EF_TRACER2 | Leaves an orange split trail |
| 7 | 128 | EF_TRACER3 | Leaves a purple trail |
Skins
numskins entries follow the header directly. Each skin is
skinwidth × skinheight bytes, one palette index per pixel, row
by row from the top, in Quake’s 256-colour palette (the game’s palette.lmp,
not stored in the model). Each entry starts with a type:
| Type | Name | Then |
|---|---|---|
| 0 | ALIAS_SKIN_SINGLE | One picture |
| 1 | ALIAS_SKIN_GROUP | An animated group: int32 count n, then n float32 times, then n pictures |
In a group, the times are the moments, in seconds, at which each picture ends, so they increase, and each must be greater than 0. The group repeats after the last.
Texture coordinates
numverts entries of 12 bytes (stvert_t), one per vertex.
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | int32 | onseam | 0, or ALIAS_ONSEAM (0x20) for a vertex on the seam between the front and back halves of the skin |
| 4 | 4 | int32 | s | Horizontal position in the skin, in pixels |
| 8 | 4 | int32 | t | Vertical position in the skin, in pixels |
Quake skins are painted as a front view on the left half and a back view on the right.
A vertex has only one texture coordinate, so when it lies on the seam and is used by a
triangle that faces backwards, the game adds skinwidth ÷ 2 to its
s.
Triangles
numtris entries of 16 bytes (dtriangle_t).
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | int32 | facesfront | 0 if the triangle is on the back half of the skin; non-zero if it is on the front |
| 4 | 12 | int32[3] | vertindex | The three vertices, numbered from 0; the same numbers choose the texture coordinates |
Frames
numframes entries follow the triangles. Each starts with an int32 type:
| Type | Name | Then |
|---|---|---|
| 0 | ALIAS_SINGLE | One simple frame |
| 1 | ALIAS_GROUP | A frame group that plays by itself: the group header, n float32 times, then n simple frames |
Simple frame
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | vertex | bboxmin | Packed lower corner of the frame’s bounding box; its normal byte is unused |
| 4 | 4 | vertex | bboxmax | Packed upper corner; its normal byte is unused |
| 8 | 16 | char[16] | name | Frame name, such as walk1, ended by a zero byte |
| 24 | 4 × numverts | vertex[] | vertices | Every vertex of the pose |
Frame group header
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | int32 | numframes | Frames in the group, n |
| 4 | 4 | vertex | bboxmin | Lower corner of a box around every frame in the group |
| 8 | 4 | vertex | bboxmax | Upper corner of that box |
| 12 | 4 × n | float32[] | intervals | When each frame ends, in seconds; each greater than 0 |
Groups are for things that loop on their own, such as a flame. A group counts as one
entry in numframes, and the game code chooses only the group.
Packed vertex
Each vertex (trivertx_t) is 4 bytes: three bytes of position and one
normal index. The position of coordinate i is
v[i] × scale[i] + scale_origin[i].
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 3 | uint8[3] | v | Packed x, y, z, each 0 to 255 |
| 3 | 1 | uint8 | lightnormalindex | The vertex normal, 0 to 161, from the same table of 162 directions that Quake II models use |
Worked example
A torch with one 8 × 8 skin and a single looping group of two frames, with 4 vertices, would be read like this:
| Offset | Bytes | Meaning |
|---|---|---|
| 0 | 49 44 50 4F 06 00 00 00 | IDPO, version 6 |
| 48 | 01 00 00 00 08 00 00 00 08 00 00 00 | 1 skin, 8 × 8 pixels |
| 72 | 01 00 00 00 | synctype 1, random |
| 84 | 00 00 00 00 + 64 bytes | A single skin, then its 64 pixels |
| 152 | 4 × 12 bytes | Texture coordinates |
| 200 | numtris × 16 bytes | Triangles |
| … | 01 00 00 00 02 00 00 00 | Frame type 1, a group of 2 frames |
| … | 8 bytes, then CD CC CC 3D CD CC 4C 3E | Group box, then times 0.1 s and 0.2 s |
| … | 2 × (24 + 16) bytes | Two simple frames of 4 vertices each |