use crate::{
asset::{
self,
compressed::{
evaluate::{JumpFrameU16, JumpFrameU32},
frame::Frame,
},
error_metric::ErrorMetric,
},
AssetParseError::{InvalidField, InvalidFileVersion, MissingData},
Compressed,
};
use bitflags::bitflags;
use std::io::{Read, Seek, SeekFrom};
use std::mem::size_of;
bitflags! {
#[derive(Clone, Debug)]
pub struct AnimationFlags: u32 {
const Unk1 = 1 << 0;
const Unk2 = 1 << 1;
const UseKeyframeParametrization = 1 << 2;
}
}
impl Compressed {
pub fn from_reader<R: Read + Seek + ?Sized>(reader: &mut R) -> asset::Result<Self> {
use byteorder::{ReadBytesExt as _, LE};
use ltk_io_ext::{
untrusted::{self, UntrustedCapacity as _},
ReaderExt as _,
};
let _magic = reader.read_u64::<LE>()?;
let version = reader.read_u32::<LE>()?;
if version != 1 && version != 2 && version != 3 {
return Err(InvalidFileVersion(version));
}
let _resource_size = reader.read_u32::<LE>()?;
let _format_token = reader.read_u32::<LE>()?;
let flags = reader.read_u32::<LE>()?;
let flags = AnimationFlags::from_bits(flags)
.ok_or_else(|| InvalidField("flags", flags.to_string()))?;
let joint_count = reader.read_u32::<LE>()?;
let frame_count = reader.read_u32::<LE>()?;
let jump_cache_count = reader.read_i32::<LE>()?;
let jump_cache_count = u32::try_from(jump_cache_count)
.map_err(|_| InvalidField("jump cache count", jump_cache_count.to_string()))?;
let duration = reader.read_f32::<LE>()?;
if !duration.is_finite() || duration < 0.0 {
return Err(InvalidField("duration", duration.to_string()));
}
let fps = reader.read_f32::<LE>()?;
let rotation_error_metric = ErrorMetric::from_reader(reader)?;
let translation_error_metric = ErrorMetric::from_reader(reader)?;
let scale_error_metric = ErrorMetric::from_reader(reader)?;
let translation_min = reader.read_vec3::<LE>()?;
let translation_max = reader.read_vec3::<LE>()?;
let scale_min = reader.read_vec3::<LE>()?;
let scale_max = reader.read_vec3::<LE>()?;
let frames_off = reader.read_i32::<LE>()?;
if frames_off <= 0 {
return Err(MissingData("frame"));
}
let jump_caches_off = reader.read_i32::<LE>()?;
if jump_caches_off <= 0 {
return Err(MissingData("jump cache"));
}
let joint_name_hashes_off = reader.read_i32::<LE>()?;
if joint_name_hashes_off <= 0 {
return Err(MissingData("joint"));
}
reader.seek(SeekFrom::Start(joint_name_hashes_off as u64 + 12))?;
let mut joints = Vec::with_untrusted_capacity(joint_count as usize);
for _ in 0..joint_count {
joints.push(reader.read_u32::<LE>()?);
}
reader.seek(SeekFrom::Start(frames_off as u64 + 12))?;
let mut frames = Vec::with_untrusted_capacity(frame_count as usize);
for _ in 0..frame_count {
let mut bytes = [0; Frame::SIZE];
reader.read_exact(&mut bytes)?;
let frame = Frame::from_bytes(bytes)?;
if usize::from(frame.joint_id()) >= joints.len() {
return Err(InvalidField("frame joint id", frame.joint_id().to_string()));
}
frames.push(frame);
}
reader.seek(SeekFrom::Start(jump_caches_off as u64 + 12))?;
let jump_frame_size = if frame_count < 0x10001 {
size_of::<JumpFrameU16>()
} else {
size_of::<JumpFrameU32>()
};
let jump_caches_len = (jump_cache_count as usize)
.checked_mul(joint_count as usize)
.and_then(|jump_frames| jump_frames.checked_mul(jump_frame_size))
.ok_or_else(|| InvalidField("jump cache count", jump_cache_count.to_string()))?;
let jump_caches = untrusted::read_bytes(reader, jump_caches_len)?;
Ok(Self {
flags,
duration,
fps,
rotation_error_metric,
translation_error_metric,
scale_error_metric,
translation_min,
translation_max,
scale_min,
scale_max,
jump_cache_count: jump_cache_count as usize,
frames,
jump_caches,
joints,
})
}
}