From ca1df6d61e304f9a42cbf104983cff467abbc51d Mon Sep 17 00:00:00 2001 From: Abe M Date: Wed, 14 Aug 2024 23:11:10 -0700 Subject: [PATCH 1/6] Refactors --- src/archive.rs | 57 +-- src/ik_aim_job.rs | 35 +- src/math.rs | 299 +++++++-------- src/sampling_job.rs | 723 +++++++++++++++++++++--------------- src/skeleton.rs | 111 +++++- src/skinning_job.rs | 67 ++-- src/track.rs | 56 +-- src/track_sampling_job.rs | 15 +- src/track_triggering_job.rs | 56 ++- 9 files changed, 824 insertions(+), 595 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 0f172f6..079e7bc 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -44,18 +44,18 @@ impl Archive { let version = archive.read::()?; archive.version = version; - return Ok(archive); + Ok(archive) } /// Reads `T` from the archive. pub fn read>(&mut self) -> Result { - return T::read(self); + T::read(self) } /// Reads `Vec` from the archive. /// * `count` - The number of elements to read. pub fn read_vec>(&mut self, count: usize) -> Result, OzzError> { - return T::read_vec(self, count); + T::read_vec(self, count) } /// Reads `[T]` from the archive into slice. @@ -66,17 +66,17 @@ impl Archive { /// Does the endian need to be swapped. pub fn endian_swap(&self) -> bool { - return self.endian_swap; + self.endian_swap } /// Gets the tag of the archive. pub fn tag(&self) -> &str { - return &self.tag; + &self.tag } /// Gets the version of the archive. pub fn version(&self) -> u32 { - return self.version; + self.version } } @@ -85,12 +85,12 @@ impl Archive { /// Creates an `Archive` from a path. pub fn from_path>(path: P) -> Result, OzzError> { let file = File::open(path)?; - return Archive::new(file); + Archive::new(file) } /// Creates an `Archive` from a file. pub fn from_file(file: File) -> Result, OzzError> { - return Archive::new(file); + Archive::new(file) } } @@ -98,7 +98,7 @@ impl Archive>> { /// Creates an `Archive` from a `Vec`. pub fn from_vec(buf: Vec) -> Result>>, OzzError> { let cursor = Cursor::new(buf); - return Archive::new(cursor); + Archive::new(cursor) } /// Creates an `Archive` from a path. @@ -115,7 +115,7 @@ impl Archive> { /// Creates an `Archive` from a `&[u8]`. pub fn from_slice(buf: &[u8]) -> Result>, OzzError> { let cursor = Cursor::new(buf); - return Archive::new(cursor); + Archive::new(cursor) } } @@ -132,7 +132,7 @@ pub trait ArchiveRead { for _ in 0..count { buffer.push(Self::read(archive)?); } - return Ok(buffer); + Ok(buffer) } /// Reads `[T]` from the archive into slice. @@ -152,13 +152,24 @@ macro_rules! primitive_reader { #[inline] fn read(archive: &mut Archive) -> Result<$type, OzzError> { let mut val = Default::default(); - archive.read.read_exact(unsafe { - slice::from_raw_parts_mut(&mut val as *const $type as *mut u8, mem::size_of::<$type>()) - })?; + let size = mem::size_of::<$type>(); + let ptr = &mut val as *mut $type as *mut u8; + + if size == 1 { + // Special case for u8 and i8 + archive + .read + .read_exact(unsafe { slice::from_raw_parts_mut(ptr, 1) })?; + } else { + archive + .read + .read_exact(unsafe { slice::from_raw_parts_mut(ptr, size) })?; + } + if !archive.endian_swap { - return Ok(val); + Ok(val) } else { - return Ok(val.swap_endian()); + Ok(val.swap_endian()) } } } @@ -182,7 +193,7 @@ impl ArchiveRead for Vec2 { fn read(archive: &mut Archive) -> Result { let x = f32::read(archive)?; let y = f32::read(archive)?; - return Ok(Vec2::new(x, y)); + Ok(Vec2::new(x, y)) } } @@ -192,7 +203,7 @@ impl ArchiveRead for Vec3 { let x = f32::read(archive)?; let y = f32::read(archive)?; let z = f32::read(archive)?; - return Ok(Vec3::new(x, y, z)); + Ok(Vec3::new(x, y, z)) } } @@ -203,7 +214,7 @@ impl ArchiveRead for Vec4 { let y = f32::read(archive)?; let z = f32::read(archive)?; let w = f32::read(archive)?; - return Ok(Vec4::new(x, y, z, w)); + Ok(Vec4::new(x, y, z, w)) } } @@ -214,7 +225,7 @@ impl ArchiveRead for Quat { let y = f32::read(archive)?; let z = f32::read(archive)?; let w = f32::read(archive)?; - return Ok(Quat::from_xyzw(x, y, z, w)); + Ok(Quat::from_xyzw(x, y, z, w)) } } @@ -231,7 +242,7 @@ impl ArchiveRead for String { } } let text = String::from_utf8(buffer).map_err(|e| e.utf8_error())?; - return Ok(text); + Ok(text) } } @@ -245,8 +256,6 @@ mod tests { #[wasm_bindgen_test] fn test_archive_new() { let archive = Archive::from_path("./resource/playback/animation.ozz").unwrap(); - assert_eq!(archive.endian_swap, false); - assert_eq!(archive.tag, "ozz-animation"); - assert_eq!(archive.version, 7); + assert!(!archive.endian_swap); } } diff --git a/src/ik_aim_job.rs b/src/ik_aim_job.rs index aa18db9..a17b0c0 100644 --- a/src/ik_aim_job.rs +++ b/src/ik_aim_job.rs @@ -59,7 +59,7 @@ impl IKAimJob { /// Gets target of `IKAimJob`. #[inline] pub fn target(&self) -> Vec3A { - return fx4_to_vec3a(self.target); + fx4_to_vec3a(self.target) } /// Sets target of `IKAimJob`. @@ -73,7 +73,7 @@ impl IKAimJob { /// Gets forward of `IKAimJob`. #[inline] pub fn forward(&self) -> Vec3A { - return fx4_to_vec3a(self.forward); + fx4_to_vec3a(self.forward) } /// Sets forward of `IKAimJob`. @@ -89,7 +89,7 @@ impl IKAimJob { /// Gets offset of `IKAimJob`. #[inline] pub fn offset(&self) -> Vec3A { - return fx4_to_vec3a(self.offset); + fx4_to_vec3a(self.offset) } /// Sets offset of `IKAimJob`. @@ -103,7 +103,7 @@ impl IKAimJob { /// Gets up of `IKAimJob`. #[inline] pub fn up(&self) -> Vec3A { - return fx4_to_vec3a(self.up); + fx4_to_vec3a(self.up) } /// Sets up of `IKAimJob`. @@ -118,7 +118,7 @@ impl IKAimJob { /// Gets pole vector of `IKAimJob`. #[inline] pub fn pole_vector(&self) -> Vec3A { - return fx4_to_vec3a(self.pole_vector); + fx4_to_vec3a(self.pole_vector) } /// Sets pole vector of `IKAimJob`. @@ -136,7 +136,7 @@ impl IKAimJob { /// Gets twist angle of `IKAimJob`. #[inline] pub fn twist_angle(&self) -> f32 { - return self.twist_angle; + self.twist_angle } /// Sets twist angle of `IKAimJob`. @@ -150,7 +150,7 @@ impl IKAimJob { /// Gets weight of `IKAimJob`. #[inline] pub fn weight(&self) -> f32 { - return self.weight; + self.weight } /// Sets weight of `IKAimJob`. @@ -165,7 +165,7 @@ impl IKAimJob { /// Gets joint of `IKAimJob`. #[inline] pub fn joint(&self) -> Mat4 { - return self.joint.into(); + self.joint.into() } /// Sets joint of `IKAimJob`. @@ -182,7 +182,7 @@ impl IKAimJob { /// It needs to be multiplied with joint local-space quaternion. #[inline] pub fn joint_correction(&self) -> Quat { - return fx4_to_quat(self.joint_correction); + fx4_to_quat(self.joint_correction) } /// Gets reached of `IKAimJob`. @@ -198,7 +198,7 @@ impl IKAimJob { /// Target is considered not reachable when target is between joint and offset position. #[inline] pub fn reached(&self) -> bool { - return self.reached; + self.reached } /// Gets reached of `IKAimJob`. @@ -217,7 +217,7 @@ impl IKAimJob { /// Validates `IKAimJob` parameters. #[inline] fn validate(&self) -> bool { - return vec3_is_normalized(self.forward); + vec3_is_normalized(self.forward) } /// Runs aim IK job's task. @@ -275,13 +275,12 @@ impl IKAimJob { rotate_plane_js = QUAT_UNIT; } - let twisted; - if self.twist_angle != 0.0 { + let twisted = if self.twist_angle != 0.0 { let twist_ss = quat_from_axis_angle(rotate_plane_axis_js, f32x4::splat(self.twist_angle)); - twisted = quat_mul(quat_mul(twist_ss, rotate_plane_js), joint_to_target_rot_js); + quat_mul(quat_mul(twist_ss, rotate_plane_js), joint_to_target_rot_js) } else { - twisted = quat_mul(rotate_plane_js, joint_to_target_rot_js); - } + quat_mul(rotate_plane_js, joint_to_target_rot_js) + }; let twisted_fu = quat_positive_w(twisted); if self.weight < 1.0 { @@ -290,7 +289,7 @@ impl IKAimJob { } else { self.joint_correction = twisted_fu; } - return Ok(()); + Ok(()) } fn compute_offsetted_forward(forward: f32x4, offset: f32x4, target: f32x4) -> Option { @@ -302,7 +301,7 @@ impl IKAimJob { } let ai_l = (r2 - ac_l2).sqrt(); let offsetted_forward = offset + forward * fx4_splat_x(ai_l - ao_l); - return Some(offsetted_forward); + Some(offsetted_forward) } } diff --git a/src/math.rs b/src/math.rs index fbbb40d..8410c5d 100644 --- a/src/math.rs +++ b/src/math.rs @@ -33,8 +33,8 @@ pub(crate) const Z_AXIS: f32x4 = f32x4::from_array([0.0, 0.0, 1.0, 0.0]); pub(crate) const QUAT_UNIT: f32x4 = f32x4::from_array([0.0, 0.0, 0.0, 1.0]); -const SIGN: i32x4 = i32x4::from_array([core::i32::MIN; 4]); -const SIGN_W: i32x4 = i32x4::from_array([0, 0, 0, core::i32::MIN]); +const SIGN: i32x4 = i32x4::from_array([i32::MIN; 4]); +const SIGN_W: i32x4 = i32x4::from_array([0, 0, 0, i32::MIN]); // // SoaVec3 @@ -52,30 +52,30 @@ pub struct SoaVec3 { impl SoaVec3 { #[inline] pub const fn new(x: [f32; 4], y: [f32; 4], z: [f32; 4]) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: f32x4::from_array(x), y: f32x4::from_array(y), z: f32x4::from_array(z), - }; + } } #[inline] pub const fn splat_row(v: f32x4) -> SoaVec3 { - return SoaVec3 { x: v, y: v, z: v }; + SoaVec3 { x: v, y: v, z: v } } #[inline] pub const fn splat_col(v: [f32; 3]) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: f32x4::from_array([v[0]; 4]), y: f32x4::from_array([v[1]; 4]), z: f32x4::from_array([v[2]; 4]), - }; + } } #[inline] pub fn col(&self, idx: usize) -> Vec3 { - return Vec3::new(self.x[idx], self.y[idx], self.z[idx]); + Vec3::new(self.x[idx], self.y[idx], self.z[idx]) } #[inline] @@ -87,74 +87,83 @@ impl SoaVec3 { #[inline] pub fn neg(&self) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: -self.x, y: -self.y, z: -self.z, - }; + } } #[inline] pub fn add(&self, other: &SoaVec3) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z, - }; + } } #[inline] pub fn sub(&self, other: &SoaVec3) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: self.x - other.x, y: self.y - other.y, z: self.z - other.z, - }; + } + } + + #[inline] + pub fn component_mul(&self, other: &SoaVec3) -> SoaVec3 { + SoaVec3 { + x: self.x * other.x, + y: self.y * other.y, + z: self.z * other.z, + } } #[inline] pub fn mul_num(&self, f: f32x4) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: self.x * f, y: self.y * f, z: self.z * f, - }; + } } #[inline] pub fn lerp(from: &SoaVec3, to: &SoaVec3, alpha: f32x4) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: (to.x - from.x) * alpha + from.x, y: (to.y - from.y) * alpha + from.y, z: (to.z - from.z) * alpha + from.z, - }; + } } #[inline] pub fn and_num(&self, i: i32x4) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: fx4_and(self.x, i), y: fx4_and(self.y, i), z: fx4_and(self.z, i), - }; + } } #[inline] pub fn or_num(&self, i: i32x4) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: fx4_or(self.x, i), y: fx4_or(self.y, i), z: fx4_or(self.z, i), - }; + } } #[inline] pub fn xor_num(&self, i: i32x4) -> SoaVec3 { - return SoaVec3 { + SoaVec3 { x: fx4_xor(self.x, i), y: fx4_xor(self.y, i), z: fx4_xor(self.z, i), - }; + } } } @@ -177,14 +186,14 @@ const _: () = { impl Serialize for SoaVec3 { #[inline] fn serialize(&self, _: &mut S) -> Result { - return Ok(()); + Ok(()) } } impl Deserialize for SoaVec3 { #[inline] fn deserialize(&self, _: &mut D) -> Result { - return Ok(from_archived!(*self)); + Ok(from_archived!(*self)) } } @@ -196,7 +205,7 @@ const _: () = { if value as usize % mem::align_of::() != 0 { return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes")); } - return Ok(&*value); + Ok(&*value) } } }; @@ -212,14 +221,14 @@ const _: () = { seq.serialize_element(&self.x.as_array())?; seq.serialize_element(&self.y.as_array())?; seq.serialize_element(&self.z.as_array())?; - return seq.end(); + seq.end() } } impl<'de> Deserialize<'de> for SoaVec3 { fn deserialize>(deserializer: D) -> Result { let tmp: [[f32; 4]; 3] = Deserialize::deserialize(deserializer)?; - return Ok(SoaVec3::new(tmp[0], tmp[1], tmp[2])); + Ok(SoaVec3::new(tmp[0], tmp[1], tmp[2])) } } }; @@ -241,32 +250,32 @@ pub struct SoaQuat { impl SoaQuat { #[inline] pub const fn new(x: [f32; 4], y: [f32; 4], z: [f32; 4], w: [f32; 4]) -> SoaQuat { - return SoaQuat { + SoaQuat { x: f32x4::from_array(x), y: f32x4::from_array(y), z: f32x4::from_array(z), w: f32x4::from_array(w), - }; + } } #[inline] pub const fn splat_row(v: f32x4) -> SoaQuat { - return SoaQuat { x: v, y: v, z: v, w: v }; + SoaQuat { x: v, y: v, z: v, w: v } } #[inline] pub const fn splat_col(v: [f32; 4]) -> SoaQuat { - return SoaQuat { + SoaQuat { x: f32x4::from_array([v[0]; 4]), y: f32x4::from_array([v[1]; 4]), z: f32x4::from_array([v[2]; 4]), w: f32x4::from_array([v[3]; 4]), - }; + } } #[inline] pub fn col(&self, idx: usize) -> Quat { - return Quat::from_xyzw(self.x[idx], self.y[idx], self.z[idx], self.w[idx]); + Quat::from_xyzw(self.x[idx], self.y[idx], self.z[idx], self.w[idx]) } #[inline] @@ -279,22 +288,22 @@ impl SoaQuat { #[inline] pub fn conjugate(&self) -> SoaQuat { - return SoaQuat { + SoaQuat { x: -self.x, y: -self.y, z: -self.z, w: self.w, - }; + } } #[inline] pub fn add(&self, other: &SoaQuat) -> SoaQuat { - return SoaQuat { + SoaQuat { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z, w: self.w + other.w, - }; + } } #[inline] @@ -303,34 +312,34 @@ impl SoaQuat { let y = self.w * other.y + self.y * other.w + self.z * other.x - self.x * other.z; let z = self.w * other.z + self.z * other.w + self.x * other.y - self.y * other.x; let w = self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z; - return SoaQuat { x, y, z, w }; + SoaQuat { x, y, z, w } } #[inline] pub fn mul_num(&self, f: f32x4) -> SoaQuat { - return SoaQuat { + SoaQuat { x: self.x * f, y: self.y * f, z: self.z * f, w: self.w * f, - }; + } } #[inline] pub fn normalize(&self) -> SoaQuat { let len2 = self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w; let inv_len = len2.sqrt().recip(); - return SoaQuat { + SoaQuat { x: self.x * inv_len, y: self.y * inv_len, z: self.z * inv_len, w: self.w * inv_len, - }; + } } #[inline] pub fn dot(&self, other: &SoaQuat) -> f32x4 { - return self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w; + self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w } #[inline] @@ -341,53 +350,53 @@ impl SoaQuat { let lerp_w = (other.w - self.w) * f + self.w; let len2 = lerp_x * lerp_x + lerp_y * lerp_y + lerp_z * lerp_z + lerp_w * lerp_w; let inv_len = len2.sqrt().recip(); - return SoaQuat { + SoaQuat { x: lerp_x * inv_len, y: lerp_y * inv_len, z: lerp_z * inv_len, w: lerp_w * inv_len, - }; + } } #[inline] pub fn and_num(&self, i: i32x4) -> SoaQuat { - return SoaQuat { + SoaQuat { x: fx4_and(self.x, i), y: fx4_and(self.y, i), z: fx4_and(self.z, i), w: fx4_and(self.w, i), - }; + } } #[inline] pub fn or_num(&self, i: i32x4) -> SoaQuat { - return SoaQuat { + SoaQuat { x: fx4_or(self.x, i), y: fx4_or(self.y, i), z: fx4_or(self.z, i), w: fx4_or(self.w, i), - }; + } } #[inline] pub fn xor_num(&self, i: i32x4) -> SoaQuat { - return SoaQuat { + SoaQuat { x: fx4_xor(self.x, i), y: fx4_xor(self.y, i), z: fx4_xor(self.z, i), w: fx4_xor(self.w, i), - }; + } } #[inline] pub fn positive_w(&self) -> SoaQuat { let sign = fx4_sign(self.w); - return SoaQuat { + SoaQuat { x: fx4_xor(self.x, sign), y: fx4_xor(self.y, sign), z: fx4_xor(self.z, sign), w: fx4_xor(self.w, sign), - }; + } } } @@ -410,14 +419,14 @@ const _: () = { impl Serialize for SoaQuat { #[inline] fn serialize(&self, _: &mut S) -> Result { - return Ok(()); + Ok(()) } } impl Deserialize for SoaQuat { #[inline] fn deserialize(&self, _: &mut D) -> Result { - return Ok(from_archived!(*self)); + Ok(from_archived!(*self)) } } @@ -429,7 +438,7 @@ const _: () = { if value as usize % mem::align_of::() != 0 { return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes")); } - return Ok(&*value); + Ok(&*value) } } }; @@ -446,14 +455,14 @@ const _: () = { seq.serialize_element(&self.y.as_array())?; seq.serialize_element(&self.z.as_array())?; seq.serialize_element(&self.w.as_array())?; - return seq.end(); + seq.end() } } impl<'de> Deserialize<'de> for SoaQuat { fn deserialize>(deserializer: D) -> Result { let tmp: [[f32; 4]; 4] = Deserialize::deserialize(deserializer)?; - return Ok(SoaQuat::new(tmp[0], tmp[1], tmp[2], tmp[3])); + Ok(SoaQuat::new(tmp[0], tmp[1], tmp[2], tmp[3])) } } }; @@ -480,18 +489,18 @@ impl ArchiveRead for SoaTransform { for idx in 0..COUNT { buffer[idx] = archive.read()?; } - return Ok(unsafe { mem::transmute(buffer) }); + Ok(unsafe { mem::transmute(buffer) }) } } impl SoaTransform { #[inline] pub fn new(translation: SoaVec3, rotation: SoaQuat, scale: SoaVec3) -> SoaTransform { - return SoaTransform { + SoaTransform { translation, rotation, scale, - }; + } } } @@ -514,14 +523,14 @@ const _: () = { impl Serialize for SoaTransform { #[inline] fn serialize(&self, _: &mut S) -> Result { - return Ok(()); + Ok(()) } } impl Deserialize for SoaTransform { #[inline] fn deserialize(&self, _: &mut D) -> Result { - return Ok(from_archived!(*self)); + Ok(from_archived!(*self)) } } @@ -533,7 +542,7 @@ const _: () = { if value as usize % mem::align_of::() != 0 { return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes")); } - return Ok(&*value); + Ok(&*value) } } }; @@ -552,13 +561,13 @@ const_assert_eq!(mem::size_of::(), mem::size_of::()); impl From for AosMat4 { fn from(mat: Mat4) -> AosMat4 { - return unsafe { mem::transmute(mat) }; + unsafe { mem::transmute(mat) } } } impl Into for AosMat4 { fn into(self) -> Mat4 { - return unsafe { mem::transmute(self) }; + unsafe { mem::transmute(self) } } } @@ -571,50 +580,50 @@ impl AosMat4 { n20: f32, n21: f32, n22: f32, n23: f32, n30: f32, n31: f32, n32: f32, n33: f32, ) -> AosMat4 { - return AosMat4 { + AosMat4 { cols: [ f32x4::from_array([n00, n01, n02, n03]), f32x4::from_array([n10, n11, n12, n13]), f32x4::from_array([n20, n21, n22, n23]), f32x4::from_array([n30, n31, n32, n33]), ], - }; + } } #[inline] pub(crate) fn new_translation(t: Vec3) -> AosMat4 { - return AosMat4 { + AosMat4 { cols: [ f32x4::from_array([1.0, 0.0, 0.0, 0.0]), f32x4::from_array([0.0, 1.0, 0.0, 0.0]), f32x4::from_array([0.0, 0.0, 1.0, 0.0]), f32x4::from_array([t.x, t.y, t.z, 1.0]), ], - }; + } } #[inline] pub(crate) fn new_scaling(s: Vec3) -> AosMat4 { - return AosMat4 { + AosMat4 { cols: [ f32x4::from_array([s.x, 0.0, 0.0, 0.0]), f32x4::from_array([0.0, s.y, 0.0, 0.0]), f32x4::from_array([0.0, 0.0, s.z, 0.0]), f32x4::from_array([0.0, 0.0, 0.0, 1.0]), ], - }; + } } #[inline] pub(crate) fn identity() -> AosMat4 { - return AosMat4 { + AosMat4 { cols: [ f32x4::from_array([1.0, 0.0, 0.0, 0.0]), f32x4::from_array([0.0, 1.0, 0.0, 0.0]), f32x4::from_array([0.0, 0.0, 1.0, 0.0]), f32x4::from_array([0.0, 0.0, 0.0, 1.0]), ], - }; + } } pub(crate) fn mul(&self, other: &AosMat4) -> AosMat4 { @@ -649,7 +658,7 @@ impl AosMat4 { let a23 = simd_swizzle!(other.cols[3], W) * self.cols[3] + zzzz; result.cols[3] = a01 + a23; - return result; + result } pub(crate) fn invert(&self) -> AosMat4 { @@ -670,7 +679,6 @@ impl AosMat4 { let mut minor2; let mut minor3; let mut tmp1; - let tmp2; tmp1 = simd_swizzle!(c2 * c3, IB1); minor0 = c1 * tmp1; @@ -684,17 +692,17 @@ impl AosMat4 { minor0 = c3 * tmp1 + minor0; minor3 = c0 * tmp1; tmp1 = simd_swizzle!(tmp1, I4E); - minor0 = minor0 - c3 * tmp1; + minor0 -= c3 * tmp1; minor3 = c0 * tmp1 - minor3; minor3 = simd_swizzle!(minor3, I4E); tmp1 = simd_swizzle!(c1, I4E) * c3; tmp1 = simd_swizzle!(tmp1, IB1); - tmp2 = simd_swizzle!(c2, I4E); + let tmp2 = simd_swizzle!(c2, I4E); minor0 = tmp2 * tmp1 + minor0; minor2 = c0 * tmp1; tmp1 = simd_swizzle!(tmp1, I4E); - minor0 = minor0 - tmp2 * tmp1; + minor0 -= tmp2 * tmp1; minor2 = c0 * tmp1 - minor2; minor2 = simd_swizzle!(minor2, I4E); @@ -703,20 +711,20 @@ impl AosMat4 { minor3 = tmp2 * tmp1 - minor3; tmp1 = simd_swizzle!(tmp1, I4E); minor2 = c3 * tmp1 - minor2; - minor3 = minor3 - tmp2 * tmp1; + minor3 -= tmp2 * tmp1; tmp1 = simd_swizzle!(c0 * c3, IB1); - minor1 = minor1 - tmp2 * tmp1; + minor1 -= tmp2 * tmp1; minor2 = c1 * tmp1 + minor2; tmp1 = simd_swizzle!(tmp1, I4E); minor1 = tmp2 * tmp1 + minor1; - minor2 = minor2 - c1 * tmp1; + minor2 -= c1 * tmp1; tmp1 = simd_swizzle!(c0 * tmp2, IB1); minor1 = c3 * tmp1 + minor1; - minor3 = minor3 - c1 * tmp1; + minor3 -= c1 * tmp1; tmp1 = simd_swizzle!(tmp1, I4E); - minor1 = minor1 - c3 * tmp1; + minor1 -= c3 * tmp1; minor3 = c1 * tmp1 + minor3; let mut det = c0 * minor0; @@ -729,9 +737,9 @@ impl AosMat4 { tmp1 = fx4((ix4(det_recip) & invertible) | (!invertible & ix4(ZERO))); // first det = (tmp1 + tmp1) - det * (tmp1 * tmp1); // first det = fx4_splat_x(det); - return AosMat4 { + AosMat4 { cols: [det * minor0, det * minor1, det * minor2, det * minor3], - }; + } } #[inline] @@ -739,7 +747,7 @@ impl AosMat4 { let xxxx = simd_swizzle!(p, [0; 4]) * self.cols[0]; let a23 = simd_swizzle!(p, [2; 4]) * self.cols[2] + self.cols[3]; let a01 = simd_swizzle!(p, [1; 4]) * self.cols[1] + xxxx; - return a01 + a23; + a01 + a23 } #[inline] @@ -747,7 +755,7 @@ impl AosMat4 { let xxxx = simd_swizzle!(p, [0; 4]) * self.cols[0]; let zzzz = simd_swizzle!(p, [1; 4]) * self.cols[1]; let a21 = simd_swizzle!(p, [2; 4]) * self.cols[2] + xxxx; - return zzzz + a21; + zzzz + a21 } } @@ -773,7 +781,7 @@ impl SoaMat4 { let yw = rotation.y * rotation.w; let zz = rotation.z * rotation.z; let zw = rotation.z * rotation.w; - return SoaMat4 { + SoaMat4 { cols: [ scale.x * (ONE - TWO * (yy + zz)), scale.x * TWO * (xy + zw), @@ -792,10 +800,10 @@ impl SoaMat4 { translation.z, ONE, ], - }; + } } - pub(crate) fn to_aos(&self) -> [AosMat4; 4] { + pub(crate) fn to_aos(self) -> [AosMat4; 4] { const LOW: [usize; 4] = [0, 4, 1, 5]; const HIGH: [usize; 4] = [2, 6, 3, 7]; @@ -834,7 +842,7 @@ impl SoaMat4 { aos[11] = simd_swizzle!(tmp14, tmp15, LOW); aos[15] = simd_swizzle!(tmp14, tmp15, HIGH); - return unsafe { mem::transmute(aos) }; + unsafe { mem::transmute(aos) } } } @@ -882,108 +890,108 @@ pub(crate) fn simd_f16_to_f32(half4: [u16; 4]) -> f32x4 { let infnanexp = was_infnan & EXP_INFNAN; let sign_inf = sign | infnanexp; let float4 = ix4(scaled) | sign_inf; - return fx4(float4); + fx4(float4) } #[inline(always)] pub(crate) const fn fx4(v: i32x4) -> f32x4 { - return unsafe { mem::transmute(v) }; + unsafe { mem::transmute(v) } } #[inline(always)] pub(crate) const fn ix4(v: f32x4) -> i32x4 { - return unsafe { mem::transmute(v) }; + unsafe { mem::transmute(v) } } const_assert_eq!(mem::size_of::(), mem::size_of::()); #[inline(always)] pub(crate) fn fx4_from_vec3a(v: Vec3A) -> f32x4 { - return unsafe { mem::transmute(v) }; + unsafe { mem::transmute(v) } } #[inline(always)] pub(crate) fn fx4_to_vec3a(v: f32x4) -> Vec3A { - return unsafe { mem::transmute(v) }; + unsafe { mem::transmute(v) } } const_assert_eq!(mem::size_of::(), mem::size_of::()); #[inline(always)] pub(crate) fn fx4_from_vec4(v: Vec4) -> f32x4 { - return unsafe { mem::transmute(v) }; + unsafe { mem::transmute(v) } } #[inline(always)] pub(crate) fn fx4_to_vec4(v: f32x4) -> Vec4 { - return unsafe { mem::transmute(v) }; + unsafe { mem::transmute(v) } } const_assert_eq!(mem::size_of::(), mem::size_of::()); #[inline(always)] pub(crate) fn fx4_from_quat(q: Quat) -> f32x4 { - return unsafe { mem::transmute(q) }; + unsafe { mem::transmute(q) } } #[inline(always)] pub(crate) fn fx4_to_quat(q: f32x4) -> Quat { - return unsafe { mem::transmute(q) }; + unsafe { mem::transmute(q) } } #[inline(always)] pub(crate) fn fx4_set_y(a: f32x4, b: f32x4) -> f32x4 { - return simd_swizzle!(a, b, [0, 4, 2, 3]); + simd_swizzle!(a, b, [0, 4, 2, 3]) } #[inline(always)] pub(crate) fn fx4_set_z(a: f32x4, b: f32x4) -> f32x4 { - return simd_swizzle!(a, b, [0, 1, 4, 3]); + simd_swizzle!(a, b, [0, 1, 4, 3]) } #[inline(always)] pub(crate) fn fx4_set_w(a: f32x4, b: f32x4) -> f32x4 { - return simd_swizzle!(a, b, [0, 1, 2, 4]); + simd_swizzle!(a, b, [0, 1, 2, 4]) } #[inline(always)] pub(crate) fn fx4_splat_x(v: f32x4) -> f32x4 { - return simd_swizzle!(v, [0, 0, 0, 0]); + simd_swizzle!(v, [0, 0, 0, 0]) } #[inline(always)] pub(crate) fn fx4_splat_y(v: f32x4) -> f32x4 { - return simd_swizzle!(v, [1, 1, 1, 1]); + simd_swizzle!(v, [1, 1, 1, 1]) } #[inline(always)] pub(crate) fn fx4_splat_z(v: f32x4) -> f32x4 { - return simd_swizzle!(v, [2, 2, 2, 2]); + simd_swizzle!(v, [2, 2, 2, 2]) } #[inline(always)] pub(crate) fn fx4_splat_w(v: f32x4) -> f32x4 { - return simd_swizzle!(v, [3, 3, 3, 3]); + simd_swizzle!(v, [3, 3, 3, 3]) } #[inline(always)] pub(crate) fn ix4_splat_x(v: i32x4) -> i32x4 { - return simd_swizzle!(v, [0, 0, 0, 0]); + simd_swizzle!(v, [0, 0, 0, 0]) } #[inline(always)] pub(crate) fn ix4_splat_y(v: i32x4) -> i32x4 { - return simd_swizzle!(v, [1, 1, 1, 1]); + simd_swizzle!(v, [1, 1, 1, 1]) } #[inline(always)] pub(crate) fn ix4_splat_z(v: i32x4) -> i32x4 { - return simd_swizzle!(v, [2, 2, 2, 2]); + simd_swizzle!(v, [2, 2, 2, 2]) } #[inline(always)] pub(crate) fn ix4_splat_w(v: i32x4) -> i32x4 { - return simd_swizzle!(v, [3, 3, 3, 3]); + simd_swizzle!(v, [3, 3, 3, 3]) } #[inline(always)] @@ -991,46 +999,46 @@ pub(crate) fn fx4_sign(v: f32x4) -> i32x4 { // In some case, x86_64 and aarch64 may produce different sign NaN (+/-NaN) in same command. // So the result of `NaN & SIGN` may be different. // For cross-platform deterministic, we want to make sure the sign of NaN is always 0(+). - return v.simd_lt(ZERO).to_int() & SIGN; + v.simd_lt(ZERO).to_int() & SIGN } #[inline(always)] pub(crate) fn fx4_and(v: f32x4, s: i32x4) -> f32x4 { - return fx4(ix4(v) & s); + fx4(ix4(v) & s) } #[inline(always)] pub(crate) fn fx4_or(v: f32x4, s: i32x4) -> f32x4 { - return fx4(ix4(v) | s); + fx4(ix4(v) | s) } #[inline(always)] pub(crate) fn fx4_xor(v: f32x4, s: i32x4) -> f32x4 { - return fx4(ix4(v) ^ s); + fx4(ix4(v) ^ s) } #[inline(always)] pub(crate) fn fx4_clamp_or_max(v: f32x4, min: f32x4, max: f32x4) -> f32x4 { // f32x4::clamp may produce NaN if self is NaN. // This implementation always returns max if self is NaN. - return v.simd_min(max).simd_max(min); + v.simd_min(max).simd_max(min) } #[inline(always)] pub(crate) fn fx4_clamp_or_min(v: f32x4, min: f32x4, max: f32x4) -> f32x4 { // f32x4::clamp may produce NaN if self is NaN. // This implementation always returns min if self is NaN. - return v.simd_max(min).simd_min(max); + v.simd_max(min).simd_min(max) } #[inline(always)] pub(crate) fn f32_clamp_or_max(v: f32, min: f32, max: f32) -> f32 { - return v.min(max).max(min); + v.min(max).max(min) } #[inline(always)] pub(crate) fn f32_clamp_or_min(v: f32, min: f32, max: f32) -> f32 { - return v.max(min).min(max); + v.max(min).min(max) } pub(crate) fn fx4_sin_cos(v: f32x4) -> (f32x4, f32x4) { @@ -1099,31 +1107,31 @@ pub(crate) fn fx4_sin_cos(v: f32x4) -> (f32x4, f32x4) { let c = cond.select(taylor_sin, taylor_cos); // Update the signs - sin_sign = sin_sign ^ bit2; + sin_sign ^= bit2; let cos_sign = bit1 ^ bit2; // Correct the signs let out_sin = fx4_xor(s, sin_sign); let out_cos = fx4_xor(c, cos_sign); - return (out_sin, out_cos); + (out_sin, out_cos) } #[inline] pub fn f32_sin_cos(x: f32) -> (f32, f32) { let (sin, cos) = fx4_sin_cos(f32x4::splat(x)); - return (sin[0], cos[0]); + (sin[0], cos[0]) } #[inline] pub fn f32_sin(x: f32) -> f32 { let (sin, _) = fx4_sin_cos(f32x4::splat(x)); - return sin[0]; + sin[0] } #[inline] pub fn f32_cos(x: f32) -> f32 { let (_, cos) = fx4_sin_cos(f32x4::splat(x)); - return cos[0]; + cos[0] } pub(crate) fn fx4_asin(v: f32x4) -> f32x4 { @@ -1163,28 +1171,28 @@ pub(crate) fn fx4_asin(v: f32x4) -> f32x4 { z = greater.select(FRAC_PI_2 - (z + z), z); // Put the sign back - return fx4_xor(z, asin_sign); + fx4_xor(z, asin_sign) } #[inline] pub(crate) fn fx4_acos(v: f32x4) -> f32x4 { const FRAC_PI_2: f32x4 = f32x4::from_array([core::f32::consts::FRAC_PI_2; 4]); - return FRAC_PI_2 - fx4_asin(v); + FRAC_PI_2 - fx4_asin(v) } #[inline] pub fn f32_asin(x: f32) -> f32 { - return fx4_asin(f32x4::splat(x))[0]; + fx4_asin(f32x4::splat(x))[0] } #[inline] pub fn f32_acos(x: f32) -> f32 { - return fx4_acos(f32x4::splat(x))[0]; + fx4_acos(f32x4::splat(x))[0] } #[inline] pub(crate) fn fx4_lerp(from: f32x4, to: f32x4, alpha: f32x4) -> f32x4 { - return alpha * (to - from) + from; + alpha * (to - from) + from } #[inline] @@ -1192,31 +1200,31 @@ pub(crate) fn vec3_is_normalized(v: f32x4) -> bool { const MAX: f32 = 1.0 + 0.002; const MIN: f32 = 1.0 - 0.002; let len2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; - return (MIN < len2) & (len2 < MAX); + (MIN < len2) & (len2 < MAX) } #[inline] pub(crate) fn vec3_length2_s(v: f32x4) -> f32x4 { - return vec3_dot_s(v, v); + vec3_dot_s(v, v) } #[inline] pub(crate) fn vec3_dot_s(a: f32x4, b: f32x4) -> f32x4 { let tmp = a * b; - return tmp + simd_swizzle!(tmp, [1; 4]) + simd_swizzle!(tmp, [2; 4]); + tmp + simd_swizzle!(tmp, [1; 4]) + simd_swizzle!(tmp, [2; 4]) } pub(crate) fn vec3_cross(a: f32x4, b: f32x4) -> f32x4 { let shufa = simd_swizzle!(a, [1, 2, 0, 3]); let shufb = simd_swizzle!(b, [1, 2, 0, 3]); let shufc = a * shufb - b * shufa; - return simd_swizzle!(shufc, [1, 2, 0, 3]); + simd_swizzle!(shufc, [1, 2, 0, 3]) } pub(crate) fn quat_from_axis_angle(axis: f32x4, angle: f32x4) -> f32x4 { let half_angle = fx4_splat_x(angle) * FRAC_1_2; let (half_sin, half_cos) = fx4_sin_cos(half_angle); - return fx4_set_w(axis * half_sin, half_cos); + fx4_set_w(axis * half_sin, half_cos) } pub(crate) fn quat_from_cos_angle(axis: f32x4, cos: f32x4) -> f32x4 { @@ -1225,7 +1233,7 @@ pub(crate) fn quat_from_cos_angle(axis: f32x4, cos: f32x4) -> f32x4 { let half_cossin2 = fx4_set_y(half_cos2, half_sin2); let half_cossin = half_cossin2.sqrt(); let half_sin = fx4_splat_y(half_cossin); - return fx4_set_w(axis * half_sin, half_cossin); + fx4_set_w(axis * half_sin, half_cossin) } pub(crate) fn quat_from_vectors(from: f32x4, to: f32x4) -> f32x4 { @@ -1249,13 +1257,13 @@ pub(crate) fn quat_from_vectors(from: f32x4, to: f32x4) -> f32x4 { quat = fx4_set_w(vec3_cross(from, to), real_part) }; - return quat_normalize(quat); + quat_normalize(quat) } #[inline] pub(crate) fn quat_length2_s(q: f32x4) -> f32x4 { let q2 = (q * q).reduce_sum(); - return f32x4::splat(q2); + f32x4::splat(q2) } #[inline] @@ -1263,14 +1271,14 @@ pub(crate) fn quat_normalize(q: f32x4) -> f32x4 { let q2 = q * q; let len2 = q2.reduce_sum(); let inv_len = f32x4::splat(len2).sqrt().recip(); - return q * inv_len; + q * inv_len } #[inline] pub(crate) fn quat_transform_vector(q: f32x4, v: f32x4) -> f32x4 { let cross1 = fx4_splat_w(q) * v + vec3_cross(q, v); let cross2 = vec3_cross(q, cross1); - return v + cross2 + cross2; + v + cross2 + cross2 } #[inline] @@ -1279,13 +1287,13 @@ pub(crate) fn quat_mul(a: f32x4, b: f32x4) -> f32x4 { let p2 = simd_swizzle!(a, [0, 1, 2, 0]) * simd_swizzle!(b, [3, 3, 3, 0]); let p13 = simd_swizzle!(a, [1, 2, 0, 1]) * simd_swizzle!(b, [2, 0, 1, 1]) + p1; let p24 = p2 - simd_swizzle!(a, [2, 0, 1, 3]) * simd_swizzle!(b, [1, 2, 0, 3]); - return fx4_xor(p13 + p24, SIGN_W); + fx4_xor(p13 + p24, SIGN_W) } #[inline] pub(crate) fn quat_positive_w(q: f32x4) -> f32x4 { let s = fx4_splat_w(q).simd_lt(ZERO).to_int() & SIGN; - return fx4_xor(q, s); + fx4_xor(q, s) } #[cfg(test)] @@ -1425,8 +1433,9 @@ mod tests { } fn approx_eq(a: f32x4, b: f32, epsilon: f32) -> bool { - return (a - f32x4::splat(b)).abs().simd_lt(f32x4::splat(epsilon)).all(); + (a - f32x4::splat(b)).abs().simd_lt(f32x4::splat(epsilon)).all() } + #[test] #[wasm_bindgen_test] fn test_asin() { diff --git a/src/sampling_job.rs b/src/sampling_job.rs index b5c2c05..e878242 100644 --- a/src/sampling_job.rs +++ b/src/sampling_job.rs @@ -43,14 +43,14 @@ const _: () = { impl Serialize for InterpSoaFloat3 { #[inline] fn serialize(&self, _: &mut S) -> Result { - return Ok(()); + Ok(()) } } impl Deserialize for InterpSoaFloat3 { #[inline] fn deserialize(&self, _: &mut D) -> Result { - return Ok(from_archived!(*self)); + Ok(from_archived!(*self)) } } @@ -62,7 +62,7 @@ const _: () = { if value as usize % mem::align_of::() != 0 { return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes")); } - return Ok(&*value); + Ok(&*value) } } }; @@ -96,14 +96,14 @@ const _: () = { impl Serialize for InterpSoaQuaternion { #[inline] fn serialize(&self, _: &mut S) -> Result { - return Ok(()); + Ok(()) } } impl Deserialize for InterpSoaQuaternion { #[inline] fn deserialize(&self, _: &mut D) -> Result { - return Ok(from_archived!(*self)); + Ok(from_archived!(*self)) } } @@ -115,7 +115,7 @@ const _: () = { if value as usize % mem::align_of::() != 0 { return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes")); } - return Ok(&*value); + Ok(&*value) } } }; @@ -130,12 +130,12 @@ mod serde_interp { let mut seq = serializer.serialize_seq(Some(2))?; seq.serialize_element(value[0].as_array())?; seq.serialize_element(value[1].as_array())?; - return seq.end(); + seq.end() } pub(crate) fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<[f32x4; 2], D::Error> { let tmp: [[f32; 4]; 2] = Deserialize::deserialize(deserializer)?; - return Ok([f32x4::from_array(tmp[0]), f32x4::from_array(tmp[1])]); + Ok([f32x4::from_array(tmp[0]), f32x4::from_array(tmp[1])]) } } @@ -166,7 +166,7 @@ struct SamplingContextInner { impl Default for SamplingContextInner { fn default() -> SamplingContextInner { - return SamplingContextInner { + SamplingContextInner { size: 0, max_tracks: 0, max_soa_tracks: 0, @@ -184,11 +184,10 @@ impl Default for SamplingContextInner { rotation_outdated: ptr::null_mut(), rotation_next: 0, - scales: ptr::null_mut(), - scale_entries: ptr::null_mut(), - scale_outdated: ptr::null_mut(), - scale_next: 0, - }; + outdated_translations_ptr: std::ptr::null_mut(), + outdated_rotations_ptr: std::ptr::null_mut(), + outdated_scales_ptr: std::ptr::null_mut(), + } } } @@ -236,7 +235,7 @@ impl Clone for SamplingContext { ctx.scale_outdated_mut().copy_from_slice(self.scale_outdated()); ctx.set_scale_next(self.scale_next()); - return ctx; + ctx } } @@ -277,12 +276,7 @@ impl Drop for SamplingContext { impl SamplingContext { #[inline(always)] fn inner(&self) -> &SamplingContextInner { - return unsafe { &*self.0 }; - } - - #[inline(always)] - fn inner_mut(&mut self) -> &mut SamplingContextInner { - return unsafe { &mut *self.0 }; + unsafe { &*self.inner } } /// Create a new `SamplingContext` @@ -333,23 +327,24 @@ impl SamplingContext { inner.rotations = ptr as *mut InterpSoaQuaternion; ptr = ptr.add(mem::size_of::() * inner.max_soa_tracks); - inner.rotation_entries = ptr as *mut u32; - ptr = ptr.add(mem::size_of::() * inner.max_tracks); - inner.rotation_outdated = ptr as *mut u8; - ptr = ptr.add(mem::size_of::() * inner.max_outdated); - ptr = align_ptr(ptr, ALIGN); - - inner.scales = ptr as *mut InterpSoaFloat3; + inner.scales_ptr = ptr as *mut InterpSoaFloat3; ptr = ptr.add(mem::size_of::() * inner.max_soa_tracks); - inner.scale_entries = ptr as *mut u32; - ptr = ptr.add(mem::size_of::() * inner.max_tracks); - inner.scale_outdated = ptr as *mut u8; - ptr = ptr.add(mem::size_of::() * inner.max_outdated); - ptr = align_ptr(ptr, ALIGN); - - assert_eq!(ptr, (ctx.0 as *mut u8).add(size)); - return ctx; - }; + inner.translation_keys_ptr = ptr as *mut i32; + ptr = ptr.add(mem::size_of::() * max_tracks * 2); + inner.rotation_keys_ptr = ptr as *mut i32; + ptr = ptr.add(mem::size_of::() * max_tracks * 2); + inner.scale_keys_ptr = ptr as *mut i32; + ptr = ptr.add(mem::size_of::() * max_tracks * 2); + inner.outdated_translations_ptr = ptr; + ptr = ptr.add(inner.num_outdated); + inner.outdated_rotations_ptr = ptr; + ptr = ptr.add(inner.num_outdated); + inner.outdated_scales_ptr = ptr; + ptr = ptr.add(inner.num_outdated); + assert_eq!(ptr, (ctx.inner as *mut u8).add(size)); + + ctx + } } /// Create a new `SamplingContext` from an `Animation`. @@ -357,8 +352,8 @@ impl SamplingContext { /// * `animation` - The animation to sample. Use `animation.num_tracks()` as max_tracks. pub fn from_animation(animation: &Animation) -> SamplingContext { let mut ctx = SamplingContext::new(animation.num_tracks()); - ctx.inner_mut().animation_id = animation as *const _ as u64; - return ctx; + ctx.animation_id = animation as *const _ as u64; + ctx } /// Clear the `SamplingContext`. @@ -375,8 +370,8 @@ impl SamplingContext { #[inline] pub fn clone_without_animation_id(&self) -> SamplingContext { let mut ctx = self.clone(); - ctx.set_animation_id(0); - return ctx; + ctx.animation_id = 0; + ctx } /// The memory size of the context in bytes. @@ -646,20 +641,35 @@ pub struct ArchivedSamplingContext { 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, + /// The unique identifier of the animation that the context is sampling. + #[inline] + pub fn animation_id(&self) -> u64 { + self.animation_id + } + + /// The current time ratio in the animation. + #[inline] + pub fn ratio(&self) -> f32 { + self.ratio + } + + /// Current cursors in the animation. 0 means that the context is invalid. + #[inline] + pub fn translation_cursor(&self) -> usize { + self.translation_cursor + } - pub rotations: rkyv::vec::ArchivedVec, - pub rotation_entries: rkyv::vec::ArchivedVec, - pub rotation_outdated: rkyv::vec::ArchivedVec, - pub rotation_next: u32, + /// Current cursors in the animation. 0 means that the context is invalid. + #[inline] + pub fn rotation_cursor(&self) -> usize { + self.rotation_cursor + } - pub scales: rkyv::vec::ArchivedVec, - pub scale_entries: rkyv::vec::ArchivedVec, - pub scale_outdated: rkyv::vec::ArchivedVec, - pub scale_next: u32, + /// Current cursors in the animation. 0 means that the context is invalid. + #[inline] + pub fn scale_cursor(&self) -> usize { + self.scale_cursor + } } #[cfg(feature = "rkyv")] @@ -733,18 +743,62 @@ const _: () = { impl Serialize for SamplingContext { fn serialize(&self, serializer: &mut S) -> Result { - serializer.align_for::()?; - return Ok(SamplingContextResolver { - translations: ArchivedVec::serialize_from_slice(self.translations(), serializer)?, - rotations: ArchivedVec::serialize_from_slice(self.rotations(), serializer)?, - scales: ArchivedVec::serialize_from_slice(self.scales(), serializer)?, - translation_entries: ArchivedVec::serialize_from_slice(self.translation_entries(), serializer)?, - rotation_entries: ArchivedVec::serialize_from_slice(self.rotation_entries(), serializer)?, - scale_entries: ArchivedVec::serialize_from_slice(self.scale_entries(), serializer)?, - translation_outdateds: ArchivedVec::serialize_from_slice(self.translation_outdated(), serializer)?, - rotation_outdateds: ArchivedVec::serialize_from_slice(self.rotation_outdated(), serializer)?, - scale_outdateds: ArchivedVec::serialize_from_slice(self.scale_outdated(), serializer)?, - }); + let mut resolver = SamplingContextResolver { + translations_pos: serializer.align_for::()?, + ..Default::default() + }; + + serializer.write(unsafe { + slice::from_raw_parts( + self.translations().as_ptr() as *const u8, + std::mem::size_of_val(self.translations()), + ) + })?; + resolver.rotations_pos = serializer.align_for::()?; + serializer.write(unsafe { + slice::from_raw_parts( + self.rotations().as_ptr() as *const u8, + std::mem::size_of_val(self.rotations()), + ) + })?; + resolver.scales_pos = serializer.align_for::()?; + serializer.write(unsafe { + slice::from_raw_parts( + self.scales().as_ptr() as *const u8, + std::mem::size_of_val(self.scales()), + ) + })?; + + resolver.translation_keys_pos = serializer.align_for::()?; + serializer.write(unsafe { + slice::from_raw_parts( + self.translation_keys().as_ptr() as *const u8, + std::mem::size_of_val(self.translation_keys()), + ) + })?; + resolver.rotation_keys_pos = serializer.align_for::()?; + serializer.write(unsafe { + slice::from_raw_parts( + self.rotation_keys().as_ptr() as *const u8, + std::mem::size_of_val(self.rotation_keys()), + ) + })?; + resolver.scale_keys_pos = serializer.align_for::()?; + serializer.write(unsafe { + slice::from_raw_parts( + self.scale_keys().as_ptr() as *const u8, + std::mem::size_of_val(self.scale_keys()), + ) + })?; + + resolver.outdated_translations_pos = serializer.align_for::()?; + serializer.write(self.outdated_translations())?; + resolver.outdated_rotations_pos = serializer.align_for::()?; + serializer.write(self.outdated_rotations())?; + resolver.outdated_scales_pos = serializer.align_for::()?; + serializer.write(self.outdated_scales())?; + + Ok(resolver) } } @@ -753,29 +807,31 @@ const _: () = { fn deserialize(&self, _: &mut D) -> Result { let archived = from_archived!(self); let mut context = SamplingContext::new(archived.max_tracks as usize); - context.set_animation_id(archived.animation_id); - context.set_ratio(archived.ratio); - context.translations_mut().copy_from_slice(&archived.translations); - context.rotations_mut().copy_from_slice(&archived.rotations); - context.scales_mut().copy_from_slice(&archived.scales); - context - .translation_entries_mut() - .copy_from_slice(&archived.translation_entries); - context - .rotation_entries_mut() - .copy_from_slice(&archived.rotation_entries); - context.scale_entries_mut().copy_from_slice(&archived.scale_entries); - context - .translation_outdated_mut() - .copy_from_slice(&archived.translation_outdated); - context - .rotation_outdated_mut() - .copy_from_slice(&archived.rotation_outdated); - context.scale_outdated_mut().copy_from_slice(&archived.scale_outdated); - context.set_translation_next(archived.translation_next as usize); - context.set_rotation_next(archived.rotation_next as usize); - context.set_scale_next(archived.scale_next as usize); - return Ok(context); + context.animation_id = archived.animation_id; + context.ratio = archived.ratio; + unsafe { + context.translations_mut().copy_from_slice(archived.translations()); + context.rotations_mut().copy_from_slice(archived.rotations()); + context.scales_mut().copy_from_slice(archived.scales()); + context + .translation_keys_mut() + .copy_from_slice(archived.translation_keys()); + context.rotation_keys_mut().copy_from_slice(archived.rotation_keys()); + context.scale_keys_mut().copy_from_slice(archived.scale_keys()); + context.translation_cursor = archived.translation_cursor as usize; + context.rotation_cursor = archived.rotation_cursor as usize; + context.scale_cursor = archived.scale_cursor as usize; + context + .outdated_translations_mut() + .copy_from_slice(archived.outdated_translations()); + context + .outdated_rotations_mut() + .copy_from_slice(archived.outdated_rotations()); + context + .outdated_scales_mut() + .copy_from_slice(archived.outdated_scales()); + } + Ok(context) } } @@ -787,7 +843,7 @@ const _: () = { if value as usize % mem::align_of::() != 0 { return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes")); } - return Ok(&*value); + Ok(&*value) } } }; @@ -810,16 +866,16 @@ const _: () = { map.serialize_entry("translations", self.translations())?; map.serialize_entry("rotations", self.rotations())?; map.serialize_entry("scales", self.scales())?; - map.serialize_entry("translation_entries", self.translation_entries())?; - map.serialize_entry("translation_outdated", self.translation_outdated())?; - map.serialize_entry("translation_next", &self.translation_next())?; - map.serialize_entry("rotation_entries", self.rotation_entries())?; - map.serialize_entry("rotation_outdated", self.rotation_outdated())?; - map.serialize_entry("rotation_next", &self.rotation_next())?; - map.serialize_entry("scale_entries", self.scale_entries())?; - map.serialize_entry("scale_outdated", self.scale_outdated())?; - map.serialize_entry("scale_next", &self.scale_next())?; - return map.end(); + map.serialize_entry("translations_keys", self.translation_keys())?; + map.serialize_entry("rotations_keys", self.rotation_keys())?; + map.serialize_entry("scales_keys", self.scale_keys())?; + map.serialize_entry("translation_cursor", &self.translation_cursor())?; + map.serialize_entry("rotation_cursor", &self.rotation_cursor())?; + map.serialize_entry("scale_cursor", &self.scale_cursor())?; + map.serialize_entry("outdated_translations", self.outdated_translations())?; + map.serialize_entry("outdated_rotations", self.outdated_rotations())?; + map.serialize_entry("outdated_scales", self.outdated_scales())?; + map.end() } } @@ -835,7 +891,7 @@ const _: () = { type Value = SamplingContext; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - return formatter.write_str("struct SamplingContext"); + formatter.write_str("struct SamplingContext") } fn visit_map>(self, mut map: V) -> Result { @@ -899,7 +955,7 @@ const _: () = { } } } - return Ok(ctx); + Ok(ctx) } } }; @@ -912,24 +968,24 @@ pub trait AsSamplingContext { impl AsSamplingContext for SamplingContext { #[inline(always)] fn as_ref(&self) -> &SamplingContext { - return self; + self } #[inline(always)] fn as_mut(&mut self) -> &mut SamplingContext { - return self; + self } } impl AsSamplingContext for &'_ mut SamplingContext { #[inline(always)] fn as_ref(&self) -> &SamplingContext { - return self; + self } #[inline(always)] fn as_mut(&mut self) -> &mut SamplingContext { - return *self; + self } } @@ -982,12 +1038,12 @@ where C: AsSamplingContext, { fn default() -> SamplingJob { - return SamplingJob { + SamplingJob { animation: None, context: None, ratio: 0.0, output: None, - }; + } } } @@ -1036,13 +1092,13 @@ where /// Takes context of `SamplingJob`. See [SamplingContext]. #[inline] pub fn take_context(&mut self) -> Option { - return self.context.take(); + self.context.take() } /// Gets the time ratio of `SamplingJob`. #[inline] pub fn ratio(&self) -> f32 { - return self.ratio; + self.ratio } /// Sets the time ratio of `SamplingJob`. @@ -1091,7 +1147,7 @@ where let mut ok = context.as_ref().max_soa_tracks() >= animation.num_soa_tracks(); ok &= output.len() >= animation.num_soa_tracks(); - return Some(ok); + Some(ok) })() .unwrap_or(false); } @@ -1130,8 +1186,7 @@ where let args = ctx.as_mut().scale_decompress_args(); Self::decompress_float3(args, anim.timepoints(), &anim.scales_ctrl(), anim.scales()); - Self::interpolates(anim, ctx.as_mut(), self.ratio, &mut output)?; - return Ok(()); + Ok(()) } #[inline] @@ -1148,34 +1203,29 @@ 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(); - - 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) { - let mut iframe = -1; - if !ctrl.iframe_desc.is_empty() { - iframe = (0.5 + ratio / ctrl.iframe_interval) as i32; - } else if next == 0 || delta < 0.0 { - iframe = 0; + fn update_translation_cursor(animation: &Animation, ctx: &mut SamplingContext, ratio: f32) { + if ctx.translation_cursor == 0 { + for i in 0..animation.num_soa_tracks() { + let in_idx0 = i * 4; + let in_idx1 = in_idx0 + animation.num_aligned_tracks(); + let out_idx = i * 4 * 2; + ctx.translation_keys_mut()[out_idx] = in_idx0 as i32; + ctx.translation_keys_mut()[out_idx + 1] = in_idx1 as i32; + ctx.translation_keys_mut()[out_idx + 2] = (in_idx0 + 1) as i32; + ctx.translation_keys_mut()[out_idx + 3] = (in_idx1 + 1) as i32; + ctx.translation_keys_mut()[out_idx + 4] = (in_idx0 + 2) as i32; + ctx.translation_keys_mut()[out_idx + 5] = (in_idx1 + 2) as i32; + ctx.translation_keys_mut()[out_idx + 6] = (in_idx0 + 3) as i32; + ctx.translation_keys_mut()[out_idx + 7] = (in_idx1 + 3) as i32; } - if iframe >= 0 { - next = Self::initialize_cache(ctrl, iframe as usize, args.entries); - assert!(next >= args.num_tracks * 2 && next <= num_keys); - Self::outdate_cache(args.outdated, args.num_soa_tracks); + ctx.outdated_translations_mut().iter_mut().for_each(|x| *x = 0xFF); + let last_offset = ((animation.num_soa_tracks() + 7) / 8 * 8) - animation.num_soa_tracks(); + if let Some(x) = ctx.outdated_translations_mut().last_mut() { + *x = 0xFF >> last_offset; } + + ctx.translation_cursor = animation.num_aligned_tracks() * 2; } // Forward @@ -1190,40 +1240,11 @@ where next += 1; } - // Rewinds - while Self::key_ratio( - ctrl, - &animation.timepoints(), - 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]; - assert!((args.entries[track] as usize) >= (previous as usize) + args.num_tracks); - args.entries[track] -= previous as u32; - next -= 1; - } - - assert!(next >= args.num_tracks * 2 && next <= num_keys); - *args.next = next; - } - - #[inline] - 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; - } else { - let num_tracks = entries.len() as u32; - for i in 0..num_tracks { - entries[i as usize] = i + num_tracks; - } - return (num_tracks * 2) as usize; + ctx.outdated_translations_mut()[track / 32] |= 1 << ((track & 0x1F) / 4); + let base = (animation.translations()[ctx.translation_cursor].track as usize) * 2; + ctx.translation_keys_mut()[base] = ctx.translation_keys()[base + 1]; + ctx.translation_keys_mut()[base + 1] = ctx.translation_cursor as i32; + ctx.translation_cursor += 1; } } @@ -1304,13 +1325,12 @@ where continue; } - 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), - ]; + let k00 = animation.translations()[ctx.translation_keys()[base] as usize]; + let k10 = animation.translations()[ctx.translation_keys()[base + 2] as usize]; + let k20 = animation.translations()[ctx.translation_keys()[base + 4] as usize]; + let k30 = animation.translations()[ctx.translation_keys()[base + 6] as usize]; + ctx.translations_mut()[i].ratio[0] = f32x4::from_array([k00.ratio, k10.ratio, k20.ratio, k30.ratio]); + Float3Key::simd_decompress(&k00, &k10, &k20, &k30, &mut ctx.translations_mut()[i].value[0]); let k00 = compressed[lefts[0] as usize]; let k10 = compressed[lefts[1] as usize]; @@ -1331,26 +1351,62 @@ where } } - fn decompress_quat( - args: DecompressArgs<'_, InterpSoaQuaternion>, - timepoints: &[f32], - ctrl: &KeyframesCtrl<'_>, - compressed: &[QuaternionKey], - ) { - for j in 0..args.outdated.len() { - let mut outdated = args.outdated[j]; + fn update_rotation_cursor(animation: &Animation, ctx: &mut SamplingContext, ratio: f32) { + if ctx.rotation_cursor == 0 { + for i in 0..animation.num_soa_tracks() { + let in_idx0 = i * 4; + let in_idx1 = in_idx0 + animation.num_aligned_tracks(); + let out_idx = i * 4 * 2; + ctx.rotation_keys_mut()[out_idx] = in_idx0 as i32; + ctx.rotation_keys_mut()[out_idx + 1] = in_idx1 as i32; + ctx.rotation_keys_mut()[out_idx + 2] = (in_idx0 + 1) as i32; + ctx.rotation_keys_mut()[out_idx + 3] = (in_idx1 + 1) as i32; + ctx.rotation_keys_mut()[out_idx + 4] = (in_idx0 + 2) as i32; + ctx.rotation_keys_mut()[out_idx + 5] = (in_idx1 + 2) as i32; + ctx.rotation_keys_mut()[out_idx + 6] = (in_idx0 + 3) as i32; + ctx.rotation_keys_mut()[out_idx + 7] = (in_idx1 + 3) as i32; + } + + ctx.outdated_rotations_mut().iter_mut().for_each(|x| *x = 0xFF); + let last_offset = ((animation.num_soa_tracks() + 7) / 8 * 8) - animation.num_soa_tracks(); + if let Some(x) = ctx.outdated_rotations_mut().last_mut() { + *x = 0xFF >> last_offset; + } + + ctx.rotation_cursor = animation.num_aligned_tracks() * 2; + } + + while ctx.rotation_cursor < animation.rotations().len() { + let track = animation.rotations()[ctx.rotation_cursor].track() as usize; + let key_idx = ctx.rotation_keys()[track * 2 + 1] as usize; + let ani_ratio = animation.rotations()[key_idx].ratio; + if ani_ratio > ratio { + break; + } + + ctx.outdated_rotations_mut()[track / 32] |= 1 << ((track & 0x1F) / 4); + let base = (animation.rotations()[ctx.rotation_cursor].track() as usize) * 2; + ctx.rotation_keys_mut()[base] = ctx.rotation_keys()[base + 1]; + ctx.rotation_keys_mut()[base + 1] = ctx.rotation_cursor as i32; + ctx.rotation_cursor += 1; + } + } + + fn update_rotation_key_frames(animation: &Animation, ctx: &mut SamplingContext) { + let num_outdated_flags = (animation.num_soa_tracks() + 7) / 8; + for j in 0..num_outdated_flags { + let mut outdated = ctx.outdated_rotations()[j]; for i in (8 * j)..(8 * j + 8) { if outdated & 1 == 0 { continue; } - 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), - ]; + let k00 = animation.rotations()[ctx.rotation_keys()[base] as usize]; + let k10 = animation.rotations()[ctx.rotation_keys()[base + 2] as usize]; + let k20 = animation.rotations()[ctx.rotation_keys()[base + 4] as usize]; + let k30 = animation.rotations()[ctx.rotation_keys()[base + 6] as usize]; + ctx.rotations_mut()[i].ratio[0] = f32x4::from_array([k00.ratio, k10.ratio, k20.ratio, k30.ratio]); + QuaternionKey::simd_decompress(&k00, &k10, &k20, &k30, &mut ctx.rotations_mut()[i].value[0]); let k00 = compressed[lefts[0] as usize]; let k10 = compressed[lefts[1] as usize]; @@ -1359,12 +1415,75 @@ where args.values[i].ratio[0] = Self::key_ratio_simd(ctrl, timepoints, &lefts); QuaternionKey::simd_decompress(&k00, &k10, &k20, &k30, &mut args.values[i].value[0]); - let k01 = compressed[rights[0] as usize]; - let k11 = compressed[rights[1] as usize]; - let k21 = compressed[rights[2] as usize]; - let k31 = compressed[rights[3] as usize]; - args.values[i].ratio[1] = Self::key_ratio_simd(ctrl, timepoints, &rights); - QuaternionKey::simd_decompress(&k01, &k11, &k21, &k31, &mut args.values[i].value[1]); + outdated >>= 1; + } + } + } + + fn update_scale_cursor(animation: &Animation, ctx: &mut SamplingContext, ratio: f32) { + if ctx.scale_cursor == 0 { + for i in 0..animation.num_soa_tracks() { + let in_idx0 = i * 4; + let in_idx1 = in_idx0 + animation.num_aligned_tracks(); + let out_idx = i * 4 * 2; + ctx.scale_keys_mut()[out_idx] = (in_idx0) as i32; + ctx.scale_keys_mut()[out_idx + 1] = (in_idx1) as i32; + ctx.scale_keys_mut()[out_idx + 2] = (in_idx0 + 1) as i32; + ctx.scale_keys_mut()[out_idx + 3] = (in_idx1 + 1) as i32; + ctx.scale_keys_mut()[out_idx + 4] = (in_idx0 + 2) as i32; + ctx.scale_keys_mut()[out_idx + 5] = (in_idx1 + 2) as i32; + ctx.scale_keys_mut()[out_idx + 6] = (in_idx0 + 3) as i32; + ctx.scale_keys_mut()[out_idx + 7] = (in_idx1 + 3) as i32; + } + + ctx.outdated_scales_mut().iter_mut().for_each(|x| *x = 0xFF); + let last_offset = ((animation.num_soa_tracks() + 7) / 8 * 8) - animation.num_soa_tracks(); + if let Some(x) = ctx.outdated_scales_mut().last_mut() { + *x = 0xFF >> last_offset; + } + + ctx.scale_cursor = animation.num_aligned_tracks() * 2; + } + + while ctx.scale_cursor < animation.scales().len() { + let track = animation.scales()[ctx.scale_cursor].track as usize; + let key_idx = ctx.scale_keys()[track * 2 + 1] as usize; + let ani_ratio = animation.scales()[key_idx].ratio; + if ani_ratio > ratio { + break; + } + + ctx.outdated_scales_mut()[track / 32] |= 1 << ((track & 0x1F) / 4); + let base = (animation.scales()[ctx.scale_cursor].track as usize) * 2; + ctx.scale_keys_mut()[base] = ctx.scale_keys()[base + 1]; + ctx.scale_keys_mut()[base + 1] = ctx.scale_cursor as i32; + ctx.scale_cursor += 1; + } + } + + fn update_scale_key_frames(animation: &Animation, ctx: &mut SamplingContext) { + let num_outdated_flags = (animation.num_soa_tracks() + 7) / 8; + for j in 0..num_outdated_flags { + let mut outdated = ctx.outdated_scales()[j]; + for i in (8 * j)..(8 * j + 8) { + if outdated & 1 == 0 { + continue; + } + let base = i * 4 * 2; + + let k00 = animation.scales()[ctx.scale_keys()[base] as usize]; + let k10 = animation.scales()[ctx.scale_keys()[base + 2] as usize]; + let k20 = animation.scales()[ctx.scale_keys()[base + 4] as usize]; + let k30 = animation.scales()[ctx.scale_keys()[base + 6] as usize]; + ctx.scales_mut()[i].ratio[0] = f32x4::from_array([k00.ratio, k10.ratio, k20.ratio, k30.ratio]); + Float3Key::simd_decompress(&k00, &k10, &k20, &k30, &mut ctx.scales_mut()[i].value[0]); + + let k01 = animation.scales()[ctx.scale_keys()[base + 1] as usize]; + let k11 = animation.scales()[ctx.scale_keys()[base + 3] as usize]; + let k21 = animation.scales()[ctx.scale_keys()[base + 5] as usize]; + let k31 = animation.scales()[ctx.scale_keys()[base + 7] as usize]; + ctx.scales_mut()[i].ratio[1] = f32x4::from_array([k01.ratio, k11.ratio, k21.ratio, k31.ratio]); + Float3Key::simd_decompress(&k01, &k11, &k21, &k31, &mut ctx.scales_mut()[i].value[1]); outdated >>= 1; } @@ -1378,20 +1497,21 @@ where output: &mut [SoaTransform], ) -> Result<(), OzzError> { let ratio4 = f32x4::splat(ratio); - for idx in 0..animation.num_soa_tracks() { + for (idx, out) in output.iter_mut().enumerate().take(animation.num_soa_tracks()) { let translation = &ctx.translations()[idx]; let translation_ratio = (ratio4 - translation.ratio[0]) / (translation.ratio[1] - translation.ratio[0]); - output[idx].translation = SoaVec3::lerp(&translation.value[0], &translation.value[1], translation_ratio); + out.translation = SoaVec3::lerp(&translation.value[0], &translation.value[1], translation_ratio); let rotation = &ctx.rotations()[idx]; let rotation_ratio = (ratio4 - rotation.ratio[0]) / (rotation.ratio[1] - rotation.ratio[0]); - output[idx].rotation = SoaQuat::nlerp(&rotation.value[0], &rotation.value[1], rotation_ratio); + out.rotation = SoaQuat::nlerp(&rotation.value[0], &rotation.value[1], rotation_ratio); let scale = &ctx.scales()[idx]; let scale_ratio = (ratio4 - scale.ratio[0]) / (scale.ratio[1] - scale.ratio[0]); - output[idx].scale = SoaVec3::lerp(&scale.value[0], &scale.value[1], scale_ratio); + out.scale = SoaVec3::lerp(&scale.value[0], &scale.value[1], scale_ratio); } - return Ok(()); + + Ok(()) } } @@ -1449,20 +1569,20 @@ mod sampling_tests { use crate::base::OzzBuf; fn make_buf(v: Vec) -> Rc>> { - return Rc::new(RefCell::new(v)); + Rc::new(RefCell::new(v)) } // f16 -> f32 // ignore overflow, infinite, NaN pub fn f16(f: f32) -> u16 { - let n = unsafe { mem::transmute::(f) }; + let n = f.to_bits(); if (n & 0x7FFFFFFF) == 0 { return (n >> 16) as u16; } let sign = (n >> 16) & 0x8000; let expo = (((n & 0x7f800000) - 0x38000000) >> 13) & 0x7c00; let base = (n >> 13) & 0x03ff; - return (sign | expo | base) as u16; + (sign | expo | base) as u16 } #[test] @@ -1499,6 +1619,45 @@ mod sampling_tests { assert!(job.run().is_ok()); } + fn new_translations() -> Vec { + vec![ + Float3Key::new(0.0, 0, [f16(0.0); 3]), + Float3Key::new(0.0, 1, [f16(0.0); 3]), + Float3Key::new(0.0, 2, [f16(0.0); 3]), + Float3Key::new(0.0, 3, [f16(0.0); 3]), + Float3Key::new(1.0, 0, [f16(0.0); 3]), + Float3Key::new(1.0, 1, [f16(0.0); 3]), + Float3Key::new(1.0, 2, [f16(0.0); 3]), + Float3Key::new(1.0, 3, [f16(0.0); 3]), + ] + } + + fn new_rotations() -> Vec { + vec![ + QuaternionKey::new(0.0, 3 << 1, [0, 0, 0]), + QuaternionKey::new(0.0, (1 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(0.0, (2 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(0.0, (3 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(1.0, 3 << 1, [0, 0, 0]), + QuaternionKey::new(1.0, (1 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(1.0, (2 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(1.0, (3 << 3) + (3 << 1), [0, 0, 0]), + ] + } + + fn new_scales() -> Vec { + vec![ + Float3Key::new(0.0, 0, [f16(1.0); 3]), + Float3Key::new(0.0, 1, [f16(1.0); 3]), + Float3Key::new(0.0, 2, [f16(1.0); 3]), + Float3Key::new(0.0, 3, [f16(1.0); 3]), + Float3Key::new(1.0, 0, [f16(1.0); 3]), + Float3Key::new(1.0, 1, [f16(1.0); 3]), + Float3Key::new(1.0, 2, [f16(1.0); 3]), + Float3Key::new(1.0, 3, [f16(1.0); 3]), + ] + } + const V0: Vec3 = Vec3::new(0.0, 0.0, 0.0); const V1: Vec3 = Vec3::new(1.0, 1.0, 1.0); const QU: Quat = Quat::from_xyzw(0.0, 0.0, 0.0, 1.0); @@ -1603,7 +1762,7 @@ mod sampling_tests { #[wasm_bindgen_test] fn test_sampling() { fn frame(ratio: f32, t1: f32, t2: f32, t3: f32, t4: f32) -> Frame<4> { - return Frame { + Frame { ratio, transform: [ (Vec3::new(t1, 0.0, 0.0), QU, V1), @@ -1611,28 +1770,10 @@ mod sampling_tests { (Vec3::new(t3, 0.0, 0.0), QU, V1), (Vec3::new(t4, 0.0, 0.0), QU, V1), ], - }; + } } - 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]; + #[allow(clippy::excessive_precision)] execute_test::<4>( ar, vec![ @@ -1703,10 +1844,10 @@ mod sampling_tests { #[wasm_bindgen_test] fn test_sampling_1_track_2_key() { fn frame(ratio: f32, v: Vec3) -> Frame<2> { - return Frame { + Frame { ratio, transform: [(v, QU, V1), (V0, QU, V1)], - }; + } } let mut ar = empty_animation_raw::<2>(46.0); @@ -1750,70 +1891,62 @@ mod sampling_tests { #[wasm_bindgen_test] #[rustfmt::skip] fn test_sampling_4_track_2_key() { - 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]), - Float3Key::new([f16(-1.0), f16(-2.0), f16(-4.0)]), - Float3Key::new([f16(1.0), f16(2.0), f16(4.0)]), - Float3Key::new([f16(0.0); 3]), - Float3Key::new([f16(0.0); 3]), - Float3Key::new([f16(-2.0), f16(-4.0), f16(-8.0)]), - Float3Key::new([f16(2.0), f16(4.0), f16(8.0)]), - Float3Key::new([f16(2.0), f16(4.0), f16(8.0)]), - ]; - - ar.rotations = empty_rotations(); - ar.rotations[5] = QuaternionKey::new([65529, 65533, 32766]); - - ar.scales = vec![ - Float3Key::new([f16(1.0); 3]), - Float3Key::new([f16(1.0); 3]), - Float3Key::new([f16(0.0); 3]), - Float3Key::new([f16(1.0); 3]), - Float3Key::new([f16(1.0); 3]), - Float3Key::new([f16(1.0); 3]), - Float3Key::new([f16(0.0); 3]), - Float3Key::new([f16(1.0); 3]), - Float3Key::new([f16(-1.0); 3]), - Float3Key::new([f16(-1.0); 3]), - ]; - - let mut frames_raw = vec![ - Frame {ratio: 0.0, transform: [ - (Vec3::new(1.0, 2.0, 4.0), QU, V1), - (V0, QU, V1), - (V0, QU, V0), - (Vec3::new(-1.0, -2.0, -4.0), QU, V1), - ]}, - Frame {ratio: 0.5, transform: [ - (Vec3::new(1.0, 2.0, 4.0), QU, V1), - (V0, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677), V1), - (V0, QU, V0), - (Vec3::new(-1.5, -3.0, -6.0), QU, V1), - ]}, - Frame {ratio: 1.0, transform: [ - (Vec3::new(2.0, 4.0, 8.0), QU, V1), - (V0, Quat::from_xyzw(0.0, 1.0, 0.0, 0.0), V1), - (V0, QU, -V1), - (Vec3::new(-2.0, -4.0, -8.0), QU, V1), - ]}, - ]; - let mut frames = frames_raw.clone(); - frames_raw.reverse(); - frames.append(&mut frames_raw); - - execute_test::<4>(ar, - frames, + execute_test::<4>( + 1.0, + vec![ + Float3Key::new(0.0, 0, [f16(1.0), f16(2.0), f16(4.0)]), + Float3Key::new(0.0, 1, [f16(0.0); 3]), + Float3Key::new(0.0, 2, [f16(0.0); 3]), + Float3Key::new(0.0, 3, [f16(-1.0), f16(-2.0), f16(-4.0)]), + Float3Key::new(0.5, 0, [f16(1.0), f16(2.0), f16(4.0)]), + Float3Key::new(1.0, 1, [f16(0.0); 3]), + Float3Key::new(1.0, 2, [f16(0.0); 3]), + Float3Key::new(1.0, 3, [f16(-2.0), f16(-4.0), f16(-8.0)]), + Float3Key::new(0.8, 0, [f16(2.0), f16(4.0), f16(8.0)]), + Float3Key::new(1.0, 0, [f16(2.0), f16(4.0), f16(8.0)]), + ], + vec![ + QuaternionKey::new(0.0, 3 << 1, [0, 0, 0]), + QuaternionKey::new(0.0, (1 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(0.0, (2 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(0.0, (3 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(1.0, 3 << 1, [0, 0, 0]), + QuaternionKey::new(1.0, (1 << 3) + (1 << 1), [0, 0, 0]), + QuaternionKey::new(1.0, (2 << 3) + (3 << 1), [0, 0, 0]), + QuaternionKey::new(1.0, (3 << 3) + (3 << 1), [0, 0, 0]), + ], + vec![ + Float3Key::new(0.0, 0, [f16(1.0); 3]), + Float3Key::new(0.0, 1, [f16(1.0); 3]), + Float3Key::new(0.0, 2, [f16(0.0); 3]), + Float3Key::new(0.0, 3, [f16(1.0); 3]), + Float3Key::new(1.0, 0, [f16(1.0); 3]), + Float3Key::new(1.0, 1, [f16(1.0); 3]), + Float3Key::new(0.5, 2, [f16(0.0); 3]), + Float3Key::new(1.0, 3, [f16(1.0); 3]), + Float3Key::new(0.8, 2, [f16(-1.0); 3]), + Float3Key::new(1.0, 2, [f16(-1.0); 3]), + ], + vec![ + Frame {ratio: 0.0, transform: [ + (Vec3::new(1.0, 2.0, 4.0), QU, V1), + (V0, QU, V1), + (V0, QU, V0), + (Vec3::new(-1.0, -2.0, -4.0), QU, V1), + ]}, + Frame {ratio: 0.5, transform: [ + (Vec3::new(1.0, 2.0, 4.0), QU, V1), + (V0, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677), V1), + (V0, QU, V0), + (Vec3::new(-1.5, -3.0, -6.0), QU, V1), + ]}, + Frame {ratio: 1.0, transform: [ + (Vec3::new(2.0, 4.0, 8.0), QU, V1), + (V0, Quat::from_xyzw(0.0, 1.0, 0.0, 0.0), V1), + (V0, QU, -V1), + (Vec3::new(-2.0, -4.0, -8.0), QU, V1), + ]}, + ], ); } @@ -1858,7 +1991,7 @@ mod sampling_tests { .abs_diff_eq(Quat::from_xyzw(0.0, 0.0, 0.0, 1.0), 5e-1)); assert_eq!(item.scale.col(0), Vec3::new(1.0, 1.0, 1.0)); } - return Ok(()); + Ok(()) } job.set_ratio(0.0); diff --git a/src/skeleton.rs b/src/skeleton.rs index dd4f6c7..e585a74 100644 --- a/src/skeleton.rs +++ b/src/skeleton.rs @@ -14,6 +14,59 @@ 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(), + DeterministicState::new(), + DeterministicState::new(), + ); + for entry in field.iter() { + result.insert( + entry.key.deserialize(deserializer)?, + entry.value.deserialize(deserializer)?, + ); + } + Ok(result) + } + } +}; + /// /// This runtime skeleton data structure provides a const-only access to joint /// hierarchy, joint names and rest-pose. @@ -69,13 +122,26 @@ impl Skeleton { /// `Skeleton` resource file tag for `Archive`. #[inline] pub fn tag() -> &'static str { - return "ozz-skeleton"; + "ozz-skeleton" } #[inline] /// `Skeleton` resource file version for `Archive`. pub fn version() -> u32 { - return 2; + 2 + } + + #[cfg(test)] + pub(crate) fn from_raw( + joint_rest_poses: Vec, + joint_parents: Vec, + joint_names: JointHashMap, + ) -> Skeleton { + Skeleton { + joint_rest_poses, + joint_parents, + joint_names, + } } /// Reads a `SkeletonMeta` from a reader. @@ -109,12 +175,12 @@ impl Skeleton { let joint_parents: Vec = archive.read_vec(num_joints as usize)?; - return Ok(SkeletonMeta { + Ok(SkeletonMeta { version: Self::version(), num_joints, joint_names, joint_parents, - }); + }) } /// Reads a `Skeleton` from a reader. @@ -127,23 +193,25 @@ impl Skeleton { skeleton.joint_names.insert(archive.read::()?, idx as i16); } - archive.read_slice(skeleton.joint_parents_mut())?; - archive.read_slice(skeleton.joint_rest_poses_mut())?; - return Ok(skeleton); + Ok(Skeleton { + joint_rest_poses, + joint_parents: meta.joint_parents, + joint_names: meta.joint_names, + }) } /// Reads a `Skeleton` from a file. #[cfg(not(feature = "wasm"))] pub fn from_path>(path: P) -> Result { let mut archive = Archive::from_path(path)?; - return Skeleton::from_archive(&mut archive); + Skeleton::from_archive(&mut archive) } // Only for wasm test in NodeJS environment. #[cfg(all(feature = "wasm", feature = "nodejs"))] pub fn from_path(path: &str) -> Result { let mut archive = Archive::from_path(path)?; - return Skeleton::from_archive(&mut archive); + Skeleton::from_archive(&mut archive) } pub(crate) fn from_raw(raw: &SkeletonRaw) -> Skeleton { @@ -204,43 +272,49 @@ impl Skeleton { /// Gets the number of joints of `Skeleton`. #[inline] pub fn num_joints(&self) -> usize { - return self.num_joints as usize; + self.joint_parents.len() } /// Gets the number of joints of `Skeleton` (aligned to 4 * SoA). #[inline] pub fn num_aligned_joints(&self) -> usize { - return (self.num_joints() + 3) & !0x3; + (self.num_joints() + 3) & !0x3 } /// Gets the number of soa elements matching the number of joints of `Skeleton`. /// This value is useful to allocate SoA runtime data structures. #[inline] pub fn num_soa_joints(&self) -> usize { - return self.num_soa_joints as usize; + (self.joint_parents.len() + 3) / 4 } /// Gets joint's rest poses. Rest poses are stored in soa format. #[inline] pub fn joint_rest_poses(&self) -> &[SoaTransform] { - return unsafe { slice::from_raw_parts(self.joint_rest_poses, self.num_soa_joints()) }; + &self.joint_rest_poses } #[inline] - fn joint_rest_poses_mut(&mut self) -> &mut [SoaTransform] { - return unsafe { slice::from_raw_parts_mut(self.joint_rest_poses, self.num_soa_joints()) }; + pub fn joint_parents(&self) -> &[i16] { + &self.joint_parents + } + + /// Gets joint's parent by index. + #[inline] + pub fn joint_parent(&self, idx: impl OzzIndex) -> i16 { + self.joint_parents[idx.usize()] } /// Gets joint's name map. #[inline] pub fn joint_names(&self) -> &JointHashMap { - return &self.joint_names; + &self.joint_names } /// Gets joint's index by name. #[inline] pub fn joint_by_name(&self, name: &str) -> Option { - return self.joint_names.get_by_left(name).map(|idx| *idx); + self.joint_names.get_by_left(name).copied() } /// Gets joint's name by index. @@ -415,6 +489,7 @@ mod tests { use super::*; use crate::math::{SoaQuat, SoaVec3}; + #[allow(clippy::excessive_precision)] #[test] #[wasm_bindgen_test] fn test_read_skeleton() { @@ -495,7 +570,7 @@ mod tests { serializer.serialize_value(&skeleton).unwrap(); let buf = serializer.into_serializer().into_inner(); let archived = unsafe { rkyv::archived_root::(&buf) }; - let mut deserializer = rkyv::Infallible::default(); + let mut deserializer = rkyv::Infallible; let skeleton2: Skeleton = archived.deserialize(&mut deserializer).unwrap(); assert_eq!(skeleton.joint_rest_poses(), skeleton2.joint_rest_poses()); diff --git a/src/skinning_job.rs b/src/skinning_job.rs index cf8ae06..beb2888 100644 --- a/src/skinning_job.rs +++ b/src/skinning_job.rs @@ -69,7 +69,7 @@ where O: OzzMutBuf, { fn default() -> Self { - return SkinningJob { + SkinningJob { vertex_count: 0, influences_count: 0, @@ -85,7 +85,7 @@ where out_positions: None, out_normals: None, out_tangents: None, - }; + } } } @@ -100,7 +100,7 @@ where /// Gets vertex count of `SkinningJob`. #[inline] pub fn vertex_count(&self) -> usize { - return self.vertex_count; + self.vertex_count } /// Sets vertex count of `SkinningJob`. @@ -115,7 +115,7 @@ where /// Gets influences count of `SkinningJob`. #[inline] pub fn influences_count(&self) -> usize { - return self.influences_count; + self.influences_count } /// Sets influences count of `SkinningJob`. @@ -134,7 +134,7 @@ where /// Gets joint matrices of `SkinningJob`. #[inline] pub fn joint_matrices(&self) -> Option<&JM> { - return self.joint_matrices.as_ref(); + self.joint_matrices.as_ref() } /// Sets joint matrices of `SkinningJob`. @@ -338,7 +338,7 @@ where /// Validates `SkinningJob` parameters. pub fn validate(&self) -> bool { - return (|| { + (|| { let mut ok = self.influences_count > 0; ok &= !self.joint_matrices.as_ref()?.buf().ok()?.is_empty(); @@ -365,13 +365,13 @@ where ok &= self.in_tangents.is_none(); } - return Some(ok); + Some(ok) })() - .unwrap_or(false); + .unwrap_or(false) } } -fn unpack_buf<'t, T, B>(ozz_buf: &'t Option, size: usize) -> Result, OzzError> +fn unpack_buf(ozz_buf: &Option, size: usize) -> Result, OzzError> where T: Debug + Clone, B: OzzBuf, @@ -380,10 +380,10 @@ where if buf.len() < size { return Err(OzzError::InvalidJob); } - return Ok(buf); + Ok(buf) } -fn unpack_mut_buf<'t, T, B>(ozz_buf: &'t mut Option, size: usize) -> Result, OzzError> +fn unpack_mut_buf(ozz_buf: &mut Option, size: usize) -> Result, OzzError> where T: Debug + Clone, B: OzzMutBuf, @@ -392,7 +392,7 @@ where if buf.len() < size { return Err(OzzError::InvalidJob); } - return Ok(buf); + Ok(buf) } #[rustfmt::skip] @@ -464,28 +464,32 @@ macro_rules! skinning_impl { ); for i in 0..$self.vertex_count { - let weight_offset = i * ($n - 1); let index_offset = i * $n; + let mut transform = Mat4::IDENTITY; + it!($it, let mut transform_it = Mat4::IDENTITY); - let weight = Vec4::splat(weights[weight_offset]); - let mut weight_sum = weight; - let joint_index = indices[index_offset] as usize; - let mut transform = mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); - it!($it, let mut transform_it = mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); + if $n == 1 { + let joint_index = indices[index_offset] as usize; + transform = *matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?; + it!($it, transform_it = *it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?); + } else { + let weight_offset = i * ($n - 1); + let mut weight_sum = Vec4::ZERO; + + for j in 0..($n - 1) { + let weight = Vec4::splat(weights[weight_offset + j]); + weight_sum += weight; + let joint_index = indices[index_offset + j] as usize; + transform += mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); + it!($it, transform_it += mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); + } - for j in 1..($n - 1) { - let weight = Vec4::splat(weights[weight_offset + j]); - weight_sum += weight; - let joint_index = indices[index_offset + j] as usize; + let weight = Vec4::ONE - weight_sum; + let joint_index = indices[index_offset + $n - 1] as usize; transform += mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); it!($it, transform_it += mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); } - let weight = Vec4::ONE - weight_sum; - let joint_index = indices[index_offset + $n - 1] as usize; - transform += mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); - it!($it, transform_it += mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); - pnt!($pnt, out_positions[i] = transform.transform_point3(in_positions[i]); out_normals[i] = it!($it, transform_it, transform).transform_vector3(in_normals[i]); @@ -498,8 +502,7 @@ macro_rules! skinning_impl { #[inline(always)] fn mat4_col_mul(m: &Mat4, v: Vec4) -> Mat4 { - let res = Mat4::from_cols(m.x_axis * v, m.y_axis * v, m.z_axis * v, m.w_axis * v); - return res; + Mat4::from_cols(m.x_axis * v, m.y_axis * v, m.z_axis * v, m.w_axis * v) } macro_rules! skinning_c { @@ -530,7 +533,7 @@ where /// Runs skinning job's task. /// The validate job before any operation is performed. pub fn run(&mut self) -> Result<(), OzzError> { - if self.influences_count <= 0 { + if self.influences_count == 0 { return Err(OzzError::InvalidJob); } @@ -545,7 +548,7 @@ where } } - return match branch { + match branch { 0 => self.skinning_1_p(), 1 => self.skinning_1_pn(), 2 => self.skinning_1_pnt(), @@ -572,7 +575,7 @@ where 23 => self.skinning_n_pn_it(), 24 => self.skinning_n_pnt_it(), _ => unreachable!(), - }; + } } skinning_1!(skinning_1_p, _, P); diff --git a/src/track.rs b/src/track.rs index 6624d1a..b01679e 100644 --- a/src/track.rs +++ b/src/track.rs @@ -27,85 +27,85 @@ where impl TrackValue for f32 { #[inline] fn tag() -> &'static str { - return "ozz-float_track"; + "ozz-float_track" } #[inline] fn lerp(a: f32, b: f32, t: f32) -> f32 { - return a + (b - a) * t; + a + (b - a) * t } #[inline] fn abs_diff_eq(a: f32, b: f32, diff: f32) -> bool { - return (a - b).abs() <= diff; + (a - b).abs() <= diff } } impl TrackValue for Vec2 { #[inline] fn tag() -> &'static str { - return "ozz-float2_track"; + "ozz-float2_track" } #[inline] fn lerp(a: Vec2, b: Vec2, t: f32) -> Vec2 { - return Vec2::lerp(a, b, t); + Vec2::lerp(a, b, t) } #[inline] fn abs_diff_eq(a: Vec2, b: Vec2, diff: f32) -> bool { - return Vec2::abs_diff_eq(a, b, diff); + Vec2::abs_diff_eq(a, b, diff) } } impl TrackValue for Vec3 { #[inline] fn tag() -> &'static str { - return "ozz-float3_track"; + "ozz-float3_track" } #[inline] fn lerp(a: Vec3, b: Vec3, t: f32) -> Vec3 { - return Vec3::lerp(a, b, t); + Vec3::lerp(a, b, t) } #[inline] fn abs_diff_eq(a: Vec3, b: Vec3, diff: f32) -> bool { - return Vec3::abs_diff_eq(a, b, diff); + Vec3::abs_diff_eq(a, b, diff) } } impl TrackValue for Vec4 { #[inline] fn tag() -> &'static str { - return "ozz-float4_track"; + "ozz-float4_track" } #[inline] fn lerp(a: Vec4, b: Vec4, t: f32) -> Vec4 { - return Vec4::lerp(a, b, t); + Vec4::lerp(a, b, t) } #[inline] fn abs_diff_eq(a: Vec4, b: Vec4, diff: f32) -> bool { - return Vec4::abs_diff_eq(a, b, diff); + Vec4::abs_diff_eq(a, b, diff) } } impl TrackValue for Quat { #[inline] fn tag() -> &'static str { - return "ozz-quat_track"; + "ozz-quat_track" } #[inline] fn lerp(a: Quat, b: Quat, t: f32) -> Quat { - return Quat::lerp(a, b, t); + Quat::lerp(a, b, t) } #[inline] fn abs_diff_eq(a: Quat, b: Quat, diff: f32) -> bool { - return Quat::abs_diff_eq(a, b, diff); + Quat::abs_diff_eq(a, b, diff) } } @@ -129,13 +129,13 @@ impl Track { /// `Track` resource file tag for `Archive`. #[inline] pub fn tag() -> &'static str { - return V::tag(); + V::tag() } /// `Track` resource file version for `Archive`. #[inline] pub fn version() -> u32 { - return 1; + 1 } #[cfg(test)] @@ -143,13 +143,13 @@ impl Track { if values.len() != ratios.len() || (values.len() + 7) / 8 != steps.len() { return Err(OzzError::custom("Invalid arguments")); } - return Ok(Track { + Ok(Track { key_count: values.len() as u32, ratios: ratios.to_vec(), values: values.to_vec(), steps: steps.to_vec(), name: String::new(), - }); + }) } /// Reads an `Track` from an `Archive`. @@ -174,27 +174,27 @@ impl Track { name = String::from_utf8(buf).map_err(|e| e.utf8_error())?; } - return Ok(Track { + Ok(Track { key_count, ratios, values, steps, name, - }); + }) } /// Reads an `Track` from a file path. #[cfg(not(feature = "wasm"))] pub fn from_path>(path: P) -> Result, OzzError> { let mut archive = Archive::from_path(path)?; - return Track::from_archive(&mut archive); + Track::from_archive(&mut archive) } // Only for wasm test in NodeJS environment. #[cfg(all(feature = "wasm", feature = "nodejs"))] pub fn from_path(path: &str) -> Result, OzzError> { let mut archive = Archive::from_path(path)?; - return Track::from_archive(&mut archive); + Track::from_archive(&mut archive) } } @@ -202,30 +202,30 @@ impl Track { /// The key count in the track. #[inline] pub fn key_count(&self) -> usize { - return self.key_count as usize; + self.key_count as usize } /// Keyframe values. #[inline] pub fn values(&self) -> &[V] { - return &self.values; + &self.values } /// Keyframe ratios (0 is the beginning of the track, 1 is the end). #[inline] pub fn ratios(&self) -> &[f32] { - return &self.ratios; + &self.ratios } /// Keyframe modes (1 bit per key): 1 for step, 0 for linear. #[inline] pub fn steps(&self) -> &[u8] { - return &self.steps; + &self.steps } /// Track name. #[inline] pub fn name(&self) -> &str { - return &self.name; + &self.name } } diff --git a/src/track_sampling_job.rs b/src/track_sampling_job.rs index 0143c98..4f1d885 100644 --- a/src/track_sampling_job.rs +++ b/src/track_sampling_job.rs @@ -35,11 +35,11 @@ where T: OzzObj>, { fn default() -> TrackSamplingJob { - return TrackSamplingJob { + TrackSamplingJob { track: None, ratio: 0.0, result: V::default(), - }; + } } } @@ -71,7 +71,7 @@ where /// Gets ratio of `TrackSamplingJob`. #[inline] pub fn ratio(&self) -> f32 { - return self.ratio; + self.ratio } /// Sets ratio of `TrackSamplingJob`. @@ -87,7 +87,7 @@ where /// Gets **output** result of `TrackSamplingJob`. #[inline] pub fn result(&self) -> V { - return self.result; + self.result } /// Clears result of `TrackSamplingJob`. @@ -105,7 +105,7 @@ where /// Validates `TrackSamplingJob` parameters. #[inline] pub fn validate(&self) -> bool { - return self.track.is_some(); + self.track.is_some() } /// Runs track sampling job's task. @@ -137,7 +137,7 @@ where self.result = V::lerp(v0, v1, t); } - return Ok(()); + Ok(()) } } @@ -319,11 +319,14 @@ mod track_sampling_tests { job.set_track(track.clone()); execute_test(&mut job, 0.0, Quat::from_xyzw(0.70710677, 0.0, 0.0, 0.70710677)); + #[allow(clippy::excessive_precision)] execute_test(&mut job, 0.1, Quat::from_xyzw(0.61721331, 0.15430345, 0.0, 0.77151674)); execute_test(&mut job, 0.4999999, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677)); execute_test(&mut job, 0.5, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677)); execute_test(&mut job, 0.6, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677)); + #[allow(clippy::approx_constant)] execute_test(&mut job, 0.7, Quat::from_xyzw(0.70710677, 0.0, 0.0, 0.7071067)); + #[allow(clippy::excessive_precision)] execute_test(&mut job, 0.8, Quat::from_xyzw(0.38268333, 0.0, 0.0, 0.92387962)); execute_test(&mut job, 0.9, Quat::from_xyzw(0.0, 0.0, 0.0, 1.0)); execute_test(&mut job, 1.0, Quat::from_xyzw(0.0, 0.0, 0.0, 1.0)); diff --git a/src/track_triggering_job.rs b/src/track_triggering_job.rs index e0e5a33..1c91e43 100644 --- a/src/track_triggering_job.rs +++ b/src/track_triggering_job.rs @@ -24,10 +24,10 @@ pub struct Edge { impl Edge { /// Creates a new `Edge`. pub fn new(ratio: f32, rising: bool) -> Edge { - return Edge { - ratio: ratio, - rising: rising, - }; + Edge { + ratio, + rising, + } } } @@ -62,12 +62,12 @@ where T: OzzObj>, { fn default() -> TrackTriggeringJob { - return TrackTriggeringJob { + TrackTriggeringJob { track: None, from: 0.0, to: 0.0, threshold: 0.0, - }; + } } } @@ -98,7 +98,7 @@ where /// Gets from of `TrackTriggeringJob`. #[inline] pub fn from(&self) -> f32 { - return self.from; + self.from } /// Sets from of `TrackTriggeringJob`. @@ -119,7 +119,7 @@ where /// Gets to of `TrackTriggeringJob`. #[inline] pub fn to(&self) -> f32 { - return self.to; + self.to } /// Sets to of `TrackTriggeringJob`. @@ -140,7 +140,7 @@ where /// Gets threshold of `TrackTriggeringJob`. #[inline] pub fn threshold(&self) -> f32 { - return self.threshold; + self.threshold } /// Sets threshold of `TrackTriggeringJob`. @@ -158,15 +158,15 @@ where /// Validates `TrackTriggeringJob` parameters. #[inline] pub fn validate(&self) -> bool { - return self.track.is_some(); + self.track.is_some() } /// Runs track triggering job's task. /// The validate job before any operation is performed. /// /// Returns an iterator of `Edge` that represents the detected edges. - pub fn run<'t>(&'t mut self) -> Result, OzzError> { - if !self.track.is_some() { + pub fn run(&mut self) -> Result, OzzError> { + if self.track.is_none() { return Err(OzzError::InvalidJob); } return Ok(TrackTriggeringIter::new(self)); @@ -192,8 +192,8 @@ where fn new(job: &'t TrackTriggeringJob) -> TrackTriggeringIter<'t, T> { let track = job.track().unwrap().obj(); let end = job.from == job.to; - return TrackTriggeringIter { - job: job, + TrackTriggeringIter { + job, track: if end { None } else { Some(track) }, outer: job.from.floor(), inner: if job.from < job.to { @@ -201,7 +201,7 @@ where } else { track.key_count() as isize - 1 }, - }; + } } fn detect_edge(&self, it0: usize, it1: usize, forward: bool) -> Option { @@ -228,17 +228,15 @@ where let step = (track.steps()[it0 / 8] & (1 << (it0 & 7))) != 0; if step { edge.ratio = track.ratios()[it1]; + } else if it1 == 0 { + edge.ratio = 0.0; } else { - if it1 == 0 { - edge.ratio = 0.0; - } else { - let alpha = (self.job.threshold - val0) / (val1 - val0); - let ratio0 = track.ratios()[it0]; - let ratio1 = track.ratios()[it1]; - edge.ratio = ratio0 + (ratio1 - ratio0) * alpha; - } + let alpha = (self.job.threshold - val0) / (val1 - val0); + let ratio0 = track.ratios()[it0]; + let ratio1 = track.ratios()[it1]; + edge.ratio = ratio0 + (ratio1 - ratio0) * alpha; } - return Some(edge); + Some(edge) } } @@ -301,7 +299,7 @@ where // iterator end self.track = None; - return None; + None } } @@ -315,21 +313,21 @@ mod track_triggering_tests { #[wasm_bindgen_test] fn test_validity() { let mut job: TrackTriggeringJobRc = TrackTriggeringJob::default(); - assert_eq!(job.validate(), false); + assert!(!job.validate()); assert!(job.run().unwrap_err().is_invalid_job()); let mut job: TrackTriggeringJobRc = TrackTriggeringJob::default(); job.set_track(Rc::new(Track::default())); job.set_from(0.0); job.set_to(1.0); - assert_eq!(job.validate(), true); + assert!(job.validate()); assert!(job.run().is_ok()); let mut job: TrackTriggeringJobRc = TrackTriggeringJob::default(); job.set_track(Rc::new(Track::default())); job.set_from(0.0); job.set_to(0.0); - assert_eq!(job.validate(), true); + assert!(job.validate()); assert!(job.run().is_ok()); } @@ -608,7 +606,7 @@ mod track_triggering_tests { check_all( &mut job, -1.0, - -core::f32::MIN_POSITIVE, + -f32::MIN_POSITIVE, if edges[len - 1].ratio != 1.0 { len } else { len - 1 }, edges, |i| i, From 2a3c81add107cbc06b6a94f0fdc403fa78e079e4 Mon Sep 17 00:00:00 2001 From: Abe M Date: Thu, 29 Aug 2024 03:33:45 -0700 Subject: [PATCH 2/6] Fixing warnings, refactors --- src/animation.rs | 100 +++--- src/archive.rs | 8 +- src/base.rs | 38 +- src/blending_job.rs | 70 ++-- src/endian.rs | 42 +-- src/ik_two_bone_job.rs | 57 +-- src/local_to_model_job.rs | 50 +-- src/math.rs | 29 +- src/sampling_job.rs | 716 ++++++++++++++++---------------------- src/skeleton.rs | 110 +----- src/skinning_job.rs | 38 +- tests/common.rs | 26 +- tests/context.rs | 2 +- tests/look_at.rs | 12 +- tests/track.rs | 2 +- tests/two_bone_ik.rs | 6 +- 16 files changed, 544 insertions(+), 762 deletions(-) diff --git a/src/animation.rs b/src/animation.rs index 9ddf0d2..f8b95bd 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -22,12 +22,12 @@ pub struct Float3Key([u16; 3]); impl Float3Key { pub const fn new(value: [u16; 3]) -> Float3Key { - return Float3Key(value); + Float3Key(value) } #[inline] pub fn decompress(&self) -> Vec3 { - return Vec3::new(f16_to_f32(self.0[0]), f16_to_f32(self.0[1]), f16_to_f32(self.0[2])); + Vec3::new(f16_to_f32(self.0[0]), f16_to_f32(self.0[1]), f16_to_f32(self.0[2])) } #[inline] @@ -42,7 +42,7 @@ impl ArchiveRead for Float3Key { #[inline] fn read(archive: &mut Archive) -> Result { let value: [u16; 3] = [archive.read()?, archive.read()?, archive.read()?]; - return Ok(Float3Key(value)); + Ok(Float3Key(value)) } } @@ -55,7 +55,7 @@ pub struct QuaternionKey([u16; 3]); impl QuaternionKey { pub const fn new(value: [u16; 3]) -> QuaternionKey { - return QuaternionKey(value); + QuaternionKey(value) } #[inline] @@ -64,7 +64,7 @@ impl QuaternionKey { let bigest = self.0[0] & 0x3; let sign = (self.0[0] >> 2) & 0x1; let value = [packed & 0x7fff, (packed >> 15) & 0x7fff, (self.0[2] as u32) >> 1]; - return (bigest, sign, value); + (bigest, sign, value) } #[inline] @@ -90,7 +90,7 @@ impl QuaternionKey { let w0 = ww0.sqrt(); let restored = if sign == 0 { w0 } else { -w0 }; cpnt[largest as usize] = restored; - return Quat::from_vec4(cpnt); + Quat::from_vec4(cpnt) } #[rustfmt::skip] @@ -151,10 +151,10 @@ impl QuaternionKey { cpnt[largest2 as usize] = fx4(ix4(cpnt[largest2 as usize]) | (restored & MASK_00F0)); cpnt[largest3 as usize] = fx4(ix4(cpnt[largest3 as usize]) | (restored & MASK_000F)); - soa.x = unsafe { mem::transmute(cpnt[0]) }; - soa.y = unsafe { mem::transmute(cpnt[1]) }; - soa.z = unsafe { mem::transmute(cpnt[2]) }; - soa.w = unsafe { mem::transmute(cpnt[3]) }; + soa.x = cpnt[0]; + soa.y = cpnt[1]; + soa.z = cpnt[2]; + soa.w = cpnt[3]; } } @@ -162,7 +162,7 @@ impl ArchiveRead for QuaternionKey { #[inline] fn read(archive: &mut Archive) -> Result { let value: [u16; 3] = [archive.read()?, archive.read()?, archive.read()?]; - return Ok(QuaternionKey(value)); + Ok(QuaternionKey(value)) } } @@ -298,24 +298,17 @@ pub(crate) struct AnimationRaw { } impl Animation { - /// `Animation` resource file tag for `Archive`. - #[inline] - pub fn tag() -> &'static str { - return "ozz-animation"; - } - /// `Animation` resource file version for `Archive`. - #[inline] - pub fn version() -> u32 { - return 7; - } + const VERSION: u32 = 7; + /// `Animation` resource file tag for `Archive`. + const TAG: &'static str = "ozz-animation"; /// Reads an `AnimationMeta` from an `Archive`. pub fn read_meta(archive: &mut Archive) -> Result { - if archive.tag() != Self::tag() { + if archive.tag() != Self::TAG { return Err(OzzError::InvalidTag); } - if archive.version() != Self::version() { + if archive.version() != Self::VERSION { return Err(OzzError::InvalidVersion); } @@ -339,7 +332,7 @@ impl Animation { name = String::from_utf8(buf).map_err(|e| e.utf8_error())?; } - return Ok(AnimationMeta { + Ok(AnimationMeta { version: archive.version(), duration, num_tracks, @@ -354,7 +347,7 @@ impl Animation { scales_count, s_iframe_entries_count, s_iframe_desc_count, - }); + }) } /// Reads an `Animation` from an `Archive`. @@ -404,28 +397,28 @@ impl Animation { animation.s_iframe_interval = archive.read()?; archive.read_slice(animation.scales_mut())?; - return Ok(animation); + Ok(animation) } /// Reads an `Animation` from a file path. #[cfg(not(feature = "wasm"))] pub fn from_path>(path: P) -> Result { let mut archive = Archive::from_path(path)?; - return Animation::from_archive(&mut archive); + Animation::from_archive(&mut archive) } /// Reads an `Animation` from a file path. #[cfg(all(feature = "wasm", feature = "nodejs"))] pub fn from_path(path: &str) -> Result { let mut archive = Archive::from_path(path)?; - return Animation::from_archive(&mut archive); + Animation::from_archive(&mut archive) } pub(crate) fn from_raw(raw: &AnimationRaw) -> Animation { let meta = AnimationMeta { - version: Animation::version(), + version: Animation::VERSION, duration: raw.duration, - num_tracks: raw.num_tracks as u32, + num_tracks: raw.num_tracks, name: raw.name.clone(), timepoints_count: raw.timepoints.len() as u32, translations_count: raw.translations.len() as u32, @@ -461,7 +454,7 @@ impl Animation { 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; + animation } pub(crate) fn to_raw(&self) -> AnimationRaw { @@ -571,8 +564,8 @@ impl Animation { 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::()); + animation.t_iframe_entries = ptr; + ptr = ptr.add(animation.t_iframe_entries_count as usize); 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::()); @@ -583,8 +576,8 @@ impl Animation { 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::()); + animation.r_iframe_entries = ptr; + ptr = ptr.add(animation.r_iframe_entries_count as usize); 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::()); @@ -595,15 +588,15 @@ impl Animation { 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::()); + animation.s_iframe_entries = ptr; + ptr = ptr.add(animation.s_iframe_entries_count as usize); 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 } } @@ -621,32 +614,32 @@ impl Animation { /// Gets the animation clip duration. #[inline] pub fn duration(&self) -> f32 { - return self.duration; + self.duration } /// Gets the number of animated tracks. #[inline] pub fn num_tracks(&self) -> usize { - return self.num_tracks as usize; + 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 as usize) + 3) & !0x3; + ((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 as usize) + 3) / 4; + ((self.num_tracks as usize) + 3) / 4 } /// Gets animation name. #[inline] pub fn name(&self) -> &str { - return &self.name; + &self.name } /// Gets the buffer of time points. @@ -972,7 +965,7 @@ const _: () = { impl Serialize for Animation { fn serialize(&self, serializer: &mut S) -> Result { - return Ok(AnimationResolver { + 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)?, @@ -990,7 +983,7 @@ const _: () = { 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)?, - }); + }) } } @@ -999,9 +992,9 @@ const _: () = { fn deserialize(&self, _: &mut D) -> Result { let archived = from_archived!(self); let mut animation = Animation::new(AnimationMeta { - version: Animation::version(), + version: Animation::VERSION, duration: archived.duration, - num_tracks: archived.num_tracks as u32, + num_tracks: archived.num_tracks, name: archived.name.to_string(), timepoints_count: archived.timepoints.len() as u32, translations_count: archived.translations.len() as u32, @@ -1064,7 +1057,7 @@ const _: () = { .copy_from_slice(archived.s_iframe_desc.as_slice()); animation.s_iframe_interval = archived.s_iframe_interval; - return Ok(animation); + Ok(animation) } } }; @@ -1076,18 +1069,19 @@ const _: () = { impl Serialize for Animation { fn serialize(&self, serializer: S) -> Result { let raw = self.to_raw(); - return raw.serialize(serializer); + 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)); + Ok(Animation::from_raw(&raw)) } } }; +#[allow(clippy::excessive_precision)] #[cfg(test)] mod tests { use wasm_bindgen_test::*; @@ -1248,7 +1242,7 @@ mod tests { 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 mut deserializer = rkyv::Infallible; let animation2: Animation = archived.deserialize(&mut deserializer).unwrap(); assert_eq!(animation.duration(), animation2.duration()); @@ -1310,7 +1304,7 @@ mod tests { animation2.scales_ctrl().iframe_desc ); } - + #[cfg(feature = "serde")] #[test] #[wasm_bindgen_test] @@ -1320,7 +1314,7 @@ mod tests { 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()); diff --git a/src/archive.rs b/src/archive.rs index 079e7bc..eb5a40c 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -61,7 +61,7 @@ impl Archive { /// 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); + T::read_slice(self, buffer) } /// Does the endian need to be swapped. @@ -139,10 +139,10 @@ pub trait ArchiveRead { /// * `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)?; + for item in buffer.iter_mut() { + *item = Self::read(archive)?; } - return Ok(()); + Ok(()) } } diff --git a/src/base.rs b/src/base.rs index 484dae5..352b78c 100644 --- a/src/base.rs +++ b/src/base.rs @@ -46,35 +46,35 @@ pub enum OzzError { impl OzzError { pub fn custom(s: S) -> OzzError { - return OzzError::Custom(Box::new(s.to_string())); + OzzError::Custom(Box::new(s.to_string())) } pub fn is_lock_poison(&self) -> bool { - return matches!(self, OzzError::LockPoison); + matches!(self, OzzError::LockPoison) } pub fn is_invalid_job(&self) -> bool { - return matches!(self, OzzError::InvalidJob); + matches!(self, OzzError::InvalidJob) } pub fn is_io(&self) -> bool { - return matches!(self, OzzError::IO(_)); + matches!(self, OzzError::IO(_)) } pub fn is_utf8(&self) -> bool { - return matches!(self, OzzError::Utf8(_)); + matches!(self, OzzError::Utf8(_)) } pub fn is_invalid_tag(&self) -> bool { - return matches!(self, OzzError::InvalidTag); + matches!(self, OzzError::InvalidTag) } pub fn is_invalid_version(&self) -> bool { - return matches!(self, OzzError::InvalidVersion); + matches!(self, OzzError::InvalidVersion) } pub fn is_custom(&self) -> bool { - return matches!(self, OzzError::Custom(_)); + matches!(self, OzzError::Custom(_)) } } @@ -99,7 +99,7 @@ pub struct DeterministicState; impl DeterministicState { /// Creates a new `DeterministicState` that builds `DefaultHasher` with default keys. pub const fn new() -> DeterministicState { - return DeterministicState; + DeterministicState } } @@ -107,7 +107,7 @@ impl BuildHasher for DeterministicState { type Hasher = DefaultHasher; fn build_hasher(&self) -> DefaultHasher { - return DefaultHasher::default(); + DefaultHasher::default() } } @@ -140,13 +140,13 @@ ozz_index!(i16); #[inline(always)] pub(crate) fn align_usize(size: usize, align: usize) -> usize { assert!(align.is_power_of_two()); - return (size + align - 1) & !(align - 1); + (size + align - 1) & !(align - 1) } #[inline(always)] pub(crate) fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { assert!(align.is_power_of_two()); - return align_usize(ptr as usize, align) as *mut u8; + align_usize(ptr as usize, align) as *mut u8 } /// Represents a reference to the ozz resource object. @@ -161,14 +161,14 @@ pub trait OzzObj { impl OzzObj for T { #[inline(always)] fn obj(&self) -> &T { - return self; + self } } impl<'t, T: Debug> OzzObj for &'t T { #[inline(always)] fn obj(&self) -> &T { - return self; + self } } @@ -241,7 +241,7 @@ impl<'t, T> Deref for ObSliceRef<'t, T> { #[inline(always)] fn deref(&self) -> &Self::Target { - return self.0; + self.0 } } @@ -278,14 +278,14 @@ impl<'t, T> Deref for ObSliceRefMut<'t, T> { #[inline(always)] fn deref(&self) -> &Self::Target { - return self.0; + self.0 } } impl<'t, T> DerefMut for ObSliceRefMut<'t, T> { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { - return self.0; + self.0 } } @@ -425,7 +425,7 @@ pub type OzzRcBuf = Rc>>; /// Creates a new `Rc>>`. #[inline] pub fn ozz_rc_buf(v: Vec) -> OzzRcBuf { - return Rc::new(RefCell::new(v)); + Rc::new(RefCell::new(v)) } /// Shortcuts for `Arc>`. @@ -434,5 +434,5 @@ pub type OzzArcBuf = Arc>>; /// Creates a new `Arc>>`. #[inline] pub fn ozz_arc_buf(v: Vec) -> OzzArcBuf { - return Arc::new(RwLock::new(v)); + Arc::new(RwLock::new(v)) } diff --git a/src/blending_job.rs b/src/blending_job.rs index da2d775..383335d 100644 --- a/src/blending_job.rs +++ b/src/blending_job.rs @@ -38,31 +38,31 @@ pub struct BlendingLayer> { impl> BlendingLayer { pub fn new(transform: I) -> BlendingLayer { - return BlendingLayer { + BlendingLayer { transform, weight: 0.0, joint_weights: Vec::new(), - }; + } } pub fn with_weight(transform: I, weight: f32) -> BlendingLayer { - return BlendingLayer { + BlendingLayer { transform, weight, joint_weights: Vec::new(), - }; + } } pub fn with_joint_weights(transform: I, joint_weights: Vec) -> BlendingLayer { - return BlendingLayer { + BlendingLayer { transform, weight: 0.0, joint_weights, - }; + } } fn joint_weight(&self, idx: usize) -> f32x4 { - return fx4_from_vec4(self.joint_weights[idx]); + fx4_from_vec4(self.joint_weights[idx]) } } @@ -77,24 +77,24 @@ pub struct BlendingContext { impl Default for BlendingContext { fn default() -> BlendingContext { - return BlendingContext { + BlendingContext { num_passes: 0, num_partial_passes: 0, accumulated_weight: 0.0, accumulated_weights: Vec::new(), - }; + } } } impl BlendingContext { /// New blending context with a given soa joints. pub fn new(soa_joints: usize) -> BlendingContext { - return BlendingContext { + BlendingContext { num_passes: 0, num_partial_passes: 0, accumulated_weight: 0.0, accumulated_weights: vec![f32x4::splat(0.0); soa_joints], - }; + } } } @@ -138,14 +138,14 @@ where O: OzzMutBuf, { fn default() -> BlendingJob { - return BlendingJob { + BlendingJob { skeleton: None, context: Some(BlendingContext::default()), threshold: 0.1, layers: Vec::new(), additive_layers: Vec::new(), output: None, - }; + } } } @@ -201,13 +201,13 @@ where /// Takes context of `BlendingJob`. See [BlendingContext]. #[inline] pub fn take_context(&mut self) -> Option { - return self.context.take(); + self.context.take() } /// Gets threshold of `BlendingJob`. #[inline] pub fn threshold(&self) -> f32 { - return self.threshold; + self.threshold } /// Set threshold of `BlendingJob`. @@ -223,7 +223,7 @@ where /// Gets layers of `BlendingJob`. #[inline] pub fn layers(&self) -> &[BlendingLayer] { - return &self.layers; + &self.layers } /// Gets mutable layers of `BlendingJob`. @@ -231,13 +231,13 @@ where /// Job input layers, can be empty or nullptr. The range of layers that must be blended. #[inline] pub fn layers_mut(&mut self) -> &mut Vec> { - return &mut self.layers; + &mut self.layers } /// Gets additive layers of `BlendingJob`. #[inline] pub fn additive_layers(&self) -> &[BlendingLayer] { - return &self.additive_layers; + &self.additive_layers } /// Gets mutable additive layers of `BlendingJob`. @@ -245,13 +245,13 @@ where /// Job input additive layers, can be empty or nullptr. The range of layers that must be added to the output. #[inline] pub fn additive_layers_mut(&mut self) -> &mut Vec> { - return &mut self.additive_layers; + &mut self.additive_layers } /// Gets output of `BlendingJob`. #[inline] pub fn output(&self) -> Option<&O> { - return self.output.as_ref(); + self.output.as_ref() } /// Sets output of `BlendingJob`. @@ -292,7 +292,7 @@ where } } - return Some(ok); + Some(ok) })() .unwrap_or(false); } @@ -321,7 +321,7 @@ where Self::blend_rest_pose(skeleton, ctx, self.threshold, &mut output); Self::normalize(skeleton, ctx, &mut output); Self::add_layers(skeleton, &self.additive_layers, &mut output)?; - return Ok(()); + Ok(()) } fn blend_layers( @@ -380,7 +380,7 @@ where } } - return Ok(()); + Ok(()) } fn blend_rest_pose(skeleton: &Skeleton, ctx: &mut BlendingContext, threshold: f32, output: &mut [SoaTransform]) { @@ -391,9 +391,7 @@ where if bp_weight > 0.0 { if ctx.num_passes == 0 { ctx.accumulated_weight = 1.0; - for idx in 0..joint_rest_poses.len() { - output[idx] = joint_rest_poses[idx]; - } + output.copy_from_slice(joint_rest_poses); } else { ctx.accumulated_weight = threshold; let simd_bp_weight = f32x4::splat(bp_weight); @@ -417,15 +415,13 @@ where if ctx.num_partial_passes == 0 { let ratio = f32x4::splat(ctx.accumulated_weight.recip()); - for idx in 0..joint_rest_poses.len() { - let dest = &mut output[idx]; + for dest in output.iter_mut().take(joint_rest_poses.len()) { dest.translation = dest.translation.mul_num(ratio); dest.rotation = dest.rotation.normalize(); dest.scale = dest.scale.mul_num(ratio); } } else { - for idx in 0..joint_rest_poses.len() { - let dest = &mut output[idx]; + for (idx, dest) in output.iter_mut().enumerate().take(joint_rest_poses.len()) { let ratio = ctx.accumulated_weights[idx].recip(); dest.translation = dest.translation.mul_num(ratio); dest.rotation = dest.rotation.normalize(); @@ -483,7 +479,7 @@ where } } - return Ok(()); + Ok(()) } #[inline(always)] @@ -543,6 +539,7 @@ where } } +#[allow(clippy::excessive_precision)] #[cfg(test)] mod blending_tests { use std::mem; @@ -559,7 +556,7 @@ mod blending_tests { }; fn make_buf(v: Vec) -> Rc>> { - return Rc::new(RefCell::new(v)); + Rc::new(RefCell::new(v)) } #[test] @@ -704,7 +701,7 @@ mod blending_tests { input2: Vec, weights2: Vec, ) -> Vec>>>> { - return vec![ + vec![ BlendingLayer { transform: make_buf(input1), weight: 0.0, @@ -715,7 +712,7 @@ mod blending_tests { weight: 0.0, joint_weights: weights2, }, - ]; + ] } fn execute_test( @@ -1026,12 +1023,13 @@ 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(&SkeletonRaw { + Rc::new(Skeleton::from_raw(&SkeletonRaw { joint_rest_poses, joint_names: JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()), joint_parents: vec![0; 4], - })); + })) } + #[test] #[wasm_bindgen_test] fn test_normalize() { diff --git a/src/endian.rs b/src/endian.rs index 0971335..9ec5c53 100644 --- a/src/endian.rs +++ b/src/endian.rs @@ -1,5 +1,3 @@ -use std::mem; - pub trait SwapEndian { fn swap_endian(self) -> Self; } @@ -13,103 +11,99 @@ pub enum Endian { impl Endian { pub fn native() -> Endian { let num: u16 = 1; - let bytes: [u8; 2] = unsafe { mem::transmute(num) }; + let bytes: [u8; 2] = num.to_ne_bytes(); if bytes[0] == 0 { - return Endian::Big; + Endian::Big } else { - return Endian::Little; + Endian::Little } } pub fn from_tag(tag: u8) -> Endian { if tag == 0 { - return Endian::Big; + Endian::Big } else { - return Endian::Little; + Endian::Little } } } impl SwapEndian for u8 { fn swap_endian(self) -> u8 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for i8 { fn swap_endian(self) -> i8 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for bool { fn swap_endian(self) -> bool { - return self; + self } } impl SwapEndian for u16 { fn swap_endian(self) -> u16 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for i16 { fn swap_endian(self) -> i16 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for u32 { fn swap_endian(self) -> u32 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for i32 { fn swap_endian(self) -> i32 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for f32 { fn swap_endian(self) -> f32 { - let mut tmp: u32 = unsafe { mem::transmute(self) }; - tmp = tmp.swap_bytes(); - return unsafe { mem::transmute(tmp) }; + f32::from_bits(self.to_bits().swap_bytes()) } } impl SwapEndian for f64 { fn swap_endian(self) -> f64 { - let mut tmp: u64 = unsafe { mem::transmute(self) }; - tmp = tmp.swap_bytes(); - return unsafe { mem::transmute(tmp) }; + f64::from_bits(self.to_bits().swap_bytes()) } } impl SwapEndian for u64 { fn swap_endian(self) -> u64 { - return self.swap_bytes(); + self.swap_bytes() } } impl SwapEndian for i64 { fn swap_endian(self) -> i64 { - return self.swap_bytes(); + self.swap_bytes() } } impl<'t, T: Copy + SwapEndian> SwapEndian for &'t mut [T] { fn swap_endian(self) -> &'t mut [T] { self.iter_mut().for_each(|e| *e = e.swap_endian()); - return self; + self } } impl SwapEndian for Vec { fn swap_endian(mut self) -> Vec { self.iter_mut().for_each(|e| *e = e.swap_endian()); - return self; + self } } diff --git a/src/ik_two_bone_job.rs b/src/ik_two_bone_job.rs index d94aa96..5e53582 100644 --- a/src/ik_two_bone_job.rs +++ b/src/ik_two_bone_job.rs @@ -25,17 +25,17 @@ impl IKConstantSetup { let inv_start_joint = job.start_joint.invert(); let inv_mid_joint = job.mid_joint.invert(); - let start_ms: f32x4 = inv_mid_joint.transform_point(job.start_joint.cols[3].into()); - let end_ms: f32x4 = inv_mid_joint.transform_point(job.end_joint.cols[3].into()); + let start_ms: f32x4 = inv_mid_joint.transform_point(job.start_joint.cols[3]); + let end_ms: f32x4 = inv_mid_joint.transform_point(job.end_joint.cols[3]); - let mid_ss: f32x4 = inv_start_joint.transform_point(job.mid_joint.cols[3].into()); - let end_ss: f32x4 = inv_start_joint.transform_point(job.end_joint.cols[3].into()); + let mid_ss: f32x4 = inv_start_joint.transform_point(job.mid_joint.cols[3]); + let end_ss: f32x4 = inv_start_joint.transform_point(job.end_joint.cols[3]); let mid_end_ss = end_ss - mid_ss; let start_end_ss = end_ss; let start_mid_ss = mid_ss; - return IKConstantSetup { + IKConstantSetup { inv_start_joint, start_mid_ms: -start_ms, mid_end_ms: end_ms, @@ -43,7 +43,7 @@ impl IKConstantSetup { start_mid_ss_len2: vec3_length2_s(start_mid_ss), // [x] mid_end_ss_len2: vec3_length2_s(mid_end_ss), // [x] start_end_ss_len2: vec3_length2_s(start_end_ss), // [x] - }; + } } } @@ -98,7 +98,7 @@ impl IKTwoBoneJob { /// Gets target of `IKTwoBoneJob`. #[inline] pub fn target(&self) -> Vec3A { - return fx4_to_vec3a(self.target); + fx4_to_vec3a(self.target) } /// Sets target of `IKTwoBoneJob`. @@ -112,7 +112,7 @@ impl IKTwoBoneJob { /// Gets mid axis of `IKTwoBoneJob` #[inline] pub fn mid_axis(&self) -> Vec3A { - return fx4_to_vec3a(self.mid_axis); + fx4_to_vec3a(self.mid_axis) } /// Sets mid axis of `IKTwoBoneJob`. @@ -132,7 +132,7 @@ impl IKTwoBoneJob { /// Gets pole vector of `IKTwoBoneJob`. #[inline] pub fn pole_vector(&self) -> Vec3A { - return fx4_to_vec3a(self.pole_vector); + fx4_to_vec3a(self.pole_vector) } /// Sets pole vector of `IKTwoBoneJob`. @@ -151,7 +151,7 @@ impl IKTwoBoneJob { /// Gets twist angle of `IKTwoBoneJob`. #[inline] pub fn twist_angle(&self) -> f32 { - return self.twist_angle; + self.twist_angle } /// Sets twist angle of `IKTwoBoneJob`. @@ -165,7 +165,7 @@ impl IKTwoBoneJob { /// Gets soften of `IKTwoBoneJob`. #[inline] pub fn soften(&self) -> f32 { - return self.soften; + self.soften } /// Sets soften of `IKTwoBoneJob`. @@ -182,7 +182,7 @@ impl IKTwoBoneJob { /// Gets weight of `IKTwoBoneJob`. #[inline] pub fn weight(&self) -> f32 { - return self.weight; + self.weight } /// Sets weight of `IKTwoBoneJob`. @@ -197,7 +197,7 @@ impl IKTwoBoneJob { /// Gets start joint of `IKTwoBoneJob` #[inline] pub fn start_joint(&self) -> Mat4 { - return self.start_joint.into(); + self.start_joint.into() } /// Sets start joint of `IKTwoBoneJob`. @@ -212,7 +212,7 @@ impl IKTwoBoneJob { /// Gets mid joint of `IKTwoBoneJob`. #[inline] pub fn mid_joint(&self) -> Mat4 { - return self.mid_joint.into(); + self.mid_joint.into() } /// Sets mid joint of `IKTwoBoneJob`. @@ -227,7 +227,7 @@ impl IKTwoBoneJob { /// Gets end joint of `IKTwoBoneJob`. #[inline] pub fn end_joint(&self) -> Mat4 { - return self.end_joint.into(); + self.end_joint.into() } /// Sets end joint of `IKTwoBoneJob` @@ -246,7 +246,7 @@ impl IKTwoBoneJob { /// These quaternions must be multiplied to the local-space quaternion of their respective joints. #[inline] pub fn start_joint_correction(&self) -> Quat { - return fx4_to_quat(self.start_joint_correction); + fx4_to_quat(self.start_joint_correction) } /// Clears start joint correction of `IKTwoBoneJob`. @@ -262,7 +262,7 @@ impl IKTwoBoneJob { /// These quaternions must be multiplied to the local-space quaternion of their respective joints. #[inline] pub fn mid_joint_correction(&self) -> Quat { - return fx4_to_quat(self.mid_joint_correction); + fx4_to_quat(self.mid_joint_correction) } /// Clears mid joint correction of `IKTwoBoneJob`. @@ -279,7 +279,7 @@ impl IKTwoBoneJob { /// Target is considered unreached if weight is less than 1. #[inline] pub fn reached(&self) -> bool { - return self.reached; + self.reached } /// Clears reached of `IKTwoBoneJob`. @@ -299,7 +299,7 @@ impl IKTwoBoneJob { /// Validates `IKTwoBoneJob` parameters. #[inline] fn validate(&self) -> bool { - return vec3_is_normalized(self.mid_axis); + vec3_is_normalized(self.mid_axis) } /// Runs two bone IK job's task. @@ -324,7 +324,7 @@ impl IKTwoBoneJob { let start_rot_ss = self.compute_start_joint(&setup, mid_rot_ms, start_target_ss, start_target_ss_len2); self.weight_output(start_rot_ss, mid_rot_ms); - return Ok(()); + Ok(()) } fn soften_target(&self, setup: &IKConstantSetup) -> (bool, f32x4, f32x4) { @@ -369,7 +369,7 @@ impl IKTwoBoneJob { start_target_ss_len2 = start_target_original_ss_len2; // [x] } - return ((comp_mask & 0x5) == 0x4, start_target_ss, start_target_ss_len2); + ((comp_mask & 0x5) == 0x4, start_target_ss, start_target_ss_len2) } fn compute_mid_joint(&self, setup: &IKConstantSetup, start_target_ss_len2: f32x4) -> f32x4 { @@ -390,7 +390,7 @@ impl IKTwoBoneJob { let mid_angles_diff = mid_corrected_angle - mid_initial_angle; // [x] - return quat_from_axis_angle(self.mid_axis, mid_angles_diff); + quat_from_axis_angle(self.mid_axis, mid_angles_diff) } fn compute_start_joint( @@ -452,7 +452,7 @@ impl IKTwoBoneJob { } } - return start_rot_ss; + start_rot_ss } fn weight_output(&mut self, start_rot: f32x4, mid_rot: f32x4) { @@ -483,6 +483,7 @@ impl IKTwoBoneJob { } } +#[allow(clippy::excessive_precision)] #[cfg(test)] mod ik_two_bone_tests { use core::f32::consts; @@ -540,7 +541,7 @@ mod ik_two_bone_tests { // 0 degree job.set_target(parent.transform_point3a(Vec3A::new(1.0, 1.0, 0.0))); job.run().unwrap(); - assert_eq!(job.reached, true); + assert!(job.reached); assert!(job.start_joint_correction().abs_diff_eq(Quat::IDENTITY, 2e-3)); assert!(job.mid_joint_correction().abs_diff_eq(Quat::IDENTITY, 2e-3)); } @@ -549,7 +550,7 @@ mod ik_two_bone_tests { // 90 degree job.set_target(parent.transform_point3a(Vec3A::new(0.0, 1.0, 1.0))); job.run().unwrap(); - assert_eq!(job.reached, true); + assert!(job.reached); assert!(job .start_joint_correction() .abs_diff_eq(Quat::from_axis_angle(Vec3::Y, -consts::FRAC_PI_2), 2e-3)); @@ -560,7 +561,7 @@ mod ik_two_bone_tests { // 180 degree job.set_target(parent.transform_point3a(Vec3A::new(-1.0, 1.0, 0.0))); job.run().unwrap(); - assert_eq!(job.reached, true); + assert!(job.reached); assert!(job .start_joint_correction() .abs_diff_eq(Quat::from_axis_angle(Vec3::Y, consts::PI), 2e-3)); @@ -571,7 +572,7 @@ mod ik_two_bone_tests { // 270 degree job.set_target(parent.transform_point3a(Vec3A::new(0.0, 1.0, -1.0))); job.run().unwrap(); - assert_eq!(job.reached, true); + assert!(job.reached); assert!(job .start_joint_correction() .abs_diff_eq(Quat::from_axis_angle(Vec3::Y, consts::FRAC_PI_2), 2e-3)); @@ -594,7 +595,7 @@ mod ik_two_bone_tests { job.set_mid_joint(mid); job.set_end_joint(end); job.set_mid_axis(mid_axis); - return job; + job } #[test] diff --git a/src/local_to_model_job.rs b/src/local_to_model_job.rs index 3f39ab1..02ffe79 100644 --- a/src/local_to_model_job.rs +++ b/src/local_to_model_job.rs @@ -51,7 +51,7 @@ where O: OzzMutBuf, { fn default() -> LocalToModelJob { - return LocalToModelJob { + LocalToModelJob { skeleton: None, input: None, root: AosMat4::identity(), @@ -59,7 +59,7 @@ where to: SKELETON_MAX_JOINTS, from_excluded: false, output: None, - }; + } } } @@ -112,7 +112,7 @@ where /// Gets root of `LocalToModelJob`. #[inline] pub fn root(&self) -> Mat4 { - return self.root.into(); + self.root.into() } /// Sets root of `LocalToModelJob`. @@ -127,7 +127,7 @@ where /// Gets from of `LocalToModelJob`. #[inline] pub fn from(&self) -> i32 { - return self.from; + self.from } /// Sets from of `LocalToModelJob`. @@ -147,7 +147,7 @@ where /// Gets to of `LocalToModelJob`. #[inline] pub fn to(&self) -> i32 { - return self.to; + self.to } /// Sets to of `LocalToModelJob`. @@ -165,7 +165,7 @@ where /// Gets from_excluded of `LocalToModelJob`. #[inline] pub fn from_excluded(&self) -> bool { - return self.from_excluded; + self.from_excluded } /// Sets from_excluded of `LocalToModelJob`. @@ -211,7 +211,7 @@ where let mut ok = input.len() >= skeleton.num_soa_joints(); ok &= output.len() >= skeleton.num_joints(); - return Some(ok); + Some(ok) })() .unwrap_or(false); } @@ -254,7 +254,7 @@ where } } - return Ok(()); + Ok(()) } } @@ -332,7 +332,7 @@ mod local_to_model_tests { // j1 j3 // | / \ // j2 j4 j5 - return Rc::new(Skeleton::from_raw(&SkeletonRaw { + Rc::new(Skeleton::from_raw(&SkeletonRaw { joint_rest_poses: vec![ SoaTransform { translation: SoaVec3::splat_col([0.0; 3]), @@ -341,7 +341,7 @@ mod local_to_model_tests { }; 2 ], - joint_names: (|| { + joint_names: { let mut map = JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()); map.insert("j0".into(), 0); map.insert("j1".into(), 1); @@ -349,14 +349,14 @@ mod local_to_model_tests { map.insert("j3".into(), 3); map.insert("j4".into(), 4); map.insert("j5".into(), 5); - return map; - })(), + map + }, joint_parents: vec![-1, 0, 1, 0, 3, 3], - })); + })) } fn new_input1() -> Rc>> { - return Rc::new(RefCell::new(vec![ + Rc::new(RefCell::new(vec![ SoaTransform { translation: SoaVec3::new([2.0, 0.0, 1.0, -2.0], [2.0, 0.0, 2.0, -2.0], [2.0, 0.0, 4.0, -2.0]), rotation: SoaQuat::new( @@ -377,7 +377,7 @@ mod local_to_model_tests { ), scale: SoaVec3::new([1.0, -0.1, 1.0, 1.0], [1.0, -0.1, 1.0, 1.0], [1.0, -0.1, 1.0, 1.0]), }, - ])); + ])) } fn new_skeleton2() -> Rc { @@ -391,7 +391,7 @@ mod local_to_model_tests { // j2 j4 j6 // | // j5 - return Rc::new(Skeleton::from_raw(&SkeletonRaw { + Rc::new(Skeleton::from_raw(&SkeletonRaw { joint_rest_poses: vec![ SoaTransform { translation: SoaVec3::splat_col([0.0; 3]), @@ -400,7 +400,7 @@ mod local_to_model_tests { }; 2 ], - joint_names: (|| { + joint_names: { let mut map = JointHashMap::with_hashers(DeterministicState::new(), DeterministicState::new()); map.insert("j0".into(), 0); map.insert("j1".into(), 1); @@ -410,14 +410,14 @@ mod local_to_model_tests { map.insert("j5".into(), 5); map.insert("j6".into(), 6); map.insert("j7".into(), 7); - return map; - })(), + map + }, joint_parents: vec![-1, 0, 1, 0, 3, 4, 3, -1], - })); + })) } fn new_input2() -> Rc>> { - return Rc::new(RefCell::new(vec![ + Rc::new(RefCell::new(vec![ SoaTransform { translation: SoaVec3::new([2.0, 0.0, -2.0, 1.0], [2.0, 0.0, -2.0, 2.0], [2.0, 0.0, -2.0, 4.0]), rotation: SoaQuat::new( @@ -438,9 +438,10 @@ mod local_to_model_tests { ), scale: SoaVec3::new([1.0, -0.1, 1.0, 1.0], [1.0, -0.1, 1.0, 1.0], [1.0, -0.1, 1.0, 1.0]), }, - ])); + ])) } + #[allow(clippy::too_many_arguments)] fn execute_test( skeleton: &Rc, input: &Rc>>, @@ -462,10 +463,9 @@ mod local_to_model_tests { job.from_excluded = from_excluded; job.run().unwrap(); - for idx in 0..skeleton.num_joints() { + for (idx, b) in expected.iter().enumerate().take(skeleton.num_joints()) { let a = output.as_ref().borrow()[idx]; - let b = expected[idx]; - assert!(a.abs_diff_eq(b, 2e-6f32), "{} joint={} {} {}", message, idx, a, b,); + assert!(a.abs_diff_eq(*b, 2e-6f32), "{} joint={} {} {}", message, idx, a, b,); } } diff --git a/src/math.rs b/src/math.rs index 8410c5d..13c9d65 100644 --- a/src/math.rs +++ b/src/math.rs @@ -16,6 +16,7 @@ use std::simd::*; use crate::archive::{Archive, ArchiveRead}; use crate::base::OzzError; +use crate::math; pub(crate) const ZERO: f32x4 = f32x4::from_array([0.0; 4]); pub(crate) const ONE: f32x4 = f32x4::from_array([1.0; 4]); @@ -486,10 +487,10 @@ impl ArchiveRead for SoaTransform { fn read(archive: &mut Archive) -> Result { const COUNT: usize = mem::size_of::() / mem::size_of::(); let mut buffer = [0f32; COUNT]; - for idx in 0..COUNT { - buffer[idx] = archive.read()?; + for value in buffer.iter_mut() { + *value = archive.read()?; } - Ok(unsafe { mem::transmute(buffer) }) + Ok(unsafe { mem::transmute::<[f32; 40], math::SoaTransform>(buffer) }) } } @@ -565,13 +566,14 @@ impl From for AosMat4 { } } -impl Into for AosMat4 { - fn into(self) -> Mat4 { - unsafe { mem::transmute(self) } +impl From for Mat4 { + fn from(val: AosMat4) -> Self { + unsafe { mem::transmute(val) } } } impl AosMat4 { + #[allow(clippy::too_many_arguments)] #[rustfmt::skip] #[inline] pub(crate) fn new( @@ -854,8 +856,8 @@ impl SoaMat4 { pub(crate) fn f16_to_f32(n: u16) -> f32 { let sign = (n & 0x8000) as u32; let expo = (n & 0x7C00) as u32; - let base = (n & 0x03FF) as u32; if expo == 0x7C00 { + let base = (n & 0x03FF) as u32; if base != 0 { return f32::NAN; } @@ -866,12 +868,10 @@ pub(crate) fn f16_to_f32(n: u16) -> f32 { } } let expmant = (n & 0x7FFF) as u32; - unsafe { - let magic = mem::transmute::((254 - 15) << 23); - let shifted = mem::transmute::(expmant << 13); - let scaled = mem::transmute::(shifted * magic); - return mem::transmute::((sign << 16) | scaled); - }; + let magic = f32::from_bits((254 - 15) << 23); + let shifted = f32::from_bits(expmant << 13); + let scaled = (shifted * magic).to_bits(); + f32::from_bits((sign << 16) | scaled) } #[inline] @@ -1041,6 +1041,7 @@ pub(crate) fn f32_clamp_or_min(v: f32, min: f32, max: f32) -> f32 { v.max(min).min(max) } +#[allow(clippy::excessive_precision)] pub(crate) fn fx4_sin_cos(v: f32x4) -> (f32x4, f32x4) { // Implementation based on Vec4.inl from the JoltPhysics // https://github.com/jrouwe/JoltPhysics/blob/master/Jolt/Math/Vec4.inl @@ -1134,6 +1135,7 @@ pub fn f32_cos(x: f32) -> f32 { cos[0] } +#[allow(clippy::excessive_precision)] pub(crate) fn fx4_asin(v: f32x4) -> f32x4 { // Implementation based on Vec4.inl from the JoltPhysics // https://github.com/jrouwe/JoltPhysics/blob/master/Jolt/Math/Vec4.inl @@ -1296,6 +1298,7 @@ pub(crate) fn quat_positive_w(q: f32x4) -> f32x4 { fx4_xor(q, s) } +#[allow(clippy::excessive_precision)] #[cfg(test)] mod tests { use wasm_bindgen_test::*; diff --git a/src/sampling_job.rs b/src/sampling_job.rs index e878242..448059a 100644 --- a/src/sampling_job.rs +++ b/src/sampling_job.rs @@ -184,9 +184,10 @@ impl Default for SamplingContextInner { rotation_outdated: ptr::null_mut(), rotation_next: 0, - outdated_translations_ptr: std::ptr::null_mut(), - outdated_rotations_ptr: std::ptr::null_mut(), - outdated_scales_ptr: std::ptr::null_mut(), + scales: ptr::null_mut(), + scale_entries: ptr::null_mut(), + scale_outdated: ptr::null_mut(), + scale_next: 0, } } } @@ -276,7 +277,12 @@ impl Drop for SamplingContext { impl SamplingContext { #[inline(always)] fn inner(&self) -> &SamplingContextInner { - unsafe { &*self.inner } + unsafe { &*self.0 } + } + + #[inline(always)] + fn inner_mut(&mut self) -> &mut SamplingContextInner { + unsafe { &mut *self.0 } } /// Create a new `SamplingContext` @@ -321,28 +327,27 @@ impl SamplingContext { ptr = ptr.add(mem::size_of::() * inner.max_soa_tracks); inner.translation_entries = ptr as *mut u32; ptr = ptr.add(mem::size_of::() * inner.max_tracks); - inner.translation_outdated = ptr as *mut u8; - ptr = ptr.add(mem::size_of::() * inner.max_outdated); + inner.translation_outdated = ptr; + ptr = ptr.add(inner.max_outdated); ptr = align_ptr(ptr, ALIGN); inner.rotations = ptr as *mut InterpSoaQuaternion; ptr = ptr.add(mem::size_of::() * inner.max_soa_tracks); - inner.scales_ptr = ptr as *mut InterpSoaFloat3; + inner.rotation_entries = ptr as *mut u32; + ptr = ptr.add(mem::size_of::() * inner.max_tracks); + inner.rotation_outdated = ptr; + ptr = ptr.add(inner.max_outdated); + ptr = align_ptr(ptr, ALIGN); + + inner.scales = ptr as *mut InterpSoaFloat3; ptr = ptr.add(mem::size_of::() * inner.max_soa_tracks); - inner.translation_keys_ptr = ptr as *mut i32; - ptr = ptr.add(mem::size_of::() * max_tracks * 2); - inner.rotation_keys_ptr = ptr as *mut i32; - ptr = ptr.add(mem::size_of::() * max_tracks * 2); - inner.scale_keys_ptr = ptr as *mut i32; - ptr = ptr.add(mem::size_of::() * max_tracks * 2); - inner.outdated_translations_ptr = ptr; - ptr = ptr.add(inner.num_outdated); - inner.outdated_rotations_ptr = ptr; - ptr = ptr.add(inner.num_outdated); - inner.outdated_scales_ptr = ptr; - ptr = ptr.add(inner.num_outdated); - assert_eq!(ptr, (ctx.inner as *mut u8).add(size)); + inner.scale_entries = ptr as *mut u32; + ptr = ptr.add(mem::size_of::() * inner.max_tracks); + inner.scale_outdated = ptr; + ptr = ptr.add(inner.max_outdated); + ptr = align_ptr(ptr, ALIGN); + assert_eq!(ptr, (ctx.0 as *mut u8).add(size)); ctx } } @@ -352,7 +357,7 @@ impl SamplingContext { /// * `animation` - The animation to sample. Use `animation.num_tracks()` as max_tracks. pub fn from_animation(animation: &Animation) -> SamplingContext { let mut ctx = SamplingContext::new(animation.num_tracks()); - ctx.animation_id = animation as *const _ as u64; + ctx.inner_mut().animation_id = animation as *const _ as u64; ctx } @@ -370,7 +375,7 @@ impl SamplingContext { #[inline] pub fn clone_without_animation_id(&self) -> SamplingContext { let mut ctx = self.clone(); - ctx.animation_id = 0; + ctx.set_animation_id(0); ctx } @@ -581,7 +586,7 @@ impl SamplingContext { } #[inline] - fn translation_decompress_args<'t>(&'t self) -> DecompressArgs<'t, InterpSoaFloat3> { + fn translation_decompress_args(&self) -> DecompressArgs<'_, InterpSoaFloat3> { let inner = self.inner(); return DecompressArgs { entries: unsafe { slice::from_raw_parts(inner.translation_entries, inner.max_tracks) }, @@ -603,7 +608,7 @@ impl SamplingContext { } #[inline] - fn rotation_decompress_args<'t>(&'t self) -> DecompressArgs<'t, InterpSoaQuaternion> { + fn rotation_decompress_args(&self) -> DecompressArgs<'_, InterpSoaQuaternion> { let inner = self.inner(); return DecompressArgs { entries: unsafe { slice::from_raw_parts(inner.rotation_entries, inner.max_tracks) }, @@ -625,7 +630,7 @@ impl SamplingContext { } #[inline] - fn scale_decompress_args<'t>(&'t self) -> DecompressArgs<'t, InterpSoaFloat3> { + fn scale_decompress_args(&self) -> DecompressArgs<'_, InterpSoaFloat3> { let inner = self.inner(); return DecompressArgs { entries: unsafe { slice::from_raw_parts(inner.scale_entries, inner.max_tracks) }, @@ -641,35 +646,20 @@ pub struct ArchivedSamplingContext { pub animation_id: u64, pub ratio: f32, - /// The unique identifier of the animation that the context is sampling. - #[inline] - pub fn animation_id(&self) -> u64 { - self.animation_id - } + pub translations: rkyv::vec::ArchivedVec, + pub translation_entries: rkyv::vec::ArchivedVec, + pub translation_outdated: rkyv::vec::ArchivedVec, + pub translation_next: u32, - /// The current time ratio in the animation. - #[inline] - pub fn ratio(&self) -> f32 { - self.ratio - } + pub rotations: rkyv::vec::ArchivedVec, + pub rotation_entries: rkyv::vec::ArchivedVec, + pub rotation_outdated: rkyv::vec::ArchivedVec, + pub rotation_next: u32, - /// Current cursors in the animation. 0 means that the context is invalid. - #[inline] - pub fn translation_cursor(&self) -> usize { - self.translation_cursor - } - - /// Current cursors in the animation. 0 means that the context is invalid. - #[inline] - pub fn rotation_cursor(&self) -> usize { - self.rotation_cursor - } - - /// Current cursors in the animation. 0 means that the context is invalid. - #[inline] - pub fn scale_cursor(&self) -> usize { - self.scale_cursor - } + pub scales: rkyv::vec::ArchivedVec, + pub scale_entries: rkyv::vec::ArchivedVec, + pub scale_outdated: rkyv::vec::ArchivedVec, + pub scale_next: u32, } #[cfg(feature = "rkyv")] @@ -743,62 +733,18 @@ const _: () = { impl Serialize for SamplingContext { fn serialize(&self, serializer: &mut S) -> Result { - let mut resolver = SamplingContextResolver { - translations_pos: serializer.align_for::()?, - ..Default::default() - }; - - serializer.write(unsafe { - slice::from_raw_parts( - self.translations().as_ptr() as *const u8, - std::mem::size_of_val(self.translations()), - ) - })?; - resolver.rotations_pos = serializer.align_for::()?; - serializer.write(unsafe { - slice::from_raw_parts( - self.rotations().as_ptr() as *const u8, - std::mem::size_of_val(self.rotations()), - ) - })?; - resolver.scales_pos = serializer.align_for::()?; - serializer.write(unsafe { - slice::from_raw_parts( - self.scales().as_ptr() as *const u8, - std::mem::size_of_val(self.scales()), - ) - })?; - - resolver.translation_keys_pos = serializer.align_for::()?; - serializer.write(unsafe { - slice::from_raw_parts( - self.translation_keys().as_ptr() as *const u8, - std::mem::size_of_val(self.translation_keys()), - ) - })?; - resolver.rotation_keys_pos = serializer.align_for::()?; - serializer.write(unsafe { - slice::from_raw_parts( - self.rotation_keys().as_ptr() as *const u8, - std::mem::size_of_val(self.rotation_keys()), - ) - })?; - resolver.scale_keys_pos = serializer.align_for::()?; - serializer.write(unsafe { - slice::from_raw_parts( - self.scale_keys().as_ptr() as *const u8, - std::mem::size_of_val(self.scale_keys()), - ) - })?; - - resolver.outdated_translations_pos = serializer.align_for::()?; - serializer.write(self.outdated_translations())?; - resolver.outdated_rotations_pos = serializer.align_for::()?; - serializer.write(self.outdated_rotations())?; - resolver.outdated_scales_pos = serializer.align_for::()?; - serializer.write(self.outdated_scales())?; - - Ok(resolver) + serializer.align_for::()?; + Ok(SamplingContextResolver { + translations: ArchivedVec::serialize_from_slice(self.translations(), serializer)?, + rotations: ArchivedVec::serialize_from_slice(self.rotations(), serializer)?, + scales: ArchivedVec::serialize_from_slice(self.scales(), serializer)?, + translation_entries: ArchivedVec::serialize_from_slice(self.translation_entries(), serializer)?, + rotation_entries: ArchivedVec::serialize_from_slice(self.rotation_entries(), serializer)?, + scale_entries: ArchivedVec::serialize_from_slice(self.scale_entries(), serializer)?, + translation_outdateds: ArchivedVec::serialize_from_slice(self.translation_outdated(), serializer)?, + rotation_outdateds: ArchivedVec::serialize_from_slice(self.rotation_outdated(), serializer)?, + scale_outdateds: ArchivedVec::serialize_from_slice(self.scale_outdated(), serializer)?, + }) } } @@ -807,30 +753,28 @@ const _: () = { fn deserialize(&self, _: &mut D) -> Result { let archived = from_archived!(self); let mut context = SamplingContext::new(archived.max_tracks as usize); - context.animation_id = archived.animation_id; - context.ratio = archived.ratio; - unsafe { - context.translations_mut().copy_from_slice(archived.translations()); - context.rotations_mut().copy_from_slice(archived.rotations()); - context.scales_mut().copy_from_slice(archived.scales()); - context - .translation_keys_mut() - .copy_from_slice(archived.translation_keys()); - context.rotation_keys_mut().copy_from_slice(archived.rotation_keys()); - context.scale_keys_mut().copy_from_slice(archived.scale_keys()); - context.translation_cursor = archived.translation_cursor as usize; - context.rotation_cursor = archived.rotation_cursor as usize; - context.scale_cursor = archived.scale_cursor as usize; - context - .outdated_translations_mut() - .copy_from_slice(archived.outdated_translations()); - context - .outdated_rotations_mut() - .copy_from_slice(archived.outdated_rotations()); - context - .outdated_scales_mut() - .copy_from_slice(archived.outdated_scales()); - } + context.set_animation_id(archived.animation_id); + context.set_ratio(archived.ratio); + context.translations_mut().copy_from_slice(&archived.translations); + context.rotations_mut().copy_from_slice(&archived.rotations); + context.scales_mut().copy_from_slice(&archived.scales); + context + .translation_entries_mut() + .copy_from_slice(&archived.translation_entries); + context + .rotation_entries_mut() + .copy_from_slice(&archived.rotation_entries); + context.scale_entries_mut().copy_from_slice(&archived.scale_entries); + context + .translation_outdated_mut() + .copy_from_slice(&archived.translation_outdated); + context + .rotation_outdated_mut() + .copy_from_slice(&archived.rotation_outdated); + context.scale_outdated_mut().copy_from_slice(&archived.scale_outdated); + context.set_translation_next(archived.translation_next as usize); + context.set_rotation_next(archived.rotation_next as usize); + context.set_scale_next(archived.scale_next as usize); Ok(context) } } @@ -866,15 +810,15 @@ const _: () = { map.serialize_entry("translations", self.translations())?; map.serialize_entry("rotations", self.rotations())?; map.serialize_entry("scales", self.scales())?; - map.serialize_entry("translations_keys", self.translation_keys())?; - map.serialize_entry("rotations_keys", self.rotation_keys())?; - map.serialize_entry("scales_keys", self.scale_keys())?; - map.serialize_entry("translation_cursor", &self.translation_cursor())?; - map.serialize_entry("rotation_cursor", &self.rotation_cursor())?; - map.serialize_entry("scale_cursor", &self.scale_cursor())?; - map.serialize_entry("outdated_translations", self.outdated_translations())?; - map.serialize_entry("outdated_rotations", self.outdated_rotations())?; - map.serialize_entry("outdated_scales", self.outdated_scales())?; + map.serialize_entry("translation_entries", self.translation_entries())?; + map.serialize_entry("translation_outdated", self.translation_outdated())?; + map.serialize_entry("translation_next", &self.translation_next())?; + map.serialize_entry("rotation_entries", self.rotation_entries())?; + map.serialize_entry("rotation_outdated", self.rotation_outdated())?; + map.serialize_entry("rotation_next", &self.rotation_next())?; + map.serialize_entry("scale_entries", self.scale_entries())?; + map.serialize_entry("scale_outdated", self.scale_outdated())?; + map.serialize_entry("scale_next", &self.scale_next())?; map.end() } } @@ -1186,6 +1130,7 @@ where let args = ctx.as_mut().scale_decompress_args(); Self::decompress_float3(args, anim.timepoints(), &anim.scales_ctrl(), anim.scales()); + Self::interpolates(anim, ctx.as_mut(), self.ratio, &mut output)?; Ok(()) } @@ -1200,38 +1145,43 @@ where } let prev_ratio = ctx.ratio(); ctx.set_ratio(ratio); - return prev_ratio; - } - - fn update_translation_cursor(animation: &Animation, ctx: &mut SamplingContext, ratio: f32) { - if ctx.translation_cursor == 0 { - for i in 0..animation.num_soa_tracks() { - let in_idx0 = i * 4; - let in_idx1 = in_idx0 + animation.num_aligned_tracks(); - let out_idx = i * 4 * 2; - ctx.translation_keys_mut()[out_idx] = in_idx0 as i32; - ctx.translation_keys_mut()[out_idx + 1] = in_idx1 as i32; - ctx.translation_keys_mut()[out_idx + 2] = (in_idx0 + 1) as i32; - ctx.translation_keys_mut()[out_idx + 3] = (in_idx1 + 1) as i32; - ctx.translation_keys_mut()[out_idx + 4] = (in_idx0 + 2) as i32; - ctx.translation_keys_mut()[out_idx + 5] = (in_idx1 + 2) as i32; - ctx.translation_keys_mut()[out_idx + 6] = (in_idx0 + 3) as i32; - ctx.translation_keys_mut()[out_idx + 7] = (in_idx1 + 3) as i32; - } + prev_ratio + } - ctx.outdated_translations_mut().iter_mut().for_each(|x| *x = 0xFF); - let last_offset = ((animation.num_soa_tracks() + 7) / 8 * 8) - animation.num_soa_tracks(); - if let Some(x) = ctx.outdated_translations_mut().last_mut() { - *x = 0xFF >> last_offset; + 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) { + let mut iframe = -1; + if !ctrl.iframe_desc.is_empty() { + iframe = (0.5 + ratio / ctrl.iframe_interval) as i32; + } else if next == 0 || delta < 0.0 { + iframe = 0; } - ctx.translation_cursor = animation.num_aligned_tracks() * 2; + if iframe >= 0 { + next = Self::initialize_cache(ctrl, iframe as usize, args.entries); + assert!(next >= args.num_tracks * 2 && next <= num_keys); + Self::outdate_cache(args.outdated, args.num_soa_tracks); + } } // 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)); @@ -1240,11 +1190,40 @@ where next += 1; } - ctx.outdated_translations_mut()[track / 32] |= 1 << ((track & 0x1F) / 4); - let base = (animation.translations()[ctx.translation_cursor].track as usize) * 2; - ctx.translation_keys_mut()[base] = ctx.translation_keys()[base + 1]; - ctx.translation_keys_mut()[base + 1] = ctx.translation_cursor as i32; - ctx.translation_cursor += 1; + // Rewinds + while Self::key_ratio( + ctrl, + animation.timepoints(), + next - 1 - ctrl.previouses[next - 1] as usize, + ) > ratio + { + assert!(next > 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]; + assert!((args.entries[track] as usize) >= (previous as usize) + args.num_tracks); + args.entries[track] -= previous as u32; + next -= 1; + } + + assert!(next >= args.num_tracks * 2 && next <= num_keys); + *args.next = next; + } + + #[inline] + 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); + (ctrl.iframe_desc[iframe + 1] + 1) as usize + } else { + let num_tracks = entries.len() as u32; + for i in 0..num_tracks { + entries[i as usize] = i + num_tracks; + } + (num_tracks * 2) as usize } } @@ -1261,22 +1240,24 @@ where #[inline] fn track_forward(cache: &[u32], previouses: &[u16], key: usize, last_track: usize, num_tracks: usize) -> usize { - assert!(key < previouses.len()); - assert!(last_track < num_tracks); - - let target = key - previouses[key] as usize; - for entry in last_track..num_tracks { - if (cache[entry] as usize) == target { - return entry; - } - } - for entry in 0..num_tracks { - if (cache[entry] as usize) == target { - return entry; - } - assert!(entry < last_track); + let target = key.saturating_sub(previouses[key] as usize); + + if let Some((entry, _)) = cache + .iter() + .enumerate() + .skip(last_track) + .take(num_tracks - last_track) + .find(|&(_, &value)| value as usize == target) + { + return entry; } - return 0; + + cache + .iter() + .enumerate() + .take(last_track) + .find(|&(_, &value)| value as usize == target) + .map_or(0, |(entry, _)| entry) } #[inline] @@ -1294,22 +1275,22 @@ where } assert!(entry > last_track); } - return 0; + 0 } #[inline(always)] fn key_ratio(ctrl: &KeyframesCtrl<'_>, timepoints: &[f32], at: usize) -> f32 { - return timepoints[ctrl.ratios[at] as usize]; + timepoints[ctrl.ratios[at] as usize] } #[inline(always)] fn key_ratio_simd(ctrl: &KeyframesCtrl<'_>, timepoints: &[f32], ats: &[u32]) -> f32x4 { - return f32x4::from_array([ + f32x4::from_array([ 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( @@ -1325,12 +1306,13 @@ where continue; } - let k00 = animation.translations()[ctx.translation_keys()[base] as usize]; - let k10 = animation.translations()[ctx.translation_keys()[base + 2] as usize]; - let k20 = animation.translations()[ctx.translation_keys()[base + 4] as usize]; - let k30 = animation.translations()[ctx.translation_keys()[base + 6] as usize]; - ctx.translations_mut()[i].ratio[0] = f32x4::from_array([k00.ratio, k10.ratio, k20.ratio, k30.ratio]); - Float3Key::simd_decompress(&k00, &k10, &k20, &k30, &mut ctx.translations_mut()[i].value[0]); + 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), + ]; let k00 = compressed[lefts[0] as usize]; let k10 = compressed[lefts[1] as usize]; @@ -1343,7 +1325,7 @@ where let k11 = compressed[rights[1] as usize]; let k21 = compressed[rights[2] as usize]; let k31 = compressed[rights[3] as usize]; - args.values[i].ratio[1] = Self::key_ratio_simd(ctrl, timepoints, &rights); + args.values[i].ratio[1] = Self::key_ratio_simd(ctrl, timepoints, rights); Float3Key::simd_decompress(&k01, &k11, &k21, &k31, &mut args.values[i].value[1]); outdated >>= 1; @@ -1351,62 +1333,26 @@ where } } - fn update_rotation_cursor(animation: &Animation, ctx: &mut SamplingContext, ratio: f32) { - if ctx.rotation_cursor == 0 { - for i in 0..animation.num_soa_tracks() { - let in_idx0 = i * 4; - let in_idx1 = in_idx0 + animation.num_aligned_tracks(); - let out_idx = i * 4 * 2; - ctx.rotation_keys_mut()[out_idx] = in_idx0 as i32; - ctx.rotation_keys_mut()[out_idx + 1] = in_idx1 as i32; - ctx.rotation_keys_mut()[out_idx + 2] = (in_idx0 + 1) as i32; - ctx.rotation_keys_mut()[out_idx + 3] = (in_idx1 + 1) as i32; - ctx.rotation_keys_mut()[out_idx + 4] = (in_idx0 + 2) as i32; - ctx.rotation_keys_mut()[out_idx + 5] = (in_idx1 + 2) as i32; - ctx.rotation_keys_mut()[out_idx + 6] = (in_idx0 + 3) as i32; - ctx.rotation_keys_mut()[out_idx + 7] = (in_idx1 + 3) as i32; - } - - ctx.outdated_rotations_mut().iter_mut().for_each(|x| *x = 0xFF); - let last_offset = ((animation.num_soa_tracks() + 7) / 8 * 8) - animation.num_soa_tracks(); - if let Some(x) = ctx.outdated_rotations_mut().last_mut() { - *x = 0xFF >> last_offset; - } - - ctx.rotation_cursor = animation.num_aligned_tracks() * 2; - } - - while ctx.rotation_cursor < animation.rotations().len() { - let track = animation.rotations()[ctx.rotation_cursor].track() as usize; - let key_idx = ctx.rotation_keys()[track * 2 + 1] as usize; - let ani_ratio = animation.rotations()[key_idx].ratio; - if ani_ratio > ratio { - break; - } - - ctx.outdated_rotations_mut()[track / 32] |= 1 << ((track & 0x1F) / 4); - let base = (animation.rotations()[ctx.rotation_cursor].track() as usize) * 2; - ctx.rotation_keys_mut()[base] = ctx.rotation_keys()[base + 1]; - ctx.rotation_keys_mut()[base + 1] = ctx.rotation_cursor as i32; - ctx.rotation_cursor += 1; - } - } - - fn update_rotation_key_frames(animation: &Animation, ctx: &mut SamplingContext) { - let num_outdated_flags = (animation.num_soa_tracks() + 7) / 8; - for j in 0..num_outdated_flags { - let mut outdated = ctx.outdated_rotations()[j]; + fn decompress_quat( + args: DecompressArgs<'_, InterpSoaQuaternion>, + timepoints: &[f32], + ctrl: &KeyframesCtrl<'_>, + compressed: &[QuaternionKey], + ) { + for j in 0..args.outdated.len() { + let mut outdated = args.outdated[j]; for i in (8 * j)..(8 * j + 8) { if outdated & 1 == 0 { continue; } - let k00 = animation.rotations()[ctx.rotation_keys()[base] as usize]; - let k10 = animation.rotations()[ctx.rotation_keys()[base + 2] as usize]; - let k20 = animation.rotations()[ctx.rotation_keys()[base + 4] as usize]; - let k30 = animation.rotations()[ctx.rotation_keys()[base + 6] as usize]; - ctx.rotations_mut()[i].ratio[0] = f32x4::from_array([k00.ratio, k10.ratio, k20.ratio, k30.ratio]); - QuaternionKey::simd_decompress(&k00, &k10, &k20, &k30, &mut ctx.rotations_mut()[i].value[0]); + 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), + ]; let k00 = compressed[lefts[0] as usize]; let k10 = compressed[lefts[1] as usize]; @@ -1415,75 +1361,12 @@ where args.values[i].ratio[0] = Self::key_ratio_simd(ctrl, timepoints, &lefts); QuaternionKey::simd_decompress(&k00, &k10, &k20, &k30, &mut args.values[i].value[0]); - outdated >>= 1; - } - } - } - - fn update_scale_cursor(animation: &Animation, ctx: &mut SamplingContext, ratio: f32) { - if ctx.scale_cursor == 0 { - for i in 0..animation.num_soa_tracks() { - let in_idx0 = i * 4; - let in_idx1 = in_idx0 + animation.num_aligned_tracks(); - let out_idx = i * 4 * 2; - ctx.scale_keys_mut()[out_idx] = (in_idx0) as i32; - ctx.scale_keys_mut()[out_idx + 1] = (in_idx1) as i32; - ctx.scale_keys_mut()[out_idx + 2] = (in_idx0 + 1) as i32; - ctx.scale_keys_mut()[out_idx + 3] = (in_idx1 + 1) as i32; - ctx.scale_keys_mut()[out_idx + 4] = (in_idx0 + 2) as i32; - ctx.scale_keys_mut()[out_idx + 5] = (in_idx1 + 2) as i32; - ctx.scale_keys_mut()[out_idx + 6] = (in_idx0 + 3) as i32; - ctx.scale_keys_mut()[out_idx + 7] = (in_idx1 + 3) as i32; - } - - ctx.outdated_scales_mut().iter_mut().for_each(|x| *x = 0xFF); - let last_offset = ((animation.num_soa_tracks() + 7) / 8 * 8) - animation.num_soa_tracks(); - if let Some(x) = ctx.outdated_scales_mut().last_mut() { - *x = 0xFF >> last_offset; - } - - ctx.scale_cursor = animation.num_aligned_tracks() * 2; - } - - while ctx.scale_cursor < animation.scales().len() { - let track = animation.scales()[ctx.scale_cursor].track as usize; - let key_idx = ctx.scale_keys()[track * 2 + 1] as usize; - let ani_ratio = animation.scales()[key_idx].ratio; - if ani_ratio > ratio { - break; - } - - ctx.outdated_scales_mut()[track / 32] |= 1 << ((track & 0x1F) / 4); - let base = (animation.scales()[ctx.scale_cursor].track as usize) * 2; - ctx.scale_keys_mut()[base] = ctx.scale_keys()[base + 1]; - ctx.scale_keys_mut()[base + 1] = ctx.scale_cursor as i32; - ctx.scale_cursor += 1; - } - } - - fn update_scale_key_frames(animation: &Animation, ctx: &mut SamplingContext) { - let num_outdated_flags = (animation.num_soa_tracks() + 7) / 8; - for j in 0..num_outdated_flags { - let mut outdated = ctx.outdated_scales()[j]; - for i in (8 * j)..(8 * j + 8) { - if outdated & 1 == 0 { - continue; - } - let base = i * 4 * 2; - - let k00 = animation.scales()[ctx.scale_keys()[base] as usize]; - let k10 = animation.scales()[ctx.scale_keys()[base + 2] as usize]; - let k20 = animation.scales()[ctx.scale_keys()[base + 4] as usize]; - let k30 = animation.scales()[ctx.scale_keys()[base + 6] as usize]; - ctx.scales_mut()[i].ratio[0] = f32x4::from_array([k00.ratio, k10.ratio, k20.ratio, k30.ratio]); - Float3Key::simd_decompress(&k00, &k10, &k20, &k30, &mut ctx.scales_mut()[i].value[0]); - - let k01 = animation.scales()[ctx.scale_keys()[base + 1] as usize]; - let k11 = animation.scales()[ctx.scale_keys()[base + 3] as usize]; - let k21 = animation.scales()[ctx.scale_keys()[base + 5] as usize]; - let k31 = animation.scales()[ctx.scale_keys()[base + 7] as usize]; - ctx.scales_mut()[i].ratio[1] = f32x4::from_array([k01.ratio, k11.ratio, k21.ratio, k31.ratio]); - Float3Key::simd_decompress(&k01, &k11, &k21, &k31, &mut ctx.scales_mut()[i].value[1]); + let k01 = compressed[rights[0] as usize]; + let k11 = compressed[rights[1] as usize]; + let k21 = compressed[rights[2] as usize]; + let k31 = compressed[rights[3] as usize]; + args.values[i].ratio[1] = Self::key_ratio_simd(ctrl, timepoints, rights); + QuaternionKey::simd_decompress(&k01, &k11, &k21, &k31, &mut args.values[i].value[1]); outdated >>= 1; } @@ -1522,7 +1405,7 @@ fn decode_gv4<'t>(buffer: &'t [u8], output: &mut [u32]) -> &'t [u8] { #[inline] fn load(input: &[u8]) -> u32 { - return input[0] as u32 | (input[1] as u32) << 8 | (input[2] as u32) << 16 | (input[3] as u32) << 24; + input[0] as u32 | (input[1] as u32) << 8 | (input[2] as u32) << 16 | (input[3] as u32) << 24 } let mut in_buf = &buffer[1..]; @@ -1542,7 +1425,7 @@ fn decode_gv4<'t>(buffer: &'t [u8], output: &mut [u32]) -> &'t [u8] { output[3] = load(in_buf) & MASK[k3]; in_buf = &in_buf[k3 + 1..]; - return in_buf; + in_buf } fn decode_gv4_stream<'t>(buffer: &'t [u8], stream: &mut [u32]) -> &'t [u8] { @@ -1554,9 +1437,9 @@ fn decode_gv4_stream<'t>(buffer: &'t [u8], stream: &mut [u32]) -> &'t [u8] { let mut in_buf = buffer; for chunk in stream.chunks_mut(4) { - in_buf = decode_gv4(in_buf, chunk.try_into().unwrap()); + in_buf = decode_gv4(in_buf, chunk); } - return in_buf; + in_buf } #[cfg(test)] @@ -1619,45 +1502,6 @@ mod sampling_tests { assert!(job.run().is_ok()); } - fn new_translations() -> Vec { - vec![ - Float3Key::new(0.0, 0, [f16(0.0); 3]), - Float3Key::new(0.0, 1, [f16(0.0); 3]), - Float3Key::new(0.0, 2, [f16(0.0); 3]), - Float3Key::new(0.0, 3, [f16(0.0); 3]), - Float3Key::new(1.0, 0, [f16(0.0); 3]), - Float3Key::new(1.0, 1, [f16(0.0); 3]), - Float3Key::new(1.0, 2, [f16(0.0); 3]), - Float3Key::new(1.0, 3, [f16(0.0); 3]), - ] - } - - fn new_rotations() -> Vec { - vec![ - QuaternionKey::new(0.0, 3 << 1, [0, 0, 0]), - QuaternionKey::new(0.0, (1 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(0.0, (2 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(0.0, (3 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(1.0, 3 << 1, [0, 0, 0]), - QuaternionKey::new(1.0, (1 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(1.0, (2 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(1.0, (3 << 3) + (3 << 1), [0, 0, 0]), - ] - } - - fn new_scales() -> Vec { - vec![ - Float3Key::new(0.0, 0, [f16(1.0); 3]), - Float3Key::new(0.0, 1, [f16(1.0); 3]), - Float3Key::new(0.0, 2, [f16(1.0); 3]), - Float3Key::new(0.0, 3, [f16(1.0); 3]), - Float3Key::new(1.0, 0, [f16(1.0); 3]), - Float3Key::new(1.0, 1, [f16(1.0); 3]), - Float3Key::new(1.0, 2, [f16(1.0); 3]), - Float3Key::new(1.0, 3, [f16(1.0); 3]), - ] - } - const V0: Vec3 = Vec3::new(0.0, 0.0, 0.0); const V1: Vec3 = Vec3::new(1.0, 1.0, 1.0); const QU: Quat = Quat::from_xyzw(0.0, 0.0, 0.0, 1.0); @@ -1668,27 +1512,27 @@ mod sampling_tests { }; fn empty_translations() -> Vec { - return vec![Float3Key::new([f16(0.0); 3]); 8]; + vec![Float3Key::new([f16(0.0); 3]); 8] } fn empty_rotations() -> Vec { - return vec![QuaternionKey::new([65531, 65533, 32766]); 8]; + vec![QuaternionKey::new([65531, 65533, 32766]); 8] } fn empty_scales() -> Vec { - return vec![Float3Key::new([f16(1.0); 3]); 8]; + vec![Float3Key::new([f16(1.0); 3]); 8] } fn empty_ratios(n: u16) -> Vec { - return vec![0, 0, 0, 0, n, n, n, n]; + vec![0, 0, 0, 0, n, n, n, n] } fn empty_previouses() -> Vec { - return vec![0, 0, 0, 0, 4, 4, 4, 4]; + vec![0, 0, 0, 0, 4, 4, 4, 4] } fn empty_animation_raw(duration: f32) -> AnimationRaw { - return AnimationRaw { + AnimationRaw { duration, num_tracks: S as u32, timepoints: vec![], @@ -1702,7 +1546,7 @@ mod sampling_tests { s_ratios: empty_ratios(S as u16), s_previouses: empty_previouses(), ..Default::default() - }; + } } #[derive(Debug, Clone)] @@ -1773,7 +1617,25 @@ mod sampling_tests { } } - #[allow(clippy::excessive_precision)] + 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![ @@ -1891,62 +1753,70 @@ mod sampling_tests { #[wasm_bindgen_test] #[rustfmt::skip] fn test_sampling_4_track_2_key() { - execute_test::<4>( - 1.0, - vec![ - Float3Key::new(0.0, 0, [f16(1.0), f16(2.0), f16(4.0)]), - Float3Key::new(0.0, 1, [f16(0.0); 3]), - Float3Key::new(0.0, 2, [f16(0.0); 3]), - Float3Key::new(0.0, 3, [f16(-1.0), f16(-2.0), f16(-4.0)]), - Float3Key::new(0.5, 0, [f16(1.0), f16(2.0), f16(4.0)]), - Float3Key::new(1.0, 1, [f16(0.0); 3]), - Float3Key::new(1.0, 2, [f16(0.0); 3]), - Float3Key::new(1.0, 3, [f16(-2.0), f16(-4.0), f16(-8.0)]), - Float3Key::new(0.8, 0, [f16(2.0), f16(4.0), f16(8.0)]), - Float3Key::new(1.0, 0, [f16(2.0), f16(4.0), f16(8.0)]), - ], - vec![ - QuaternionKey::new(0.0, 3 << 1, [0, 0, 0]), - QuaternionKey::new(0.0, (1 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(0.0, (2 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(0.0, (3 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(1.0, 3 << 1, [0, 0, 0]), - QuaternionKey::new(1.0, (1 << 3) + (1 << 1), [0, 0, 0]), - QuaternionKey::new(1.0, (2 << 3) + (3 << 1), [0, 0, 0]), - QuaternionKey::new(1.0, (3 << 3) + (3 << 1), [0, 0, 0]), - ], - vec![ - Float3Key::new(0.0, 0, [f16(1.0); 3]), - Float3Key::new(0.0, 1, [f16(1.0); 3]), - Float3Key::new(0.0, 2, [f16(0.0); 3]), - Float3Key::new(0.0, 3, [f16(1.0); 3]), - Float3Key::new(1.0, 0, [f16(1.0); 3]), - Float3Key::new(1.0, 1, [f16(1.0); 3]), - Float3Key::new(0.5, 2, [f16(0.0); 3]), - Float3Key::new(1.0, 3, [f16(1.0); 3]), - Float3Key::new(0.8, 2, [f16(-1.0); 3]), - Float3Key::new(1.0, 2, [f16(-1.0); 3]), - ], - vec![ - Frame {ratio: 0.0, transform: [ - (Vec3::new(1.0, 2.0, 4.0), QU, V1), - (V0, QU, V1), - (V0, QU, V0), - (Vec3::new(-1.0, -2.0, -4.0), QU, V1), - ]}, - Frame {ratio: 0.5, transform: [ - (Vec3::new(1.0, 2.0, 4.0), QU, V1), - (V0, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677), V1), - (V0, QU, V0), - (Vec3::new(-1.5, -3.0, -6.0), QU, V1), - ]}, - Frame {ratio: 1.0, transform: [ - (Vec3::new(2.0, 4.0, 8.0), QU, V1), - (V0, Quat::from_xyzw(0.0, 1.0, 0.0, 0.0), V1), - (V0, QU, -V1), - (Vec3::new(-2.0, -4.0, -8.0), QU, V1), - ]}, - ], + 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]), + Float3Key::new([f16(-1.0), f16(-2.0), f16(-4.0)]), + Float3Key::new([f16(1.0), f16(2.0), f16(4.0)]), + Float3Key::new([f16(0.0); 3]), + Float3Key::new([f16(0.0); 3]), + Float3Key::new([f16(-2.0), f16(-4.0), f16(-8.0)]), + Float3Key::new([f16(2.0), f16(4.0), f16(8.0)]), + Float3Key::new([f16(2.0), f16(4.0), f16(8.0)]), + ]; + + ar.rotations = empty_rotations(); + ar.rotations[5] = QuaternionKey::new([65529, 65533, 32766]); + + ar.scales = vec![ + Float3Key::new([f16(1.0); 3]), + Float3Key::new([f16(1.0); 3]), + Float3Key::new([f16(0.0); 3]), + Float3Key::new([f16(1.0); 3]), + Float3Key::new([f16(1.0); 3]), + Float3Key::new([f16(1.0); 3]), + Float3Key::new([f16(0.0); 3]), + Float3Key::new([f16(1.0); 3]), + Float3Key::new([f16(-1.0); 3]), + Float3Key::new([f16(-1.0); 3]), + ]; + + let mut frames_raw = vec![ + Frame {ratio: 0.0, transform: [ + (Vec3::new(1.0, 2.0, 4.0), QU, V1), + (V0, QU, V1), + (V0, QU, V0), + (Vec3::new(-1.0, -2.0, -4.0), QU, V1), + ]}, + Frame {ratio: 0.5, transform: [ + (Vec3::new(1.0, 2.0, 4.0), QU, V1), + (V0, Quat::from_xyzw(0.0, 0.70710677, 0.0, 0.70710677), V1), + (V0, QU, V0), + (Vec3::new(-1.5, -3.0, -6.0), QU, V1), + ]}, + Frame {ratio: 1.0, transform: [ + (Vec3::new(2.0, 4.0, 8.0), QU, V1), + (V0, Quat::from_xyzw(0.0, 1.0, 0.0, 0.0), V1), + (V0, QU, -V1), + (Vec3::new(-2.0, -4.0, -8.0), QU, V1), + ]}, + ]; + let mut frames = frames_raw.clone(); + frames_raw.reverse(); + frames.append(&mut frames_raw); + + execute_test::<4>(ar, + frames, ); } diff --git a/src/skeleton.rs b/src/skeleton.rs index e585a74..14e8739 100644 --- a/src/skeleton.rs +++ b/src/skeleton.rs @@ -14,59 +14,6 @@ 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(), - DeterministicState::new(), - DeterministicState::new(), - ); - for entry in field.iter() { - result.insert( - entry.key.deserialize(deserializer)?, - entry.value.deserialize(deserializer)?, - ); - } - Ok(result) - } - } -}; - /// /// This runtime skeleton data structure provides a const-only access to joint /// hierarchy, joint names and rest-pose. @@ -131,19 +78,6 @@ impl Skeleton { 2 } - #[cfg(test)] - pub(crate) fn from_raw( - joint_rest_poses: Vec, - joint_parents: Vec, - joint_names: JointHashMap, - ) -> Skeleton { - 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() { @@ -193,11 +127,9 @@ impl Skeleton { skeleton.joint_names.insert(archive.read::()?, idx as i16); } - 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())?; + Ok(skeleton) } /// Reads a `Skeleton` from a file. @@ -224,15 +156,15 @@ impl Skeleton { 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; + skeleton } pub(crate) fn to_raw(&self) -> SkeletonRaw { - return SkeletonRaw { + 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 { @@ -264,7 +196,7 @@ impl Skeleton { assert_eq!(ptr, (skeleton.joint_rest_poses as *mut u8).add(skeleton.size)); } - return skeleton; + skeleton } } @@ -272,7 +204,7 @@ impl Skeleton { /// Gets the number of joints of `Skeleton`. #[inline] pub fn num_joints(&self) -> usize { - self.joint_parents.len() + self.num_joints as usize } /// Gets the number of joints of `Skeleton` (aligned to 4 * SoA). @@ -285,24 +217,18 @@ impl Skeleton { /// This value is useful to allocate SoA runtime data structures. #[inline] pub fn num_soa_joints(&self) -> usize { - (self.joint_parents.len() + 3) / 4 + 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] { - &self.joint_rest_poses - } - - #[inline] - pub fn joint_parents(&self) -> &[i16] { - &self.joint_parents + return unsafe { slice::from_raw_parts(self.joint_rest_poses, self.num_soa_joints()) }; } - /// Gets joint's parent by index. #[inline] - pub fn joint_parent(&self, idx: impl OzzIndex) -> i16 { - 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. @@ -420,14 +346,14 @@ const _: () = { impl Serialize for Skeleton { fn serialize(&self, serializer: &mut S) -> Result { serializer.align_for::()?; - return Ok(SkeletonResolver { + 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)?, - }); + }) } } @@ -446,7 +372,7 @@ const _: () = { .copy_from_slice(archived.joint_rest_poses.as_slice()); skeleton.joint_names = JointHashMap::with_capacity_and_hashers( - archived.joint_names.len() as usize, + archived.joint_names.len(), DeterministicState::new(), DeterministicState::new(), ); @@ -457,7 +383,7 @@ const _: () = { skeleton .joint_parents_mut() .copy_from_slice(archived.joint_parents.as_slice()); - return Ok(skeleton); + Ok(skeleton) } } }; @@ -469,14 +395,14 @@ const _: () = { impl Serialize for Skeleton { fn serialize(&self, serializer: S) -> Result { let raw = self.to_raw(); - return raw.serialize(serializer); + 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)); + Ok(Skeleton::from_raw(&raw)) } } }; diff --git a/src/skinning_job.rs b/src/skinning_job.rs index beb2888..ff4475c 100644 --- a/src/skinning_job.rs +++ b/src/skinning_job.rs @@ -134,7 +134,7 @@ where /// Gets joint matrices of `SkinningJob`. #[inline] pub fn joint_matrices(&self) -> Option<&JM> { - self.joint_matrices.as_ref() + return self.joint_matrices.as_ref(); } /// Sets joint matrices of `SkinningJob`. @@ -464,32 +464,28 @@ macro_rules! skinning_impl { ); for i in 0..$self.vertex_count { + let weight_offset = i * ($n - 1); let index_offset = i * $n; - let mut transform = Mat4::IDENTITY; - it!($it, let mut transform_it = Mat4::IDENTITY); - if $n == 1 { - let joint_index = indices[index_offset] as usize; - transform = *matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?; - it!($it, transform_it = *it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?); - } else { - let weight_offset = i * ($n - 1); - let mut weight_sum = Vec4::ZERO; - - for j in 0..($n - 1) { - let weight = Vec4::splat(weights[weight_offset + j]); - weight_sum += weight; - let joint_index = indices[index_offset + j] as usize; - transform += mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); - it!($it, transform_it += mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); - } + let weight = Vec4::splat(weights[weight_offset]); + let mut weight_sum = weight; + let joint_index = indices[index_offset] as usize; + let mut transform = mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); + it!($it, let mut transform_it = mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); - let weight = Vec4::ONE - weight_sum; - let joint_index = indices[index_offset + $n - 1] as usize; + for j in 1..($n - 1) { + let weight = Vec4::splat(weights[weight_offset + j]); + weight_sum += weight; + let joint_index = indices[index_offset + j] as usize; transform += mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); it!($it, transform_it += mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); } + let weight = Vec4::ONE - weight_sum; + let joint_index = indices[index_offset + $n - 1] as usize; + transform += mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); + it!($it, transform_it += mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); + pnt!($pnt, out_positions[i] = transform.transform_point3(in_positions[i]); out_normals[i] = it!($it, transform_it, transform).transform_vector3(in_normals[i]); @@ -533,7 +529,7 @@ where /// Runs skinning job's task. /// The validate job before any operation is performed. pub fn run(&mut self) -> Result<(), OzzError> { - if self.influences_count == 0 { + if self.influences_count <= 0 { return Err(OzzError::InvalidJob); } diff --git a/tests/common.rs b/tests/common.rs index 9b2b704..f2b0946 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -18,7 +18,7 @@ pub fn compare_with_cpp(folder: &str, name: &str, data: &[Mat4], diff: f32) -> R let path = format!("./output/{0}/{1}_rust_{2}_{3}.bin", folder, name, OS, ARCH); let mut file = File::create(path)?; - let data_size = data.len() * mem::size_of::(); + let data_size = std::mem::size_of_val(data); file.write_all(unsafe { slice::from_raw_parts(data.as_ptr() as *mut _, data_size) })?; let path = format!("./expected/{0}/{1}_cpp.bin", folder, name); @@ -28,7 +28,7 @@ pub fn compare_with_cpp(folder: &str, name: &str, data: &[Mat4], diff: f32) -> R } let mut expected: Vec = vec![Mat4::default(); data.len()]; - file.read(unsafe { slice::from_raw_parts_mut(expected.as_mut_ptr() as *mut _, data_size) })?; + file.read_exact(unsafe { slice::from_raw_parts_mut(expected.as_mut_ptr() as *mut _, data_size) })?; for i in 0..expected.len() { if !Mat4::abs_diff_eq(&data[i], expected[i], diff) { println!("actual: {:?}", data[i]); @@ -36,7 +36,7 @@ pub fn compare_with_cpp(folder: &str, name: &str, data: &[Mat4], diff: f32) -> R return Err(format!("compare_with_cpp() idx:{}", i).into()); } } - return Ok(()); + Ok(()) } #[cfg(all(feature = "wasm", feature = "nodejs"))] @@ -59,7 +59,7 @@ pub fn compare_with_cpp(folder: &str, name: &str, data: &[Mat4], diff: f32) -> R return Err(format!("compare_with_cpp() idx:{}", i).into()); } } - return Ok(()); + Ok(()) } #[cfg(feature = "rkyv")] @@ -102,13 +102,13 @@ where expected_buf.extend_from_slice(&unaligned_buf); let archived = unsafe { rkyv::archived_root::(&expected_buf) }; - let mut deserializer = rkyv::Infallible::default(); + let mut deserializer = rkyv::Infallible; let expected = archived.deserialize(&mut deserializer)?; if data != &expected { return Err(format!("compare_with_rkyv({})", path).into()); } } - return Ok(()); + Ok(()) } #[cfg(feature = "rkyv")] @@ -133,12 +133,12 @@ where if data != &expected { return Err(format!("compare_with_rkyv({})", path).into()); } - return Ok(()); + Ok(()) } #[cfg(not(feature = "rkyv"))] pub fn compare_with_rkyv(_folder: &str, _name: &str, _data: &T) -> Result<(), Box> { - return Ok(()); + Ok(()) } #[cfg(feature = "rkyv")] @@ -165,12 +165,12 @@ where }; let mut file = File::create(path)?; file.write_all(&wbuf)?; - return Ok(()); + Ok(()) } #[cfg(any(not(feature = "rkyv"), feature = "wasm"))] pub fn save_rkyv(_folder: &str, _name: &str, _data: &T, _to_expected: bool) -> Result<(), Box> { - return Ok(()); + Ok(()) } #[cfg(feature = "rkyv")] @@ -193,9 +193,9 @@ where expected_buf.extend_from_slice(&unaligned_buf); let archived = unsafe { rkyv::archived_root::(&expected_buf) }; - let mut deserializer = rkyv::Infallible::default(); + let mut deserializer = rkyv::Infallible; let data = archived.deserialize(&mut deserializer)?; - return Ok(data); + Ok(data) } #[cfg(feature = "rkyv")] @@ -217,7 +217,7 @@ where let archived = unsafe { rkyv::archived_root::(&expected_buf) }; let mut deserializer = rkyv::Infallible::default(); let data = archived.deserialize(&mut deserializer)?; - return Ok(data); + Ok(data) } #[cfg(not(feature = "rkyv"))] diff --git a/tests/context.rs b/tests/context.rs index 9a164d4..658daf1 100644 --- a/tests/context.rs +++ b/tests/context.rs @@ -80,7 +80,7 @@ fn prepare_contexts( } let contexts: Vec = common::load_rkyv("context", name).unwrap(); - return (skeleton, animation, contexts); + (skeleton, animation, contexts) } #[derive(Debug)] diff --git a/tests/look_at.rs b/tests/look_at.rs index 91284a9..76b94bd 100644 --- a/tests/look_at.rs +++ b/tests/look_at.rs @@ -18,7 +18,7 @@ struct TestData { reacheds: [bool; 4], } -const JOINT_NAMES: &'static [&'static str] = &["Head", "Spine3", "Spine2", "Spine1"]; +const JOINT_NAMES: &[&str] = &["Head", "Spine3", "Spine2", "Spine1"]; const TARGET_EXTENT: f32 = 1.0; const TARGET_OFFSET: Vec3A = Vec3A::new(0.2, 1.5, -0.3); @@ -103,7 +103,7 @@ where let mut previous_joint = SKELETON_NO_PARENT; for (idx, joint) in joints_chain.iter().enumerate() { - ik_job.set_joint(models1.buf().unwrap()[*joint as usize].into()); + ik_job.set_joint(models1.buf().unwrap()[*joint as usize]); ik_job.set_up(Vec3A::X); if idx == joints_chain.len() - 1 { @@ -116,13 +116,13 @@ where ik_job.set_offset(EYES_OFFSET); ik_job.set_forward(Vec3A::Y); } else { - let transform: Mat4 = models1.buf().unwrap()[previous_joint as usize].into(); + let transform: Mat4 = models1.buf().unwrap()[previous_joint as usize]; let corrected_forward_ms = transform.transform_vector3a(ik_job.joint_correction().mul_vec3a(ik_job.forward())); let corrected_offset_ms = transform.transform_point3a(ik_job.joint_correction().mul_vec3a(ik_job.offset())); - let transform: Mat4 = models1.buf().unwrap()[*joint as usize].into(); + let transform: Mat4 = models1.buf().unwrap()[*joint as usize]; let inv_transform = transform.inverse(); ik_job.set_offset(inv_transform.transform_point3a(corrected_offset_ms)); ik_job.set_forward(inv_transform.transform_vector3a(corrected_forward_ms)); @@ -160,7 +160,7 @@ where } fn validate_joints_order(skeleton: &Skeleton, joints: &[i16]) -> bool { - if joints.len() == 0 { + if joints.is_empty() { return true; } @@ -175,5 +175,5 @@ fn validate_joints_order(skeleton: &Skeleton, joints: &[i16]) -> bool { parent = skeleton.joint_parent(joint as usize); } - return joints.len() == i; + joints.len() == i } diff --git a/tests/track.rs b/tests/track.rs index 85e5afa..070976e 100644 --- a/tests/track.rs +++ b/tests/track.rs @@ -60,7 +60,7 @@ fn test_track_triggering_deterministic() { job.set_to(to); job.set_threshold(0.5); - let results: Vec<_> = job.run().unwrap().map(|x| x).collect(); + let results: Vec<_> = job.run().unwrap().collect(); all_data.push(TestTriggeringData { from, to, results }); } diff --git a/tests/two_bone_ik.rs b/tests/two_bone_ik.rs index fa4df6b..aa840a2 100644 --- a/tests/two_bone_ik.rs +++ b/tests/two_bone_ik.rs @@ -87,9 +87,9 @@ where ik_job.set_soften(0.97); ik_job.set_twist_angle(0.0); ik_job.set_pole_vector(Vec3A::new(0.0, 1.0, 0.0)); - ik_job.set_start_joint(models1.borrow()[start_joint as usize].into()); - ik_job.set_mid_joint(models1.borrow()[mid_joint as usize].into()); - ik_job.set_end_joint(models1.borrow()[end_joint as usize].into()); + ik_job.set_start_joint(models1.borrow()[start_joint as usize]); + ik_job.set_mid_joint(models1.borrow()[mid_joint as usize]); + ik_job.set_end_joint(models1.borrow()[end_joint as usize]); ik_job.run().unwrap(); From e8d89922dce9e2df604224723ec5042b82b1aba8 Mon Sep 17 00:00:00 2001 From: Abe M Date: Thu, 29 Aug 2024 03:33:55 -0700 Subject: [PATCH 3/6] Update glam to 0.29 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 023db93..3e049b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ nodejs = ["wasm", "dep:js-sys", "dep:wasm-bindgen"] [dependencies] bimap = { version = "0.6" } bytecheck = { version = "0.6", optional = true, default-features = false } -glam = { version = "0.28", features = [ "core-simd", "libm" ] } +glam = { version = "0.29", features = [ "core-simd", "libm" ] } js-sys = { version = "0.3", optional = true } rkyv = { version = "0.7", optional = true, features = [ "validation" ] } serde = { version= "1.0", optional = true, features = [ "serde_derive" ] } From 6a74dce2c55c45502a4c6cd18de2c577aee9581a Mon Sep 17 00:00:00 2001 From: Abe M Date: Thu, 29 Aug 2024 03:46:06 -0700 Subject: [PATCH 4/6] Fix error --- src/skinning_job.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/skinning_job.rs b/src/skinning_job.rs index ff4475c..9ba1351 100644 --- a/src/skinning_job.rs +++ b/src/skinning_job.rs @@ -473,7 +473,7 @@ macro_rules! skinning_impl { let mut transform = mat4_col_mul(matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight); it!($it, let mut transform_it = mat4_col_mul(it_matrices.get(joint_index).ok_or(OzzError::InvalidIndex)?, weight)); - for j in 1..($n - 1) { + for j in 1..($n - 1).max(1) { let weight = Vec4::splat(weights[weight_offset + j]); weight_sum += weight; let joint_index = indices[index_offset + j] as usize; @@ -529,7 +529,7 @@ where /// Runs skinning job's task. /// The validate job before any operation is performed. pub fn run(&mut self) -> Result<(), OzzError> { - if self.influences_count <= 0 { + if self.influences_count == 0 { return Err(OzzError::InvalidJob); } From fb10a6db5b1da22d4dd54162e26636076e6576f8 Mon Sep 17 00:00:00 2001 From: Abe M Date: Thu, 29 Aug 2024 04:28:50 -0700 Subject: [PATCH 5/6] Go back to glam 0.27 --- Cargo.toml | 2 +- demo/src/playback.rs | 6 +++--- demo/src/two_bone_ik.rs | 6 +++--- src/ik_two_bone_job.rs | 17 +++++++++++------ 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e049b1..836f1da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ nodejs = ["wasm", "dep:js-sys", "dep:wasm-bindgen"] [dependencies] bimap = { version = "0.6" } bytecheck = { version = "0.6", optional = true, default-features = false } -glam = { version = "0.29", features = [ "core-simd", "libm" ] } +glam = { version = "0.27", features = [ "core-simd", "libm" ] } js-sys = { version = "0.3", optional = true } rkyv = { version = "0.7", optional = true, features = [ "validation" ] } serde = { version= "1.0", optional = true, features = [ "serde_derive" ] } diff --git a/demo/src/playback.rs b/demo/src/playback.rs index cbeedaa..dc0dc7a 100644 --- a/demo/src/playback.rs +++ b/demo/src/playback.rs @@ -113,14 +113,14 @@ impl OzzExample for OzzPlayback { let bone_rot = Quat::from_mat3(&Mat3::from_cols(bone_dir, bone_rot_y, bone_rot_z)); self.bone_trans.push(OzzTransform { - scale: scale, + scale, rotation: bone_rot, position: parent_pos, }); let parent_rot = Quat::from_mat4(parent); self.spine_trans.push(OzzTransform { - scale: scale, + scale, rotation: parent_rot, position: parent_pos, }); @@ -128,7 +128,7 @@ impl OzzExample for OzzPlayback { if self.skeleton.is_leaf(i as i16) { let current_rot = Quat::from_mat4(current); self.spine_trans.push(OzzTransform { - scale: scale, + scale, rotation: current_rot, position: current_pos, }); diff --git a/demo/src/two_bone_ik.rs b/demo/src/two_bone_ik.rs index 6908164..9267d89 100644 --- a/demo/src/two_bone_ik.rs +++ b/demo/src/two_bone_ik.rs @@ -169,14 +169,14 @@ impl OzzExample for OzzTwoBoneIK { let bone_rot = Quat::from_mat3(&Mat3::from_cols(bone_dir, bone_rot_y, bone_rot_z)); self.bone_trans.push(OzzTransform { - scale: scale, + scale, rotation: bone_rot, position: parent_pos, }); let parent_rot = Quat::from_mat4(parent); self.spine_trans.push(OzzTransform { - scale: scale, + scale, rotation: parent_rot, position: parent_pos, }); @@ -184,7 +184,7 @@ impl OzzExample for OzzTwoBoneIK { if self.skeleton.is_leaf(i as i16) { let current_rot = Quat::from_mat4(current); self.spine_trans.push(OzzTransform { - scale: scale, + scale, rotation: current_rot, position: current_pos, }); diff --git a/src/ik_two_bone_job.rs b/src/ik_two_bone_job.rs index 5e53582..22e264c 100644 --- a/src/ik_two_bone_job.rs +++ b/src/ik_two_bone_job.rs @@ -487,7 +487,7 @@ impl IKTwoBoneJob { #[cfg(test)] mod ik_two_bone_tests { use core::f32::consts; - use glam::Vec3; + use glam::{Vec3, Vec4}; use wasm_bindgen_test::*; use super::*; @@ -504,6 +504,11 @@ mod ik_two_bone_tests { assert!(job.validate()); } + #[inline(always)] + fn vec4_to_vec3a(v: Vec4) -> Vec3A { + Vec3A::new(v[0], v[1], v[2]) + } + #[test] #[wasm_bindgen_test] fn test_start_joint_correction() { @@ -512,8 +517,8 @@ mod ik_two_bone_tests { Mat4::from_rotation_translation(Quat::from_axis_angle(Vec3::Z, core::f32::consts::FRAC_PI_2), Vec3::Y); let base_end = Mat4::from_translation(Vec3::X + Vec3::Y); let mid_axis = Vec3A::cross( - Vec3A::from_vec4(base_start.col(3)) - Vec3A::from_vec4(base_mid.col(3)), - Vec3A::from_vec4(base_end.col(3)) - Vec3A::from_vec4(base_mid.col(3)), + vec4_to_vec3a(base_start.col(3)) - vec4_to_vec3a(base_mid.col(3)), + vec4_to_vec3a(base_end.col(3)) - vec4_to_vec3a(base_mid.col(3)), ); let parents = [ @@ -586,8 +591,8 @@ mod ik_two_bone_tests { let mid = Mat4::from_rotation_translation(Quat::from_axis_angle(Vec3::Z, consts::FRAC_PI_2), Vec3::Y); let end = Mat4::from_translation(Vec3::X + Vec3::Y); let mid_axis = Vec3A::cross( - Vec3A::from_vec4(start.col(3)) - Vec3A::from_vec4(mid.col(3)), - Vec3A::from_vec4(end.col(3)) - Vec3A::from_vec4(mid.col(3)), + vec4_to_vec3a(start.col(3)) - vec4_to_vec3a(mid.col(3)), + vec4_to_vec3a(end.col(3)) - vec4_to_vec3a(mid.col(3)), ); let mut job = IKTwoBoneJob::default(); @@ -975,7 +980,7 @@ mod ik_two_bone_tests { let end = Mat4::from_translation(Vec3::X + Vec3::Y); let mut job = IKTwoBoneJob::default(); - job.set_target(Vec3A::from_vec4(start.col(3))); + job.set_target(vec4_to_vec3a(start.col(3))); job.set_start_joint(start); job.set_mid_joint(mid); job.set_end_joint(end); From 88a72a1cbc3697de07466f15375c9ec0562ac3b0 Mon Sep 17 00:00:00 2001 From: Abe M Date: Thu, 29 Aug 2024 04:37:38 -0700 Subject: [PATCH 6/6] Update example to bevy 0.14 --- .gitignore | 1 + demo/Cargo.toml | 2 +- demo/src/blend.rs | 17 +++++++++------ demo/src/main.rs | 48 +++++++++++++++++++---------------------- demo/src/playback.rs | 9 +++++--- demo/src/two_bone_ik.rs | 15 +++++++------ 6 files changed, 49 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 048c7fb..b33ed9d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ Cargo.lock .vscode/ output/ +.DS_Store diff --git a/demo/Cargo.toml b/demo/Cargo.toml index b40cc7d..0346efc 100644 --- a/demo/Cargo.toml +++ b/demo/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" resolver = "2" [dependencies] -bevy = "0.13" +bevy = "0.14" ozz-animation-rs = { path = "../" } reqwest = "0.11" diff --git a/demo/src/blend.rs b/demo/src/blend.rs index 2ecddde..04562e4 100644 --- a/demo/src/blend.rs +++ b/demo/src/blend.rs @@ -17,6 +17,9 @@ pub struct OzzBlend { spine_trans: Vec, } +unsafe impl Send for OzzBlend {} +unsafe impl Sync for OzzBlend {} + impl OzzBlend { pub async fn new() -> Box { let ((mut ar_skeleton, mut ar_animation1), (mut ar_animation2, mut ar_animation3)) = try_zip( @@ -100,7 +103,7 @@ impl OzzBlend { ob.bone_trans.reserve(bone_count); ob.spine_trans.reserve(spine_count); - return Box::new(ob); + Box::new(ob) } } @@ -110,11 +113,11 @@ impl OzzExample for OzzBlend { } fn bone_trans(&self) -> &[OzzTransform] { - return &self.bone_trans; + &self.bone_trans } fn spine_trans(&self) -> &[OzzTransform] { - return &self.spine_trans; + &self.spine_trans } fn update(&mut self, time: Time) { @@ -184,14 +187,14 @@ impl OzzExample for OzzBlend { let bone_rot = Quat::from_mat3(&Mat3::from_cols(bone_dir, bone_rot_y, bone_rot_z)); self.bone_trans.push(OzzTransform { - scale: scale, + scale, rotation: bone_rot, position: parent_pos, }); let parent_rot = Quat::from_mat4(parent); self.spine_trans.push(OzzTransform { - scale: scale, + scale, rotation: parent_rot, position: parent_pos, }); @@ -199,11 +202,11 @@ impl OzzExample for OzzBlend { if self.skeleton.is_leaf(i as i16) { let current_rot = Quat::from_mat4(current); self.spine_trans.push(OzzTransform { - scale: scale, + scale, rotation: current_rot, position: current_pos, }); } } } -} \ No newline at end of file +} diff --git a/demo/src/main.rs b/demo/src/main.rs index 456f155..555e4a7 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -43,7 +43,7 @@ enum OzzType { TwoBoneIK, } -const OZZ_TYPES: [(OzzType, &'static str); 3] = [ +const OZZ_TYPES: [(OzzType, &str); 3] = [ (OzzType::Playback, "Playback"), (OzzType::Blend, "Blend"), (OzzType::TwoBoneIK, "TwoBoneIK"), @@ -87,7 +87,7 @@ fn setup(mut commands: Commands, mut meshes: ResMut>, mut materials // ground commands.spawn(PbrBundle { mesh: meshes.add(Rectangle::new(20.0, 30.0)), - material: materials.add(Color::rgb(1.0, 0.96, 0.95)), + material: materials.add(Color::srgb(1.0, 0.96, 0.95)), transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)) .with_translation(Vec3::new(-2.0, 0.0, -5.0)), ..default() @@ -95,7 +95,7 @@ fn setup(mut commands: Commands, mut meshes: ResMut>, mut materials // bones let bone_mesh = meshes.add(build_bone_mesh()); - let bone_material = materials.add(Color::rgb(0.68, 0.68, 0.8)); + let bone_material = materials.add(Color::srgb(0.68, 0.68, 0.8)); for i in 0..BONE_COUNT { commands.spawn(( PbrBundle { @@ -120,7 +120,7 @@ fn setup(mut commands: Commands, mut meshes: ResMut>, mut materials PbrBundle { mesh: meshes.add(Cuboid::new(2.0, 1.0, 1.0)), material: materials.add(StandardMaterial { - base_color: Color::rgb(0.4, 0.61, 0.98), + base_color: Color::srgb(0.4, 0.61, 0.98), unlit: true, cull_mode: None, ..default() @@ -139,7 +139,6 @@ fn setup(mut commands: Commands, mut meshes: ResMut>, mut materials shadows_enabled: true, shadow_depth_bias: 0.05, shadow_normal_bias: 0.9, - ..default() }, transform: Transform::from_xyz(-3.0, 1.6, -4.0).looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), ..default() @@ -196,7 +195,7 @@ fn update_bones(mut query: Query<(&mut Transform, &mut Visibility, &BoneIndex)>, if let Some(example) = &oc.iter().last().unwrap().example { // only one OzzComponent let bone_trans = example.bone_trans(); - if bone_trans.len() > 0 { + if !bone_trans.is_empty() { for (mut transform, mut visibility, idx) in query.iter_mut() { if idx.0 < bone_trans.len() { *visibility = Visibility::Visible; @@ -215,7 +214,7 @@ fn draw_spines(mut gizmos: Gizmos, oc: Query<&OzzComponent>) { if let Some(example) = &oc.iter().last().unwrap().example { // only one OzzComponent let spine_trans = example.spine_trans(); - if spine_trans.len() > 0 { + if !spine_trans.is_empty() { for trans in spine_trans { draw_gizmos(&mut gizmos, trans); } @@ -226,26 +225,23 @@ fn draw_spines(mut gizmos: Gizmos, oc: Query<&OzzComponent>) { #[rustfmt::skip] fn build_bone_mesh() -> Mesh { - let c = vec![ - Vec3::new(1.0, 0.0, 0.0), + let c = [Vec3::new(1.0, 0.0, 0.0), Vec3::new(0.2, 0.1, 0.1), Vec3::new(0.2, 0.1, -0.1), Vec3::new(0.2, -0.1, -0.1), Vec3::new(0.2, -0.1, 0.1), - Vec3::new(0.0, 0.0, 0.0), - ]; - let n = vec![ - Vec3::cross(c[2] - c[1], c[2] - c[0]).normalize(), + Vec3::new(0.0, 0.0, 0.0)]; + let n = [Vec3::cross(c[2] - c[1], c[2] - c[0]).normalize(), Vec3::cross(c[1] - c[2], c[1] - c[5]).normalize(), Vec3::cross(c[3] - c[2], c[3] - c[0]).normalize(), Vec3::cross(c[2] - c[3], c[2] - c[5]).normalize(), Vec3::cross(c[4] - c[3], c[4] - c[0]).normalize(), Vec3::cross(c[3] - c[4], c[3] - c[5]).normalize(), Vec3::cross(c[1] - c[4], c[1] - c[0]).normalize(), - Vec3::cross(c[4] - c[1], c[4] - c[5]).normalize(), - ]; + Vec3::cross(c[4] - c[1], c[4] - c[5]).normalize()]; + - let mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default()) + Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default()) .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vec![ c[0], c[2], c[1], c[5], c[1], c[2], @@ -265,8 +261,7 @@ fn build_bone_mesh() -> Mesh { n[5], n[5], n[5], n[6], n[6], n[6], n[7], n[7], n[7], - ]); - return mesh; + ]) } fn draw_ground(gizmos: &mut Gizmos) { @@ -274,14 +269,14 @@ fn draw_ground(gizmos: &mut Gizmos) { gizmos.line( Vec3::new(i as f32, 0.0, -20.0), Vec3::new(i as f32, 0.0, 10.0), - Color::rgba(0.25, 0.25, 0.25, 0.4), + Color::srgba(0.25, 0.25, 0.25, 0.4), ); } for i in -20..=10 { gizmos.line( Vec3::new(-12.0, 0.0, i as f32), Vec3::new(8.0, 0.0, i as f32), - Color::rgba(0.25, 0.25, 0.25, 0.4), + Color::srgba(0.25, 0.25, 0.25, 0.4), ); } } @@ -292,21 +287,22 @@ fn draw_gizmos(gizmos: &mut Gizmos, trans: &OzzTransform) { let normal_z = trans.rotation.mul_vec3(Vec3::Z).normalize(); gizmos.circle( trans.position, - Direction3d::new_unchecked(normal_x), + Dir3::new_unchecked(normal_x), trans.scale * 0.25, - Color::rgba(1.0, 0.1, 0.1, 0.5), + Color::srgba(1.0, 0.1, 0.1, 0.5), ); + gizmos.circle( trans.position, - Direction3d::new_unchecked(normal_y), + Dir3::new_unchecked(normal_y), trans.scale * 0.25, - Color::rgba(0.1, 1.0, 0.1, 0.5), + Color::srgba(0.1, 1.0, 0.1, 0.5), ); gizmos.circle( trans.position, - Direction3d::new_unchecked(normal_z), + Dir3::new_unchecked(normal_z), trans.scale * 0.25, - Color::rgba(0.1, 0.1, 1.0, 0.5), + Color::srgba(0.1, 0.1, 1.0, 0.5), ); } diff --git a/demo/src/playback.rs b/demo/src/playback.rs index dc0dc7a..eb6c515 100644 --- a/demo/src/playback.rs +++ b/demo/src/playback.rs @@ -14,6 +14,9 @@ pub struct OzzPlayback { spine_trans: Vec, } +unsafe impl Send for OzzPlayback {} +unsafe impl Sync for OzzPlayback {} + impl OzzPlayback { pub async fn new() -> Box { let (mut ar_skeleton, mut ar_animation) = try_zip( @@ -60,7 +63,7 @@ impl OzzPlayback { oc.bone_trans.reserve(bone_count); oc.spine_trans.reserve(spine_count); - return Box::new(oc); + Box::new(oc) } } @@ -70,11 +73,11 @@ impl OzzExample for OzzPlayback { } fn bone_trans(&self) -> &[OzzTransform] { - return &self.bone_trans; + &self.bone_trans } fn spine_trans(&self) -> &[OzzTransform] { - return &self.spine_trans; + &self.spine_trans } fn update(&mut self, time: Time) { diff --git a/demo/src/two_bone_ik.rs b/demo/src/two_bone_ik.rs index 9267d89..be30fa0 100644 --- a/demo/src/two_bone_ik.rs +++ b/demo/src/two_bone_ik.rs @@ -19,6 +19,9 @@ pub struct OzzTwoBoneIK { spine_trans: Vec, } +unsafe impl Send for OzzTwoBoneIK {} +unsafe impl Sync for OzzTwoBoneIK {} + impl OzzTwoBoneIK { pub async fn new() -> Box { let mut ar_skeleton = load_archive("/two_bone_ik/skeleton.ozz").await.unwrap(); @@ -61,7 +64,7 @@ impl OzzTwoBoneIK { oc.bone_trans.reserve(bone_count); oc.spine_trans.reserve(spine_count); - return Box::new(oc); + Box::new(oc) } } @@ -71,11 +74,11 @@ impl OzzExample for OzzTwoBoneIK { } fn bone_trans(&self) -> &[OzzTransform] { - return &self.bone_trans; + &self.bone_trans } fn spine_trans(&self) -> &[OzzTransform] { - return &self.spine_trans; + &self.spine_trans } fn update(&mut self, time: Time) { @@ -108,11 +111,11 @@ impl OzzExample for OzzTwoBoneIK { self.ik_job.set_twist_angle(0.0); self.ik_job.set_pole_vector(Vec3::new(0.0, 1.0, 0.0).into()); self.ik_job - .set_start_joint(self.models1.buf().unwrap()[start_joint as usize].into()); + .set_start_joint(self.models1.buf().unwrap()[start_joint as usize]); self.ik_job - .set_mid_joint(self.models1.buf().unwrap()[mid_joint as usize].into()); + .set_mid_joint(self.models1.buf().unwrap()[mid_joint as usize]); self.ik_job - .set_end_joint(self.models1.buf().unwrap()[end_joint as usize].into()); + .set_end_joint(self.models1.buf().unwrap()[end_joint as usize]); self.ik_job.run().unwrap();