use core::fmt;
use core::ops::{
Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Range, RangeFull,
RangeInclusive, Sub, SubAssign,
};
use core::slice::{ChunksExact, ChunksExactMut};
use num_traits::{ConstOne, ConstZero, MulAdd, MulAddAssign, One, Signed, Zero, float::FloatCore};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{MathConstants, Matrix2x2, Matrix3x3, Matrix4x4Math, Vector4d};
pub type Matrix4x4f32 = Matrix4x4<f32>;
pub type Matrix4x4f64 = Matrix4x4<f64>;
#[derive(Clone, Copy, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C, align(64))]
pub struct Matrix4x4<T> {
pub(crate) a: [T; 16],
}
impl<T> fmt::Debug for Matrix4x4<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Matrix4x4 [")?;
for row in self.chunks_exact(4) {
write!(f, " ")?;
fmt::Debug::fmt(row, f)?;
writeln!(f, ",")?;
}
write!(f, "]")
}
}
impl<T> Matrix4x4<T> {
pub const SIZE: usize = 16;
pub const ROW_COUNT: usize = 4;
pub const COL_COUNT: usize = 4;
pub const M11: usize = 0;
pub const M12: usize = 1;
pub const M13: usize = 2;
pub const M14: usize = 3;
pub const M21: usize = 4;
pub const M22: usize = 5;
pub const M23: usize = 6;
pub const M24: usize = 7;
pub const M31: usize = 8;
pub const M32: usize = 9;
pub const M33: usize = 10;
pub const M34: usize = 11;
pub const M41: usize = 12;
pub const M42: usize = 13;
pub const M43: usize = 14;
pub const M44: usize = 15;
}
impl<T> Matrix4x4<T>
where
T: Copy,
{
#[inline]
pub const fn new(input: [T; 16]) -> Self {
Self { a: input }
}
}
impl<T> Zero for Matrix4x4<T>
where
T: Copy + Zero + PartialEq + Matrix4x4Math,
{
#[inline]
fn zero() -> Self {
Self { a: [T::zero(); 16] }
}
#[inline]
fn is_zero(&self) -> bool {
*self == Self::zero()
}
}
impl<T> ConstZero for Matrix4x4<T>
where
T: Copy + ConstZero + PartialEq + Matrix4x4Math,
{
const ZERO: Self = Self { a: [T::ZERO; 16] };
}
impl<T> One for Matrix4x4<T>
where
T: Copy + Zero + One + PartialEq + Matrix4x4Math,
{
#[rustfmt::skip]
#[inline]
fn one() -> Self {
Self {
a: [
T::one(), T::zero(), T::zero(), T::zero(),
T::zero(), T::one(), T::zero(), T::zero(),
T::zero(), T::zero(), T::one(), T::zero(),
T::zero(), T::zero(), T::zero(), T::one()
]
}
}
#[inline]
fn is_one(&self) -> bool {
*self == Self::one()
}
}
impl<T> ConstOne for Matrix4x4<T>
where
T: Copy + ConstZero + ConstOne + PartialEq + Matrix4x4Math,
{
#[rustfmt::skip]
const ONE: Self = Self {
a: [
T::ONE, T::ZERO, T::ZERO, T::ZERO,
T::ZERO, T::ONE, T::ZERO, T::ZERO,
T::ZERO, T::ZERO, T::ONE, T::ZERO,
T::ZERO, T::ZERO, T::ZERO, T::ONE,
]
};
}
impl<T> Matrix4x4<T>
where
T: Copy + Zero + One,
{
#[rustfmt::skip]
#[inline]
pub fn identity() -> Self {
Self {
a: [
T::one(), T::zero(), T::zero(), T::zero(),
T::zero(), T::one(), T::zero(), T::zero(),
T::zero(), T::zero(), T::one(), T::zero(),
T::zero(), T::zero(), T::zero(), T::one()
],
}
}
}
impl<T> Neg for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn neg(self) -> Self {
T::m4x4_neg(self)
}
}
impl<T> Add for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
T::m4x4_add(self, other)
}
}
impl<T> AddAssign for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<T> MulAdd<T> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn mul_add(self, k: T, other: Self) -> Self {
T::m4x4_mul_add(self, k, other)
}
}
impl<T> MulAddAssign<T> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
fn mul_add_assign(&mut self, k: T, other: Self) {
*self = self.mul_add(k, other);
}
}
impl<T> Sub for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
self + (-other)
}
}
impl<T> SubAssign for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl Mul<Matrix4x4<f32>> for f32 {
type Output = Matrix4x4<f32>;
#[inline]
fn mul(self, other: Matrix4x4<f32>) -> Matrix4x4<f32> {
f32::m4x4_mul_scalar(other, self)
}
}
impl Mul<Matrix4x4<f64>> for f64 {
type Output = Matrix4x4<f64>;
#[inline]
fn mul(self, other: Matrix4x4<f64>) -> Matrix4x4<f64> {
f64::m4x4_mul_scalar(other, self)
}
}
impl<T> Mul<T> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn mul(self, other: T) -> Self {
T::m4x4_mul_scalar(self, other)
}
}
impl<T> MulAssign<T> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
fn mul_assign(&mut self, other: T) {
*self = *self * other;
}
}
impl<T> Mul<Vector4d<T>> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Vector4d<T>;
#[inline]
fn mul(self, other: Vector4d<T>) -> Vector4d<T> {
T::m4x4_mul_vector(self, other)
}
}
impl<T> Mul<Matrix4x4<T>> for Vector4d<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn mul(self, other: Matrix4x4<T>) -> Self {
T::m4x4_vector_mul(self, other)
}
}
impl<T> Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
pub fn outer_product(col: Vector4d<T>, row: Vector4d<T>) -> Self {
T::m4x4_vector_outer_product(col, row)
}
}
impl<T> Mul<Matrix4x4<T>> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
T::m4x4_mul(self, other)
}
}
impl<T> MulAssign<Matrix4x4<T>> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
fn mul_assign(&mut self, other: Matrix4x4<T>) {
*self = *self * other;
}
}
impl<T> Div<T> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
type Output = Self;
#[inline]
fn div(self, other: T) -> Self {
T::m4x4_div_scalar(self, other)
}
}
impl<T> DivAssign<T> for Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
fn div_assign(&mut self, other: T) {
*self = *self / other;
}
}
impl<T> AsRef<[T; 16]> for Matrix4x4<T> {
#[inline]
fn as_ref(&self) -> &[T; 16] {
&self.a
}
}
impl<T> AsMut<[T; 16]> for Matrix4x4<T> {
#[inline]
fn as_mut(&mut self) -> &mut [T; 16] {
&mut self.a
}
}
impl<T> Deref for Matrix4x4<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
&self.a
}
}
impl<T> DerefMut for Matrix4x4<T> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
&mut self.a
}
}
impl<T> Index<usize> for Matrix4x4<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
&self.a[index]
}
}
impl<T> Index<Range<usize>> for Matrix4x4<T> {
type Output = [T];
#[inline]
fn index(&self, index: Range<usize>) -> &[T] {
&self.a[index]
}
}
impl<T> Index<RangeFull> for Matrix4x4<T> {
type Output = [T];
#[inline]
fn index(&self, _index: RangeFull) -> &[T] {
&self.a
}
}
impl<T> Index<RangeInclusive<usize>> for Matrix4x4<T> {
type Output = [T];
#[inline]
fn index(&self, index: RangeInclusive<usize>) -> &[T] {
&self.a[index]
}
}
impl<T> Index<(usize, usize)> for Matrix4x4<T> {
type Output = T;
#[inline]
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
assert!(row < 4 && col < 4, "Matrix index out of bounds: row={row}, col={col}");
&self.a[row * 4 + col]
}
}
impl<T> IndexMut<usize> for Matrix4x4<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
&mut self.a[index]
}
}
impl<T> IndexMut<Range<usize>> for Matrix4x4<T> {
#[inline]
fn index_mut(&mut self, index: Range<usize>) -> &mut [T] {
&mut self.a[index]
}
}
impl<T> IndexMut<RangeFull> for Matrix4x4<T> {
#[inline]
fn index_mut(&mut self, _index: RangeFull) -> &mut [T] {
&mut self.a
}
}
impl<T> IndexMut<RangeInclusive<usize>> for Matrix4x4<T> {
#[inline]
fn index_mut(&mut self, index: RangeInclusive<usize>) -> &mut [T] {
&mut self.a[index]
}
}
impl<T> IndexMut<(usize, usize)> for Matrix4x4<T> {
#[inline]
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
assert!(row < 4 && col < 4, "Matrix index out of bounds: row={row}, col={col}");
&mut self.a[row * 4 + col]
}
}
impl<T> Matrix4x4<T>
where
T: Copy,
{
pub fn set_row(&mut self, row: usize, value: Vector4d<T>) {
let row_slice = &mut self.a[row * 4..(row + 1) * 4];
row_slice.copy_from_slice(&[value.x, value.y, value.z, value.t]);
}
pub fn row(self, row: usize) -> Vector4d<T> {
match row {
0 => Vector4d::<T> { x: self.a[0], y: self.a[1], z: self.a[2], t: self.a[3] },
1 => Vector4d::<T> { x: self.a[4], y: self.a[5], z: self.a[6], t: self.a[7] },
2 => Vector4d::<T> { x: self.a[8], y: self.a[9], z: self.a[10], t: self.a[11] },
_ => Vector4d::<T> { x: self.a[12], y: self.a[13], z: self.a[14], t: self.a[15] },
}
}
pub fn set_column(&mut self, column: usize, value: Vector4d<T>) {
if column >= 4 {
return;
}
let values = [value.x, value.y, value.z, value.t];
for (i, &val) in values.iter().enumerate() {
self.a[i * 4 + column] = val;
}
}
pub fn column(self, column: usize) -> Vector4d<T> {
match column {
0 => Vector4d::<T> { x: self.a[0], y: self.a[4], z: self.a[8], t: self.a[12] },
1 => Vector4d::<T> { x: self.a[1], y: self.a[5], z: self.a[9], t: self.a[13] },
2 => Vector4d::<T> { x: self.a[2], y: self.a[6], z: self.a[10], t: self.a[14] },
_ => Vector4d::<T> { x: self.a[3], y: self.a[7], z: self.a[11], t: self.a[15] },
}
}
pub fn diagonal(self) -> Vector4d<T> {
Vector4d::<T> { x: self.a[0], y: self.a[5], z: self.a[10], t: self.a[15] }
}
}
impl<T> Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
pub fn abs(self) -> Self {
T::m4x4_abs(self)
}
#[inline]
pub fn abs_in_place(&mut self) -> &mut Self {
*self = T::m4x4_abs(*self);
self
}
}
impl<T> Matrix4x4<T>
where
T: Copy + FloatCore,
{
#[inline]
pub fn clamp(self, min: T, max: T) -> Self {
let mut a = self.a;
for it in &mut a {
*it = it.clamp(min, max);
}
Self { a }
}
#[inline]
pub fn clamp_in_place(&mut self, min: T, max: T) -> &mut Self {
*self = self.clamp(min, max);
self
}
}
impl<T> Matrix4x4<T>
where
T: Copy,
{
#[inline]
pub fn transpose(self) -> Self {
Self {
a: [
self.a[0], self.a[4], self.a[8], self.a[12], self.a[1], self.a[5], self.a[9], self.a[13], self.a[2], self.a[6], self.a[10], self.a[14], self.a[3], self.a[7], self.a[11], self.a[15], ],
}
}
#[inline]
pub fn transpose_in_place(&mut self) -> &mut Self {
*self = self.transpose();
self
}
}
impl<T> Matrix4x4<T>
where
T: Copy + Matrix4x4Math,
{
#[inline]
pub fn adjugate(self) -> (Self, T) {
let (adjugate, determinant) = T::m4x4_adjugate(self);
(adjugate, determinant)
}
#[inline]
pub fn adjugate_in_place(&mut self) -> &mut Self {
*self = self.adjugate().0;
self
}
#[inline]
pub fn inverse(self) -> Self {
let (adjugate, determinant) = T::m4x4_adjugate(self);
adjugate / determinant
}
#[inline]
pub fn invert_in_place(&mut self) -> &mut Self {
let (adjugate, determinant) = T::m4x4_adjugate(*self);
*self = adjugate / determinant;
self
}
#[inline]
pub fn determinant(self) -> T {
T::m4x4_determinant(self)
}
#[inline]
pub fn trace(self) -> T {
T::m4x4_trace(self)
}
}
impl<T> Matrix4x4<T>
where
T: Copy + Zero + One + Matrix4x4Math + MathConstants + PartialOrd + Signed,
{
pub fn inverse_or_zero(self) -> Self {
let (adjugate, determinant) = self.adjugate();
if determinant.abs() < T::EPSILON {
return Self::zero();
}
adjugate / determinant
}
pub fn try_inverse(self) -> Option<Self> {
let (adjugate, determinant) = self.adjugate();
if determinant.abs() < T::EPSILON {
return None;
}
Some(adjugate / determinant)
}
#[inline]
pub fn sum(self) -> T {
T::m4x4_sum(self)
}
#[inline]
pub fn mean(self) -> T {
T::m4x4_mean(self)
}
#[inline]
pub fn product(self) -> T {
T::m4x4_product(self)
}
#[inline]
pub fn trace_sum_squares(self) -> T {
T::m4x4_trace_sum_squares(self)
}
pub fn is_near_zero(self) -> bool {
for a in &self.a {
if a.abs() > T::EPSILON {
return false;
}
}
true
}
pub fn is_near_identity(self) -> bool {
if self.a[1].abs() > T::EPSILON
|| self.a[2].abs() > T::EPSILON
|| self.a[3].abs() > T::EPSILON
|| self.a[4].abs() > T::EPSILON
|| self.a[6].abs() > T::EPSILON
|| self.a[7].abs() > T::EPSILON
|| self.a[8].abs() > T::EPSILON
|| self.a[9].abs() > T::EPSILON
|| self.a[11].abs() > T::EPSILON
|| self.a[12].abs() > T::EPSILON
|| self.a[13].abs() > T::EPSILON
{
return false;
}
if (self.a[0] - T::one()).abs() > T::EPSILON
|| (self.a[5] - T::one()).abs() > T::EPSILON
|| (self.a[10] - T::one()).abs() > T::EPSILON
|| (self.a[15] - T::one()).abs() > T::EPSILON
{
return false;
}
true
}
}
impl<T> Matrix4x4<T> {
#[inline]
pub fn rows(&self) -> ChunksExact<'_, T> {
self.chunks_exact(4)
}
}
impl<T> Matrix4x4<T> {
#[inline]
pub fn rows_mut(&mut self) -> ChunksExactMut<'_, T> {
self.chunks_exact_mut(4)
}
}
impl<T> Matrix4x4<T>
where
T: Copy,
{
#[inline]
pub fn into_rows(self) -> [[T; 4]; 4] {
core::array::from_fn(|r| core::array::from_fn(|c| self.a[r * 4 + c]))
}
}
impl<T> Matrix4x4<T>
where
T: Copy,
{
#[inline]
pub fn cols(&self) -> impl Iterator<Item = [T; 4]> {
(0..4).map(|c| {
[self.a[c], self.a[c + 4], self.a[c + 8], self.a[c + 12]]
})
}
}
impl<'a, T> IntoIterator for &'a Matrix4x4<T> {
type Item = &'a [T];
type IntoIter = ChunksExact<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.chunks_exact(4)
}
}
impl<'a, T> IntoIterator for &'a mut Matrix4x4<T> {
type Item = &'a mut [T];
type IntoIter = ChunksExactMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.chunks_exact_mut(4)
}
}
impl<T> IntoIterator for Matrix4x4<T>
where
T: Copy,
{
type Item = [T; 4];
type IntoIter = core::array::IntoIter<[T; 4], 4>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let rows = core::array::from_fn(|r| core::array::from_fn(|c| self.a[r * 4 + c]));
rows.into_iter()
}
}
impl<T> From<[T; 16]> for Matrix4x4<T>
where
T: Copy,
{
#[inline]
fn from(input: [T; 16]) -> Self {
Self { a: input }
}
}
impl<T> From<[[T; 4]; 4]> for Matrix4x4<T>
where
T: Copy,
{
#[inline]
fn from(a: [[T; 4]; 4]) -> Self {
Self {
a: [
a[0][0], a[0][1], a[0][2], a[0][3], a[1][0], a[1][1], a[1][2], a[1][3], a[2][0], a[2][1], a[2][2], a[2][3], a[3][0], a[3][1], a[3][2], a[3][3], ],
}
}
}
impl<T> From<[Vector4d<T>; 4]> for Matrix4x4<T>
where
T: Copy,
{
#[inline]
fn from(v: [Vector4d<T>; 4]) -> Self {
Self {
a: [
v[0].x, v[0].y, v[0].z, v[0].t, v[1].x, v[1].y, v[1].z, v[1].t, v[2].x, v[2].y, v[2].z, v[2].t, v[3].x, v[3].y, v[3].z, v[3].t, ],
}
}
}
impl<T> From<(Vector4d<T>, Vector4d<T>, Vector4d<T>, Vector4d<T>)> for Matrix4x4<T> {
#[rustfmt::skip]
#[inline]
fn from(v: (Vector4d<T>, Vector4d<T>, Vector4d<T>, Vector4d<T>)) -> Self {
Self { a: [
v.0.x, v.0.y, v.0.z, v.0.t,
v.1.x, v.1.y, v.1.z, v.1.t,
v.2.x, v.2.y, v.2.z, v.2.t,
v.3.x, v.3.y, v.3.z, v.3.t,
] }
}
}
impl<T> From<Matrix2x2<T>> for Matrix4x4<T>
where
T: Copy + Zero,
{
#[rustfmt::skip]
#[inline]
fn from(m: Matrix2x2<T>) -> Self {
Self { a: [
m[0], m[1], T::zero(), T::zero(),
m[2], m[3], T::zero(), T::zero(),
T::zero(), T::zero(), T::zero(), T::zero(),
T::zero(), T::zero(), T::zero(), T::zero(),
] }
}
}
impl<T> From<Matrix4x4<T>> for Matrix2x2<T>
where
T: Copy,
{
#[rustfmt::skip]
#[inline]
fn from(m: Matrix4x4<T>) -> Self {
Self { a: [
m.a[0], m.a[1],
m.a[4], m.a[5]
] }
}
}
impl<T> From<Matrix4x4<T>> for Matrix3x3<T>
where
T: Copy,
{
#[rustfmt::skip]
#[inline]
fn from(m: Matrix4x4<T>) -> Self {
Self { a: [
m.a[0], m.a[1], m.a[2],
m.a[4], m.a[5], m.a[6],
m.a[8], m.a[9], m.a[10]
] }
}
}