Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

Module hmd8

Module hmd8 

Source
Expand description

HMD8: a merged model container carrying mesh, bone ranges and every clip’s composed bone palettes in one blob.

Lifted from hl-psx, which developed it to run the whole Half-Life campaign (103 maps, 237 transitions) inside a 223.7 KB model pool covering mesh AND animation. It lives here so both games share one format rather than each carrying a private reader.

What it does that Model + Animation do not:

  • one blob per model, with a clip table, so a model’s whole animation set is a single asset rather than one file per clip;
  • vertices stored bone-local and grouped into contiguous RANGES, so each range pays one matrix load and feeds the static stream straight to RTPT;
  • a 20-byte composed affine per bone per frame (HMD8_AFFINE_BYTES), the same packed Q11 encoding .psxanim v3 already uses;
  • optional sections gated by flags (body masks, mouth transforms, studio hitboxes, packed or i8 normals, frame times, vertex SoA), so a consumer that wants none of the GoldSrc specifics simply does not emit them.

Extraction note: the only coupling to its old home was a vertex-count guard reading a game-local budget constant. That is now DEFAULT_MAX_VERTICES with Model::from_bytes_with_vertex_cap for callers that police their own arena.

Structs§

BoneRange
A contiguous run of vertices sharing one bone.
BoneTransform
A bone’s composed pose, unpacked from the 20-byte record into GTE registers.
GteVertexWords
One HMD8 vertex in the exact two-register layout consumed by the GTE.
InterpolatedModelFrame
Two baked bone palettes prepared for fixed-point affine interpolation.
Jaw
The cooked mouth controller: one bone’s local rotation, fully open.
Model
A parsed HMD8 blob: mesh, bone ranges, clip table and every clip’s composed bone palettes, all borrowed from one &'static slice with no copying.
ModelFrame
One frame’s bone palette, read lazily: a bone’s affine is unpacked from the blob when asked for, not eagerly into a scratch array.
RenderFacePayload
Cold UV payload for a projected model face. Vertex indices live in a separate packed-u32 stream so near/backface rejects touch only four uncached bytes. Texture ids live once per ordered face run, not once per face; the streamed actor set keeps those ids out of every face payload.
StudioHitbox
A GoldSrc studio hitbox, present only when the cook set the hitbox flag.
Tracks
A model’s HMA1 section (see Model::tracks).
Triangle
A decoded triangle. The blob keeps these packed; this is the unpacked view.
VertexWords
A model’s vertex stream as GTE register words, bounds-checked once.

Enums§

Pose
One animation sample’s bone transforms (see Model::pose).

Constants§

DEFAULT_MAX_VERTICES
Vertex-count guard used by Model::from_bytes.
RENDER_FACE_INDEX_MASK
Three ten-bit indices fit one hot word exactly (with the top two bits unused), so a model whose faces are packed this way can have at most RENDER_FACE_INDEX_MASK + 1 (1024) vertices. DEFAULT_MAX_VERTICES is that bound, so Model::from_bytes never admits a model the packing would mangle; a caller that passes a larger cap to Model::from_bytes_with_vertex_cap must not pack its faces.