Document last updated 2006 Jun 29.

Much of the information was extracted from the header files provided in the Q3AToolsSource package from Id Software, Inc.

Disclaimer:

I make no claims as to the accuracy of the information provided within. I have made attempts to be as accurate as possible, but the information herein is still provided "as-is". I am not affiliated with Id Software, Inc., nor RSA Data Security, Inc. Copyrights and trademarks are under the control of their respective holders.

Introduction:

MD3 is the 3D data format used in Quake 3: Arena and derivative games (Q3 mods, Return to Castle Wolfenstein, Jedi Knights 2, etc.). The file format is used to describe 3D objects in the game that move and interact with players, other objects, and/or the environment. Animation is recorded by describing the position of every vertex in the model for each frame of animation. This style of animation may also be known as "mesh deformation", "vertex animation", ???.

A separate file format is used to describe maps, the environment of the game: a source MAP file that compiles into a BSP file. This document does not cover the MAP nor BSP file formats.

Id Software, Inc., introduced a new 3D data format that appeared in Quake 3 PR 1.29(?), called MD4. The MD4 format uses "bones animation", which describes how groups of vertex moves together around together in terms of rotation and translation, instead of describing every the positon of every vertex. The animation style in MD4 may also be known as "skeleton animation", ???.

This newer file format from Id Software, Inc., should not be confused with RSA Data Security, Inc., Message Digest 4 algorithm, also called MD4. One is a file format, the other is an algorithm ("math formula"), but they are, unfortunately, both called "MD4". Furthermore, to add to the confusion, the Quake series uses the MD4 algorithm (slightly modified?) as a checksum algorithm for network error-checking and pak file integrity (including the MD4 files).

This document does not cover the MD4 file format.

The Quake series was developed and run on IA32 (x86) machines, using C. The file format shows many evidences of x86-isms and C-isms (expected byte order, word sizes, data type names, etc.). Some of these isms spill over into this document.

The MD3 format is presented here from a larger scope to smaller ones.

Data type indicator:

Datatypename/purposeDescription
U8char8-bit unsigned octet (character).
S16shortlittle-endian signed 16-bit integer.
S32intlittle-endian signed 32-bit integer.
F32floatIEEE-754 32-bit floating-point.
VEC3vec3_ttriplet of F32 in sequence (read 4 octets, make float, read 4, make float, read 4, make float), describing a 3-space vector.
*[]indicates sequential repeat count (homogenous aggregation, array, vector), as in "U8 * 16" to mean a 16-octet array (i.e. character string).
-file/array offset of which to make special note.
!aggregate complex data that should be described elsewhere.

MD3:

Datatypename/purposeDescription
-MD3_STARToffset of MD3 object. Usually 0, but not guaranteed.
S32IDENTMagic number. As a string of 4 octets, reads "IDP3"; as unsigned little-endian 1367369843 (0x51806873); as unsigned big-endian 1936228433 (0x73688051).
S32VERSIONMD3 version number, latest known is 15, but use the constant MD3_VERSION
U8 * MAX_QPATHNAMEMD3 name, usually its pathname in the PK3. ASCII character string, NUL-terminated (C-style). Current value of MAX_QPATH is 64.
S32FLAGS???
S32NUM_FRAMESNumber of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024.
S32NUM_TAGSNumber of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16.
S32NUM_SURFACESNumber of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32.
S32NUM_SKINSNumber of Skin objects. I should note that I have not seen an MD3 using this particular field for anything; this appears to be an artifact from the Quake 2 MD2 format. Surface objects have their own Shader field.
S32OFS_FRAMESRelative offset from start of MD3 object where Frame objects start. The Frame objects are written sequentially, that is, when you read one Frame object, you do not need to seek() for the next object.
S32OFS_TAGSRelative offset from start of MD3 where Tag objects start. Similarly written sequentially.
S32OFS_SURFACESRelative offset from start of MD3 where Surface objects start. Again, written sequentially.
S32OFS_EOFRelative offset from start of MD3 to the end of the MD3 object. Note there is no offset for Skin objects.
!(Frame)The array of Frame objects usually starts immediately afterwards, but OFS_FRAMES should be used.
!(Tag)The array of Tag objects usually starts immediately after FRAMES, but OFS_TAGS should be used.
!(Surface)The array of Surface objects usually start after TAGS, but OFS_SURFACES should be used.
-MD3_ENDEnd of MD3 object. Should match MD3_START.

Frame:

(member of MD3)
Datatypename/purposeDescription
VEC3MIN_BOUNDSFirst corner of the bounding box.
VEC3MAX_BOUNDSSecond corner of the bounding box.
VEC3LOCAL_ORIGINLocal origin, usually (0, 0, 0).
F32RADIUSRadius of bounding sphere.
U8 * 16NAMEName of Frame. ASCII character string, NUL-terminated (C-style).

Tag:

(member of MD3)
Datatypename/purposeDescription
U8 * MAX_QPATHNAMEName of Tag object. ASCII character string, NUL-terminated (C-style). Current value of MAX_QPATH is 64.
VEC3ORIGINCoordinates of Tag object.
VEC3 * 3AXISOrientation of Tag object. (XXX: more descr)

Surface:

(member of MD3)
Datatypename/purposeDescription
-SURFACE_STARTOffset relative to start of MD3 object.
S32IDENTMagic number. As a string of 4 octets, reads "IDP3"; as unsigned little-endian 1367369843 (0x51806873); as unsigned big-endian 1936228433 (0x73688051).
U8 * MAX_QPATHNAMEName of Surface object. ASCII character string, NUL-terminated (C-style). Current value of MAX_QPATH is 64.
S32FLAGSflags?
S32NUM_FRAMESNumber of animation frames. This should match NUM_FRAMES in the MD3 header.
S32NUM_SHADERSNumber of Shader objects defined in this Surface, with a limit of MD3_MAX_SHADERS. Current value of MD3_MAX_SHADERS is 256.
S32NUM_VERTSNumber of Vertex objects defined in this Surface, up to MD3_MAX_VERTS. Current value of MD3_MAX_VERTS is 4096.
S32NUM_TRIANGLESNumber of Triangle objects defined in this Surface, maximum of MD3_MAX_TRIANGLES. Current value of MD3_MAX_TRIANGLES is 8192.
S32OFS_TRIANGLESRelative offset from SURFACE_START where the list of Triangle objects starts.
S32OFS_SHADERSRelative offset from SURFACE_START where the list of Shader objects starts.
S32OFS_STRelative offset from SURFACE_START where the list of St objects (Texture Coordinates, S-T vertices) starts.
S32OFS_XYZNORMALRelative offset from SURFACE_START where the list of Vertex objects (X-Y-Z-N vertices) starts.
S32OFS_ENDRelative offset from SURFACE_START to where the Surface object ends.
!(Shader)List of Shader objects usually starts immediate after the Surface header, but use OFS_SHADERS (or rather, OFS_SHADERS+OFS_SURFACES for files).
!(Triangle)List of Triangle objects usually starts immedately after the list of Shader objects, but use OFS_TRIANGLES (+ OFS_SURFACES).
!(St)List of St objects usually starts immedately after the list of Triangle objects, but use OFS_ST (+ OFS_SURFACES).
!(XYZNormal)List of Vertex objects usually starts immediate after the list of St objects, but use OFS_XYZNORMALS (+ OFS_SURFACES). The total number of objects is (NUM_FRAMES * NUM_VERTS). One set of NUM_VERTS Vertex objects describes the Surface in one frame of animation; the first NUM_VERTS Vertex objects describes the Surface in the first frame of animation, the second NUM_VERTEX Vertex objects describes the Surface in the second frame of animation, and so forth.
-SURFACE_ENDEnd of Surface object. Should match OFS_END.

Shader:

(member of Surface) ;
Datatypename/purposeDescription
U8 * MAX_QPATHNAMEPathname of shader in the PK3. ASCII character string, NUL-terminated (C-style). Current value of MAX_QPATH is 64.
S32SHADER_INDEXShader index number. No idea how this is allocated, but presumably in sequential order of definiton.

Triangle:

(member of Surface)
Datatypename/purposeDescription
S32 * 3INDEXESList of offset values into the list of Vertex objects that constitute the corners of the Triangle object. Vertex numbers are used instead of actual coordinates, as the coordinates are implicit in the Vertex object. (XXX: does order matter?)

TexCoord:

(member of Surface) (St)
Datatypename/purposeDescription
F32 * 2STS-T (U-V?) texture coordinate. I am a little fuzzy on the whole notion of texture coordinates. Values tend to stay within [0.0 .. 1.0], suggesting (0,0) is one corner of the shader/texture and (1,1) is the other far corner of the shader/texture, with values outside the range indicating wraparounds/repeats. Again, I am fuzzy on this notion.

Vertex:

(member of Surface) (XYZNormal)
Datatypename/purposeDescription
S16XX-coordinate in left-handed 3-space, scaled down by factor MD3_XYZ_SCALE. Current value of MD3_XYZ_SCALE is (1.0/64). (multiply by MD3_XYZ_SCALE to obtain original coordinate value)
S16YY-coordinate in left-handed 3-space, scaled down by factor MD3_XYZ_SCALE. Current value of MD3_XYZ_SCALE is (1.0/64). (multiply by MD3_XYZ_SCALE to obtain original coordinate value)
S16ZZ-coordinate in left-handed 3-space, scaled down by factor MD3_XYZ_SCALE. Current value of MD3_XYZ_SCALE is (1.0/64). (multiply by MD3_XYZ_SCALE to obtain original coordinate value)
S16NORMALEncoded normal vector. See Normals.

Tags:

Tags are volumeless vectors. Tags are primarily used in aligning separate MD3 objects in-game. For example, the Tag object in the railgun model is called 'tag_weapon', and the position (and rotation) of this Tag gets aligned with those of the Tag named 'tag_weapon' in the player model, dragging the rest of the railgun model over with the [railgun's] Tag object. The railgun model follows its Tag positions and rotations, which in turn follows the positions and rotations of the player model Tag object (most noticeable in taunt animation). Tags are also used to line up the torso with the legs, and the head with the torso, and so on.

Normals:

Encoding:

The encoded normal vector uses a spherical coordinate system. Since the normal vector is, by definition, a length of one, only the angles need to be recorded. Each angle is constrained within [0, 255], so as to fit in one octet. A normal vector encodes into 16 bits. (XXX: more blah)

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
lat (latitude) lng (longitude)

(Code in q3tools/common/mathlib.c:NormalToLatLong)
lng <- atan2 ( y / x) * 255 / (2 * pi)
lat <- acos ( z ) * 255 / (2 * pi)
lng <- lower 8 bits of lng
lat <- lower 8 bits of lat
normal <- (lat shift-left 8) binary-or (lng)

Two special vectors are the ones that point up and point down, as these values for z result in a singularity for acos. The special case of straight-up is:
normal <- 0

And the special case of straight down is:
lat <- 0
lng <- 128
normal <- (lat shift-left 8) binary-or (lng)

or, shorter:
normal <- 32768

Decoding:

(Code in q3tools/q3map/misc_model.c:InsertMD3Model)
lat <- ((normal shift-right 8) binary-and 255) * (2 * pi ) / 255
lng <- (normal binary-and 255) * (2 * pi) / 255
x <- cos ( lat ) * sin ( lng )
y <- sin ( lat ) * sin ( lng )
z <- cos ( lng )

See Also (Links):

.md2 File Format Specification (local mirror: md2-schoenblum.html)


-- PhaethonH (phaethon@linux.ucla.edu)