Jump to content

MD2: Difference between revisions

From Kingpin Wiki
Created page with "<p style="text-align: center;" align="center"><span style="font-size: x-large;"><strong>.md2 File Format Specification</strong></span></p> <p style="text-align: center;" align="center"><span style="font-size: medium;"><strong>by </strong></span><a href="mailto:dansch@hops.cs.jhu.edu"> <span style="font-size: medium;"><strong>Daniel E. Schoenblum</strong></span></a></p> <p align="left"><span style="color: #436888; font-size: large;">INTRO</span></p> <p>This page will try..."
 
No edit summary
Line 1: Line 1:
<p style="text-align: center;" align="center"><span style="font-size: x-large;"><strong>.md2 File Format Specification</strong></span></p>
<p style="text-align: center;" align="center"><span style="font-size: x-large;"><strong>.md2 File Format Specification</strong></span></p>
<p style="text-align: center;" align="center"><span style="font-size: medium;"><strong>by </strong></span><a href="mailto:dansch@hops.cs.jhu.edu"> <span style="font-size: medium;"><strong>Daniel E. Schoenblum</strong></span></a></p>
<p style="text-align: center;" align="center"><span style="font-size: medium;"><strong>by </strong></span>[mailto:dansch@hops.cs.jhu.edu"> <span style="font-size: medium;"><strong>Daniel E. Schoenblum</strong></span>]</p>
<p align="left"><span style="color: #436888; font-size: large;">INTRO</span></p>
<p align="left"><span style="color: #436888; font-size: large;">INTRO</span></p>
<p>This page will try and give some sort of technical documentation on the Quake2 model format (.md2).</p>
<p>This page will try and give some sort of technical documentation on the Quake2 model format (.md2).</p>
<p>These specs can be used freely for whatever you want. I only ask that people <a href="mailto:dansch@hops.cs.jhu.edu">send me</a> corrections, suggestions, etc.</p>
<p>These specs can be used freely for whatever you want. I only ask that people [mailto:dansch@hops.cs.jhu.edu">send me] corrections, suggestions, etc.</p>
<p align="left">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).</p>
<p align="left">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).</p>
<p align="left"><span style="color: #436888; font-size: large;">HEADER</span></p>
<p align="left"><span style="color: #436888; font-size: large;">HEADER</span></p>
<p align="left">The header comes right at the start of the file. The information in the header is needed to load different parts of the model.</p>
<p align="left">The header comes right at the start of the file. The information in the header is needed to load different parts of the model.</p>
<p align="left"><code>typedef struct <br /> { <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_magic">magic</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_version">version</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_skinWidth">skinWidth</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_skinHeight">skinHeight</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_frameSize">frameSize</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_numSkins">numSkins</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_numVertices">numVertices</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_numTexCoords">numTexCoords</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_numTriangles">numTriangles</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_numGlCommands">numGlCommands</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_numFrames">numFrames</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_offsetSkins">offsetSkins</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_offsetTexCoords">offsetTexCoords</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_offsetTriangles">offsetTriangles</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_offsetFrames">offsetFrames</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_offsetGlCommands">offsetGlCommands</a>; <br /> &nbsp;&nbsp;&nbsp;int <a href="#model_offsetEnd">offsetEnd</a>; <br /> } model_t;</code></p>
<p align="left"><code>typedef struct <br /> { <br /> &nbsp;&nbsp;&nbsp;int [#model_magic">magic]; <br /> &nbsp;&nbsp;&nbsp;int [#model_version">version]; <br /> &nbsp;&nbsp;&nbsp;int [#model_skinWidth">skinWidth]; <br /> &nbsp;&nbsp;&nbsp;int [#model_skinHeight">skinHeight]; <br /> &nbsp;&nbsp;&nbsp;int [#model_frameSize">frameSize]; <br /> &nbsp;&nbsp;&nbsp;int [#model_numSkins">numSkins]; <br /> &nbsp;&nbsp;&nbsp;int [#model_numVertices">numVertices]; <br /> &nbsp;&nbsp;&nbsp;int [#model_numTexCoords">numTexCoords]; <br /> &nbsp;&nbsp;&nbsp;int [#model_numTriangles">numTriangles]; <br /> &nbsp;&nbsp;&nbsp;int [#model_numGlCommands">numGlCommands]; <br /> &nbsp;&nbsp;&nbsp;int [#model_numFrames">numFrames]; <br /> &nbsp;&nbsp;&nbsp;int [#model_offsetSkins">offsetSkins]; <br /> &nbsp;&nbsp;&nbsp;int [#model_offsetTexCoords">offsetTexCoords]; <br /> &nbsp;&nbsp;&nbsp;int [#model_offsetTriangles">offsetTriangles]; <br /> &nbsp;&nbsp;&nbsp;int [#model_offsetFrames">offsetFrames]; <br /> &nbsp;&nbsp;&nbsp;int [#model_offsetGlCommands">offsetGlCommands]; <br /> &nbsp;&nbsp;&nbsp;int [#model_offsetEnd">offsetEnd]; <br /> } model_t;</code></p>
<p><a name="model_magic"></a></p>
<p><a name="model_magic">]</p>
<p align="left">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' &lt;&lt; 8) + ('P' &lt;&lt; 16) + ('2' &lt;&lt; 24)).</p>
<p align="left">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' &lt;&lt; 8) + ('P' &lt;&lt; 16) + ('2' &lt;&lt; 24)).</p>
<p align="left"><a target="_top" name="model_version"></a> int version: Version number of the file. Always 8.</p>
<p align="left"><a target="_top" name="model_version">] int version: Version number of the file. Always 8.</p>
<p align="left"><a target="_top" name="model_skinWidth"></a> int skinWidth: Width of the skin(s) in pixels.</p>
<p align="left"><a target="_top" name="model_skinWidth">] int skinWidth: Width of the skin(s) in pixels.</p>
<p align="left"><a target="_top" name="model_skinHeight"></a> int skinHeight: Height of the skin(s) in pixels.</p>
<p align="left"><a target="_top" name="model_skinHeight">] int skinHeight: Height of the skin(s) in pixels.</p>
<p align="left"><a target="_top" name="model_frameSize"></a> int frameSize: Size of each <a href="#FRAMES">frame</a> in bytes.</p>
<p align="left"><a target="_top" name="model_frameSize">] int frameSize: Size of each [#FRAMES">frame] in bytes.</p>
<p align="left"><a target="_top" name="model_numSkins"></a> int numSkins: Number of skins associated with this model.</p>
<p align="left"><a target="_top" name="model_numSkins">] int numSkins: Number of skins associated with this model.</p>
<p align="left"><a target="_top" name="model_numVertices"></a> int numVertices: Number of <a href="#triangleVertex">vertices</a> in each frame.</p>
<p align="left"><a target="_top" name="model_numVertices">] int numVertices: Number of [#triangleVertex">vertices] in each frame.</p>
<p align="left"><a target="_top" name="model_numTexCoords"></a> int numTexCoords: Number of texture coordinates (not necessarily the same as the number of vertices).</p>
<p align="left"><a target="_top" name="model_numTexCoords">] int numTexCoords: Number of texture coordinates (not necessarily the same as the number of vertices).</p>
<p align="left"><a target="_top" name="model_numTriangles"></a> int numTriangles: Number of triangles in each frame.</p>
<p align="left"><a target="_top" name="model_numTriangles">] int numTriangles: Number of triangles in each frame.</p>
<p align="left"><a target="_top" name="model_numGlCommands"></a> int numGlCommands: Number of dwords (4 bytes) in the gl command list.</p>
<p align="left"><a target="_top" name="model_numGlCommands">] int numGlCommands: Number of dwords (4 bytes) in the gl command list.</p>
<p align="left"><a target="_top" name="model_numFrames"></a> int numFrames: Number of <a href="#FRAMES">frames</a>.</p>
<p align="left"><a target="_top" name="model_numFrames">] int numFrames: Number of [#FRAMES">frames].</p>
<p align="left"><a target="_top" name="model_offsetSkins"></a> int offsetSkins: Offset, in bytes from the start of the file, to the list of skin names.</p>
<p align="left"><a target="_top" name="model_offsetSkins">] int offsetSkins: Offset, in bytes from the start of the file, to the list of skin names.</p>
<p align="left"><a target="_top" name="model_offsetTexCoords"></a> int offsetTexCoords: Offset, in bytes from the start of the file, to the list of texture coordinates.</p>
<p align="left"><a target="_top" name="model_offsetTexCoords">] int offsetTexCoords: Offset, in bytes from the start of the file, to the list of texture coordinates.</p>
<p align="left"><a target="_top" name="model_offsetTriangles"></a> int offsetTriangles: Offset, in bytes from the start of the file, to the list of triangles.</p>
<p align="left"><a target="_top" name="model_offsetTriangles">] int offsetTriangles: Offset, in bytes from the start of the file, to the list of triangles.</p>
<p align="left"><a target="_top" name="model_offsetFrames"></a> int offsetFrames: Offset, in bytes from the start of the file, to the list of <a href="#FRAMES">frames</a>.</p>
<p align="left"><a target="_top" name="model_offsetFrames">] int offsetFrames: Offset, in bytes from the start of the file, to the list of [#FRAMES">frames].</p>
<p align="left"><a target="_top" name="model_offsetGlCommands"></a> int offsetGlCommands: Offset, in bytes from the start of the file, to the gl command list.</p>
<p align="left"><a target="_top" name="model_offsetGlCommands">] int offsetGlCommands: Offset, in bytes from the start of the file, to the gl command list.</p>
<p align="left"><a target="_top" name="model_offsetEnd"></a> int offsetEnd: Offset, in bytes from the start of the file, to the end (size of the file).</p>
<p align="left"><a target="_top" name="model_offsetEnd">] int offsetEnd: Offset, in bytes from the start of the file, to the end (size of the file).</p>
<p><a name="FRAMES"></a></p>
<p><a name="FRAMES">]</p>
<p align="left"><span style="color: #436888; font-size: large;">FRAMES</span></p>
<p align="left"><span style="color: #436888; font-size: large;">FRAMES</span></p>
<p align="left">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.</p>
<p align="left">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.</p>
<p><a name="triangleVertex"></a> <code> typdef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;byte <a href="#triangleVertex_vertex">vertex</a>[3];<br /> &nbsp;&nbsp;&nbsp;byte <a href="#triangleVertex_lightNormalIndex">lightNormalIndex</a>;<br /> } triangleVertex_t;<br /> </code></p>
<p><a name="triangleVertex">] <code> typdef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;byte [#triangleVertex_vertex">vertex][3];<br /> &nbsp;&nbsp;&nbsp;byte [#triangleVertex_lightNormalIndex">lightNormalIndex];<br /> } triangleVertex_t;<br /> </code></p>
<p align="left"><a target="_top" name="triangleVertex_vertex"></a> 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 <a href="#frame_scale">scale</a> in the <a href="#frame">frame_t</a> structure, and then add the respective float <a href="#frame_translate">translation </a>, also in the <a href="#frame">frame_t</a> structure. This will give you the vertex coordinate relative to the model's origin, which is at the origin, (0, 0, 0).</p>
<p align="left"><a target="_top" name="triangleVertex_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 [#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. This will give you the vertex coordinate relative to the model's origin, which is at the origin, (0, 0, 0).</p>
<p align="left"><a target="_top" name="triangleVertex_lightNormalIndex"></a> byte lightNormalIndex: This is an index into a table of normals kept by Quake2. To get the table, you need to download <a href="https://www.quaddicted.com/files/idgames2/idstuff/quake2/source/old/q2source_12_11.zip">this zip file (1.7 MB)</a>, released by <a href="http://www
<p align="left"><a target="_top" name="triangleVertex_lightNormalIndex">] byte lightNormalIndex: This is an index into a table of normals kept by Quake2. To get the table, you need to download [https://www.quaddicted.com/files/idgames2/idstuff/quake2/source/old/q2source_12_11.zip">this zip file (1.7 MB)], released by [http://www
.idsoftware.com">id</a>, that has the source code to all of the tools they used for quake2.</p>
.idsoftware.com">id], that has the source code to all of the tools they used for quake2.</p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;float <a href="#frame_scale">scale</a>[3];<br /> &nbsp;&nbsp;&nbsp;float <a href="#frame_translate">translate</a>[3];<br /> &nbsp;&nbsp;&nbsp;char <a href="#frame_name">name</a>[16];<br /> &nbsp;&nbsp;&nbsp;<a href="#triangleVertex">triangleVertex_t</a> <a href="#frame_vertices">vertices</a>[1];<br /> } frame_t;<br /> </code></p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;float [#frame_scale">scale][3];<br /> &nbsp;&nbsp;&nbsp;float [#frame_translate">translate][3];<br /> &nbsp;&nbsp;&nbsp;char [#frame_name">name][16];<br /> &nbsp;&nbsp;&nbsp;[#triangleVertex">triangleVertex_t] [#frame_vertices">vertices][1];<br /> } frame_t;<br /> </code></p>
<p align="left">frame_t is a variable sized structure, however all frame_t structures within the same file will have the same size (<a href="#model_numVertices">numVertices</a> in the <a href="#model">header</a>)</p>
<p align="left">frame_t is a variable sized structure, however all frame_t structures within the same file will have the same size ([#model_numVertices">numVertices] in the [#model">header])</p>
<p align="left"><a target="_top" name="frame_scale"></a> float scale[3]: This is a scale used by the <a href="#triangleVertex_vertex">vertex</a> member of the <a href="#triangleVertex">triangleVertex_t</a> structure.</p>
<p align="left"><a target="_top" name="frame_scale">] float scale[3]: This is a scale used by the [#triangleVertex_vertex">vertex] member of the [#triangleVertex">triangleVertex_t] structure.</p>
<p align="left"><a target="_top" name="frame_translate"></a> float translate[3]: This is a translation used by the <a href="#triangleVertex_vertex">vertex</a> member of the <a href="#triangleVertex">triangleVertex_t</a> structure.</p>
<p align="left"><a target="_top" name="frame_translate">] float translate[3]: This is a translation used by the [#triangleVertex_vertex">vertex] member of the [#triangleVertex">triangleVertex_t] structure.</p>
<p align="left"><a target="_top" name="frame_name"></a> char name[16]: This is a name for the frame.</p>
<p align="left"><a target="_top" name="frame_name">] char name[16]: This is a name for the frame.</p>
<p align="left"><a target="_top" name="frame_vertices"></a> <a href="#triangleVertex">triangleVertex_t</a> vertices[1]: An array of <a href="#model_numVertices">numVertices</a> <a href="#triangleVertex">triangleVertex_t</a> structures.</p>
<p align="left"><a target="_top" name="frame_vertices">] [#triangleVertex">triangleVertex_t] vertices[1]: An array of [#model_numVertices">numVertices] [#triangleVertex">triangleVertex_t] structures.</p>
<p align="left"><a name="TRIANGLES"></a></p>
<p align="left"><a name="TRIANGLES">]</p>
<p align="left"><span style="color: #436888; font-size: large;">TRIANGLES</span></p>
<p align="left"><span style="color: #436888; font-size: large;">TRIANGLES</span></p>
<p align="left">Quake 2 models are made up of only triangles. At <a href="#model_offsetTriangles">offsetTriangles</a> in the file is an array of <a href="#triangle">triangle_t</a> structures. The array has <a href="#model_numTriangles">numTriangles</a> structures in it.</p>
<p align="left">Quake 2 models are made up of only triangles. At [#model_offsetTriangles">offsetTriangles] in the file is an array of [#triangle">triangle_t] structures. The array has [#model_numTriangles">numTriangles] structures in it.</p>
<p align="left"><a name="triangle"></a></p>
<p align="left"><a name="triangle">]</p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;short <a href="#triangle_vertexIndices">vertexIndices</a>[3];<br /> &nbsp;&nbsp;&nbsp;short <a href="#triangle_textureIndices">textureIndices</a>[3];<br /> } triangle_t;<br /> </code></p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;short [#triangle_vertexIndices">vertexIndices][3];<br /> &nbsp;&nbsp;&nbsp;short [#triangle_textureIndices">textureIndices][3];<br /> } triangle_t;<br /> </code></p>
<p align="left"><a target="_top" name="triangle_vertexIndices"></a> short vertexIndices: These three shorts are indices into the array of <a href="#frame_vertices">vertices</a> in each <a href="#frame">frames</a>. In other words, the number of triangles in a md2 file is fixed, and each triangle is always made of the same three indices into each frame's array of vertices. So, in each frame, the triangles themselves stay intact, their vertices are just moved around.</p>
<p align="left"><a target="_top" name="triangle_vertexIndices">] short vertexIndices: These three shorts are indices into the array of [#frame_vertices">vertices] in each [#frame">frames]. In other words, the number of triangles in a md2 file is fixed, and each triangle is always made of the same three indices into each frame's array of vertices. So, in each frame, the triangles themselves stay intact, their vertices are just moved around.</p>
<p align="left"><a target="_top" name="triangle_textureIndices"></a> short textureIndices: These three shorts are indices into the array of <a href="#textureCoordinate">texture coordinates</a>.</p>
<p align="left"><a target="_top" name="triangle_textureIndices">] short textureIndices: These three shorts are indices into the array of [#textureCoordinate">texture coordinates].</p>
<p align="left"><a name="SKINS"></a></p>
<p align="left"><a name="SKINS">]</p>
<p align="left"><span style="color: #436888; font-size: large;">SKINS</span></p>
<p align="left"><span style="color: #436888; font-size: large;">SKINS</span></p>
<p align="left"><a name="SKINS"></a></p>
<p align="left"><a name="SKINS">]</p>
<p align="left">There is an array of <a href="#model_numSkins">numSkins</a> skin names stored at <a href="#model_offsetSkins">offsetSkins</a> 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 f or "standard" Quake2). The skin files are regular pcx files.</p>
<p align="left">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 f or "standard" Quake2). The skin files are regular pcx files.</p>
<p align="left"><a name="textureCoordinate"></a></p>
<p align="left"><a name="textureCoordinate">]</p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;short <a href="#textureCoordinate_st">s</a>, <a href="#textureCoordinate_st">t</a>;<br /> } textureCoordinate_t;<br /> </code></p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;short [#textureCoordinate_st">s], [#textureCoordinate_st">t];<br /> } textureCoordinate_t;<br /> </code></p>
<p align="left"><a target="_top" name="textureCoordinate_t"></a> short s, t: These two shorts are used to map a vertex onto a skin. The horizontal axis position is given by s, and the vertical axis position is given by t. The range for s is greater than or equal to 0 and less than <a href="#model_skinWidth">skinWidth</a> (0 &lt;= s &lt; skinWidth). The range for t is greater than or equal to 0 and less than <a href="#model_skinHeight">skinHeight</a> (0 &lt;= s &lt; skinHeight). Note that the ranges are different than in the <a href="#glCommandVertex_s">s</a> and <a href="#glCommandVertex_t">t</a> members of the <a href="#glCommandVertex">glCommandVertex</a> structure.</p>
<p align="left"><a target="_top" name="textureCoordinate_t">] short s, t: These two shorts are used to map a vertex onto a skin. The horizontal axis position is given by s, and the vertical axis position is given by t. The range for s is greater than or equal to 0 and less than [#model_skinWidth">skinWidth] (0 &lt;= s &lt; skinWidth). The range for t is greater than or equal to 0 and less than [#model_skinHeight">skinHeight] (0 &lt;= s &lt; skinHeight). Note that the ranges are different than in the [#glCommandVertex_s">s] and [#glCommandVertex_t">t] members of the [#glCommandVertex">glCommandVertex] structure.</p>
<p align="left"><a name="GL_COMMANDS"></a></p>
<p align="left"><a name="GL_COMMANDS">]</p>
<p align="left"><span style="color: #436888; font-size: large;">GL COMMANDS</span></p>
<p align="left"><span style="color: #436888; font-size: large;">GL COMMANDS</span></p>
<p align="left"><a name="GL_COMMANDS"></a>At <a href="#model_offsetGlCommands">offsetGlCommands</a><a name="GL_COMMANDS"></a> bytes into the file, there is the gl command list, which is made up of a series of <a href="#model_numGlCommands">numGlCommands</a><a name="GL_COMMANDS"></a> int's and float's, organized into groups. Each group starts with an int. If it is positive, it is followed by that many <a href="#glCommandVertex">glCommandVertex_t</a><a name="GL_COMMANDS"></a> structures, which form a triangle strip. If it is negative, it is followed by -x <a href="#glCommandVertex">glCommandVertex_t</a><a name="GL_COMMANDS"></a> structures, which fo rm a triangle fan. A 0 indicates the end of the list. The list is an optimized way of issuing commands when rendering with <a href="http://www.opengl.org">OpenGl</a><a name="GL_COMMANDS"></a>. <a name="glCommandVertex"></a></p>
<p align="left"><a name="GL_COMMANDS">]At [#model_offsetGlCommands">offsetGlCommands]<a name="GL_COMMANDS">] bytes into the file, there is the gl command list, which is made up of a series of [#model_numGlCommands">numGlCommands]<a name="GL_COMMANDS">] int's and float's, organized into groups. Each group starts with an int. If it is positive, it is followed by that many [#glCommandVertex">glCommandVertex_t]<a name="GL_COMMANDS">] structures, which form a triangle strip. If it is negative, it is followed by -x [#glCommandVertex">glCommandVertex_t]<a name="GL_COMMANDS">] structures, which fo rm a triangle fan. A 0 indicates the end of the list. The list is an optimized way of issuing commands when rendering with [http://www.opengl.org">OpenGl]<a name="GL_COMMANDS">]. <a name="glCommandVertex">]</p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;float <a href="#glCommandVertex_st">s</a>, <a href="#glCommandVertex_st">t</a>;<br /> &nbsp;&nbsp;&nbsp;int <a href="#glCommandVertex_vertexIndex">vertexIndex</a>;<br /> } glCommandVertex_t;<br /> </code></p>
<p align="left"><code> typedef struct<br /> {<br /> &nbsp;&nbsp;&nbsp;float [#glCommandVertex_st">s], [#glCommandVertex_st">t];<br /> &nbsp;&nbsp;&nbsp;int [#glCommandVertex_vertexIndex">vertexIndex];<br /> } glCommandVertex_t;<br /> </code></p>
<p align="left"><a target="_top" name="glCommandVertex_t"></a> float s, t: These two floats are used to map a vertex onto a skin. The horizontal axis position is given by s, and the vertical axis position is given by t. The range for s and for t is 0.0 to 1.0. Note that the ranges are different than in the <a href="#textureCoordinate">textureCoordinate_t</a><a target="_top" name="glCommandVertex_t"></a> structure. They are stored as floats here because that's the way Quake2 passes them to <a href="http://www.opengl.org">OpenGl</a><a target="_top" name="glCommandVertex_t"></a>.</p>
<p align="left"><a target="_top" name="glCommandVertex_t">] float s, t: These two floats are used to map a vertex onto a skin. The horizontal axis position is given by s, and the vertical axis position is given by t. The range for s and for t is 0.0 to 1.0. Note that the ranges are different than in the [#textureCoordinate">textureCoordinate_t]<a target="_top" name="glCommandVertex_t">] structure. They are stored as floats here because that's the way Quake2 passes them to [http://www.opengl.org">OpenGl]<a target="_top" name="glCommandVertex_t">].</p>
<p align="left"><a target="_top" name="glCommandVertex_vertexIndex"></a> int vertexIndex: Index into the array of <a href="#frame_vertices">vertices</a><a target="_top" name="glCommandVertex_vertexIndex"></a> stored in each <a href="#frame">frame</a><a target="_top" name="glCommandVertex_vertexIndex"></a>.</p>
<p align="left"><a target="_top" name="glCommandVertex_vertexIndex">] int vertexIndex: Index into the array of [#frame_vertices">vertices]<a target="_top" name="glCommandVertex_vertexIndex">] stored in each [#frame">frame]<a target="_top" name="glCommandVertex_vertexIndex">].</p>
<p align="left"><span style="color: #436888; font-size: large;">MAXIMUMS</span></p>
<p align="left"><span style="color: #436888; font-size: large;">MAXIMUMS</span></p>
<p align="left">Quake2 has some pre-defined limits, so that dynamic memory does not need to be used. You can use these to your advantage to speed up loading if you want.</p>
<p align="left">Quake2 has some pre-defined limits, so that dynamic memory does not need to be used. You can use these to your advantage to speed up loading if you want.</p>
<ul>
<ul>
<li><a href="#TRIANGLES">Triangles</a>: 4096</li>
<li>[#TRIANGLES">Triangles]: 4096</li>
<li><a href="#triangleVertex">Vertices</a>: 2048</li>
<li>[#triangleVertex">Vertices]: 2048</li>
<li><a href="#textureCoordinate">Texture Coordinates</a>: 2048</li>
<li>[#textureCoordinate">Texture Coordinates]: 2048</li>
<li><a href="#FRAMES">Frames</a>: 512</li>
<li>[#FRAMES">Frames]: 512</li>
<li><a href="#SKINS">Skins</a>: 32</li>
<li>[#SKINS">Skins]: 32</li>
</ul>
</ul>
<p align="left"><span> Quake and Quake2 are trademarks of <a href="http://www.idsoftware.com">id Software</a>.<br /> All trademarks used are properties of their respective owners. </span></p>
<p align="left"><span> Quake and Quake2 are trademarks of [http://www.idsoftware.com">id Software].<br /> All trademarks used are properties of their respective owners. </span></p>
<p align="left"><a name="glCommandVertex"></a></p>
<p align="left"><a name="glCommandVertex">]</p>
<p align="left"><a name="textureCoordinate"></a></p>
<p align="left"><a name="textureCoordinate">]</p>
<p align="left"><a name="triangle"></a></p>
<p align="left"><a name="triangle">]</p>

Revision as of 21:04, 18 March 2025

.md2 File Format Specification

by "> Daniel E. Schoenblum

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 [#model_magic">magic];
   int [#model_version">version];
   int [#model_skinWidth">skinWidth];
   int [#model_skinHeight">skinHeight];
   int [#model_frameSize">frameSize];
   int [#model_numSkins">numSkins];
   int [#model_numVertices">numVertices];
   int [#model_numTexCoords">numTexCoords];
   int [#model_numTriangles">numTriangles];
   int [#model_numGlCommands">numGlCommands];
   int [#model_numFrames">numFrames];
   int [#model_offsetSkins">offsetSkins];
   int [#model_offsetTexCoords">offsetTexCoords];
   int [#model_offsetTriangles">offsetTriangles];
   int [#model_offsetFrames">offsetFrames];
   int [#model_offsetGlCommands">offsetGlCommands];
   int [#model_offsetEnd">offsetEnd];
} model_t;

<a name="model_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)).

<a target="_top" name="model_version">] int version: Version number of the file. Always 8.

<a target="_top" name="model_skinWidth">] int skinWidth: Width of the skin(s) in pixels.

<a target="_top" name="model_skinHeight">] int skinHeight: Height of the skin(s) in pixels.

<a target="_top" name="model_frameSize">] int frameSize: Size of each [#FRAMES">frame] in bytes.

<a target="_top" name="model_numSkins">] int numSkins: Number of skins associated with this model.

<a target="_top" name="model_numVertices">] int numVertices: Number of [#triangleVertex">vertices] in each frame.

<a target="_top" name="model_numTexCoords">] int numTexCoords: Number of texture coordinates (not necessarily the same as the number of vertices).

<a target="_top" name="model_numTriangles">] int numTriangles: Number of triangles in each frame.

<a target="_top" name="model_numGlCommands">] int numGlCommands: Number of dwords (4 bytes) in the gl command list.

<a target="_top" name="model_numFrames">] int numFrames: Number of [#FRAMES">frames].

<a target="_top" name="model_offsetSkins">] int offsetSkins: Offset, in bytes from the start of the file, to the list of skin names.

<a target="_top" name="model_offsetTexCoords">] int offsetTexCoords: Offset, in bytes from the start of the file, to the list of texture coordinates.

<a target="_top" name="model_offsetTriangles">] int offsetTriangles: Offset, in bytes from the start of the file, to the list of triangles.

<a target="_top" name="model_offsetFrames">] int offsetFrames: Offset, in bytes from the start of the file, to the list of [#FRAMES">frames].

<a target="_top" name="model_offsetGlCommands">] int offsetGlCommands: Offset, in bytes from the start of the file, to the gl command list.

<a target="_top" name="model_offsetEnd">] int offsetEnd: Offset, in bytes from the start of the file, to the end (size of the file).

<a name="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.

<a name="triangleVertex">] typdef struct
{
   byte [#triangleVertex_vertex">vertex][3];
   byte [#triangleVertex_lightNormalIndex">lightNormalIndex];
} triangleVertex_t;

<a target="_top" name="triangleVertex_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 [#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. This will give you the vertex coordinate relative to the model's origin, which is at the origin, (0, 0, 0).

<a target="_top" name="triangleVertex_lightNormalIndex">] byte lightNormalIndex: This is an index into a table of normals kept by Quake2. To get the table, you need to download ">this zip file (1.7 MB), released by [http://www .idsoftware.com">id], that has the source code to all of the tools they used for quake2.

typedef struct
{
   float [#frame_scale">scale][3];
   float [#frame_translate">translate][3];
   char [#frame_name">name][16];
   [#triangleVertex">triangleVertex_t] [#frame_vertices">vertices][1];
} frame_t;

frame_t is a variable sized structure, however all frame_t structures within the same file will have the same size ([#model_numVertices">numVertices] in the [#model">header])

<a target="_top" name="frame_scale">] float scale[3]: This is a scale used by the [#triangleVertex_vertex">vertex] member of the [#triangleVertex">triangleVertex_t] structure.

<a target="_top" name="frame_translate">] float translate[3]: This is a translation used by the [#triangleVertex_vertex">vertex] member of the [#triangleVertex">triangleVertex_t] structure.

<a target="_top" name="frame_name">] char name[16]: This is a name for the frame.

<a target="_top" name="frame_vertices">] [#triangleVertex">triangleVertex_t] vertices[1]: An array of [#model_numVertices">numVertices] [#triangleVertex">triangleVertex_t] structures.

<a name="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. The array has [#model_numTriangles">numTriangles] structures in it.

<a name="triangle">]

typedef struct
{
   short [#triangle_vertexIndices">vertexIndices][3];
   short [#triangle_textureIndices">textureIndices][3];
} triangle_t;

<a target="_top" name="triangle_vertexIndices">] short vertexIndices: These three shorts are indices into the array of [#frame_vertices">vertices] in each [#frame">frames]. In other words, the number of triangles in a md2 file is fixed, and each triangle is always made of the same three indices into each frame's array of vertices. So, in each frame, the triangles themselves stay intact, their vertices are just moved around.

<a target="_top" name="triangle_textureIndices">] short textureIndices: These three shorts are indices into the array of [#textureCoordinate">texture coordinates].

<a name="SKINS">]

SKINS

<a name="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 f or "standard" Quake2). The skin files are regular pcx files.

<a name="textureCoordinate">]

typedef struct
{
   short [#textureCoordinate_st">s], [#textureCoordinate_st">t];
} textureCoordinate_t;

<a target="_top" name="textureCoordinate_t">] short s, t: These two shorts are used to map a vertex onto a skin. The horizontal axis position is given by s, and the vertical axis position is given by t. The range for s is greater than or equal to 0 and less than [#model_skinWidth">skinWidth] (0 <= s < skinWidth). The range for t is greater than or equal to 0 and less than [#model_skinHeight">skinHeight] (0 <= s < skinHeight). Note that the ranges are different than in the [#glCommandVertex_s">s] and [#glCommandVertex_t">t] members of the [#glCommandVertex">glCommandVertex] structure.

<a name="GL_COMMANDS">]

GL COMMANDS

<a name="GL_COMMANDS">]At [#model_offsetGlCommands">offsetGlCommands]<a name="GL_COMMANDS">] bytes into the file, there is the gl command list, which is made up of a series of [#model_numGlCommands">numGlCommands]<a name="GL_COMMANDS">] int's and float's, organized into groups. Each group starts with an int. If it is positive, it is followed by that many [#glCommandVertex">glCommandVertex_t]<a name="GL_COMMANDS">] structures, which form a triangle strip. If it is negative, it is followed by -x [#glCommandVertex">glCommandVertex_t]<a name="GL_COMMANDS">] structures, which fo rm a triangle fan. A 0 indicates the end of the list. The list is an optimized way of issuing commands when rendering with ">OpenGl<a name="GL_COMMANDS">]. <a name="glCommandVertex">]

typedef struct
{
   float [#glCommandVertex_st">s], [#glCommandVertex_st">t];
   int [#glCommandVertex_vertexIndex">vertexIndex];
} glCommandVertex_t;

<a target="_top" name="glCommandVertex_t">] float s, t: These two floats are used to map a vertex onto a skin. The horizontal axis position is given by s, and the vertical axis position is given by t. The range for s and for t is 0.0 to 1.0. Note that the ranges are different than in the [#textureCoordinate">textureCoordinate_t]<a target="_top" name="glCommandVertex_t">] structure. They are stored as floats here because that's the way Quake2 passes them to ">OpenGl<a target="_top" name="glCommandVertex_t">].

<a target="_top" name="glCommandVertex_vertexIndex">] int vertexIndex: Index into the array of [#frame_vertices">vertices]<a target="_top" name="glCommandVertex_vertexIndex">] stored in each [#frame">frame]<a target="_top" name="glCommandVertex_vertexIndex">].

MAXIMUMS

Quake2 has some pre-defined limits, so that dynamic memory does not need to be used. You can use these to your advantage to speed up loading if you want.

  • [#TRIANGLES">Triangles]: 4096
  • [#triangleVertex">Vertices]: 2048
  • [#textureCoordinate">Texture Coordinates]: 2048
  • [#FRAMES">Frames]: 512
  • [#SKINS">Skins]: 32

Quake and Quake2 are trademarks of ">id Software.
All trademarks used are properties of their respective owners.

<a name="glCommandVertex">]

<a name="textureCoordinate">]

<a name="triangle">]