DMX model
Jump to navigation
Jump to search
The DMX model format replaces Studiomdl Data. Only binary-encoded files can be compiled.
For sanity's sake, the data structure is expressed in pseudo-C++:

class DmeModelRoot
{
// model and skeleton should point to the same object
DmeModel* model;
DmeModel* skeleton;
DmeCombinationOperator* combinationOperator; // flex animations only
};
class DmeCombinationOperator // flex controller global settings
{
DmeCombinationInputControl controls[];
Vector controlValues[]; // rest position...but why a 3D vector?
Vector controlValuesLagged[]; // unknown
bool usesLaggedValues;
DmeMesh* dominators[]; // unknown
DmeMesh* targets[]; // mesh with the shapes on
};
class DmeCombinationInputControl // a flex controller
{
CUtlString rawControlNames[]; // which controls are being wrapped
bool stereo; // equivalent to QC 'split'?
bool eyelid; // flags as an eyelid used by AI for blinking
float wrinkleScales[]; // wrinklemap stuff; one value for each named control.
};
class DmeModel
{
DmeTransform* transform; // global model transform? DAG not supported here?
DmeAttachment* shape;
bool visible;
DmeModel children[];
DmeJoint jointList[];
DmeTransformList baseStates[]; // bone positions; only ever seen with one value
CUtlString upAxis; // uppercase character
};
// A "DAG" is a generic Maya container, appearing here in order to transform objects.
// It can take the place of a DmeMesh, DmeJoint or DmeAttachment at any time.
class DmeDag
{
DmeTransform* transform;
bool visible;
void children[]; // never seen used
// One of the following:
CUtlString name // of a DmeJoint
DmeMesh* shape;
DmeAttachment* shape;
};
class DmeJoint // a bone
{
DmeTransform* transform;
void* shape; // only seen empty
bool visible;
DmeJoint children[];
bool lockInfluenceWeights;
};
class DmeTransformList
{
DmeTransform transforms[];
};
class DmeTransform // name is of a defined model if there are children, otherwise blank
{
Vector position;
Quaternion orientation;
};
class DmeAttachment // an attachment
{
bool visible;
bool IsRigid; // does not animate with associated bone
bool isWorldAligned; // transform in world co-ords
};
class DmeMesh
{
bool visible;
void* bindState; // only seen empty
DmeVertexData* currentState; // pointer to default baseState
DmeVertexData baseStates[]; // only ever seen with one value
DmeVertexData deltaStates[]; // unknown
DmeFaceSet faceSets[];
Vector2D deltaStateWeights[]; // unknown
Vector2D deltaStateWeightsLagged[]; // unknown
};
class DmeVertexData // mesh data
{
CUtlString vertexFormat[]; // positions, normals, textureCoordinates, [jointWeights, jointIndices]
int jointCount; // total number of bones this mesh is weighted to
bool flipVCoordinates; // left-handed to right-handed?
// In the next three cases, the "Indicies" array contains one entry for each vertex.
// the indice value defines which value from the 'real' array the vertex takes. In this
// way, vertices can share data. This is a useful optimisation since each poly has its
// own three verts, even if they overlap other verts.
Vector positions[];
int positionsIndices[];
Vector normals[];
int normalsIndices[];
Vector2D textureCoordinates[];
int textureCoordinatesIndices[];
// Weightmapping; optional. The size of both arrays is equal to ( sizeof(positions) * jointCount );
// it is not possible for two verts in the same place to be weighted differently.
float jointWeights[]; // weight
int jointIndicies[]; // index in DmeModel::jointList
};
class DmeFaceSet // defines faces, including their material
{
DmeMaterial* material; // the material these faces are drawn with
int faces[]; // the vertices that make up each face, delimited by -1. Quads and n-gons allowed.
};
class DmeMaterial // a material
{
CUtlString mtlName; // relative to \game\materials\, no extension
};