use crate::SsbhArray;
use crate::SsbhByteBuffer;
use crate::SsbhString;
use crate::Version;
use binrw::BinRead;
use modular_bitfield::prelude::*;
use ssbh_write::SsbhWrite;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "strum")]
use strum::{Display, EnumIter, EnumString, FromRepr};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
#[br(import(major_version: u16, minor_version: u16))]
pub enum Anim {
#[br(pre_assert(major_version == 1 && minor_version == 2))]
V12 {
name: SsbhString,
unk1: f32,
final_frame_index: f32,
unk2: f32,
unk3: f32,
tracks: SsbhArray<TrackV1>,
buffers: SsbhArray<SsbhByteBuffer>,
},
#[br(pre_assert(major_version == 2 && minor_version == 0))]
V20 {
final_frame_index: f32,
unk1: u16, unk2: u16, name: SsbhString,
groups: SsbhArray<Group>,
buffer: SsbhByteBuffer,
},
#[br(pre_assert(major_version == 2 && minor_version == 1))]
#[ssbhwrite(align_after = 8)]
V21 {
final_frame_index: f32,
unk1: u16, unk2: u16, name: SsbhString,
groups: SsbhArray<Group>,
buffer: SsbhByteBuffer,
unk_data: UnkData,
},
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct Group {
pub group_type: GroupType,
pub nodes: SsbhArray<Node>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct Node {
pub name: SsbhString,
pub tracks: SsbhArray<TrackV2>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct TrackV2 {
pub name: SsbhString,
pub flags: TrackFlags,
pub frame_count: u32,
pub transform_flags: TransformFlags,
pub data_offset: u32,
pub data_size: u64,
}
impl Version for Anim {
fn major_minor_version(&self) -> (u16, u16) {
match self {
Anim::V12 { .. } => (1, 2),
Anim::V20 { .. } => (2, 0),
Anim::V21 { .. } => (2, 1),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct TrackV1 {
pub name: SsbhString,
pub track_type: TrackTypeV1,
pub properties: SsbhArray<Property>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct Property {
pub name: SsbhString,
pub buffer_index: u64,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct UnkData {
pub unk1: SsbhArray<UnkItem1>,
pub unk2: SsbhArray<UnkItem2>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct UnkItem1 {
pub unk1: u64, pub unk2: SsbhArray<UnkSubItem>, }
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct UnkItem2 {
pub unk1: SsbhString, pub unk2: SsbhArray<UnkSubItem>, }
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, PartialEq)]
pub struct UnkSubItem {
pub unk1: u32,
pub unk2: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, Copy, PartialEq, Eq)]
#[ssbhwrite(pad_after = 2)]
pub struct TrackFlags {
pub track_type: TrackTypeV2,
#[br(pad_after = 2)]
pub compression_type: CompressionType,
}
#[bitfield(bits = 32)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Clone, Copy, PartialEq, Default)]
#[br(map = Self::from_bytes)]
pub struct TransformFlags {
pub override_translation: bool,
pub override_rotation: bool,
pub override_scale: bool,
pub override_compensate_scale: bool,
#[skip]
__: B28,
}
ssbh_write::ssbh_write_modular_bitfield_impl!(TransformFlags, 4);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, Copy, PartialEq, Eq)]
#[br(repr(u64))]
#[ssbhwrite(repr(u64))]
pub enum TrackTypeV1 {
Transform = 0,
UvTransform = 2,
Visibility = 5,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, Copy, PartialEq, Eq)]
#[br(repr(u8))]
#[ssbhwrite(repr(u8))]
pub enum TrackTypeV2 {
Transform = 1,
UvTransform = 2,
Float = 3,
PatternIndex = 5,
Boolean = 8,
Vector4 = 9,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, SsbhWrite, Clone, Copy, PartialEq, Eq)]
#[br(repr(u8))]
#[ssbhwrite(repr(u8))]
pub enum CompressionType {
Direct = 1,
ConstTransform = 2,
Compressed = 4,
Constant = 5,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "strum", derive(FromRepr, Display, EnumIter, EnumString))]
#[derive(Debug, BinRead, SsbhWrite, Clone, Copy, PartialEq, Eq, Hash)]
#[br(repr(u64))]
#[ssbhwrite(repr(u64))]
pub enum GroupType {
Transform = 1,
Visibility = 2,
Material = 4,
Camera = 5,
}
#[cfg(test)]
mod tests {
use binrw::io::Cursor;
use super::*;
#[test]
fn align_v20() {
let mut buffer = Cursor::new(Vec::new());
let anim = Anim::V20 {
final_frame_index: 0.0,
unk1: 0,
unk2: 0,
name: "a".into(),
groups: SsbhArray::new(),
buffer: SsbhByteBuffer::new(),
};
anim.write(&mut buffer).unwrap();
assert_eq!(2, buffer.into_inner().len() % 8);
}
#[test]
fn align_v21() {
let mut buffer = Cursor::new(Vec::new());
let anim = Anim::V21 {
final_frame_index: 0.0,
unk1: 0,
unk2: 0,
name: "a".into(),
groups: SsbhArray::new(),
buffer: SsbhByteBuffer::new(),
unk_data: UnkData {
unk1: SsbhArray::new(),
unk2: SsbhArray::new(),
},
};
anim.write(&mut buffer).unwrap();
assert_eq!(0, buffer.into_inner().len() % 8);
}
}