diff --git a/src/animation.rs b/src/animation.rs index cf6efa6..9ddf0d2 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -3,13 +3,14 @@ //! use glam::{Quat, Vec3, Vec4}; +use std::alloc::{self, Layout}; use std::io::Read; use std::simd::prelude::*; use std::simd::*; use std::{mem, slice}; use crate::archive::{Archive, ArchiveRead}; -use crate::base::OzzError; +use crate::base::{align_ptr, align_usize, OzzError}; use crate::math::{f16_to_f32, fx4, ix4, simd_f16_to_f32, SoaQuat, SoaVec3, ONE, ZERO}; /// Float3 key for `Animation` track. @@ -165,68 +166,6 @@ impl ArchiveRead for QuaternionKey { } } -/// Animation keyframes control structure. -#[derive(Debug, Default)] -#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct KeyframesCtrl { - ratios: Vec, - previouses: Vec, - iframe_entries: Vec, - iframe_desc: Vec, - iframe_interval: f32, -} - -impl KeyframesCtrl { - pub fn new( - ratios: Vec, - previouses: Vec, - iframe_entries: Vec, - iframe_desc: Vec, - iframe_interval: f32, - ) -> KeyframesCtrl { - return KeyframesCtrl { - ratios, - previouses, - iframe_entries, - iframe_desc, - iframe_interval, - }; - } - - #[inline] - pub fn ratios_u8(&self) -> &[u8] { - return &self.ratios; - } - - #[inline] - pub fn ratios_u16(&self) -> &[u16] { - let data = self.ratios.as_ptr() as *const u16; - let len = self.ratios.len() / 2; - return unsafe { slice::from_raw_parts(data, len) }; - } - - #[inline] - pub fn previouses(&self) -> &[u16] { - return &self.previouses; - } - - #[inline] - pub fn iframe_entries(&self) -> &[u8] { - return &self.iframe_entries; - } - - #[inline] - pub fn iframe_desc(&self) -> &[u32] { - return &self.iframe_desc; - } - - #[inline] - pub fn iframe_interval(&self) -> f32 { - return self.iframe_interval; - } -} - /// /// Defines a runtime skeletal animation clip. /// @@ -240,41 +179,124 @@ impl KeyframesCtrl { /// coherency when sampling the animation, Keyframes in this array are sorted by /// time, then by track number. /// -#[derive(Debug, Default)] -#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug)] +// #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +// #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Animation { + size: usize, duration: f32, - num_tracks: usize, + num_tracks: u32, name: String, - timepoints: Vec, - translations_ctrl: KeyframesCtrl, - rotations_ctrl: KeyframesCtrl, - scales_ctrl: KeyframesCtrl, - translations: Vec, - rotations: Vec, - scales: Vec, + timepoints: *mut f32, + timepoints_count: u32, + + translations: *mut Float3Key, + translations_count: u32, + t_ratios: *mut u16, + t_previouses: *mut u16, + t_iframe_interval: f32, + t_iframe_entries: *mut u8, + t_iframe_entries_count: u32, + t_iframe_desc: *mut u32, + t_iframe_desc_count: u32, + + rotations: *mut QuaternionKey, + rotations_count: u32, + r_ratios: *mut u16, + r_previouses: *mut u16, + r_iframe_interval: f32, + r_iframe_entries: *mut u8, + r_iframe_entries_count: u32, + r_iframe_desc: *mut u32, + r_iframe_desc_count: u32, + + scales: *mut Float3Key, + scales_count: u32, + s_ratios: *mut u16, + s_previouses: *mut u16, + s_iframe_interval: f32, + s_iframe_entries: *mut u8, + s_iframe_entries_count: u32, + s_iframe_desc: *mut u32, + s_iframe_desc_count: u32, +} + +impl Drop for Animation { + fn drop(&mut self) { + if !self.timepoints.is_null() { + unsafe { + let layout = Layout::from_size_align_unchecked(self.size, mem::size_of::()); + alloc::dealloc(self.timepoints as *mut u8, layout); + } + self.timepoints = std::ptr::null_mut(); + self.translations = std::ptr::null_mut(); + self.t_ratios = std::ptr::null_mut(); + self.t_previouses = std::ptr::null_mut(); + self.t_iframe_entries = std::ptr::null_mut(); + self.t_iframe_desc = std::ptr::null_mut(); + self.rotations = std::ptr::null_mut(); + self.r_ratios = std::ptr::null_mut(); + self.r_previouses = std::ptr::null_mut(); + self.r_iframe_entries = std::ptr::null_mut(); + self.r_iframe_desc = std::ptr::null_mut(); + self.scales = std::ptr::null_mut(); + self.s_ratios = std::ptr::null_mut(); + self.s_previouses = std::ptr::null_mut(); + self.s_iframe_entries = std::ptr::null_mut(); + self.s_iframe_desc = std::ptr::null_mut(); + } + } } /// Animation meta in `Archive`. -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct AnimationMeta { pub version: u32, pub duration: f32, pub num_tracks: u32, pub name: String, pub timepoints_count: u32, - pub translation_count: u32, - pub rotation_count: u32, - pub scale_count: u32, + pub translations_count: u32, pub t_iframe_entries_count: u32, pub t_iframe_desc_count: u32, + pub rotations_count: u32, pub r_iframe_entries_count: u32, pub r_iframe_desc_count: u32, + pub scales_count: u32, pub s_iframe_entries_count: u32, pub s_iframe_desc_count: u32, } +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub(crate) struct AnimationRaw { + pub duration: f32, + pub num_tracks: u32, + pub name: String, + pub timepoints: Vec, + + pub translations: Vec, + pub t_ratios: Vec, + pub t_previouses: Vec, + pub t_iframe_interval: f32, + pub t_iframe_entries: Vec, + pub t_iframe_desc: Vec, + + pub rotations: Vec, + pub r_ratios: Vec, + pub r_previouses: Vec, + pub r_iframe_interval: f32, + pub r_iframe_entries: Vec, + pub r_iframe_desc: Vec, + + pub scales: Vec, + pub s_ratios: Vec, + pub s_previouses: Vec, + pub s_iframe_interval: f32, + pub s_iframe_entries: Vec, + pub s_iframe_desc: Vec, +} + impl Animation { /// `Animation` resource file tag for `Archive`. #[inline] @@ -288,33 +310,6 @@ impl Animation { return 7; } - #[cfg(test)] - pub(crate) fn from_raw( - duration: f32, - num_tracks: usize, - name: String, - timepoints: Vec, - translations_ctrl: KeyframesCtrl, - rotations_ctrl: KeyframesCtrl, - scales_ctrl: KeyframesCtrl, - translations: Vec, - rotations: Vec, - scales: Vec, - ) -> Animation { - return Animation { - duration, - num_tracks, - name, - timepoints, - translations_ctrl, - rotations_ctrl, - scales_ctrl, - translations, - rotations, - scales, - }; - } - /// Reads an `AnimationMeta` from an `Archive`. pub fn read_meta(archive: &mut Archive) -> Result { if archive.tag() != Self::tag() { @@ -328,9 +323,9 @@ impl Animation { let num_tracks: u32 = archive.read()?; let name_len: u32 = archive.read()?; let timepoints_count: u32 = archive.read()?; - let translation_count: u32 = archive.read()?; - let rotation_count: u32 = archive.read()?; - let scale_count: u32 = archive.read()?; + let translations_count: u32 = archive.read()?; + let rotations_count: u32 = archive.read()?; + let scales_count: u32 = archive.read()?; let t_iframe_entries_count: u32 = archive.read()?; let t_iframe_desc_count: u32 = archive.read()?; let r_iframe_entries_count: u32 = archive.read()?; @@ -350,13 +345,13 @@ impl Animation { num_tracks, name, timepoints_count, - translation_count, - rotation_count, - scale_count, + translations_count, t_iframe_entries_count, t_iframe_desc_count, + rotations_count, r_iframe_entries_count, r_iframe_desc_count, + scales_count, s_iframe_entries_count, s_iframe_desc_count, }); @@ -365,46 +360,51 @@ impl Animation { /// Reads an `Animation` from an `Archive`. pub fn from_archive(archive: &mut Archive) -> Result { let meta = Animation::read_meta(archive)?; + let mut animation = Animation::new(meta); - let timepoints: Vec = archive.read_vec(meta.timepoints_count as usize)?; - let sizeof_ratio = if timepoints.len() <= u8::MAX as usize { 1 } else { 2 }; - let translations_ctrl = KeyframesCtrl { - ratios: archive.read_vec((meta.translation_count * sizeof_ratio) as usize)?, - previouses: archive.read_vec(meta.translation_count as usize)?, - iframe_entries: archive.read_vec(meta.t_iframe_entries_count as usize)?, - iframe_desc: archive.read_vec(meta.t_iframe_desc_count as usize)?, - iframe_interval: archive.read()?, - }; - let translations: Vec = archive.read_vec(meta.translation_count as usize)?; - let rotations_ctrl = KeyframesCtrl { - ratios: archive.read_vec((meta.rotation_count * sizeof_ratio) as usize)?, - previouses: archive.read_vec(meta.rotation_count as usize)?, - iframe_entries: archive.read_vec(meta.r_iframe_entries_count as usize)?, - iframe_desc: archive.read_vec(meta.r_iframe_desc_count as usize)?, - iframe_interval: archive.read()?, - }; - let rotations: Vec = archive.read_vec(meta.rotation_count as usize)?; - let scales_ctrl = KeyframesCtrl { - ratios: archive.read_vec((meta.scale_count * sizeof_ratio) as usize)?, - previouses: archive.read_vec(meta.scale_count as usize)?, - iframe_entries: archive.read_vec(meta.s_iframe_entries_count as usize)?, - iframe_desc: archive.read_vec(meta.s_iframe_desc_count as usize)?, - iframe_interval: archive.read()?, - }; - let scales: Vec = archive.read_vec(meta.scale_count as usize)?; + archive.read_slice(animation.timepoints_mut())?; + let is_ratio_u8 = animation.timepoints().len() <= (u8::MAX as usize); - return Ok(Animation { - duration: meta.duration, - num_tracks: meta.num_tracks as usize, - name: meta.name, - timepoints, - translations, - rotations, - scales, - translations_ctrl, - rotations_ctrl, - scales_ctrl, - }); + if is_ratio_u8 { + for i in 0..animation.t_ratios().len() { + animation.t_ratios_mut()[i] = archive.read::()? as u16; + } + } else { + archive.read_slice(animation.t_ratios_mut())?; + } + archive.read_slice(animation.t_previouses_mut())?; + archive.read_slice(animation.t_iframe_entries_mut())?; + archive.read_slice(animation.t_iframe_desc_mut())?; + animation.t_iframe_interval = archive.read()?; + archive.read_slice(animation.translations_mut())?; + + if is_ratio_u8 { + for i in 0..animation.r_ratios().len() { + animation.r_ratios_mut()[i] = archive.read::()? as u16; + } + } else { + archive.read_slice(animation.r_ratios_mut())?; + } + archive.read_slice(animation.r_previouses_mut())?; + archive.read_slice(animation.r_iframe_entries_mut())?; + archive.read_slice(animation.r_iframe_desc_mut())?; + animation.r_iframe_interval = archive.read()?; + archive.read_slice(animation.rotations_mut())?; + + if is_ratio_u8 { + for i in 0..animation.s_ratios().len() { + animation.s_ratios_mut()[i] = archive.read::()? as u16; + } + } else { + archive.read_slice(animation.s_ratios_mut())?; + } + archive.read_slice(animation.s_previouses_mut())?; + archive.read_slice(animation.s_iframe_entries_mut())?; + archive.read_slice(animation.s_iframe_desc_mut())?; + animation.s_iframe_interval = archive.read()?; + archive.read_slice(animation.scales_mut())?; + + return Ok(animation); } /// Reads an `Animation` from a file path. @@ -420,6 +420,201 @@ impl Animation { let mut archive = Archive::from_path(path)?; return Animation::from_archive(&mut archive); } + + pub(crate) fn from_raw(raw: &AnimationRaw) -> Animation { + let meta = AnimationMeta { + version: Animation::version(), + duration: raw.duration, + num_tracks: raw.num_tracks as u32, + name: raw.name.clone(), + timepoints_count: raw.timepoints.len() as u32, + translations_count: raw.translations.len() as u32, + t_iframe_entries_count: raw.t_iframe_entries.len() as u32, + t_iframe_desc_count: raw.t_iframe_desc.len() as u32, + rotations_count: raw.rotations.len() as u32, + r_iframe_entries_count: raw.r_iframe_entries.len() as u32, + r_iframe_desc_count: raw.r_iframe_desc.len() as u32, + scales_count: raw.scales.len() as u32, + s_iframe_entries_count: raw.s_iframe_entries.len() as u32, + s_iframe_desc_count: raw.s_iframe_desc.len() as u32, + }; + let mut animation = Animation::new(meta); + animation.timepoints_mut().copy_from_slice(&raw.timepoints); + + animation.translations_mut().copy_from_slice(&raw.translations); + animation.t_ratios_mut().copy_from_slice(&raw.t_ratios); + animation.t_previouses_mut().copy_from_slice(&raw.t_previouses); + animation.t_iframe_interval = raw.t_iframe_interval; + animation.t_iframe_entries_mut().copy_from_slice(&raw.t_iframe_entries); + animation.t_iframe_desc_mut().copy_from_slice(&raw.t_iframe_desc); + + animation.rotations_mut().copy_from_slice(&raw.rotations); + animation.r_ratios_mut().copy_from_slice(&raw.r_ratios); + animation.r_previouses_mut().copy_from_slice(&raw.r_previouses); + animation.r_iframe_interval = raw.r_iframe_interval; + animation.r_iframe_entries_mut().copy_from_slice(&raw.r_iframe_entries); + animation.r_iframe_desc_mut().copy_from_slice(&raw.r_iframe_desc); + + animation.scales_mut().copy_from_slice(&raw.scales); + animation.s_ratios_mut().copy_from_slice(&raw.s_ratios); + animation.s_previouses_mut().copy_from_slice(&raw.s_previouses); + animation.s_iframe_interval = raw.s_iframe_interval; + animation.s_iframe_entries_mut().copy_from_slice(&raw.s_iframe_entries); + animation.s_iframe_desc_mut().copy_from_slice(&raw.s_iframe_desc); + return animation; + } + + pub(crate) fn to_raw(&self) -> AnimationRaw { + return AnimationRaw { + duration: self.duration, + num_tracks: self.num_tracks, + name: self.name.clone(), + timepoints: self.timepoints().to_vec(), + + translations: self.translations().to_vec(), + t_ratios: self.t_ratios().to_vec(), + t_previouses: self.t_previouses().to_vec(), + t_iframe_interval: self.t_iframe_interval, + t_iframe_entries: self.t_iframe_entries().to_vec(), + t_iframe_desc: self.t_iframe_desc().to_vec(), + + rotations: self.rotations().to_vec(), + r_ratios: self.r_ratios().to_vec(), + r_previouses: self.r_previouses().to_vec(), + r_iframe_interval: self.r_iframe_interval, + r_iframe_entries: self.r_iframe_entries().to_vec(), + r_iframe_desc: self.r_iframe_desc().to_vec(), + + scales: self.scales().to_vec(), + s_ratios: self.s_ratios().to_vec(), + s_previouses: self.s_previouses().to_vec(), + s_iframe_interval: self.s_iframe_interval, + s_iframe_entries: self.s_iframe_entries().to_vec(), + s_iframe_desc: self.s_iframe_desc().to_vec(), + }; + } + + fn new(meta: AnimationMeta) -> Animation { + let mut animation = Animation { + size: 0, + duration: meta.duration, + num_tracks: meta.num_tracks, + name: meta.name, + timepoints: std::ptr::null_mut(), + timepoints_count: meta.timepoints_count, + + translations: std::ptr::null_mut(), + translations_count: meta.translations_count, + t_ratios: std::ptr::null_mut(), + t_previouses: std::ptr::null_mut(), + t_iframe_interval: 0.0, + t_iframe_entries: std::ptr::null_mut(), + t_iframe_entries_count: meta.t_iframe_entries_count, + t_iframe_desc: std::ptr::null_mut(), + t_iframe_desc_count: meta.t_iframe_desc_count, + + rotations: std::ptr::null_mut(), + rotations_count: meta.rotations_count, + r_ratios: std::ptr::null_mut(), + r_previouses: std::ptr::null_mut(), + r_iframe_interval: 0.0, + r_iframe_entries: std::ptr::null_mut(), + r_iframe_entries_count: meta.r_iframe_entries_count, + r_iframe_desc: std::ptr::null_mut(), + r_iframe_desc_count: meta.r_iframe_desc_count, + + scales: std::ptr::null_mut(), + scales_count: meta.scales_count, + s_ratios: std::ptr::null_mut(), + s_previouses: std::ptr::null_mut(), + s_iframe_interval: 0.0, + s_iframe_entries: std::ptr::null_mut(), + s_iframe_entries_count: meta.s_iframe_entries_count, + s_iframe_desc: std::ptr::null_mut(), + s_iframe_desc_count: meta.s_iframe_desc_count, + }; + + const ALIGN: usize = mem::align_of::(); + animation.size = (animation.timepoints_count as usize) * mem::size_of::(); + + animation.size += animation.translations_count as usize * mem::size_of::() + // translations + animation.translations_count as usize * mem::size_of::() + // ratios + animation.translations_count as usize * mem::size_of::() + // previouses + animation.t_iframe_entries_count as usize * mem::size_of::(); // t_iframe_entries + animation.size = align_usize(animation.size, ALIGN); + animation.size += animation.t_iframe_desc_count as usize * mem::size_of::(); // t_iframe_desc + + animation.size += animation.rotations_count as usize * mem::size_of::() + // rotations + animation.rotations_count as usize * mem::size_of::() + // r_ratios + animation.rotations_count as usize * mem::size_of::() + // r_previouses + animation.r_iframe_entries_count as usize * mem::size_of::(); // r_iframe_entries + animation.size = align_usize(animation.size, ALIGN); + animation.size += animation.r_iframe_desc_count as usize * mem::size_of::(); // r_iframe_desc + + animation.size += animation.scales_count as usize * mem::size_of::() + // scales + animation.scales_count as usize * mem::size_of::() + // s_ratios + animation.scales_count as usize * mem::size_of::() + // s_previouses + animation.s_iframe_entries_count as usize * mem::size_of::(); // s_iframe_entries + animation.size = align_usize(animation.size, ALIGN); + animation.size += animation.s_iframe_desc_count as usize * mem::size_of::(); // s_iframe_desc + + unsafe { + let layout = Layout::from_size_align_unchecked(animation.size, mem::size_of::()); + let mut ptr = alloc::alloc(layout); + + animation.timepoints = ptr as *mut f32; + ptr = ptr.add(animation.timepoints_count as usize * mem::size_of::()); + + animation.translations = ptr as *mut Float3Key; + ptr = ptr.add(animation.translations_count as usize * mem::size_of::()); + animation.t_ratios = ptr as *mut u16; + ptr = ptr.add(animation.translations_count as usize * mem::size_of::()); + animation.t_previouses = ptr as *mut u16; + ptr = ptr.add(animation.translations_count as usize * mem::size_of::()); + animation.t_iframe_entries = ptr as *mut u8; + ptr = ptr.add(animation.t_iframe_entries_count as usize * mem::size_of::()); + ptr = align_ptr(ptr, ALIGN); + animation.t_iframe_desc = ptr as *mut u32; + ptr = ptr.add(animation.t_iframe_desc_count as usize * mem::size_of::()); + + animation.rotations = ptr as *mut QuaternionKey; + ptr = ptr.add(animation.rotations_count as usize * mem::size_of::()); + animation.r_ratios = ptr as *mut u16; + ptr = ptr.add(animation.rotations_count as usize * mem::size_of::()); + animation.r_previouses = ptr as *mut u16; + ptr = ptr.add(animation.rotations_count as usize * mem::size_of::()); + animation.r_iframe_entries = ptr as *mut u8; + ptr = ptr.add(animation.r_iframe_entries_count as usize * mem::size_of::()); + ptr = align_ptr(ptr, ALIGN); + animation.r_iframe_desc = ptr as *mut u32; + ptr = ptr.add(animation.r_iframe_desc_count as usize * mem::size_of::()); + + animation.scales = ptr as *mut Float3Key; + ptr = ptr.add(animation.scales_count as usize * mem::size_of::()); + animation.s_ratios = ptr as *mut u16; + ptr = ptr.add(animation.scales_count as usize * mem::size_of::()); + animation.s_previouses = ptr as *mut u16; + ptr = ptr.add(animation.scales_count as usize * mem::size_of::()); + animation.s_iframe_entries = ptr as *mut u8; + ptr = ptr.add(animation.s_iframe_entries_count as usize * mem::size_of::()); + ptr = align_ptr(ptr, ALIGN); + animation.s_iframe_desc = ptr as *mut u32; + ptr = ptr.add(animation.s_iframe_desc_count as usize * mem::size_of::()); + + assert_eq!(ptr, (animation.timepoints as *mut u8).add(animation.size)); + } + return animation; + } +} + +/// Animation keyframes control structure. +#[derive(Debug, Default)] +pub struct KeyframesCtrl<'t> { + pub ratios: &'t [u16], + pub previouses: &'t [u16], + pub iframe_entries: &'t [u8], + pub iframe_desc: &'t [u32], + pub iframe_interval: f32, } impl Animation { @@ -432,20 +627,20 @@ impl Animation { /// Gets the number of animated tracks. #[inline] pub fn num_tracks(&self) -> usize { - return self.num_tracks; + return self.num_tracks as usize; } /// Gets the number of animated tracks (aligned to 4 * SoA). #[inline] pub fn num_aligned_tracks(&self) -> usize { - return (self.num_tracks + 3) & !0x3; + return ((self.num_tracks as usize) + 3) & !0x3; } /// Gets the number of SoA elements matching the number of tracks of `Animation`. /// This value is useful to allocate SoA runtime data structures. #[inline] pub fn num_soa_tracks(&self) -> usize { - return (self.num_tracks + 3) / 4; + return ((self.num_tracks as usize) + 3) / 4; } /// Gets animation name. @@ -457,46 +652,442 @@ impl Animation { /// Gets the buffer of time points. #[inline] pub fn timepoints(&self) -> &[f32] { - return &self.timepoints; + return unsafe { slice::from_raw_parts(self.timepoints, self.timepoints_count as usize) }; + } + + #[inline] + fn timepoints_mut(&mut self) -> &mut [f32] { + return unsafe { slice::from_raw_parts_mut(self.timepoints, self.timepoints_count as usize) }; } /// Gets the buffer of translation keys. #[inline] - pub fn translations_ctrl(&self) -> &KeyframesCtrl { - return &self.translations_ctrl; + pub fn translations(&self) -> &[Float3Key] { + return unsafe { slice::from_raw_parts(self.translations, self.translations_count as usize) }; + } + + #[inline] + fn translations_mut(&mut self) -> &mut [Float3Key] { + return unsafe { slice::from_raw_parts_mut(self.translations, self.translations_count as usize) }; + } + + #[inline] + fn t_ratios(&self) -> &[u16] { + return unsafe { slice::from_raw_parts(self.t_ratios, self.translations_count as usize) }; + } + + #[inline] + fn t_ratios_mut(&mut self) -> &mut [u16] { + return unsafe { slice::from_raw_parts_mut(self.t_ratios, self.translations_count as usize) }; + } + + #[inline] + fn t_previouses(&self) -> &[u16] { + return unsafe { slice::from_raw_parts(self.t_previouses, self.translations_count as usize) }; + } + + #[inline] + fn t_previouses_mut(&mut self) -> &mut [u16] { + return unsafe { slice::from_raw_parts_mut(self.t_previouses, self.translations_count as usize) }; + } + + #[inline] + fn t_iframe_entries(&self) -> &[u8] { + return unsafe { slice::from_raw_parts(self.t_iframe_entries, self.t_iframe_entries_count as usize) }; + } + + #[inline] + fn t_iframe_entries_mut(&mut self) -> &mut [u8] { + return unsafe { slice::from_raw_parts_mut(self.t_iframe_entries, self.t_iframe_entries_count as usize) }; + } + + #[inline] + fn t_iframe_desc(&self) -> &[u32] { + return unsafe { slice::from_raw_parts(self.t_iframe_desc, self.t_iframe_desc_count as usize) }; + } + + #[inline] + fn t_iframe_desc_mut(&mut self) -> &mut [u32] { + return unsafe { slice::from_raw_parts_mut(self.t_iframe_desc, self.t_iframe_desc_count as usize) }; } /// Gets the buffer of rotation keys. #[inline] - pub fn rotations_ctrl(&self) -> &KeyframesCtrl { - return &self.rotations_ctrl; + pub fn rotations(&self) -> &[QuaternionKey] { + return unsafe { slice::from_raw_parts(self.rotations, self.rotations_count as usize) }; + } + + #[inline] + fn rotations_mut(&mut self) -> &mut [QuaternionKey] { + return unsafe { slice::from_raw_parts_mut(self.rotations, self.rotations_count as usize) }; + } + + #[inline] + fn r_ratios(&self) -> &[u16] { + return unsafe { slice::from_raw_parts(self.r_ratios, self.rotations_count as usize) }; + } + + #[inline] + fn r_ratios_mut(&mut self) -> &mut [u16] { + return unsafe { slice::from_raw_parts_mut(self.r_ratios, self.rotations_count as usize) }; + } + + #[inline] + fn r_previouses(&self) -> &[u16] { + return unsafe { slice::from_raw_parts(self.r_previouses, self.rotations_count as usize) }; + } + + #[inline] + fn r_previouses_mut(&mut self) -> &mut [u16] { + return unsafe { slice::from_raw_parts_mut(self.r_previouses, self.rotations_count as usize) }; + } + + #[inline] + fn r_iframe_entries(&self) -> &[u8] { + return unsafe { slice::from_raw_parts(self.r_iframe_entries, self.r_iframe_entries_count as usize) }; + } + + #[inline] + fn r_iframe_entries_mut(&mut self) -> &mut [u8] { + return unsafe { slice::from_raw_parts_mut(self.r_iframe_entries, self.r_iframe_entries_count as usize) }; + } + + #[inline] + fn r_iframe_desc(&self) -> &[u32] { + return unsafe { slice::from_raw_parts(self.r_iframe_desc, self.r_iframe_desc_count as usize) }; + } + + #[inline] + fn r_iframe_desc_mut(&mut self) -> &mut [u32] { + return unsafe { slice::from_raw_parts_mut(self.r_iframe_desc, self.r_iframe_desc_count as usize) }; } /// Gets the buffer of scale keys. #[inline] - pub fn scales_ctrl(&self) -> &KeyframesCtrl { - return &self.scales_ctrl; + pub fn scales(&self) -> &[Float3Key] { + return unsafe { slice::from_raw_parts(self.scales, self.scales_count as usize) }; + } + + #[inline] + fn scales_mut(&mut self) -> &mut [Float3Key] { + return unsafe { slice::from_raw_parts_mut(self.scales, self.scales_count as usize) }; + } + + #[inline] + fn s_ratios(&self) -> &[u16] { + return unsafe { slice::from_raw_parts(self.s_ratios, self.scales_count as usize) }; + } + + #[inline] + fn s_ratios_mut(&mut self) -> &mut [u16] { + return unsafe { slice::from_raw_parts_mut(self.s_ratios, self.scales_count as usize) }; + } + + #[inline] + fn s_previouses(&self) -> &[u16] { + return unsafe { slice::from_raw_parts(self.s_previouses, self.scales_count as usize) }; + } + + #[inline] + fn s_previouses_mut(&mut self) -> &mut [u16] { + return unsafe { slice::from_raw_parts_mut(self.s_previouses, self.scales_count as usize) }; + } + + #[inline] + fn s_iframe_entries(&self) -> &[u8] { + return unsafe { slice::from_raw_parts(self.s_iframe_entries, self.s_iframe_entries_count as usize) }; + } + + #[inline] + fn s_iframe_entries_mut(&mut self) -> &mut [u8] { + return unsafe { slice::from_raw_parts_mut(self.s_iframe_entries, self.s_iframe_entries_count as usize) }; + } + + #[inline] + fn s_iframe_desc(&self) -> &[u32] { + return unsafe { slice::from_raw_parts(self.s_iframe_desc, self.s_iframe_desc_count as usize) }; + } + + #[inline] + fn s_iframe_desc_mut(&mut self) -> &mut [u32] { + return unsafe { slice::from_raw_parts_mut(self.s_iframe_desc, self.s_iframe_desc_count as usize) }; } /// Gets the buffer of translation keys. #[inline] - pub fn translations(&self) -> &[Float3Key] { - return &self.translations; + pub fn translations_ctrl(&self) -> KeyframesCtrl<'_> { + return unsafe { + KeyframesCtrl { + ratios: slice::from_raw_parts(self.t_ratios, self.translations_count as usize), + previouses: slice::from_raw_parts(self.t_previouses, self.translations_count as usize), + iframe_entries: slice::from_raw_parts(self.t_iframe_entries, self.t_iframe_entries_count as usize), + iframe_desc: slice::from_raw_parts(self.t_iframe_desc, self.t_iframe_desc_count as usize), + iframe_interval: self.t_iframe_interval, + } + }; } /// Gets the buffer of rotation keys. #[inline] - pub fn rotations(&self) -> &[QuaternionKey] { - return &self.rotations; + pub fn rotations_ctrl(&self) -> KeyframesCtrl<'_> { + return unsafe { + KeyframesCtrl { + ratios: slice::from_raw_parts(self.r_ratios, self.rotations_count as usize), + previouses: slice::from_raw_parts(self.r_previouses, self.rotations_count as usize), + iframe_entries: slice::from_raw_parts(self.r_iframe_entries, self.r_iframe_entries_count as usize), + iframe_desc: slice::from_raw_parts(self.r_iframe_desc, self.r_iframe_desc_count as usize), + iframe_interval: self.r_iframe_interval, + } + }; } /// Gets the buffer of scale keys. #[inline] - pub fn scales(&self) -> &[Float3Key] { - return &self.scales; + pub fn scales_ctrl(&self) -> KeyframesCtrl<'_> { + return unsafe { + KeyframesCtrl { + ratios: slice::from_raw_parts(self.s_ratios, self.scales_count as usize), + previouses: slice::from_raw_parts(self.s_previouses, self.scales_count as usize), + iframe_entries: slice::from_raw_parts(self.s_iframe_entries, self.s_iframe_entries_count as usize), + iframe_desc: slice::from_raw_parts(self.s_iframe_desc, self.s_iframe_desc_count as usize), + iframe_interval: self.s_iframe_interval, + } + }; } } +#[cfg(feature = "rkyv")] +pub struct ArchivedAnimation { + pub duration: f32, + pub num_tracks: u32, + pub name: rkyv::string::ArchivedString, + pub timepoints: rkyv::vec::ArchivedVec, + + pub translations: rkyv::vec::ArchivedVec, + pub t_ratios: rkyv::vec::ArchivedVec, + pub t_previouses: rkyv::vec::ArchivedVec, + pub t_iframe_interval: f32, + pub t_iframe_entries: rkyv::vec::ArchivedVec, + pub t_iframe_desc: rkyv::vec::ArchivedVec, + + pub rotations: rkyv::vec::ArchivedVec, + pub r_ratios: rkyv::vec::ArchivedVec, + pub r_previouses: rkyv::vec::ArchivedVec, + pub r_iframe_interval: f32, + pub r_iframe_entries: rkyv::vec::ArchivedVec, + pub r_iframe_desc: rkyv::vec::ArchivedVec, + + pub scales: rkyv::vec::ArchivedVec, + pub s_ratios: rkyv::vec::ArchivedVec, + pub s_previouses: rkyv::vec::ArchivedVec, + pub s_iframe_interval: f32, + pub s_iframe_entries: rkyv::vec::ArchivedVec, + pub s_iframe_desc: rkyv::vec::ArchivedVec, +} + +#[cfg(feature = "rkyv")] +const _: () = { + use rkyv::ser::{ScratchSpace, Serializer}; + use rkyv::string::{ArchivedString, StringResolver}; + use rkyv::vec::{ArchivedVec, VecResolver}; + use rkyv::{from_archived, out_field, Archive, Deserialize, Fallible, Serialize}; + + pub struct AnimationResolver { + name: StringResolver, + timepoints: VecResolver, + + translations: VecResolver, + t_ratios: VecResolver, + t_previouses: VecResolver, + t_iframe_entries: VecResolver, + t_iframe_desc: VecResolver, + + rotations: VecResolver, + r_ratios: VecResolver, + r_previouses: VecResolver, + r_iframe_entries: VecResolver, + r_iframe_desc: VecResolver, + + scales: VecResolver, + s_ratios: VecResolver, + s_previouses: VecResolver, + s_iframe_entries: VecResolver, + s_iframe_desc: VecResolver, + } + + impl Archive for Animation { + type Archived = ArchivedAnimation; + type Resolver = AnimationResolver; + + unsafe fn resolve(&self, pos: usize, resolver: AnimationResolver, out: *mut ArchivedAnimation) { + let (fp, fo) = out_field!(out.duration); + f32::resolve(&self.duration, pos + fp, (), fo); + let (fp, fo) = out_field!(out.num_tracks); + u32::resolve(&self.num_tracks, pos + fp, (), fo); + let (fp, fo) = out_field!(out.name); + String::resolve(&self.name, pos + fp, resolver.name, fo); + let (fp, fo) = out_field!(out.timepoints); + ArchivedVec::resolve_from_slice(self.timepoints(), pos + fp, resolver.timepoints, fo); + + let (fp, fo) = out_field!(out.translations); + ArchivedVec::resolve_from_slice(self.translations(), pos + fp, resolver.translations, fo); + let (fp, fo) = out_field!(out.t_ratios); + ArchivedVec::resolve_from_slice(self.t_ratios(), pos + fp, resolver.t_ratios, fo); + let (fp, fo) = out_field!(out.t_previouses); + ArchivedVec::resolve_from_slice(self.t_previouses(), pos + fp, resolver.t_previouses, fo); + let (fp, fo) = out_field!(out.t_iframe_interval); + f32::resolve(&self.t_iframe_interval, pos + fp, (), fo); + let (fp, fo) = out_field!(out.t_iframe_entries); + ArchivedVec::resolve_from_slice(self.t_iframe_entries(), pos + fp, resolver.t_iframe_entries, fo); + let (fp, fo) = out_field!(out.t_iframe_desc); + ArchivedVec::resolve_from_slice(self.t_iframe_desc(), pos + fp, resolver.t_iframe_desc, fo); + + let (fp, fo) = out_field!(out.rotations); + ArchivedVec::resolve_from_slice(self.rotations(), pos + fp, resolver.rotations, fo); + let (fp, fo) = out_field!(out.r_ratios); + ArchivedVec::resolve_from_slice(self.r_ratios(), pos + fp, resolver.r_ratios, fo); + let (fp, fo) = out_field!(out.r_previouses); + ArchivedVec::resolve_from_slice(self.r_previouses(), pos + fp, resolver.r_previouses, fo); + let (fp, fo) = out_field!(out.r_iframe_interval); + f32::resolve(&self.r_iframe_interval, pos + fp, (), fo); + let (fp, fo) = out_field!(out.r_iframe_entries); + ArchivedVec::resolve_from_slice(self.r_iframe_entries(), pos + fp, resolver.r_iframe_entries, fo); + let (fp, fo) = out_field!(out.r_iframe_desc); + ArchivedVec::resolve_from_slice(self.r_iframe_desc(), pos + fp, resolver.r_iframe_desc, fo); + + let (fp, fo) = out_field!(out.scales); + ArchivedVec::resolve_from_slice(self.scales(), pos + fp, resolver.scales, fo); + let (fp, fo) = out_field!(out.s_ratios); + ArchivedVec::resolve_from_slice(self.s_ratios(), pos + fp, resolver.s_ratios, fo); + let (fp, fo) = out_field!(out.s_previouses); + ArchivedVec::resolve_from_slice(self.s_previouses(), pos + fp, resolver.s_previouses, fo); + let (fp, fo) = out_field!(out.s_iframe_interval); + f32::resolve(&self.s_iframe_interval, pos + fp, (), fo); + let (fp, fo) = out_field!(out.s_iframe_entries); + ArchivedVec::resolve_from_slice(self.s_iframe_entries(), pos + fp, resolver.s_iframe_entries, fo); + let (fp, fo) = out_field!(out.s_iframe_desc); + ArchivedVec::resolve_from_slice(self.s_iframe_desc(), pos + fp, resolver.s_iframe_desc, fo); + } + } + + impl Serialize for Animation { + fn serialize(&self, serializer: &mut S) -> Result { + return Ok(AnimationResolver { + name: ArchivedString::serialize_from_str(&self.name, serializer)?, + timepoints: ArchivedVec::serialize_from_slice(self.timepoints(), serializer)?, + translations: ArchivedVec::serialize_from_slice(self.translations(), serializer)?, + t_ratios: ArchivedVec::serialize_from_slice(self.t_ratios(), serializer)?, + t_previouses: ArchivedVec::serialize_from_slice(self.t_previouses(), serializer)?, + t_iframe_entries: ArchivedVec::serialize_from_slice(self.t_iframe_entries(), serializer)?, + t_iframe_desc: ArchivedVec::serialize_from_slice(self.t_iframe_desc(), serializer)?, + rotations: ArchivedVec::serialize_from_slice(self.rotations(), serializer)?, + r_ratios: ArchivedVec::serialize_from_slice(self.r_ratios(), serializer)?, + r_previouses: ArchivedVec::serialize_from_slice(self.r_previouses(), serializer)?, + r_iframe_entries: ArchivedVec::serialize_from_slice(self.r_iframe_entries(), serializer)?, + r_iframe_desc: ArchivedVec::serialize_from_slice(self.r_iframe_desc(), serializer)?, + scales: ArchivedVec::serialize_from_slice(self.scales(), serializer)?, + s_ratios: ArchivedVec::serialize_from_slice(self.s_ratios(), serializer)?, + s_previouses: ArchivedVec::serialize_from_slice(self.s_previouses(), serializer)?, + s_iframe_entries: ArchivedVec::serialize_from_slice(self.s_iframe_entries(), serializer)?, + s_iframe_desc: ArchivedVec::serialize_from_slice(self.s_iframe_desc(), serializer)?, + }); + } + } + + impl Deserialize for ArchivedAnimation { + #[inline] + fn deserialize(&self, _: &mut D) -> Result { + let archived = from_archived!(self); + let mut animation = Animation::new(AnimationMeta { + version: Animation::version(), + duration: archived.duration, + num_tracks: archived.num_tracks as u32, + name: archived.name.to_string(), + timepoints_count: archived.timepoints.len() as u32, + translations_count: archived.translations.len() as u32, + t_iframe_entries_count: archived.t_iframe_entries.len() as u32, + t_iframe_desc_count: archived.t_iframe_desc.len() as u32, + rotations_count: archived.rotations.len() as u32, + r_iframe_entries_count: archived.r_iframe_entries.len() as u32, + r_iframe_desc_count: archived.r_iframe_desc.len() as u32, + scales_count: archived.scales.len() as u32, + s_iframe_entries_count: archived.s_iframe_entries.len() as u32, + s_iframe_desc_count: archived.s_iframe_desc.len() as u32, + }); + + animation + .timepoints_mut() + .copy_from_slice(archived.timepoints.as_slice()); + + for (idx, t) in archived.translations.iter().enumerate() { + animation.translations_mut()[idx] = Float3Key(t.0); + } + animation.t_ratios_mut().copy_from_slice(archived.t_ratios.as_slice()); + animation + .t_previouses_mut() + .copy_from_slice(archived.t_previouses.as_slice()); + animation + .t_iframe_entries_mut() + .copy_from_slice(archived.t_iframe_entries.as_slice()); + animation + .t_iframe_desc_mut() + .copy_from_slice(archived.t_iframe_desc.as_slice()); + animation.t_iframe_interval = archived.t_iframe_interval; + + for (idx, r) in archived.rotations.iter().enumerate() { + animation.rotations_mut()[idx] = QuaternionKey(r.0); + } + animation.r_ratios_mut().copy_from_slice(archived.r_ratios.as_slice()); + animation + .r_previouses_mut() + .copy_from_slice(archived.r_previouses.as_slice()); + animation + .r_iframe_entries_mut() + .copy_from_slice(archived.r_iframe_entries.as_slice()); + animation + .r_iframe_desc_mut() + .copy_from_slice(archived.r_iframe_desc.as_slice()); + animation.r_iframe_interval = archived.r_iframe_interval; + + for (idx, s) in archived.scales.iter().enumerate() { + animation.scales_mut()[idx] = Float3Key(s.0); + } + animation.s_ratios_mut().copy_from_slice(archived.s_ratios.as_slice()); + animation + .s_previouses_mut() + .copy_from_slice(archived.s_previouses.as_slice()); + animation + .s_iframe_entries_mut() + .copy_from_slice(archived.s_iframe_entries.as_slice()); + animation + .s_iframe_desc_mut() + .copy_from_slice(archived.s_iframe_desc.as_slice()); + animation.s_iframe_interval = archived.s_iframe_interval; + + return Ok(animation); + } + } +}; + +#[cfg(feature = "serde")] +const _: () = { + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + impl Serialize for Animation { + fn serialize(&self, serializer: S) -> Result { + let raw = self.to_raw(); + return raw.serialize(serializer); + } + } + + impl<'de> Deserialize<'de> for Animation { + fn deserialize>(deserializer: D) -> Result { + let raw = AnimationRaw::deserialize(deserializer)?; + return Ok(Animation::from_raw(&raw)); + } + } +}; + #[cfg(test)] mod tests { use wasm_bindgen_test::*; @@ -602,35 +1193,35 @@ mod tests { assert_eq!(animation.timepoints().first().unwrap(), &0.0); assert_eq!(animation.timepoints().last().unwrap(), &1.0); - assert_eq!(animation.translations_ctrl().ratios_u8().len(), 178); - assert_eq!(animation.translations_ctrl().ratios_u8().first().unwrap(), &0); - assert_eq!(animation.translations_ctrl().ratios_u8().last().unwrap(), &251); - assert_eq!(animation.translations_ctrl().previouses().len(), 178); - assert_eq!(animation.translations_ctrl().previouses().first().unwrap(), &0); - assert_eq!(animation.translations_ctrl().previouses().last().unwrap(), &1); - assert!(animation.translations_ctrl().iframe_entries().is_empty()); - assert!(animation.translations_ctrl().iframe_desc().is_empty()); + assert_eq!(animation.translations_ctrl().ratios.len(), 178); + assert_eq!(animation.translations_ctrl().ratios.first().unwrap(), &0); + assert_eq!(animation.translations_ctrl().ratios.last().unwrap(), &251); + assert_eq!(animation.translations_ctrl().previouses.len(), 178); + assert_eq!(animation.translations_ctrl().previouses.first().unwrap(), &0); + assert_eq!(animation.translations_ctrl().previouses.last().unwrap(), &1); assert_eq!(animation.translations_ctrl().iframe_interval, 1.0); - - assert_eq!(animation.rotations_ctrl().ratios_u8().len(), 1699); - assert_eq!(animation.rotations_ctrl().ratios_u8().first().unwrap(), &0); - assert_eq!(animation.rotations_ctrl().ratios_u8().last().unwrap(), &251); - assert_eq!(animation.rotations_ctrl().previouses().len(), 1699); - assert_eq!(animation.rotations_ctrl().previouses().first().unwrap(), &0); - assert_eq!(animation.rotations_ctrl().previouses().last().unwrap(), &6); - assert!(animation.rotations_ctrl().iframe_entries().is_empty()); - assert!(animation.rotations_ctrl().iframe_desc().is_empty()); + assert!(animation.translations_ctrl().iframe_entries.is_empty()); + assert!(animation.translations_ctrl().iframe_desc.is_empty()); + + assert_eq!(animation.rotations_ctrl().ratios.len(), 1699); + assert_eq!(animation.rotations_ctrl().ratios.first().unwrap(), &0); + assert_eq!(animation.rotations_ctrl().ratios.last().unwrap(), &251); + assert_eq!(animation.rotations_ctrl().previouses.len(), 1699); + assert_eq!(animation.rotations_ctrl().previouses.first().unwrap(), &0); + assert_eq!(animation.rotations_ctrl().previouses.last().unwrap(), &6); assert_eq!(animation.rotations_ctrl().iframe_interval, 1.0); - - assert_eq!(animation.scales_ctrl().ratios_u8().len(), 136); - assert_eq!(animation.scales_ctrl().ratios_u8().first().unwrap(), &0); - assert_eq!(animation.scales_ctrl().ratios_u8().last().unwrap(), &251); - assert_eq!(animation.scales_ctrl().previouses().len(), 136); - assert_eq!(animation.scales_ctrl().previouses().first().unwrap(), &0); - assert_eq!(animation.scales_ctrl().previouses().last().unwrap(), &68); - assert!(animation.scales_ctrl().iframe_entries().is_empty()); - assert!(animation.scales_ctrl().iframe_desc().is_empty()); + assert!(animation.rotations_ctrl().iframe_entries.is_empty()); + assert!(animation.rotations_ctrl().iframe_desc.is_empty()); + + assert_eq!(animation.scales_ctrl().ratios.len(), 136); + assert_eq!(animation.scales_ctrl().ratios.first().unwrap(), &0); + assert_eq!(animation.scales_ctrl().ratios.last().unwrap(), &251); + assert_eq!(animation.scales_ctrl().previouses.len(), 136); + assert_eq!(animation.scales_ctrl().previouses.first().unwrap(), &0); + assert_eq!(animation.scales_ctrl().previouses.last().unwrap(), &68); assert_eq!(animation.scales_ctrl().iframe_interval, 1.0); + assert!(animation.scales_ctrl().iframe_entries.is_empty()); + assert!(animation.scales_ctrl().iframe_desc.is_empty()); assert_eq!(animation.translations().len(), 178); assert_eq!(animation.translations().first().unwrap().0, [0, 15400, 43950]); @@ -644,4 +1235,149 @@ mod tests { assert_eq!(animation.scales().first().unwrap().0, [15360, 15360, 15360]); assert_eq!(animation.scales().last().unwrap().0, [15360, 15360, 15360]); } + + #[cfg(feature = "rkyv")] + #[test] + #[wasm_bindgen_test] + fn test_rkyv_animation() { + use rkyv::ser::Serializer; + use rkyv::Deserialize; + + let animation = Animation::from_path("./resource/playback/animation.ozz").unwrap(); + let mut serializer = rkyv::ser::serializers::AllocSerializer::<30720>::default(); + serializer.serialize_value(&animation).unwrap(); + let buf = serializer.into_serializer().into_inner(); + let archived = unsafe { rkyv::archived_root::(&buf) }; + let mut deserializer = rkyv::Infallible::default(); + let animation2: Animation = archived.deserialize(&mut deserializer).unwrap(); + + assert_eq!(animation.duration(), animation2.duration()); + assert_eq!(animation.num_tracks(), animation2.num_tracks()); + assert_eq!(animation.name(), animation2.name()); + assert_eq!(animation.timepoints(), animation2.timepoints()); + + assert_eq!( + animation.translations_ctrl().ratios, + animation2.translations_ctrl().ratios + ); + assert_eq!( + animation.translations_ctrl().previouses, + animation2.translations_ctrl().previouses + ); + assert_eq!( + animation.translations_ctrl().iframe_interval, + animation2.translations_ctrl().iframe_interval + ); + assert_eq!( + animation.translations_ctrl().iframe_entries, + animation2.translations_ctrl().iframe_entries + ); + assert_eq!( + animation.translations_ctrl().iframe_desc, + animation2.translations_ctrl().iframe_desc + ); + + assert_eq!(animation.rotations_ctrl().ratios, animation2.rotations_ctrl().ratios); + assert_eq!( + animation.rotations_ctrl().previouses, + animation2.rotations_ctrl().previouses + ); + assert_eq!( + animation.rotations_ctrl().iframe_interval, + animation2.rotations_ctrl().iframe_interval + ); + assert_eq!( + animation.rotations_ctrl().iframe_entries, + animation2.rotations_ctrl().iframe_entries + ); + assert_eq!( + animation.rotations_ctrl().iframe_desc, + animation2.rotations_ctrl().iframe_desc + ); + + assert_eq!(animation.scales_ctrl().ratios, animation2.scales_ctrl().ratios); + assert_eq!(animation.scales_ctrl().previouses, animation2.scales_ctrl().previouses); + assert_eq!( + animation.scales_ctrl().iframe_interval, + animation2.scales_ctrl().iframe_interval + ); + assert_eq!( + animation.scales_ctrl().iframe_entries, + animation2.scales_ctrl().iframe_entries + ); + assert_eq!( + animation.scales_ctrl().iframe_desc, + animation2.scales_ctrl().iframe_desc + ); + } + + #[cfg(feature = "serde")] + #[test] + #[wasm_bindgen_test] + fn test_serde_animation() { + use serde_json; + + let animation = Animation::from_path("./resource/blend/animation1.ozz").unwrap(); + let josn = serde_json::to_vec(&animation).unwrap(); + let animation2: Animation = serde_json::from_slice(&josn).unwrap(); + + assert_eq!(animation.duration(), animation2.duration()); + assert_eq!(animation.num_tracks(), animation2.num_tracks()); + assert_eq!(animation.name(), animation2.name()); + assert_eq!(animation.timepoints(), animation2.timepoints()); + + assert_eq!( + animation.translations_ctrl().ratios, + animation2.translations_ctrl().ratios + ); + assert_eq!( + animation.translations_ctrl().previouses, + animation2.translations_ctrl().previouses + ); + assert_eq!( + animation.translations_ctrl().iframe_interval, + animation2.translations_ctrl().iframe_interval + ); + assert_eq!( + animation.translations_ctrl().iframe_entries, + animation2.translations_ctrl().iframe_entries + ); + assert_eq!( + animation.translations_ctrl().iframe_desc, + animation2.translations_ctrl().iframe_desc + ); + + assert_eq!(animation.rotations_ctrl().ratios, animation2.rotations_ctrl().ratios); + assert_eq!( + animation.rotations_ctrl().previouses, + animation2.rotations_ctrl().previouses + ); + assert_eq!( + animation.rotations_ctrl().iframe_interval, + animation2.rotations_ctrl().iframe_interval + ); + assert_eq!( + animation.rotations_ctrl().iframe_entries, + animation2.rotations_ctrl().iframe_entries + ); + assert_eq!( + animation.rotations_ctrl().iframe_desc, + animation2.rotations_ctrl().iframe_desc + ); + + assert_eq!(animation.scales_ctrl().ratios, animation2.scales_ctrl().ratios); + assert_eq!(animation.scales_ctrl().previouses, animation2.scales_ctrl().previouses); + assert_eq!( + animation.scales_ctrl().iframe_interval, + animation2.scales_ctrl().iframe_interval + ); + assert_eq!( + animation.scales_ctrl().iframe_entries, + animation2.scales_ctrl().iframe_entries + ); + assert_eq!( + animation.scales_ctrl().iframe_desc, + animation2.scales_ctrl().iframe_desc + ); + } } diff --git a/src/archive.rs b/src/archive.rs index b05a067..0f172f6 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -58,6 +58,12 @@ impl Archive { return T::read_vec(self, count); } + /// Reads `[T]` from the archive into slice. + /// * `buffer` - The buffer to read into. + pub fn read_slice>(&mut self, buffer: &mut [T]) -> Result<(), OzzError> { + return T::read_slice(self, buffer); + } + /// Does the endian need to be swapped. pub fn endian_swap(&self) -> bool { return self.endian_swap; @@ -128,6 +134,16 @@ pub trait ArchiveRead { } return Ok(buffer); } + + /// Reads `[T]` from the archive into slice. + /// * `buffer` - The buffer to read into. + #[inline] + fn read_slice(archive: &mut Archive, buffer: &mut [T]) -> Result<(), OzzError> { + for i in 0..buffer.len() { + buffer[i] = Self::read(archive)?; + } + return Ok(()); + } } macro_rules! primitive_reader { diff --git a/src/blending_job.rs b/src/blending_job.rs index f96083f..da2d775 100644 --- a/src/blending_job.rs +++ b/src/blending_job.rs @@ -550,7 +550,7 @@ mod blending_tests { use super::*; use crate::base::DeterministicState; - use crate::skeleton::JointHashMap; + use crate::skeleton::{JointHashMap, SkeletonRaw}; const IDENTITY: SoaTransform = SoaTransform { translation: SoaVec3::splat_col([0.0; 3]), @@ -565,7 +565,7 @@ mod blending_tests { #[test] #[wasm_bindgen_test] fn test_validity() { - let skeleton = Rc::new(Skeleton::from_path("./resource/skeleton-blending.ozz").unwrap()); + let skeleton = Rc::new(Skeleton::from_path("./resource/blend/skeleton.ozz").unwrap()); let num_bind_pose = skeleton.num_soa_joints(); let default_layer = BlendingLayer { transform: make_buf(vec![SoaTransform::default(); num_bind_pose]), @@ -801,11 +801,11 @@ mod blending_tests { joint_rest_poses[1].rotation = SoaQuat::splat_col([0.0, 0.0, 0.0, 1.0]); joint_rest_poses[1].scale = joint_rest_poses[0].scale.mul_num(f32x4::splat(2.0)); - let skeleton = Rc::new(Skeleton::from_raw( + let skeleton = Rc::new(Skeleton::from_raw(&SkeletonRaw { joint_rest_poses, - vec![0; 8], - JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), - )); + joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), + joint_parents: vec![0; 8], + })); execute_test( &skeleton, @@ -847,7 +847,7 @@ mod blending_tests { input2[1].translation = input1[1].translation.neg(); let mut layers = new_layers(input1, vec![], input2, vec![]); - let rest_poses = vec![ + let joint_rest_poses = vec![ SoaTransform { translation: SoaVec3::splat_col([0.0, 0.0, 0.0]), rotation: SoaQuat::splat_col([0.0, 0.0, 0.0, 1.0]), @@ -863,11 +863,11 @@ mod blending_tests { ), }, ]; - let skeleton = Rc::new(Skeleton::from_raw( - rest_poses, - vec![0; 8], - JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), - )); + let skeleton = Rc::new(Skeleton::from_raw(&SkeletonRaw { + joint_rest_poses, + joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), + joint_parents: vec![0; 8], + })); { layers[0].weight = -0.07; @@ -947,7 +947,7 @@ mod blending_tests { let weights2 = vec![Vec4::new(1.0, 1.0, 1.0, 0.0), Vec4::new(0.0, 1.0, 1.0, 1.0)]; let mut layers = new_layers(input1, weights1, input2, weights2); - let rest_poses = vec![ + let joint_rest_poses = vec![ SoaTransform { translation: SoaVec3::new( [10.0, 11.0, 12.0, 13.0], @@ -963,11 +963,11 @@ mod blending_tests { scale: SoaVec3::new([0.0, 2.0, 4.0, 6.0], [8.0, 10.0, 12.0, 14.0], [16.0, 18.0, 20.0, 22.0]), }, ]; - let skeleton = Rc::new(Skeleton::from_raw( - rest_poses, - vec![0; 8], - JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), - )); + let skeleton = Rc::new(Skeleton::from_raw(&SkeletonRaw { + joint_rest_poses, + joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), + joint_parents: vec![0; 8], + })); { layers[0].weight = 0.5; @@ -1026,11 +1026,11 @@ mod blending_tests { let mut joint_rest_poses = vec![IDENTITY]; joint_rest_poses[0].scale = SoaVec3::new([0.0, 1.0, 2.0, 3.0], [4.0, 5.0, 6.0, 7.0], [8.0, 9.0, 10.0, 11.0]); - return Rc::new(Skeleton::from_raw( + return Rc::new(Skeleton::from_raw(&SkeletonRaw { joint_rest_poses, - vec![0; 4], - JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), - )); + joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), + joint_parents: vec![0; 4], + })); } #[test] #[wasm_bindgen_test] @@ -1246,11 +1246,11 @@ mod blending_tests { #[test] #[wasm_bindgen_test] fn test_additive_weight() { - let skeleton = Rc::new(Skeleton::from_raw( - vec![IDENTITY; 1], - vec![0; 4], - JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), - )); + let skeleton = Rc::new(Skeleton::from_raw(&SkeletonRaw { + joint_rest_poses: vec![IDENTITY; 1], + joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), + joint_parents: vec![0; 4], + })); let mut input1 = vec![IDENTITY; 1]; input1[0].translation = SoaVec3::new([0.0, 1.0, 2.0, 3.0], [4.0, 5.0, 6.0, 7.0], [8.0, 9.0, 10.0, 11.0]); @@ -1417,11 +1417,11 @@ mod blending_tests { #[test] #[wasm_bindgen_test] fn test_additive_joint_weight() { - let skeleton = Rc::new(Skeleton::from_raw( - vec![IDENTITY; 1], - vec![0; 4], - JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), - )); + let skeleton = Rc::new(Skeleton::from_raw(&SkeletonRaw { + joint_rest_poses: vec![IDENTITY; 1], + joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), + joint_parents: vec![0; 4], + })); let mut input1 = vec![IDENTITY; 1]; input1[0].translation = SoaVec3::new([0.0, 1.0, 2.0, 3.0], [4.0, 5.0, 6.0, 7.0], [8.0, 9.0, 10.0, 11.0]); diff --git a/src/local_to_model_job.rs b/src/local_to_model_job.rs index 445adc9..3f39ab1 100644 --- a/src/local_to_model_job.rs +++ b/src/local_to_model_job.rs @@ -266,7 +266,7 @@ mod local_to_model_tests { use super::*; use crate::base::DeterministicState; use crate::math::{SoaQuat, SoaVec3}; - use crate::skeleton::JointHashMap; + use crate::skeleton::{JointHashMap, SkeletonRaw}; #[test] #[wasm_bindgen_test] @@ -332,8 +332,8 @@ mod local_to_model_tests { // j1 j3 // | / \ // j2 j4 j5 - return Rc::new(Skeleton::from_raw( - vec![ + return Rc::new(Skeleton::from_raw(&SkeletonRaw { + joint_rest_poses: vec![ SoaTransform { translation: SoaVec3::splat_col([0.0; 3]), rotation: SoaQuat::splat_col([0.0, 0.0, 0.0, 1.0]), @@ -341,8 +341,7 @@ mod local_to_model_tests { }; 2 ], - vec![-1, 0, 1, 0, 3, 3], - (|| { + joint_names: (|| { let mut map = JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()); map.insert("j0".into(), 0); map.insert("j1".into(), 1); @@ -352,7 +351,8 @@ mod local_to_model_tests { map.insert("j5".into(), 5); return map; })(), - )); + joint_parents: vec![-1, 0, 1, 0, 3, 3], + })); } fn new_input1() -> Rc>> { @@ -391,8 +391,8 @@ mod local_to_model_tests { // j2 j4 j6 // | // j5 - return Rc::new(Skeleton::from_raw( - vec![ + return Rc::new(Skeleton::from_raw(&SkeletonRaw { + joint_rest_poses: vec![ SoaTransform { translation: SoaVec3::splat_col([0.0; 3]), rotation: SoaQuat::splat_col([0.0, 0.0, 0.0, 1.0]), @@ -400,8 +400,7 @@ mod local_to_model_tests { }; 2 ], - vec![-1, 0, 1, 0, 3, 4, 3, -1], - (|| { + joint_names: (|| { let mut map = JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()); map.insert("j0".into(), 0); map.insert("j1".into(), 1); @@ -413,7 +412,8 @@ mod local_to_model_tests { map.insert("j7".into(), 7); return map; })(), - )); + joint_parents: vec![-1, 0, 1, 0, 3, 4, 3, -1], + })); } fn new_input2() -> Rc>> { diff --git a/src/sampling_job.rs b/src/sampling_job.rs index c26ba68..b5c2c05 100644 --- a/src/sampling_job.rs +++ b/src/sampling_job.rs @@ -11,7 +11,7 @@ use std::sync::{Arc, RwLock}; use std::{mem, ptr, slice}; use crate::animation::{Animation, Float3Key, KeyframesCtrl, QuaternionKey}; -use crate::base::{align_usize, align_ptr, OzzError, OzzMutBuf, OzzObj}; +use crate::base::{align_ptr, align_usize, OzzError, OzzMutBuf, OzzObj}; use crate::math::{f32_clamp_or_max, SoaQuat, SoaTransform, SoaVec3}; /// Soa hot `SoaVec3` data to interpolate. @@ -293,19 +293,19 @@ impl SamplingContext { let max_soa_tracks = (max_tracks + 3) / 4; let max_tracks = max_soa_tracks * 4; let max_outdated = (max_soa_tracks + 7) / 8; - let translation_size = mem::size_of::() * max_soa_tracks + - mem::size_of::() * max_tracks + - mem::size_of::() * max_outdated; - let rotation_size = mem::size_of::() * max_soa_tracks + - mem::size_of::() * max_tracks + - mem::size_of::() * max_outdated; - let scale_size = mem::size_of::() * max_soa_tracks + - mem::size_of::() * max_tracks + - mem::size_of::() * max_outdated; - let size = align_usize(mem::size_of::(), ALIGN) + - align_usize(translation_size, ALIGN) + - align_usize(rotation_size, ALIGN) + - align_usize(scale_size, ALIGN); + let translation_size = mem::size_of::() * max_soa_tracks + + mem::size_of::() * max_tracks + + mem::size_of::() * max_outdated; + let rotation_size = mem::size_of::() * max_soa_tracks + + mem::size_of::() * max_tracks + + mem::size_of::() * max_outdated; + let scale_size = mem::size_of::() * max_soa_tracks + + mem::size_of::() * max_tracks + + mem::size_of::() * max_outdated; + let size = align_usize(mem::size_of::(), ALIGN) + + align_usize(translation_size, ALIGN) + + align_usize(rotation_size, ALIGN) + + align_usize(scale_size, ALIGN); unsafe { let layout = Layout::from_size_align_unchecked(size, mem::size_of::()); @@ -640,6 +640,28 @@ impl SamplingContext { } } +#[cfg(feature = "rkyv")] +pub struct ArchivedSamplingContext { + pub max_tracks: u32, + pub animation_id: u64, + pub ratio: f32, + + pub translations: rkyv::vec::ArchivedVec, + pub translation_entries: rkyv::vec::ArchivedVec, + pub translation_outdated: rkyv::vec::ArchivedVec, + pub translation_next: u32, + + pub rotations: rkyv::vec::ArchivedVec, + pub rotation_entries: rkyv::vec::ArchivedVec, + pub rotation_outdated: rkyv::vec::ArchivedVec, + pub rotation_next: u32, + + pub scales: rkyv::vec::ArchivedVec, + pub scale_entries: rkyv::vec::ArchivedVec, + pub scale_outdated: rkyv::vec::ArchivedVec, + pub scale_next: u32, +} + #[cfg(feature = "rkyv")] const _: () = { use bytecheck::CheckBytes; @@ -648,28 +670,6 @@ const _: () = { use rkyv::{from_archived, out_field, Archive, Deserialize, Fallible, Serialize}; use std::io::{Error, ErrorKind}; - #[cfg(feature = "rkyv")] - pub struct ArchivedSamplingContext { - pub max_tracks: u32, - pub animation_id: u64, - pub ratio: f32, - - pub translations: ArchivedVec, - pub translation_entries: ArchivedVec, - pub translation_outdated: ArchivedVec, - pub translation_next: u32, - - pub rotations: ArchivedVec, - pub rotation_entries: ArchivedVec, - pub rotation_outdated: ArchivedVec, - pub rotation_next: u32, - - pub scales: ArchivedVec, - pub scale_entries: ArchivedVec, - pub scale_outdated: ArchivedVec, - pub scale_next: u32, - } - pub struct SamplingContextResolver { translations: VecResolver, translation_entries: VecResolver, @@ -1118,17 +1118,17 @@ where let args = ctx.as_mut().translation_update_args(anim); Self::update_cache(args, anim, &anim.translations_ctrl(), self.ratio, prev_ratio); let args = ctx.as_mut().translation_decompress_args(); - Self::decompress_float3(args, anim.timepoints(), anim.translations_ctrl(), anim.translations()); + Self::decompress_float3(args, anim.timepoints(), &anim.translations_ctrl(), anim.translations()); let args = ctx.as_mut().rotation_update_args(anim); Self::update_cache(args, anim, &anim.rotations_ctrl(), self.ratio, prev_ratio); let args = ctx.as_mut().rotation_decompress_args(); - Self::decompress_quat(args, anim.timepoints(), anim.rotations_ctrl(), anim.rotations()); + Self::decompress_quat(args, anim.timepoints(), &anim.rotations_ctrl(), anim.rotations()); let args = ctx.as_mut().scale_update_args(anim); Self::update_cache(args, anim, &anim.scales_ctrl(), self.ratio, prev_ratio); let args = ctx.as_mut().scale_decompress_args(); - Self::decompress_float3(args, anim.timepoints(), anim.scales_ctrl(), anim.scales()); + Self::decompress_float3(args, anim.timepoints(), &anim.scales_ctrl(), anim.scales()); Self::interpolates(anim, ctx.as_mut(), self.ratio, &mut output)?; return Ok(()); @@ -1148,19 +1148,25 @@ where return prev_ratio; } - fn update_cache(args: UpdateArgs<'_>, animation: &Animation, ctrl: &KeyframesCtrl, ratio: f32, prev_ratio: f32) { - assert!(ctrl.previouses().len() >= args.num_tracks * 2); - let num_keys = ctrl.previouses().len(); + fn update_cache( + args: UpdateArgs<'_>, + animation: &Animation, + ctrl: &KeyframesCtrl<'_>, + ratio: f32, + prev_ratio: f32, + ) { + assert!(ctrl.previouses.len() >= args.num_tracks * 2); + let num_keys = ctrl.previouses.len(); let mut next = *args.next; assert!(next == 0 || (next >= args.num_tracks * 2 && next <= num_keys)); // Initialize let delta = ratio - prev_ratio; - if next == 0 || (delta.abs() > ctrl.iframe_interval() / 2.0) { + if next == 0 || (delta.abs() > ctrl.iframe_interval / 2.0) { let mut iframe = -1; - if !ctrl.iframe_desc().is_empty() { - iframe = (0.5 + ratio / ctrl.iframe_interval()) as i32; + if !ctrl.iframe_desc.is_empty() { + iframe = (0.5 + ratio / ctrl.iframe_interval) as i32; } else if next == 0 || delta < 0.0 { iframe = 0; } @@ -1175,10 +1181,10 @@ where // Forward let mut track = 0; while next < num_keys - && Self::key_ratio(ctrl, &animation.timepoints(), next - ctrl.previouses()[next] as usize) <= ratio + && Self::key_ratio(ctrl, &animation.timepoints(), next - ctrl.previouses[next] as usize) <= ratio { - track = Self::track_forward(args.entries, ctrl.previouses(), next, track, args.num_tracks); - assert!((args.entries[track] as usize) == next - (ctrl.previouses()[next] as usize)); + track = Self::track_forward(args.entries, ctrl.previouses, next, track, args.num_tracks); + assert!((args.entries[track] as usize) == next - (ctrl.previouses[next] as usize)); args.outdated[track / 32] |= 1 << ((track & 0x1F) / 4); args.entries[track] = next as u32; next += 1; @@ -1188,14 +1194,14 @@ where while Self::key_ratio( ctrl, &animation.timepoints(), - next - 1 - ctrl.previouses()[next - 1] as usize, + next - 1 - ctrl.previouses[next - 1] as usize, ) > ratio { assert!(next - 1 >= args.num_tracks * 2); track = Self::track_backward(args.entries, next - 1, track, args.num_tracks); args.outdated[track / 32] |= 1 << ((track & 0x1F) / 4); assert!((args.entries[track] as usize) == next - 1); - let previous = ctrl.previouses()[args.entries[track] as usize]; + let previous = ctrl.previouses[args.entries[track] as usize]; assert!((args.entries[track] as usize) >= (previous as usize) + args.num_tracks); args.entries[track] -= previous as u32; next -= 1; @@ -1206,12 +1212,12 @@ where } #[inline] - fn initialize_cache(ctrl: &KeyframesCtrl, iframe: usize, entries: &mut [u32]) -> usize { + fn initialize_cache(ctrl: &KeyframesCtrl<'_>, iframe: usize, entries: &mut [u32]) -> usize { if iframe > 0 { let iframe = (iframe - 1) * 2; - let offset = ctrl.iframe_desc()[iframe] as usize; - decode_gv4_stream(&ctrl.iframe_entries()[offset..], entries); - return (ctrl.iframe_desc()[iframe + 1] + 1) as usize; + let offset = ctrl.iframe_desc[iframe] as usize; + decode_gv4_stream(&ctrl.iframe_entries[offset..], entries); + return (ctrl.iframe_desc[iframe + 1] + 1) as usize; } else { let num_tracks = entries.len() as u32; for i in 0..num_tracks { @@ -1270,45 +1276,25 @@ where return 0; } - #[inline] - fn key_ratio(ctrl: &KeyframesCtrl, timepoints: &[f32], at: usize) -> f32 { - let timepoint; - if timepoints.len() <= u8::MAX as usize { - timepoint = timepoints[ctrl.ratios_u8()[at] as usize]; - } else { - timepoint = timepoints[ctrl.ratios_u16()[at] as usize]; - } - return timepoint; + #[inline(always)] + fn key_ratio(ctrl: &KeyframesCtrl<'_>, timepoints: &[f32], at: usize) -> f32 { + return timepoints[ctrl.ratios[at] as usize]; } - #[inline] - fn key_ratio_simd(ctrl: &KeyframesCtrl, timepoints: &[f32], ats: &[u32]) -> f32x4 { - let mut index = [0u16; 4]; - if timepoints.len() <= u8::MAX as usize { - let ratios = ctrl.ratios_u8(); - index[0] = ratios[ats[0] as usize] as u16; - index[1] = ratios[ats[1] as usize] as u16; - index[2] = ratios[ats[2] as usize] as u16; - index[3] = ratios[ats[3] as usize] as u16; - } else { - let ratios = ctrl.ratios_u16(); - index[0] = ratios[ats[0] as usize]; - index[1] = ratios[ats[1] as usize]; - index[2] = ratios[ats[2] as usize]; - index[3] = ratios[ats[3] as usize]; - }; + #[inline(always)] + fn key_ratio_simd(ctrl: &KeyframesCtrl<'_>, timepoints: &[f32], ats: &[u32]) -> f32x4 { return f32x4::from_array([ - timepoints[index[0] as usize], - timepoints[index[1] as usize], - timepoints[index[2] as usize], - timepoints[index[3] as usize], + timepoints[ctrl.ratios[ats[0] as usize] as usize], + timepoints[ctrl.ratios[ats[1] as usize] as usize], + timepoints[ctrl.ratios[ats[2] as usize] as usize], + timepoints[ctrl.ratios[ats[3] as usize] as usize], ]); } fn decompress_float3( args: DecompressArgs<'_, InterpSoaFloat3>, timepoints: &[f32], - ctrl: &KeyframesCtrl, + ctrl: &KeyframesCtrl<'_>, compressed: &[Float3Key], ) { for j in 0..args.outdated.len() { @@ -1320,10 +1306,10 @@ where let rights = &args.entries[i * 4..i * 4 + 4]; let lefts = [ - rights[0] - (ctrl.previouses()[rights[0] as usize] as u32), - rights[1] - (ctrl.previouses()[rights[1] as usize] as u32), - rights[2] - (ctrl.previouses()[rights[2] as usize] as u32), - rights[3] - (ctrl.previouses()[rights[3] as usize] as u32), + rights[0] - (ctrl.previouses[rights[0] as usize] as u32), + rights[1] - (ctrl.previouses[rights[1] as usize] as u32), + rights[2] - (ctrl.previouses[rights[2] as usize] as u32), + rights[3] - (ctrl.previouses[rights[3] as usize] as u32), ]; let k00 = compressed[lefts[0] as usize]; @@ -1348,7 +1334,7 @@ where fn decompress_quat( args: DecompressArgs<'_, InterpSoaQuaternion>, timepoints: &[f32], - ctrl: &KeyframesCtrl, + ctrl: &KeyframesCtrl<'_>, compressed: &[QuaternionKey], ) { for j in 0..args.outdated.len() { @@ -1360,10 +1346,10 @@ where let rights = &args.entries[i * 4..i * 4 + 4]; let lefts = [ - rights[0] - (ctrl.previouses()[rights[0] as usize] as u32), - rights[1] - (ctrl.previouses()[rights[1] as usize] as u32), - rights[2] - (ctrl.previouses()[rights[2] as usize] as u32), - rights[3] - (ctrl.previouses()[rights[3] as usize] as u32), + rights[0] - (ctrl.previouses[rights[0] as usize] as u32), + rights[1] - (ctrl.previouses[rights[1] as usize] as u32), + rights[2] - (ctrl.previouses[rights[2] as usize] as u32), + rights[3] - (ctrl.previouses[rights[3] as usize] as u32), ]; let k00 = compressed[lefts[0] as usize]; @@ -1459,6 +1445,7 @@ mod sampling_tests { use wasm_bindgen_test::*; use super::*; + use crate::animation::AnimationRaw; use crate::base::OzzBuf; fn make_buf(v: Vec) -> Rc>> { @@ -1533,77 +1520,46 @@ mod sampling_tests { return vec![Float3Key::new([f16(1.0); 3]); 8]; } - fn empty_ctrl_ratios(n: u8) -> Vec { + fn empty_ratios(n: u16) -> Vec { return vec![0, 0, 0, 0, n, n, n, n]; } - fn empty_ctrl_previouses() -> Vec { + fn empty_previouses() -> Vec { return vec![0, 0, 0, 0, 4, 4, 4, 4]; } + fn empty_animation_raw(duration: f32) -> AnimationRaw { + return AnimationRaw { + duration, + num_tracks: S as u32, + timepoints: vec![], + translations: empty_translations(), + t_ratios: empty_ratios(S as u16), + t_previouses: empty_previouses(), + rotations: empty_rotations(), + r_ratios: empty_ratios(S as u16), + r_previouses: empty_previouses(), + scales: empty_scales(), + s_ratios: empty_ratios(S as u16), + s_previouses: empty_previouses(), + ..Default::default() + }; + } + #[derive(Debug, Clone)] struct Frame { ratio: f32, transform: [(Vec3, Quat, Vec3); S], } - struct TestArgs { - duration: f32, - timepoints: Vec, - translations: Vec, - translations_ctrl_ratios: Vec, - translations_ctrl_previouses: Vec, - rotations: Vec, - rotations_ctrl_ratios: Vec, - rotations_ctrl_previouses: Vec, - scales: Vec, - scales_ctrl_ratios: Vec, - scales_ctrl_previouses: Vec, - frames: Vec>, - } - - impl Default for TestArgs { - fn default() -> TestArgs { - return TestArgs { - duration: 1.0, - timepoints: vec![], - translations: empty_translations(), - translations_ctrl_ratios: empty_ctrl_ratios(S as u8), - translations_ctrl_previouses: empty_ctrl_previouses(), - rotations: empty_rotations(), - rotations_ctrl_ratios: empty_ctrl_ratios(S as u8), - rotations_ctrl_previouses: empty_ctrl_previouses(), - scales: empty_scales(), - scales_ctrl_ratios: empty_ctrl_ratios(S as u8), - scales_ctrl_previouses: empty_ctrl_previouses(), - frames: vec![], - }; - } - } - - fn new_keyframes_ctrl(ratios: Vec, previouses: Vec) -> KeyframesCtrl { - return KeyframesCtrl::new(ratios, previouses, vec![], vec![], 1.0); - } - - fn execute_test(args: TestArgs) { - let animation = Rc::new(Animation::from_raw( - args.duration, - S, - String::new(), - args.timepoints, - new_keyframes_ctrl(args.translations_ctrl_ratios, args.translations_ctrl_previouses), - new_keyframes_ctrl(args.rotations_ctrl_ratios, args.rotations_ctrl_previouses), - new_keyframes_ctrl(args.scales_ctrl_ratios, args.scales_ctrl_previouses), - args.translations, - args.rotations, - args.scales, - )); + fn execute_test(animation: AnimationRaw, frames: Vec>) { + let animation = Rc::new(Animation::from_raw(&animation)); let mut job = SamplingJob::default(); job.set_animation(animation); job.set_context(SamplingContext::new(S)); let output = make_buf(vec![TX; S + 1]); - for frame in &args.frames { + for frame in frames.iter() { job.set_output(output.clone()); job.set_ratio(frame.ratio); job.run().unwrap(); @@ -1658,27 +1614,28 @@ mod sampling_tests { }; } - execute_test::<4>(TestArgs { - duration: 1.0, - timepoints: vec![0.0, 0.2, 0.4, 0.6, 1.0], - translations: vec![ - Float3Key::new([f16(-1.000000), 0, 0]), - Float3Key::new([f16(0.000000), 0, 0]), - Float3Key::new([f16(2.000000), 0, 0]), - Float3Key::new([f16(7.000000), 0, 0]), - Float3Key::new([f16(-1.000000), 0, 0]), - Float3Key::new([f16(0.000000), 0, 0]), - Float3Key::new([f16(6.000000), 0, 0]), - Float3Key::new([f16(7.000000), 0, 0]), - Float3Key::new([f16(8.000000), 0, 0]), - Float3Key::new([f16(9.000000), 0, 0]), - Float3Key::new([f16(10.000000), 0, 0]), - Float3Key::new([f16(11.000000), 0, 0]), - Float3Key::new([f16(9.000000), 0, 0]), - ], - translations_ctrl_ratios: vec![0, 0, 0, 0, 4, 4, 1, 1, 2, 3, 3, 4, 4], - translations_ctrl_previouses: vec![0, 0, 0, 0, 4, 4, 4, 4, 2, 2, 2, 1, 3], - frames: vec![ + let mut ar = empty_animation_raw::<4>(1.0); + ar.timepoints = vec![0.0, 0.2, 0.4, 0.6, 1.0]; + ar.translations = vec![ + Float3Key::new([f16(-1.000000), 0, 0]), + Float3Key::new([f16(0.000000), 0, 0]), + Float3Key::new([f16(2.000000), 0, 0]), + Float3Key::new([f16(7.000000), 0, 0]), + Float3Key::new([f16(-1.000000), 0, 0]), + Float3Key::new([f16(0.000000), 0, 0]), + Float3Key::new([f16(6.000000), 0, 0]), + Float3Key::new([f16(7.000000), 0, 0]), + Float3Key::new([f16(8.000000), 0, 0]), + Float3Key::new([f16(9.000000), 0, 0]), + Float3Key::new([f16(10.000000), 0, 0]), + Float3Key::new([f16(11.000000), 0, 0]), + Float3Key::new([f16(9.000000), 0, 0]), + ]; + ar.t_ratios = vec![0, 0, 0, 0, 4, 4, 1, 1, 2, 3, 3, 4, 4]; + ar.t_previouses = vec![0, 0, 0, 0, 4, 4, 4, 4, 2, 2, 2, 1, 3]; + execute_test::<4>( + ar, + vec![ frame(-0.2, -1.0, 0.0, 2.0, 7.0), frame(0.0, -1.0, 0.0, 2.0, 7.0), frame(0.0000001, -1.0, 0.0, 2.000002, 7.0), @@ -1697,54 +1654,49 @@ mod sampling_tests { frame(0.9999999, -1.0, 0.0, 11.0, 9.0), frame(0.0000001, -1.0, 0.0, 2.000002, 7.0), ], - ..Default::default() - }); + ); } #[test] #[wasm_bindgen_test] fn test_sampling_no_track() { - execute_test::<0>(TestArgs { - duration: 46.0, - ..Default::default() - }); + execute_test::<0>(empty_animation_raw::<0>(46.0), vec![]); } #[test] #[wasm_bindgen_test] fn test_sampling_1_track_0_key() { - execute_test::<1>(TestArgs { - duration: 46.0, - timepoints: vec![0.0, 1.0], - frames: (-2..12) + let mut ar = empty_animation_raw::<1>(46.0); + ar.timepoints = vec![0.0, 1.0]; + execute_test::<1>( + ar, + (-2..12) .map(|x| Frame { ratio: x as f32 / 10.0, transform: [(V0, QU, V1)], }) .collect::>(), - ..Default::default() - }); + ); } #[test] #[wasm_bindgen_test] fn test_sampling_1_track_1_key() { - let mut translations = empty_translations(); - translations[0] = Float3Key::new([f16(1.0), f16(-1.0), f16(5.0)]); - translations[4] = Float3Key::new([f16(1.0), f16(-1.0), f16(5.0)]); - - execute_test::<1>(TestArgs { - duration: 46.0, - timepoints: vec![0.0, 1.0], - translations, - frames: (-2..12) + let mut ar = empty_animation_raw::<1>(46.0); + ar.timepoints = vec![0.0, 1.0]; + ar.translations = empty_translations(); + ar.translations[0] = Float3Key::new([f16(1.0), f16(-1.0), f16(5.0)]); + ar.translations[4] = Float3Key::new([f16(1.0), f16(-1.0), f16(5.0)]); + + execute_test::<1>( + ar, + (-2..12) .map(|x| Frame { ratio: x as f32 / 10.0, transform: [(Vec3::new(1.0, -1.0, 5.0), QU, V1)], }) .collect::>(), - ..Default::default() - }); + ); } #[test] @@ -1757,7 +1709,13 @@ mod sampling_tests { }; } - let translations = vec![ + let mut ar = empty_animation_raw::<2>(46.0); + ar.timepoints = vec![0.0, 0.5 / 46.0, 0.8 / 46.0, 1.0]; + ar.t_ratios = vec![0, 0, 0, 0, 1, 3, 3, 3, 2, 3]; + ar.t_previouses = vec![0, 0, 0, 0, 4, 4, 4, 4, 4, 1]; + ar.r_ratios = empty_ratios(3); + ar.s_ratios = empty_ratios(3); + ar.translations = vec![ Float3Key::new([f16(1.0), f16(2.0), f16(4.0)]), Float3Key::new([f16(0.0); 3]), Float3Key::new([f16(0.0); 3]), @@ -1770,15 +1728,9 @@ mod sampling_tests { Float3Key::new([f16(2.0), f16(4.0), f16(8.0)]), ]; - execute_test::<2>(TestArgs { - duration: 46.0, - timepoints: vec![0.0, 0.5 / 46.0, 0.8 / 46.0, 1.0], - translations, - translations_ctrl_ratios: vec![0, 0, 0, 0, 1, 3, 3, 3, 2, 3], - translations_ctrl_previouses: vec![0, 0, 0, 0, 4, 4, 4, 4, 4, 1], - rotations_ctrl_ratios: empty_ctrl_ratios(3), - scales_ctrl_ratios: empty_ctrl_ratios(3), - frames: vec![ + execute_test::<2>( + ar, + vec![ // forward frame(0.0, Vec3::new(1.0, 2.0, 4.0)), frame(0.5 / 46.0, Vec3::new(1.0, 2.0, 4.0)), @@ -1791,15 +1743,23 @@ mod sampling_tests { frame(0.5 / 46.0, Vec3::new(1.0, 2.0, 4.0)), frame(0.0, Vec3::new(1.0, 2.0, 4.0)), ], - ..Default::default() - }); + ); } #[test] #[wasm_bindgen_test] #[rustfmt::skip] fn test_sampling_4_track_2_key() { - let translations = vec![ + let mut ar = empty_animation_raw::<4>(1.0); + ar.timepoints=vec![0.0, 0.5, 0.8, 1.0]; + ar.t_ratios=vec![0, 0, 0, 0, 1, 3, 3, 3, 2, 3]; + ar.t_previouses=vec![0, 0, 0, 0, 4, 4, 4, 4, 4, 1]; + ar.r_ratios=empty_ratios(3); + ar.r_previouses=empty_previouses(); + ar.s_ratios=vec![0, 0, 0, 0, 3, 3, 1, 3, 2, 3]; + ar.s_previouses=vec![0, 0, 0, 0, 4, 4, 4, 4, 2, 1]; + + ar.translations = vec![ Float3Key::new([f16(1.0), f16(2.0), f16(4.0)]), Float3Key::new([f16(0.0); 3]), Float3Key::new([f16(0.0); 3]), @@ -1812,10 +1772,10 @@ mod sampling_tests { Float3Key::new([f16(2.0), f16(4.0), f16(8.0)]), ]; - let mut rotations = empty_rotations(); - rotations[5] = QuaternionKey::new([65529, 65533, 32766]); + ar.rotations = empty_rotations(); + ar.rotations[5] = QuaternionKey::new([65529, 65533, 32766]); - let scales = vec![ + ar.scales = vec![ Float3Key::new([f16(1.0); 3]), Float3Key::new([f16(1.0); 3]), Float3Key::new([f16(0.0); 3]), @@ -1852,21 +1812,9 @@ mod sampling_tests { frames_raw.reverse(); frames.append(&mut frames_raw); - execute_test::<4>(TestArgs { - duration: 1.0, - timepoints: vec![0.0, 0.5, 0.8, 1.0], - translations, - translations_ctrl_ratios: vec![0, 0, 0, 0, 1, 3, 3, 3, 2, 3], - translations_ctrl_previouses: vec![0, 0, 0, 0, 4, 4, 4, 4, 4, 1], - rotations, - rotations_ctrl_ratios: empty_ctrl_ratios(3), - rotations_ctrl_previouses: empty_ctrl_previouses(), - scales, - scales_ctrl_ratios: vec![0, 0, 0, 0, 3, 3, 1, 3, 2, 3], - scales_ctrl_previouses: vec![0, 0, 0, 0, 4, 4, 4, 4, 2, 1], + execute_test::<4>(ar, frames, - ..Default::default() - }); + ); } #[test] @@ -1876,31 +1824,23 @@ mod sampling_tests { translations[0] = Float3Key::new([f16(1.0), f16(-1.0), f16(5.0)]); translations[4] = Float3Key::new([f16(1.0), f16(-1.0), f16(5.0)]); - let animation1 = Rc::new(Animation::from_raw( - 46.0, - 1, - String::new(), - vec![0.0, 1.0], - new_keyframes_ctrl(empty_ctrl_ratios(1), empty_ctrl_previouses()), - new_keyframes_ctrl(empty_ctrl_ratios(1), empty_ctrl_previouses()), - new_keyframes_ctrl(empty_ctrl_ratios(1), empty_ctrl_previouses()), - translations.clone(), - empty_rotations(), - empty_scales(), - )); - - let animation2 = Rc::new(Animation::from_raw( - 46.0, - 1, - String::new(), - vec![0.0, 1.0], - new_keyframes_ctrl(empty_ctrl_ratios(1), empty_ctrl_previouses()), - new_keyframes_ctrl(empty_ctrl_ratios(1), empty_ctrl_previouses()), - new_keyframes_ctrl(empty_ctrl_ratios(1), empty_ctrl_previouses()), + let animation_raw = AnimationRaw { + duration: 46.0, + num_tracks: 1, + timepoints: vec![0.0, 1.0], translations, - empty_rotations(), - empty_scales(), - )); + t_ratios: empty_ratios(1), + t_previouses: empty_previouses(), + rotations: empty_rotations(), + r_ratios: empty_ratios(1), + r_previouses: empty_previouses(), + scales: empty_scales(), + s_ratios: empty_ratios(1), + s_previouses: empty_previouses(), + ..Default::default() + }; + let animation1 = Rc::new(Animation::from_raw(&animation_raw)); + let animation2 = Rc::new(Animation::from_raw(&animation_raw)); let mut job = SamplingJob::default(); job.set_animation(animation1.clone()); diff --git a/src/skeleton.rs b/src/skeleton.rs index 95a607a..dd4f6c7 100644 --- a/src/skeleton.rs +++ b/src/skeleton.rs @@ -3,7 +3,9 @@ //! use bimap::BiHashMap; +use std::alloc::{self, Layout}; use std::io::Read; +use std::{mem, slice}; use crate::archive::Archive; use crate::base::{DeterministicState, OzzError, OzzIndex}; @@ -12,88 +14,57 @@ use crate::math::SoaTransform; /// Rexported `BiHashMap` in bimap crate. pub type JointHashMap = BiHashMap; -struct JointHashMapWrapper; - -#[cfg(feature = "rkyv")] -const _: () = { - use rkyv::collections::util::Entry; - use rkyv::ser::{ScratchSpace, Serializer}; - use rkyv::string::ArchivedString; - use rkyv::vec::{ArchivedVec, VecResolver}; - use rkyv::with::{ArchiveWith, DeserializeWith, SerializeWith}; - use rkyv::{Deserialize, Fallible}; - - impl ArchiveWith for JointHashMapWrapper { - type Archived = ArchivedVec>; - type Resolver = VecResolver; - - unsafe fn resolve_with(field: &JointHashMap, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - ArchivedVec::resolve_from_len(field.len(), pos, resolver, out); - } - } - - impl SerializeWith for JointHashMapWrapper - where - S: ScratchSpace + Serializer + ?Sized, - { - fn serialize_with(field: &JointHashMap, serializer: &mut S) -> Result { - return ArchivedVec::serialize_from_iter(field.iter().map(|(key, value)| Entry { key, value }), serializer); - } - } - - impl DeserializeWith>, JointHashMap, D> for JointHashMapWrapper - where - D: Fallible + ?Sized, - { - fn deserialize_with( - field: &ArchivedVec>, - deserializer: &mut D, - ) -> Result { - let mut result = JointHashMap::with_capacity_and_hashers( - field.len() as usize, - DeterministicState::new(), - DeterministicState::new(), - ); - for entry in field.iter() { - result.insert( - entry.key.deserialize(deserializer)?, - entry.value.deserialize(deserializer)?, - ); - } - return Ok(result); - } - } -}; - /// /// This runtime skeleton data structure provides a const-only access to joint /// hierarchy, joint names and rest-pose. /// /// Joint names, rest-poses and hierarchy information are all stored in separate -/// arrays of data (as opposed to joint structures for the RawSkeleton), in order +/// arrays of data (as opposed to joint structures for the SkeletonRaw), in order /// to closely match with the way runtime algorithms use them. Joint hierarchy is /// packed as an array of parent jont indices (16 bits), stored in depth-first /// order. This is enough to traverse the whole joint hierarchy. Use /// iter_depth_first() to implement a depth-first traversal utility. /// -#[derive(Debug, Default)] -#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug)] pub struct Skeleton { - joint_rest_poses: Vec, - joint_parents: Vec, - #[cfg_attr(feature = "rkyv", with(JointHashMapWrapper))] + size: usize, + num_joints: u32, + num_soa_joints: u32, + joint_rest_poses: *mut SoaTransform, joint_names: JointHashMap, + joint_parents: *mut i16, +} + +impl Drop for Skeleton { + fn drop(&mut self) { + if !self.joint_rest_poses.is_null() { + unsafe { + let layout = Layout::from_size_align_unchecked(self.size, mem::align_of::()); + alloc::dealloc(self.joint_rest_poses as *mut u8, layout); + } + self.joint_rest_poses = std::ptr::null_mut(); + self.joint_parents = std::ptr::null_mut(); + } + } } /// Skeleton meta in `Archive`. +#[derive(Debug)] pub struct SkeletonMeta { pub version: u32, - pub num_joints: i32, + pub num_joints: u32, pub joint_names: JointHashMap, pub joint_parents: Vec, } +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub(crate) struct SkeletonRaw { + pub joint_rest_poses: Vec, + pub joint_parents: Vec, + pub joint_names: JointHashMap, +} + impl Skeleton { /// `Skeleton` resource file tag for `Archive`. #[inline] @@ -107,19 +78,6 @@ impl Skeleton { return 2; } - #[cfg(test)] - pub(crate) fn from_raw( - joint_rest_poses: Vec, - joint_parents: Vec, - joint_names: JointHashMap, - ) -> Skeleton { - return Skeleton { - joint_rest_poses, - joint_parents, - joint_names, - }; - } - /// Reads a `SkeletonMeta` from a reader. pub fn read_meta(archive: &mut Archive, with_joints: bool) -> Result { if archive.tag() != Self::tag() { @@ -129,7 +87,7 @@ impl Skeleton { return Err(OzzError::InvalidVersion); } - let num_joints: i32 = archive.read()?; + let num_joints: u32 = archive.read()?; if num_joints == 0 || !with_joints { return Ok(SkeletonMeta { version: Self::version(), @@ -139,7 +97,7 @@ impl Skeleton { }); } - let _char_count: i32 = archive.read()?; + let _char_count: u32 = archive.read()?; let mut joint_names = BiHashMap::with_capacity_and_hashers( num_joints as usize, DeterministicState::new(), @@ -161,19 +119,17 @@ impl Skeleton { /// Reads a `Skeleton` from a reader. pub fn from_archive(archive: &mut Archive) -> Result { - let meta = Skeleton::read_meta(archive, true)?; + let meta = Skeleton::read_meta(archive, false)?; + let mut skeleton = Skeleton::new(meta); - let soa_num_joints = (meta.num_joints + 3) / 4; - let mut joint_rest_poses: Vec = Vec::with_capacity(soa_num_joints as usize); - for _ in 0..soa_num_joints { - joint_rest_poses.push(archive.read()?); + let _char_count: u32 = archive.read()?; + for idx in 0..skeleton.num_joints() { + skeleton.joint_names.insert(archive.read::()?, idx as i16); } - return Ok(Skeleton { - joint_rest_poses, - joint_parents: meta.joint_parents, - joint_names: meta.joint_names, - }); + archive.read_slice(skeleton.joint_parents_mut())?; + archive.read_slice(skeleton.joint_rest_poses_mut())?; + return Ok(skeleton); } /// Reads a `Skeleton` from a file. @@ -189,13 +145,66 @@ impl Skeleton { let mut archive = Archive::from_path(path)?; return Skeleton::from_archive(&mut archive); } + + pub(crate) fn from_raw(raw: &SkeletonRaw) -> Skeleton { + let mut skeleton = Skeleton::new(SkeletonMeta { + version: Self::version(), + num_joints: raw.joint_parents.len() as u32, + joint_names: BiHashMap::default(), + joint_parents: Vec::new(), + }); + skeleton.joint_rest_poses_mut().copy_from_slice(&raw.joint_rest_poses); + skeleton.joint_parents_mut().copy_from_slice(&raw.joint_parents); + skeleton.joint_names = raw.joint_names.clone(); + return skeleton; + } + + pub(crate) fn to_raw(&self) -> SkeletonRaw { + return SkeletonRaw { + joint_rest_poses: self.joint_rest_poses().to_vec(), + joint_parents: self.joint_parents().to_vec(), + joint_names: self.joint_names().clone(), + }; + } + + fn new(meta: SkeletonMeta) -> Skeleton { + let mut skeleton = Skeleton { + size: 0, + num_joints: meta.num_joints, + num_soa_joints: ((meta.num_joints + 3) / 4), + joint_rest_poses: std::ptr::null_mut(), + joint_parents: std::ptr::null_mut(), + joint_names: BiHashMap::with_capacity_and_hashers( + meta.num_joints as usize, + DeterministicState::new(), + DeterministicState::new(), + ), + }; + + const ALIGN: usize = mem::align_of::(); + skeleton.size = + mem::size_of::() * skeleton.num_soa_joints() + mem::size_of::() * skeleton.num_joints(); + + unsafe { + let layout = Layout::from_size_align_unchecked(skeleton.size, ALIGN); + let mut ptr = alloc::alloc(layout); + + skeleton.joint_rest_poses = ptr as *mut SoaTransform; + ptr = ptr.add(mem::size_of::() * skeleton.num_soa_joints()); + skeleton.joint_parents = ptr as *mut i16; + ptr = ptr.add(mem::size_of::() * skeleton.num_joints()); + + assert_eq!(ptr, (skeleton.joint_rest_poses as *mut u8).add(skeleton.size)); + } + return skeleton; + } } impl Skeleton { /// Gets the number of joints of `Skeleton`. #[inline] pub fn num_joints(&self) -> usize { - return self.joint_parents.len(); + return self.num_joints as usize; } /// Gets the number of joints of `Skeleton` (aligned to 4 * SoA). @@ -208,25 +217,18 @@ impl Skeleton { /// This value is useful to allocate SoA runtime data structures. #[inline] pub fn num_soa_joints(&self) -> usize { - return (self.joint_parents.len() + 3) / 4; + return self.num_soa_joints as usize; } /// Gets joint's rest poses. Rest poses are stored in soa format. #[inline] pub fn joint_rest_poses(&self) -> &[SoaTransform] { - return &self.joint_rest_poses; + return unsafe { slice::from_raw_parts(self.joint_rest_poses, self.num_soa_joints()) }; } - /// Gets joint's parent indices range. #[inline] - pub fn joint_parents(&self) -> &[i16] { - return &self.joint_parents; - } - - /// Gets joint's parent by index. - #[inline] - pub fn joint_parent(&self, idx: impl OzzIndex) -> i16 { - return self.joint_parents[idx.usize()]; + fn joint_rest_poses_mut(&mut self) -> &mut [SoaTransform] { + return unsafe { slice::from_raw_parts_mut(self.joint_rest_poses, self.num_soa_joints()) }; } /// Gets joint's name map. @@ -247,6 +249,22 @@ impl Skeleton { return self.joint_names.get_by_right(&index).map(|s| s.as_str()); } + /// Gets joint's parent indices range. + #[inline] + pub fn joint_parents(&self) -> &[i16] { + return unsafe { slice::from_raw_parts(self.joint_parents, self.num_joints()) }; + } + + fn joint_parents_mut(&mut self) -> &mut [i16] { + return unsafe { slice::from_raw_parts_mut(self.joint_parents, self.num_joints()) }; + } + + /// Gets joint's parent by index. + #[inline] + pub fn joint_parent(&self, idx: impl OzzIndex) -> i16 { + return self.joint_parents()[idx.usize()]; + } + /// Test if a joint is a leaf. /// /// * `joint` - `joint` must be in range [0, num joints]. @@ -288,6 +306,107 @@ impl Skeleton { } } +#[cfg(feature = "rkyv")] +pub struct ArchivedSkeleton { + pub num_joints: u32, + pub joint_rest_poses: rkyv::vec::ArchivedVec, + pub joint_names: rkyv::vec::ArchivedVec>, + pub joint_parents: rkyv::vec::ArchivedVec, +} + +#[cfg(feature = "rkyv")] +const _: () = { + use rkyv::collections::util::Entry; + use rkyv::ser::{ScratchSpace, Serializer}; + use rkyv::vec::{ArchivedVec, VecResolver}; + use rkyv::{from_archived, out_field, Archive, Deserialize, Fallible, Serialize}; + + pub struct SkeletonResolver { + joint_rest_poses: VecResolver, + joint_names: VecResolver, + joint_parents: VecResolver, + } + + impl Archive for Skeleton { + type Archived = ArchivedSkeleton; + type Resolver = SkeletonResolver; + + unsafe fn resolve(&self, pos: usize, resolver: SkeletonResolver, out: *mut ArchivedSkeleton) { + let (fp, fo) = out_field!(out.num_joints); + u32::resolve(&self.num_joints, pos + fp, (), fo); + let (fp, fo) = out_field!(out.joint_rest_poses); + ArchivedVec::resolve_from_slice(self.joint_rest_poses(), pos + fp, resolver.joint_rest_poses, fo); + let (fp, fo) = out_field!(out.joint_names); + ArchivedVec::resolve_from_len(self.joint_names().len(), pos + fp, resolver.joint_names, fo); + let (fp, fo) = out_field!(out.joint_parents); + ArchivedVec::resolve_from_slice(self.joint_parents(), pos + fp, resolver.joint_parents, fo); + } + } + + impl Serialize for Skeleton { + fn serialize(&self, serializer: &mut S) -> Result { + serializer.align_for::()?; + return Ok(SkeletonResolver { + joint_rest_poses: ArchivedVec::serialize_from_slice(self.joint_rest_poses(), serializer)?, + joint_names: ArchivedVec::serialize_from_iter( + self.joint_names().iter().map(|(key, value)| Entry { key, value }), + serializer, + )?, + joint_parents: ArchivedVec::serialize_from_slice(self.joint_parents(), serializer)?, + }); + } + } + + impl Deserialize for ArchivedSkeleton { + #[inline] + fn deserialize(&self, _: &mut D) -> Result { + let archived = from_archived!(self); + let mut skeleton = Skeleton::new(SkeletonMeta { + version: Skeleton::version(), + num_joints: archived.num_joints, + joint_names: BiHashMap::default(), + joint_parents: Vec::new(), + }); + skeleton + .joint_rest_poses_mut() + .copy_from_slice(archived.joint_rest_poses.as_slice()); + + skeleton.joint_names = JointHashMap::with_capacity_and_hashers( + archived.joint_names.len() as usize, + DeterministicState::new(), + DeterministicState::new(), + ); + for entry in archived.joint_names.iter() { + skeleton.joint_names.insert(entry.key.to_string(), entry.value); + } + + skeleton + .joint_parents_mut() + .copy_from_slice(archived.joint_parents.as_slice()); + return Ok(skeleton); + } + } +}; + +#[cfg(feature = "serde")] +const _: () = { + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + impl Serialize for Skeleton { + fn serialize(&self, serializer: S) -> Result { + let raw = self.to_raw(); + return raw.serialize(serializer); + } + } + + impl<'de> Deserialize<'de> for Skeleton { + fn deserialize>(deserializer: D) -> Result { + let raw = SkeletonRaw::deserialize(deserializer)?; + return Ok(Skeleton::from_raw(&raw)); + } + } +}; + #[cfg(test)] mod tests { use std::simd::prelude::*; @@ -383,4 +502,19 @@ mod tests { assert_eq!(skeleton.joint_parents(), skeleton2.joint_parents()); assert_eq!(skeleton.joint_names(), skeleton2.joint_names()); } + + #[cfg(feature = "serde")] + #[test] + #[wasm_bindgen_test] + fn test_serde_skeleton() { + use serde_json; + + let skeleton = Skeleton::from_path("./resource/blend/skeleton.ozz").unwrap(); + let josn = serde_json::to_vec(&skeleton).unwrap(); + let skeleton2: Skeleton = serde_json::from_slice(&josn).unwrap(); + + assert_eq!(skeleton.joint_rest_poses(), skeleton2.joint_rest_poses()); + assert_eq!(skeleton.joint_parents(), skeleton2.joint_parents()); + assert_eq!(skeleton.joint_names(), skeleton2.joint_names()); + } }