1mod compressed_vector;
2mod error;
3mod handle;
4pub mod mdl;
5mod shared;
6pub mod vtx;
7pub mod vvd;
8
9pub use crate::mdl::Mdl;
10use crate::mdl::{AnimationDescription, Bone, ModelFlags, PoseParameterDescription, TextureInfo};
11pub use crate::vtx::Vtx;
12use crate::vvd::Vertex;
13pub use crate::vvd::Vvd;
14use bytemuck::{pod_read_unaligned, Contiguous, Pod};
15use cgmath::{Matrix4, SquareMatrix, Transform, Vector3};
16pub use error::*;
17pub use handle::Handle;
18use itertools::Either;
19pub use shared::*;
20use std::any::type_name;
21use std::fs;
22use std::iter::once;
23use std::mem::size_of;
24use std::path::Path;
25
26pub struct Model {
27 #[allow(dead_code)]
28 mdl: Mdl,
29 vtx: Vtx,
30 vvd: Vvd,
31}
32
33impl Model {
34 pub fn from_parts(mdl: Mdl, vtx: Vtx, vvd: Vvd) -> Self {
35 Model { mdl, vtx, vvd }
36 }
37
38 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ModelError> {
42 let path = path.as_ref();
43 let data = fs::read(path)?;
44 let mdl = Mdl::read(&data)?;
45 let data = fs::read(path.with_extension("dx90.vtx"))?;
46 let vtx = Vtx::read(&data)?;
47 let data = fs::read(path.with_extension("vvd"))?;
48 let vvd = Vvd::read(&data)?;
49
50 Ok(Model::from_parts(mdl, vtx, vvd))
51 }
52
53 pub fn vertices(&self) -> &[Vertex] {
54 &self.vvd.vertices
55 }
56
57 pub fn tangents(&self) -> &[[f32; 4]] {
58 &self.vvd.tangents
59 }
60
61 pub fn texture_directories(&self) -> &[String] {
62 &self.mdl.texture_paths
63 }
64
65 pub fn textures(&self) -> &[TextureInfo] {
66 &self.mdl.textures
67 }
68
69 pub fn skin_tables(&self) -> impl Iterator<Item = SkinTable> {
70 if self.mdl.header.skin_reference_count > 0 {
71 Either::Left(
72 self.mdl
73 .skin_table
74 .chunks(self.mdl.header.skin_reference_count as usize)
75 .map(|chunk| SkinTable {
76 table: chunk,
77 textures: &self.mdl.textures,
78 }),
79 )
80 } else {
81 Either::Right(once(SkinTable {
82 table: &[],
83 textures: &[],
84 }))
85 }
86 }
87
88 pub fn animations(&self) -> impl Iterator<Item = &AnimationDescription> {
89 self.mdl.local_animations.iter()
90 }
91
92 pub fn meshes(&self) -> impl Iterator<Item = Mesh> {
93 let mdl_meshes = self
94 .mdl
95 .body_parts
96 .iter()
97 .flat_map(|part| part.models.iter())
98 .flat_map(|model| {
99 model
100 .meshes
101 .iter()
102 .map(|mesh| (mesh, model.name.as_str(), model.vertex_offset as usize))
103 });
104
105 let vtx_meshes = self
106 .vtx
107 .body_parts
108 .iter()
109 .flat_map(|part| part.models.iter())
110 .flat_map(|model| model.lods.first())
111 .flat_map(|lod| lod.meshes.iter());
112
113 mdl_meshes
114 .zip(vtx_meshes)
115 .map(|((mdl, model_name, model_vertex_offset), vtx)| Mesh {
116 model_vertex_offset,
117 model_name,
118 vertices: self.vertices(),
119 tangents: self.tangents(),
120 mdl,
121 vtx,
122 })
123 }
124
125 pub fn bounding_box(&self) -> (Vector, Vector) {
127 (
128 self.mdl.header.bounding_box[0],
129 self.mdl.header.bounding_box[1],
130 )
131 }
132
133 pub fn name(&self) -> &str {
134 self.mdl.name.as_str()
135 }
136
137 pub fn bones(&self) -> impl Iterator<Item = &Bone> {
138 self.mdl.bones.iter()
139 }
140
141 pub fn root_transform(&self) -> Matrix4<f32> {
142 if self.mdl.header.flags.contains(ModelFlags::STATIC_PROP) {
143 return Matrix4::identity();
144 }
145
146 self.bones()
147 .next()
148 .map(|bone| Matrix4::from(bone.rot))
149 .unwrap_or_else(Matrix4::identity)
150 }
151
152 pub fn idle_transform(&self) -> Matrix4<f32> {
153 if self.mdl.header.flags.contains(ModelFlags::STATIC_PROP) {
154 return Matrix4::identity();
155 }
156
157 self.mdl
158 .local_animations
159 .iter()
160 .filter_map(|desc| desc.animations.iter().find(|animation| animation.bone == 0))
161 .find(|anim| anim.rotation_looks_valid())
162 .map(|animation| animation.rotation(0))
163 .map(Matrix4::from)
164 .unwrap_or_else(Matrix4::identity)
165 }
166
167 pub fn surface_prop(&self) -> &str {
168 self.mdl.surface_prop.as_str()
169 }
170
171 pub fn poses(&self) -> impl Iterator<Item = &PoseParameterDescription> {
172 self.mdl.pose_parameters.iter()
173 }
174
175 pub fn apply_root_transform(&self, vec: Vector) -> Vector {
176 let transform = self.idle_transform() * self.root_transform();
177 transform.transform_vector(Vector3::from(vec)).into()
178 }
179}
180
181pub struct SkinTable<'a> {
182 textures: &'a [TextureInfo],
183 table: &'a [u16],
184}
185
186impl<'a> SkinTable<'a> {
187 pub fn texture(&self, index: i32) -> Option<&'a str> {
188 self.texture_info(index).map(|info| info.name.as_str())
189 }
190
191 pub fn texture_index(&self, index: i32) -> Option<usize> {
192 let texture_index = self.table.get(index as usize)?;
193 Some(*texture_index as usize)
194 }
195 pub fn texture_info(&self, index: i32) -> Option<&'a TextureInfo> {
196 let texture_index = self.table.get(index as usize)?;
197 self.textures.get(*texture_index as usize)
198 }
199}
200
201pub struct Mesh<'a> {
202 pub model_name: &'a str,
203 model_vertex_offset: usize,
204 vertices: &'a [Vertex],
205 tangents: &'a [[f32; 4]],
206 mdl: &'a mdl::Mesh,
207 vtx: &'a vtx::Mesh,
208}
209
210impl<'a> Mesh<'a> {
211 pub fn vertex_strip_indices(&self) -> impl Iterator<Item = impl Iterator<Item = usize> + 'a> {
213 let mdl_offset = self.mdl.vertex_offset as usize + self.model_vertex_offset;
214 self.vtx.strip_groups.iter().flat_map(move |strip_group| {
215 let group_indices = &strip_group.indices;
216 let vertices = &strip_group.vertices;
217 strip_group.strips.iter().map(move |strip| {
218 strip
219 .indices()
220 .map(move |index| group_indices[index] as usize)
221 .map(move |index| vertices[index].original_mesh_vertex_id as usize + mdl_offset)
222 })
223 })
224 }
225
226 pub fn material_index(&self) -> i32 {
227 self.mdl.material
228 }
229
230 pub fn vertices(&self) -> impl Iterator<Item = &'a Vertex> + 'a {
231 self.vertex_strip_indices()
232 .flat_map(|strip| strip.map(|index| &self.vertices[index]))
233 }
234
235 pub fn tangents(&self) -> impl Iterator<Item = [f32; 4]> + '_ {
236 self.vertex_strip_indices()
237 .flat_map(|strip| strip.map(|index| self.tangents[index]))
238 }
239}
240
241fn index_range(index: i32, count: i32, size: usize) -> impl Iterator<Item = usize> {
242 (0..count as usize)
243 .map(move |i| i * size)
244 .map(move |i| index as usize + i)
245}
246
247fn read_relative_iter<'a, T: ReadRelative, I: 'a + Iterator<Item = usize>>(
248 data: &'a [u8],
249 indexes: I,
250) -> impl Iterator<Item = Result<T, ModelError>> + 'a {
251 indexes.map(|index| {
252 let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
253 data: type_name::<T>(),
254 offset: index,
255 })?;
256 let header = <T::Header as Readable>::read(data)?;
257 T::read(data, header)
258 })
259}
260
261fn read_relative<T: ReadRelative, I: Iterator<Item = usize>>(
262 data: &[u8],
263 indexes: I,
264) -> Result<Vec<T>, ModelError> {
265 read_relative_iter(data, indexes).collect()
266}
267
268fn read_single<T: ReadRelative, I: TryInto<usize>>(data: &[u8], index: I) -> Result<T, ModelError> {
269 let index = index.try_into().map_err(|_| ModelError::OutOfBounds {
270 data: type_name::<T>(),
271 offset: usize::MAX_VALUE,
272 })?;
273 let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
274 data: type_name::<T>(),
275 offset: index,
276 })?;
277 let header = <T::Header as Readable>::read(data)?;
278 T::read(data, header)
279}
280
281trait Readable: Sized {
282 fn read(data: &[u8]) -> Result<Self, ModelError>;
283}
284
285impl<T: Pod> Readable for T {
286 fn read(data: &[u8]) -> Result<Self, ModelError> {
287 let data = data
288 .get(0..size_of::<Self>())
289 .ok_or(ModelError::Eof(size_of::<Self>()))?;
290 Ok(pod_read_unaligned(data))
291 }
292}
293
294trait ReadRelative: Sized {
295 type Header: Readable;
296
297 fn read(data: &[u8], header: Self::Header) -> Result<Self, ModelError>;
298}
299
300trait ReadableRelative: Readable {}
301
302impl ReadableRelative for u8 {}
303impl ReadableRelative for u16 {}
304impl ReadableRelative for u32 {}
305impl ReadableRelative for i8 {}
306impl ReadableRelative for i16 {}
307impl ReadableRelative for i32 {}
308impl ReadableRelative for f32 {}
309impl<T: ReadableRelative + Pod> ReadableRelative for [T; 1] {}
310impl<T: ReadableRelative + Pod> ReadableRelative for [T; 2] {}
311impl<T: ReadableRelative + Pod> ReadableRelative for [T; 3] {}
312impl<T: ReadableRelative + Pod> ReadableRelative for [T; 4] {}
313
314impl<T: ReadableRelative> ReadRelative for T {
315 type Header = T;
316
317 fn read(_data: &[u8], header: Self::Header) -> Result<Self, ModelError> {
318 Ok(header)
319 }
320}
321
322impl ReadRelative for String {
323 type Header = ();
324
325 fn read(data: &[u8], _header: Self::Header) -> Result<Self, ModelError> {
326 let bytes = data.iter().copied().take_while(|byte| *byte != 0).collect();
327 String::from_utf8(bytes).map_err(ModelError::from)
328 }
329}