MD2: Difference between revisions
No edit summary |
|||
Line 1: | Line 1: | ||
= .md2 File Format Specification = | == .md2 File Format Specification == | ||
'''by''' [mailto:dansch@hops.cs.jhu.edu Daniel E. Schoenblum] | '''by''' [mailto:dansch@hops.cs.jhu.edu Daniel E. Schoenblum] | ||
== INTRO == | == INTRO == | ||
This page will try and give some sort of technical documentation on the Quake2 model format (.md2). | This page will try and give some sort of technical documentation on the Quake2 model format (.md2). | ||
Line 10: | Line 12: | ||
== HEADER == | == HEADER == | ||
The header comes right at the start of the file. The information in the header is needed to load different parts of the model. | The header comes right at the start of the file. The information in the header is needed to load different parts of the model. | ||
< | <syntaxhighlight lang="c"> | ||
typedef struct | typedef struct | ||
{ | { | ||
int | int magic; | ||
int | int version; | ||
int | int skinWidth; | ||
int | int skinHeight; | ||
int | int frameSize; | ||
int | int numSkins; | ||
int | int numVertices; | ||
int | int numTexCoords; | ||
int | int numTriangles; | ||
int | int numGlCommands; | ||
int | int numFrames; | ||
int | int offsetSkins; | ||
int | int offsetTexCoords; | ||
int | int offsetTriangles; | ||
int | int offsetFrames; | ||
int | int offsetGlCommands; | ||
int | int offsetEnd; | ||
} model_t; | } model_t; | ||
</ | </syntaxhighlight> | ||
=== | === magic === | ||
'''int magic''': A "magic number" used to identify the file. The magic number is 844121161 in decimal (0x32504449 in hexadecimal). The magic number is equal to the int "IDP2" (id polygon 2), which is formed by ('I' + ('D' << 8) + ('P' << 16) + ('2' << 24)). | '''int magic''': A "magic number" used to identify the file. The magic number is 844121161 in decimal (0x32504449 in hexadecimal). The magic number is equal to the int "IDP2" (id polygon 2), which is formed by ('I' + ('D' << 8) + ('P' << 16) + ('2' << 24)). | ||
=== | === version === | ||
'''int version''': Version number of the file. Always 8. | '''int version''': Version number of the file. Always 8. | ||
=== | === skinWidth === | ||
'''int skinWidth''': Width of the skin(s) in pixels. | '''int skinWidth''': Width of the skin(s) in pixels. | ||
=== | === skinHeight === | ||
'''int skinHeight''': Height of the skin(s) in pixels. | '''int skinHeight''': Height of the skin(s) in pixels. | ||
=== | === frameSize === | ||
'''int frameSize''': Size of each [[#FRAMES|frame]] in bytes. | '''int frameSize''': Size of each [[#FRAMES|frame]] in bytes. | ||
=== | === numSkins === | ||
'''int numSkins''': Number of skins associated with this model. | '''int numSkins''': Number of skins associated with this model. | ||
=== | === numVertices === | ||
'''int numVertices''': Number of [[#triangleVertex|vertices]] in each frame. | '''int numVertices''': Number of [[#triangleVertex|vertices]] in each frame. | ||
=== | === numTexCoords === | ||
'''int numTexCoords''': Number of texture coordinates (not necessarily the same as the number of vertices). | '''int numTexCoords''': Number of texture coordinates (not necessarily the same as the number of vertices). | ||
=== | === numTriangles === | ||
'''int numTriangles''': Number of triangles in each frame. | '''int numTriangles''': Number of triangles in each frame. | ||
=== | === numGlCommands === | ||
'''int numGlCommands''': Number of dwords (4 bytes) in the gl command list. | '''int numGlCommands''': Number of dwords (4 bytes) in the gl command list. | ||
=== | === numFrames === | ||
'''int numFrames''': Number of [[#FRAMES|frames]]. | '''int numFrames''': Number of [[#FRAMES|frames]]. | ||
=== | === offsetSkins === | ||
'''int offsetSkins''': Offset, in bytes from the start of the file, to the list of skin names. | '''int offsetSkins''': Offset, in bytes from the start of the file, to the list of skin names. | ||
=== | === offsetTexCoords === | ||
'''int offsetTexCoords''': Offset, in bytes from the start of the file, to the list of texture coordinates. | '''int offsetTexCoords''': Offset, in bytes from the start of the file, to the list of texture coordinates. | ||
=== | === offsetTriangles === | ||
'''int offsetTriangles''': Offset, in bytes from the start of the file, to the list of triangles. | '''int offsetTriangles''': Offset, in bytes from the start of the file, to the list of triangles. | ||
=== | === offsetFrames === | ||
'''int offsetFrames''': Offset, in bytes from the start of the file, to the list of [[#FRAMES|frames]]. | '''int offsetFrames''': Offset, in bytes from the start of the file, to the list of [[#FRAMES|frames]]. | ||
=== | === offsetGlCommands === | ||
'''int offsetGlCommands''': Offset, in bytes from the start of the file, to the gl command list. | '''int offsetGlCommands''': Offset, in bytes from the start of the file, to the gl command list. | ||
=== | === offsetEnd === | ||
'''int offsetEnd''': Offset, in bytes from the start of the file, to the end (size of the file). | '''int offsetEnd''': Offset, in bytes from the start of the file, to the end (size of the file). | ||
== FRAMES == | == FRAMES == | ||
Each frame contains the positions in 3D space for each vertex of each triangle that makes up the model. Quake 2 (and Quake) models contain only triangles. | Each frame contains the positions in 3D space for each vertex of each triangle that makes up the model. Quake 2 (and Quake) models contain only triangles. | ||
< | <syntaxhighlight lang="c"> | ||
typedef struct | typedef struct | ||
{ | { | ||
byte | byte vertex[3]; | ||
byte | byte lightNormalIndex; | ||
} triangleVertex_t; | } triangleVertex_t; | ||
</ | </syntaxhighlight> | ||
=== | === vertex === | ||
'''byte vertex[3]''': The three bytes represent the x, y, and z coordinates of this vertex. This is not the "real" vertex coordinate. This is a scaled version of the coordinate, scaled so that each of the three numbers fit within one byte. | '''byte vertex[3]''': The three bytes represent the x, y, and z coordinates of this vertex. This is not the "real" vertex coordinate. This is a scaled version of the coordinate, scaled so that each of the three numbers fit within one byte. To scale the vertex back to the "real" coordinate, you need to first multiply each of the bytes by their respective float [[#frame_scale|scale]] in the [[#frame|frame_t]] structure, and then add the respective float [[#frame_translate|translation]], also in the [[#frame|frame_t]] structure. | ||
=== | === lightNormalIndex === | ||
'''byte lightNormalIndex''': This is an index into a table of normals kept by Quake2. | '''byte lightNormalIndex''': This is an index into a table of normals kept by Quake2. | ||
== TRIANGLES == | == TRIANGLES == | ||
Quake 2 models are made up of only triangles. At [[#model_offsetTriangles|offsetTriangles]] in the file is an array of [[#triangle|triangle_t]] structures. | Quake 2 models are made up of only triangles. At [[#model_offsetTriangles|offsetTriangles]] in the file is an array of [[#triangle|triangle_t]] structures. | ||
< | <syntaxhighlight lang="c"> | ||
typedef struct | typedef struct | ||
{ | { | ||
short | short vertexIndices[3]; | ||
short | short textureIndices[3]; | ||
} triangle_t; | } triangle_t; | ||
</ | </syntaxhighlight> | ||
=== | === vertexIndices === | ||
'''short vertexIndices''': These three shorts are indices into the array of [[#frame_vertices|vertices]] in each [[#frame|frame]]. | '''short vertexIndices[3]''': These three shorts are indices into the array of [[#frame_vertices|vertices]] in each [[#frame|frame]]. | ||
=== | === textureIndices === | ||
'''short textureIndices''': These three shorts are indices into the array of [[#textureCoordinate|texture coordinates]]. | '''short textureIndices[3]''': These three shorts are indices into the array of [[#textureCoordinate|texture coordinates]]. | ||
== SKINS == | == SKINS == | ||
There is an array of [[#model_numSkins|numSkins]] skin names stored at [[#model_offsetSkins|offsetSkins]] into the file. Each skin name is a char[64]. The name is really a path to the skin, relative to the base game directory (baseq2 for "standard" Quake2). The skin files are regular PCX files. | There is an array of [[#model_numSkins|numSkins]] skin names stored at [[#model_offsetSkins|offsetSkins]] into the file. Each skin name is a char[64]. The name is really a path to the skin, relative to the base game directory (baseq2 for "standard" Quake2). The skin files are regular PCX files. | ||
== TEXTURE COORDINATES == | |||
<syntaxhighlight lang="c"> | |||
typedef struct | |||
{ | |||
short s, t; | |||
} textureCoordinate_t; | |||
</syntaxhighlight> | |||
== GL COMMANDS == | == GL COMMANDS == | ||
At [[#model_offsetGlCommands|offsetGlCommands]] bytes into the file, there is the gl command list. | At [[#model_offsetGlCommands|offsetGlCommands]] bytes into the file, there is the gl command list. | ||
< | <syntaxhighlight lang="c"> | ||
typedef struct | typedef struct | ||
{ | { | ||
float | float s, t; | ||
int | int vertexIndex; | ||
} glCommandVertex_t; | } glCommandVertex_t; | ||
</ | </syntaxhighlight> | ||
=== | == MAXIMUMS == | ||
Quake2 has some pre-defined limits: | Quake2 has some pre-defined limits: | ||
* | * '''Triangles''': 4096 | ||
* | * '''Vertices''': 2048 | ||
* | * '''Texture Coordinates''': 2048 | ||
* | * '''Frames''': 512 | ||
* | * '''Skins''': 32 | ||
Quake and Quake2 are trademarks of [http://www.idsoftware.com id Software]. All trademarks used are properties of their respective owners. | Quake and Quake2 are trademarks of [http://www.idsoftware.com id Software]. | ||
All trademarks used are properties of their respective owners. |
Revision as of 23:23, 18 March 2025
.md2 File Format Specification
INTRO
This page will try and give some sort of technical documentation on the Quake2 model format (.md2).
These specs can be used freely for whatever you want. I only ask that people send me corrections, suggestions, etc.
Quake2 models are stored in files with the .md2 extension. This is a custom format used only by Quake2 and (probably) Quake2 mission packs. md2 files can be generated from various other file formats by tools provided freely by id, in original and modified form. A single md2 file contains the model's geometry, frame information, skin filename(s), and texture coordinates. The file is little-endian (intel byte ordering).
HEADER
The header comes right at the start of the file. The information in the header is needed to load different parts of the model.
typedef struct
{
int magic;
int version;
int skinWidth;
int skinHeight;
int frameSize;
int numSkins;
int numVertices;
int numTexCoords;
int numTriangles;
int numGlCommands;
int numFrames;
int offsetSkins;
int offsetTexCoords;
int offsetTriangles;
int offsetFrames;
int offsetGlCommands;
int offsetEnd;
} model_t;
magic
int magic: A "magic number" used to identify the file. The magic number is 844121161 in decimal (0x32504449 in hexadecimal). The magic number is equal to the int "IDP2" (id polygon 2), which is formed by ('I' + ('D' << 8) + ('P' << 16) + ('2' << 24)).
version
int version: Version number of the file. Always 8.
skinWidth
int skinWidth: Width of the skin(s) in pixels.
skinHeight
int skinHeight: Height of the skin(s) in pixels.
frameSize
int frameSize: Size of each frame in bytes.
numSkins
int numSkins: Number of skins associated with this model.
numVertices
int numVertices: Number of vertices in each frame.
numTexCoords
int numTexCoords: Number of texture coordinates (not necessarily the same as the number of vertices).
numTriangles
int numTriangles: Number of triangles in each frame.
numGlCommands
int numGlCommands: Number of dwords (4 bytes) in the gl command list.
numFrames
int numFrames: Number of frames.
offsetSkins
int offsetSkins: Offset, in bytes from the start of the file, to the list of skin names.
offsetTexCoords
int offsetTexCoords: Offset, in bytes from the start of the file, to the list of texture coordinates.
offsetTriangles
int offsetTriangles: Offset, in bytes from the start of the file, to the list of triangles.
offsetFrames
int offsetFrames: Offset, in bytes from the start of the file, to the list of frames.
offsetGlCommands
int offsetGlCommands: Offset, in bytes from the start of the file, to the gl command list.
offsetEnd
int offsetEnd: Offset, in bytes from the start of the file, to the end (size of the file).
FRAMES
Each frame contains the positions in 3D space for each vertex of each triangle that makes up the model. Quake 2 (and Quake) models contain only triangles.
typedef struct
{
byte vertex[3];
byte lightNormalIndex;
} triangleVertex_t;
vertex
byte vertex[3]: The three bytes represent the x, y, and z coordinates of this vertex. This is not the "real" vertex coordinate. This is a scaled version of the coordinate, scaled so that each of the three numbers fit within one byte. To scale the vertex back to the "real" coordinate, you need to first multiply each of the bytes by their respective float scale in the frame_t structure, and then add the respective float translation, also in the frame_t structure.
lightNormalIndex
byte lightNormalIndex: This is an index into a table of normals kept by Quake2.
TRIANGLES
Quake 2 models are made up of only triangles. At offsetTriangles in the file is an array of triangle_t structures.
typedef struct
{
short vertexIndices[3];
short textureIndices[3];
} triangle_t;
vertexIndices
short vertexIndices[3]: These three shorts are indices into the array of vertices in each frame.
textureIndices
short textureIndices[3]: These three shorts are indices into the array of texture coordinates.
SKINS
There is an array of numSkins skin names stored at offsetSkins into the file. Each skin name is a char[64]. The name is really a path to the skin, relative to the base game directory (baseq2 for "standard" Quake2). The skin files are regular PCX files.
TEXTURE COORDINATES
typedef struct
{
short s, t;
} textureCoordinate_t;
GL COMMANDS
At offsetGlCommands bytes into the file, there is the gl command list.
typedef struct
{
float s, t;
int vertexIndex;
} glCommandVertex_t;
MAXIMUMS
Quake2 has some pre-defined limits:
- Triangles: 4096
- Vertices: 2048
- Texture Coordinates: 2048
- Frames: 512
- Skins: 32
Quake and Quake2 are trademarks of id Software. All trademarks used are properties of their respective owners.