MDX
INTRO
This page will try and give some sort of technical documentation on the Kingpin model format (.mdx).
These specs can be used freely for whatever you want. I only ask that people send me corrections, suggestions, etc.
Kingpin models are stored in files with the .mdx extension. A single mdx file contains the model's geometry, frame information, skin filename(s), skin texture mapping, and bounding box max's and min's. 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 numTriangles;
int numGlCommands;
int numFrames;
int numSfxDefines;
int numSfxEntries;
int numSubObjects;
int offsetSkins;
int offsetTriangles;
int offsetFrames;
int offsetGlCommands;
int offsetVertexInfo;
int offsetSfxDefines;
int offsetSfxEntries;
int offsetBBoxFrames;
int offsetDummyEnd;
int offsetEnd;
} model_t;
- magic: A "magic number" used to identify the file. The magic number is 1481655369 in decimal (0x58504449 in hexadecimal). The magic number is equal to the int "IDPX" (id polygon Xatrix), which is formed by ('I' + ('D' << 8) + ('P' << 16) + ('X' << 24)).
- version: Version number of the file. Always 4.
- skinWidth: Width of the skin(s) in pixels.
- skinHeight: Height of the skin(s) in pixels.
- frameSize: Size of each frame in bytes.
- numSkins: Number of skins associated with this model.
- numVertices: Number of vertices in each frame.
- numTriangles: Number of triangles in each frame.
- numGlCommands: Number of dwords (4 bytes) in the gl command list.
- numFrames: Number of frames.
- numSfxDefines: Number of SFX definitions.
- numSfxEntries: Number of SFX entries.
- numSubObjects: Number of subobjects in the `.mdx` file.
- offsetSkins: Offset, in bytes from the start of the file, to the list of skin names.
- offsetTriangles: Offset, in bytes from the start of the file, to the list of triangles.
- offsetFrames: Offset, in bytes from the start of the file, to the list of frames.
- offsetGlCommands: Offset, in bytes from the start of the file, to the GL command list.
- offsetVertexInfo: Offset, in bytes from the start of the file, to the vertex info list.
- offsetSfxDefines: Offset, in bytes from the start of the file, to the SFX definition list.
- offsetSfxEntries: Offset, in bytes from the start of the file, to the SFX entry list.
- offsetBBoxFrames: Offset, in bytes from the start of the file, to the bounding box frames list.
- offsetDummyEnd: Offset, in bytes from the start of the file, to the end (same as offsetEnd).
- 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. Kingpin, Quake 2 (and Quake) models contain only triangles.
typedef struct
{
byte vertex[3];
byte lightNormalIndex;
} triangleVertex_t;
- 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, multiply each of the bytes by their respective float scale in the frame_t structure, and then add the respective float translation. This provides the vertex coordinate relative to the model's origin, which is at the origin, (0, 0, 0).
- lightNormalIndex: This is an index into a table of normals kept by Quake2. The table can be obtained from this zip file, released by id Software, containing the source code of tools used for Quake2.
typedef struct
{
float scale[3];
float translate[3];
char name[16];
triangleVertex_t vertices[1];
} frame_t;
- scale[3]: A scale used by the vertex member of triangleVertex_t.
- translate[3]: A translation used by the vertex member of triangleVertex_t.
- name[16]: The name of the frame.
- vertices[1]: An array of numVertices triangleVertex_t structures.
frame_t is a variable-sized structure; however, all frame_t structures within the same file will have the same size (numVertices in the header).
TRIANGLES
Kingpin models are made up of only triangles. At offsetTriangles in the file is an array of triangle_t structures. The array contains numTriangles structures.
typedef struct
{
short vertexIndices[3];
short textureIndices[3];
} triangle_t;
- vertexIndices[3]: These three shorts are indices into the array of vertices in each frame. In other words, the number of triangles in a `.mdx` 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.
- 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 in the file. Each skin name is a char[64]. The name is a path to the skin, relative to the base game directory (e.g., main for Kingpin). The skin files are compressed and uncompressed 24-bit TGA files.
GL COMMANDS
At offsetGlCommands bytes into the file, there is the GL command list, which is made up of a series of numGlCommands ints and floats, organized into groups. Each group starts with an int (TrisTypeNum).
- If positive, it is followed by another int (SubObjectID) and that (first int) many glCommandVertex_t structures, which form a triangle strip.
- If negative, it is followed by another int (SubObjectID) and -x glCommandVertex_t structures, which form a triangle fan.
- A 0 indicates the end of the list.
The list is an optimized way of issuing commands when rendering with OpenGL.
NOTE: If there are more sub-objects than 1, then this set of `glCommandVertex_t` structs continues after the first set of GL commands.
typedef struct
{
float s, t;
int vertexIndex;
} glCommandVertex_t;
typedef struct
{
int TrisTypeNum;
int SubObjectID;
glCommandVertex_t GLCmdVerts[TrisTypeNum];
} glGLCommands_t;
- s, t: These two floats are used to map a vertex onto a skin. The range for s and t is 0.0 to 1.0. Note that the ranges differ from those in the textureCoordinate_t structure. They are stored as floats because that's how Kingpin passes them to OpenGL.
- SubObjectID: Integer possibly specifying the sub-object's ID.
- vertexIndex: Index into the array of vertices stored in each frame.
VERTEX INFO
At offsetVertexInfo bytes into the file, there is the vertex info list, which is made up of a series of numVertices ints, all grouped by the sub-object they belong to.
For example, if the first sub-object has 4 vertices and the second sub-object has 2 vertices, the HEX code in the MDX would look like this: 0100 0000 0100 0000 0100 0000 0100 0000 0200 0000 0200 0000
typedef struct
{
int Object[numVertexInObject];
} SubObjectsVerts_t;
typedef struct
{
SubObjectsVerts_t VertexInfo[numSubObjects];
} VertexInfo_t;
The `VertexInfo[numSubObjects]` array groups vertex info for each sub-object. All values in an array correspond to the sub-object number.
SFX DEFINITION LIST
At offsetSfxDefines bytes into the file, there is the SFX definition list, which is made up of a series of ints and floats. If `numSfxDefines` is zero, the structure points to `offsetBBoxFrames`.
typedef struct
{
int type;
int flags;
int velocity_type;
int velocity_speed_up;
float gravity;
int spawn_interval;
float random_spawn_interval;
float start_alpha;
float end_alpha;
float fadein_time;
float lifetime;
float random_time_scale;
float start_width;
float end_width;
float start_height;
float end_height;
float random_size_scale;
} Define_t;
typedef struct
{
Define_t SfxDefintions[numSfxDefines];
} SfxDefine_t;
SFX ENTRY
At offsetSfxEntries bytes into the file, there is the SFX entry list. An MDX file can have only one or no SFX entries.
typedef struct
{
int index; // Vertex to show SFX on
int define_no;
int vertexindex;
char SfxFrames[64];
} SfxEntry_t;
`SfxFrames[64]` contains 512 bits/64 bytes representing animation frames. A bit set to 1 indicates the SFX is shown on that frame; a bit set to 0 means it's not shown.
BOUNDING BOX LIST
At offsetBBoxFrames bytes into the file, there is the bounding box list. Each sub-object has its own bounding box for each frame, which stores its MinX, MinY, MinZ, MaxX, MaxY, and MaxZ.
typedef struct
{
float MinX;
float MinY;
float MinZ;
float MaxX;
float MaxY;
float MaxZ;
} BBox_t;
typedef struct
{
BBox_t BoxFrames[numFrames];
} BFrames_t;
typedef struct
{
BFrames_t Boxes[numSubObjects];
} BBoxFrames_t;
MAXIMUMS
Kingpin has pre-defined limits to avoid dynamic memory use:
Kingpin is a trademark of Xatrix/Gray Matter. All trademarks are properties of their respective owners.