1use crate::error::{M2Error, Result};
2use crate::io_ext::{ReadExt, WriteExt};
3use std::io::{Read, Seek, SeekFrom, Write};
4
5pub trait M2Parse {
11 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self>
19 where
20 Self: Sized;
21
22 fn write<W: Write>(&self, writer: &mut W) -> Result<()>;
30}
31
32impl M2Parse for f32 {
33 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
34 Ok(reader.read_f32_le()?)
35 }
36
37 fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
38 writer.write_f32_le(*self)?;
39 Ok(())
40 }
41}
42
43impl M2Parse for u16 {
44 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
45 Ok(reader.read_u16_le()?)
46 }
47
48 fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
49 writer.write_u16_le(*self)?;
50 Ok(())
51 }
52}
53
54impl M2Parse for u32 {
55 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
56 Ok(reader.read_u32_le()?)
57 }
58
59 fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
60 writer.write_u32_le(*self)?;
61 Ok(())
62 }
63}
64
65#[derive(Debug, Clone, Default)]
73pub struct M2Vec<T: M2Parse> {
74 pub array: M2Array<T>,
76 pub data: Vec<T>,
78}
79
80impl<T: M2Parse> M2Vec<T> {
81 pub fn new() -> Self {
83 Self {
84 array: M2Array::new(0, 0),
85 data: Vec::new(),
86 }
87 }
88}
89
90impl<T: M2Parse> M2Parse for M2Vec<T> {
91 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
92 let array = M2Array::<T>::parse(reader)?;
93 let pos = reader.stream_position()?;
94 let data = read_array(reader, &array, |r| T::parse(r))?;
95 reader.seek(SeekFrom::Start(pos))?;
96 Ok(Self { array, data })
97 }
98
99 fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
100 self.array.write(writer)?;
101 Ok(())
102 }
103}
104
105#[derive(Debug, Clone, Copy, Default, PartialEq)]
107pub struct M2Array<T> {
108 pub count: u32,
110 pub offset: u32,
112 _phantom: std::marker::PhantomData<T>,
114}
115
116impl<T> M2Array<T> {
117 pub fn new(count: u32, offset: u32) -> Self {
119 Self {
120 count,
121 offset,
122 _phantom: std::marker::PhantomData,
123 }
124 }
125
126 pub fn parse<R: Read>(reader: &mut R) -> Result<Self> {
128 let count = reader.read_u32_le()?;
129 let offset = reader.read_u32_le()?;
130
131 Ok(Self {
132 count,
133 offset,
134 _phantom: std::marker::PhantomData,
135 })
136 }
137
138 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
140 writer.write_u32_le(self.count)?;
141 writer.write_u32_le(self.offset)?;
142
143 Ok(())
144 }
145
146 pub fn is_empty(&self) -> bool {
148 self.count == 0
149 }
150
151 pub fn convert<U>(&self) -> M2Array<U> {
153 M2Array {
154 count: self.count,
155 offset: self.offset,
156 _phantom: std::marker::PhantomData,
157 }
158 }
159}
160
161pub fn read_array<T, R, F>(reader: &mut R, array: &M2Array<T>, parse_fn: F) -> Result<Vec<T>>
163where
164 R: Read + Seek,
165 F: Fn(&mut R) -> Result<T>,
166{
167 if array.is_empty() {
168 return Ok(Vec::new());
169 }
170
171 reader
173 .seek(std::io::SeekFrom::Start(array.offset as u64))
174 .map_err(M2Error::Io)?;
175
176 let mut result = Vec::with_capacity(array.count as usize);
178 for _ in 0..array.count {
179 result.push(parse_fn(reader)?);
180 }
181
182 Ok(result)
183}
184
185pub fn read_raw_bytes<R: Read + Seek>(
187 reader: &mut R,
188 array: &M2Array<u32>,
189 element_size: usize,
190) -> Result<Vec<u8>> {
191 if array.is_empty() {
192 return Ok(Vec::new());
193 }
194
195 reader
197 .seek(std::io::SeekFrom::Start(array.offset as u64))
198 .map_err(M2Error::Io)?;
199
200 let total_bytes = array.count as usize * element_size;
202 let mut data = vec![0u8; total_bytes];
203 reader.read_exact(&mut data).map_err(M2Error::Io)?;
204
205 Ok(data)
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Default)]
210pub struct C3Vector {
211 pub x: f32,
212 pub y: f32,
213 pub z: f32,
214}
215
216impl M2Parse for C3Vector {
217 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
218 C3Vector::parse(reader)
219 }
220
221 fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
222 self.write(writer)
223 }
224}
225
226impl C3Vector {
227 pub fn parse<R: Read>(reader: &mut R) -> Result<Self> {
229 let x = reader.read_f32_le()?;
230 let y = reader.read_f32_le()?;
231 let z = reader.read_f32_le()?;
232
233 Ok(Self { x, y, z })
234 }
235
236 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
238 writer.write_f32_le(self.x)?;
239 writer.write_f32_le(self.y)?;
240 writer.write_f32_le(self.z)?;
241
242 Ok(())
243 }
244
245 pub fn to_glam(&self) -> glam::Vec3 {
247 glam::Vec3::new(self.x, self.y, self.z)
248 }
249
250 pub fn from_glam(v: glam::Vec3) -> Self {
252 Self {
253 x: v.x,
254 y: v.y,
255 z: v.z,
256 }
257 }
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Default)]
262pub struct C2Vector {
263 pub x: f32,
264 pub y: f32,
265}
266
267impl M2Parse for C2Vector {
268 fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
269 C2Vector::parse(reader)
270 }
271
272 fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
273 self.write(writer)
274 }
275}
276
277impl C2Vector {
278 pub fn parse<R: Read>(reader: &mut R) -> Result<Self> {
280 let x = reader.read_f32_le()?;
281 let y = reader.read_f32_le()?;
282
283 Ok(Self { x, y })
284 }
285
286 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
288 writer.write_f32_le(self.x)?;
289 writer.write_f32_le(self.y)?;
290
291 Ok(())
292 }
293
294 pub fn to_glam(&self) -> glam::Vec2 {
296 glam::Vec2::new(self.x, self.y)
297 }
298
299 pub fn from_glam(v: glam::Vec2) -> Self {
301 Self { x: v.x, y: v.y }
302 }
303}
304
305#[derive(Debug, Clone, PartialEq, Default)]
307pub struct FixedString {
308 pub data: Vec<u8>,
309}
310
311impl FixedString {
312 pub fn len(&self) -> usize {
313 self.data.len()
314 }
315
316 pub fn is_empty(&self) -> bool {
318 self.data.is_empty()
319 }
320
321 pub fn parse<R: Read + Seek>(reader: &mut R, len: usize) -> Result<Self> {
323 let mut data = vec![0u8; len];
324 reader.read_exact(&mut data)?;
325
326 let null_pos = data.iter().position(|&b| b == 0).unwrap_or(len);
328 data.truncate(null_pos);
329
330 Ok(Self { data })
331 }
332
333 pub fn write<W: Write>(&self, writer: &mut W, len: usize) -> Result<()> {
335 let mut data = self.data.clone();
336 data.resize(len, 0);
337 writer.write_all(&data)?;
338
339 Ok(())
340 }
341
342 pub fn to_string_lossy(&self) -> String {
344 String::from_utf8_lossy(&self.data).to_string()
345 }
346}
347
348#[derive(Debug, Clone, PartialEq, Default)]
349pub struct M2ArrayString {
350 pub string: FixedString,
351 pub array: M2Array<u8>,
352}
353
354impl M2ArrayString {
355 pub fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
356 let array = M2Array::<u8>::parse(reader)?;
357 let current_pos = reader.stream_position()?;
358 reader.seek(SeekFrom::Start(array.offset as u64))?;
359 let string = FixedString::parse(reader, array.count as usize)?;
360 reader.seek(SeekFrom::Start(current_pos))?;
361 Ok(Self { string, array })
362 }
363
364 pub fn is_empty(&self) -> bool {
365 self.array.is_empty()
366 }
367
368 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
370 writer.write_u32_le(self.array.count)?;
371 writer.write_u32_le(self.array.offset)?;
372
373 Ok(())
374 }
375}
376
377#[derive(Debug, Clone, Copy, PartialEq)]
379pub struct Quaternion {
380 pub x: f32,
381 pub y: f32,
382 pub z: f32,
383 pub w: f32,
384}
385
386impl Quaternion {
387 pub fn parse<R: Read>(reader: &mut R) -> Result<Self> {
389 let x = reader.read_f32_le()?;
390 let y = reader.read_f32_le()?;
391 let z = reader.read_f32_le()?;
392 let w = reader.read_f32_le()?;
393
394 Ok(Self { x, y, z, w })
395 }
396
397 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
399 writer.write_f32_le(self.x)?;
400 writer.write_f32_le(self.y)?;
401 writer.write_f32_le(self.z)?;
402 writer.write_f32_le(self.w)?;
403
404 Ok(())
405 }
406
407 pub fn to_glam(&self) -> glam::Quat {
409 glam::Quat::from_xyzw(self.x, self.y, self.z, self.w)
410 }
411
412 pub fn from_glam(q: glam::Quat) -> Self {
414 Self {
415 x: q.x,
416 y: q.y,
417 z: q.z,
418 w: q.w,
419 }
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426 use std::io::Cursor;
427
428 #[test]
429 fn test_m2array_parse() {
430 let data = [
431 0x05, 0x00, 0x00, 0x00, 0x20, 0x30, 0x00, 0x00, ];
434
435 let mut cursor = Cursor::new(data);
436 let array = M2Array::<u32>::parse(&mut cursor).unwrap();
437
438 assert_eq!(array.count, 5);
439 assert_eq!(array.offset, 0x3020);
440 }
441
442 #[test]
443 fn test_m2array_write() {
444 let array = M2Array::<u32>::new(5, 0x3020);
445 let mut cursor = Cursor::new(Vec::new());
446
447 array.write(&mut cursor).unwrap();
448
449 let data = cursor.into_inner();
450 assert_eq!(
451 data,
452 [
453 0x05, 0x00, 0x00, 0x00, 0x20, 0x30, 0x00, 0x00, ]
456 );
457 }
458
459 #[test]
460 fn test_c3vector_parse() {
461 let data = [
462 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x40, ];
466
467 let mut cursor = Cursor::new(data);
468 let vector = C3Vector::parse(&mut cursor).unwrap();
469
470 assert_eq!(vector.x, 1.0);
471 assert_eq!(vector.y, 2.0);
472 assert_eq!(vector.z, 3.0);
473 }
474
475 #[test]
476 fn test_c2vector_parse() {
477 let data = [
478 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x40, ];
481
482 let mut cursor = Cursor::new(data);
483 let vector = C2Vector::parse(&mut cursor).unwrap();
484
485 assert_eq!(vector.x, 1.0);
486 assert_eq!(vector.y, 2.0);
487 }
488
489 #[test]
490 fn test_fixed_string_parse() {
491 let data = [b'T', b'e', b's', b't', 0, 0, 0, 0];
492
493 let mut cursor = Cursor::new(data);
494 let string = FixedString::parse(&mut cursor, 8).unwrap();
495
496 assert_eq!(string.data, b"Test");
497 assert_eq!(string.to_string_lossy(), "Test");
498 }
499}