MD2 (file format)

MD2 is a model format used by id Software's id Tech 2 engine and is thus used by Quake II as well as many other games, most of them using this engine, including SiN and Soldier of Fortune. The format is primarily used for animated player models although it can also be used for static models. Unlike more recent character model formats, MD2 animations are achieved via keyframes on a per-vertex level; the keyframes are stored within the model file and the engine interpolates between them to create a smooth animation.

Contents

File format

An MD2 file begins with a fixed length header followed by static model data such as texture coordinates. Dynamic data such as vertices and normals are stored within a number of file chunks called frames (or key-frames) which each have their own short headers.

In defining the file structure several data types will be referred to.

int (4 bytes), short (2 bytes), and char (1 byte)

MD2 Header

Offset Data type Name Description
0 int ident Magic number. Must be equal to "IDP2"
4 int version MD2 version. Must be equal to 8
8 int skinwidth Width of the texture
12 int skinheight Height of the texture
16 int framesize Size of one frame in bytes
20 int num_skins Number of textures
24 int num_xyz Number of vertices
28 int num_st Number of texture coordinates
32 int num_tris Number of triangles
36 int num_glcmds Number of OpenGL commands
40 int num_frames Total number of frames
44 int ofs_skins Offset to skin names (each skin name is an unsigned char[64] and are null terminated)
48 int ofs_st Offset to s-t texture coordinates
52 int ofs_tris Offset to triangles
56 int ofs_frames Offset to frame data
60 int ofs_glcmds Offset to OpenGL commands
64 int ofs_end Offset to end of file

At the offset ofs_st there are num_st of this structure:

Data type Name
short s
short t

The texture coordinates are multiplied by the texture's size and so are always integers.

To recover the floating-point texture coordinates as used by common 3D display API's such as OpenGl, divide the texture coordinates by the respective size dimensions of the texture:

 sfloat = (float)s / texturewidth
 tfloat = (float)t / textureheight

At offset ofs_tris there are num_tris of the following structure

 short vertexindex[3]
 short textureindex[3]

These are indexes to the vertexs and texture coordinates and tell the engine reading the file how to build primitives from the data.

At offset ofs_frames frame data is stored, each frame has a short header followed by a number of vertex and Surface-normal indexes, the frame header structure is like this:

 float scale[3]
 float translate[3]
 char name[16]

Then there is num_xyz of this structure:

 unsigned char v[3]
 unsigned char lightnormalindex

Each vertex is stored as an integer. To recover the floating-point vertex coordinates, the MD2 reader multiplies each coordinate by the scaling vector for the current frame and then adds the frame's translation vector:

 float x = (v[0] * scale[0]) + translate[0]
 float y = (v[1] * scale[1]) + translate[1]
 float z = (v[2] * scale[2]) + translate[2]

The frames scale and translation vector can be found in the frame's header.

Example

This is an example of how to decompress a single frame and display it. Its not in any specific programming language to try and make it easy for every one to interpret. variables have $ before them and their type

 loop while $(int)index is less than $(int)num_tris
 
   texture_function_s $(float)texture_coordinates[ $(short)triangle[ $(int)index ].textureindex[0] ].s / skinwidth
   texture_function_t $(float)texture_coordinates[ $(short)triangle[ $(int)index ].textureindex[0] ].t / skinheight
 
   normal_function $(unsigned char)vertex[ $(short)triangle[ $(int)index ].vertexindex[0] ].lightnormalindex
 
   vertex_function_x ($(unsigned char)vertex[ $(short)triangle[ $(int)index ].vertexindex[0] ].v[0] * scale[0]) + translate[0]
   vertex_function_y ($(unsigned char)vertex[ $(short)triangle[ $(int)index ].vertexindex[0] ].v[1] * scale[1]) + translate[1]
   vertex_function_z ($(unsigned char)vertex[ $(short)triangle[ $(int)index ].vertexindex[0] ].v[2] * scale[2]) + translate[2]
 
   $(int)index = $(int)index + 1
 end loop

See also

Resources