Vvd (Where the vertices are)

class valvemdl.Vvd(path=None)[source]

Contains the data from a vvd file.

An mdl carries no vertex positions; they all live here, in one flat pool shared by every mesh in the model. The header is parsed when the file is opened; the pools are large, so they are parsed on first access and cached.

The pools are stored exactly as they sit on disk, which for a model with fixups means LOD-sorted rather than mesh-sorted. mesh_vertices() replays the fixups to hand back the mesh order that mstudiomodel_t.vertexindex expects. Keeping the raw order is what lets a vvd be written back byte for byte.

__init__(path=None)[source]

Creates an empty instance of Vvd.

Parameters:

path (str, optional) – A path to an existing vvd file.

source_path
Type:

(str) - The location of the parsed file.

header
Type:

(construct.Container) - The parsed vertexFileHeader_t.

property checksum
Type:

(int) - Ties this vvd to its mdl and vtx.

property vertices

The vertex pool, in the order it is stored.

That order is LOD-sorted when header .numFixups is non-zero. Use mesh_vertices() for the order a mesh indexes.

Type:

(list[construct.Container]) - numLODVertexes[0] vertices.

property tangents

The tangent pool, parallel to vertices.

Tangents are kept in their own pool rather than inside the vertex, which is what holds mstudiovertex_t at 48 bytes. Empty when tangentDataStart is 0.

Type:

(list[construct.Container]) - One Vector4D per vertex.

property fixups

The fixup table.

Empty unless the pool is LOD-sorted. Each entry names a run of the pool and the LOD it belongs to; replaying them rebuilds mesh order.

Type:

(list[construct.Container]) - numFixups fixups.

mesh_vertices(root_lod=0)[source]

The vertices in mesh order, for a given root LOD.

When the pool is LOD-sorted (numFixups non-zero), a mesh’s vertexoffset indexes an order that only exists once the fixup table has been replayed. This does that, following Studio_LoadVertexes: each fixup at or below the requested LOD copies a run of the stored pool into the next free slot, and the runs land consecutively.

With no fixups the pool is already in mesh order and this returns it unchanged.

Parameters:

root_lod (int, optional) – The most detailed LOD to include; 0 is full detail.

Returns:

The vertices a mesh can index into.

Return type:

list[construct.Container]

mesh_tangents(root_lod=0)[source]

The tangents in mesh order, for a given root LOD.

Tangents run parallel to vertices, so they take the identical fixup replay – reordering one without the other would pair each vertex with the wrong tangent.

Parameters:

root_lod (int, optional) – The most detailed LOD to include; 0 is full detail.

Returns:

The tangents, in the same order as mesh_vertices().

Return type:

list[construct.Container]

validate()[source]

Checks the vvd’s internal invariants.

Like Mdl.validate this reports rather than raises: a vvd that fails one of these is the interesting one. It is deliberately cheap – every check reads the header and the small fixup table, never the vertex pool – so the corpus sweep can run it on every file without parsing a quarter megabyte of vertices each time.

Returns:

One string per broken invariant, empty when sound.

Return type:

list[str]

save(destination=None)[source]

Writes the vvd back out, rebuilt from its pools.

Parameters:

destination (str, optional) – Where to write. Overwrites the original when not given.

coverage()[source]

How much of the vvd ValveMDL can account for.

A vvd has no compressed regions, so a sound one comes back essentially all struct – every byte regenerated from the object graph, none merely copied. See Mdl.coverage.

Returns:

Byte counts, plus differ: bytes the rebuild got wrong.

Return type:

dict

__repr__()[source]

Return repr(self).