Unofficial MDS Format Specification


Overview

MDS is defined as a triangle mesh using skeletal animation. Surfaces make up the basic model. They are described by geometry, level of detail and color data. Tags complement the format.

Geometry of a surface is described by grouping vertices into a triangle. Triangles are then grouped into a surface.

A progressive mesh algorithm is used to draw a surface with varying level of detail (LOD) during runtime. This is described by a collapse map.

Colorization of a surface is done by defining UV-maps and references to shaders. The UV-maps are used to color surfaces with solid color from a 2D image. Shaders manipulate surface properties. These properties define how the surface interacts with light sources present in a scene. Additionally vertex normals manipulate the shading of a surface.

Animation of a surface is done by storing vertex location and normal values in relation to a skeleton. This animation technique is also known as "skeletal animation". The way it works is that for each key frame the vertex location and normal values are influenced-by/weighted-against the location and orientation values of 1 or more bones. Thus, only bones contain animation data while vertex values are stored once in a special model pose called "binding pose".

Tags provide the possibility to attach external models to the model.

Symbols

Name Description
UINT8 unsigned 8-bit integer
INT16 signed 16-bit integer
UINT16 unsigned 16-bit integer
INT32 signed 32-bit integer
UINT32 unsigned 32-bit integer
F32 32-bit floating-point (IEEE-754)
ASCII 8-bit ASCII character
(*) Marks a list of objects of the same type. There can be multiple appearances of * inside those round brackets, for example (**) describes a list of lists.

Tables

MDS

Name Description Type
header reference to MDSHeader object. MDSHeader
frames list of MDSFrame objects, size=num_frames. MDSFrame (*)
bone_infos list of MDSBoneInfo objects, size=num_bones. MDSBoneInfo (*)
surfaces list of MDSSurface objects, size=num_surfaces. MDSSurface (*)
tags list of MDSTag objects, size=num_tags. MDSTag (*)

Notes:

Container object. References all MDS data.

MDSHeader

Name Description Type
ident magic number, ASCII encoded, length 4, reads "MDSW". 4*ASCII
version version number, latest known is 4. UINT32
name model name, usually its pathname, ASCII encoded, null-terminated, length 64. 64*ASCII
lod_scale TODO F32
lod_bias TODO F32
num_frames number of animation frames. UINT32
num_bones number of bones. UINT32
ofs_frames file offset to field of frames. UINT32
ofs_bone_infos file offset to field of bone infos. UINT32
torso_parent_bone TODO UINT32
num_surfaces number of surfaces. UINT32
ofs_surfaces file offset to field of surfaces. UINT32
num_tags number of tags. UINT32
ofs_tags file offset to field of tags. UINT32
ofs_end file offset to end of file. UINT32

Notes:

General information about MDS data. Used mainly to navigate file data.

MDSFrame

Name Description Type
frame_info reference to MDSFrameInfo object. MDSFrameInfo
bone_frames_compressed list of MDSBoneFrameCompressed objects, size=num_bones. MDSBoneFrameCompressed (*)

Notes:

Container object. References bounding volume and bone animation data.

MDSFrameInfo

Name Description Type
min_bound location coordinates of min corner of minimum bounding box. 3*F32
max_bound location coordinates of max corner of minimum bounding box. 3*F32
local_origin TODO 3*F32
radius TODO F32
root_bone_location TODO 3*F32

Notes:

Describes bounding volume information: axially aligned bounding box and bounding sphere. Additionally contains the root bone location.

MDSBoneFrameCompressed

Name Description Type
orientation orientation as euler angles in frame. Index 0 = pitch, index 1 = yaw, index 2 = roll. Index 3 is not used and contains a default value. 4*INT16
location_dir location in spherical coordinates. Index 0 = latitude, index 1 = longitude. 2*INT16

Notes:

Bone location and orientation in a specific frame.

Bone orientation values are given as compressed 16-Bit integers. To convert this range to a range of floats, the given value is linearly mapped. For this, a hard coded scale value is used. The result is an angle in the range of [0, 360). To convert the angles to a rotation matrix, we first roll, then pitch, then yaw (intrinsic). TODO recheck signed integer to angle range

Bone location values are given as offset direction from a parent bone. Combined with the parent_dist value in the bone info field and the parent bones frame location, one can calculate the bones frame location. Linear mapping is done the same way as with the bone orientation values to get the angle values from the range of integer to the range of floats. To convert the angles to a direction vector, we first pitch (latitude), then yaw (longitude).

MDSBoneInfo

Name Description Type
name bone name, ASCII encoded, null-terminated, length 64. 64*ASCII
parent_bone parent bone as index into the list of bone_infos. UINT32
torso_weight TODO F32
parent_dist distance to parent bone. F32
flags this bone is either a bone (0) or a tag (1). UINT32

Notes:

Frame independent bone information.

MDSSurface

header reference to MDSSurfaceHeader object. MDSSurfaceHeader
vertices list of MDSVertex objects, size=num_vertices. MDSVertex (*)
triangles list of MDSTriangle objects, size=num_triangles. MDSTriangle (*)
collapse_map reference to MDSCollapseMap object. MDSCollapseMap
bone_refs reference to MDSBoneRefs object. MDSBoneRefs

Notes:

Container object. References surface data.

Background:

Surfaces are described by geometry, level-of-detail and color data. A model can consist of multiple surfaces.

MDSSurfaceHeader

MDSSurfaceHeader
Name Description Type
ident magic number, ASCII encoded, length 4. 4*ASCII
name surface name, ASCII encoded, null-terminated, length 64. 64*ASCII
shader shader name, ASCII encoded, null-terminated, length 64. 64*ASCII
shader_index TODO UINT32
min_lod minimum amount of vertices for the surface or maximum amount of collapse operations during runtime. UINT32
ofs_header relative offset from this surface to start of file. This is a negative number. UINT32
num_vertices number of vertices. UINT32
ofs_vertices file offset to field of vertices. UINT32
num_triangles number of triangles. UINT32
ofs_triangles file offset to field of triangles. UINT32
ofs_collapse_map file offset to collapse map. UINT32
num_bone_refs number of bones this surface references. UINT32
ofs_bone_refs file offset to bone references. UINT32
ofs_end file offset to end of surface. UINT32

Notes:

General information about a surface. Used mainly to navigate surface data.

MDSVertex

Name Description Type
normal vertex normal coordinates. 3*F32
tex_coords u and v coordinates in UV-space as tuple. 2*F32
num_weights number of weights for this vertex. UINT32
fixed_parent not used. UINT32
fixed_dist not used. F32

Notes:

Vertex location, normal and texture coordinates.

The number of weights usually does not exceed 3 (at least i have never seen any model with more).

Background:

Vertex normals manipulate the shading of a surface (for example smooth or flat).

Texture coordinate values refer to the process of UV-mapping.

MDSWeight

Name Description Type
bone_index bone that exercises a weighted influence over the vertex location given as index into the list of bone_infos. UINT32
bone_weight amount of influence from the bone over the vertex location. F32
location_offset location coordinates given in bone space. TODO recheck with source code. 3*F32

Notes:

Weights are used to define a vertex location in conjunction with all other weights of a vertex. The weights and their offsets are specified in binding pose.

The sum of all weights for a vertex should always be equal to 1.

MDSTriangle

Name Description Type
indices indices into the list of vertices. The order defines in which direction the face normal is pointing. 3*UINT32

Notes:

A triangle for a surface.

MDSCollapseMap

Name Description Type
mappings indices into the list of vertices for this surface, size=num_vertices. num_vertices*UINT32

Notes:

The collapse map is used to render a surface with varying level of detail (LOD) dependent on view distance during runtime (progressive mesh algorithm).

Background:

The collapse map is a list of vertex indices pointing into the list of vertices for this surface. The value j at index i of the collapse map describes a collapse operation. This operation can be read as "vertex i is to be mapped/collapsed to vertex j".

A user will take a fully detailed mesh and gradually reduce vertex and triangle count at runtime by using the pre-calculated collapse map. For this, he first determines the amount of vertices the mesh should have. Then he applies the collapse operations starting from the end of the collapse map.

The particular method used was described by Stan Melax in a publication from November 1998, see "A Simple, Fast, and Effective Polygon Reduction Algorithm" for further details. A demo implementation can be found at: https://github.com/melax/sandbox/tree/master/bunnylod

MDSBoneRefs

Name Description Type
bone_refs indices into the list of bone_infos for this surface, size=num_bone_refs. num_bone_refs*UINT32

Notes:

Defines which bones a surface references. Probably used for optimization inside the engine. Needs to be hierarchically ordered.

MDSTag

Name Description Type
name tag name, ASCII encoded, null-terminated, length 64. 64*ASCII
torso_weight scale torso rotation about torso parent by this. F32
parent_bone bone that controls the tags location and orientation. Given as index into the list of bone_infos. UINT32

Notes:

MDS stores location and orientation values for a tag in the field of bones, so tags are actually bones with a special flag.

Background:

Tags are used to attach external models to a model. Attachment means that the external models origin aligns itself with the models tag location and orientation. As the external model is parented to the tag (nested in tag space), any animation of the tag will also affect the external model.

Domain specific scripts tell the engine which external models to attach to a given tag. These scripts are either located in mapscript files (attachtotag command) or .skin files. Sometimes they are also hard coded.

An example use case is a hat model (defined separately) attached to a head model. This way, characters can be assembled with different looks without having to duplicate their model definitions. Tags therefore support reuse.

Another example use case is that of a tank turret model attached to a tank model. Instead of having a shooting animation (rotate turret left, shoot, rotate turret right) be recorded as vertex positions across several key-frames inside a single model, a tag can be used to control  the shooting animation of a separated model. This safes memory, as the  tags animation data most likely takes much less space compared to the animation data of the tank turret inside a single model.

However, reuse and memory savings are traded against loss in performance. Vertex positions of the external models have to be recalculated against the current frame tags location and orientation.

UML View

UML view of MDS file format
Figure: UML view of MDS file format