These pages describe version 10, the studio model of Half-Life. Valve never published a
specification; the definition is the header file studio.h in the Half-Life
SDK, together with the model compiler studiomdl, the model viewer and the
client’s renderer in the same repository. Source engine models (version 44 and later)
are a different layout and are not covered here.
All numbers are little-endian: 32-bit integers and floats unless marked otherwise. Every
…index field is an offset in bytes from the start of the file, and each
table is an array of fixed-size records at that offset.
Header
244 bytes (studiohdr_t) at the start of the file.
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | char[4] | id | IDST (49 44 53 54) |
| 4 | 4 | int32 | version | 10 (STUDIO_VERSION) |
| 8 | 64 | char[64] | name | Model path, such as models/scientist.mdl |
| 72 | 4 | int32 | length | Size of the file in bytes |
| 76 | 12 | float32[3] | eyeposition | Ideal eye position |
| 88 | 12 | float32[3] | min | Ideal movement hull, lower corner |
| 100 | 12 | float32[3] | max | Ideal movement hull, upper corner |
| 112 | 12 | float32[3] | bbmin | Clipping bounding box, lower corner |
| 124 | 12 | float32[3] | bbmax | Clipping bounding box, upper corner |
| 136 | 4 | int32 | flags | Model flags, the number given to the compiler’s $flags command; their meaning belongs to the engine |
| 140 | 4 | int32 | numbones | Bones (112 bytes each) |
| 144 | 4 | int32 | boneindex | Offset of the bones |
| 148 | 4 | int32 | numbonecontrollers | Bone controllers (24 bytes each) |
| 152 | 4 | int32 | bonecontrollerindex | Offset of the bone controllers |
| 156 | 4 | int32 | numhitboxes | Hit boxes (32 bytes each) |
| 160 | 4 | int32 | hitboxindex | Offset of the hit boxes |
| 164 | 4 | int32 | numseq | Sequences (176 bytes each) |
| 168 | 4 | int32 | seqindex | Offset of the sequences |
| 172 | 4 | int32 | numseqgroups | Sequence groups (104 bytes each), at least 1 |
| 176 | 4 | int32 | seqgroupindex | Offset of the sequence groups |
| 180 | 4 | int32 | numtextures | Textures (80 bytes each); 0 when they are in a separate file |
| 184 | 4 | int32 | textureindex | Offset of the texture records |
| 188 | 4 | int32 | texturedataindex | Offset of the texture pixel data |
| 192 | 4 | int32 | numskinref | Texture slots in each skin family |
| 196 | 4 | int32 | numskinfamilies | Skin families |
| 200 | 4 | int32 | skinindex | Offset of the skin table |
| 204 | 4 | int32 | numbodyparts | Body parts (76 bytes each) |
| 208 | 4 | int32 | bodypartindex | Offset of the body parts |
| 212 | 4 | int32 | numattachments | Attachments (88 bytes each) |
| 216 | 4 | int32 | attachmentindex | Offset of the attachments |
| 220 | 4 | int32 | soundtable | Unused; studiomdl leaves it 0 |
| 224 | 4 | int32 | soundindex | Unused, 0 |
| 228 | 4 | int32 | soundgroups | Unused, 0 |
| 232 | 4 | int32 | soundgroupindex | Unused, 0 |
| 236 | 4 | int32 | numtransitions | Nodes in the transition graph |
| 240 | 4 | int32 | transitionindex | Offset of the transition table |
Limits
The constants in studio.h, as Valve’s SDK now gives them:
| Constant | Value | Limit on |
|---|---|---|
MAXSTUDIOTRIANGLES | 20000 | Triangles |
MAXSTUDIOVERTS | 2048 | Vertices in a model |
MAXSTUDIOSEQUENCES | 2048 | Sequences |
MAXSTUDIOSKINS | 100 | Textures |
MAXSTUDIOSRCBONES | 512 | Bones in the source files |
MAXSTUDIOBONES | 128 | Bones in the compiled model |
MAXSTUDIOMODELS | 32 | Models in a body part |
MAXSTUDIOBODYPARTS | 32 | Body parts |
MAXSTUDIOGROUPS | 16 | Sequence groups |
MAXSTUDIOANIMATIONS | 2048 | Animations |
MAXSTUDIOMESHES | 256 | Meshes |
MAXSTUDIOEVENTS | 1024 | Events |
MAXSTUDIOPIVOTS | 256 | Pivots |
MAXSTUDIOCONTROLLERS | 8 | Bone controllers |
Companion files
A model can be split into several files beside each other, named after the main one:
| File | When | Holds |
|---|---|---|
name.mdl | Always | The header, skeleton, sequences, geometry and, normally, the textures and the animation of sequence group 0 |
nameT.mdl | When the main file’s numtextures is 0 | A complete studio header starting with IDST, whose texture, skin and pixel data the game uses |
name01.mdl, name02.mdl, … | One per sequence group after group 0 | The animation data of that group, loaded when first needed |
Sequence group file header
A sequence group file starts with a 76-byte header (studioseqhdr_t);
its sequences’ animindex values are offsets from the start of that
file.
| Offset | Size | Type | Name | Meaning |
|---|---|---|---|---|
| 0 | 4 | char[4] | id | IDSQ (49 44 53 51) |
| 4 | 4 | int32 | version | 10 |
| 8 | 64 | char[64] | name | File name |
| 72 | 4 | int32 | length | Size of the file in bytes |
Transition graph
Sequences can be marked as entering and leaving numbered nodes, so the game can pass
through linking sequences, such as standing up before walking. At
transitionindex is a table of numtransitions ×
numtransitions bytes. The byte at row a − 1, column
b − 1 is the node to go through next on the way from node a to
node b; 0 means go straight to the goal. Nodes are numbered from 1, and 0 in
a sequence means it takes part in no transition.