vmdl/vtx/
mod.rs

1mod raw;
2
3use crate::{read_relative, ModelError, ReadRelative, Readable};
4use itertools::Either;
5use raw::*;
6pub use raw::{MeshFlags, StripFlags, StripGroupFlags, Vertex};
7use std::ops::Range;
8
9pub const MDL_VERSION: i32 = 7;
10
11type Result<T> = std::result::Result<T, ModelError>;
12
13/// The vtx file contains the mesh data for each mesh in an mdl, indexing into the vvd file
14#[derive(Debug, Clone)]
15pub struct Vtx {
16    pub header: VtxHeader,
17    pub body_parts: Vec<BodyPart>,
18}
19
20impl Vtx {
21    pub fn read(data: &[u8]) -> Result<Self> {
22        let header = <VtxHeader as Readable>::read(data)?;
23        Ok(Vtx {
24            body_parts: read_relative(data, header.body_indexes())?,
25            header,
26        })
27    }
28}
29
30#[derive(Debug, Clone)]
31pub struct BodyPart {
32    pub models: Vec<Model>,
33}
34
35impl ReadRelative for BodyPart {
36    type Header = BodyPartHeader;
37
38    fn read(data: &[u8], header: Self::Header) -> Result<Self> {
39        Ok(BodyPart {
40            models: read_relative(data, header.model_indexes())?,
41        })
42    }
43}
44
45#[derive(Debug, Clone)]
46pub struct Model {
47    pub lods: Vec<ModelLod>,
48}
49
50impl ReadRelative for Model {
51    type Header = ModelHeader;
52
53    fn read(data: &[u8], header: Self::Header) -> Result<Self> {
54        Ok(Model {
55            lods: read_relative(data, header.lod_indexes())?,
56        })
57    }
58}
59
60#[derive(Debug, Clone)]
61pub struct ModelLod {
62    pub meshes: Vec<Mesh>,
63    pub switch_point: f32,
64}
65
66impl ReadRelative for ModelLod {
67    type Header = ModelLodHeader;
68
69    fn read(data: &[u8], header: Self::Header) -> Result<Self> {
70        Ok(ModelLod {
71            meshes: read_relative(data, header.mesh_indexes())?,
72            switch_point: header.switch_point,
73        })
74    }
75}
76
77#[derive(Debug, Clone)]
78pub struct Mesh {
79    pub strip_groups: Vec<StripGroup>,
80    pub flags: MeshFlags,
81}
82
83impl ReadRelative for Mesh {
84    type Header = MeshHeader;
85
86    fn read(data: &[u8], header: Self::Header) -> Result<Self> {
87        Ok(Mesh {
88            strip_groups: read_relative(data, header.strip_group_indexes())?,
89            flags: header.flags,
90        })
91    }
92}
93
94#[derive(Debug, Clone)]
95pub struct StripGroup {
96    // todo topologies
97    pub indices: Vec<u16>,
98    pub vertices: Vec<Vertex>,
99    pub strips: Vec<Strip>,
100    pub flags: StripGroupFlags,
101}
102
103impl ReadRelative for StripGroup {
104    type Header = StripGroupHeader;
105
106    fn read(data: &[u8], header: Self::Header) -> Result<Self> {
107        Ok(StripGroup {
108            vertices: read_relative(data, header.vertex_indexes())?,
109            strips: read_relative(data, header.strip_indexes())?,
110            indices: read_relative(data, header.index_indexes())?,
111            flags: header.flags,
112        })
113    }
114}
115
116#[derive(Debug, Clone)]
117pub struct Strip {
118    // todo bone state changes
119    vertices: Range<usize>,
120    pub flags: StripFlags,
121    indices: Range<usize>,
122}
123
124impl ReadRelative for Strip {
125    type Header = StripHeader;
126
127    fn read(_data: &[u8], header: Self::Header) -> Result<Self> {
128        Ok(Strip {
129            vertices: header.vertex_indexes(),
130            indices: header.index_indexes(),
131            flags: header.flags,
132        })
133    }
134}
135
136impl Strip {
137    pub fn vertices(&self) -> impl Iterator<Item = usize> + 'static {
138        self.vertices.clone()
139    }
140
141    pub fn indices(&self) -> impl Iterator<Item = usize> + 'static {
142        if self.flags.contains(StripFlags::IS_TRI_STRIP) {
143            let offset = self.indices.start;
144            Either::Left((0..self.indices.len()).flat_map(move |i| {
145                let cw = i & 1;
146                let idx = offset + i;
147                [idx, idx + 1 - cw, idx + 2 - cw].into_iter().rev()
148            }))
149        } else {
150            Either::Right(self.indices.clone().rev())
151        }
152    }
153}