An open-source container for models, animations, and more.
PythonMIT
Cast | An open-source container for models, animations, and more
The goal of cast is to create an easy to use format for models, animations, materials, and game worlds. In addition, cast should be able to produce the same scenes in any 3d software.
structCastHeader
{
uint32_t Magic; // char[4] cast (0x74736163)uint32_t Version; // 0x1uint32_t RootNodes; // Number of root nodes, which contain various sub nodes if necessaryuint32_t Flags; // Reserved for flags, or padding, whichever is needed
};
A cast file is basically a group of generic nodes. Nodes are given a unique registered id, which can tell the loader what the data is, and how to handle it.
Following the cast header is a collection of nodes which must be of type CastId::Root.
A node looks like:
structCastNodeHeader
{
CastId Identifier; // Used to signify which class this node usesuint32_t NodeSize; // Size of all data and sub data following the nodeuint64_t NodeHash; // Unique hash, like an id, used to link nodes togetheruint32_t PropertyCount; // The count of propertiesuint32_t ChildCount; // The count of direct children nodes// We must read until the node size hits, and that means we are done.// The nodes are in a stack layout, so it's easy to load, FILO order.
};
Following a node, is the list of properties [Node.PropertyCount], a property looks like:
structCastPropertyHeader
{
CastPropertyId Identifier; // The element type of this propertyuint16_t NameSize; // The size of the name of this propertyuint32_t ArrayLength; // The number of elements this property contains (1 for single)// Following is UTF-8 string lowercase, size of namesize, NOT null terminated// cast_property[ArrayLength] array of data
};
To read a cast file, you just need to traverse the root nodes and their children. Properties always come before a nodes children. Each node has the total size of itself, and all children, so if a processor doesn't understand a node id, it can skip the entire node and continue reading.
Cast ids are stored as integers to make it faster to serialize and deserialize.
Cast processors:
Model:
Field
Type(s)
IsArray
Required
Children
Skeleton, Mesh, Material
True
False
Parent
Root
False
True
Property (id)
Type(s)
IsArray
Required
Name (n)
String (s)
False
False
Mesh:
Field
Type(s)
IsArray
Required
Children
None
True
False
Parent
Model
False
True
Property (id)
Type(s)
IsArray
Required
Name (n)
String (s)
False
False
Vertex Position Buffer (vp)
Vector 3 (v3)
True
True
Vertex Normal Buffer (vn)
Vector 3 (v3)
True
False
Vertex Tangent Buffer (vt)
Vector 3 (v3)
True
False
Vertex Color Buffer (c%d)
Integer 32 (i)
True
False
Vertex UV Buffer (u%d)
Vector 2 (v2)
True
False
Vertex Weight Bone Buffer (wb)
Integer 32 (i), Short (h), Byte (b)
True
False
Vertex Weight Value Buffer (wv)
Float (f)
True
False
Face Buffer (f)
Integer 32 (i), Short (h), Byte (b)
True
True
Color Layer Count (cl)
Integer 32 (i), Short (h), Byte (b)
False
True if has color layers else False
UV Layer Count (ul)
Integer 32 (i), Short (h), Byte (b)
False
True if has uv layers else False
Maximum Weight Influence (mi)
Integer 32 (i), Short (h), Byte (b)
False
True if has weights else False
Skinning Method (sm)
String (s) [linear, quaternion]
False
False
Material (Hash of CastNode:Material) (m)
Integer 64 (l)
False
False
Notes:
Face Buffer is an index into the current meshes vertex data buffers where (0, 1, 2) are the first three vertices from this mesh.
The Face Buffer follows CCW (right-handed) winding order, this may be different in other apis, where you may have to remap the indices.
If a face contains an invalid index combination (0, 1, 1), (0, 1, 0), (0, 0, 0) where two or more indices are the same, it is acceptable for the user processing these faces to ignore them in order to properly render the mesh. It would be wise to present the user with a warning stating that this happened.
Each vertex descriptor buffer must contain the same number of elements ex: if you have 16 vertices, you must have 16 normals if they exist, 16 colors if the buffer exists. Otherwise it's assumed they are default / skipped.
Weights are additive which means having the same bone with 0.5 and 0.5 would end up making that bones influence 1.0 for example.
The default skinning method is linear. When set to quaternion dual quaternion skinning is used.
NEW 8/18/2024: The vertex color specification has changed, in order to support multiple color layers, a new Color Layer Count (cl) was added which mimics the UV Layer Count (ul) property.
To be backwards compatible, cast processors should check for cl, and use that by default along with the new c%d layer properties.
If the cl property does not exist, a processor should check for the legacy vc property which is the one and only color layer if it exists.
Blend Shape:
Field
Type(s)
IsArray
Required
Children
None
True
False
Parent
Model
False
True
Property (id)
Type(s)
IsArray
Required
Name (n)
String (s)
False
True
Base Shape (Hash of CastNode:Mesh) (b)
Integer 64 (l)
False
True
Target Shape Vertex Indices (vi)
Byte (b), Short (h), Integer 32 (i)
True
True
Target Shape Vertex Positions (vp)
Vector 3 (v3)
True
True
Target Weight Scale (ts)
Float (f)
True
False
Notes:
The Base Shape must be an existing cast mesh.
The Target Shape Vertex Indices and Target Shape Vertex Positions must be the same length as they are paired together.
Target Shape Vertex Positions is the final value of each changed vertex position ignoring the Base Shape's corresponding vertex.
Target Weight Scale indicates the maximum value the target shape can deform to and should default to 1.0.
Skeleton:
Field
Type(s)
IsArray
Required
Children
Bone, IKHandle, Constraint
True
False
Parent
Model
False
True
Bone:
Field
Type(s)
IsArray
Required
Children
None
True
False
Parent
Skeleton
False
True
Property (id)
Type(s)
IsArray
Required
Name (n)
String (s)
False
True
Parent Index (p)
Integer 32 (i)
False
False
Segment Scale Compensate (ssc)
Byte (b) [True, False]
False
False
Local Position (lp)
Vector 3 (v3)
False
False
Local Rotation (lr)
Vector 4 (v4)
False
False
World Position (wp)
Vector 3 (v3)
False
False
World Rotation (wr)
Vector 4 (v4)
False
False
Scale (s)
Vector 3 (v3)
False
False
Notes:
Segment Scale Compensate should default to True when not specified.
Scale is always local to the current bone.
IKHandle:
Field
Type(s)
IsArray
Required
Children
None
True
False
Parent
Skeleton
False
True
Property (id)
Type(s)
IsArray
Required
Name (n)
String (s)
False
False
Start Bone Hash (sb)
Integer 64 (l)
False
True
End Bone Hash (eb)
Integer 64 (l)
False
True
Target Bone Hash (tb)
Integer 64 (l)
False
False
Pole Vector Bone Hash (pv)
Integer 64 (l)
False
False
Pole Bone Hash (pb)
Integer 64 (l)
False
False
Use Target Rotation (tr)
Byte (b) [True, False]
False
False
Notes:
Use Target Rotation should default to False when not specified.
Pole Bone must only effect the twist of the chain, in general you either have a Pole Bone or a Pole Vector Bone.
Constraint:
Field
Type(s)
IsArray
Required
Children
None
True
False
Parent
Skeleton
False
True
Property (id)
Type(s)
IsArray
Required
Name (n)
String (s)
False
False
Constraint Type (ct)
String (s) [pt, or, sc]
False
True
Constraint Bone Hash (cb)
Integer 64 (l)
False
True
Target Bone Hash (tb)
Integer 64 (l)
False
True
Maintain Offset (mo)
Byte (b) [True, False]
False
False
Skip X (sx)
Byte (b) [True, False]
False
False
Skip Y (sy)
Byte (b) [True, False]
False
False
Skip Z (sz)
Byte (b) [True, False]
False
False
Notes:
The constraint type values correspond to:
pt Point Constraint, which applies to translations.
or Orient Constraint, which applies to rotations.
sc Scale Constraint, which applies to scales.
Maintain offset should default to False when not specified.
Skip X, Skip Y, and Skip Z should default to False when not specified and refer to ignoring that axis in the constraint.