A text .x file is the header xof 0303txt 0032
(or 0302), then any number of template declarations and data objects. The
format itself knows nothing about meshes: templates declare data types, much like C
structures, and data objects fill them in. The standard templates for meshes,
materials, frames and animation are listed on the template pages.
Reserved words
These words are reserved and must not be used as names:
| Reserved words | ||
|---|---|---|
ARRAY | DWORD | UCHAR |
BINARY | FLOAT | ULONGLONG |
BINARY_RESOURCE | SDWORD | UNICODE |
CHAR | STRING | WORD |
CSTRING | SWORD | |
DOUBLE | TEMPLATE |
Microsoft’s own examples write template, array and the type
names in lower case as often as upper case, and readers accept both.
BINARY, BINARY_RESOURCE and ULONGLONG are
reserved but not described.
Template declarations
template name {
<UUID>
member 1;
…
member n;
[restrictions]
}
The name is made of letters, digits and underscores, and must not begin with a digit.
The UUID identifies the template wherever it is used. It is written in the Open
Software Foundation’s DCE form between angle brackets, for example
<3D82AB43-62DA-11cf-AB39-0020AF71E433>. A template may only use types
declared earlier in the stream: there are no forward references.
A file may declare the templates it uses before its data, and most exported files do. A reader that already knows the standard templates, as D3DX does, does not need them.
Members and primitive types
A member is a type followed by an optional name and a semicolon. The type is either a primitive type or a template declared earlier.
| Type | Size | Notes |
|---|---|---|
WORD | 16 bits | Unsigned integer |
DWORD | 32 bits | Unsigned integer |
SWORD | 16 bits | Signed integer; a reserved word and a binary token, missing from Microsoft’s table |
SDWORD | 32 bits | Signed integer; likewise |
FLOAT | IEEE float | 32 or 64 bits, as the header’s float size says |
DOUBLE | 64 bits | IEEE double |
CHAR | 8 bits | Character |
UCHAR | 8 bits | Unsigned character |
BYTE | 8 bits | Unsigned byte |
STRING | Variable | A string, written in double quotes |
CSTRING | Variable | Formatted C string; not supported |
UNICODE | Variable | Unicode string; not supported |
Any type can form an array. The size in brackets is a number or the name of an earlier member of the same template, whose value then gives the size. Arrays may have several dimensions:
array DWORD FixedHerd[24];
array DWORD Herd[nCows];
array FLOAT Matrix4x4[4][4];
Open, closed and restricted templates
The last part of a template says which data objects may be nested inside an object of that type.
| Kind | Written | Allows inside |
|---|---|---|
| Open | [ ... ] | Any data object |
| Restricted | [ Directory <UUID>, File <UUID> ] | Only the named types; each UUID is optional |
| Closed | Nothing | No nested objects |
template Mesh {
<3D82AB44-62DA-11cf-AB39-0020AF71E433>
DWORD nVertices;
array Vector vertices[nVertices];
DWORD nFaces;
array MeshFace faces[nFaces];
[ ... ] // an open template
}
template Vector {
<3D82AB5E-62DA-11cf-AB39-0020AF71E433>
FLOAT x;
FLOAT y;
FLOAT z;
} // a closed template
Data objects
Identifier [name] {
[<UUID>]
member 1;
…
member n;
}
The identifier is required and must be a template or primitive type declared earlier. The name is optional, but a named object can be referred to later. An object may also carry its own UUID. The members are written in the template’s order, followed by any nested objects the template allows.
| Member kind | Example |
|---|---|
| A nested data object | Material { … } |
| A reference to an earlier object | { name }, { <UUID> } or { name <UUID> } |
| Integer list | 1; 2; 3; |
| Float list | 1.0; 2.0; 3.0; |
| String list | "Moose"; "Goats"; "Sheep"; |
A reference stands for the whole object it names, so the same material can serve several meshes and an animation can name the frame it moves. References can only be used for optional members, the nested objects, not for the template’s own members.
Commas and semicolons
The rules are strict and are where most hand-written files go wrong: a semicolon ends every data item, and a comma separates the items of an array. A member that is itself a template ends with its own semicolon and then the one of the member that holds it, so semicolons pile up at the end of nested values.
| Template | Data | Why |
|---|---|---|
DWORD myvar; | 1; | One item, one semicolon |
FLOAT aFloat; mytemp aTemp; where mytemp holds two DWORDs | 1.1; 2; 3;; | The second ; after 3 ends aTemp |
array DWORD myvar[3]; | 1, 2, 3; | Commas between items, a semicolon to end the array |
DWORD count; array mytemp tempArray[count]; | 3; 1;2;, 3;4;, 5;6;; | Each item ends with ;, items are separated by ,, and the array ends with ; |
So a Vector in an array of vertices is written 0.0; 1.0; 0.0;,
and the last one 0.0; 1.0; 0.0;;. Microsoft’s own explanation of the
second example says the extra semicolon ends the container, which does not fit its
array example; the reading above fits both. Exporters have not always followed the
rules exactly, and readers such as Assimp tolerate a missing or extra separator.
Example
xof 0303txt 0032
Material RedMaterial {
1.000000;0.000000;0.000000;1.000000;; // faceColor: red, opaque
0.000000; // power
0.000000;0.000000;0.000000;; // specularColor
0.000000;0.000000;0.000000;; // emissiveColor
}
Frame Root {
FrameTransformMatrix {
1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0;;
}
Mesh Triangle {
3;
0.0;0.0;0.0;,
1.0;0.0;0.0;,
0.0;1.0;0.0;;
1;
3;0,1,2;;
MeshMaterialList {
1;
1;
0;
{ RedMaterial }
}
}
}
Comments and white space
Comments exist only in text files, and may appear anywhere. A comment starts with
//or#and runs to the end of the line. Spaces, tabs and line breaks separate tokens and are otherwise ignored.