diff --git a/CHANGELOG.md b/CHANGELOG.md index b38659c..16bee14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Unreleased + +- Add `padding` field to `Pose3` for better compatibility with `bytemuck` and `spirv`. +- Fix various internal implementation details that are incompatible with `spirv`/`naga`. +- Update to `glam 0.32`. + # v0.1.3 - Add `From`/`Into` conversions between f32 and f64 type variants. diff --git a/Cargo.toml b/Cargo.toml index 2eedb52..0205b14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Sébastien Crozet "] description = "Extensions for glam: Pose2, Pose3, Rot2, and matrix utilities." documentation = "https://docs.rs/glamx" homepage = "https://dimforge.com" -repository = "https://github.com/dimforge/parry" +repository = "https://github.com/dimforge/glamx" readme = "README.md" keywords = ["math", "geometry", "rotation", "pose", "glam"] categories = ["mathematics", "game-development", "no-std"] @@ -61,15 +61,15 @@ rand = ["glam/rand"] encase = ["glam/encase"] [dependencies] -glam = { version = "0.30", default-features = false } +glam = { version = "0.32", default-features = false } simba = { version = "0.9", default-features = false } num-traits = { version = "0.2", default-features = false, features = ["libm"] } approx = { version = "0.5", default-features = false, optional = true } serde = { version = "1.0", optional = true, features = ["derive"] } bytemuck = { version = "1", features = ["derive"], optional = true } -nalgebra = { version = "0.34", default-features = false, features = ["convert-glam030"], optional = true } +nalgebra = { version = "0.34", default-features = false, features = ["convert-glam032"], optional = true } rkyv = { version = "0.8", optional = true, default-features = false } [dev-dependencies] approx = "0.5" -glam = { version = "0.30", features = ["approx"] } +glam = { version = "0.32", features = ["approx"] } diff --git a/src/eigen3.rs b/src/eigen3.rs index 8dfb535..0467ed0 100644 --- a/src/eigen3.rs +++ b/src/eigen3.rs @@ -6,6 +6,8 @@ //! //! Adapted from +#![allow(clippy::manual_swap)] // Needed for spirv compatibility. + use glam::Vec3Swizzles; use num_traits::float::FloatConst; @@ -63,7 +65,12 @@ macro_rules! impl_symmetric_eigen3 { if p1 == 0.0 { // The matrix is diagonal. let mut eigenvalues = [mat.x_axis.x, mat.y_axis.y, mat.z_axis.z]; - eigenvalues.sort_by(|a, b| a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal)); + // Simple 3-element sorting network (no alloc needed). + // NOTE: manual swaps instead of .swap() to avoid ptr::swap which + // generates memcpy unsupported in SPIR-V. + if eigenvalues[0] > eigenvalues[1] { let t = eigenvalues[0]; eigenvalues[0] = eigenvalues[1]; eigenvalues[1] = t; } + if eigenvalues[1] > eigenvalues[2] { let t = eigenvalues[1]; eigenvalues[1] = eigenvalues[2]; eigenvalues[2] = t; } + if eigenvalues[0] > eigenvalues[1] { let t = eigenvalues[0]; eigenvalues[0] = eigenvalues[1]; eigenvalues[1] = t; } <$Vec3>::from_array(eigenvalues) } else { let q = (mat.x_axis.x + mat.y_axis.y + mat.z_axis.z) / 3.0; @@ -71,9 +78,17 @@ macro_rules! impl_symmetric_eigen3 { + (mat.y_axis.y - q).powi(2) + (mat.z_axis.z - q).powi(2) + 2.0 * p1; + let p = (p2 / 6.0).sqrt(); - let mat_b = 1.0 / p * (mat - q * <$Mat3>::IDENTITY); - let r = mat_b.determinant() / 2.0; + + // NOTE: `p` shouldn’t be zero, but in some platforms (nvidia gpus apparently), + // denormals can be flushed resulting in a zero. + let r = if p != 0.0 { + let mat_b = 1.0 / p * (mat - q * <$Mat3>::IDENTITY); + mat_b.determinant() / 2.0 + } else { + 1.0 // Will result in phy == 0.0 + }; // r should be in the [-1, 1] range for a symmetric matrix, // but computation error can leave it slightly outside this range. diff --git a/src/lib.rs b/src/lib.rs index c2813c3..63090b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,8 +36,6 @@ #[cfg(feature = "std")] extern crate std; -extern crate alloc; - // Re-export approx for convenience #[cfg(feature = "approx")] pub use approx; diff --git a/src/pose2.rs b/src/pose2.rs index 4f3d131..7fa86fa 100644 --- a/src/pose2.rs +++ b/src/pose2.rs @@ -10,6 +10,7 @@ macro_rules! impl_pose2 { #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] + #[repr(C)] $(#[$attr])* pub struct $Pose2 { /// The rotational part of the pose. @@ -352,7 +353,8 @@ impl_pose2!( glam::Vec2, glam::Vec3, glam::Mat2, - glam::Mat3 + glam::Mat3, + #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))] ); impl_pose2!( DPose2, diff --git a/src/pose3.rs b/src/pose3.rs index 49cb222..89ba212 100644 --- a/src/pose3.rs +++ b/src/pose3.rs @@ -5,17 +5,24 @@ use core::ops::{Mul, MulAssign}; /// Macro to generate a 3D pose type for a specific scalar type. macro_rules! impl_pose3 { - ($Pose3:ident, $Rot3:ident, $Real:ty, $Vec3:ty, $Mat4: ty $(, #[$attr:meta])*) => { + ($Pose3:ident, $Rot3:ident, $Real:ty, $Vec3:ty, $Mat4: ty $(, $Padding: ty, $bytemuck: ident)?) => { #[doc = concat!("A 3D pose (rotation + translation), representing a rigid body transformation (", stringify!($Real), " precision).")] #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] - $(#[$attr])* + $(#[cfg_attr(feature = "bytemuck", derive($bytemuck::Pod, $bytemuck::Zeroable))])* + #[repr(C)] pub struct $Pose3 { /// The rotational part of the pose. pub rotation: $Rot3, /// The translational part of the pose. pub translation: $Vec3, + $( + /// Explicit padding for compatibility with bytemuck and targets like spirv. + /// + /// Can have any value as it is never read from or written to. + pub padding: $Padding, + )* } impl $Pose3 { @@ -23,6 +30,7 @@ macro_rules! impl_pose3 { pub const IDENTITY: Self = Self { rotation: $Rot3::IDENTITY, translation: <$Vec3>::ZERO, + $(padding: 0 as $Padding,)* }; /// Creates the identity pose. @@ -37,6 +45,7 @@ macro_rules! impl_pose3 { Self { rotation: $Rot3::IDENTITY, translation, + $(padding: 0 as $Padding,)* } } @@ -52,6 +61,7 @@ macro_rules! impl_pose3 { Self { rotation, translation: <$Vec3>::ZERO, + $(padding: 0 as $Padding,)* } } @@ -61,6 +71,7 @@ macro_rules! impl_pose3 { Self { rotation, translation, + $(padding: 0 as $Padding,)* } } @@ -71,6 +82,7 @@ macro_rules! impl_pose3 { Self { rotation, translation, + $(padding: 0 as $Padding,)* } } @@ -80,6 +92,7 @@ macro_rules! impl_pose3 { Self { rotation: $Rot3::from_scaled_axis(axisangle.into()), translation: <$Vec3>::ZERO, + $(padding: 0 as $Padding,)* } } @@ -89,6 +102,7 @@ macro_rules! impl_pose3 { Self { rotation: self.rotation, translation: self.translation + self.rotation * translation, + $(padding: 0 as $Padding,)* } } @@ -98,6 +112,7 @@ macro_rules! impl_pose3 { Self { rotation: self.rotation, translation: self.translation + translation, + $(padding: 0 as $Padding,)* } } @@ -108,6 +123,7 @@ macro_rules! impl_pose3 { Self { rotation: inv_rot, translation: inv_rot * (-self.translation), + $(padding: 0 as $Padding,)* } } @@ -119,6 +135,7 @@ macro_rules! impl_pose3 { $Pose3 { translation: inv_rot1 * tr_12, rotation: inv_rot1 * rhs.rotation, + $(padding: 0 as $Padding,)* } } @@ -158,6 +175,7 @@ macro_rules! impl_pose3 { Self { rotation: self.rotation.slerp(other.rotation, t), translation: self.translation.lerp(other.translation, t), + $(padding: 0 as $Padding,)* } } @@ -189,6 +207,7 @@ macro_rules! impl_pose3 { Self { rotation, translation: translation.into(), + $(padding: 0 as $Padding,)* } } @@ -210,6 +229,7 @@ macro_rules! impl_pose3 { $Pose3 { rotation, translation, + $(padding: 0 as $Padding,)* } } @@ -228,6 +248,7 @@ macro_rules! impl_pose3 { $Pose3 { rotation: <$Rot3>::look_at_lh(eye.into(), target.into(), up.into()).inverse(), translation: eye, + $(padding: 0 as $Padding,)* } } } @@ -241,6 +262,7 @@ macro_rules! impl_pose3 { Self { rotation: self.rotation * rhs.rotation, translation: self.translation + self.rotation * rhs.translation, + $(padding: 0 as $Padding,)* } } } @@ -324,6 +346,7 @@ macro_rules! impl_pose3 { $Pose3 { translation: self * rhs.translation, rotation: self * rhs.rotation, + $(padding: 0 as $Padding,)* } } } @@ -336,6 +359,7 @@ macro_rules! impl_pose3 { $Pose3 { translation: self.translation, rotation: self.rotation * rhs, + $(padding: 0 as $Padding,)* } } } @@ -387,7 +411,7 @@ macro_rules! impl_pose3 { }; } -impl_pose3!(Pose3, Rot3, f32, glam::Vec3, glam::Mat4); +impl_pose3!(Pose3, Rot3, f32, glam::Vec3, glam::Mat4, u32, bytemuck); impl_pose3!(Pose3A, Rot3, f32, glam::Vec3A, glam::Mat4); impl_pose3!(DPose3, DRot3, f64, glam::DVec3, glam::DMat4); @@ -408,6 +432,7 @@ impl From for Pose3 { Self { rotation: p.rotation.as_quat(), translation: p.translation.as_vec3(), + padding: 0, } } } @@ -449,6 +474,7 @@ impl From for Pose3 { Self { rotation: p.rotation, translation: p.translation.into(), + padding: 0, } } } @@ -481,6 +507,7 @@ mod nalgebra_conv { iso.translation.y, iso.translation.z, ), + padding: 0, } } }