use crate::{
coresimd::*,
euler::{EulerRot, FromEuler, ToEuler},
f32::math,
DQuat, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4,
};
use core::simd::*;
use core::fmt;
use core::iter::{Product, Sum};
use core::ops::{
Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
};
#[inline]
#[must_use]
pub const fn quat(x: f32, y: f32, z: f32, w: f32) -> Quat {
Quat::from_xyzw(x, y, z, w)
}
#[derive(Clone, Copy)]
#[cfg_attr(
all(feature = "bytemuck", not(target_arch = "spirv")),
derive(bytemuck::Pod, bytemuck::Zeroable)
)]
#[repr(transparent)]
pub struct Quat(pub(crate) f32x4);
impl Quat {
const ZERO: Self = Self::from_array([0.0; 4]);
pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0);
pub const NAN: Self = Self::from_array([f32::NAN; 4]);
#[inline(always)]
#[must_use]
pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self {
Self(f32x4::from_array([x, y, z, w]))
}
#[inline]
#[must_use]
pub const fn from_array(a: [f32; 4]) -> Self {
Self(f32x4::from_array(a))
}
#[inline]
#[must_use]
pub const fn from_vec4(v: Vec4) -> Self {
Self(v.0)
}
#[inline]
#[must_use]
pub fn from_slice(slice: &[f32]) -> Self {
Self::from_xyzw(slice[0], slice[1], slice[2], slice[3])
}
#[inline]
pub fn write_to_slice(self, slice: &mut [f32]) {
slice[0] = self.x;
slice[1] = self.y;
slice[2] = self.z;
slice[3] = self.w;
}
#[inline]
#[must_use]
pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
glam_assert!(axis.is_normalized());
let (s, c) = math::sin_cos(angle * 0.5);
let v = axis * s;
Self::from_xyzw(v.x, v.y, v.z, c)
}
#[inline]
#[must_use]
pub fn from_scaled_axis(v: Vec3) -> Self {
let length = v.length();
if length == 0.0 {
Self::IDENTITY
} else {
Self::from_axis_angle(v / length, length)
}
}
#[inline]
#[must_use]
pub fn from_rotation_x(angle: f32) -> Self {
let (s, c) = math::sin_cos(angle * 0.5);
Self::from_xyzw(s, 0.0, 0.0, c)
}
#[inline]
#[must_use]
pub fn from_rotation_y(angle: f32) -> Self {
let (s, c) = math::sin_cos(angle * 0.5);
Self::from_xyzw(0.0, s, 0.0, c)
}
#[inline]
#[must_use]
pub fn from_rotation_z(angle: f32) -> Self {
let (s, c) = math::sin_cos(angle * 0.5);
Self::from_xyzw(0.0, 0.0, s, c)
}
#[inline]
#[must_use]
pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self {
Self::from_euler_angles(euler, a, b, c)
}
#[inline]
#[must_use]
pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
let (m00, m01, m02) = x_axis.into();
let (m10, m11, m12) = y_axis.into();
let (m20, m21, m22) = z_axis.into();
if m22 <= 0.0 {
let dif10 = m11 - m00;
let omm22 = 1.0 - m22;
if dif10 <= 0.0 {
let four_xsq = omm22 - dif10;
let inv4x = 0.5 / math::sqrt(four_xsq);
Self::from_xyzw(
four_xsq * inv4x,
(m01 + m10) * inv4x,
(m02 + m20) * inv4x,
(m12 - m21) * inv4x,
)
} else {
let four_ysq = omm22 + dif10;
let inv4y = 0.5 / math::sqrt(four_ysq);
Self::from_xyzw(
(m01 + m10) * inv4y,
four_ysq * inv4y,
(m12 + m21) * inv4y,
(m20 - m02) * inv4y,
)
}
} else {
let sum10 = m11 + m00;
let opm22 = 1.0 + m22;
if sum10 <= 0.0 {
let four_zsq = opm22 - sum10;
let inv4z = 0.5 / math::sqrt(four_zsq);
Self::from_xyzw(
(m02 + m20) * inv4z,
(m12 + m21) * inv4z,
four_zsq * inv4z,
(m01 - m10) * inv4z,
)
} else {
let four_wsq = opm22 + sum10;
let inv4w = 0.5 / math::sqrt(four_wsq);
Self::from_xyzw(
(m12 - m21) * inv4w,
(m20 - m02) * inv4w,
(m01 - m10) * inv4w,
four_wsq * inv4w,
)
}
}
}
#[inline]
#[must_use]
pub fn from_mat3(mat: &Mat3) -> Self {
Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis)
}
#[inline]
#[must_use]
pub fn from_mat3a(mat: &Mat3A) -> Self {
Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
}
#[inline]
#[must_use]
pub fn from_mat4(mat: &Mat4) -> Self {
Self::from_rotation_axes(
mat.x_axis.truncate(),
mat.y_axis.truncate(),
mat.z_axis.truncate(),
)
}
#[must_use]
pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self {
glam_assert!(from.is_normalized());
glam_assert!(to.is_normalized());
const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * f32::EPSILON;
let dot = from.dot(to);
if dot > ONE_MINUS_EPS {
Self::IDENTITY
} else if dot < -ONE_MINUS_EPS {
use core::f32::consts::PI; Self::from_axis_angle(from.any_orthonormal_vector(), PI)
} else {
let c = from.cross(to);
Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize()
}
}
#[inline]
#[must_use]
pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self {
if from.dot(to) < 0.0 {
Self::from_rotation_arc(from, -to)
} else {
Self::from_rotation_arc(from, to)
}
}
#[must_use]
pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self {
glam_assert!(from.is_normalized());
glam_assert!(to.is_normalized());
const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * f32::EPSILON;
let dot = from.dot(to);
if dot > ONE_MINUS_EPSILON {
Self::IDENTITY
} else if dot < -ONE_MINUS_EPSILON {
const COS_FRAC_PI_2: f32 = 0.0;
const SIN_FRAC_PI_2: f32 = 1.0;
Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2)
} else {
let z = from.x * to.y - to.x * from.y;
let w = 1.0 + dot;
let len_rcp = 1.0 / math::sqrt(z * z + w * w);
Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp)
}
}
#[inline]
#[must_use]
pub fn look_to_lh(dir: Vec3, up: Vec3) -> Self {
Self::look_to_rh(-dir, up)
}
#[inline]
#[must_use]
pub fn look_to_rh(dir: Vec3, up: Vec3) -> Self {
glam_assert!(dir.is_normalized());
glam_assert!(up.is_normalized());
let f = dir;
let s = f.cross(up).normalize();
let u = s.cross(f);
Self::from_rotation_axes(
Vec3::new(s.x, u.x, -f.x),
Vec3::new(s.y, u.y, -f.y),
Vec3::new(s.z, u.z, -f.z),
)
}
#[inline]
#[must_use]
pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
Self::look_to_lh(center.sub(eye).normalize(), up)
}
#[inline]
#[must_use]
pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
Self::look_to_rh(center.sub(eye).normalize(), up)
}
#[inline]
#[must_use]
pub fn to_axis_angle(self) -> (Vec3, f32) {
const EPSILON: f32 = 1.0e-8;
let v = Vec3::new(self.x, self.y, self.z);
let length = v.length();
if length >= EPSILON {
let angle = 2.0 * math::atan2(length, self.w);
let axis = v / length;
(axis, angle)
} else {
(Vec3::X, 0.0)
}
}
#[inline]
#[must_use]
pub fn to_scaled_axis(self) -> Vec3 {
let (axis, angle) = self.to_axis_angle();
axis * angle
}
#[inline]
#[must_use]
pub fn to_euler(self, order: EulerRot) -> (f32, f32, f32) {
self.to_euler_angles(order)
}
#[inline]
#[must_use]
pub fn to_array(&self) -> [f32; 4] {
[self.x, self.y, self.z, self.w]
}
#[inline]
#[must_use]
pub fn xyz(self) -> Vec3 {
Vec3::new(self.x, self.y, self.z)
}
#[inline]
#[must_use]
pub fn conjugate(self) -> Self {
const SIGN: f32x4 = f32x4::from_array([-1.0, -1.0, -1.0, 1.0]);
Self(self.0.mul(SIGN))
}
#[inline]
#[must_use]
pub fn inverse(self) -> Self {
glam_assert!(self.is_normalized());
self.conjugate()
}
#[inline]
#[must_use]
pub fn dot(self, rhs: Self) -> f32 {
Vec4::from(self).dot(Vec4::from(rhs))
}
#[doc(alias = "magnitude")]
#[inline]
#[must_use]
pub fn length(self) -> f32 {
Vec4::from(self).length()
}
#[doc(alias = "magnitude2")]
#[inline]
#[must_use]
pub fn length_squared(self) -> f32 {
Vec4::from(self).length_squared()
}
#[inline]
#[must_use]
pub fn length_recip(self) -> f32 {
Vec4::from(self).length_recip()
}
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Self::from_vec4(Vec4::from(self).normalize())
}
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
Vec4::from(self).is_finite()
}
#[inline]
#[must_use]
pub fn is_nan(self) -> bool {
Vec4::from(self).is_nan()
}
#[inline]
#[must_use]
pub fn is_normalized(self) -> bool {
Vec4::from(self).is_normalized()
}
#[inline]
#[must_use]
pub fn is_near_identity(self) -> bool {
let threshold_angle = 0.002_847_144_6;
let positive_w_angle = math::acos_approx(math::abs(self.w)) * 2.0;
positive_w_angle < threshold_angle
}
#[inline]
#[must_use]
pub fn angle_between(self, rhs: Self) -> f32 {
glam_assert!(self.is_normalized() && rhs.is_normalized());
math::acos_approx(math::abs(self.dot(rhs))) * 2.0
}
#[inline]
#[must_use]
pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
glam_assert!(self.is_normalized() && rhs.is_normalized());
let angle = self.angle_between(rhs);
if angle <= 1e-4 {
return rhs;
}
let s = (max_angle / angle).clamp(-1.0, 1.0);
self.slerp(rhs, s)
}
#[inline]
#[must_use]
pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff)
}
#[inline(always)]
#[must_use]
fn lerp_impl(self, end: Self, s: f32) -> Self {
(self * (1.0 - s) + end * s).normalize()
}
#[doc(alias = "mix")]
#[inline]
#[must_use]
pub fn lerp(self, end: Self, s: f32) -> Self {
glam_assert!(self.is_normalized());
glam_assert!(end.is_normalized());
const NEG_ZERO: f32x4 = f32x4::from_array([-0.0; 4]);
let dot = dot4_into_f32x4(self.0, end.0);
let bias = f32x4_bitand(dot, NEG_ZERO);
self.lerp_impl(Self(f32x4_bitxor(end.0, bias)), s)
}
#[inline]
#[must_use]
pub fn slerp(self, mut end: Self, s: f32) -> Self {
glam_assert!(self.is_normalized());
glam_assert!(end.is_normalized());
let mut dot = self.dot(end);
if dot < 0.0 {
end = -end;
dot = -dot;
}
const DOT_THRESHOLD: f32 = 1.0 - f32::EPSILON;
if dot > DOT_THRESHOLD {
self.lerp_impl(end, s)
} else {
let theta = math::acos_approx(dot);
let scale1 = math::sin(theta * (1.0 - s));
let scale2 = math::sin(theta * s);
let theta_sin = math::sin(theta);
((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
}
}
#[inline]
#[must_use]
pub fn mul_vec3(self, rhs: Vec3) -> Vec3 {
glam_assert!(self.is_normalized());
self.mul_vec3a(rhs.into()).into()
}
#[inline]
#[must_use]
pub fn mul_quat(self, rhs: Self) -> Self {
let lhs = self.0;
let rhs = rhs.0;
const CONTROL_WZYX: f32x4 = f32x4::from_array([1.0, -1.0, 1.0, -1.0]);
const CONTROL_ZWXY: f32x4 = f32x4::from_array([1.0, 1.0, -1.0, -1.0]);
const CONTROL_YXWZ: f32x4 = f32x4::from_array([-1.0, 1.0, 1.0, -1.0]);
let r_xxxx = simd_swizzle!(lhs, [0, 0, 0, 0]);
let r_yyyy = simd_swizzle!(lhs, [1, 1, 1, 1]);
let r_zzzz = simd_swizzle!(lhs, [2, 2, 2, 2]);
let r_wwww = simd_swizzle!(lhs, [3, 3, 3, 3]);
let lxrw_lyrw_lzrw_lwrw = r_wwww * rhs;
let l_wzyx = simd_swizzle!(rhs, [3, 2, 1, 0]);
let lwrx_lzrx_lyrx_lxrx = r_xxxx * l_wzyx;
let l_zwxy = simd_swizzle!(l_wzyx, [1, 0, 3, 2]);
let lwrx_nlzrx_lyrx_nlxrx = lwrx_lzrx_lyrx_lxrx * CONTROL_WZYX;
let lzry_lwry_lxry_lyry = r_yyyy * l_zwxy;
let l_yxwz = simd_swizzle!(l_zwxy, [3, 2, 1, 0]);
let lzry_lwry_nlxry_nlyry = lzry_lwry_lxry_lyry * CONTROL_ZWXY;
let lyrz_lxrz_lwrz_lzrz = r_zzzz * l_yxwz;
let result0 = lxrw_lyrw_lzrw_lwrw + lwrx_nlzrx_lyrx_nlxrx;
let nlyrz_lxrz_lwrz_wlzrz = lyrz_lxrz_lwrz_lzrz * CONTROL_YXWZ;
let result1 = lzry_lwry_nlxry_nlyry + nlyrz_lxrz_lwrz_wlzrz;
Self(result0 + result1)
}
#[inline]
#[must_use]
pub fn from_affine3(a: &crate::Affine3A) -> Self {
#[allow(clippy::useless_conversion)]
Self::from_rotation_axes(
a.matrix3.x_axis.into(),
a.matrix3.y_axis.into(),
a.matrix3.z_axis.into(),
)
}
#[inline]
#[must_use]
pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A {
const TWO: f32x4 = f32x4::from_array([2.0; 4]);
let w = simd_swizzle!(self.0, [3, 3, 3, 3]);
let b = self.0;
let b2 = dot3_into_f32x4(b, b);
Vec3A(
rhs.0
.mul(w.mul(w).sub(b2))
.add(b.mul(dot3_into_f32x4(rhs.0, b).mul(TWO)))
.add(Vec3A(b).cross(rhs).0.mul(w.mul(TWO))),
)
}
#[inline]
#[must_use]
pub fn as_dquat(self) -> DQuat {
DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
}
}
impl fmt::Debug for Quat {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple(stringify!(Quat))
.field(&self.x)
.field(&self.y)
.field(&self.z)
.field(&self.w)
.finish()
}
}
impl fmt::Display for Quat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(p) = f.precision() {
write!(
f,
"[{:.*}, {:.*}, {:.*}, {:.*}]",
p, self.x, p, self.y, p, self.z, p, self.w
)
} else {
write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
}
}
}
impl Add for Quat {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::from_vec4(Vec4::from(self) + Vec4::from(rhs))
}
}
impl Add<&Self> for Quat {
type Output = Self;
#[inline]
fn add(self, rhs: &Self) -> Self {
self.add(*rhs)
}
}
impl Add<&Quat> for &Quat {
type Output = Quat;
#[inline]
fn add(self, rhs: &Quat) -> Quat {
(*self).add(*rhs)
}
}
impl Add<Quat> for &Quat {
type Output = Quat;
#[inline]
fn add(self, rhs: Quat) -> Quat {
(*self).add(rhs)
}
}
impl AddAssign for Quat {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = self.add(rhs);
}
}
impl AddAssign<&Self> for Quat {
#[inline]
fn add_assign(&mut self, rhs: &Self) {
self.add_assign(*rhs);
}
}
impl Sub for Quat {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::from_vec4(Vec4::from(self) - Vec4::from(rhs))
}
}
impl Sub<&Self> for Quat {
type Output = Self;
#[inline]
fn sub(self, rhs: &Self) -> Self {
self.sub(*rhs)
}
}
impl Sub<&Quat> for &Quat {
type Output = Quat;
#[inline]
fn sub(self, rhs: &Quat) -> Quat {
(*self).sub(*rhs)
}
}
impl Sub<Quat> for &Quat {
type Output = Quat;
#[inline]
fn sub(self, rhs: Quat) -> Quat {
(*self).sub(rhs)
}
}
impl SubAssign for Quat {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = self.sub(rhs);
}
}
impl SubAssign<&Self> for Quat {
#[inline]
fn sub_assign(&mut self, rhs: &Self) {
self.sub_assign(*rhs);
}
}
impl Mul<f32> for Quat {
type Output = Self;
#[inline]
fn mul(self, rhs: f32) -> Self {
Self::from_vec4(Vec4::from(self) * rhs)
}
}
impl Mul<&f32> for Quat {
type Output = Self;
#[inline]
fn mul(self, rhs: &f32) -> Self {
self.mul(*rhs)
}
}
impl Mul<&f32> for &Quat {
type Output = Quat;
#[inline]
fn mul(self, rhs: &f32) -> Quat {
(*self).mul(*rhs)
}
}
impl Mul<f32> for &Quat {
type Output = Quat;
#[inline]
fn mul(self, rhs: f32) -> Quat {
(*self).mul(rhs)
}
}
impl MulAssign<f32> for Quat {
#[inline]
fn mul_assign(&mut self, rhs: f32) {
*self = self.mul(rhs);
}
}
impl MulAssign<&f32> for Quat {
#[inline]
fn mul_assign(&mut self, rhs: &f32) {
self.mul_assign(*rhs);
}
}
impl Div<f32> for Quat {
type Output = Self;
#[inline]
fn div(self, rhs: f32) -> Self {
Self::from_vec4(Vec4::from(self) / rhs)
}
}
impl Div<&f32> for Quat {
type Output = Self;
#[inline]
fn div(self, rhs: &f32) -> Self {
self.div(*rhs)
}
}
impl Div<&f32> for &Quat {
type Output = Quat;
#[inline]
fn div(self, rhs: &f32) -> Quat {
(*self).div(*rhs)
}
}
impl Div<f32> for &Quat {
type Output = Quat;
#[inline]
fn div(self, rhs: f32) -> Quat {
(*self).div(rhs)
}
}
impl DivAssign<f32> for Quat {
#[inline]
fn div_assign(&mut self, rhs: f32) {
*self = self.div(rhs);
}
}
impl DivAssign<&f32> for Quat {
#[inline]
fn div_assign(&mut self, rhs: &f32) {
self.div_assign(*rhs);
}
}
impl Mul for Quat {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
self.mul_quat(rhs)
}
}
impl Mul<&Self> for Quat {
type Output = Self;
#[inline]
fn mul(self, rhs: &Self) -> Self {
self.mul(*rhs)
}
}
impl Mul<&Quat> for &Quat {
type Output = Quat;
#[inline]
fn mul(self, rhs: &Quat) -> Quat {
(*self).mul(*rhs)
}
}
impl Mul<Quat> for &Quat {
type Output = Quat;
#[inline]
fn mul(self, rhs: Quat) -> Quat {
(*self).mul(rhs)
}
}
impl MulAssign for Quat {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = self.mul(rhs);
}
}
impl MulAssign<&Self> for Quat {
#[inline]
fn mul_assign(&mut self, rhs: &Self) {
self.mul_assign(*rhs);
}
}
impl Mul<Vec3> for Quat {
type Output = Vec3;
#[inline]
fn mul(self, rhs: Vec3) -> Self::Output {
self.mul_vec3(rhs)
}
}
impl Mul<&Vec3> for Quat {
type Output = Vec3;
#[inline]
fn mul(self, rhs: &Vec3) -> Vec3 {
self.mul(*rhs)
}
}
impl Mul<&Vec3> for &Quat {
type Output = Vec3;
#[inline]
fn mul(self, rhs: &Vec3) -> Vec3 {
(*self).mul(*rhs)
}
}
impl Mul<Vec3> for &Quat {
type Output = Vec3;
#[inline]
fn mul(self, rhs: Vec3) -> Vec3 {
(*self).mul(rhs)
}
}
impl Mul<Vec3A> for Quat {
type Output = Vec3A;
#[inline]
fn mul(self, rhs: Vec3A) -> Self::Output {
self.mul_vec3a(rhs)
}
}
impl Mul<&Vec3A> for Quat {
type Output = Vec3A;
#[inline]
fn mul(self, rhs: &Vec3A) -> Vec3A {
self.mul(*rhs)
}
}
impl Mul<&Vec3A> for &Quat {
type Output = Vec3A;
#[inline]
fn mul(self, rhs: &Vec3A) -> Vec3A {
(*self).mul(*rhs)
}
}
impl Mul<Vec3A> for &Quat {
type Output = Vec3A;
#[inline]
fn mul(self, rhs: Vec3A) -> Vec3A {
(*self).mul(rhs)
}
}
impl Neg for Quat {
type Output = Self;
#[inline]
fn neg(self) -> Self {
self * -1.0
}
}
impl Neg for &Quat {
type Output = Quat;
#[inline]
fn neg(self) -> Quat {
(*self).neg()
}
}
impl Default for Quat {
#[inline]
fn default() -> Self {
Self::IDENTITY
}
}
impl PartialEq for Quat {
#[inline]
fn eq(&self, rhs: &Self) -> bool {
Vec4::from(*self).eq(&Vec4::from(*rhs))
}
}
#[cfg(not(target_arch = "spirv"))]
impl AsRef<[f32; 4]> for Quat {
#[inline]
fn as_ref(&self) -> &[f32; 4] {
unsafe { &*(self as *const Self as *const [f32; 4]) }
}
}
impl Sum<Self> for Quat {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
iter.fold(Self::ZERO, Self::add)
}
}
impl<'a> Sum<&'a Self> for Quat {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
}
}
impl Product for Quat {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
iter.fold(Self::IDENTITY, Self::mul)
}
}
impl<'a> Product<&'a Self> for Quat {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
}
}
impl From<Quat> for Vec4 {
#[inline]
fn from(q: Quat) -> Self {
Self(q.0)
}
}
impl From<Quat> for (f32, f32, f32, f32) {
#[inline]
fn from(q: Quat) -> Self {
Vec4::from(q).into()
}
}
impl From<Quat> for [f32; 4] {
#[inline]
fn from(q: Quat) -> Self {
Vec4::from(q).into()
}
}
impl From<Quat> for f32x4 {
#[inline]
fn from(q: Quat) -> Self {
q.0
}
}
impl Deref for Quat {
type Target = crate::deref::Vec4<f32>;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self).cast() }
}
}
impl DerefMut for Quat {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self as *mut Self).cast() }
}
}