use std::io::Read;
use anyhow::{Result, bail};
use crate::core::class_index::ClassIndex;
use crate::core::synched_object::SynchedObjectData;
use crate::core::uoid::{Uoid, read_key_uoid};
use crate::resource::prp::PlasmaRead;
use super::controller::Controller;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum BodyUsage {
Unknown = 0,
Upper = 1,
Full = 2,
Lower = 3,
}
impl BodyUsage {
pub fn from_u8(v: u8) -> Self {
match v {
1 => Self::Upper,
2 => Self::Full,
3 => Self::Lower,
_ => Self::Unknown,
}
}
}
#[derive(Debug, Clone)]
pub struct AffineParts {
pub translation: [f32; 3], pub rotation: [f32; 4], pub stretch_rotation: [f32; 4], pub scale: [f32; 3], pub det_sign: f32, }
impl AffineParts {
pub fn read(reader: &mut impl Read) -> Result<Self> {
Ok(Self {
translation: [reader.read_f32()?, reader.read_f32()?, reader.read_f32()?],
rotation: [reader.read_f32()?, reader.read_f32()?, reader.read_f32()?, reader.read_f32()?],
stretch_rotation: [reader.read_f32()?, reader.read_f32()?, reader.read_f32()?, reader.read_f32()?],
scale: [reader.read_f32()?, reader.read_f32()?, reader.read_f32()?],
det_sign: reader.read_f32()?,
})
}
}
#[derive(Debug, Clone)]
pub enum ChannelData {
MatrixController {
controller: Option<Controller>,
initial_pose: AffineParts,
},
MatrixConstant {
pose: AffineParts,
},
ScalarController(Option<Controller>),
ScalarConstant(f32),
PointController(Option<Controller>),
PointConstant([f32; 3]),
QuatConstant([f32; 4]),
}
#[derive(Debug, Clone)]
pub struct AnimApplicator {
pub applicator_class: u16,
pub channel_name: String,
pub enabled: bool,
pub channel_class: u16,
pub channel_name_from_channel: String,
pub channel_data: ChannelData,
}
impl AnimApplicator {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let app_class = reader.read_u16()?;
let (channel_name, enabled) = if app_class != 0x8000 {
let enabled = reader.read_u8()? != 0;
let name = reader.read_safe_string()?;
(name, enabled)
} else {
(String::new(), false)
};
let chan_class = reader.read_u16()?;
if chan_class == 0x8000 {
return Ok(Self {
applicator_class: app_class,
channel_name,
enabled,
channel_class: 0x8000,
channel_name_from_channel: String::new(),
channel_data: ChannelData::ScalarConstant(0.0),
});
}
let channel_name_from_channel = reader.read_safe_string()?;
let channel_data = match chan_class {
ClassIndex::PL_MATRIX_CONTROLLER_CHANNEL => {
let controller = Controller::read_creatable(reader)?;
let initial_pose = AffineParts::read(reader)?;
ChannelData::MatrixController { controller, initial_pose }
}
ClassIndex::PL_MATRIX_CONSTANT => {
let pose = AffineParts::read(reader)?;
ChannelData::MatrixConstant { pose }
}
ClassIndex::PL_SCALAR_CONTROLLER_CHANNEL => {
let controller = Controller::read_creatable(reader)?;
ChannelData::ScalarController(controller)
}
ClassIndex::PL_SCALAR_CONSTANT => {
let value = reader.read_f32()?;
ChannelData::ScalarConstant(value)
}
ClassIndex::PL_POINT_CONTROLLER_CHANNEL => {
let controller = Controller::read_creatable(reader)?;
ChannelData::PointController(controller)
}
ClassIndex::PL_POINT_CONSTANT => {
let value = [reader.read_f32()?, reader.read_f32()?, reader.read_f32()?];
ChannelData::PointConstant(value)
}
ClassIndex::PL_QUAT_CONSTANT => {
let value = [reader.read_f32()?, reader.read_f32()?, reader.read_f32()?, reader.read_f32()?];
ChannelData::QuatConstant(value)
}
_ => {
bail!("Unknown channel class 0x{:04X} ({}) for applicator '{}'",
chan_class,
ClassIndex::class_name(chan_class),
channel_name);
}
};
Ok(Self {
applicator_class: app_class,
channel_name,
enabled,
channel_class: chan_class,
channel_name_from_channel,
channel_data,
})
}
}
#[derive(Debug, Clone)]
pub struct AnimMarker {
pub name: String,
pub time: f32,
}
#[derive(Debug, Clone)]
pub struct AnimLoop {
pub name: String,
pub begin: f32,
pub end: f32,
}
#[derive(Debug, Clone)]
pub struct AGAnimData {
pub self_key: Option<Uoid>,
pub synched: SynchedObjectData,
pub name: String,
pub start: f32,
pub end: f32,
pub applicators: Vec<AnimApplicator>,
}
impl AGAnimData {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let self_key = read_key_uoid(reader)?;
let synched = SynchedObjectData::read(reader)?;
let name = reader.read_safe_string()?;
let start = reader.read_f32()?;
let end = reader.read_f32()?;
let num_apps = reader.read_u32()?;
let mut applicators = Vec::with_capacity(num_apps as usize);
for _ in 0..num_apps {
applicators.push(AnimApplicator::read(reader)?);
}
Ok(Self {
self_key,
synched,
name,
start,
end,
applicators,
})
}
}
#[derive(Debug, Clone)]
pub struct ATCAnimData {
pub base: AGAnimData,
pub initial: f32,
pub auto_start: bool,
pub loop_start: f32,
pub loop_end: f32,
pub do_loop: bool,
pub ease_in_type: u8,
pub ease_in_min: f32,
pub ease_in_max: f32,
pub ease_in_length: f32,
pub ease_out_type: u8,
pub ease_out_min: f32,
pub ease_out_max: f32,
pub ease_out_length: f32,
pub markers: Vec<AnimMarker>,
pub loops: Vec<AnimLoop>,
pub stop_points: Vec<f32>,
}
impl ATCAnimData {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = AGAnimData::read(reader)?;
let initial = reader.read_f32()?;
let auto_start = reader.read_u8()? != 0;
let loop_start = reader.read_f32()?;
let loop_end = reader.read_f32()?;
let do_loop = reader.read_u8()? != 0;
let ease_in_type = reader.read_u8()?;
let ease_in_min = reader.read_f32()?;
let ease_in_max = reader.read_f32()?;
let ease_in_length = reader.read_f32()?;
let ease_out_type = reader.read_u8()?;
let ease_out_min = reader.read_f32()?;
let ease_out_max = reader.read_f32()?;
let ease_out_length = reader.read_f32()?;
let num_markers = reader.read_u32()?;
let mut markers = Vec::with_capacity(num_markers as usize);
for _ in 0..num_markers {
markers.push(AnimMarker {
name: reader.read_safe_string()?,
time: reader.read_f32()?,
});
}
let num_loops = reader.read_u32()?;
let mut loops = Vec::with_capacity(num_loops as usize);
for _ in 0..num_loops {
loops.push(AnimLoop {
name: reader.read_safe_string()?,
begin: reader.read_f32()?,
end: reader.read_f32()?,
});
}
let num_stop_points = reader.read_u32()?;
let mut stop_points = Vec::with_capacity(num_stop_points as usize);
for _ in 0..num_stop_points {
stop_points.push(reader.read_f32()?);
}
Ok(Self {
base,
initial,
auto_start,
loop_start,
loop_end,
do_loop,
ease_in_type,
ease_in_min,
ease_in_max,
ease_in_length,
ease_out_type,
ease_out_min,
ease_out_max,
ease_out_length,
markers,
loops,
stop_points,
})
}
}
#[derive(Debug, Clone)]
pub struct EmoteAnimData {
pub base: ATCAnimData,
pub fade_in: f32,
pub fade_out: f32,
pub body_usage: BodyUsage,
}
impl EmoteAnimData {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = ATCAnimData::read(reader)?;
let fade_in = reader.read_f32()?;
let fade_out = reader.read_f32()?;
let body_usage = BodyUsage::from_u8(reader.read_u8()?);
Ok(Self {
base,
fade_in,
fade_out,
body_usage,
})
}
}
#[derive(Debug, Clone)]
pub struct AgeGlobalAnimData {
pub base: AGAnimData,
pub global_var_name: String,
}
impl AgeGlobalAnimData {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = AGAnimData::read(reader)?;
let global_var_name = reader.read_safe_string()?;
Ok(Self {
base,
global_var_name,
})
}
}