From c944325607ead462ff9654f7718fb193a4ffc0f1 Mon Sep 17 00:00:00 2001 From: Scott Kane Date: Tue, 9 Jul 2024 17:31:21 +0100 Subject: [PATCH 1/2] Initial repr_c feature --- Cargo.toml | 3 + crates/bevy_gizmos/src/cross.rs | 4 +- crates/bevy_internal/Cargo.toml | 6 + crates/bevy_math/Cargo.toml | 2 + crates/bevy_math/src/affine3.rs | 1 + crates/bevy_math/src/aspect_ratio.rs | 1 + .../bevy_math/src/bounding/bounded2d/mod.rs | 1 + .../bevy_math/src/bounding/bounded3d/mod.rs | 3 +- .../src/bounding/bounded3d/primitive_impls.rs | 2 +- crates/bevy_math/src/bounding/raycast2d.rs | 3 + crates/bevy_math/src/bounding/raycast3d.rs | 3 + crates/bevy_math/src/compass.rs | 1 + crates/bevy_math/src/direction.rs | 3 + crates/bevy_math/src/float_ord.rs | 1 + crates/bevy_math/src/lib.rs | 9 +- crates/bevy_math/src/primitives/dim2.rs | 4 + crates/bevy_math/src/primitives/dim3.rs | 15 + crates/bevy_math/src/primitives/mod.rs | 1 + crates/bevy_math/src/quat.rs | 940 ++++++++++++++++++ crates/bevy_math/src/ray.rs | 2 + crates/bevy_math/src/rects/irect.rs | 1 + crates/bevy_math/src/rects/rect.rs | 1 + crates/bevy_math/src/rects/urect.rs | 1 + crates/bevy_math/src/rotation2d.rs | 1 + crates/bevy_math/src/sampling/standard.rs | 25 +- crates/bevy_pbr/src/light/mod.rs | 2 +- crates/bevy_sprite/src/render/mod.rs | 10 +- crates/bevy_transform/Cargo.toml | 2 + .../src/components/global_transform.rs | 9 +- .../src/components/transform.rs | 8 +- 30 files changed, 1044 insertions(+), 21 deletions(-) create mode 100644 crates/bevy_math/src/quat.rs diff --git a/Cargo.toml b/Cargo.toml index f6a30b4892e0d..28ac1cf7e3cd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -348,6 +348,9 @@ ios_simulator = ["bevy_internal/ios_simulator"] # Enable built in global state machines bevy_state = ["bevy_internal/bevy_state"] +# Enable C style struct representation to allow passing built-in types over FFI +repr_c = ["bevy_internal/repr_c"] + [dependencies] bevy_internal = { path = "crates/bevy_internal", version = "0.15.0-dev", default-features = false } diff --git a/crates/bevy_gizmos/src/cross.rs b/crates/bevy_gizmos/src/cross.rs index 4d716a9dd4a28..ce327b8a7376f 100644 --- a/crates/bevy_gizmos/src/cross.rs +++ b/crates/bevy_gizmos/src/cross.rs @@ -5,7 +5,7 @@ use crate::prelude::{GizmoConfigGroup, Gizmos}; use bevy_color::Color; -use bevy_math::{Mat2, Mat3, Quat, Vec2, Vec3}; +use bevy_math::{Mat2, Quat, Vec2, Vec3}; impl Gizmos<'_, '_, Config> where @@ -33,7 +33,7 @@ where half_size: f32, color: impl Into, ) { - let axes = half_size * Mat3::from_quat(rotation); + let axes = half_size * rotation.to_mat3(); let local_x = axes.col(0); let local_y = axes.col(1); let local_z = axes.col(2); diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 821350c24c1c3..a690c8b381584 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -195,6 +195,12 @@ ios_simulator = ["bevy_pbr?/ios_simulator", "bevy_render?/ios_simulator"] # Enable built in global state machines bevy_state = ["dep:bevy_state"] +# Enable C style struct representation to allow passing built-in types over FFI +repr_c = [ + "bevy_transform/repr_c", + "bevy_math/repr_c" +] + [dependencies] # bevy bevy_a11y = { path = "../bevy_a11y", version = "0.15.0-dev" } diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index eebd683cfc7d9..2ee03c92317cc 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -52,6 +52,8 @@ debug_glam_assert = ["glam/debug-glam-assert"] # Enable the rand dependency for shape_sampling rand = ["dep:rand", "dep:rand_distr", "glam/rand"] +repr_c = [] + [lints] workspace = true diff --git a/crates/bevy_math/src/affine3.rs b/crates/bevy_math/src/affine3.rs index 654721bdfe8a4..9235f4e0f75d0 100644 --- a/crates/bevy_math/src/affine3.rs +++ b/crates/bevy_math/src/affine3.rs @@ -7,6 +7,7 @@ use bevy_reflect::Reflect; /// significant performance impact. Convert to `glam::Affine3A` to do /// non-trivial calculations. #[cfg_attr(feature = "bevy_reflect", derive(Reflect))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Affine3 { /// Scaling, rotation, shears, and other non-translation affine transforms pub matrix3: Mat3, diff --git a/crates/bevy_math/src/aspect_ratio.rs b/crates/bevy_math/src/aspect_ratio.rs index 97960015a5ac1..62bf9015e2fd5 100644 --- a/crates/bevy_math/src/aspect_ratio.rs +++ b/crates/bevy_math/src/aspect_ratio.rs @@ -8,6 +8,7 @@ use bevy_reflect::Reflect; /// An `AspectRatio` is the ratio of width to height. #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct AspectRatio(f32); impl AspectRatio { diff --git a/crates/bevy_math/src/bounding/bounded2d/mod.rs b/crates/bevy_math/src/bounding/bounded2d/mod.rs index 87123075a90b0..270ac9f7a4bd3 100644 --- a/crates/bevy_math/src/bounding/bounded2d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded2d/mod.rs @@ -32,6 +32,7 @@ pub trait Bounded2d { #[doc(alias = "BoundingRectangle")] #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Aabb2d { /// The minimum, conventionally bottom-left, point of the box pub min: Vec2, diff --git a/crates/bevy_math/src/bounding/bounded3d/mod.rs b/crates/bevy_math/src/bounding/bounded3d/mod.rs index 4e67a4d4084f2..e4b597e810f4c 100644 --- a/crates/bevy_math/src/bounding/bounded3d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded3d/mod.rs @@ -35,6 +35,7 @@ pub trait Bounded3d { /// A 3D axis-aligned bounding box #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Aabb3d { /// The minimum point of the box pub min: Vec3A, @@ -232,7 +233,7 @@ impl BoundingVolume for Aabb3d { /// and consider storing the original AABB and rotating that every time instead. #[inline(always)] fn rotate_by(&mut self, rotation: impl Into) { - let rot_mat = Mat3::from_quat(rotation.into()); + let rot_mat = Into::::into(rotation).to_mat3(); let abs_rot_mat = Mat3::from_cols( rot_mat.x_axis.abs(), rot_mat.y_axis.abs(), diff --git a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs index d11f8b9bbe5f8..f9d41cbe6cf2e 100644 --- a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs @@ -101,7 +101,7 @@ impl Bounded3d for Cuboid { fn aabb_3d(&self, translation: Vec3, rotation: Quat) -> Aabb3d { // Compute the AABB of the rotated cuboid by transforming the half-size // by an absolute rotation matrix. - let rot_mat = Mat3::from_quat(rotation); + let rot_mat = rotation.to_mat3(); let abs_rot_mat = Mat3::from_cols( rot_mat.x_axis.abs(), rot_mat.y_axis.abs(), diff --git a/crates/bevy_math/src/bounding/raycast2d.rs b/crates/bevy_math/src/bounding/raycast2d.rs index e3a4764725171..de4f924819375 100644 --- a/crates/bevy_math/src/bounding/raycast2d.rs +++ b/crates/bevy_math/src/bounding/raycast2d.rs @@ -7,6 +7,7 @@ use bevy_reflect::Reflect; /// A raycast intersection test for 2D bounding volumes #[derive(Clone, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct RayCast2d { /// The ray for the test pub ray: Ray2d, @@ -105,6 +106,7 @@ impl IntersectsVolume for RayCast2d { /// An intersection test that casts an [`Aabb2d`] along a ray. #[derive(Clone, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct AabbCast2d { /// The ray along which to cast the bounding volume pub ray: RayCast2d, @@ -143,6 +145,7 @@ impl IntersectsVolume for AabbCast2d { /// An intersection test that casts a [`BoundingCircle`] along a ray. #[derive(Clone, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct BoundingCircleCast { /// The ray along which to cast the bounding volume pub ray: RayCast2d, diff --git a/crates/bevy_math/src/bounding/raycast3d.rs b/crates/bevy_math/src/bounding/raycast3d.rs index 24b28e2774ebd..83b0fe0f70125 100644 --- a/crates/bevy_math/src/bounding/raycast3d.rs +++ b/crates/bevy_math/src/bounding/raycast3d.rs @@ -7,6 +7,7 @@ use bevy_reflect::Reflect; /// A raycast intersection test for 3D bounding volumes #[derive(Clone, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct RayCast3d { /// The origin of the ray. pub origin: Vec3A, @@ -100,6 +101,7 @@ impl IntersectsVolume for RayCast3d { /// An intersection test that casts an [`Aabb3d`] along a ray. #[derive(Clone, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct AabbCast3d { /// The ray along which to cast the bounding volume pub ray: RayCast3d, @@ -143,6 +145,7 @@ impl IntersectsVolume for AabbCast3d { /// An intersection test that casts a [`BoundingSphere`] along a ray. #[derive(Clone, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct BoundingSphereCast { /// The ray along which to cast the bounding volume pub ray: RayCast3d, diff --git a/crates/bevy_math/src/compass.rs b/crates/bevy_math/src/compass.rs index ed1d4b947f248..2141a07e7b1bc 100644 --- a/crates/bevy_math/src/compass.rs +++ b/crates/bevy_math/src/compass.rs @@ -23,6 +23,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Deserialize, Serialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub enum CompassQuadrant { /// Corresponds to [`Dir2::Y`] and [`Dir2::NORTH`] North, diff --git a/crates/bevy_math/src/direction.rs b/crates/bevy_math/src/direction.rs index df061195a7308..15dead5750eba 100644 --- a/crates/bevy_math/src/direction.rs +++ b/crates/bevy_math/src/direction.rs @@ -92,6 +92,7 @@ pub type Direction3d = Dir3; reflect(Serialize, Deserialize) )] #[doc(alias = "Direction2d")] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Dir2(Vec2); impl Primitive2d for Dir2 {} @@ -345,6 +346,7 @@ impl approx::UlpsEq for Dir2 { reflect(Serialize, Deserialize) )] #[doc(alias = "Direction3d")] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Dir3(Vec3); impl Primitive3d for Dir3 {} @@ -551,6 +553,7 @@ impl approx::UlpsEq for Dir3 { reflect(Serialize, Deserialize) )] #[doc(alias = "Direction3dA")] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Dir3A(Vec3A); impl Primitive3d for Dir3A {} diff --git a/crates/bevy_math/src/float_ord.rs b/crates/bevy_math/src/float_ord.rs index 63360449258d3..e116339a71d16 100644 --- a/crates/bevy_math/src/float_ord.rs +++ b/crates/bevy_math/src/float_ord.rs @@ -22,6 +22,7 @@ use bevy_reflect::Reflect; derive(Reflect), reflect(Debug, PartialEq, Hash) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct FloatOrd(pub f32); impl PartialOrd for FloatOrd { diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 868dae094510d..8358a667220d9 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -25,6 +25,9 @@ mod rects; mod rotation2d; #[cfg(feature = "rand")] pub mod sampling; + +mod quat; + pub use compass::{CompassOctant, CompassQuadrant}; pub use affine3::*; @@ -52,10 +55,12 @@ pub mod prelude { }, direction::{Dir2, Dir3, Dir3A}, primitives::*, + quat::Quat, BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4, - Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, + Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, }; } -pub use glam::*; +pub use quat::Quat; +pub use glam::*; \ No newline at end of file diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index e96160367802b..2cc8cd4c14a31 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -20,6 +20,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Circle { /// The radius of the circle pub radius: f32, @@ -107,6 +108,7 @@ impl Measured2d for Circle { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Arc2d { /// The radius of the circle pub radius: f32, @@ -274,6 +276,7 @@ impl Arc2d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct CircularSector { /// The arc defining the sector #[cfg_attr(feature = "serialize", serde(flatten))] @@ -413,6 +416,7 @@ impl CircularSector { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct CircularSegment { /// The arc defining the segment #[cfg_attr(feature = "serialize", serde(flatten))] diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 5eb456f37c101..a3751327c7b4d 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -20,6 +20,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Sphere { /// The radius of the sphere pub radius: f32, @@ -92,6 +93,7 @@ impl Measured3d for Sphere { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Plane3d { /// The normal of the plane. The plane will be placed perpendicular to this direction pub normal: Dir3, @@ -164,6 +166,7 @@ impl Plane3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct InfinitePlane3d { /// The normal of the plane. The plane will be placed perpendicular to this direction pub normal: Dir3, @@ -226,6 +229,7 @@ impl InfinitePlane3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Line3d { /// The direction of the line pub direction: Dir3, @@ -241,6 +245,7 @@ impl Primitive3d for Line3d {} all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Segment3d { /// The direction of the line pub direction: Dir3, @@ -300,6 +305,7 @@ impl Segment3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Polyline3d { /// The vertices of the polyline #[cfg_attr(feature = "serialize", serde(with = "super::serde::array"))] @@ -331,6 +337,7 @@ impl Polyline3d { /// For a version without alloc: [`Polyline3d`] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct BoxedPolyline3d { /// The vertices of the polyline pub vertices: Box<[Vec3]>, @@ -366,6 +373,7 @@ impl BoxedPolyline3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Cuboid { /// Half of the width, height and depth of the cuboid pub half_size: Vec3, @@ -458,6 +466,7 @@ impl Measured3d for Cuboid { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Cylinder { /// The radius of the cylinder pub radius: f32, @@ -536,6 +545,7 @@ impl Measured3d for Cylinder { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Capsule3d { /// The radius of the capsule pub radius: f32, @@ -606,6 +616,7 @@ impl Measured3d for Capsule3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Cone { /// The radius of the base pub radius: f32, @@ -684,6 +695,7 @@ impl Measured3d for Cone { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct ConicalFrustum { /// The radius of the top of the frustum pub radius_top: f32, @@ -736,6 +748,7 @@ pub enum TorusKind { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Torus { /// The radius of the tube of the torus #[doc( @@ -847,6 +860,7 @@ impl Measured3d for Torus { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Triangle3d { /// The vertices of the triangle. pub vertices: [Vec3; 3], @@ -1040,6 +1054,7 @@ impl Measured2d for Triangle3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Tetrahedron { /// The vertices of the tetrahedron. pub vertices: [Vec3; 4], diff --git a/crates/bevy_math/src/primitives/mod.rs b/crates/bevy_math/src/primitives/mod.rs index 460e635867ecb..3d40a885472d8 100644 --- a/crates/bevy_math/src/primitives/mod.rs +++ b/crates/bevy_math/src/primitives/mod.rs @@ -18,6 +18,7 @@ pub trait Primitive3d {} /// The winding order for a set of points #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[doc(alias = "Orientation")] +#[cfg_attr(feature = "repr_c", repr(C))] pub enum WindingOrder { /// A clockwise winding order Clockwise, diff --git a/crates/bevy_math/src/quat.rs b/crates/bevy_math/src/quat.rs new file mode 100644 index 0000000000000..cb60329cf1fed --- /dev/null +++ b/crates/bevy_math/src/quat.rs @@ -0,0 +1,940 @@ +// #![allow(unsafe_code)] +use core::fmt; +use std::arch::x86_64::__m128; +use std::fmt::{Debug, Display}; +use std::iter::{Product, Sum}; +use std::ops::{Add, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub}; + +use glam::{Affine3A, DQuat, EulerRot, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4}; +use bevy_reflect::prelude::{Reflect, ReflectDefault}; +// use bevy_reflect::{ApplyError, DynamicTypePath, FromReflect, GetTypeRegistration, ReflectMut, ReflectOwned, ReflectRef, Typed, TypeInfo, TypePath, TypeRegistration, ValueInfo}; +// use bevy_reflect::utility::NonGenericTypeInfoCell; + +#[derive(Clone, Copy, Reflect)] +#[reflect(Default)] +#[repr(C)] +pub struct QuatReprC { + pub x: f32, + pub y: f32, + pub z: f32, + pub w: f32, +} + +/// A quaternion representing an orientation. +/// +/// This quaternion is intended to be of unit length but may denormalize due to +/// floating point "error creep" which can occur when successive quaternion +/// operations are applied. +/// +/// SIMD vector types are used for storage on supported platforms unless repr_c feature flag is enabled. +/// SIMD types currently aren't compatible with FFI. +/// +/// This type is 16 byte aligned. +#[derive(Clone, Copy, Reflect)] +#[reflect(Default)] +#[repr(transparent)] +pub struct Quat { + #[cfg(feature = "repr_c")] + inner: QuatReprC, + #[cfg(not(feature = "repr_c"))] + inner: glam::Quat, +} + +impl Quat { + /// All zeros. + const ZERO: Self = Self::from_array([0.0; 4]); + + /// The identity quaternion. Corresponds to no rotation. + pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); + + /// All NANs. + pub const NAN: Self = Self::from_array([f32::NAN; 4]); + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline(always)] + #[must_use] + pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self { + #[cfg(feature = "repr_c")] + return Self { + inner: QuatReprC { x, y, z, w }, + }; + #[cfg(not(feature = "repr_c"))] + return Self { + inner: glam::Quat::from_xyzw(x, y, z, w), + }; + } + + /// Creates a rotation quaternion from an array. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + #[must_use] + pub const fn from_array(a: [f32; 4]) -> Self { + #[cfg(feature = "repr_c")] + return Self { + inner: QuatReprC { + x: a[0], + y: a[1], + z: a[2], + w: a[3], + }, + }; + #[cfg(not(feature = "repr_c"))] + return Self { + inner: glam::Quat::from_xyzw(a[0], a[1], a[2], a[3]), + }; + } + + /// Creates a new rotation quaternion from a 4D vector. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + #[must_use] + pub const fn from_vec4(v: Vec4) -> Self { + let [x, y, z, w] = v.to_array(); + Self::from_xyzw(x, y, z, w) + } + + /// Creates a rotation quaternion from a slice. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + #[must_use] + pub fn from_slice(slice: &[f32]) -> Self { + glam::Quat::from_slice(slice).into() + } + + /// Writes the quaternion to an unaligned slice. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + Into::::into(self).write_to_slice(slice) + } + + /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). + /// + /// The axis must be a unit vector. + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam::Quat::from_axis_angle(axis, angle).into() + } + + /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. + /// + /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. + #[inline] + #[must_use] + pub fn from_scaled_axis(v: Vec3) -> Self { + glam::Quat::from_scaled_axis(v).into() + } + + /// Creates a quaternion from the `angle` (in radians) around the x axis. + #[inline] + #[must_use] + pub fn from_rotation_x(angle: f32) -> Self { + glam::Quat::from_rotation_x(angle).into() + } + + /// Creates a quaternion from the `angle` (in radians) around the y axis. + #[inline] + #[must_use] + pub fn from_rotation_y(angle: f32) -> Self { + glam::Quat::from_rotation_y(angle).into() + } + + /// Creates a quaternion from the `angle` (in radians) around the z axis. + #[inline] + #[must_use] + pub fn from_rotation_z(angle: f32) -> Self { + glam::Quat::from_rotation_z(angle).into() + } + + /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). + #[inline] + #[must_use] + pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self { + glam::Quat::from_euler(euler, a, b, c).into() + } + + /// Creates a quaternion from a 3x3 rotation matrix. + #[inline] + #[must_use] + pub fn from_mat3(mat: &Mat3) -> Self { + glam::Quat::from_mat3(mat).into() + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn to_mat3(self) -> Mat3 { + Mat3::from_quat(self.into()) + } + + /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix. + #[inline] + #[must_use] + pub fn from_mat3a(mat: &Mat3A) -> Self { + glam::Quat::from_mat3a(mat).into() + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn to_mat3a(self) -> Mat3A { + Mat3A::from_quat(self.into()) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. + #[inline] + #[must_use] + pub fn from_mat4(mat: &Mat4) -> Self { + glam::Quat::from_mat4(mat).into() + } + + /// Creates an affine transformation matrix from the given `rotation` quaternion. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn to_mat4(self) -> Mat4 { + Mat4::from_quat(self.into()) + } + + /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn scale_rotation_translation_to_mat4(scale: Vec3, rotation: Quat, translation: Vec3) -> Mat4 { + Mat4::from_scale_rotation_translation(scale, rotation.into(), translation) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is + /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero or if the resulting scale vector + /// contains any zero elements when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn mat4_to_scale_rotation_translation(mat: Mat4) -> (Vec3, Quat, Vec3) { + let (scale, rotation, translation) = mat.to_scale_rotation_translation(); + (scale, rotation.into(), translation) + } + + /// Creates an affine transform from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// Equivalent to `Affine3A::from_translation(translation) * + /// Affine3A::from_quat(rotation) * Affine3A::from_scale(scale)` + #[inline] + #[must_use] + pub fn scale_rotation_translation_to_affine3a(scale: Vec3, rotation: Quat, translation: Vec3) -> Affine3A { + Affine3A::from_scale_rotation_translation( + scale, + rotation.into(), + translation, + ) + } + + /// Creates an affine transform from the given 3D `rotation` and `translation`. + /// + /// Equivalent to `Affine3A::from_translation(translation) * Affine3A::from_quat(rotation)` + #[inline] + #[must_use] + pub fn rotation_translation_to_affine3a(rotation: Quat, translation: Vec3) -> Affine3A { + Affine3A::from_rotation_translation(rotation.into(), translation) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. + /// + /// The transform is expected to be non-degenerate and without shearing, or the output + /// will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale + /// vector contains any zero elements when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn affine3a_to_scale_rotation_translation(affine: Affine3A) -> (Vec3, Quat, Vec3) { + let (scale, rotation, translation) = affine.to_scale_rotation_translation(); + (scale, rotation.into(), translation) + } + + /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the + /// plane spanned by the two vectors. Will rotate at most 180 degrees. + /// + /// The inputs must be unit vectors. + /// + /// `from_rotation_arc(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[must_use] + pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self { + glam::Quat::from_rotation_arc(from, to).into() + } + + /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means + /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. + /// + /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 + /// degrees. + /// + /// The inputs must be unit vectors. + /// + /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self { + glam::Quat::from_rotation_arc_colinear(from, to).into() + } + + /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is + /// around the z axis. Will rotate at most 180 degrees. + /// + /// The inputs must be unit vectors. + /// + /// `from_rotation_arc_2d(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[must_use] + pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self { + glam::Quat::from_rotation_arc_2d(from, to).into() + } + + /// Returns the rotation axis (normalized) and angle (in radians) of `self`. + #[inline] + #[must_use] + pub fn to_axis_angle(self) -> (Vec3, f32) { + Into::::into(self).to_axis_angle() + } + + /// Returns the rotation axis scaled by the rotation in radians. + #[inline] + #[must_use] + pub fn to_scaled_axis(self) -> Vec3 { + Into::::into(self).to_scaled_axis() + } + + /// Returns the rotation angles for the given euler rotation sequence. + #[inline] + #[must_use] + pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) { + Into::::into(self).to_euler(euler) + } + + /// `[x, y, z, w]` + #[inline] + #[must_use] + pub fn to_array(&self) -> [f32; 4] { + Into::::into(*self).to_array() + } + + /// Returns the vector part of the quaternion. + #[inline] + #[must_use] + pub fn xyz(self) -> Vec3 { + Into::::into(self).xyz() + } + + /// Returns the quaternion conjugate of `self`. For a unit quaternion the + /// conjugate is also the inverse. + #[inline] + #[must_use] + pub fn conjugate(self) -> Self { + Into::::into(self).conjugate().into() + } + + /// Returns the inverse of a normalized quaternion. + /// + /// Typically quaternion inverse returns the conjugate of a normalized quaternion. + /// Because `self` is assumed to already be unit length this method *does not* normalize + /// before returning the conjugate. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn inverse(self) -> Self { + Into::::into(self).inverse().into() + } + + /// Computes the dot product of `self` and `rhs`. The dot product is + /// equal to the cosine of the angle between two quaternion rotations. + #[inline] + #[must_use] + pub fn dot(self, rhs: Self) -> f32 { + Into::::into(self).dot(Into::::into(rhs)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + #[must_use] + pub fn length(self) -> f32 { + Into::::into(self).length() + } + + /// Computes the squared length of `self`. + /// + /// This is generally faster than `length()` as it avoids a square + /// root operation. + #[doc(alias = "magnitude2")] + #[inline] + #[must_use] + pub fn length_squared(self) -> f32 { + Into::::into(self).length_squared() + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + #[must_use] + pub fn length_recip(self) -> f32 { + Into::::into(self).length_recip() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn normalize(self) -> Self { + Into::::into(self).normalize().into() + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + #[must_use] + pub fn is_finite(self) -> bool { + Into::::into(self).is_finite() + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + #[must_use] + pub fn is_nan(self) -> bool { + Into::::into(self).is_nan() + } + + /// Returns whether `self` of length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + #[must_use] + pub fn is_normalized(self) -> bool { + Into::::into(self).is_normalized() + } + + /// Checks if the quaternion is near the identity rotation. + /// + /// # Details + /// + /// This function determines if the quaternion represents a rotation that is + /// very close to the identity rotation (no rotation). Due to floating point + /// precision limitations, very small rotations cannot be accurately represented. + /// + /// The threshold for considering a quaternion as near identity is set to + /// `0.0028471446` radians. This threshold is based on the closest value to + /// `1.0` that a `f32` can represent which is not `1.0` itself: + /// + /// ```text + /// 0.99999994.acos() * 2.0 = 0.000690533954 rad + /// ``` + /// + /// An error threshold of `1.e-6` is used by default: + /// + /// ```text + /// (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad + /// (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad + /// ``` + /// + /// The function calculates the angle based on the w-component of the quaternion + /// and compares it to the threshold. The absolute value of `quat.w` is taken + /// to ensure the shortest path is considered, as `quat.w` close to `-1.0` + /// would indicate a near 2*PI rotation, which is essentially a negative zero rotation. + /// + /// # Returns + /// + /// * `true` if the quaternion is near the identity rotation. + /// * `false` otherwise. + /// + /// # References + /// + /// This implementation is based on the algorithm from the [`rtm`](https://github.com/nfrechette/rtm) + /// library's `rtm::quat_near_identity` function. + #[inline] + #[must_use] + pub fn is_near_identity(self) -> bool { + Into::::into(self).is_near_identity() + } + + /// Returns the angle (in radians) for the minimal rotation + /// for transforming this quaternion into another. + /// + /// Both quaternions must be normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn angle_between(self, rhs: Self) -> f32 { + Into::::into(self).angle_between(Into::::into(rhs)) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two quaternions contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + #[must_use] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + Into::::into(self).abs_diff_eq(Into::::into(rhs), max_abs_diff) + } + + /// Performs a linear interpolation between `self` and `rhs` based on + /// the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `rhs`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[doc(alias = "mix")] + #[inline] + #[must_use] + pub fn lerp(self, end: Self, s: f32) -> Self { + Into::::into(self).lerp(Into::::into(end), s).into() + } + + /// Performs a spherical linear interpolation between `self` and `end` + /// based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `end`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + #[allow(unused_mut)] + pub fn slerp(self, mut end: Self, s: f32) -> Self { + Into::::into(self).slerp(end.into(), s).into() + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn mul_vec3(self, rhs: Vec3) -> Vec3 { + Into::::into(self).mul_vec3(rhs) + } + + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + #[must_use] + pub fn mul_quat(self, rhs: Self) -> Self { + Into::::into(self).mul_quat(Into::::into(rhs)).into() + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. + #[inline] + #[must_use] + pub fn from_affine3(a: &Affine3A) -> Self { + glam::Quat::from_affine3(a).into() + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + #[inline] + #[must_use] + pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A { + Into::::into(self).mul_vec3a(rhs) + } + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + #[must_use] + pub fn as_dquat(self) -> DQuat { + Into::::into(self).as_dquat() + } +} + +impl Debug for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&Into::::into(*self), fmt) + } +} + +impl Display for Quat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::Display::fmt(&Into::::into(*self), f) + } +} + +impl Add for Quat { + type Output = Self; + /// Adds two quaternions. + /// + /// The sum is not guaranteed to be normalized. + /// + /// Note that addition is not the same as combining the rotations represented by the + /// two quaternions! That corresponds to multiplication. + #[inline] + fn add(self, rhs: Self) -> Self { + Into::::into(self).add(Into::::into(rhs)).into() + } +} + +impl Sub for Quat { + type Output = Self; + /// Subtracts the `rhs` quaternion from `self`. + /// + /// The difference is not guaranteed to be normalized. + #[inline] + fn sub(self, rhs: Self) -> Self { + Into::::into(self).sub(Into::::into(rhs)).into() + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies a quaternion by a scalar value. + /// + /// The product is not guaranteed to be normalized. + #[inline] + fn mul(self, rhs: f32) -> Self { + Into::::into(self).mul(rhs).into() + } +} + +impl Div for Quat { + type Output = Self; + /// Divides a quaternion by a scalar value. + /// The quotient is not guaranteed to be normalized. + #[inline] + fn div(self, rhs: f32) -> Self { + Into::::into(self).div(rhs).into() + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Self) -> Self { + Into::::into(self).mul(Into::::into(rhs)).into() + } +} + +impl MulAssign for Quat { + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = Into::::into(*self).mul(Into::::into(rhs)).into() + } +} + +impl Mul for Quat { + type Output = Vec3; + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Vec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Neg for Quat { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Into::::into(self).neg().into() + } +} + +impl Default for Quat { + #[inline] + fn default() -> Self { + glam::Quat::default().into() + } +} + +impl PartialEq for Quat { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + Into::::into(*self) == Into::::into(*rhs) + } +} + +impl Sum for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +impl<'a> Sum<&'a Self> for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl Product for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +impl<'a> Product<&'a Self> for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl Mul for Quat { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl From for Vec4 { + #[inline] + fn from(q: Quat) -> Self { + Into::::into(q).into() + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(q: Quat) -> Self { + Into::::into(q).into() + } +} + +impl From for [f32; 4] { + #[inline] + fn from(q: Quat) -> Self { + Into::::into(q).into() + } +} + +impl From for __m128 { + #[inline] + fn from(q: Quat) -> Self { + Into::::into(q).into() + } +} + +impl Into for QuatReprC { + fn into(self) -> glam::Quat { + glam::Quat::from_xyzw(self.x, self.y, self.z, self.w) + } +} + +#[cfg(feature = "repr_c")] +impl Into for QuatReprC { + fn into(self) -> Quat { + Quat { + inner: QuatReprC { + x: self.x, + y: self.y, + z: self.z, + w: self.w, + }, + } + } +} + +impl Into for glam::Quat { + fn into(self) -> Quat { + #[cfg(feature = "repr_c")] + let inner = QuatReprC { + x: self.x, + y: self.y, + z: self.z, + w: self.w, + }; + #[cfg(not(feature = "repr_c"))] + let inner = glam::Quat::from_xyzw(self.x, self.y, self.z, self.w); + Quat { + inner + } + } +} + +impl From for QuatReprC { + fn from(q: glam::Quat) -> Self { + QuatReprC { + x: q.x, + y: q.y, + z: q.z, + w: q.w, + } + } +} + +impl From for glam::Quat { + fn from(q: Quat) -> Self { + glam::Quat::from_xyzw(q.x, q.y, q.z, q.w) + } +} + +impl Default for QuatReprC { + fn default() -> Self { + glam::Quat::default().into() + } +} + +impl Deref for Quat { + #[cfg(feature = "repr_c")] + type Target = QuatReprC; + #[cfg(not(feature = "repr_c"))] + type Target = glam::Quat; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Quat { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} \ No newline at end of file diff --git a/crates/bevy_math/src/ray.rs b/crates/bevy_math/src/ray.rs index df490a506cf49..a5d0baa469ec0 100644 --- a/crates/bevy_math/src/ray.rs +++ b/crates/bevy_math/src/ray.rs @@ -16,6 +16,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Deserialize, Serialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Ray2d { /// The origin of the ray. pub origin: Vec2, @@ -65,6 +66,7 @@ impl Ray2d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Deserialize, Serialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Ray3d { /// The origin of the ray. pub origin: Vec3, diff --git a/crates/bevy_math/src/rects/irect.rs b/crates/bevy_math/src/rects/irect.rs index ae858a88c0bfe..49fa5b6f0e83f 100644 --- a/crates/bevy_math/src/rects/irect.rs +++ b/crates/bevy_math/src/rects/irect.rs @@ -25,6 +25,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct IRect { /// The minimum corner point of the rect. pub min: IVec2, diff --git a/crates/bevy_math/src/rects/rect.rs b/crates/bevy_math/src/rects/rect.rs index 8e804dcd085f0..3783fd8d38d07 100644 --- a/crates/bevy_math/src/rects/rect.rs +++ b/crates/bevy_math/src/rects/rect.rs @@ -25,6 +25,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Rect { /// The minimum corner point of the rect. pub min: Vec2, diff --git a/crates/bevy_math/src/rects/urect.rs b/crates/bevy_math/src/rects/urect.rs index 54cde829040fc..356946fad1d6f 100644 --- a/crates/bevy_math/src/rects/urect.rs +++ b/crates/bevy_math/src/rects/urect.rs @@ -25,6 +25,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct URect { /// The minimum corner point of the rect. pub min: UVec2, diff --git a/crates/bevy_math/src/rotation2d.rs b/crates/bevy_math/src/rotation2d.rs index 77011f93a3cd7..3b4cf479151c7 100644 --- a/crates/bevy_math/src/rotation2d.rs +++ b/crates/bevy_math/src/rotation2d.rs @@ -42,6 +42,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; reflect(Serialize, Deserialize) )] #[doc(alias = "rotation", alias = "rotation2d", alias = "rotation_2d")] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Rot2 { /// The cosine of the rotation angle in radians. /// diff --git a/crates/bevy_math/src/sampling/standard.rs b/crates/bevy_math/src/sampling/standard.rs index 9c5ff1fa3dea4..951b48279e429 100644 --- a/crates/bevy_math/src/sampling/standard.rs +++ b/crates/bevy_math/src/sampling/standard.rs @@ -25,12 +25,13 @@ use std::f32::consts::TAU; use crate::{ primitives::{Circle, Sphere}, - Dir2, Dir3, Dir3A, Quat, Rot2, ShapeSample, Vec3A, + Dir2, Dir3, Dir3A, Rot2, ShapeSample, Vec3A, }; use rand::{ distributions::{Distribution, Standard}, Rng, }; +use crate::prelude::Quat; /// Ergonomics trait for a type with a [`Standard`] distribution, allowing values to be generated /// uniformly from an [`Rng`] by a method in its own namespace. @@ -96,4 +97,26 @@ impl Distribution for Standard { impl FromRng for Rot2 {} +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> Quat { + let u1 = rng.gen::(); + let u2 = rng.gen::(); + let u3 = rng.gen::(); + + let sq1 = (1.0 - u1).sqrt(); + let sq2 = u1.sqrt(); + + let theta1 = TAU * u2; + let theta2 = TAU * u3; + + let x = sq1 * theta1.cos(); + let y = sq1 * theta1.sin(); + let z = sq2 * theta2.cos(); + let w = sq2 * theta2.sin(); + + Quat::from_xyzw(x, y, z, w) + } +} + impl FromRng for Quat {} diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 247aa49f504cc..12478d143b932 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -332,7 +332,7 @@ pub fn build_directional_light_cascades( // users to not change any other aspects of the transform - there's no guarantee // `transform.compute_matrix()` will give us a matrix with our desired properties. // Instead, we directly create a good matrix from just the rotation. - let world_from_light = Mat4::from_quat(transform.compute_transform().rotation); + let world_from_light = transform.compute_transform().rotation.to_mat4(); let light_to_world_inverse = world_from_light.inverse(); for (view_entity, projection, view_to_world) in views.iter().copied() { diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index d60efb0977eb2..6646945588273 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -699,11 +699,11 @@ pub fn prepare_sprite_image_bind_groups( quad_size = custom_size; } let transform = extracted_sprite.transform.affine() - * Affine3A::from_scale_rotation_translation( - quad_size.extend(1.0), - Quat::IDENTITY, - (quad_size * (-extracted_sprite.anchor - Vec2::splat(0.5))).extend(0.0), - ); + * Quat::scale_rotation_translation_to_affine3a( + quad_size.extend(1.0), + Quat::IDENTITY, + (quad_size * (-extracted_sprite.anchor - Vec2::splat(0.5))).extend(0.0) + ); // Store the vertex data and add the item to the render phase sprite_meta diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index e5edff96ea9ed..5436ee9bc7544 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -48,6 +48,8 @@ default = ["bevy-support"] serialize = ["dep:serde", "bevy_math/serialize"] +repr_c = [] + [lints] workspace = true diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index fa5384c1d0253..221e3ed3aa651 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -42,6 +42,7 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect}; derive(Component, Reflect), reflect(Component, Default, PartialEq) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct GlobalTransform(Affine3A); macro_rules! impl_local_axis { @@ -79,7 +80,7 @@ impl GlobalTransform { #[doc(hidden)] #[inline] pub fn from_rotation(rotation: Quat) -> Self { - GlobalTransform(Affine3A::from_rotation_translation(rotation, Vec3::ZERO)) + GlobalTransform(Quat::rotation_translation_to_affine3a(rotation, Vec3::ZERO)) } #[doc(hidden)] @@ -106,7 +107,7 @@ impl GlobalTransform { /// will be invalid. #[inline] pub fn compute_transform(&self) -> Transform { - let (scale, rotation, translation) = self.0.to_scale_rotation_translation(); + let (scale, rotation, translation) = Quat::affine3a_to_scale_rotation_translation(self.0); Transform { translation, rotation, @@ -150,7 +151,7 @@ impl GlobalTransform { #[inline] pub fn reparented_to(&self, parent: &GlobalTransform) -> Transform { let relative_affine = parent.affine().inverse() * self.affine(); - let (scale, rotation, translation) = relative_affine.to_scale_rotation_translation(); + let (scale, rotation, translation) = Quat::affine3a_to_scale_rotation_translation(relative_affine); Transform { translation, rotation, @@ -164,7 +165,7 @@ impl GlobalTransform { /// will be invalid. #[inline] pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) { - self.0.to_scale_rotation_translation() + Quat::affine3a_to_scale_rotation_translation(self.0) } impl_local_axis!(right, left, X); diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 554d5f66177f5..248e3eacf39c1 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -40,6 +40,7 @@ use std::ops::Mul; derive(Component, Reflect), reflect(Component, Default, PartialEq) )] +#[cfg_attr(feature = "repr_c", repr(C))] pub struct Transform { /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. /// @@ -81,8 +82,7 @@ impl Transform { /// transformation matrix. #[inline] pub fn from_matrix(world_from_local: Mat4) -> Self { - let (scale, rotation, translation) = world_from_local.to_scale_rotation_translation(); - + let (scale, rotation, translation) = Quat::mat4_to_scale_rotation_translation(world_from_local); Transform { translation, rotation, @@ -209,14 +209,14 @@ impl Transform { /// rotation, and scale. #[inline] pub fn compute_matrix(&self) -> Mat4 { - Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + Quat::scale_rotation_translation_to_mat4(self.scale, self.rotation, self.translation) } /// Returns the 3d affine transformation matrix from this transforms translation, /// rotation, and scale. #[inline] pub fn compute_affine(&self) -> Affine3A { - Affine3A::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + Quat::scale_rotation_translation_to_affine3a(self.scale, self.rotation, self.translation) } /// Get the unit vector in the local `X` direction. From 615dcdb975dce55e754f0b519300962a40d40957 Mon Sep 17 00:00:00 2001 From: Scott Kane Date: Sat, 3 Aug 2024 14:54:51 +0100 Subject: [PATCH 2/2] Switch to glam scalar-math and revert repr c wrappers --- crates/bevy_gizmos/src/cross.rs | 4 +- crates/bevy_internal/Cargo.toml | 3 +- crates/bevy_math/Cargo.toml | 5 +- .../bevy_math/src/bounding/bounded3d/mod.rs | 2 +- .../src/bounding/bounded3d/primitive_impls.rs | 2 +- crates/bevy_math/src/lib.rs | 6 +- crates/bevy_math/src/quat.rs | 940 ------------------ crates/bevy_math/src/sampling/standard.rs | 23 - crates/bevy_pbr/src/light/mod.rs | 2 +- crates/bevy_reflect/Cargo.toml | 2 + crates/bevy_reflect/src/impls/glam.rs | 1 + crates/bevy_sprite/src/render/mod.rs | 2 +- .../src/components/global_transform.rs | 8 +- .../src/components/transform.rs | 6 +- 14 files changed, 24 insertions(+), 982 deletions(-) delete mode 100644 crates/bevy_math/src/quat.rs diff --git a/crates/bevy_gizmos/src/cross.rs b/crates/bevy_gizmos/src/cross.rs index ce327b8a7376f..4d716a9dd4a28 100644 --- a/crates/bevy_gizmos/src/cross.rs +++ b/crates/bevy_gizmos/src/cross.rs @@ -5,7 +5,7 @@ use crate::prelude::{GizmoConfigGroup, Gizmos}; use bevy_color::Color; -use bevy_math::{Mat2, Quat, Vec2, Vec3}; +use bevy_math::{Mat2, Mat3, Quat, Vec2, Vec3}; impl Gizmos<'_, '_, Config> where @@ -33,7 +33,7 @@ where half_size: f32, color: impl Into, ) { - let axes = half_size * rotation.to_mat3(); + let axes = half_size * Mat3::from_quat(rotation); let local_x = axes.col(0); let local_y = axes.col(1); let local_z = axes.col(2); diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index a690c8b381584..02fbbeec77366 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -198,7 +198,8 @@ bevy_state = ["dep:bevy_state"] # Enable C style struct representation to allow passing built-in types over FFI repr_c = [ "bevy_transform/repr_c", - "bevy_math/repr_c" + "bevy_math/repr_c", + "bevy_reflect/repr_c" ] [dependencies] diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index 2ee03c92317cc..ab28fe90a9df7 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -52,7 +52,10 @@ debug_glam_assert = ["glam/debug-glam-assert"] # Enable the rand dependency for shape_sampling rand = ["dep:rand", "dep:rand_distr", "glam/rand"] -repr_c = [] +repr_c = [ + "glam/scalar-math", + "bevy_reflect/repr_c" +] [lints] workspace = true diff --git a/crates/bevy_math/src/bounding/bounded3d/mod.rs b/crates/bevy_math/src/bounding/bounded3d/mod.rs index e4b597e810f4c..39f912307006d 100644 --- a/crates/bevy_math/src/bounding/bounded3d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded3d/mod.rs @@ -233,7 +233,7 @@ impl BoundingVolume for Aabb3d { /// and consider storing the original AABB and rotating that every time instead. #[inline(always)] fn rotate_by(&mut self, rotation: impl Into) { - let rot_mat = Into::::into(rotation).to_mat3(); + let rot_mat = Mat3::from_quat(rotation.into()); let abs_rot_mat = Mat3::from_cols( rot_mat.x_axis.abs(), rot_mat.y_axis.abs(), diff --git a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs index f9d41cbe6cf2e..d11f8b9bbe5f8 100644 --- a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs @@ -101,7 +101,7 @@ impl Bounded3d for Cuboid { fn aabb_3d(&self, translation: Vec3, rotation: Quat) -> Aabb3d { // Compute the AABB of the rotated cuboid by transforming the half-size // by an absolute rotation matrix. - let rot_mat = rotation.to_mat3(); + let rot_mat = Mat3::from_quat(rotation); let abs_rot_mat = Mat3::from_cols( rot_mat.x_axis.abs(), rot_mat.y_axis.abs(), diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 8358a667220d9..4d9d5f8f56083 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -26,7 +26,7 @@ mod rotation2d; #[cfg(feature = "rand")] pub mod sampling; -mod quat; +// mod quat; pub use compass::{CompassOctant, CompassQuadrant}; @@ -55,12 +55,10 @@ pub mod prelude { }, direction::{Dir2, Dir3, Dir3A}, primitives::*, - quat::Quat, BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4, - Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, + Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, }; } -pub use quat::Quat; pub use glam::*; \ No newline at end of file diff --git a/crates/bevy_math/src/quat.rs b/crates/bevy_math/src/quat.rs deleted file mode 100644 index cb60329cf1fed..0000000000000 --- a/crates/bevy_math/src/quat.rs +++ /dev/null @@ -1,940 +0,0 @@ -// #![allow(unsafe_code)] -use core::fmt; -use std::arch::x86_64::__m128; -use std::fmt::{Debug, Display}; -use std::iter::{Product, Sum}; -use std::ops::{Add, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub}; - -use glam::{Affine3A, DQuat, EulerRot, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4}; -use bevy_reflect::prelude::{Reflect, ReflectDefault}; -// use bevy_reflect::{ApplyError, DynamicTypePath, FromReflect, GetTypeRegistration, ReflectMut, ReflectOwned, ReflectRef, Typed, TypeInfo, TypePath, TypeRegistration, ValueInfo}; -// use bevy_reflect::utility::NonGenericTypeInfoCell; - -#[derive(Clone, Copy, Reflect)] -#[reflect(Default)] -#[repr(C)] -pub struct QuatReprC { - pub x: f32, - pub y: f32, - pub z: f32, - pub w: f32, -} - -/// A quaternion representing an orientation. -/// -/// This quaternion is intended to be of unit length but may denormalize due to -/// floating point "error creep" which can occur when successive quaternion -/// operations are applied. -/// -/// SIMD vector types are used for storage on supported platforms unless repr_c feature flag is enabled. -/// SIMD types currently aren't compatible with FFI. -/// -/// This type is 16 byte aligned. -#[derive(Clone, Copy, Reflect)] -#[reflect(Default)] -#[repr(transparent)] -pub struct Quat { - #[cfg(feature = "repr_c")] - inner: QuatReprC, - #[cfg(not(feature = "repr_c"))] - inner: glam::Quat, -} - -impl Quat { - /// All zeros. - const ZERO: Self = Self::from_array([0.0; 4]); - - /// The identity quaternion. Corresponds to no rotation. - pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); - - /// All NANs. - pub const NAN: Self = Self::from_array([f32::NAN; 4]); - - /// Creates a new rotation quaternion. - /// - /// This should generally not be called manually unless you know what you are doing. - /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. - /// - /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline(always)] - #[must_use] - pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self { - #[cfg(feature = "repr_c")] - return Self { - inner: QuatReprC { x, y, z, w }, - }; - #[cfg(not(feature = "repr_c"))] - return Self { - inner: glam::Quat::from_xyzw(x, y, z, w), - }; - } - - /// Creates a rotation quaternion from an array. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline] - #[must_use] - pub const fn from_array(a: [f32; 4]) -> Self { - #[cfg(feature = "repr_c")] - return Self { - inner: QuatReprC { - x: a[0], - y: a[1], - z: a[2], - w: a[3], - }, - }; - #[cfg(not(feature = "repr_c"))] - return Self { - inner: glam::Quat::from_xyzw(a[0], a[1], a[2], a[3]), - }; - } - - /// Creates a new rotation quaternion from a 4D vector. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline] - #[must_use] - pub const fn from_vec4(v: Vec4) -> Self { - let [x, y, z, w] = v.to_array(); - Self::from_xyzw(x, y, z, w) - } - - /// Creates a rotation quaternion from a slice. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - /// - /// # Panics - /// - /// Panics if `slice` length is less than 4. - #[inline] - #[must_use] - pub fn from_slice(slice: &[f32]) -> Self { - glam::Quat::from_slice(slice).into() - } - - /// Writes the quaternion to an unaligned slice. - /// - /// # Panics - /// - /// Panics if `slice` length is less than 4. - #[inline] - pub fn write_to_slice(self, slice: &mut [f32]) { - Into::::into(self).write_to_slice(slice) - } - - /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). - /// - /// The axis must be a unit vector. - /// - /// # Panics - /// - /// Will panic if `axis` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { - glam::Quat::from_axis_angle(axis, angle).into() - } - - /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. - /// - /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. - #[inline] - #[must_use] - pub fn from_scaled_axis(v: Vec3) -> Self { - glam::Quat::from_scaled_axis(v).into() - } - - /// Creates a quaternion from the `angle` (in radians) around the x axis. - #[inline] - #[must_use] - pub fn from_rotation_x(angle: f32) -> Self { - glam::Quat::from_rotation_x(angle).into() - } - - /// Creates a quaternion from the `angle` (in radians) around the y axis. - #[inline] - #[must_use] - pub fn from_rotation_y(angle: f32) -> Self { - glam::Quat::from_rotation_y(angle).into() - } - - /// Creates a quaternion from the `angle` (in radians) around the z axis. - #[inline] - #[must_use] - pub fn from_rotation_z(angle: f32) -> Self { - glam::Quat::from_rotation_z(angle).into() - } - - /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). - #[inline] - #[must_use] - pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self { - glam::Quat::from_euler(euler, a, b, c).into() - } - - /// Creates a quaternion from a 3x3 rotation matrix. - #[inline] - #[must_use] - pub fn from_mat3(mat: &Mat3) -> Self { - glam::Quat::from_mat3(mat).into() - } - - /// Creates a 3D rotation matrix from the given quaternion. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn to_mat3(self) -> Mat3 { - Mat3::from_quat(self.into()) - } - - /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix. - #[inline] - #[must_use] - pub fn from_mat3a(mat: &Mat3A) -> Self { - glam::Quat::from_mat3a(mat).into() - } - - /// Creates a 3D rotation matrix from the given quaternion. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn to_mat3a(self) -> Mat3A { - Mat3A::from_quat(self.into()) - } - - /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. - #[inline] - #[must_use] - pub fn from_mat4(mat: &Mat4) -> Self { - glam::Quat::from_mat4(mat).into() - } - - /// Creates an affine transformation matrix from the given `rotation` quaternion. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn to_mat4(self) -> Mat4 { - Mat4::from_quat(self.into()) - } - - /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and - /// `translation`. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn scale_rotation_translation_to_mat4(scale: Vec3, rotation: Quat, translation: Vec3) -> Mat4 { - Mat4::from_scale_rotation_translation(scale, rotation.into(), translation) - } - - /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is - /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant of `self` is zero or if the resulting scale vector - /// contains any zero elements when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn mat4_to_scale_rotation_translation(mat: Mat4) -> (Vec3, Quat, Vec3) { - let (scale, rotation, translation) = mat.to_scale_rotation_translation(); - (scale, rotation.into(), translation) - } - - /// Creates an affine transform from the given 3D `scale`, `rotation` and - /// `translation`. - /// - /// Equivalent to `Affine3A::from_translation(translation) * - /// Affine3A::from_quat(rotation) * Affine3A::from_scale(scale)` - #[inline] - #[must_use] - pub fn scale_rotation_translation_to_affine3a(scale: Vec3, rotation: Quat, translation: Vec3) -> Affine3A { - Affine3A::from_scale_rotation_translation( - scale, - rotation.into(), - translation, - ) - } - - /// Creates an affine transform from the given 3D `rotation` and `translation`. - /// - /// Equivalent to `Affine3A::from_translation(translation) * Affine3A::from_quat(rotation)` - #[inline] - #[must_use] - pub fn rotation_translation_to_affine3a(rotation: Quat, translation: Vec3) -> Affine3A { - Affine3A::from_rotation_translation(rotation.into(), translation) - } - - /// Extracts `scale`, `rotation` and `translation` from `self`. - /// - /// The transform is expected to be non-degenerate and without shearing, or the output - /// will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale - /// vector contains any zero elements when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn affine3a_to_scale_rotation_translation(affine: Affine3A) -> (Vec3, Quat, Vec3) { - let (scale, rotation, translation) = affine.to_scale_rotation_translation(); - (scale, rotation.into(), translation) - } - - /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the - /// plane spanned by the two vectors. Will rotate at most 180 degrees. - /// - /// The inputs must be unit vectors. - /// - /// `from_rotation_arc(from, to) * from ≈ to`. - /// - /// For near-singular cases (from≈to and from≈-to) the current implementation - /// is only accurate to about 0.001 (for `f32`). - /// - /// # Panics - /// - /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. - #[must_use] - pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self { - glam::Quat::from_rotation_arc(from, to).into() - } - - /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means - /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. - /// - /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 - /// degrees. - /// - /// The inputs must be unit vectors. - /// - /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. - /// - /// # Panics - /// - /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self { - glam::Quat::from_rotation_arc_colinear(from, to).into() - } - - /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is - /// around the z axis. Will rotate at most 180 degrees. - /// - /// The inputs must be unit vectors. - /// - /// `from_rotation_arc_2d(from, to) * from ≈ to`. - /// - /// For near-singular cases (from≈to and from≈-to) the current implementation - /// is only accurate to about 0.001 (for `f32`). - /// - /// # Panics - /// - /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. - #[must_use] - pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self { - glam::Quat::from_rotation_arc_2d(from, to).into() - } - - /// Returns the rotation axis (normalized) and angle (in radians) of `self`. - #[inline] - #[must_use] - pub fn to_axis_angle(self) -> (Vec3, f32) { - Into::::into(self).to_axis_angle() - } - - /// Returns the rotation axis scaled by the rotation in radians. - #[inline] - #[must_use] - pub fn to_scaled_axis(self) -> Vec3 { - Into::::into(self).to_scaled_axis() - } - - /// Returns the rotation angles for the given euler rotation sequence. - #[inline] - #[must_use] - pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) { - Into::::into(self).to_euler(euler) - } - - /// `[x, y, z, w]` - #[inline] - #[must_use] - pub fn to_array(&self) -> [f32; 4] { - Into::::into(*self).to_array() - } - - /// Returns the vector part of the quaternion. - #[inline] - #[must_use] - pub fn xyz(self) -> Vec3 { - Into::::into(self).xyz() - } - - /// Returns the quaternion conjugate of `self`. For a unit quaternion the - /// conjugate is also the inverse. - #[inline] - #[must_use] - pub fn conjugate(self) -> Self { - Into::::into(self).conjugate().into() - } - - /// Returns the inverse of a normalized quaternion. - /// - /// Typically quaternion inverse returns the conjugate of a normalized quaternion. - /// Because `self` is assumed to already be unit length this method *does not* normalize - /// before returning the conjugate. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn inverse(self) -> Self { - Into::::into(self).inverse().into() - } - - /// Computes the dot product of `self` and `rhs`. The dot product is - /// equal to the cosine of the angle between two quaternion rotations. - #[inline] - #[must_use] - pub fn dot(self, rhs: Self) -> f32 { - Into::::into(self).dot(Into::::into(rhs)) - } - - /// Computes the length of `self`. - #[doc(alias = "magnitude")] - #[inline] - #[must_use] - pub fn length(self) -> f32 { - Into::::into(self).length() - } - - /// Computes the squared length of `self`. - /// - /// This is generally faster than `length()` as it avoids a square - /// root operation. - #[doc(alias = "magnitude2")] - #[inline] - #[must_use] - pub fn length_squared(self) -> f32 { - Into::::into(self).length_squared() - } - - /// Computes `1.0 / length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - #[must_use] - pub fn length_recip(self) -> f32 { - Into::::into(self).length_recip() - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero. - /// - /// Panics - /// - /// Will panic if `self` is zero length when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn normalize(self) -> Self { - Into::::into(self).normalize().into() - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline] - #[must_use] - pub fn is_finite(self) -> bool { - Into::::into(self).is_finite() - } - - /// Returns a vector with elements representing the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - `NAN` if the number is `NAN` - #[inline] - #[must_use] - pub fn is_nan(self) -> bool { - Into::::into(self).is_nan() - } - - /// Returns whether `self` of length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline] - #[must_use] - pub fn is_normalized(self) -> bool { - Into::::into(self).is_normalized() - } - - /// Checks if the quaternion is near the identity rotation. - /// - /// # Details - /// - /// This function determines if the quaternion represents a rotation that is - /// very close to the identity rotation (no rotation). Due to floating point - /// precision limitations, very small rotations cannot be accurately represented. - /// - /// The threshold for considering a quaternion as near identity is set to - /// `0.0028471446` radians. This threshold is based on the closest value to - /// `1.0` that a `f32` can represent which is not `1.0` itself: - /// - /// ```text - /// 0.99999994.acos() * 2.0 = 0.000690533954 rad - /// ``` - /// - /// An error threshold of `1.e-6` is used by default: - /// - /// ```text - /// (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad - /// (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad - /// ``` - /// - /// The function calculates the angle based on the w-component of the quaternion - /// and compares it to the threshold. The absolute value of `quat.w` is taken - /// to ensure the shortest path is considered, as `quat.w` close to `-1.0` - /// would indicate a near 2*PI rotation, which is essentially a negative zero rotation. - /// - /// # Returns - /// - /// * `true` if the quaternion is near the identity rotation. - /// * `false` otherwise. - /// - /// # References - /// - /// This implementation is based on the algorithm from the [`rtm`](https://github.com/nfrechette/rtm) - /// library's `rtm::quat_near_identity` function. - #[inline] - #[must_use] - pub fn is_near_identity(self) -> bool { - Into::::into(self).is_near_identity() - } - - /// Returns the angle (in radians) for the minimal rotation - /// for transforming this quaternion into another. - /// - /// Both quaternions must be normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn angle_between(self, rhs: Self) -> f32 { - Into::::into(self).angle_between(Into::::into(rhs)) - } - - /// Returns true if the absolute difference of all elements between `self` and `rhs` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two quaternions contain similar elements. It works - /// best when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline] - #[must_use] - pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { - Into::::into(self).abs_diff_eq(Into::::into(rhs), max_abs_diff) - } - - /// Performs a linear interpolation between `self` and `rhs` based on - /// the value `s`. - /// - /// When `s` is `0.0`, the result will be equal to `self`. When `s` - /// is `1.0`, the result will be equal to `rhs`. - /// - /// # Panics - /// - /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. - #[doc(alias = "mix")] - #[inline] - #[must_use] - pub fn lerp(self, end: Self, s: f32) -> Self { - Into::::into(self).lerp(Into::::into(end), s).into() - } - - /// Performs a spherical linear interpolation between `self` and `end` - /// based on the value `s`. - /// - /// When `s` is `0.0`, the result will be equal to `self`. When `s` - /// is `1.0`, the result will be equal to `end`. - /// - /// # Panics - /// - /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - #[allow(unused_mut)] - pub fn slerp(self, mut end: Self, s: f32) -> Self { - Into::::into(self).slerp(end.into(), s).into() - } - - /// Multiplies a quaternion and a 3D vector, returning the rotated vector. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn mul_vec3(self, rhs: Vec3) -> Vec3 { - Into::::into(self).mul_vec3(rhs) - } - - /// Multiplies two quaternions. If they each represent a rotation, the result will - /// represent the combined rotation. - /// - /// Note that due to floating point rounding the result may not be perfectly normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. - #[inline] - #[must_use] - pub fn mul_quat(self, rhs: Self) -> Self { - Into::::into(self).mul_quat(Into::::into(rhs)).into() - } - - /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. - #[inline] - #[must_use] - pub fn from_affine3(a: &Affine3A) -> Self { - glam::Quat::from_affine3(a).into() - } - - /// Multiplies a quaternion and a 3D vector, returning the rotated vector. - #[inline] - #[must_use] - pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A { - Into::::into(self).mul_vec3a(rhs) - } - - /// Creates a new rotation quaternion. - /// - /// This should generally not be called manually unless you know what you are doing. - /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. - /// - /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline] - #[must_use] - pub fn as_dquat(self) -> DQuat { - Into::::into(self).as_dquat() - } -} - -impl Debug for Quat { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&Into::::into(*self), fmt) - } -} - -impl Display for Quat { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::Display::fmt(&Into::::into(*self), f) - } -} - -impl Add for Quat { - type Output = Self; - /// Adds two quaternions. - /// - /// The sum is not guaranteed to be normalized. - /// - /// Note that addition is not the same as combining the rotations represented by the - /// two quaternions! That corresponds to multiplication. - #[inline] - fn add(self, rhs: Self) -> Self { - Into::::into(self).add(Into::::into(rhs)).into() - } -} - -impl Sub for Quat { - type Output = Self; - /// Subtracts the `rhs` quaternion from `self`. - /// - /// The difference is not guaranteed to be normalized. - #[inline] - fn sub(self, rhs: Self) -> Self { - Into::::into(self).sub(Into::::into(rhs)).into() - } -} - -impl Mul for Quat { - type Output = Self; - /// Multiplies a quaternion by a scalar value. - /// - /// The product is not guaranteed to be normalized. - #[inline] - fn mul(self, rhs: f32) -> Self { - Into::::into(self).mul(rhs).into() - } -} - -impl Div for Quat { - type Output = Self; - /// Divides a quaternion by a scalar value. - /// The quotient is not guaranteed to be normalized. - #[inline] - fn div(self, rhs: f32) -> Self { - Into::::into(self).div(rhs).into() - } -} - -impl Mul for Quat { - type Output = Self; - /// Multiplies two quaternions. If they each represent a rotation, the result will - /// represent the combined rotation. - /// - /// Note that due to floating point rounding the result may not be perfectly - /// normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. - #[inline] - fn mul(self, rhs: Self) -> Self { - Into::::into(self).mul(Into::::into(rhs)).into() - } -} - -impl MulAssign for Quat { - /// Multiplies two quaternions. If they each represent a rotation, the result will - /// represent the combined rotation. - /// - /// Note that due to floating point rounding the result may not be perfectly - /// normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. - #[inline] - fn mul_assign(&mut self, rhs: Self) { - *self = Into::::into(*self).mul(Into::::into(rhs)).into() - } -} - -impl Mul for Quat { - type Output = Vec3; - /// Multiplies a quaternion and a 3D vector, returning the rotated vector. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline] - fn mul(self, rhs: Vec3) -> Self::Output { - self.mul_vec3(rhs) - } -} - -impl Neg for Quat { - type Output = Self; - #[inline] - fn neg(self) -> Self { - Into::::into(self).neg().into() - } -} - -impl Default for Quat { - #[inline] - fn default() -> Self { - glam::Quat::default().into() - } -} - -impl PartialEq for Quat { - #[inline] - fn eq(&self, rhs: &Self) -> bool { - Into::::into(*self) == Into::::into(*rhs) - } -} - -impl Sum for Quat { - fn sum(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::ZERO, Self::add) - } -} - -impl<'a> Sum<&'a Self> for Quat { - fn sum(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) - } -} - -impl Product for Quat { - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::IDENTITY, Self::mul) - } -} - -impl<'a> Product<&'a Self> for Quat { - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) - } -} - -impl Mul for Quat { - type Output = Vec3A; - #[inline] - fn mul(self, rhs: Vec3A) -> Self::Output { - self.mul_vec3a(rhs) - } -} - -impl From for Vec4 { - #[inline] - fn from(q: Quat) -> Self { - Into::::into(q).into() - } -} - -impl From for (f32, f32, f32, f32) { - #[inline] - fn from(q: Quat) -> Self { - Into::::into(q).into() - } -} - -impl From for [f32; 4] { - #[inline] - fn from(q: Quat) -> Self { - Into::::into(q).into() - } -} - -impl From for __m128 { - #[inline] - fn from(q: Quat) -> Self { - Into::::into(q).into() - } -} - -impl Into for QuatReprC { - fn into(self) -> glam::Quat { - glam::Quat::from_xyzw(self.x, self.y, self.z, self.w) - } -} - -#[cfg(feature = "repr_c")] -impl Into for QuatReprC { - fn into(self) -> Quat { - Quat { - inner: QuatReprC { - x: self.x, - y: self.y, - z: self.z, - w: self.w, - }, - } - } -} - -impl Into for glam::Quat { - fn into(self) -> Quat { - #[cfg(feature = "repr_c")] - let inner = QuatReprC { - x: self.x, - y: self.y, - z: self.z, - w: self.w, - }; - #[cfg(not(feature = "repr_c"))] - let inner = glam::Quat::from_xyzw(self.x, self.y, self.z, self.w); - Quat { - inner - } - } -} - -impl From for QuatReprC { - fn from(q: glam::Quat) -> Self { - QuatReprC { - x: q.x, - y: q.y, - z: q.z, - w: q.w, - } - } -} - -impl From for glam::Quat { - fn from(q: Quat) -> Self { - glam::Quat::from_xyzw(q.x, q.y, q.z, q.w) - } -} - -impl Default for QuatReprC { - fn default() -> Self { - glam::Quat::default().into() - } -} - -impl Deref for Quat { - #[cfg(feature = "repr_c")] - type Target = QuatReprC; - #[cfg(not(feature = "repr_c"))] - type Target = glam::Quat; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for Quat { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} \ No newline at end of file diff --git a/crates/bevy_math/src/sampling/standard.rs b/crates/bevy_math/src/sampling/standard.rs index 951b48279e429..1cda3f8ffc2e7 100644 --- a/crates/bevy_math/src/sampling/standard.rs +++ b/crates/bevy_math/src/sampling/standard.rs @@ -96,27 +96,4 @@ impl Distribution for Standard { } impl FromRng for Rot2 {} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Quat { - let u1 = rng.gen::(); - let u2 = rng.gen::(); - let u3 = rng.gen::(); - - let sq1 = (1.0 - u1).sqrt(); - let sq2 = u1.sqrt(); - - let theta1 = TAU * u2; - let theta2 = TAU * u3; - - let x = sq1 * theta1.cos(); - let y = sq1 * theta1.sin(); - let z = sq2 * theta2.cos(); - let w = sq2 * theta2.sin(); - - Quat::from_xyzw(x, y, z, w) - } -} - impl FromRng for Quat {} diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 12478d143b932..247aa49f504cc 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -332,7 +332,7 @@ pub fn build_directional_light_cascades( // users to not change any other aspects of the transform - there's no guarantee // `transform.compute_matrix()` will give us a matrix with our desired properties. // Instead, we directly create a good matrix from just the rotation. - let world_from_light = transform.compute_transform().rotation.to_mat4(); + let world_from_light = Mat4::from_quat(transform.compute_transform().rotation); let light_to_world_inverse = world_from_light.inverse(); for (view_entity, projection, view_to_world) in views.iter().copied() { diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index 8cdd32204f741..38f91c5ca8112 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -20,6 +20,8 @@ uuid = ["dep:uuid"] # When enabled, allows documentation comments to be accessed via reflection documentation = ["bevy_reflect_derive/documentation"] +repr_c = ["glam/scalar-math"] + [dependencies] # bevy bevy_reflect_derive = { path = "derive", version = "0.15.0-dev" } diff --git a/crates/bevy_reflect/src/impls/glam.rs b/crates/bevy_reflect/src/impls/glam.rs index 06823374b0c08..5d06eecc1e66b 100644 --- a/crates/bevy_reflect/src/impls/glam.rs +++ b/crates/bevy_reflect/src/impls/glam.rs @@ -332,4 +332,5 @@ impl_reflect!( impl_reflect_value!(::glam::EulerRot(Debug, Default)); impl_reflect_value!(::glam::BVec3A(Debug, Default)); +#[cfg(not(feature = "repr_c"))] impl_reflect_value!(::glam::BVec4A(Debug, Default)); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 6646945588273..f75771e47006d 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -699,7 +699,7 @@ pub fn prepare_sprite_image_bind_groups( quad_size = custom_size; } let transform = extracted_sprite.transform.affine() - * Quat::scale_rotation_translation_to_affine3a( + * Affine3A::from_scale_rotation_translation( quad_size.extend(1.0), Quat::IDENTITY, (quad_size * (-extracted_sprite.anchor - Vec2::splat(0.5))).extend(0.0) diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index 221e3ed3aa651..642d69971d82b 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -80,7 +80,7 @@ impl GlobalTransform { #[doc(hidden)] #[inline] pub fn from_rotation(rotation: Quat) -> Self { - GlobalTransform(Quat::rotation_translation_to_affine3a(rotation, Vec3::ZERO)) + GlobalTransform(Affine3A::from_rotation_translation(rotation, Vec3::ZERO)) } #[doc(hidden)] @@ -107,7 +107,7 @@ impl GlobalTransform { /// will be invalid. #[inline] pub fn compute_transform(&self) -> Transform { - let (scale, rotation, translation) = Quat::affine3a_to_scale_rotation_translation(self.0); + let (scale, rotation, translation) = self.0.to_scale_rotation_translation(); Transform { translation, rotation, @@ -151,7 +151,7 @@ impl GlobalTransform { #[inline] pub fn reparented_to(&self, parent: &GlobalTransform) -> Transform { let relative_affine = parent.affine().inverse() * self.affine(); - let (scale, rotation, translation) = Quat::affine3a_to_scale_rotation_translation(relative_affine); + let (scale, rotation, translation) = relative_affine.to_scale_rotation_translation(); Transform { translation, rotation, @@ -165,7 +165,7 @@ impl GlobalTransform { /// will be invalid. #[inline] pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) { - Quat::affine3a_to_scale_rotation_translation(self.0) + self.0.to_scale_rotation_translation() } impl_local_axis!(right, left, X); diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 248e3eacf39c1..575926b128370 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -82,7 +82,7 @@ impl Transform { /// transformation matrix. #[inline] pub fn from_matrix(world_from_local: Mat4) -> Self { - let (scale, rotation, translation) = Quat::mat4_to_scale_rotation_translation(world_from_local); + let (scale, rotation, translation) = world_from_local.to_scale_rotation_translation(); Transform { translation, rotation, @@ -209,14 +209,14 @@ impl Transform { /// rotation, and scale. #[inline] pub fn compute_matrix(&self) -> Mat4 { - Quat::scale_rotation_translation_to_mat4(self.scale, self.rotation, self.translation) + Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) } /// Returns the 3d affine transformation matrix from this transforms translation, /// rotation, and scale. #[inline] pub fn compute_affine(&self) -> Affine3A { - Quat::scale_rotation_translation_to_affine3a(self.scale, self.rotation, self.translation) + Affine3A::from_scale_rotation_translation(self.scale, self.rotation, self.translation) } /// Get the unit vector in the local `X` direction.