Skip to main content

wow_m2/chunks/
sequence.rs

1use crate::io_ext::{ReadExt, WriteExt};
2use std::io::{Read, Write};
3
4use crate::error::Result;
5use crate::version::M2Version;
6
7/// Sequence data for an animation
8#[derive(Debug, Clone)]
9pub struct M2Sequence {
10    /// Animation ID
11    pub animation_id: u16,
12    /// SubAnimation ID
13    pub sub_animation_id: u16,
14    /// Start frame
15    pub start: u32,
16    /// End frame
17    pub end: u32,
18    /// Movement speed
19    pub movement_speed: f32,
20    /// Flags
21    pub flags: u32,
22    /// Frequency
23    pub frequency: i16,
24    /// Padding
25    pub padding: u16,
26    /// Replay information
27    pub replay: M2AnimationRepeat,
28    /// Blend time
29    pub blend_time: u16,
30    /// Bounds
31    pub bounds: M2Bounds,
32    /// Variation next
33    pub variation_next: i16,
34    /// Alias next
35    pub alias_next: u16,
36}
37
38/// Animation repeat parameters
39#[derive(Debug, Clone)]
40pub struct M2AnimationRepeat {
41    /// Minimum repeat count
42    pub minimum: u32,
43    /// Maximum repeat count
44    pub maximum: u32,
45}
46
47impl M2AnimationRepeat {
48    /// Parse animation repeat parameters from a reader
49    pub fn parse<R: Read>(reader: &mut R) -> Result<Self> {
50        let minimum = reader.read_u32_le()?;
51        let maximum = reader.read_u32_le()?;
52
53        Ok(Self { minimum, maximum })
54    }
55
56    /// Write animation repeat parameters to a writer
57    pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
58        writer.write_u32_le(self.minimum)?;
59        writer.write_u32_le(self.maximum)?;
60
61        Ok(())
62    }
63}
64
65/// Animation bounds
66#[derive(Debug, Clone)]
67pub struct M2Bounds {
68    /// Minimum extent
69    pub minimum: [f32; 3],
70    /// Maximum extent
71    pub maximum: [f32; 3],
72    /// Bounds radius
73    pub radius: f32,
74}
75
76impl M2Bounds {
77    /// Parse animation bounds from a reader
78    pub fn parse<R: Read>(reader: &mut R) -> Result<Self> {
79        let mut minimum = [0.0; 3];
80        let mut maximum = [0.0; 3];
81
82        for item in &mut minimum {
83            *item = reader.read_f32_le()?;
84        }
85
86        for item in &mut maximum {
87            *item = reader.read_f32_le()?;
88        }
89
90        let radius = reader.read_f32_le()?;
91
92        Ok(Self {
93            minimum,
94            maximum,
95            radius,
96        })
97    }
98
99    /// Write animation bounds to a writer
100    pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
101        for &value in &self.minimum {
102            writer.write_f32_le(value)?;
103        }
104
105        for &value in &self.maximum {
106            writer.write_f32_le(value)?;
107        }
108
109        writer.write_f32_le(self.radius)?;
110
111        Ok(())
112    }
113}
114
115impl M2Sequence {
116    /// Parse a sequence from a reader based on the M2 version
117    pub fn parse<R: Read>(reader: &mut R, _version: u32) -> Result<Self> {
118        let animation_id = reader.read_u16_le()?;
119        let sub_animation_id = reader.read_u16_le()?;
120        let start = reader.read_u32_le()?;
121        let end = reader.read_u32_le()?;
122        let movement_speed = reader.read_f32_le()?;
123        let flags = reader.read_u32_le()?;
124        let frequency = reader.read_i16_le()?;
125        let padding = reader.read_u16_le()?;
126        let replay = M2AnimationRepeat::parse(reader)?;
127        let blend_time = reader.read_u16_le()?;
128        // Skip 2 bytes of padding
129        reader.read_u16_le()?;
130        let bounds = M2Bounds::parse(reader)?;
131        let variation_next = reader.read_i16_le()?;
132        let alias_next = reader.read_u16_le()?;
133
134        Ok(Self {
135            animation_id,
136            sub_animation_id,
137            start,
138            end,
139            movement_speed,
140            flags,
141            frequency,
142            padding,
143            replay,
144            blend_time,
145            bounds,
146            variation_next,
147            alias_next,
148        })
149    }
150
151    /// Write a sequence to a writer
152    pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
153        writer.write_u16_le(self.animation_id)?;
154        writer.write_u16_le(self.sub_animation_id)?;
155        writer.write_u32_le(self.start)?;
156        writer.write_u32_le(self.end)?;
157        writer.write_f32_le(self.movement_speed)?;
158        writer.write_u32_le(self.flags)?;
159        writer.write_i16_le(self.frequency)?;
160        writer.write_u16_le(self.padding)?;
161        self.replay.write(writer)?;
162        writer.write_u16_le(self.blend_time)?;
163        // Write 2 bytes of padding
164        writer.write_u16_le(0)?;
165        self.bounds.write(writer)?;
166        writer.write_i16_le(self.variation_next)?;
167        writer.write_u16_le(self.alias_next)?;
168
169        Ok(())
170    }
171
172    /// Convert this sequence to a different version (no version differences for sequences yet)
173    pub fn convert(&self, _target_version: M2Version) -> Self {
174        self.clone()
175    }
176
177    /// Create a new sequence with default values
178    pub fn new(animation_id: u16, sub_animation_id: u16, start: u32, end: u32) -> Self {
179        Self {
180            animation_id,
181            sub_animation_id,
182            start,
183            end,
184            movement_speed: 0.0,
185            flags: 0,
186            frequency: 0,
187            padding: 0,
188            replay: M2AnimationRepeat {
189                minimum: 0,
190                maximum: 0,
191            },
192            blend_time: 0,
193            bounds: M2Bounds {
194                minimum: [0.0, 0.0, 0.0],
195                maximum: [0.0, 0.0, 0.0],
196                radius: 0.0,
197            },
198            variation_next: -1,
199            alias_next: 0,
200        }
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207    use std::io::Cursor;
208
209    #[test]
210    fn test_sequence_parse_write() {
211        let sequence = M2Sequence::new(1, 0, 0, 30);
212
213        // Write to buffer
214        let mut buffer = Vec::new();
215        sequence.write(&mut buffer).unwrap();
216
217        // Read back
218        let mut cursor = Cursor::new(buffer);
219        let parsed =
220            M2Sequence::parse(&mut cursor, M2Version::Vanilla.to_header_version()).unwrap();
221
222        // Verify
223        assert_eq!(parsed.animation_id, 1);
224        assert_eq!(parsed.sub_animation_id, 0);
225        assert_eq!(parsed.start, 0);
226        assert_eq!(parsed.end, 30);
227    }
228}