MDL

MDL is the extension for Source's proprietary model format. It defines the structure of the model along with animation, bounding box, hit box, materials, mesh and LOD information. It does not, however, contain all the information needed for the model. Additional data is stored in PHY, ANI, VTX and VVD files, and sometimes, usually for shared animations, other .mdl files.
== File format ==
Some details of the file format may be gleaned from the source code in Valve's studio.h, specifically the struct studiohdr_t. The early header defines a series of offsets and lengths for various sub-sections within the file, along with some key scalar information. The MDL also contains the names of materials (VMT), which may be used and referenced in various ways. 
=== Main header ===
To get the latest header for specific game, please use the studio.h file in the Valve's SDK instead.
struct studiohdr_t
{
 int id; // Model format ID, such as "IDST" (0x49 0x44 0x53 0x54)
 int version; // Format version number, such as 48 (0x30,0x00,0x00,0x00)
 int checksum; // This has to be the same in the phy and vtx files to load!
 char name[64]; // The internal name of the model, padding with null bytes.
 // Typically "my_model.mdl" will have an internal name of "my_model"
 int dataLength; // Data size of MDL file in bytes.
 
 // A vector is 12 bytes, three 4-byte float-values in a row.
 Vector eyeposition; // Position of player viewpoint relative to model origin
 Vector illumposition; // Position (relative to model origin) used to calculate ambient light contribution and cubemap reflections for the entire model.
 Vector hull_min; // Corner of model hull box with the least X/Y/Z values
 Vector hull_max; // Opposite corner of model hull box
 Vector view_bbmin; // Same, but for bounding box,
 Vector view_bbmax; // which is used for view culling
 
 int flags; // Binary flags in little-endian order. 
 // ex (0x010000C0) means flags for position 0, 30, and 31 are set. 
 // Set model flags section for more information
 
 /*
 * After this point, the header contains many references to offsets
 * within the MDL file and the number of items at those offsets.
 *
 * Offsets are from the very beginning of the file.
 * 
 * Note that indexes/counts are not always paired and ordered consistently.
 */ 
 
 // mstudiobone_t
 int bone_count; // Number of data sections (of type mstudiobone_t)
 int bone_offset; // Offset of first data section
 
 // mstudiobonecontroller_t
 int bonecontroller_count;
 int bonecontroller_offset;
 
 // mstudiohitboxset_t
 int hitbox_count;
 int hitbox_offset;
 
 // mstudioanimdesc_t
 int localanim_count;
 int localanim_offset;
 
 // mstudioseqdesc_t
 int localseq_count;
 int localseq_offset;
 
 int activitylistversion; // ??
 int eventsindexed; // ??
 
 // VMT texture filenames
 // mstudiotexture_t
 int texture_count;
 int texture_offset;
 
 // This offset points to a series of ints.
 // Each int value, in turn, is an offset relative to the start of this header/the-file,
 // At which there is a null-terminated string.
 int texturedir_count;
 int texturedir_offset;
 
 // Each skin-family assigns a texture-id to a skin location
 int skinreference_count;
 int skinrfamily_count;
 int skinreference_index;
 
 // mstudiobodyparts_t
 int bodypart_count;
 int bodypart_offset;
 
 // Local attachment points 
 // mstudioattachment_t
 int attachment_count;
 int attachment_offset;
 
 // Node values appear to be single bytes, while their names are null-terminated strings.
 int localnode_count;
 int localnode_index;
 int localnode_name_index;
 
 // mstudioflexdesc_t
 int flexdesc_count;
 int flexdesc_index;
 
 // mstudioflexcontroller_t
 int flexcontroller_count;
 int flexcontroller_index;
 
 // mstudioflexrule_t
 int flexrules_count;
 int flexrules_index;
 
 // IK probably referse to inverse kinematics
 // mstudioikchain_t
 int ikchain_count;
 int ikchain_index;
 
 // Information about any "mouth" on the model for speech animation
 // More than one sounds pretty creepy.
 // mstudiomouth_t
 int mouths_count; 
 int mouths_index;
 
 // mstudioposeparamdesc_t
 int localposeparam_count;
 int localposeparam_index;
 
 /*
 * For anyone trying to follow along, as of this writing,
 * the next "surfaceprop_index" value is at position 0x0134 (308)
 * from the start of the file.
 */
 
 // Surface property value (single null-terminated string)
 int surfaceprop_index;
 
 // Unusual: In this one index comes first, then count.
 // Key-value data is a series of strings. If you can't find
 // what you're interested in, check the associated PHY file as well.
 int keyvalue_index;
 int keyvalue_count; 
 
 // More inverse-kinematics
 // mstudioiklock_t
 int iklock_count;
 int iklock_index;
 
 
 float mass; // Mass of object (4-bytes) in kilograms
 int contents; // contents flag, as defined in bspflags.h
 // not all content types are valid; see 
 // documentation on $contents QC command
 
 // Other models can be referenced for re-used sequences and animations
 // (See also: The $includemodel QC option.)
 // mstudiomodelgroup_t
 int includemodel_count;
 int includemodel_index;
 
 int virtualModel; // Placeholder for mutable-void*
 // Note that the SDK only compiles as 32-bit, so an int and a pointer are the same size (4 bytes)
 
 // mstudioanimblock_t
 int animblocks_name_index;
 int animblocks_count;
 int animblocks_index;
 
 int animblockModel; // Placeholder for mutable-void*
 // Points to a series of bytes?
 int bonetablename_index;
 
 int vertex_base; // Placeholder for void*
 int offset_base; // Placeholder for void*
 
 // Used with $constantdirectionallight from the QC 
 // Model should have flag #13 set if enabled
 byte directionaldotproduct;
 
 byte rootLod; // Preferred rather than clamped
 
 // 0 means any allowed, N means Lod 0 -> (N-1)
 byte numAllowedRootLods; 
 
 byte unused0; // ??
 int unused1; // ??
 
 // mstudioflexcontrollerui_t
 int flexcontrollerui_count;
 int flexcontrollerui_index;
 float vertAnimFixedPointScale; // ??
 int unused2;
 
 /**
 * Offset for additional header information.
 * May be zero if not present, or also 408 if it immediately 
 * follows this studiohdr_t
 */
 // studiohdr2_t
 int studiohdr2index;
 
 int unused3; // ??
 
 /**
 * As of this writing, the header is 408 bytes long in total
 */
};
=== Model flags ===
Bit 	Name 	Dev comment 	Description
0x00000001	STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX 	This flag is set if no hitbox information was specified 	Set by StudioMDL if no $hbox QC commands were used
0x00000002	STUDIOHDR_FLAGS_USES_ENV_CUBEMAP 	NOTE: This flag is set at loadtime, not mdl build time so that we don't have to rebuild models when we change materials. 	Set by game engine if VMTs used for the model have .
0x00000004	STUDIOHDR_FLAGS_FORCE_OPAQUE 	Use this when there are translucent parts to the model but we're not going to sort it 	Set by StudioMDL if the $opaque QC command is used
0x00000008	STUDIOHDR_FLAGS_TRANSLUCENT_TWOPASS 	Use this when we want to render the opaque parts during the opaque pass and the translucent parts during the translucent pass 	Set by StudioMDL if the $mostlyopaque QC command is used
0x00000010	STUDIOHDR_FLAGS_STATIC_PROP 	This is set any time the .qc files has $staticprop in it
Means there's no bones and no transforms 	Set by StudioMDL if the $staticprop QC command is used. Required for prop_static and prop_physics.
0x00000020	STUDIOHDR_FLAGS_USES_FB_TEXTURE 	NOTE: This flag is set at loadtime, not mdl build time so that we don't have to rebuild models when we change materials. 	Set by game engine; has something to do with power-of-two framebuffer textures.
0x00000040	STUDIOHDR_FLAGS_HASSHADOWLOD 	This flag is set by studiomdl.exe if a separate "$shadowlod" entry was present for the .mdl (the shadow lod is the last entry in the lod list if present) 	Set by StudioMDL if the $shadowlod QC command is used.
0x00000080	STUDIOHDR_FLAGS_USES_BUMPMAPPING 	NOTE: This flag is set at loadtime, not mdl build time so that we don't have to rebuild models when we change materials. 	Set by game engine if $bumpmap or $normalmap are present in any of the models's VMTs.
0x00000100	STUDIOHDR_FLAGS_USE_SHADOWLOD_MATERIALS 	NOTE: This flag is set when we should use the actual materials on the shadow LOD instead of overriding them with the default one (necessary for translucent shadows)	Set by StudioMDL if the $shadowlod command has the parameter
0x00000200	STUDIOHDR_FLAGS_OBSOLETE 	NOTE: This flag is set when we should use the actual materials on the shadow LOD instead of overriding them with the default one (necessary for translucent shadows)	Set by StudioMDL if the $obsolete QC command is used.
0x00000400	STUDIOHDR_FLAGS_UNUSED 	N/A 	
0x00000800	STUDIOHDR_FLAGS_NO_FORCED_FADE 	NOTE: This flag is set at mdl build time 	Set by StudioMDL if the $noforcedfade QC command is used.
0x00001000	STUDIOHDR_FLAGS_FORCE_PHONEME_CROSSFADE 	NOTE: The npc will lengthen the viseme check to always include two phonemes 	Set by StudioMDL if the $forcephonemecrossfade QC command is used.
0x00002000	STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT	This flag is set when the .qc has $constantdirectionallight in it
If set, we use constantdirectionallightdot to calculate light intensity rather than the normal directional dot product
only valid if STUDIOHDR_FLAGS_STATIC_PROP is also set	Set by StudioMDL if the $constantdirectionallight QC command is used.
0x00004000	STUDIOHDR_FLAGS_FLEXES_CONVERTED 	Flag to mark delta flexes as already converted from disk format to memory format 	Used by engine at runtime
0x00008000	STUDIOHDR_FLAGS_BUILT_IN_PREVIEW_MODE 	Indicates the studiomdl was built in preview mode 	Model has not been optimized into tristrips, and DMX quads have not been triangulated.
Set by running StudioMDL with parameter.
0x00010000	STUDIOHDR_FLAGS_AMBIENT_BOOST 	Ambient boost (runtime flag) 	Contrary to the dev comment, this can be set by StudioMDL using the $ambientboost QC command.
0x00020000	STUDIOHDR_FLAGS_DO_NOT_CAST_SHADOWS 	Don't cast shadows from this model (useful on first-person models) 	Set by StudioMDL if the $donotcastshadows QC command is used.
0x00040000	STUDIOHDR_FLAGS_CAST_TEXTURE_SHADOWS 	alpha textures should cast shadows in vrad on this model (ONLY prop_static!) 	Set by StudioMDL if the $casttextureshadows QC command is used.
0x00080000	N/A 	N/A (undefined) 	
0x00100000	N/A 	N/A (undefined) 	
0x00200000	STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE 	flagged on load to indicate no animation events on this model 	
===Secondary header===
This header section is optional, and is found via the studiohdr2index value.
struct studiohdr2_t
{
 // ??
 int srcbonetransform_count;
 int srcbonetransform_index;
 int illumpositionattachmentindex;
 float flMaxEyeDeflection; // If set to 0, then equivalent to cos(30)
 // mstudiolinearbone_t
 int linearbone_index;
 int unknown[64];
};
===Texture data===
struct mstudiotexture_t
{
 // Number of bytes past the beginning of this structure
 // where the first character of the texture name can be found.
 int name_offset; // Offset for null-terminated string
 int flags;
 int used; // Padding?
 int unused; // Padding.
 int material; // Placeholder for IMaterial
 int client_material; // Placeholder for void*
	
 int unused2[10]; // Final padding
 // Struct is 64 bytes long
};
=== Skin replacement tables ===
Each "skin" that a model has (as seen in the Model Viewer and choose-able for prop entities) is actually referred to as a skin "family" in the MDL code. (Additional skins may be created with the $texturegroup compile option.) For the purposes of this section, a "skin" an area where a single material (aka texture) may be applied, while a skin-family defines a list of materials to use on skin zones 0,1,2, etc. 
The skin-family section of the MDL is a sequence of short (2-byte) values, which should be broken up into a table. To illustrate how it works, we will consider a model and then examine how it would be represented on the byte-level. For this example, imagine a crate-model with three skin-families labeled (fam0,fam1,fam2) two skins-zones (mainbody,trimming) and three textures (lightwood,darkwood,metal). 
Skin table
 	mainbody 	trimming
fam0	lightwood	metal
fam1	darkwood 	metal
fam2	metal 	metal
Let's assume that the various textures are given ID values in the MDL like so:
Texture IDs
ID	Name
0 	lightwood
1 	darkwood
2 	metal
In the MDL data, this table relationship is broken down into a stream of bytes, with two-byte texture IDs replacing the literal names. Thus the final series of bytes that corresponds to these skin-family relationships would (as little-endian short values) be:
 00 00 02 00
 01 00 02 00
 02 00 02 00
The total number of bytes is numskinfamilies*numskins*2.
== See also ==
* 3D Model
* Model Viewer
* Model Creation Overview
 
Category:Modeling
Category:File formats