GMDC Data Structure
A Datacentric View of the GMDC
There are six major divisions used in building a GMDC: Header, Elements, Linkages, Groups, Model and Subset.
The general structure of the file is the header followed by each of the other blocks. Each block begins with a count of the component parts (which have various sizes) that enable it to be read as a stream. One common technique is the use of a modified ‘pascal’ style string for names. This string has the first byte, in the range of 0 to 128, indicating the number of characters to follow, followed by that many characters.
The Header is built from standard DBPF RCOL package identifier properties. Instead of discussing the RCOL layout, we will describe it as it applies to the GMDC below:
short Language; // 1 short StringStyle; // 0xffff long RepeatValue; // 0 long IndexValue; // 1 (or larger if more than one GMDC) long FileType; // 0xAC4F8687 (GMDC identifier) char NameLen; // bytes (0 – 128) in following name char Name[NameLen]; // ‘cGeometryDataContainer’ long BlockID; // 0xAC4F8687 long Version; // 1, 2 or 4 used char NameLen; // bytes (0 – 128) in following name char Name[NameLen]; // ‘cSGResource’ long ResourceID; // 0 long ResourceVersion; // 2 char NameLen; // bytes (0 – 128) in following name char FileName[NameLen]; // ex: ‘afBodyNaked_tslocator_gmdc’
Some possibilities exist in the RCOL definition for the start of the header to differ. Generally, to load a GMDC you check the values against this list for a sanity check, and then retain the Version (1, 2 or 4) and the FileName. The size of the header is 67 bytes plus the number of characters in the filename plus one.
When creating a GMDC, building the header is as simple as writing out the 67 bytes before the filename, writing out a one-byte filename length, and the writing out the filename. Most of the meshes use Version = 4 in the game files, so consistently outputting a version 4 will simplify the job.
The Elements section is a collection of typed data arrays, the basic mesh elements, that will be referenced later when the face structure is defined.
long NumRecs; // count of total elements long Identity; // typing value, detailed later long RepeatCount; // count of repeats for the same type long BlockFormat; // data element sizes (detailed below) long SetGroup; // elements formats (detailed below) long BlockSize; // number of bytes that follow (calculate) char Block[BlockSize]; // these may be sets of floats or bytes long ItemCount; // number of 2 or 4 byte elements to follow
Only one of the following two apply (per version value):
short Array2[ItemCount]; // used when version == 4 long Array4[ItemCount]; // used for versions 1 and 2
The Identity field is a value from the following list:
0x1C4AFC56 Blend Indices 0x5C4AFC5C Blend Weights 0x7C4DEE82 Target Indices 0xCB6F3A6A Morph Normal Deltas 0xCB7206A1 Colour 0xEB720693 Colour Deltas 0x3B83078B Normals List 0x5B830781 Vertices 0xBB8307AB UV Coordinates 0xDB830795 UV Coordinate Deltas 0x9BB38AFB Binormals 0x3BD70105 Skin (Bone) Weights 0xFBD70111 Bone Assignments 0x89D92BA0 Bump Map Normals 0x69D92B93 Bump Map Normal Deltas 0x5CF2CFE1 Morph Vertex Deltas 0xDCF2CFDC Morph Vertex Map 0x114113C3 (EP4) VertexID 0x114113CD (EP4) RegionMask
The BlockFormat is one of these four values:
0x00 single float (4 byte length) 0x01 paired floats (8 total bytes) 0x02 triple floats (12 bytes total) 0x04 unsigned long or bytes (4 bytes)
The SetGroups are one of the following values:
0x00 Main 0x01 Norms 0x02 UV 0x03 Secondary
The elements are generally collects of vertices, normals, UVs, morph values, bone assignments and skin weights that are tied together by the face references to build a 3D object.
Elements appear ordered in sets. There is usually an empty set of each used Identity that comes first, followed by one or more referenced sets. The empty sets appears necessary, perhaps to allocate storage space.
A set of Identities will be built as matched arrays, that is, one of the basic size units (per BlockFormat) of each set will align with the vertex of the same index. While many elements appear only when mesh features are used, the first and each subsequent vertex will have a corresponding element in each included set. What we mean here is that the first vertex will correspond with the first normal, the first UV, the first bone assignment and so on.
The following discussion lists the main types used in Sims2 meshes in the order they are normally found (all but the first two are essentially optional, being present only when needed to support a mesh property):
Vertices (0x5B830781 [format 0x02]) – These are the main building elements, and are a set of coordinates in local 3D space for a point, normally one corner of a triangle. Each vertex has three floats of four bytes each (IEEE single-precision floating point number).
Normals (0x3B83078B [format 0x02]) – These are standard vertex normals. Like the vertices, they are three floats, but represent a vector in space, and thus are normalized (all values are smaller than 1.0).
UV Coordinates (0xBB8307AB [format 0x01]) – These are paired floats that represent the fractional distance from the upper-left corner to map the vertex into the texture map.
UV Coordinate Deltas (0xDB830795 [format 0x04]) – The purpose of these is undetermined, and may be misnamed. They are normally empty occurring only in the initial set of elements, but sometimes are found in the regular sets.
Target Indices (0x7C4DEE82 [format 0x02]) – These only appear in the empty initial set of elements. They have an ordinal relationship with the morph names, but do not appear to be needed by the loader. The contents, when present, have both vertices and vertex indices that are believed to be offsets to the Subset (Bounding Mesh) group when the corresponding morph is active. This is usually the only element that has a set of items after the Block.
Bone Assignments (0xFBD70111 [format 0x04]) – There are four bytes here. If this element is present, the first byte (lsb if read as a long) is the main bone assignment. A value of 255 (-1) means no bone is assigned, otherwise the value is the bone index (defined later). So, up to four bone assignments are available per-vertex.
Skin (Bone) Weights (0x3BD70105 [format 0x00, 0x01 or 0x02]) – This element is present if the Bone Assignments element is present. While there are four slots to assign bones, the usage is determined by the Skin Weights. A single weight section will normally always contain values of 1.0, indicating that all the influence on the skin will be obtained from the first bone assignment. A dual weight section will have two weights per vertex that should total exactly 1.0. Depending on the animation needs, this may be all weighted on one assignment or spread between two. A three weight section will support three or four bone assignments. Three is the simple one-to-one correspondence with the bone assignments, and the total weighting should add up to 1.0 (failing to total 1.0 will result in animation and other display issues). Three weights may also be made to work with four bone assignments by implying the fourth weight. This is done by adding the three weights up and subtracting the sum from 1.0. The difference is the weight to be applied to the fourth assignment. For example, spreading four assignments equally would have weights of 0.25, 0.25 and 0.25, these total 0.75 and thus leave 0.25 when subtracted, which is the weighting to be applied to the fourth assignment.
Morph Vertex Deltas (0x5CF2CFE1 [format 0x02]) -
If there are morphs present in the GMDC, then there will be at least one Morph Vertex Deltas (MVD) section, optionally a matching Morph Normal Delta (MND) plus a Morph Vertex Map (MVM). There can be up to four MVD sections per Vertex element. Each of the MVD elements is not a complete morph, but rather a data repository that holds values that are to be added to a vertex (a delta value) when a morph is triggered. How these are keyed is through the MVM element.
Morph Normal Deltas (0xCB6F3A6A [format 0x02]) -
When these are used, they are deltas to adjust the normals for a morph. If they are used, they are aligned with the MVD because the same morph map is used for both types.
Morph Vertex Map (0xDCF2CFDC [format 0x04]) -
The Morph Vertex Map is a collection of 4-byte morph name index values that map the MVD and MND to a vertex for a particular morph. The limit of 4-bytes to the format means that any one vertex can have no more than four morphs. How this map works is that in a section we haven’t reviewed yet there is a set of morph (blend) name pairs. Each of these has an implied index value based on its position on the list (starting at zero). Every legal value to be used in a morph map should have a morph name pair. The first of each 4-byte set maps an index value to the first MVD that is grouped with the vertices. The next byte maps to the second MVD, and so on, to the third and fourth sets (if used). The end result is that when a specific target value, e.g. 1, is present in the first byte, when the morph is triggered the game will add the delta values from the first MVD to the vertex coordinates to alter the mesh shape. If the ‘1’ had been in the second byte instead, the delta values used would have been from the second MVD element.
Bump Map Normals (0x89D92BA0) – These are also known as Tangent Normals, and are used to define a ray that would lie on plane tangent to the vertex. This is used for allowing bump maps to alter the apparent height of the surface. While it would have been possible for the game to calculate these at run time, by pre-calculating these values at mesh creation time the loading time is reduced.
The linkages section groups elements into sets. Although their position in the elements section is generally ordered by groupings, it is through this part that they are linked to the face definitions.
long Count; // count of total sets
for each Count:
long IndexCount; // number of indexes in block A
one of the following, per version
short Indices[IndexCount]; // for version == 4 long Indices[IndexCount]; // for versions 1 and 2
Repeat above for Blocks B, C and D (generally zeroed out).
The values for Indices are the applicable index value for an element block from the previous section. Generally, there will be at least two values here, Vertices and Normals, likely a third, UVs, sometimes Target Indices, and then (if used) Bone Assignments, Skin Weights, Morph Vertex Deltas(s), Morph Normal Deltas and a Morph Map, and maybe the Bump Map Normals.
The sets from this section are indexed, and may be referenced by more than one set of triangles (group), or there may be a one-to-one relationship between groups and sets, or the two may be mixed.
This section is where the triangle sets, or groups, are defined and stored. Each group will have a link index, which indicates the sets grouping definition from the Linkages section, and each triangle consists of three vertex indices, each of which then indicates which vertex and all associated elements are to be used.
long Count; // count of total groups
For each group:
long PrimitiveType; // default = 2 long LinkIndex; // Index of set from Linkages section char NameLen; // bytes (0 – 128) in following name char Name[NameLen]; // group name long FaceCt; // faces*3 (number of triangle points)
One of the following two, per version:
short VertexIndex[FaceCt]; // version == 4 long VertexIndex[FaceCt]; // versions 1 and 2
long Opacity; // alpha value. 0xffffffff for opaque. long SubsetCount; // versions 2 and 4 only short SubsetIndices[SubsetCount];// version 4 only long SubsetIndices[SubsetCount];// version 2 only
The SubsetIndices map the standard bone values, as defined in the CRES, to the values used in the GMDC Bone Assignment elements. The mapping works by using the Bone Assignment value as the index, and retrieving the Standard Bone Value from the array. The SubsetCount should be equal to the number of bones actually referenced in the group, or animation difficulties will be encountered.
This contains the joint definitions, expressed as sets of 7 float values known as Quaternions, the morph names and for non-IK animated meshes a model of the entire entity, consisting of only vertices and faces, which is used as a bounding mesh for the game to use to determine intersection on mouse-clicks.
long Count // number of transform blocks float Quaternion[Count]; // ordered: x,y,z,w rotation; x,y,z transform long PairCt; // number of morph name pairs
PairCount number of:
char NameLen1; // bytes (0 – 128) in following name char Name[NameLen1]; // blend group name char NameLen2; // bytes (0 – 128) in following name char Name[NameLen2]; // assigned element name
long VCount; // number of vertices in Model
If VertexCount == 0, then skip the next items
long FCount; // number of faces(*3) in model float Vertices[VCount]; // XYZ for each vertex
Use one of the following two items, per version:
short Faces[FCount]; // version == 4 long Faces[FCount]; // versions 1 and 2
The transform blocks are values used to translate and then rotate a point from 0,0,0 to the joint position via a Quaternion. The name pairs are the morph names. The paired index position indicates the target value (one or more of these names may be empty) that is used in the Morph Map(s).
The Model is used where there is no IK animation (essentially models that are not hair, body, clothing, face or pet meshes). It can be built by placing all the vertices from all the groups into the single Vertices array and then putting all the faces together in the Faces array, making sure to add the number of previous group vertices to each point vertex index. A more sophisticated algorithm would eliminate all duplicate vertices as it built the Vertices and Faces arrays. This is more computationally intensive at mesh creation time, but creates a smaller output file and will reduce the memory and computation time required at run time.
Essentially, the Subset section replaces the Model portion of the Model section. It serves the same purpose, but the Subset is defined bone-by-bone, and the vertex position values have been reverse-rotated and then translated using the transform blocks from the Model section.
long SubCount; // number of subsets (one per transform)
One of each for each SubCount:
long VCount; // number of vertices for this bone
The rest of the items only if VCount is not zero:
long FCount; // number of faces(*3)
float Vertices[VCount]; // XYZ (transformed) for each vertex
One of the following two, per version:
short Faces[FCount]; // version == 4 long Faces[FCount]; // versions 1 and 2
This transformed bounding mesh, sorted by bone, is used in IK animated models so that the bounding mesh can be reshaped to fit the model by using the transforms that represent the bone positions at the time it is needed.