use crate::core::{
storage::{Columns4, XYZW},
traits::{
matrix::{FloatMatrix4x4, Matrix4x4, MatrixConst},
projection::ProjectionMatrix,
},
};
use crate::{DMat3, DQuat, DVec3, DVec4, EulerRot, Mat3, Quat, Vec3, Vec3A, Vec4};
#[cfg(all(
target_feature = "sse2",
not(feature = "scalar-math"),
target_arch = "x86"
))]
use core::arch::x86::*;
#[cfg(all(
target_feature = "sse2",
not(feature = "scalar-math"),
target_arch = "x86_64"
))]
use core::arch::x86_64::*;
#[cfg(target_feature = "simd128")]
use core::arch::wasm32::v128;
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::iter::{Product, Sum};
use core::ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Sub, SubAssign};
macro_rules! impl_mat4_methods {
($t:ident, $vec4:ident, $vec3:ident, $mat3:ident, $quat:ident, $inner:ident) => {
pub const ZERO: Self = Self($inner::ZERO);
pub const IDENTITY: Self = Self($inner::IDENTITY);
pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN);
#[inline(always)]
pub fn from_cols(x_axis: $vec4, y_axis: $vec4, z_axis: $vec4, w_axis: $vec4) -> Self {
Self($inner::from_cols(x_axis.0, y_axis.0, z_axis.0, w_axis.0))
}
#[inline(always)]
pub fn from_cols_array(m: &[$t; 16]) -> Self {
Self($inner::from_cols_array(m))
}
#[inline(always)]
pub fn to_cols_array(&self) -> [$t; 16] {
self.0.to_cols_array()
}
#[inline(always)]
pub fn from_cols_array_2d(m: &[[$t; 4]; 4]) -> Self {
Self($inner::from_cols_array_2d(m))
}
#[inline(always)]
pub fn to_cols_array_2d(&self) -> [[$t; 4]; 4] {
self.0.to_cols_array_2d()
}
#[doc(alias = "scale")]
#[inline(always)]
pub fn from_diagonal(diagonal: $vec4) -> Self {
Self($inner::from_diagonal(diagonal.0.into()))
}
#[inline(always)]
pub fn from_scale_rotation_translation(
scale: $vec3,
rotation: $quat,
translation: $vec3,
) -> Self {
Self($inner::from_scale_quaternion_translation(
scale.0,
rotation.0,
translation.0,
))
}
#[inline(always)]
pub fn from_rotation_translation(rotation: $quat, translation: $vec3) -> Self {
Self($inner::from_quaternion_translation(
rotation.0,
translation.0,
))
}
#[inline(always)]
pub fn to_scale_rotation_translation(&self) -> ($vec3, $quat, $vec3) {
let (scale, rotation, translation) = self.0.to_scale_quaternion_translation();
($vec3(scale), $quat(rotation), $vec3(translation))
}
#[inline(always)]
pub fn from_quat(rotation: $quat) -> Self {
Self($inner::from_quaternion(rotation.0))
}
#[inline(always)]
pub fn from_mat3(m: $mat3) -> Self {
Self::from_cols(
(m.x_axis, 0.0).into(),
(m.y_axis, 0.0).into(),
(m.z_axis, 0.0).into(),
$vec4::W,
)
}
#[inline(always)]
pub fn from_translation(translation: $vec3) -> Self {
Self($inner::from_translation(translation.0))
}
#[inline(always)]
pub fn from_axis_angle(axis: $vec3, angle: $t) -> Self {
Self($inner::from_axis_angle(axis.0, angle))
}
#[inline(always)]
pub fn from_euler(order: EulerRot, a: $t, b: $t, c: $t) -> Self {
let quat = $quat::from_euler(order, a, b, c);
Self::from_quat(quat)
}
#[inline(always)]
pub fn from_rotation_x(angle: $t) -> Self {
Self($inner::from_rotation_x(angle))
}
#[inline(always)]
pub fn from_rotation_y(angle: $t) -> Self {
Self($inner::from_rotation_y(angle))
}
#[inline(always)]
pub fn from_rotation_z(angle: $t) -> Self {
Self($inner::from_rotation_z(angle))
}
#[inline(always)]
pub fn from_scale(scale: $vec3) -> Self {
Self($inner::from_scale(scale.0))
}
#[inline(always)]
pub fn from_cols_slice(slice: &[$t]) -> Self {
Self(Matrix4x4::from_cols_slice(slice))
}
#[inline(always)]
pub fn write_cols_to_slice(self, slice: &mut [$t]) {
Matrix4x4::write_cols_to_slice(&self.0, slice)
}
#[inline]
pub fn col(&self, index: usize) -> $vec4 {
match index {
0 => self.x_axis,
1 => self.y_axis,
2 => self.z_axis,
3 => self.w_axis,
_ => panic!("index out of bounds"),
}
}
#[inline]
pub fn col_mut(&mut self, index: usize) -> &mut $vec4 {
match index {
0 => &mut self.x_axis,
1 => &mut self.y_axis,
2 => &mut self.z_axis,
3 => &mut self.w_axis,
_ => panic!("index out of bounds"),
}
}
#[inline]
pub fn row(&self, index: usize) -> $vec4 {
match index {
0 => $vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
1 => $vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
2 => $vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
3 => $vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
_ => panic!("index out of bounds"),
}
}
#[inline]
pub fn is_finite(&self) -> bool {
self.x_axis.is_finite()
&& self.y_axis.is_finite()
&& self.z_axis.is_finite()
&& self.w_axis.is_finite()
}
#[inline]
pub fn is_nan(&self) -> bool {
self.x_axis.is_nan()
|| self.y_axis.is_nan()
|| self.z_axis.is_nan()
|| self.w_axis.is_nan()
}
#[must_use]
#[inline(always)]
pub fn transpose(&self) -> Self {
Self(self.0.transpose())
}
#[inline(always)]
pub fn determinant(&self) -> $t {
self.0.determinant()
}
#[must_use]
#[inline(always)]
pub fn inverse(&self) -> Self {
Self(self.0.inverse())
}
#[inline(always)]
pub fn look_at_lh(eye: $vec3, center: $vec3, up: $vec3) -> Self {
Self($inner::look_at_lh(eye.0, center.0, up.0))
}
#[inline(always)]
pub fn look_at_rh(eye: $vec3, center: $vec3, up: $vec3) -> Self {
Self($inner::look_at_rh(eye.0, center.0, up.0))
}
#[inline(always)]
pub fn perspective_rh_gl(
fov_y_radians: $t,
aspect_ratio: $t,
z_near: $t,
z_far: $t,
) -> Self {
Self($inner::perspective_rh_gl(
fov_y_radians,
aspect_ratio,
z_near,
z_far,
))
}
#[inline(always)]
pub fn perspective_lh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t, z_far: $t) -> Self {
Self($inner::perspective_lh(
fov_y_radians,
aspect_ratio,
z_near,
z_far,
))
}
#[inline(always)]
pub fn perspective_rh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t, z_far: $t) -> Self {
Self($inner::perspective_rh(
fov_y_radians,
aspect_ratio,
z_near,
z_far,
))
}
#[inline(always)]
pub fn perspective_infinite_lh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t) -> Self {
Self($inner::perspective_infinite_lh(
fov_y_radians,
aspect_ratio,
z_near,
))
}
#[inline(always)]
pub fn perspective_infinite_reverse_lh(
fov_y_radians: $t,
aspect_ratio: $t,
z_near: $t,
) -> Self {
Self($inner::perspective_infinite_reverse_lh(
fov_y_radians,
aspect_ratio,
z_near,
))
}
#[inline(always)]
pub fn perspective_infinite_rh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t) -> Self {
Self($inner::perspective_infinite_rh(
fov_y_radians,
aspect_ratio,
z_near,
))
}
#[inline(always)]
pub fn perspective_infinite_reverse_rh(
fov_y_radians: $t,
aspect_ratio: $t,
z_near: $t,
) -> Self {
Self($inner::perspective_infinite_reverse_rh(
fov_y_radians,
aspect_ratio,
z_near,
))
}
#[inline(always)]
pub fn orthographic_rh_gl(
left: $t,
right: $t,
bottom: $t,
top: $t,
near: $t,
far: $t,
) -> Self {
Self($inner::orthographic_rh_gl(
left, right, bottom, top, near, far,
))
}
#[inline(always)]
pub fn orthographic_lh(
left: $t,
right: $t,
bottom: $t,
top: $t,
near: $t,
far: $t,
) -> Self {
Self($inner::orthographic_lh(left, right, bottom, top, near, far))
}
#[inline(always)]
pub fn orthographic_rh(
left: $t,
right: $t,
bottom: $t,
top: $t,
near: $t,
far: $t,
) -> Self {
Self($inner::orthographic_rh(left, right, bottom, top, near, far))
}
#[inline(always)]
pub fn mul_vec4(&self, other: $vec4) -> $vec4 {
$vec4(self.0.mul_vector(other.0))
}
#[inline(always)]
pub fn mul_mat4(&self, other: &Self) -> Self {
Self(self.0.mul_matrix(&other.0))
}
#[inline(always)]
pub fn add_mat4(&self, other: &Self) -> Self {
Self(self.0.add_matrix(&other.0))
}
#[inline(always)]
pub fn sub_mat4(&self, other: &Self) -> Self {
Self(self.0.sub_matrix(&other.0))
}
#[inline(always)]
pub fn mul_scalar(&self, other: $t) -> Self {
Self(self.0.mul_scalar(other))
}
#[inline]
pub fn project_point3(&self, other: $vec3) -> $vec3 {
$vec3(self.0.project_point3(other.0))
}
#[inline]
pub fn transform_point3(&self, other: $vec3) -> $vec3 {
glam_assert!(self.row(3) == $vec4::W);
$vec3(self.0.transform_point3(other.0))
}
#[inline]
pub fn transform_vector3(&self, other: $vec3) -> $vec3 {
glam_assert!(self.row(3) == $vec4::W);
$vec3(self.0.transform_vector3(other.0))
}
#[inline(always)]
pub fn abs_diff_eq(&self, other: Self, max_abs_diff: $t) -> bool {
self.0.abs_diff_eq(&other.0, max_abs_diff)
}
};
}
macro_rules! impl_mat4_traits {
($t:ty, $new:ident, $mat4:ident, $vec4:ident) => {
#[inline(always)]
pub fn $new(x_axis: $vec4, y_axis: $vec4, z_axis: $vec4, w_axis: $vec4) -> $mat4 {
$mat4::from_cols(x_axis, y_axis, z_axis, w_axis)
}
impl_matn_common_traits!($t, $mat4, $vec4);
impl Deref for $mat4 {
type Target = Columns4<$vec4>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self as *const Self::Target) }
}
}
impl DerefMut for $mat4 {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self as *mut Self as *mut Self::Target) }
}
}
impl PartialEq for $mat4 {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.x_axis.eq(&other.x_axis)
&& self.y_axis.eq(&other.y_axis)
&& self.z_axis.eq(&other.z_axis)
&& self.w_axis.eq(&other.w_axis)
}
}
#[cfg(not(target_arch = "spriv"))]
impl AsRef<[$t; 16]> for $mat4 {
#[inline]
fn as_ref(&self) -> &[$t; 16] {
unsafe { &*(self as *const Self as *const [$t; 16]) }
}
}
#[cfg(not(target_arch = "spriv"))]
impl AsMut<[$t; 16]> for $mat4 {
#[inline]
fn as_mut(&mut self) -> &mut [$t; 16] {
unsafe { &mut *(self as *mut Self as *mut [$t; 16]) }
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for $mat4 {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(stringify!($mat4))
.field("x_axis", &self.x_axis)
.field("y_axis", &self.y_axis)
.field("z_axis", &self.z_axis)
.field("w_axis", &self.w_axis)
.finish()
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for $mat4 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"[{}, {}, {}, {}]",
self.x_axis, self.y_axis, self.z_axis, self.w_axis
)
}
}
};
}
#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
type InnerF32 = Columns4<__m128>;
#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))]
type InnerF32 = Columns4<v128>;
#[cfg(any(
not(any(target_feature = "sse2", target_feature = "simd128")),
feature = "scalar-math"
))]
type InnerF32 = Columns4<XYZW<f32>>;
#[derive(Clone, Copy)]
#[cfg_attr(
not(any(feature = "scalar-math", target_arch = "spriv")),
repr(align(16))
)]
#[cfg_attr(any(feature = "scalar-math", target_arch = "spriv"), repr(transparent))]
pub struct Mat4(pub(crate) InnerF32);
impl Mat4 {
impl_mat4_methods!(f32, Vec4, Vec3, Mat3, Quat, InnerF32);
#[inline(always)]
pub fn transform_point3a(&self, other: Vec3A) -> Vec3A {
#[allow(clippy::useless_conversion)]
Vec3A(self.0.transform_float4_as_point3(other.0.into()).into())
}
#[inline(always)]
pub fn transform_vector3a(&self, other: Vec3A) -> Vec3A {
#[allow(clippy::useless_conversion)]
Vec3A(self.0.transform_float4_as_vector3(other.0.into()).into())
}
#[deprecated(since = "0.18.0", note = "please use `as_dmat4()` instead")]
#[inline(always)]
pub fn as_f64(&self) -> DMat4 {
self.as_dmat4()
}
#[inline(always)]
pub fn as_dmat4(&self) -> DMat4 {
DMat4::from_cols(
self.x_axis.as_dvec4(),
self.y_axis.as_dvec4(),
self.z_axis.as_dvec4(),
self.w_axis.as_dvec4(),
)
}
}
impl_mat4_traits!(f32, mat4, Mat4, Vec4);
type InnerF64 = Columns4<XYZW<f64>>;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct DMat4(pub(crate) InnerF64);
impl DMat4 {
impl_mat4_methods!(f64, DVec4, DVec3, DMat3, DQuat, InnerF64);
#[deprecated(since = "0.18.0", note = "please use `as_mat4()` instead")]
#[inline(always)]
pub fn as_f32(&self) -> Mat4 {
self.as_mat4()
}
#[inline(always)]
pub fn as_mat4(&self) -> Mat4 {
Mat4::from_cols(
self.x_axis.as_vec4(),
self.y_axis.as_vec4(),
self.z_axis.as_vec4(),
self.w_axis.as_vec4(),
)
}
}
impl_mat4_traits!(f64, dmat4, DMat4, DVec4);
#[cfg(any(feature = "scalar-math", target_arch = "spriv"))]
mod const_test_mat4 {
const_assert_eq!(
core::mem::align_of::<f32>(),
core::mem::align_of::<super::Mat4>()
);
const_assert_eq!(64, core::mem::size_of::<super::Mat4>());
}
#[cfg(not(any(feature = "scalar-math", target_arch = "spriv")))]
mod const_test_mat4 {
const_assert_eq!(16, core::mem::align_of::<super::Mat4>());
const_assert_eq!(64, core::mem::size_of::<super::Mat4>());
}
mod const_test_dmat4 {
const_assert_eq!(
core::mem::align_of::<f64>(),
core::mem::align_of::<super::DMat4>()
);
const_assert_eq!(128, core::mem::size_of::<super::DMat4>());
}