use cgmath::{Matrix4, Vector3};
use fancy_slice::FancySlice;
use std::iter::Iterator;
use crate::math;
use crate::resources;
#[rustfmt::skip]
pub(crate) fn chr0(data: FancySlice) -> Chr0 {
let _size = data.i32_be(0x4);
let version = data.i32_be(0x8);
let _bres_offset = data.i32_be(0xc);
let resources_offset = data.i32_be(0x10);
let string_offset = data.i32_be(0x14);
let _orig_path_offset = data.i32_be(0x18);
let num_frames = data.u16_be(0x1c);
let _num_children = data.u16_be(0x1e);
let loop_value = data.i32_be(0x20);
let _scaling_rule = data.i32_be(0x24);
if version == 0 || version == 4 {
}
else if version == 5 {
unimplemented!("Need to implement handling for chr0 v5, refer to brawlbox CHR0Node.cs");
}
else {
panic!("Unknown chr0 version: {}", version);
}
let name = data.str(string_offset as usize).unwrap().to_string();
let mut children = vec!();
for resource in resources::resources(data.relative_fancy_slice(resources_offset as usize ..)) {
let child_data = data.relative_fancy_slice(resources_offset as usize + resource.data_offset as usize .. );
let string_offset = child_data.i32_be(0);
let _string = child_data.str(string_offset as usize).unwrap();
let code = Chr0ChildCode::new(child_data.u32_be(4));
let mut data_offset = CHR0_CHILD_SIZE;
let scale = keyframe_holder(child_data.relative_fancy_slice(..), &mut data_offset, code.scale_exists(), code.scale_isotropic(), code.scale_fixed_x(), code.scale_fixed_y(), code.scale_fixed_z(), code.scale_format(), num_frames);
let rot = keyframe_holder(child_data.relative_fancy_slice(..), &mut data_offset, code.rot_exists(), code.rot_isotropic(), code.rot_fixed_x(), code.rot_fixed_y(), code.rot_fixed_z(), code.rot_format(), num_frames);
let translation = keyframe_holder(child_data.relative_fancy_slice(..), &mut data_offset, code.translation_exists(), code.translation_isotropic(), code.translation_fixed_x(), code.translation_fixed_y(), code.translation_fixed_z(), code.translation_format(), num_frames);
children.push(Chr0Child {
name: resource.string,
_code: code,
scale,
rot,
translation,
});
}
Chr0 {
name,
_size,
_version: version,
_bres_offset,
_orig_path_offset,
num_frames,
_num_children,
loop_value: loop_value != 0,
_scaling_rule,
children,
}
}
#[derive(Clone, Debug)]
pub struct Chr0 {
pub name: String,
_size: i32,
_version: i32,
_bres_offset: i32,
_orig_path_offset: i32,
pub num_frames: u16,
_num_children: u16,
pub loop_value: bool,
_scaling_rule: i32,
pub children: Vec<Chr0Child>,
}
const CHR0_CHILD_SIZE: usize = 0x8;
#[derive(Clone, Debug)]
pub struct Chr0Child {
pub name: String,
pub scale: KeyframeHolder,
pub rot: KeyframeHolder,
pub translation: KeyframeHolder,
_code: Chr0ChildCode,
}
impl Chr0Child {
pub fn get_transform(&self, loop_value: bool, frame: i32) -> Matrix4<f32> {
let scale = self.scale.get_value(loop_value, frame, 1.0);
let rot = self.rot.get_value(loop_value, frame, 0.0);
let translation = self.translation.get_value(loop_value, frame, 0.0);
math::gen_transform(scale, rot, translation)
}
pub fn get_transform_rot_only(&self, loop_value: bool, frame: i32) -> Matrix4<f32> {
let scale = Vector3::new(1.0, 1.0, 1.0);
let rot = self.rot.get_value(loop_value, frame, 0.0);
let translation = Vector3::new(0.0, 0.0, 0.0);
math::gen_transform(scale, rot, translation)
}
}
#[derive(Clone, Debug)]
pub struct Chr0ChildCode {
value: u32,
}
#[rustfmt::skip]
impl Chr0ChildCode {
fn new(value: u32) -> Chr0ChildCode {
assert_eq!(value & 1, 1);
Chr0ChildCode { value }
}
pub fn identity (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_0000_0010 != 0 } pub fn rot_translation_zero (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_0000_0100 != 0 } pub fn scale_one (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_0000_1000 != 0 }
pub fn scale_isotropic (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_0001_0000 != 0 }
pub fn rot_isotropic (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_0010_0000 != 0 }
pub fn translation_isotropic (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_0100_0000 != 0 }
pub fn use_model_scale (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0000_1000_0000 != 0 }
pub fn use_model_rot (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0001_0000_0000 != 0 }
pub fn use_model_translation (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0010_0000_0000 != 0 }
pub fn scale_compensate_apply (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_0100_0000_0000 != 0 } pub fn scale_compenstate_parent (&self) -> bool { self.value & 0b0000_0000_0000_0000_0000_1000_0000_0000 != 0 } pub fn classic_scale_off (&self) -> bool { self.value & 0b0000_0000_0000_0000_0001_0000_0000_0000 != 0 }
pub fn scale_fixed_x (&self) -> bool { self.value & 0b0000_0000_0000_0000_0010_0000_0000_0000 != 0 }
pub fn scale_fixed_y (&self) -> bool { self.value & 0b0000_0000_0000_0000_0100_0000_0000_0000 != 0 }
pub fn scale_fixed_z (&self) -> bool { self.value & 0b0000_0000_0000_0000_1000_0000_0000_0000 != 0 }
pub fn rot_fixed_x (&self) -> bool { self.value & 0b0000_0000_0000_0001_0000_0000_0000_0000 != 0 }
pub fn rot_fixed_y (&self) -> bool { self.value & 0b0000_0000_0000_0010_0000_0000_0000_0000 != 0 }
pub fn rot_fixed_z (&self) -> bool { self.value & 0b0000_0000_0000_0100_0000_0000_0000_0000 != 0 }
pub fn translation_fixed_x (&self) -> bool { self.value & 0b0000_0000_0000_1000_0000_0000_0000_0000 != 0 }
pub fn translation_fixed_y (&self) -> bool { self.value & 0b0000_0000_0001_0000_0000_0000_0000_0000 != 0 }
pub fn translation_fixed_z (&self) -> bool { self.value & 0b0000_0000_0010_0000_0000_0000_0000_0000 != 0 }
pub fn scale_exists (&self) -> bool { self.value & 0b0000_0000_0100_0000_0000_0000_0000_0000 != 0 } pub fn rot_exists (&self) -> bool { self.value & 0b0000_0000_1000_0000_0000_0000_0000_0000 != 0 } pub fn translation_exists (&self) -> bool { self.value & 0b0000_0001_0000_0000_0000_0000_0000_0000 != 0 }
pub fn scale_format (&self) -> Chr0Format { f((self.value & 0b0000_0110_0000_0000_0000_0000_0000_0000) >> 25) }
pub fn rot_format (&self) -> Chr0Format { f((self.value & 0b0011_1000_0000_0000_0000_0000_0000_0000) >> 27) }
pub fn translation_format(&self) -> Chr0Format { f((self.value & 0b1100_0000_0000_0000_0000_0000_0000_0000) >> 30) }
}
fn f(value: u32) -> Chr0Format {
match value {
0 => Chr0Format::None,
1 => Chr0Format::Interpolated4,
2 => Chr0Format::Interpolated6,
3 => Chr0Format::Interpolated12,
4 => Chr0Format::Linear1,
5 => Chr0Format::Linear2,
6 => Chr0Format::Linear4,
_ => unreachable!(),
}
}
#[derive(Clone, Debug)]
pub enum Chr0Format {
None,
Interpolated4,
Interpolated6,
Interpolated12,
Linear1,
Linear2,
Linear4,
}
fn keyframe_holder(
child_data: FancySlice,
data_offset: &mut usize,
exists: bool,
isotropic: bool,
fixed_x: bool,
fixed_y: bool,
fixed_z: bool,
format: Chr0Format,
num_frames: u16,
) -> KeyframeHolder {
if !exists {
KeyframeHolder::None
} else if isotropic {
let keyframe = if fixed_z {
Keyframe::Fixed(child_data.f32_be(*data_offset))
} else {
let offset = child_data.u32_be(*data_offset);
keyframe(
child_data.relative_fancy_slice(offset as usize..),
&format,
num_frames,
)
};
*data_offset += 4;
KeyframeHolder::Isotropic(keyframe)
} else {
let x = if fixed_x {
Keyframe::Fixed(child_data.f32_be(*data_offset))
} else {
let offset = child_data.u32_be(*data_offset);
keyframe(
child_data.relative_fancy_slice(offset as usize..),
&format,
num_frames,
)
};
*data_offset += 4;
let y = if fixed_y {
Keyframe::Fixed(child_data.f32_be(*data_offset))
} else {
let offset = child_data.u32_be(*data_offset);
keyframe(
child_data.relative_fancy_slice(offset as usize..),
&format,
num_frames,
)
};
*data_offset += 4;
let z = if fixed_z {
Keyframe::Fixed(child_data.f32_be(*data_offset))
} else {
let offset = child_data.u32_be(*data_offset);
keyframe(
child_data.relative_fancy_slice(offset as usize..),
&format,
num_frames,
)
};
*data_offset += 4;
KeyframeHolder::Individual { x, y, z }
}
}
#[derive(Clone, Debug)]
pub enum KeyframeHolder {
Isotropic(Keyframe),
Individual {
x: Keyframe,
y: Keyframe,
z: Keyframe,
},
None,
}
impl KeyframeHolder {
pub fn get_value(&self, loop_value: bool, frame: i32, default: f32) -> Vector3<f32> {
match self {
KeyframeHolder::Isotropic(keyframe) => {
let value = keyframe.get_value(loop_value, frame);
Vector3::new(value, value, value)
}
KeyframeHolder::Individual { x, y, z } => Vector3::new(
x.get_value(loop_value, frame),
y.get_value(loop_value, frame),
z.get_value(loop_value, frame),
),
KeyframeHolder::None => Vector3::new(default, default, default),
}
}
}
#[derive(Clone, Debug)]
pub enum Keyframe {
Fixed(f32),
Interpolated4(Interpolated4Header),
Interpolated6(Interpolated6Header),
Interpolated12(Interpolated12Header),
Linear1(Linear1Header),
Linear2(Linear2Header),
Linear4(Vec<f32>),
}
impl Keyframe {
pub fn get_value(&self, loop_value: bool, frame: i32) -> f32 {
match self {
Keyframe::Fixed(value) => *value,
Keyframe::Interpolated4(header) => {
let children = header.children.iter().map(|child| InterpolatedNEntry {
value: header.base + header.step * child.step() as f32,
frame_index: child.frame_index() as i32,
tangent: child.tangent() as f32,
});
Keyframe::get_value_interpolated_n_entry(children, loop_value, frame)
}
Keyframe::Interpolated6(header) => {
let children = header.children.iter().map(|child| InterpolatedNEntry {
value: header.base + header.step * child.step as f32,
frame_index: child.frame_index(),
tangent: child.tangent() as f32,
});
Keyframe::get_value_interpolated_n_entry(children, loop_value, frame)
}
Keyframe::Interpolated12(header) => {
let children = header.children.iter().map(|child| InterpolatedNEntry {
value: child.value,
frame_index: child.frame_index as i32,
tangent: child.tangent,
});
Keyframe::get_value_interpolated_n_entry(children, loop_value, frame)
}
Keyframe::Linear1(header) => {
header.base + header.step as f32 * header.children_steps[frame as usize] as f32
}
Keyframe::Linear2(header) => {
header.base + header.step * header.children_steps[frame as usize] as f32
}
Keyframe::Linear4(values) => values[frame as usize],
}
}
fn get_value_interpolated_n_entry<I>(children: I, _loop_value: bool, frame: i32) -> f32
where
I: Iterator<Item = InterpolatedNEntry>,
{
let mut prev_prev: Option<InterpolatedNEntry> = None; let mut prev: Option<InterpolatedNEntry> = None; let mut next: Option<InterpolatedNEntry> = None; let mut next_next: Option<InterpolatedNEntry> = None;
for child in children {
if let Some(prev) = &prev {
if child.frame_index < prev.frame_index {
assert_eq!(child.frame_index, 0);
break;
}
}
if child.frame_index >= frame {
if next.is_none() {
next = Some(child.clone());
} else if next_next.is_none() {
next_next = Some(child.clone());
}
}
if child.frame_index <= frame {
if let Some(inner_prev) = prev {
prev = Some(child);
prev_prev = Some(inner_prev);
} else {
prev = Some(child)
}
}
}
let result = match (prev, next) {
(Some(prev), Some(next)) => {
let one_apart = next.frame_index == prev.frame_index + 1;
let prev_double = if let Some(prev_prev) = prev_prev {
prev_prev.frame_index >= 0 && prev_prev.frame_index == prev.frame_index - 1
} else {
false
};
let next_double = if let Some(next_next) = next_next {
next_next.frame_index >= 0 && next_next.frame_index == next.frame_index + 1
} else {
false
};
let double_value =
(next.value - prev.value) / (next.frame_index - prev.frame_index) as f32;
let prev_tangent = if one_apart || prev_double {
double_value
} else {
prev.tangent
};
let next_tangent = if one_apart || next_double {
double_value
} else {
next.tangent
};
let value_diff = next.value - prev.value;
let span = next.frame_index - prev.frame_index;
let offset = frame - prev.frame_index;
if offset == 0 {
prev.value
} else if offset == span {
next.value
} else {
let time = offset as f32 / span as f32;
let time_inv = time - 1.0;
prev.value
+ (offset as f32
* time_inv
* (time_inv * prev_tangent + time * next_tangent))
+ ((time * time) * (3.0 - 2.0 * time) * value_diff)
}
}
(Some(child), None) | (None, Some(child)) => child.value,
(None, None) => unreachable!(),
};
debug_assert!(result.is_finite());
result
}
}
const INTERPOLATED_4_HEADER_SIZE: usize = 0x10;
#[derive(Clone, Debug)]
pub struct Interpolated4Header {
pub entries: u16,
pub unk: u16,
pub frame_scale: f32,
pub step: f32,
pub base: f32,
pub children: Vec<Interpolated4Entry>,
}
const INTERPOLATED_4_ENTRY_SIZE: usize = 0x4;
#[derive(Clone, Debug)]
pub struct Interpolated4Entry {
pub data: u32,
}
#[rustfmt::skip]
impl Interpolated4Entry {
pub fn frame_index(&self) -> u8 { ((self.data & 0xFF00_0000) >> 24) as u8 }
pub fn step (&self) -> u16 { ((self.data & 0x00FF_F000) >> 12) as u16 }
#[allow(arithmetic_overflow)]
pub fn tangent (&self) -> f32 {
let signed_int = ((self.data as i32) << 20) >> 20;
signed_int as f32 / 32.0
}
}
const INTERPOLATED_6_HEADER_SIZE: usize = 0x10;
#[derive(Clone, Debug)]
pub struct Interpolated6Header {
pub num_frames: u16,
pub unk: u16,
pub frame_scale: f32,
pub step: f32,
pub base: f32,
pub children: Vec<Interpolated6Entry>,
}
const INTERPOLATED_6_ENTRY_SIZE: usize = 0x6;
#[derive(Clone, Debug)]
pub struct Interpolated6Entry {
frame_index: u16,
pub step: u16,
tangent: i16,
}
impl Interpolated6Entry {
pub fn frame_index(&self) -> i32 {
(self.frame_index >> 5) as i32
}
pub fn tangent(&self) -> f32 {
self.tangent as f32 / 256.0
}
}
const INTERPOLATED_12_HEADER_SIZE: usize = 0x8;
#[derive(Clone, Debug)]
pub struct Interpolated12Header {
pub num_frames: u16,
pub unk: u16,
pub frame_scale: f32,
pub children: Vec<Interpolated12Entry>,
}
const INTERPOLATED_12_ENTRY_SIZE: usize = 0xc;
#[derive(Clone, Debug)]
pub struct Interpolated12Entry {
pub frame_index: f32,
pub value: f32,
pub tangent: f32,
}
#[derive(Clone, Debug)]
pub struct InterpolatedNEntry {
pub frame_index: i32,
pub value: f32,
pub tangent: f32,
}
const LINEAR_1_HEADER_SIZE: usize = 0x8;
#[derive(Clone, Debug)]
pub struct Linear1Header {
pub step: f32,
pub base: f32,
pub children_steps: Vec<u8>,
}
const LINEAR_2_HEADER_SIZE: usize = 0x8;
#[derive(Clone, Debug)]
pub struct Linear2Header {
pub step: f32,
pub base: f32,
pub children_steps: Vec<u16>,
}
const LINEAR_2_ENTRY_SIZE: usize = 0x2;
const LINEAR_4_ENTRY_SIZE: usize = 0x4;
#[rustfmt::skip]
fn keyframe(data: FancySlice, format: &Chr0Format, num_frames: u16) -> Keyframe {
match format {
Chr0Format::Interpolated4 => {
let entries = data.u16_be(0x0);
let unk = data.u16_be(0x2);
let frame_scale = data.f32_be(0x4);
let step = data.f32_be(0x8);
let base = data.f32_be(0xc);
let mut children = vec!();
for i in 0..entries as usize {
let child_data = data.relative_fancy_slice(INTERPOLATED_4_HEADER_SIZE + INTERPOLATED_4_ENTRY_SIZE * i ..);
let data = child_data.u32_be(0);
children.push(Interpolated4Entry { data });
}
Keyframe::Interpolated4 (Interpolated4Header { entries, unk, frame_scale, step, base, children })
}
Chr0Format::Interpolated6 => {
let num_frames = data.u16_be(0x0);
let unk = data.u16_be(0x2);
let frame_scale = data.f32_be(0x4);
let step = data.f32_be(0x8);
let base = data.f32_be(0xc);
let mut children = vec!();
for i in 0..num_frames as usize {
let child_data = data.relative_fancy_slice(INTERPOLATED_6_HEADER_SIZE + INTERPOLATED_6_ENTRY_SIZE * i ..);
let frame_index = child_data.u16_be(0x0);
let step = child_data.u16_be(0x2);
let tangent = child_data.i16_be(0x4);
children.push(Interpolated6Entry { frame_index, step, tangent });
}
Keyframe::Interpolated6 (Interpolated6Header { num_frames, unk, frame_scale, step, base, children })
}
Chr0Format::Interpolated12 => {
let num_frames = data.u16_be(0x0);
let unk = data.u16_be(0x2);
let frame_scale = data.f32_be(0x4);
let mut children = vec!();
for i in 0..num_frames as usize {
let child_data = data.relative_fancy_slice(INTERPOLATED_12_HEADER_SIZE + INTERPOLATED_12_ENTRY_SIZE * i ..);
let frame_index = child_data.f32_be(0x0);
let value = child_data.f32_be(0x4);
let tangent = child_data.f32_be(0x8);
children.push(Interpolated12Entry { frame_index, value, tangent });
}
Keyframe::Interpolated12 (Interpolated12Header { num_frames, unk, frame_scale, children })
}
Chr0Format::Linear1 => {
let step = data.f32_be(0x0);
let base = data.f32_be(0x4);
let children_steps = data.relative_slice(LINEAR_1_HEADER_SIZE .. LINEAR_1_HEADER_SIZE + num_frames as usize).to_vec();
Keyframe::Linear1 (Linear1Header { step, base, children_steps })
}
Chr0Format::Linear2 => {
let step = data.f32_be(0x0);
let base = data.f32_be(0x4);
let mut children_steps = vec!();
for i in 0..num_frames as usize {
children_steps.push(data.u16_be(LINEAR_2_HEADER_SIZE + LINEAR_2_ENTRY_SIZE * i));
}
Keyframe::Linear2 (Linear2Header { step, base, children_steps })
}
Chr0Format::Linear4 => {
let mut values = vec!();
for i in 0..num_frames as usize {
values.push(data.f32_be(LINEAR_4_ENTRY_SIZE * i));
}
Keyframe::Linear4 (values)
}
Chr0Format::None => panic!("this function should not be called with a format of None"),
}
}