pub struct Model {
pub n_verts: usize,
pub n_tris: usize,
/* private fields */
}Expand description
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.
Construct with Model::from_bytes or
Model::from_bytes_with_vertex_cap; a blob that fails validation yields
an empty model rather than panicking, so a bad cook draws nothing instead
of taking the guest down.
Every accessor is memory-safe on any model, including one whose public
counts (the deprecated n_verts and n_tris) were overwritten:
reads are bounded by the blob and the private offsets from_bytes
validated, never by the
public counts. An index past a table reads an inert value (origin vertex,
skipped triangle, identity pose). The *_unchecked forms skip that check
for hot loops that already bound their index by the loaded count.
Fields§
§n_verts: usizeuse vertex_count()
n_tris: usizeuse triangle_count()
Implementations§
Source§impl Model
impl Model
Sourcepub fn from_bytes(data: &'static [u8]) -> Model
pub fn from_bytes(data: &'static [u8]) -> Model
Parse a HMD8 blob, guarding vertex count with DEFAULT_MAX_VERTICES.
Sourcepub const fn vertex_count(&self) -> usize
pub const fn vertex_count(&self) -> usize
Number of vertices in the stream.
Sourcepub const fn triangle_count(&self) -> usize
pub const fn triangle_count(&self) -> usize
Number of triangles in the face table.
Sourcepub const fn frame_count(&self) -> usize
pub const fn frame_count(&self) -> usize
Number of baked palette frames across every clip.
Sourcepub const fn clip_count(&self) -> usize
pub const fn clip_count(&self) -> usize
Number of clips in the clip table.
Sourcepub const fn bone_count(&self) -> usize
pub const fn bone_count(&self) -> usize
Number of bones in each pose palette.
Sourcepub const fn bone_range_count(&self) -> usize
pub const fn bone_range_count(&self) -> usize
Number of bone ranges (see Model::bone_range).
Sourcepub const fn hitbox_count(&self) -> usize
pub const fn hitbox_count(&self) -> usize
Number of studio hitboxes (zero when the cook emitted none).
Sourcepub fn from_bytes_with_vertex_cap(
data: &'static [u8],
max_verts: usize,
) -> Model
pub fn from_bytes_with_vertex_cap( data: &'static [u8], max_verts: usize, ) -> Model
Parse a HMD8 blob, guarding vertex count with the caller’s own arena capacity.
Sourcepub fn tracks(&self) -> Option<Tracks>
pub fn tracks(&self) -> Option<Tracks>
HMA1 local-space tracks, when the cook emitted them (validated at
load). Most callers want Model::pose, which picks the right path.
Sourcepub fn has_tracks(&self) -> bool
pub fn has_tracks(&self) -> bool
True when the model animates from HMA1 tracks. Its phase functions
then return (clip, clip, pos_q8): pos_q8 is the source position in
frames * 256, and Model::pose reads the triple the same way.
Sourcepub fn pose<'a>(
&'a self,
frame: usize,
frame2: usize,
frac16: u32,
mouth: u8,
scratch: &'a mut [Affine],
) -> Pose<'a>
pub fn pose<'a>( &'a self, frame: usize, frame2: usize, frac16: u32, mouth: u8, scratch: &'a mut [Affine], ) -> Pose<'a>
The bone transforms for one animation sample, whichever animation the
model carries: a (frame, frame2, frac16) palette pair, or for HMA1
models (clip, _, pos_q8) decoded into scratch with the mouth
controller opened mouth/64 on the jaw. A model with more HMA1 bones
than scratch holds draws its bind pose.
Sourcepub fn clip_end_pose(&self, clip: usize) -> (usize, usize, u32)
pub fn clip_end_pose(&self, clip: usize) -> (usize, usize, u32)
The sample holding clip’s final pose.
pub fn local_to_world_q12(&self) -> u16
pub fn clip_len(&self, clip: usize) -> usize
Sourcepub fn clip_hold_ticks(&self, clip: usize) -> u16
pub fn clip_hold_ticks(&self, clip: usize) -> u16
GoldSrc source-sequence duration at the 20 Hz game clock. HMD8 cooks pack 100 ms quanta in ClipRec.frame_count’s unused high byte and duration bit 8 in ClipRec.first_frame’s unused high bit. A zero duration falls back safely instead of allowing a malformed clip to divide by zero.
pub fn clip_frame(&self, clip: usize, local_frame: usize) -> usize
pub fn looped_clip_phase( &self, clip: usize, duration: usize, elapsed: usize, ) -> (usize, usize, u32)
pub fn one_shot_clip_phase( &self, clip: usize, duration: usize, elapsed: usize, ) -> (usize, usize, u32)
pub fn frame(&self, frame: usize) -> ModelFrame<'_>
Sourcepub fn bone_range(&self, index: usize) -> BoneRange
pub fn bone_range(&self, index: usize) -> BoneRange
Bone range index, clamped to the last range. A model without ranges
(the empty model) returns an empty range.
Sourcepub fn hitbox(&self, index: usize) -> StudioHitbox
pub fn hitbox(&self, index: usize) -> StudioHitbox
Studio hitbox index, clamped to the last one. A model without
hitboxes returns a zero box on bone 0.
Sourcepub fn vertex(&self, index: usize) -> Vec3I16
pub fn vertex(&self, index: usize) -> Vec3I16
Bone-local position of vertex index. An index past the vertex
stream reads as the origin instead of outside the blob; hot loops that
have already bounded the index can use Self::vertex_unchecked.
Sourcepub unsafe fn vertex_unchecked(&self, index: usize) -> Vec3I16
pub unsafe fn vertex_unchecked(&self, index: usize) -> Vec3I16
Self::vertex without the bounds check.
§Safety
index must be below the Model::vertex_count that
Model::from_bytes gave this model. (The public count can be
overwritten; the bound is the loaded value.)
Sourcepub fn vertex_gte_words(&self, index: usize) -> GteVertexWords
pub fn vertex_gte_words(&self, index: usize) -> GteVertexWords
Vertex index packed as the GTE’s VXY/VZ register words. An index
past the vertex stream reads as the origin; see
Self::vertex_gte_words_unchecked for bounded hot loops.
Sourcepub fn vertex_words(&self) -> VertexWords<'static>
pub fn vertex_words(&self) -> VertexWords<'static>
The whole vertex stream as a bounds-checked-once view; see
VertexWords. Hot loops that walk a bone range read it through
VertexWords::slice and VertexWords::triples instead of
calling Self::vertex_gte_words per index.
Only the struct-of-arrays stream (HMD_FLAG_VERTEX_SOA, which every
current cook sets) has this shape. An older interleaved cook, and the
empty or a rejected model, return an empty view; read those through
the per-index accessors.
Sourcepub unsafe fn vertex_gte_words_unchecked(&self, index: usize) -> GteVertexWords
pub unsafe fn vertex_gte_words_unchecked(&self, index: usize) -> GteVertexWords
Sourcepub fn frame_section_len(&self) -> usize
pub fn frame_section_len(&self) -> usize
Byte length of the header + clips + ranges + static vertices + palettes –
everything the per-frame draw needs. The TriRec/texture tail after it is
only read by fill_render_faces_split_raw/triangle() (load-time or viewmodels),
so the enemy pool can drop it once the faces are baked.
Sourcepub fn compact_visible_bodies(
blob: &mut [u8],
visible_bodies: u8,
remap: &mut [u16],
) -> Option<usize>
pub fn compact_visible_bodies( blob: &mut [u8], visible_bodies: u8, remap: &mut [u16], ) -> Option<usize>
Compact the HMD8 blob in blob, in place, to the bodies in
visible_bodies: whole bone/body ranges and their static vertices are
dropped, and the shared pose palette, mouth transforms, hitboxes and
HMA1 tracks move down unchanged. The triangle tail is not kept, so bake
faces before compacting. Parse the result again with
Model::from_bytes over blob[..len].
remap receives, for every old vertex index, its new index or
u16::MAX when it was dropped; it needs one entry per vertex.
Returns the compact frame-section length, or None when blob is not
a valid HMD8 model with body masks, remap is too short, or no
visible body remains. blob may be partly rewritten on None after
the range pass has started.
The buffer is borrowed exclusively, so no Model can read it while
it changes: a model parsed from these bytes earlier must not be used
again.
Sourcepub fn triangle(&self, t: usize) -> Triangle
pub fn triangle(&self, t: usize) -> Triangle
Triangle t, unpacked. An index past the triangle table reads as a
degenerate triangle with an empty body mask, which every renderer
skips; hot loops that have already bounded t can use
Self::triangle_unchecked.
Sourcepub unsafe fn triangle_unchecked(&self, t: usize) -> Triangle
pub unsafe fn triangle_unchecked(&self, t: usize) -> Triangle
Self::triangle without the bounds check.
§Safety
t must be below the Model::triangle_count that
Model::from_bytes gave this model.
(The public count can be overwritten; the bound is the loaded value.)
Sourcepub fn triangle_uv_words(&self, t: usize) -> [u16; 3]
pub fn triangle_uv_words(&self, t: usize) -> [u16; 3]
Packet-order UV words for a triangle whose other steady-render fields
are already in the viewmodel pose cache. An index past the triangle
table reads as zero; see Self::triangle_uv_words_unchecked.
Sourcepub unsafe fn triangle_uv_words_unchecked(&self, t: usize) -> [u16; 3]
pub unsafe fn triangle_uv_words_unchecked(&self, t: usize) -> [u16; 3]
pub fn has_body_masks(&self) -> bool
Sourcepub fn triangle_normal(&self, t: usize) -> [i8; 3]
pub fn triangle_normal(&self, t: usize) -> [i8; 3]
Triangle t’s face normal. An index past the triangle table reads as
zero; see Self::triangle_normal_unchecked.
Sourcepub unsafe fn triangle_normal_unchecked(&self, t: usize) -> [i8; 3]
pub unsafe fn triangle_normal_unchecked(&self, t: usize) -> [i8; 3]
Sourcepub fn render_face_count(&self, visible_bodies: u8) -> usize
pub fn render_face_count(&self, visible_bodies: u8) -> usize
Number of consecutive texture/body-mask runs in authored face order.
pub fn render_texture_mask(&self, visible_bodies: u8) -> u32
pub fn render_face_run_count(&self, visible_bodies: u8) -> usize
Sourcepub unsafe fn fill_render_faces_split_raw(
&self,
indices: *mut u32,
payloads: *mut RenderFacePayload,
runs: *mut u32,
out_len: usize,
visible_bodies: u8,
) -> (usize, usize)
pub unsafe fn fill_render_faces_split_raw( &self, indices: *mut u32, payloads: *mut RenderFacePayload, runs: *mut u32, out_len: usize, visible_bodies: u8, ) -> (usize, usize)
Split GPU face records into a hot packed-index stream, a cold UV stream,
and ordered texture runs. Each run word is
end_face:u16 | tex:u8<<16 | body_mask:u8<<24; end_face is relative
to this model. The caller guarantees enough face and run storage.
§Safety
indices and payloads must each be writable for out_len records.
runs must be writable for the maximum texture/body run count reported
by Self::render_face_run_count, and the outputs must not overlap.
Sourcepub fn vert(&self, index: usize) -> Vec3I16
👎Deprecated: renamed to vertex
pub fn vert(&self, index: usize) -> Vec3I16
renamed to vertex
Renamed to Model::vertex.
Sourcepub fn tri_uv_words(&self, t: usize) -> [u16; 3]
👎Deprecated: renamed to triangle_uv_words
pub fn tri_uv_words(&self, t: usize) -> [u16; 3]
renamed to triangle_uv_words
Renamed to Model::triangle_uv_words.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Model
impl RefUnwindSafe for Model
impl Send for Model
impl Sync for Model
impl Unpin for Model
impl UnsafeUnpin for Model
impl UnwindSafe for Model
Blanket Implementations§
§impl<T> Any for Twhere
T: 'static + ?Sized,
impl<T> Any for Twhere
T: 'static + ?Sized,
§impl<T> Borrow<T> for Twhere
T: ?Sized,
impl<T> Borrow<T> for Twhere
T: ?Sized,
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§unsafe fn clone_to_uninit(&self, dest: *mut u8)
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)