wow_m2/chunks/
texture_animation.rs1use crate::io_ext::{ReadExt, WriteExt};
2use std::io::{Read, Seek, Write};
3
4use crate::chunks::animation::{M2AnimationBlock, M2AnimationTrack};
5use crate::error::Result;
6use crate::version::M2Version;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum M2TextureAnimationType {
11 None = 0,
13 Scroll = 1,
15 Rotate = 2,
17 Scale = 3,
19 KeyFrame = 4,
21}
22
23impl M2TextureAnimationType {
24 pub fn from_u16(value: u16) -> Option<Self> {
26 match value {
27 0 => Some(Self::None),
28 1 => Some(Self::Scroll),
29 2 => Some(Self::Rotate),
30 3 => Some(Self::Scale),
31 4 => Some(Self::KeyFrame),
32 _ => None,
33 }
34 }
35}
36
37#[derive(Debug, Clone)]
39pub struct M2TextureAnimation {
40 pub animation_type: M2TextureAnimationType,
42 pub translation_u: M2AnimationBlock<f32>,
44 pub translation_v: M2AnimationBlock<f32>,
46 pub rotation: M2AnimationBlock<f32>,
48 pub scale_u: M2AnimationBlock<f32>,
50 pub scale_v: M2AnimationBlock<f32>,
52}
53
54impl M2TextureAnimation {
55 pub fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
57 let type_raw = reader.read_u16_le()?;
58 let animation_type =
59 M2TextureAnimationType::from_u16(type_raw).unwrap_or(M2TextureAnimationType::None);
60
61 reader.read_u16_le()?;
63
64 let translation_u = M2AnimationBlock::parse(reader)?;
65 let translation_v = M2AnimationBlock::parse(reader)?;
66 let rotation = M2AnimationBlock::parse(reader)?;
67 let scale_u = M2AnimationBlock::parse(reader)?;
68 let scale_v = M2AnimationBlock::parse(reader)?;
69
70 Ok(Self {
71 animation_type,
72 translation_u,
73 translation_v,
74 rotation,
75 scale_u,
76 scale_v,
77 })
78 }
79
80 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
82 writer.write_u16_le(self.animation_type as u16)?;
83
84 writer.write_u16_le(0)?;
86
87 self.translation_u.write(writer)?;
88 self.translation_v.write(writer)?;
89 self.rotation.write(writer)?;
90 self.scale_u.write(writer)?;
91 self.scale_v.write(writer)?;
92
93 Ok(())
94 }
95
96 pub fn convert(&self, _target_version: M2Version) -> Self {
98 self.clone()
99 }
100
101 pub fn new(animation_type: M2TextureAnimationType) -> Self {
103 Self {
104 animation_type,
105 translation_u: M2AnimationBlock::new(M2AnimationTrack::default()),
106 translation_v: M2AnimationBlock::new(M2AnimationTrack::default()),
107 rotation: M2AnimationBlock::new(M2AnimationTrack::default()),
108 scale_u: M2AnimationBlock::new(M2AnimationTrack::default()),
109 scale_v: M2AnimationBlock::new(M2AnimationTrack::default()),
110 }
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use std::io::Cursor;
118
119 #[test]
120 fn test_texture_animation_parse_write() {
121 let mut data = Vec::new();
122
123 data.extend_from_slice(&1u16.to_le_bytes());
125
126 data.extend_from_slice(&0u16.to_le_bytes());
128
129 data.extend_from_slice(&1u16.to_le_bytes()); data.extend_from_slice(&(-1i16).to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&1u16.to_le_bytes()); data.extend_from_slice(&(-1i16).to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&1u16.to_le_bytes()); data.extend_from_slice(&(-1i16).to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&1u16.to_le_bytes()); data.extend_from_slice(&(-1i16).to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&1u16.to_le_bytes()); data.extend_from_slice(&(-1i16).to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); let mut cursor = Cursor::new(data);
180 let tex_anim = M2TextureAnimation::parse(&mut cursor).unwrap();
181
182 assert_eq!(tex_anim.animation_type, M2TextureAnimationType::Scroll);
183
184 let mut output = Vec::new();
186 tex_anim.write(&mut output).unwrap();
187
188 assert_eq!(output.len(), cursor.get_ref().len());
190 }
191}