use crate::io_ext::{ReadExt, WriteExt};
use std::io::{Read, Seek, Write};
use crate::chunks::animation::{M2AnimationBlock, M2AnimationTrack};
use crate::error::Result;
use crate::version::M2Version;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum M2TextureAnimationType {
None = 0,
Scroll = 1,
Rotate = 2,
Scale = 3,
KeyFrame = 4,
}
impl M2TextureAnimationType {
pub fn from_u16(value: u16) -> Option<Self> {
match value {
0 => Some(Self::None),
1 => Some(Self::Scroll),
2 => Some(Self::Rotate),
3 => Some(Self::Scale),
4 => Some(Self::KeyFrame),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct M2TextureAnimation {
pub animation_type: M2TextureAnimationType,
pub translation_u: M2AnimationBlock<f32>,
pub translation_v: M2AnimationBlock<f32>,
pub rotation: M2AnimationBlock<f32>,
pub scale_u: M2AnimationBlock<f32>,
pub scale_v: M2AnimationBlock<f32>,
}
impl M2TextureAnimation {
pub fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
let type_raw = reader.read_u16_le()?;
let animation_type =
M2TextureAnimationType::from_u16(type_raw).unwrap_or(M2TextureAnimationType::None);
reader.read_u16_le()?;
let translation_u = M2AnimationBlock::parse(reader)?;
let translation_v = M2AnimationBlock::parse(reader)?;
let rotation = M2AnimationBlock::parse(reader)?;
let scale_u = M2AnimationBlock::parse(reader)?;
let scale_v = M2AnimationBlock::parse(reader)?;
Ok(Self {
animation_type,
translation_u,
translation_v,
rotation,
scale_u,
scale_v,
})
}
pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
writer.write_u16_le(self.animation_type as u16)?;
writer.write_u16_le(0)?;
self.translation_u.write(writer)?;
self.translation_v.write(writer)?;
self.rotation.write(writer)?;
self.scale_u.write(writer)?;
self.scale_v.write(writer)?;
Ok(())
}
pub fn convert(&self, _target_version: M2Version) -> Self {
self.clone()
}
pub fn new(animation_type: M2TextureAnimationType) -> Self {
Self {
animation_type,
translation_u: M2AnimationBlock::new(M2AnimationTrack::default()),
translation_v: M2AnimationBlock::new(M2AnimationTrack::default()),
rotation: M2AnimationBlock::new(M2AnimationTrack::default()),
scale_u: M2AnimationBlock::new(M2AnimationTrack::default()),
scale_v: M2AnimationBlock::new(M2AnimationTrack::default()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_texture_animation_parse_write() {
let mut data = Vec::new();
data.extend_from_slice(&1u16.to_le_bytes());
data.extend_from_slice(&0u16.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());
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);
let tex_anim = M2TextureAnimation::parse(&mut cursor).unwrap();
assert_eq!(tex_anim.animation_type, M2TextureAnimationType::Scroll);
let mut output = Vec::new();
tex_anim.write(&mut output).unwrap();
assert_eq!(output.len(), cursor.get_ref().len());
}
}