From Valve Developer Community
Revision as of 16:25, 31 July 2011 by Rozzy85 (talk | contribs)
Jump to: navigation, search

VTX is the extension for Source's proprietary mesh strip format. It stores hardware optimized material, skinning and triangle strip/fan information for each LOD of each mesh in the MDL. Currently it is found in .sw.vtx (Software), .dx80.vtx (DirectX 8.0) .dx90.vtx (DirectX 9.0) and .xbox.vtx (XBox) flavours.


// this structure is in <mod folder>/src/public/optimize.h
struct FileHeader_t
	// file version as defined by OPTIMIZED_MODEL_FILE_VERSION (currently 7)
	int version;

	// hardware params that affect how the model is to be optimized.
	int vertCacheSize;
	unsigned short maxBonesPerStrip;
	unsigned short maxBonesPerTri;
	int maxBonesPerVert;

	// must match checkSum in the .mdl
	long checkSum;
	int numLODs; // garymcthack - this is also specified in ModelHeader_t and should match

	// this is an offset to an array of 8 MaterialReplacementListHeader_t's
	// (one for each LOD)
	int materialReplacementListOffset;

	int numBodyParts;
	int bodyPartOffset; // offset to an array of BodyPartHeader_t's

Data Structure

Data is read through a series of offsets which vary depending on how many textures the model uses, bodygroups, submodels and LoD. Each group of offsets will lead to a 25 byte block that contains all the face/triangle information to draw the mesh. For example, if the model has 3 LoD levels and the mesh uses 2 textures per mesh then there will be 6 separate mesh references.

The 25 byte block contains the following data:

Offset Datatype Size (bytes) Description
0 uInt32 4 Number of vertexes
4 uInt32 4 Offset to vertex number table
8 uInt32 4 Number of vertexes to draw faces
12 uInt32 4 Offset to sequence to draw faces
16 uInt32 4 Unknown offset reference (possibly related to vertex faces)
20 uInt32 4 Offset to (unknown) reference
24 byte 1 Unknown

Note.png Note: All offsets are calculated from the position of the start of the block.

Vertex Number Table

This offset will lead to a table containing 9 byte blocks which contain the ID of the vert from the VVD file. The first 4 bytes are unknown but are usually 00 01 02 00 although can be different. The next 2 bytes contain the vert number. The remaining 3 bytes are unknown (maybe LoD related). This data needs to be stored into an array with the key starting at 0 to be read correctly.

Vertex Sequence

This offset will lead to a table containing 2 byte blocks which contain the order of verts to draw the faces correctly. The 16-bit int contains the array key.

Face Draw Order

The draw sequence can be constructed with the following statement done using PHP.

//$vert_seq contains the 16-bit int keys.
//$vert_data contains the 16-bit int vert number extracted from the 9 byte block.
//$faces contains the sorted vert numbers to draw the faces.
foreach($vert_seq as $vid)
	array_push($faces, $vert_data[$vid]);

The array $faces now contains the keys of the vertexes to be read from the VVD data assuming it is also stored in an array.

Decompile Example Script

Here is a link to a PHP script that will decompile a model can convert the reference mesh to SMD plain text. It will also partially re-construct a QC. It is not complete and does not work correctly on models with bodygroups, submodels and/or LoD. This script will only run on a Linux PHP server but the code can be modified to work on a Windows PHP server. Recommended for advanced users with programming/scripting knowledge only.


The script above is now active at the link below. It will decompile simple models such as props although it may be updated in the future to support more advanced models.

MDL Unpack Web Site

See also