glam/f32/neon/
mat4.rs

1// Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3use crate::{
4    euler::{FromEuler, ToEuler},
5    f32::math,
6    neon::*,
7    swizzles::*,
8    DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
9};
10use core::fmt;
11use core::iter::{Product, Sum};
12use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
13
14use core::arch::aarch64::*;
15
16/// Creates a 4x4 matrix from four column vectors.
17#[inline(always)]
18#[must_use]
19pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 {
20    Mat4::from_cols(x_axis, y_axis, z_axis, w_axis)
21}
22
23/// A 4x4 column major matrix.
24///
25/// This 4x4 matrix type features convenience methods for creating and using affine transforms and
26/// perspective projections. If you are primarily dealing with 3D affine transformations
27/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix
28/// for some affine operations.
29///
30/// Affine transformations including 3D translation, rotation and scale can be created
31/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
32/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
33///
34/// Orthographic projections can be created using the methods [`Self::orthographic_lh()`] for
35/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed
36/// systems. The resulting matrix is also an affine transformation.
37///
38/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
39/// are provided for performing affine transformations on 3D vectors and points. These
40/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
41/// for vectors respectively. These methods assume that `Self` contains a valid affine
42/// transform.
43///
44/// Perspective projections can be created using methods such as
45/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and
46/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and
47/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and
48/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems.
49///
50/// The resulting perspective project can be use to transform 3D vectors as points with
51/// perspective correction using the [`Self::project_point3()`] convenience method.
52#[derive(Clone, Copy)]
53#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
54#[repr(C)]
55pub struct Mat4 {
56    pub x_axis: Vec4,
57    pub y_axis: Vec4,
58    pub z_axis: Vec4,
59    pub w_axis: Vec4,
60}
61
62impl Mat4 {
63    /// A 4x4 matrix with all elements set to `0.0`.
64    pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO);
65
66    /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
67    pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W);
68
69    /// All NAN:s.
70    pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN);
71
72    #[allow(clippy::too_many_arguments)]
73    #[inline(always)]
74    #[must_use]
75    const fn new(
76        m00: f32,
77        m01: f32,
78        m02: f32,
79        m03: f32,
80        m10: f32,
81        m11: f32,
82        m12: f32,
83        m13: f32,
84        m20: f32,
85        m21: f32,
86        m22: f32,
87        m23: f32,
88        m30: f32,
89        m31: f32,
90        m32: f32,
91        m33: f32,
92    ) -> Self {
93        Self {
94            x_axis: Vec4::new(m00, m01, m02, m03),
95            y_axis: Vec4::new(m10, m11, m12, m13),
96            z_axis: Vec4::new(m20, m21, m22, m23),
97            w_axis: Vec4::new(m30, m31, m32, m33),
98        }
99    }
100
101    /// Creates a 4x4 matrix from four column vectors.
102    #[inline(always)]
103    #[must_use]
104    pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self {
105        Self {
106            x_axis,
107            y_axis,
108            z_axis,
109            w_axis,
110        }
111    }
112
113    /// Creates a 4x4 matrix from a `[f32; 16]` array stored in column major order.
114    /// If your data is stored in row major you will need to `transpose` the returned
115    /// matrix.
116    #[inline]
117    #[must_use]
118    pub const fn from_cols_array(m: &[f32; 16]) -> Self {
119        Self::new(
120            m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13],
121            m[14], m[15],
122        )
123    }
124
125    /// Creates a `[f32; 16]` array storing data in column major order.
126    /// If you require data in row major order `transpose` the matrix first.
127    #[inline]
128    #[must_use]
129    pub const fn to_cols_array(&self) -> [f32; 16] {
130        let [x_axis_x, x_axis_y, x_axis_z, x_axis_w] = self.x_axis.to_array();
131        let [y_axis_x, y_axis_y, y_axis_z, y_axis_w] = self.y_axis.to_array();
132        let [z_axis_x, z_axis_y, z_axis_z, z_axis_w] = self.z_axis.to_array();
133        let [w_axis_x, w_axis_y, w_axis_z, w_axis_w] = self.w_axis.to_array();
134
135        [
136            x_axis_x, x_axis_y, x_axis_z, x_axis_w, y_axis_x, y_axis_y, y_axis_z, y_axis_w,
137            z_axis_x, z_axis_y, z_axis_z, z_axis_w, w_axis_x, w_axis_y, w_axis_z, w_axis_w,
138        ]
139    }
140
141    /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 4D array stored in column major order.
142    /// If your data is in row major order you will need to `transpose` the returned
143    /// matrix.
144    #[inline]
145    #[must_use]
146    pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self {
147        Self::from_cols(
148            Vec4::from_array(m[0]),
149            Vec4::from_array(m[1]),
150            Vec4::from_array(m[2]),
151            Vec4::from_array(m[3]),
152        )
153    }
154
155    /// Creates a `[[f32; 4]; 4]` 4D array storing data in column major order.
156    /// If you require data in row major order `transpose` the matrix first.
157    #[inline]
158    #[must_use]
159    pub const fn to_cols_array_2d(&self) -> [[f32; 4]; 4] {
160        [
161            self.x_axis.to_array(),
162            self.y_axis.to_array(),
163            self.z_axis.to_array(),
164            self.w_axis.to_array(),
165        ]
166    }
167
168    /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0.
169    #[doc(alias = "scale")]
170    #[inline]
171    #[must_use]
172    pub const fn from_diagonal(diagonal: Vec4) -> Self {
173        // diagonal.x, diagonal.y etc can't be done in a const-context
174        let [x, y, z, w] = diagonal.to_array();
175        Self::new(
176            x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, w,
177        )
178    }
179
180    #[inline]
181    #[must_use]
182    fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) {
183        glam_assert!(rotation.is_normalized());
184
185        let (x, y, z, w) = rotation.into();
186        let x2 = x + x;
187        let y2 = y + y;
188        let z2 = z + z;
189        let xx = x * x2;
190        let xy = x * y2;
191        let xz = x * z2;
192        let yy = y * y2;
193        let yz = y * z2;
194        let zz = z * z2;
195        let wx = w * x2;
196        let wy = w * y2;
197        let wz = w * z2;
198
199        let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
200        let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
201        let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
202        (x_axis, y_axis, z_axis)
203    }
204
205    /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and
206    /// `translation`.
207    ///
208    /// The resulting matrix can be used to transform 3D points and vectors. See
209    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
210    ///
211    /// # Panics
212    ///
213    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
214    #[inline]
215    #[must_use]
216    pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
217        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
218        Self::from_cols(
219            x_axis.mul(scale.x),
220            y_axis.mul(scale.y),
221            z_axis.mul(scale.z),
222            Vec4::from((translation, 1.0)),
223        )
224    }
225
226    /// Creates an affine transformation matrix from the given 3D `translation`.
227    ///
228    /// The resulting matrix can be used to transform 3D points and vectors. See
229    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
230    ///
231    /// # Panics
232    ///
233    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
234    #[inline]
235    #[must_use]
236    pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
237        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
238        Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0)))
239    }
240
241    /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is
242    /// expected to be a 3D affine transformation matrix otherwise the output will be invalid.
243    ///
244    /// # Panics
245    ///
246    /// Will panic if the determinant of `self` is zero or if the resulting scale vector
247    /// contains any zero elements when `glam_assert` is enabled.
248    #[inline]
249    #[must_use]
250    pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
251        let det = self.determinant();
252        glam_assert!(det != 0.0);
253
254        let scale = Vec3::new(
255            self.x_axis.length() * math::signum(det),
256            self.y_axis.length(),
257            self.z_axis.length(),
258        );
259
260        glam_assert!(scale.cmpne(Vec3::ZERO).all());
261
262        let inv_scale = scale.recip();
263
264        let rotation = Quat::from_rotation_axes(
265            self.x_axis.mul(inv_scale.x).xyz(),
266            self.y_axis.mul(inv_scale.y).xyz(),
267            self.z_axis.mul(inv_scale.z).xyz(),
268        );
269
270        let translation = self.w_axis.xyz();
271
272        (scale, rotation, translation)
273    }
274
275    /// Creates an affine transformation matrix from the given `rotation` quaternion.
276    ///
277    /// The resulting matrix can be used to transform 3D points and vectors. See
278    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
279    ///
280    /// # Panics
281    ///
282    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
283    #[inline]
284    #[must_use]
285    pub fn from_quat(rotation: Quat) -> Self {
286        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
287        Self::from_cols(x_axis, y_axis, z_axis, Vec4::W)
288    }
289
290    /// Creates an affine transformation matrix from the given 3x3 linear transformation
291    /// matrix.
292    ///
293    /// The resulting matrix can be used to transform 3D points and vectors. See
294    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
295    #[inline]
296    #[must_use]
297    pub fn from_mat3(m: Mat3) -> Self {
298        Self::from_cols(
299            Vec4::from((m.x_axis, 0.0)),
300            Vec4::from((m.y_axis, 0.0)),
301            Vec4::from((m.z_axis, 0.0)),
302            Vec4::W,
303        )
304    }
305
306    /// Creates an affine transformation matrics from a 3x3 matrix (expressing scale, shear and
307    /// rotation) and a translation vector.
308    ///
309    /// Equivalent to `Mat4::from_translation(translation) * Mat4::from_mat3(mat3)`
310    #[inline]
311    #[must_use]
312    pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
313        Self::from_cols(
314            Vec4::from((mat3.x_axis, 0.0)),
315            Vec4::from((mat3.y_axis, 0.0)),
316            Vec4::from((mat3.z_axis, 0.0)),
317            Vec4::from((translation, 1.0)),
318        )
319    }
320
321    /// Creates an affine transformation matrix from the given 3x3 linear transformation
322    /// matrix.
323    ///
324    /// The resulting matrix can be used to transform 3D points and vectors. See
325    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
326    #[inline]
327    #[must_use]
328    pub fn from_mat3a(m: Mat3A) -> Self {
329        Self::from_cols(
330            Vec4::from((m.x_axis, 0.0)),
331            Vec4::from((m.y_axis, 0.0)),
332            Vec4::from((m.z_axis, 0.0)),
333            Vec4::W,
334        )
335    }
336
337    /// Creates an affine transformation matrix from the given 3D `translation`.
338    ///
339    /// The resulting matrix can be used to transform 3D points and vectors. See
340    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
341    #[inline]
342    #[must_use]
343    pub fn from_translation(translation: Vec3) -> Self {
344        Self::from_cols(
345            Vec4::X,
346            Vec4::Y,
347            Vec4::Z,
348            Vec4::new(translation.x, translation.y, translation.z, 1.0),
349        )
350    }
351
352    /// Creates an affine transformation matrix containing a 3D rotation around a normalized
353    /// rotation `axis` of `angle` (in radians).
354    ///
355    /// The resulting matrix can be used to transform 3D points and vectors. See
356    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
357    ///
358    /// # Panics
359    ///
360    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
361    #[inline]
362    #[must_use]
363    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
364        glam_assert!(axis.is_normalized());
365
366        let (sin, cos) = math::sin_cos(angle);
367        let axis_sin = axis.mul(sin);
368        let axis_sq = axis.mul(axis);
369        let omc = 1.0 - cos;
370        let xyomc = axis.x * axis.y * omc;
371        let xzomc = axis.x * axis.z * omc;
372        let yzomc = axis.y * axis.z * omc;
373        Self::from_cols(
374            Vec4::new(
375                axis_sq.x * omc + cos,
376                xyomc + axis_sin.z,
377                xzomc - axis_sin.y,
378                0.0,
379            ),
380            Vec4::new(
381                xyomc - axis_sin.z,
382                axis_sq.y * omc + cos,
383                yzomc + axis_sin.x,
384                0.0,
385            ),
386            Vec4::new(
387                xzomc + axis_sin.y,
388                yzomc - axis_sin.x,
389                axis_sq.z * omc + cos,
390                0.0,
391            ),
392            Vec4::W,
393        )
394    }
395
396    /// Creates a affine transformation matrix containing a rotation from the given euler
397    /// rotation sequence and angles (in radians).
398    ///
399    /// The resulting matrix can be used to transform 3D points and vectors. See
400    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
401    #[inline]
402    #[must_use]
403    pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
404        Self::from_euler_angles(order, a, b, c)
405    }
406
407    /// Extract Euler angles with the given Euler rotation order.
408    ///
409    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
410    /// then the resulting Euler angles will be ill-defined.
411    ///
412    /// # Panics
413    ///
414    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
415    /// `glam_assert` is enabled.
416    #[inline]
417    #[must_use]
418    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
419        glam_assert!(
420            self.x_axis.xyz().is_normalized()
421                && self.y_axis.xyz().is_normalized()
422                && self.z_axis.xyz().is_normalized()
423        );
424        self.to_euler_angles(order)
425    }
426
427    /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
428    /// `angle` (in radians).
429    ///
430    /// The resulting matrix can be used to transform 3D points and vectors. See
431    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
432    #[inline]
433    #[must_use]
434    pub fn from_rotation_x(angle: f32) -> Self {
435        let (sina, cosa) = math::sin_cos(angle);
436        Self::from_cols(
437            Vec4::X,
438            Vec4::new(0.0, cosa, sina, 0.0),
439            Vec4::new(0.0, -sina, cosa, 0.0),
440            Vec4::W,
441        )
442    }
443
444    /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
445    /// `angle` (in radians).
446    ///
447    /// The resulting matrix can be used to transform 3D points and vectors. See
448    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
449    #[inline]
450    #[must_use]
451    pub fn from_rotation_y(angle: f32) -> Self {
452        let (sina, cosa) = math::sin_cos(angle);
453        Self::from_cols(
454            Vec4::new(cosa, 0.0, -sina, 0.0),
455            Vec4::Y,
456            Vec4::new(sina, 0.0, cosa, 0.0),
457            Vec4::W,
458        )
459    }
460
461    /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
462    /// `angle` (in radians).
463    ///
464    /// The resulting matrix can be used to transform 3D points and vectors. See
465    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
466    #[inline]
467    #[must_use]
468    pub fn from_rotation_z(angle: f32) -> Self {
469        let (sina, cosa) = math::sin_cos(angle);
470        Self::from_cols(
471            Vec4::new(cosa, sina, 0.0, 0.0),
472            Vec4::new(-sina, cosa, 0.0, 0.0),
473            Vec4::Z,
474            Vec4::W,
475        )
476    }
477
478    /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
479    ///
480    /// The resulting matrix can be used to transform 3D points and vectors. See
481    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
482    ///
483    /// # Panics
484    ///
485    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
486    #[inline]
487    #[must_use]
488    pub fn from_scale(scale: Vec3) -> Self {
489        // Do not panic as long as any component is non-zero
490        glam_assert!(scale.cmpne(Vec3::ZERO).any());
491
492        Self::from_cols(
493            Vec4::new(scale.x, 0.0, 0.0, 0.0),
494            Vec4::new(0.0, scale.y, 0.0, 0.0),
495            Vec4::new(0.0, 0.0, scale.z, 0.0),
496            Vec4::W,
497        )
498    }
499
500    /// Creates a 4x4 matrix from the first 16 values in `slice`.
501    ///
502    /// # Panics
503    ///
504    /// Panics if `slice` is less than 16 elements long.
505    #[inline]
506    #[must_use]
507    pub const fn from_cols_slice(slice: &[f32]) -> Self {
508        Self::new(
509            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
510            slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
511        )
512    }
513
514    /// Writes the columns of `self` to the first 16 elements in `slice`.
515    ///
516    /// # Panics
517    ///
518    /// Panics if `slice` is less than 16 elements long.
519    #[inline]
520    pub fn write_cols_to_slice(self, slice: &mut [f32]) {
521        slice[0] = self.x_axis.x;
522        slice[1] = self.x_axis.y;
523        slice[2] = self.x_axis.z;
524        slice[3] = self.x_axis.w;
525        slice[4] = self.y_axis.x;
526        slice[5] = self.y_axis.y;
527        slice[6] = self.y_axis.z;
528        slice[7] = self.y_axis.w;
529        slice[8] = self.z_axis.x;
530        slice[9] = self.z_axis.y;
531        slice[10] = self.z_axis.z;
532        slice[11] = self.z_axis.w;
533        slice[12] = self.w_axis.x;
534        slice[13] = self.w_axis.y;
535        slice[14] = self.w_axis.z;
536        slice[15] = self.w_axis.w;
537    }
538
539    /// Returns the matrix column for the given `index`.
540    ///
541    /// # Panics
542    ///
543    /// Panics if `index` is greater than 3.
544    #[inline]
545    #[must_use]
546    pub fn col(&self, index: usize) -> Vec4 {
547        match index {
548            0 => self.x_axis,
549            1 => self.y_axis,
550            2 => self.z_axis,
551            3 => self.w_axis,
552            _ => panic!("index out of bounds"),
553        }
554    }
555
556    /// Returns a mutable reference to the matrix column for the given `index`.
557    ///
558    /// # Panics
559    ///
560    /// Panics if `index` is greater than 3.
561    #[inline]
562    pub fn col_mut(&mut self, index: usize) -> &mut Vec4 {
563        match index {
564            0 => &mut self.x_axis,
565            1 => &mut self.y_axis,
566            2 => &mut self.z_axis,
567            3 => &mut self.w_axis,
568            _ => panic!("index out of bounds"),
569        }
570    }
571
572    /// Returns the matrix row for the given `index`.
573    ///
574    /// # Panics
575    ///
576    /// Panics if `index` is greater than 3.
577    #[inline]
578    #[must_use]
579    pub fn row(&self, index: usize) -> Vec4 {
580        match index {
581            0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
582            1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
583            2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
584            3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
585            _ => panic!("index out of bounds"),
586        }
587    }
588
589    /// Returns `true` if, and only if, all elements are finite.
590    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
591    #[inline]
592    #[must_use]
593    pub fn is_finite(&self) -> bool {
594        self.x_axis.is_finite()
595            && self.y_axis.is_finite()
596            && self.z_axis.is_finite()
597            && self.w_axis.is_finite()
598    }
599
600    /// Returns `true` if any elements are `NaN`.
601    #[inline]
602    #[must_use]
603    pub fn is_nan(&self) -> bool {
604        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
605    }
606
607    /// Returns the transpose of `self`.
608    #[inline]
609    #[must_use]
610    pub fn transpose(&self) -> Self {
611        Self {
612            x_axis: Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
613            y_axis: Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
614            z_axis: Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
615            w_axis: Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
616        }
617    }
618
619    /// Returns the determinant of `self`.
620    #[must_use]
621    pub fn determinant(&self) -> f32 {
622        let (m00, m01, m02, m03) = self.x_axis.into();
623        let (m10, m11, m12, m13) = self.y_axis.into();
624        let (m20, m21, m22, m23) = self.z_axis.into();
625        let (m30, m31, m32, m33) = self.w_axis.into();
626
627        let a2323 = m22 * m33 - m23 * m32;
628        let a1323 = m21 * m33 - m23 * m31;
629        let a1223 = m21 * m32 - m22 * m31;
630        let a0323 = m20 * m33 - m23 * m30;
631        let a0223 = m20 * m32 - m22 * m30;
632        let a0123 = m20 * m31 - m21 * m30;
633
634        m00 * (m11 * a2323 - m12 * a1323 + m13 * a1223)
635            - m01 * (m10 * a2323 - m12 * a0323 + m13 * a0223)
636            + m02 * (m10 * a1323 - m11 * a0323 + m13 * a0123)
637            - m03 * (m10 * a1223 - m11 * a0223 + m12 * a0123)
638    }
639
640    /// Returns the inverse of `self`.
641    ///
642    /// If the matrix is not invertible the returned matrix will be invalid.
643    ///
644    /// # Panics
645    ///
646    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
647    #[must_use]
648    pub fn inverse(&self) -> Self {
649        unsafe {
650            // Based on https://github.com/g-truc/glm `glm_mat4_inverse`
651            let swizzle3377 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
652                let r = vuzp2q_f32(a, b);
653                vtrn2q_f32(r, r)
654            };
655            let swizzle2266 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
656                let r = vuzp1q_f32(a, b);
657                vtrn2q_f32(r, r)
658            };
659            let swizzle0046 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
660                let r = vuzp1q_f32(a, a);
661                vuzp1q_f32(r, b)
662            };
663            let swizzle1155 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
664                let r = vzip1q_f32(a, b);
665                vzip2q_f32(r, r)
666            };
667            let swizzle0044 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
668                let r = vuzp1q_f32(a, b);
669                vtrn1q_f32(r, r)
670            };
671            let swizzle0266 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
672                let r = vuzp1q_f32(a, b);
673                vsetq_lane_f32(vgetq_lane_f32(b, 2), r, 2)
674            };
675            let swizzle0246 = |a: float32x4_t, b: float32x4_t| -> float32x4_t { vuzp1q_f32(a, b) };
676            let fac0 = {
677                let swp0a = swizzle3377(self.w_axis.0, self.z_axis.0);
678                let swp0b = swizzle2266(self.w_axis.0, self.z_axis.0);
679
680                let swp00 = swizzle2266(self.z_axis.0, self.y_axis.0);
681                let swp01 = swizzle0046(swp0a, swp0a);
682                let swp02 = swizzle0046(swp0b, swp0b);
683                let swp03 = swizzle3377(self.z_axis.0, self.y_axis.0);
684
685                let mul00 = vmulq_f32(swp00, swp01);
686                let mul01 = vmulq_f32(swp02, swp03);
687                vsubq_f32(mul00, mul01)
688            };
689            let fac1 = {
690                let swp0a = swizzle3377(self.w_axis.0, self.z_axis.0);
691                let swp0b = swizzle1155(self.w_axis.0, self.z_axis.0);
692
693                let swp00 = swizzle1155(self.z_axis.0, self.y_axis.0);
694                let swp01 = swizzle0046(swp0a, swp0a);
695                let swp02 = swizzle0046(swp0b, swp0b);
696                let swp03 = swizzle3377(self.z_axis.0, self.y_axis.0);
697
698                let mul00 = vmulq_f32(swp00, swp01);
699                let mul01 = vmulq_f32(swp02, swp03);
700                vsubq_f32(mul00, mul01)
701            };
702            let fac2 = {
703                let swp0a = swizzle2266(self.w_axis.0, self.z_axis.0);
704                let swp0b = swizzle1155(self.w_axis.0, self.z_axis.0);
705
706                let swp00 = swizzle1155(self.z_axis.0, self.y_axis.0);
707                let swp01 = swizzle0046(swp0a, swp0a);
708                let swp02 = swizzle0046(swp0b, swp0b);
709                let swp03 = swizzle2266(self.z_axis.0, self.y_axis.0);
710
711                let mul00 = vmulq_f32(swp00, swp01);
712                let mul01 = vmulq_f32(swp02, swp03);
713                vsubq_f32(mul00, mul01)
714            };
715            let fac3 = {
716                let swp0a = swizzle3377(self.w_axis.0, self.z_axis.0);
717                let swp0b = swizzle0044(self.w_axis.0, self.z_axis.0);
718
719                let swp00 = swizzle0044(self.z_axis.0, self.y_axis.0);
720                let swp01 = swizzle0046(swp0a, swp0a);
721                let swp02 = swizzle0046(swp0b, swp0b);
722                let swp03 = swizzle3377(self.z_axis.0, self.y_axis.0);
723
724                let mul00 = vmulq_f32(swp00, swp01);
725                let mul01 = vmulq_f32(swp02, swp03);
726                vsubq_f32(mul00, mul01)
727            };
728            let fac4 = {
729                let swp0a = swizzle2266(self.w_axis.0, self.z_axis.0);
730                let swp0b = swizzle0044(self.w_axis.0, self.z_axis.0);
731
732                let swp00 = swizzle0044(self.z_axis.0, self.y_axis.0);
733                let swp01 = swizzle0046(swp0a, swp0a);
734                let swp02 = swizzle0046(swp0b, swp0b);
735                let swp03 = swizzle2266(self.z_axis.0, self.y_axis.0);
736
737                let mul00 = vmulq_f32(swp00, swp01);
738                let mul01 = vmulq_f32(swp02, swp03);
739                vsubq_f32(mul00, mul01)
740            };
741            let fac5 = {
742                let swp0a = swizzle1155(self.w_axis.0, self.z_axis.0);
743                let swp0b = swizzle0044(self.w_axis.0, self.z_axis.0);
744
745                let swp00 = swizzle0044(self.z_axis.0, self.y_axis.0);
746                let swp01 = swizzle0046(swp0a, swp0a);
747                let swp02 = swizzle0046(swp0b, swp0b);
748                let swp03 = swizzle1155(self.z_axis.0, self.y_axis.0);
749
750                let mul00 = vmulq_f32(swp00, swp01);
751                let mul01 = vmulq_f32(swp02, swp03);
752                vsubq_f32(mul00, mul01)
753            };
754
755            const SIGN_A: float32x4_t = Vec4::new(-1.0, 1.0, -1.0, 1.0).0;
756            const SIGN_B: float32x4_t = Vec4::new(1.0, -1.0, 1.0, -1.0).0;
757
758            let temp0 = swizzle0044(self.y_axis.0, self.x_axis.0);
759            let vec0 = swizzle0266(temp0, temp0);
760
761            let temp1 = swizzle1155(self.y_axis.0, self.x_axis.0);
762            let vec1 = swizzle0266(temp1, temp1);
763
764            let temp2 = swizzle2266(self.y_axis.0, self.x_axis.0);
765            let vec2 = swizzle0266(temp2, temp2);
766
767            let temp3 = swizzle3377(self.y_axis.0, self.x_axis.0);
768            let vec3 = swizzle0266(temp3, temp3);
769
770            let mul00 = vmulq_f32(vec1, fac0);
771            let mul01 = vmulq_f32(vec2, fac1);
772            let mul02 = vmulq_f32(vec3, fac2);
773            let sub00 = vsubq_f32(mul00, mul01);
774            let add00 = vaddq_f32(sub00, mul02);
775            let inv0 = vmulq_f32(SIGN_B, add00);
776
777            let mul03 = vmulq_f32(vec0, fac0);
778            let mul04 = vmulq_f32(vec2, fac3);
779            let mul05 = vmulq_f32(vec3, fac4);
780            let sub01 = vsubq_f32(mul03, mul04);
781            let add01 = vaddq_f32(sub01, mul05);
782            let inv1 = vmulq_f32(SIGN_A, add01);
783
784            let mul06 = vmulq_f32(vec0, fac1);
785            let mul07 = vmulq_f32(vec1, fac3);
786            let mul08 = vmulq_f32(vec3, fac5);
787            let sub02 = vsubq_f32(mul06, mul07);
788            let add02 = vaddq_f32(sub02, mul08);
789            let inv2 = vmulq_f32(SIGN_B, add02);
790
791            let mul09 = vmulq_f32(vec0, fac2);
792            let mul10 = vmulq_f32(vec1, fac4);
793            let mul11 = vmulq_f32(vec2, fac5);
794            let sub03 = vsubq_f32(mul09, mul10);
795            let add03 = vaddq_f32(sub03, mul11);
796            let inv3 = vmulq_f32(SIGN_A, add03);
797
798            let row0 = swizzle0044(inv0, inv1);
799            let row1 = swizzle0044(inv2, inv3);
800            let row2 = swizzle0246(row0, row1);
801
802            let dot0 = dot4(self.x_axis.0, row2);
803            glam_assert!(dot0 != 0.0);
804
805            let rcp0 = dot0.recip();
806
807            Self {
808                x_axis: Vec4(vmulq_n_f32(inv0, rcp0)),
809                y_axis: Vec4(vmulq_n_f32(inv1, rcp0)),
810                z_axis: Vec4(vmulq_n_f32(inv2, rcp0)),
811                w_axis: Vec4(vmulq_n_f32(inv3, rcp0)),
812            }
813        }
814    }
815
816    /// Creates a left-handed view matrix using a camera position, a facing direction and an up
817    /// direction
818    ///
819    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
820    ///
821    /// # Panics
822    ///
823    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
824    #[inline]
825    #[must_use]
826    pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
827        Self::look_to_rh(eye, -dir, up)
828    }
829
830    /// Creates a right-handed view matrix using a camera position, a facing direction, and an up
831    /// direction.
832    ///
833    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
834    ///
835    /// # Panics
836    ///
837    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
838    #[inline]
839    #[must_use]
840    pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
841        glam_assert!(dir.is_normalized());
842        glam_assert!(up.is_normalized());
843        let f = dir;
844        let s = f.cross(up).normalize();
845        let u = s.cross(f);
846
847        Self::from_cols(
848            Vec4::new(s.x, u.x, -f.x, 0.0),
849            Vec4::new(s.y, u.y, -f.y, 0.0),
850            Vec4::new(s.z, u.z, -f.z, 0.0),
851            Vec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
852        )
853    }
854
855    /// Creates a left-handed view matrix using a camera position, a focal points and an up
856    /// direction.
857    ///
858    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
859    ///
860    /// # Panics
861    ///
862    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
863    #[inline]
864    #[must_use]
865    pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
866        Self::look_to_lh(eye, center.sub(eye).normalize(), up)
867    }
868
869    /// Creates a right-handed view matrix using a camera position, a focal point, and an up
870    /// direction.
871    ///
872    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
873    ///
874    /// # Panics
875    ///
876    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
877    #[inline]
878    pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
879        Self::look_to_rh(eye, center.sub(eye).normalize(), up)
880    }
881
882    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
883    ///
884    /// This is the same as the OpenGL `glFurstum` function.
885    ///
886    /// See <https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glFrustum.xml>
887    #[inline]
888    #[must_use]
889    pub fn frustum_rh_gl(
890        left: f32,
891        right: f32,
892        bottom: f32,
893        top: f32,
894        z_near: f32,
895        z_far: f32,
896    ) -> Self {
897        let inv_width = 1.0 / (right - left);
898        let inv_height = 1.0 / (top - bottom);
899        let inv_depth = 1.0 / (z_far - z_near);
900        let a = (right + left) * inv_width;
901        let b = (top + bottom) * inv_height;
902        let c = -(z_far + z_near) * inv_depth;
903        let d = -(2.0 * z_far * z_near) * inv_depth;
904        let two_z_near = 2.0 * z_near;
905        Self::from_cols(
906            Vec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
907            Vec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
908            Vec4::new(a, b, c, -1.0),
909            Vec4::new(0.0, 0.0, d, 0.0),
910        )
911    }
912
913    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
914    ///
915    /// # Panics
916    ///
917    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
918    /// enabled.
919    #[inline]
920    #[must_use]
921    pub fn frustum_lh(
922        left: f32,
923        right: f32,
924        bottom: f32,
925        top: f32,
926        z_near: f32,
927        z_far: f32,
928    ) -> Self {
929        glam_assert!(z_near > 0.0 && z_far > 0.0);
930        let inv_width = 1.0 / (right - left);
931        let inv_height = 1.0 / (top - bottom);
932        let inv_depth = 1.0 / (z_far - z_near);
933        let a = (right + left) * inv_width;
934        let b = (top + bottom) * inv_height;
935        let c = z_far * inv_depth;
936        let d = -(z_far * z_near) * inv_depth;
937        let two_z_near = 2.0 * z_near;
938        Self::from_cols(
939            Vec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
940            Vec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
941            Vec4::new(a, b, c, 1.0),
942            Vec4::new(0.0, 0.0, d, 0.0),
943        )
944    }
945
946    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
947    ///
948    /// # Panics
949    ///
950    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
951    /// enabled.
952    #[inline]
953    #[must_use]
954    pub fn frustum_rh(
955        left: f32,
956        right: f32,
957        bottom: f32,
958        top: f32,
959        z_near: f32,
960        z_far: f32,
961    ) -> Self {
962        glam_assert!(z_near > 0.0 && z_far > 0.0);
963        let inv_width = 1.0 / (right - left);
964        let inv_height = 1.0 / (top - bottom);
965        let inv_depth = 1.0 / (z_far - z_near);
966        let a = (right + left) * inv_width;
967        let b = (top + bottom) * inv_height;
968        let c = -z_far * inv_depth;
969        let d = -(z_far * z_near) * inv_depth;
970        let two_z_near = 2.0 * z_near;
971        Self::from_cols(
972            Vec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
973            Vec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
974            Vec4::new(a, b, c, -1.0),
975            Vec4::new(0.0, 0.0, d, 0.0),
976        )
977    }
978
979    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
980    ///
981    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
982    ///
983    /// This is the same as the OpenGL `gluPerspective` function.
984    /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
985    #[inline]
986    #[must_use]
987    pub fn perspective_rh_gl(
988        fov_y_radians: f32,
989        aspect_ratio: f32,
990        z_near: f32,
991        z_far: f32,
992    ) -> Self {
993        let inv_length = 1.0 / (z_near - z_far);
994        let f = 1.0 / math::tan(0.5 * fov_y_radians);
995        let a = f / aspect_ratio;
996        let b = (z_near + z_far) * inv_length;
997        let c = (2.0 * z_near * z_far) * inv_length;
998        Self::from_cols(
999            Vec4::new(a, 0.0, 0.0, 0.0),
1000            Vec4::new(0.0, f, 0.0, 0.0),
1001            Vec4::new(0.0, 0.0, b, -1.0),
1002            Vec4::new(0.0, 0.0, c, 0.0),
1003        )
1004    }
1005
1006    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
1007    ///
1008    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
1009    ///
1010    /// # Panics
1011    ///
1012    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1013    /// enabled.
1014    #[inline]
1015    #[must_use]
1016    pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
1017        glam_assert!(z_near > 0.0 && z_far > 0.0);
1018        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1019        let h = cos_fov / sin_fov;
1020        let w = h / aspect_ratio;
1021        let r = z_far / (z_far - z_near);
1022        Self::from_cols(
1023            Vec4::new(w, 0.0, 0.0, 0.0),
1024            Vec4::new(0.0, h, 0.0, 0.0),
1025            Vec4::new(0.0, 0.0, r, 1.0),
1026            Vec4::new(0.0, 0.0, -r * z_near, 0.0),
1027        )
1028    }
1029
1030    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
1031    ///
1032    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
1033    ///
1034    /// # Panics
1035    ///
1036    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1037    /// enabled.
1038    #[inline]
1039    #[must_use]
1040    pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
1041        glam_assert!(z_near > 0.0 && z_far > 0.0);
1042        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1043        let h = cos_fov / sin_fov;
1044        let w = h / aspect_ratio;
1045        let r = z_far / (z_near - z_far);
1046        Self::from_cols(
1047            Vec4::new(w, 0.0, 0.0, 0.0),
1048            Vec4::new(0.0, h, 0.0, 0.0),
1049            Vec4::new(0.0, 0.0, r, -1.0),
1050            Vec4::new(0.0, 0.0, r * z_near, 0.0),
1051        )
1052    }
1053
1054    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
1055    ///
1056    /// Like `perspective_lh`, but with an infinite value for `z_far`.
1057    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
1058    ///
1059    /// # Panics
1060    ///
1061    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1062    /// enabled.
1063    #[inline]
1064    #[must_use]
1065    pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
1066        glam_assert!(z_near > 0.0);
1067        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1068        let h = cos_fov / sin_fov;
1069        let w = h / aspect_ratio;
1070        Self::from_cols(
1071            Vec4::new(w, 0.0, 0.0, 0.0),
1072            Vec4::new(0.0, h, 0.0, 0.0),
1073            Vec4::new(0.0, 0.0, 1.0, 1.0),
1074            Vec4::new(0.0, 0.0, -z_near, 0.0),
1075        )
1076    }
1077
1078    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
1079    ///
1080    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
1081    ///
1082    /// # Panics
1083    ///
1084    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
1085    #[inline]
1086    #[must_use]
1087    pub fn perspective_infinite_reverse_lh(
1088        fov_y_radians: f32,
1089        aspect_ratio: f32,
1090        z_near: f32,
1091    ) -> Self {
1092        glam_assert!(z_near > 0.0);
1093        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1094        let h = cos_fov / sin_fov;
1095        let w = h / aspect_ratio;
1096        Self::from_cols(
1097            Vec4::new(w, 0.0, 0.0, 0.0),
1098            Vec4::new(0.0, h, 0.0, 0.0),
1099            Vec4::new(0.0, 0.0, 0.0, 1.0),
1100            Vec4::new(0.0, 0.0, z_near, 0.0),
1101        )
1102    }
1103
1104    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
1105    ///
1106    /// Like `perspective_rh`, but with an infinite value for `z_far`.
1107    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
1108    ///
1109    /// # Panics
1110    ///
1111    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1112    /// enabled.
1113    #[inline]
1114    #[must_use]
1115    pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
1116        glam_assert!(z_near > 0.0);
1117        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1118        Self::from_cols(
1119            Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1120            Vec4::new(0.0, f, 0.0, 0.0),
1121            Vec4::new(0.0, 0.0, -1.0, -1.0),
1122            Vec4::new(0.0, 0.0, -z_near, 0.0),
1123        )
1124    }
1125
1126    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
1127    ///
1128    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
1129    ///
1130    /// # Panics
1131    ///
1132    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
1133    #[inline]
1134    #[must_use]
1135    pub fn perspective_infinite_reverse_rh(
1136        fov_y_radians: f32,
1137        aspect_ratio: f32,
1138        z_near: f32,
1139    ) -> Self {
1140        glam_assert!(z_near > 0.0);
1141        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1142        Self::from_cols(
1143            Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1144            Vec4::new(0.0, f, 0.0, 0.0),
1145            Vec4::new(0.0, 0.0, 0.0, -1.0),
1146            Vec4::new(0.0, 0.0, z_near, 0.0),
1147        )
1148    }
1149
1150    /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
1151    /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
1152    /// See
1153    /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
1154    ///
1155    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
1156    #[inline]
1157    #[must_use]
1158    pub fn orthographic_rh_gl(
1159        left: f32,
1160        right: f32,
1161        bottom: f32,
1162        top: f32,
1163        near: f32,
1164        far: f32,
1165    ) -> Self {
1166        let a = 2.0 / (right - left);
1167        let b = 2.0 / (top - bottom);
1168        let c = -2.0 / (far - near);
1169        let tx = -(right + left) / (right - left);
1170        let ty = -(top + bottom) / (top - bottom);
1171        let tz = -(far + near) / (far - near);
1172
1173        Self::from_cols(
1174            Vec4::new(a, 0.0, 0.0, 0.0),
1175            Vec4::new(0.0, b, 0.0, 0.0),
1176            Vec4::new(0.0, 0.0, c, 0.0),
1177            Vec4::new(tx, ty, tz, 1.0),
1178        )
1179    }
1180
1181    /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
1182    ///
1183    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1184    #[inline]
1185    #[must_use]
1186    pub fn orthographic_lh(
1187        left: f32,
1188        right: f32,
1189        bottom: f32,
1190        top: f32,
1191        near: f32,
1192        far: f32,
1193    ) -> Self {
1194        let rcp_width = 1.0 / (right - left);
1195        let rcp_height = 1.0 / (top - bottom);
1196        let r = 1.0 / (far - near);
1197        Self::from_cols(
1198            Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1199            Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1200            Vec4::new(0.0, 0.0, r, 0.0),
1201            Vec4::new(
1202                -(left + right) * rcp_width,
1203                -(top + bottom) * rcp_height,
1204                -r * near,
1205                1.0,
1206            ),
1207        )
1208    }
1209
1210    /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
1211    ///
1212    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1213    #[inline]
1214    #[must_use]
1215    pub fn orthographic_rh(
1216        left: f32,
1217        right: f32,
1218        bottom: f32,
1219        top: f32,
1220        near: f32,
1221        far: f32,
1222    ) -> Self {
1223        let rcp_width = 1.0 / (right - left);
1224        let rcp_height = 1.0 / (top - bottom);
1225        let r = 1.0 / (near - far);
1226        Self::from_cols(
1227            Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1228            Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1229            Vec4::new(0.0, 0.0, r, 0.0),
1230            Vec4::new(
1231                -(left + right) * rcp_width,
1232                -(top + bottom) * rcp_height,
1233                r * near,
1234                1.0,
1235            ),
1236        )
1237    }
1238
1239    /// Transforms the given 3D vector as a point, applying perspective correction.
1240    ///
1241    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
1242    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1243    ///
1244    /// This method assumes that `self` contains a projective transform.
1245    #[inline]
1246    #[must_use]
1247    pub fn project_point3(&self, rhs: Vec3) -> Vec3 {
1248        let mut res = self.x_axis.mul(rhs.x);
1249        res = self.y_axis.mul(rhs.y).add(res);
1250        res = self.z_axis.mul(rhs.z).add(res);
1251        res = self.w_axis.add(res);
1252        res = res.div(res.w);
1253        res.xyz()
1254    }
1255
1256    /// Transforms the given 3D vector as a point.
1257    ///
1258    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1259    /// `1.0`.
1260    ///
1261    /// This method assumes that `self` contains a valid affine transform. It does not perform
1262    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
1263    /// the [`Self::project_point3()`] method should be used instead.
1264    ///
1265    /// # Panics
1266    ///
1267    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1268    #[inline]
1269    #[must_use]
1270    pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
1271        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1272        let mut res = self.x_axis.mul(rhs.x);
1273        res = self.y_axis.mul(rhs.y).add(res);
1274        res = self.z_axis.mul(rhs.z).add(res);
1275        res = self.w_axis.add(res);
1276        res.xyz()
1277    }
1278
1279    /// Transforms the give 3D vector as a direction.
1280    ///
1281    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1282    /// `0.0`.
1283    ///
1284    /// This method assumes that `self` contains a valid affine transform.
1285    ///
1286    /// # Panics
1287    ///
1288    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1289    #[inline]
1290    #[must_use]
1291    pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
1292        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1293        let mut res = self.x_axis.mul(rhs.x);
1294        res = self.y_axis.mul(rhs.y).add(res);
1295        res = self.z_axis.mul(rhs.z).add(res);
1296        res.xyz()
1297    }
1298
1299    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
1300    ///
1301    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
1302    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1303    ///
1304    /// This method assumes that `self` contains a projective transform.
1305    #[inline]
1306    #[must_use]
1307    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
1308        let mut res = self.x_axis.mul(rhs.xxxx());
1309        res = self.y_axis.mul(rhs.yyyy()).add(res);
1310        res = self.z_axis.mul(rhs.zzzz()).add(res);
1311        res = self.w_axis.add(res);
1312        res = res.div(res.wwww());
1313        Vec3A::from_vec4(res)
1314    }
1315
1316    /// Transforms the given [`Vec3A`] as 3D point.
1317    ///
1318    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
1319    #[inline]
1320    #[must_use]
1321    pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
1322        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1323        let mut res = self.x_axis.mul(rhs.xxxx());
1324        res = self.y_axis.mul(rhs.yyyy()).add(res);
1325        res = self.z_axis.mul(rhs.zzzz()).add(res);
1326        res = self.w_axis.add(res);
1327        Vec3A::from_vec4(res)
1328    }
1329
1330    /// Transforms the give [`Vec3A`] as 3D vector.
1331    ///
1332    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `0.0`.
1333    #[inline]
1334    #[must_use]
1335    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
1336        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1337        let mut res = self.x_axis.mul(rhs.xxxx());
1338        res = self.y_axis.mul(rhs.yyyy()).add(res);
1339        res = self.z_axis.mul(rhs.zzzz()).add(res);
1340        Vec3A::from_vec4(res)
1341    }
1342
1343    /// Transforms a 4D vector.
1344    #[inline]
1345    #[must_use]
1346    pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 {
1347        let mut res = self.x_axis.mul(rhs.xxxx());
1348        res = res.add(self.y_axis.mul(rhs.yyyy()));
1349        res = res.add(self.z_axis.mul(rhs.zzzz()));
1350        res = res.add(self.w_axis.mul(rhs.wwww()));
1351        res
1352    }
1353
1354    /// Multiplies two 4x4 matrices.
1355    #[inline]
1356    #[must_use]
1357    pub fn mul_mat4(&self, rhs: &Self) -> Self {
1358        self.mul(rhs)
1359    }
1360
1361    /// Adds two 4x4 matrices.
1362    #[inline]
1363    #[must_use]
1364    pub fn add_mat4(&self, rhs: &Self) -> Self {
1365        self.add(rhs)
1366    }
1367
1368    /// Subtracts two 4x4 matrices.
1369    #[inline]
1370    #[must_use]
1371    pub fn sub_mat4(&self, rhs: &Self) -> Self {
1372        self.sub(rhs)
1373    }
1374
1375    /// Multiplies a 4x4 matrix by a scalar.
1376    #[inline]
1377    #[must_use]
1378    pub fn mul_scalar(&self, rhs: f32) -> Self {
1379        Self::from_cols(
1380            self.x_axis.mul(rhs),
1381            self.y_axis.mul(rhs),
1382            self.z_axis.mul(rhs),
1383            self.w_axis.mul(rhs),
1384        )
1385    }
1386
1387    /// Divides a 4x4 matrix by a scalar.
1388    #[inline]
1389    #[must_use]
1390    pub fn div_scalar(&self, rhs: f32) -> Self {
1391        let rhs = Vec4::splat(rhs);
1392        Self::from_cols(
1393            self.x_axis.div(rhs),
1394            self.y_axis.div(rhs),
1395            self.z_axis.div(rhs),
1396            self.w_axis.div(rhs),
1397        )
1398    }
1399
1400    /// Returns true if the absolute difference of all elements between `self` and `rhs`
1401    /// is less than or equal to `max_abs_diff`.
1402    ///
1403    /// This can be used to compare if two matrices contain similar elements. It works best
1404    /// when comparing with a known value. The `max_abs_diff` that should be used used
1405    /// depends on the values being compared against.
1406    ///
1407    /// For more see
1408    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
1409    #[inline]
1410    #[must_use]
1411    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
1412        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1413            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1414            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1415            && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1416    }
1417
1418    /// Takes the absolute value of each element in `self`
1419    #[inline]
1420    #[must_use]
1421    pub fn abs(&self) -> Self {
1422        Self::from_cols(
1423            self.x_axis.abs(),
1424            self.y_axis.abs(),
1425            self.z_axis.abs(),
1426            self.w_axis.abs(),
1427        )
1428    }
1429
1430    #[inline]
1431    pub fn as_dmat4(&self) -> DMat4 {
1432        DMat4::from_cols(
1433            self.x_axis.as_dvec4(),
1434            self.y_axis.as_dvec4(),
1435            self.z_axis.as_dvec4(),
1436            self.w_axis.as_dvec4(),
1437        )
1438    }
1439}
1440
1441impl Default for Mat4 {
1442    #[inline]
1443    fn default() -> Self {
1444        Self::IDENTITY
1445    }
1446}
1447
1448impl Add for Mat4 {
1449    type Output = Self;
1450    #[inline]
1451    fn add(self, rhs: Self) -> Self {
1452        Self::from_cols(
1453            self.x_axis.add(rhs.x_axis),
1454            self.y_axis.add(rhs.y_axis),
1455            self.z_axis.add(rhs.z_axis),
1456            self.w_axis.add(rhs.w_axis),
1457        )
1458    }
1459}
1460
1461impl Add<&Self> for Mat4 {
1462    type Output = Self;
1463    #[inline]
1464    fn add(self, rhs: &Self) -> Self {
1465        self.add(*rhs)
1466    }
1467}
1468
1469impl Add<&Mat4> for &Mat4 {
1470    type Output = Mat4;
1471    #[inline]
1472    fn add(self, rhs: &Mat4) -> Mat4 {
1473        (*self).add(*rhs)
1474    }
1475}
1476
1477impl Add<Mat4> for &Mat4 {
1478    type Output = Mat4;
1479    #[inline]
1480    fn add(self, rhs: Mat4) -> Mat4 {
1481        (*self).add(rhs)
1482    }
1483}
1484
1485impl AddAssign for Mat4 {
1486    #[inline]
1487    fn add_assign(&mut self, rhs: Self) {
1488        *self = self.add(rhs);
1489    }
1490}
1491
1492impl AddAssign<&Self> for Mat4 {
1493    #[inline]
1494    fn add_assign(&mut self, rhs: &Self) {
1495        self.add_assign(*rhs);
1496    }
1497}
1498
1499impl Sub for Mat4 {
1500    type Output = Self;
1501    #[inline]
1502    fn sub(self, rhs: Self) -> Self {
1503        Self::from_cols(
1504            self.x_axis.sub(rhs.x_axis),
1505            self.y_axis.sub(rhs.y_axis),
1506            self.z_axis.sub(rhs.z_axis),
1507            self.w_axis.sub(rhs.w_axis),
1508        )
1509    }
1510}
1511
1512impl Sub<&Self> for Mat4 {
1513    type Output = Self;
1514    #[inline]
1515    fn sub(self, rhs: &Self) -> Self {
1516        self.sub(*rhs)
1517    }
1518}
1519
1520impl Sub<&Mat4> for &Mat4 {
1521    type Output = Mat4;
1522    #[inline]
1523    fn sub(self, rhs: &Mat4) -> Mat4 {
1524        (*self).sub(*rhs)
1525    }
1526}
1527
1528impl Sub<Mat4> for &Mat4 {
1529    type Output = Mat4;
1530    #[inline]
1531    fn sub(self, rhs: Mat4) -> Mat4 {
1532        (*self).sub(rhs)
1533    }
1534}
1535
1536impl SubAssign for Mat4 {
1537    #[inline]
1538    fn sub_assign(&mut self, rhs: Self) {
1539        *self = self.sub(rhs);
1540    }
1541}
1542
1543impl SubAssign<&Self> for Mat4 {
1544    #[inline]
1545    fn sub_assign(&mut self, rhs: &Self) {
1546        self.sub_assign(*rhs);
1547    }
1548}
1549
1550impl Neg for Mat4 {
1551    type Output = Self;
1552    #[inline]
1553    fn neg(self) -> Self::Output {
1554        Self::from_cols(
1555            self.x_axis.neg(),
1556            self.y_axis.neg(),
1557            self.z_axis.neg(),
1558            self.w_axis.neg(),
1559        )
1560    }
1561}
1562
1563impl Neg for &Mat4 {
1564    type Output = Mat4;
1565    #[inline]
1566    fn neg(self) -> Mat4 {
1567        (*self).neg()
1568    }
1569}
1570
1571impl Mul for Mat4 {
1572    type Output = Self;
1573    #[inline]
1574    fn mul(self, rhs: Self) -> Self {
1575        Self::from_cols(
1576            self.mul(rhs.x_axis),
1577            self.mul(rhs.y_axis),
1578            self.mul(rhs.z_axis),
1579            self.mul(rhs.w_axis),
1580        )
1581    }
1582}
1583
1584impl Mul<&Self> for Mat4 {
1585    type Output = Self;
1586    #[inline]
1587    fn mul(self, rhs: &Self) -> Self {
1588        self.mul(*rhs)
1589    }
1590}
1591
1592impl Mul<&Mat4> for &Mat4 {
1593    type Output = Mat4;
1594    #[inline]
1595    fn mul(self, rhs: &Mat4) -> Mat4 {
1596        (*self).mul(*rhs)
1597    }
1598}
1599
1600impl Mul<Mat4> for &Mat4 {
1601    type Output = Mat4;
1602    #[inline]
1603    fn mul(self, rhs: Mat4) -> Mat4 {
1604        (*self).mul(rhs)
1605    }
1606}
1607
1608impl MulAssign for Mat4 {
1609    #[inline]
1610    fn mul_assign(&mut self, rhs: Self) {
1611        *self = self.mul(rhs);
1612    }
1613}
1614
1615impl MulAssign<&Self> for Mat4 {
1616    #[inline]
1617    fn mul_assign(&mut self, rhs: &Self) {
1618        self.mul_assign(*rhs);
1619    }
1620}
1621
1622impl Mul<Vec4> for Mat4 {
1623    type Output = Vec4;
1624    #[inline]
1625    fn mul(self, rhs: Vec4) -> Self::Output {
1626        self.mul_vec4(rhs)
1627    }
1628}
1629
1630impl Mul<&Vec4> for Mat4 {
1631    type Output = Vec4;
1632    #[inline]
1633    fn mul(self, rhs: &Vec4) -> Vec4 {
1634        self.mul(*rhs)
1635    }
1636}
1637
1638impl Mul<&Vec4> for &Mat4 {
1639    type Output = Vec4;
1640    #[inline]
1641    fn mul(self, rhs: &Vec4) -> Vec4 {
1642        (*self).mul(*rhs)
1643    }
1644}
1645
1646impl Mul<Vec4> for &Mat4 {
1647    type Output = Vec4;
1648    #[inline]
1649    fn mul(self, rhs: Vec4) -> Vec4 {
1650        (*self).mul(rhs)
1651    }
1652}
1653
1654impl Mul<Mat4> for f32 {
1655    type Output = Mat4;
1656    #[inline]
1657    fn mul(self, rhs: Mat4) -> Self::Output {
1658        rhs.mul_scalar(self)
1659    }
1660}
1661
1662impl Mul<&Mat4> for f32 {
1663    type Output = Mat4;
1664    #[inline]
1665    fn mul(self, rhs: &Mat4) -> Mat4 {
1666        self.mul(*rhs)
1667    }
1668}
1669
1670impl Mul<&Mat4> for &f32 {
1671    type Output = Mat4;
1672    #[inline]
1673    fn mul(self, rhs: &Mat4) -> Mat4 {
1674        (*self).mul(*rhs)
1675    }
1676}
1677
1678impl Mul<Mat4> for &f32 {
1679    type Output = Mat4;
1680    #[inline]
1681    fn mul(self, rhs: Mat4) -> Mat4 {
1682        (*self).mul(rhs)
1683    }
1684}
1685
1686impl Mul<f32> for Mat4 {
1687    type Output = Self;
1688    #[inline]
1689    fn mul(self, rhs: f32) -> Self {
1690        self.mul_scalar(rhs)
1691    }
1692}
1693
1694impl Mul<&f32> for Mat4 {
1695    type Output = Self;
1696    #[inline]
1697    fn mul(self, rhs: &f32) -> Self {
1698        self.mul(*rhs)
1699    }
1700}
1701
1702impl Mul<&f32> for &Mat4 {
1703    type Output = Mat4;
1704    #[inline]
1705    fn mul(self, rhs: &f32) -> Mat4 {
1706        (*self).mul(*rhs)
1707    }
1708}
1709
1710impl Mul<f32> for &Mat4 {
1711    type Output = Mat4;
1712    #[inline]
1713    fn mul(self, rhs: f32) -> Mat4 {
1714        (*self).mul(rhs)
1715    }
1716}
1717
1718impl MulAssign<f32> for Mat4 {
1719    #[inline]
1720    fn mul_assign(&mut self, rhs: f32) {
1721        *self = self.mul(rhs);
1722    }
1723}
1724
1725impl MulAssign<&f32> for Mat4 {
1726    #[inline]
1727    fn mul_assign(&mut self, rhs: &f32) {
1728        self.mul_assign(*rhs);
1729    }
1730}
1731
1732impl Div<Mat4> for f32 {
1733    type Output = Mat4;
1734    #[inline]
1735    fn div(self, rhs: Mat4) -> Self::Output {
1736        rhs.div_scalar(self)
1737    }
1738}
1739
1740impl Div<&Mat4> for f32 {
1741    type Output = Mat4;
1742    #[inline]
1743    fn div(self, rhs: &Mat4) -> Mat4 {
1744        self.div(*rhs)
1745    }
1746}
1747
1748impl Div<&Mat4> for &f32 {
1749    type Output = Mat4;
1750    #[inline]
1751    fn div(self, rhs: &Mat4) -> Mat4 {
1752        (*self).div(*rhs)
1753    }
1754}
1755
1756impl Div<Mat4> for &f32 {
1757    type Output = Mat4;
1758    #[inline]
1759    fn div(self, rhs: Mat4) -> Mat4 {
1760        (*self).div(rhs)
1761    }
1762}
1763
1764impl Div<f32> for Mat4 {
1765    type Output = Self;
1766    #[inline]
1767    fn div(self, rhs: f32) -> Self {
1768        self.div_scalar(rhs)
1769    }
1770}
1771
1772impl Div<&f32> for Mat4 {
1773    type Output = Self;
1774    #[inline]
1775    fn div(self, rhs: &f32) -> Self {
1776        self.div(*rhs)
1777    }
1778}
1779
1780impl Div<&f32> for &Mat4 {
1781    type Output = Mat4;
1782    #[inline]
1783    fn div(self, rhs: &f32) -> Mat4 {
1784        (*self).div(*rhs)
1785    }
1786}
1787
1788impl Div<f32> for &Mat4 {
1789    type Output = Mat4;
1790    #[inline]
1791    fn div(self, rhs: f32) -> Mat4 {
1792        (*self).div(rhs)
1793    }
1794}
1795
1796impl DivAssign<f32> for Mat4 {
1797    #[inline]
1798    fn div_assign(&mut self, rhs: f32) {
1799        *self = self.div(rhs);
1800    }
1801}
1802
1803impl DivAssign<&f32> for Mat4 {
1804    #[inline]
1805    fn div_assign(&mut self, rhs: &f32) {
1806        self.div_assign(*rhs);
1807    }
1808}
1809
1810impl Sum<Self> for Mat4 {
1811    fn sum<I>(iter: I) -> Self
1812    where
1813        I: Iterator<Item = Self>,
1814    {
1815        iter.fold(Self::ZERO, Self::add)
1816    }
1817}
1818
1819impl<'a> Sum<&'a Self> for Mat4 {
1820    fn sum<I>(iter: I) -> Self
1821    where
1822        I: Iterator<Item = &'a Self>,
1823    {
1824        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1825    }
1826}
1827
1828impl Product for Mat4 {
1829    fn product<I>(iter: I) -> Self
1830    where
1831        I: Iterator<Item = Self>,
1832    {
1833        iter.fold(Self::IDENTITY, Self::mul)
1834    }
1835}
1836
1837impl<'a> Product<&'a Self> for Mat4 {
1838    fn product<I>(iter: I) -> Self
1839    where
1840        I: Iterator<Item = &'a Self>,
1841    {
1842        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1843    }
1844}
1845
1846impl PartialEq for Mat4 {
1847    #[inline]
1848    fn eq(&self, rhs: &Self) -> bool {
1849        self.x_axis.eq(&rhs.x_axis)
1850            && self.y_axis.eq(&rhs.y_axis)
1851            && self.z_axis.eq(&rhs.z_axis)
1852            && self.w_axis.eq(&rhs.w_axis)
1853    }
1854}
1855
1856impl AsRef<[f32; 16]> for Mat4 {
1857    #[inline]
1858    fn as_ref(&self) -> &[f32; 16] {
1859        unsafe { &*(self as *const Self as *const [f32; 16]) }
1860    }
1861}
1862
1863impl AsMut<[f32; 16]> for Mat4 {
1864    #[inline]
1865    fn as_mut(&mut self) -> &mut [f32; 16] {
1866        unsafe { &mut *(self as *mut Self as *mut [f32; 16]) }
1867    }
1868}
1869
1870impl fmt::Debug for Mat4 {
1871    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1872        fmt.debug_struct(stringify!(Mat4))
1873            .field("x_axis", &self.x_axis)
1874            .field("y_axis", &self.y_axis)
1875            .field("z_axis", &self.z_axis)
1876            .field("w_axis", &self.w_axis)
1877            .finish()
1878    }
1879}
1880
1881impl fmt::Display for Mat4 {
1882    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1883        if let Some(p) = f.precision() {
1884            write!(
1885                f,
1886                "[{:.*}, {:.*}, {:.*}, {:.*}]",
1887                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
1888            )
1889        } else {
1890            write!(
1891                f,
1892                "[{}, {}, {}, {}]",
1893                self.x_axis, self.y_axis, self.z_axis, self.w_axis
1894            )
1895        }
1896    }
1897}