use super::transforms::{LinearInterpolation, Rotation, Scale, Transform, Translation}; use anyhow::Result; use utilities::prelude::cgmath::{Matrix4, Quaternion, Vector3, VectorSpace, Zero}; use gltf; use std::cmp::Ordering; use std::time::Duration; #[derive(Clone, Debug)] pub struct Channel { translations: Vec, rotations: Vec, scales: Vec, } impl Channel { pub fn new( gltf_channel: &gltf::animation::Channel<'_>, buffers: &Vec, outputs: Vec, ) -> Result { let reader = gltf_channel.reader(|buffer| Some(&buffers[buffer.index()])); let mut translations = Vec::new(); let mut rotations = Vec::new(); let mut scales = Vec::new(); match reader.read_inputs() { Some(inputs) => { for (i, time) in inputs.enumerate() { match outputs[i] { Transform::Translation(translation) => translations .push(Translation::new(Duration::from_secs_f32(time), translation)), Transform::Rotation(rotation) => { rotations.push(Rotation::new(Duration::from_secs_f32(time), rotation)) } Transform::Scale(scale) => { scales.push(Scale::new(Duration::from_secs_f32(time), scale)) } } } } None => return Err(anyhow::Error::msg("Gltf: Missing Input from Channel")), }; Ok(Channel { translations, rotations, scales, }) } pub fn update( &mut self, gltf_channel: &gltf::animation::Channel<'_>, buffers: &Vec, outputs: Vec, ) -> Result<()> { let reader = gltf_channel.reader(|buffer| Some(&buffers[buffer.index()])); match reader.read_inputs() { Some(inputs) => { for (time, transform) in inputs.zip(outputs.into_iter()) { let time = Duration::from_secs_f32(time); match transform { Transform::Translation(translation) => { // check that time is unique if cfg!(debug_assertions) { for translation in self.translations.iter() { assert!(translation.time() != time); } } self.translations.push(Translation::new(time, translation)); } Transform::Rotation(rotation) => { // check that time is unique if cfg!(debug_assertions) { for rotation in self.rotations.iter() { assert!(rotation.time() != time); } } self.rotations.push(Rotation::new(time, rotation)); } Transform::Scale(scale) => { // check that time is unique if cfg!(debug_assertions) { for scale in self.scales.iter() { assert!(scale.time() != time); } } self.scales.push(Scale::new(time, scale)); } } } } None => return Err(anyhow::Error::msg("Gltf: Missing Input from Channel")), }; Ok(()) } pub fn compress(&mut self) { self.translations = Self::compress_transform(&self.translations); self.rotations = Self::compress_transform(&self.rotations); self.scales = Self::compress_transform(&self.scales); } #[inline] fn compress_transform + Clone, K: PartialEq>( transforms: &Vec, ) -> Vec { let mut current: Option<&T> = None; let mut result: Vec = Vec::new(); for transform in transforms { match current { Some(current_transform) => { if transform.almost_equal(current_transform) { current = Some(transform); } else { result.push(transform.clone()); current = None; } } None => { result.push(transform.clone()); current = Some(transform); } } } if result.is_empty() { if let Some(transform) = current { result.push(transform.clone()); } } result } pub fn sort_by_time(&mut self) { self.translations .sort_by(|a, b| a.time().partial_cmp(&b.time()).unwrap_or(Ordering::Equal)); self.rotations .sort_by(|a, b| a.time().partial_cmp(&b.time()).unwrap_or(Ordering::Equal)); self.scales .sort_by(|a, b| a.time().partial_cmp(&b.time()).unwrap_or(Ordering::Equal)); } pub fn duration(&self) -> Duration { let translation_duration = match self.translations.last() { Some(translation) => translation.time(), None => Duration::from_secs(0), }; let rotation_duration = match self.rotations.last() { Some(rotation) => rotation.time(), None => Duration::from_secs(0), }; let scale_duration = match self.scales.last() { Some(scale) => scale.time(), None => Duration::from_secs(0), }; use std::cmp::max; max(max(translation_duration, rotation_duration), scale_duration) } pub fn transform(&self, time: Duration) -> InterpolatedTransforms { InterpolatedTransforms { translation: Self::interpolate(&self.translations, time), rotation: Self::interpolate(&self.rotations, time), scale: Self::interpolate(&self.scales, time), } } #[inline] fn interpolate( transforms: &Vec>, now: Duration, ) -> K { if transforms.is_empty() { return K::zero(); } else if transforms.len() == 1 { return transforms[0].to_inner(); } match transforms .iter() .enumerate() .find_map(|(index, transform)| { if transform.time() >= now { Some((index, transform)) } else { None } }) { Some((index, transform)) => { if index == 0 { transform.to_inner() } else { let previous_transform = &transforms[index - 1]; transform .linear_interpolation(previous_transform, now) .to_inner() } } None => K::zero(), } } } #[derive(Clone, Debug)] pub struct InterpolatedTransforms { pub(crate) translation: Vector3, pub(crate) rotation: Quaternion, pub(crate) scale: Vector3, } impl InterpolatedTransforms { pub fn interpolate(self, other: InterpolatedTransforms, factor: f32) -> InterpolatedTransforms { InterpolatedTransforms { translation: self.translation.lerp(other.translation, factor), rotation: self.rotation.lerp(other.rotation, factor), scale: self.scale.lerp(other.scale, factor), } } pub fn collapse(self) -> Matrix4 { Self::convert_translation(self.translation) * Self::convert_rotation(self.rotation) * Self::convert_scale(self.scale) } fn convert_translation(translation: Vector3) -> Matrix4 { Matrix4::from_translation(translation) } fn convert_rotation(rotation: Quaternion) -> Matrix4 { Matrix4::from(rotation) } fn convert_scale(scale: Vector3) -> Matrix4 { Matrix4::from_nonuniform_scale(scale.x, scale.y, scale.z) } }