1use crate::{
4 euler::{FromEuler, ToEuler},
5 f32::math,
6 sse2::*,
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
14#[cfg(target_arch = "x86")]
15use core::arch::x86::*;
16#[cfg(target_arch = "x86_64")]
17use core::arch::x86_64::*;
18
19#[inline(always)]
21#[must_use]
22pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 {
23 Mat4::from_cols(x_axis, y_axis, z_axis, w_axis)
24}
25
26#[derive(Clone, Copy)]
56#[repr(C)]
57pub struct Mat4 {
58 pub x_axis: Vec4,
59 pub y_axis: Vec4,
60 pub z_axis: Vec4,
61 pub w_axis: Vec4,
62}
63
64impl Mat4 {
65 pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO);
67
68 pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W);
70
71 pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN);
73
74 #[allow(clippy::too_many_arguments)]
75 #[inline(always)]
76 #[must_use]
77 const fn new(
78 m00: f32,
79 m01: f32,
80 m02: f32,
81 m03: f32,
82 m10: f32,
83 m11: f32,
84 m12: f32,
85 m13: f32,
86 m20: f32,
87 m21: f32,
88 m22: f32,
89 m23: f32,
90 m30: f32,
91 m31: f32,
92 m32: f32,
93 m33: f32,
94 ) -> Self {
95 Self {
96 x_axis: Vec4::new(m00, m01, m02, m03),
97 y_axis: Vec4::new(m10, m11, m12, m13),
98 z_axis: Vec4::new(m20, m21, m22, m23),
99 w_axis: Vec4::new(m30, m31, m32, m33),
100 }
101 }
102
103 #[inline(always)]
105 #[must_use]
106 pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self {
107 Self {
108 x_axis,
109 y_axis,
110 z_axis,
111 w_axis,
112 }
113 }
114
115 #[inline]
119 #[must_use]
120 pub const fn from_cols_array(m: &[f32; 16]) -> Self {
121 Self::new(
122 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],
123 m[14], m[15],
124 )
125 }
126
127 #[inline]
130 #[must_use]
131 pub const fn to_cols_array(&self) -> [f32; 16] {
132 let [x_axis_x, x_axis_y, x_axis_z, x_axis_w] = self.x_axis.to_array();
133 let [y_axis_x, y_axis_y, y_axis_z, y_axis_w] = self.y_axis.to_array();
134 let [z_axis_x, z_axis_y, z_axis_z, z_axis_w] = self.z_axis.to_array();
135 let [w_axis_x, w_axis_y, w_axis_z, w_axis_w] = self.w_axis.to_array();
136
137 [
138 x_axis_x, x_axis_y, x_axis_z, x_axis_w, y_axis_x, y_axis_y, y_axis_z, y_axis_w,
139 z_axis_x, z_axis_y, z_axis_z, z_axis_w, w_axis_x, w_axis_y, w_axis_z, w_axis_w,
140 ]
141 }
142
143 #[inline]
147 #[must_use]
148 pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self {
149 Self::from_cols(
150 Vec4::from_array(m[0]),
151 Vec4::from_array(m[1]),
152 Vec4::from_array(m[2]),
153 Vec4::from_array(m[3]),
154 )
155 }
156
157 #[inline]
160 #[must_use]
161 pub const fn to_cols_array_2d(&self) -> [[f32; 4]; 4] {
162 [
163 self.x_axis.to_array(),
164 self.y_axis.to_array(),
165 self.z_axis.to_array(),
166 self.w_axis.to_array(),
167 ]
168 }
169
170 #[doc(alias = "scale")]
172 #[inline]
173 #[must_use]
174 pub const fn from_diagonal(diagonal: Vec4) -> Self {
175 let [x, y, z, w] = diagonal.to_array();
177 Self::new(
178 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,
179 )
180 }
181
182 #[inline]
183 #[must_use]
184 fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) {
185 glam_assert!(rotation.is_normalized());
186
187 let (x, y, z, w) = rotation.into();
188 let x2 = x + x;
189 let y2 = y + y;
190 let z2 = z + z;
191 let xx = x * x2;
192 let xy = x * y2;
193 let xz = x * z2;
194 let yy = y * y2;
195 let yz = y * z2;
196 let zz = z * z2;
197 let wx = w * x2;
198 let wy = w * y2;
199 let wz = w * z2;
200
201 let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
202 let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
203 let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
204 (x_axis, y_axis, z_axis)
205 }
206
207 #[inline]
217 #[must_use]
218 pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
219 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
220 Self::from_cols(
221 x_axis.mul(scale.x),
222 y_axis.mul(scale.y),
223 z_axis.mul(scale.z),
224 Vec4::from((translation, 1.0)),
225 )
226 }
227
228 #[inline]
237 #[must_use]
238 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
239 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
240 Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0)))
241 }
242
243 #[inline]
251 #[must_use]
252 pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
253 let det = self.determinant();
254 glam_assert!(det != 0.0);
255
256 let scale = Vec3::new(
257 self.x_axis.length() * math::signum(det),
258 self.y_axis.length(),
259 self.z_axis.length(),
260 );
261
262 glam_assert!(scale.cmpne(Vec3::ZERO).all());
263
264 let inv_scale = scale.recip();
265
266 let rotation = Quat::from_rotation_axes(
267 self.x_axis.mul(inv_scale.x).xyz(),
268 self.y_axis.mul(inv_scale.y).xyz(),
269 self.z_axis.mul(inv_scale.z).xyz(),
270 );
271
272 let translation = self.w_axis.xyz();
273
274 (scale, rotation, translation)
275 }
276
277 #[inline]
286 #[must_use]
287 pub fn from_quat(rotation: Quat) -> Self {
288 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
289 Self::from_cols(x_axis, y_axis, z_axis, Vec4::W)
290 }
291
292 #[inline]
298 #[must_use]
299 pub fn from_mat3(m: Mat3) -> Self {
300 Self::from_cols(
301 Vec4::from((m.x_axis, 0.0)),
302 Vec4::from((m.y_axis, 0.0)),
303 Vec4::from((m.z_axis, 0.0)),
304 Vec4::W,
305 )
306 }
307
308 #[inline]
314 #[must_use]
315 pub fn from_mat3a(m: Mat3A) -> Self {
316 Self::from_cols(
317 Vec4::from((m.x_axis, 0.0)),
318 Vec4::from((m.y_axis, 0.0)),
319 Vec4::from((m.z_axis, 0.0)),
320 Vec4::W,
321 )
322 }
323
324 #[inline]
329 #[must_use]
330 pub fn from_translation(translation: Vec3) -> Self {
331 Self::from_cols(
332 Vec4::X,
333 Vec4::Y,
334 Vec4::Z,
335 Vec4::new(translation.x, translation.y, translation.z, 1.0),
336 )
337 }
338
339 #[inline]
349 #[must_use]
350 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
351 glam_assert!(axis.is_normalized());
352
353 let (sin, cos) = math::sin_cos(angle);
354 let axis_sin = axis.mul(sin);
355 let axis_sq = axis.mul(axis);
356 let omc = 1.0 - cos;
357 let xyomc = axis.x * axis.y * omc;
358 let xzomc = axis.x * axis.z * omc;
359 let yzomc = axis.y * axis.z * omc;
360 Self::from_cols(
361 Vec4::new(
362 axis_sq.x * omc + cos,
363 xyomc + axis_sin.z,
364 xzomc - axis_sin.y,
365 0.0,
366 ),
367 Vec4::new(
368 xyomc - axis_sin.z,
369 axis_sq.y * omc + cos,
370 yzomc + axis_sin.x,
371 0.0,
372 ),
373 Vec4::new(
374 xzomc + axis_sin.y,
375 yzomc - axis_sin.x,
376 axis_sq.z * omc + cos,
377 0.0,
378 ),
379 Vec4::W,
380 )
381 }
382
383 #[inline]
389 #[must_use]
390 pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
391 Self::from_euler_angles(order, a, b, c)
392 }
393
394 #[inline]
404 #[must_use]
405 pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
406 glam_assert!(
407 self.x_axis.xyz().is_normalized()
408 && self.y_axis.xyz().is_normalized()
409 && self.z_axis.xyz().is_normalized()
410 );
411 self.to_euler_angles(order)
412 }
413
414 #[inline]
420 #[must_use]
421 pub fn from_rotation_x(angle: f32) -> Self {
422 let (sina, cosa) = math::sin_cos(angle);
423 Self::from_cols(
424 Vec4::X,
425 Vec4::new(0.0, cosa, sina, 0.0),
426 Vec4::new(0.0, -sina, cosa, 0.0),
427 Vec4::W,
428 )
429 }
430
431 #[inline]
437 #[must_use]
438 pub fn from_rotation_y(angle: f32) -> Self {
439 let (sina, cosa) = math::sin_cos(angle);
440 Self::from_cols(
441 Vec4::new(cosa, 0.0, -sina, 0.0),
442 Vec4::Y,
443 Vec4::new(sina, 0.0, cosa, 0.0),
444 Vec4::W,
445 )
446 }
447
448 #[inline]
454 #[must_use]
455 pub fn from_rotation_z(angle: f32) -> Self {
456 let (sina, cosa) = math::sin_cos(angle);
457 Self::from_cols(
458 Vec4::new(cosa, sina, 0.0, 0.0),
459 Vec4::new(-sina, cosa, 0.0, 0.0),
460 Vec4::Z,
461 Vec4::W,
462 )
463 }
464
465 #[inline]
474 #[must_use]
475 pub fn from_scale(scale: Vec3) -> Self {
476 glam_assert!(scale.cmpne(Vec3::ZERO).any());
478
479 Self::from_cols(
480 Vec4::new(scale.x, 0.0, 0.0, 0.0),
481 Vec4::new(0.0, scale.y, 0.0, 0.0),
482 Vec4::new(0.0, 0.0, scale.z, 0.0),
483 Vec4::W,
484 )
485 }
486
487 #[inline]
493 #[must_use]
494 pub const fn from_cols_slice(slice: &[f32]) -> Self {
495 Self::new(
496 slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
497 slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
498 )
499 }
500
501 #[inline]
507 pub fn write_cols_to_slice(self, slice: &mut [f32]) {
508 slice[0] = self.x_axis.x;
509 slice[1] = self.x_axis.y;
510 slice[2] = self.x_axis.z;
511 slice[3] = self.x_axis.w;
512 slice[4] = self.y_axis.x;
513 slice[5] = self.y_axis.y;
514 slice[6] = self.y_axis.z;
515 slice[7] = self.y_axis.w;
516 slice[8] = self.z_axis.x;
517 slice[9] = self.z_axis.y;
518 slice[10] = self.z_axis.z;
519 slice[11] = self.z_axis.w;
520 slice[12] = self.w_axis.x;
521 slice[13] = self.w_axis.y;
522 slice[14] = self.w_axis.z;
523 slice[15] = self.w_axis.w;
524 }
525
526 #[inline]
532 #[must_use]
533 pub fn col(&self, index: usize) -> Vec4 {
534 match index {
535 0 => self.x_axis,
536 1 => self.y_axis,
537 2 => self.z_axis,
538 3 => self.w_axis,
539 _ => panic!("index out of bounds"),
540 }
541 }
542
543 #[inline]
549 pub fn col_mut(&mut self, index: usize) -> &mut Vec4 {
550 match index {
551 0 => &mut self.x_axis,
552 1 => &mut self.y_axis,
553 2 => &mut self.z_axis,
554 3 => &mut self.w_axis,
555 _ => panic!("index out of bounds"),
556 }
557 }
558
559 #[inline]
565 #[must_use]
566 pub fn row(&self, index: usize) -> Vec4 {
567 match index {
568 0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
569 1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
570 2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
571 3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
572 _ => panic!("index out of bounds"),
573 }
574 }
575
576 #[inline]
579 #[must_use]
580 pub fn is_finite(&self) -> bool {
581 self.x_axis.is_finite()
582 && self.y_axis.is_finite()
583 && self.z_axis.is_finite()
584 && self.w_axis.is_finite()
585 }
586
587 #[inline]
589 #[must_use]
590 pub fn is_nan(&self) -> bool {
591 self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
592 }
593
594 #[inline]
596 #[must_use]
597 pub fn transpose(&self) -> Self {
598 unsafe {
599 let tmp0 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b01_00_01_00);
601 let tmp1 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b11_10_11_10);
602 let tmp2 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b01_00_01_00);
603 let tmp3 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b11_10_11_10);
604
605 Self {
606 x_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b10_00_10_00)),
607 y_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b11_01_11_01)),
608 z_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b10_00_10_00)),
609 w_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b11_01_11_01)),
610 }
611 }
612 }
613
614 #[must_use]
616 pub fn determinant(&self) -> f32 {
617 unsafe {
618 let swp2a = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_01_01_10);
620 let swp3a = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b11_10_11_11);
621 let swp2b = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b11_10_11_11);
622 let swp3b = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b00_01_01_10);
623 let swp2c = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_00_01_10);
624 let swp3c = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b01_10_00_00);
625
626 let mula = _mm_mul_ps(swp2a, swp3a);
627 let mulb = _mm_mul_ps(swp2b, swp3b);
628 let mulc = _mm_mul_ps(swp2c, swp3c);
629 let sube = _mm_sub_ps(mula, mulb);
630 let subf = _mm_sub_ps(_mm_movehl_ps(mulc, mulc), mulc);
631
632 let subfaca = _mm_shuffle_ps(sube, sube, 0b10_01_00_00);
633 let swpfaca = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b00_00_00_01);
634 let mulfaca = _mm_mul_ps(swpfaca, subfaca);
635
636 let subtmpb = _mm_shuffle_ps(sube, subf, 0b00_00_11_01);
637 let subfacb = _mm_shuffle_ps(subtmpb, subtmpb, 0b11_01_01_00);
638 let swpfacb = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b01_01_10_10);
639 let mulfacb = _mm_mul_ps(swpfacb, subfacb);
640
641 let subres = _mm_sub_ps(mulfaca, mulfacb);
642 let subtmpc = _mm_shuffle_ps(sube, subf, 0b01_00_10_10);
643 let subfacc = _mm_shuffle_ps(subtmpc, subtmpc, 0b11_11_10_00);
644 let swpfacc = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b10_11_11_11);
645 let mulfacc = _mm_mul_ps(swpfacc, subfacc);
646
647 let addres = _mm_add_ps(subres, mulfacc);
648 let detcof = _mm_mul_ps(addres, _mm_setr_ps(1.0, -1.0, 1.0, -1.0));
649
650 dot4(self.x_axis.0, detcof)
651 }
652 }
653
654 #[must_use]
662 pub fn inverse(&self) -> Self {
663 unsafe {
664 let fac0 = {
666 let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11);
667 let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10);
668
669 let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10);
670 let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
671 let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
672 let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11);
673
674 let mul00 = _mm_mul_ps(swp00, swp01);
675 let mul01 = _mm_mul_ps(swp02, swp03);
676 _mm_sub_ps(mul00, mul01)
677 };
678 let fac1 = {
679 let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11);
680 let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01);
681
682 let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01);
683 let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
684 let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
685 let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11);
686
687 let mul00 = _mm_mul_ps(swp00, swp01);
688 let mul01 = _mm_mul_ps(swp02, swp03);
689 _mm_sub_ps(mul00, mul01)
690 };
691 let fac2 = {
692 let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10);
693 let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01);
694
695 let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01);
696 let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
697 let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
698 let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10);
699
700 let mul00 = _mm_mul_ps(swp00, swp01);
701 let mul01 = _mm_mul_ps(swp02, swp03);
702 _mm_sub_ps(mul00, mul01)
703 };
704 let fac3 = {
705 let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11);
706 let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00);
707
708 let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00);
709 let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
710 let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
711 let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11);
712
713 let mul00 = _mm_mul_ps(swp00, swp01);
714 let mul01 = _mm_mul_ps(swp02, swp03);
715 _mm_sub_ps(mul00, mul01)
716 };
717 let fac4 = {
718 let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10);
719 let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00);
720
721 let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00);
722 let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
723 let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
724 let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10);
725
726 let mul00 = _mm_mul_ps(swp00, swp01);
727 let mul01 = _mm_mul_ps(swp02, swp03);
728 _mm_sub_ps(mul00, mul01)
729 };
730 let fac5 = {
731 let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01);
732 let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00);
733
734 let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00);
735 let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
736 let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
737 let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01);
738
739 let mul00 = _mm_mul_ps(swp00, swp01);
740 let mul01 = _mm_mul_ps(swp02, swp03);
741 _mm_sub_ps(mul00, mul01)
742 };
743 let sign_a = _mm_set_ps(1.0, -1.0, 1.0, -1.0);
744 let sign_b = _mm_set_ps(-1.0, 1.0, -1.0, 1.0);
745
746 let temp0 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b00_00_00_00);
747 let vec0 = _mm_shuffle_ps(temp0, temp0, 0b10_10_10_00);
748
749 let temp1 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b01_01_01_01);
750 let vec1 = _mm_shuffle_ps(temp1, temp1, 0b10_10_10_00);
751
752 let temp2 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b10_10_10_10);
753 let vec2 = _mm_shuffle_ps(temp2, temp2, 0b10_10_10_00);
754
755 let temp3 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b11_11_11_11);
756 let vec3 = _mm_shuffle_ps(temp3, temp3, 0b10_10_10_00);
757
758 let mul00 = _mm_mul_ps(vec1, fac0);
759 let mul01 = _mm_mul_ps(vec2, fac1);
760 let mul02 = _mm_mul_ps(vec3, fac2);
761 let sub00 = _mm_sub_ps(mul00, mul01);
762 let add00 = _mm_add_ps(sub00, mul02);
763 let inv0 = _mm_mul_ps(sign_b, add00);
764
765 let mul03 = _mm_mul_ps(vec0, fac0);
766 let mul04 = _mm_mul_ps(vec2, fac3);
767 let mul05 = _mm_mul_ps(vec3, fac4);
768 let sub01 = _mm_sub_ps(mul03, mul04);
769 let add01 = _mm_add_ps(sub01, mul05);
770 let inv1 = _mm_mul_ps(sign_a, add01);
771
772 let mul06 = _mm_mul_ps(vec0, fac1);
773 let mul07 = _mm_mul_ps(vec1, fac3);
774 let mul08 = _mm_mul_ps(vec3, fac5);
775 let sub02 = _mm_sub_ps(mul06, mul07);
776 let add02 = _mm_add_ps(sub02, mul08);
777 let inv2 = _mm_mul_ps(sign_b, add02);
778
779 let mul09 = _mm_mul_ps(vec0, fac2);
780 let mul10 = _mm_mul_ps(vec1, fac4);
781 let mul11 = _mm_mul_ps(vec2, fac5);
782 let sub03 = _mm_sub_ps(mul09, mul10);
783 let add03 = _mm_add_ps(sub03, mul11);
784 let inv3 = _mm_mul_ps(sign_a, add03);
785
786 let row0 = _mm_shuffle_ps(inv0, inv1, 0b00_00_00_00);
787 let row1 = _mm_shuffle_ps(inv2, inv3, 0b00_00_00_00);
788 let row2 = _mm_shuffle_ps(row0, row1, 0b10_00_10_00);
789
790 let dot0 = dot4(self.x_axis.0, row2);
791 glam_assert!(dot0 != 0.0);
792
793 let rcp0 = _mm_set1_ps(dot0.recip());
794
795 Self {
796 x_axis: Vec4(_mm_mul_ps(inv0, rcp0)),
797 y_axis: Vec4(_mm_mul_ps(inv1, rcp0)),
798 z_axis: Vec4(_mm_mul_ps(inv2, rcp0)),
799 w_axis: Vec4(_mm_mul_ps(inv3, rcp0)),
800 }
801 }
802 }
803
804 #[inline]
809 #[must_use]
810 pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
811 Self::look_to_rh(eye, -dir, up)
812 }
813
814 #[inline]
819 #[must_use]
820 pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
821 let f = dir.normalize();
822 let s = f.cross(up).normalize();
823 let u = s.cross(f);
824
825 Self::from_cols(
826 Vec4::new(s.x, u.x, -f.x, 0.0),
827 Vec4::new(s.y, u.y, -f.y, 0.0),
828 Vec4::new(s.z, u.z, -f.z, 0.0),
829 Vec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
830 )
831 }
832
833 #[inline]
841 #[must_use]
842 pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
843 glam_assert!(up.is_normalized());
844 Self::look_to_lh(eye, center.sub(eye), up)
845 }
846
847 #[inline]
855 pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
856 glam_assert!(up.is_normalized());
857 Self::look_to_rh(eye, center.sub(eye), up)
858 }
859
860 #[inline]
867 #[must_use]
868 pub fn perspective_rh_gl(
869 fov_y_radians: f32,
870 aspect_ratio: f32,
871 z_near: f32,
872 z_far: f32,
873 ) -> Self {
874 let inv_length = 1.0 / (z_near - z_far);
875 let f = 1.0 / math::tan(0.5 * fov_y_radians);
876 let a = f / aspect_ratio;
877 let b = (z_near + z_far) * inv_length;
878 let c = (2.0 * z_near * z_far) * inv_length;
879 Self::from_cols(
880 Vec4::new(a, 0.0, 0.0, 0.0),
881 Vec4::new(0.0, f, 0.0, 0.0),
882 Vec4::new(0.0, 0.0, b, -1.0),
883 Vec4::new(0.0, 0.0, c, 0.0),
884 )
885 }
886
887 #[inline]
896 #[must_use]
897 pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
898 glam_assert!(z_near > 0.0 && z_far > 0.0);
899 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
900 let h = cos_fov / sin_fov;
901 let w = h / aspect_ratio;
902 let r = z_far / (z_far - z_near);
903 Self::from_cols(
904 Vec4::new(w, 0.0, 0.0, 0.0),
905 Vec4::new(0.0, h, 0.0, 0.0),
906 Vec4::new(0.0, 0.0, r, 1.0),
907 Vec4::new(0.0, 0.0, -r * z_near, 0.0),
908 )
909 }
910
911 #[inline]
920 #[must_use]
921 pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
922 glam_assert!(z_near > 0.0 && z_far > 0.0);
923 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
924 let h = cos_fov / sin_fov;
925 let w = h / aspect_ratio;
926 let r = z_far / (z_near - z_far);
927 Self::from_cols(
928 Vec4::new(w, 0.0, 0.0, 0.0),
929 Vec4::new(0.0, h, 0.0, 0.0),
930 Vec4::new(0.0, 0.0, r, -1.0),
931 Vec4::new(0.0, 0.0, r * z_near, 0.0),
932 )
933 }
934
935 #[inline]
945 #[must_use]
946 pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
947 glam_assert!(z_near > 0.0);
948 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
949 let h = cos_fov / sin_fov;
950 let w = h / aspect_ratio;
951 Self::from_cols(
952 Vec4::new(w, 0.0, 0.0, 0.0),
953 Vec4::new(0.0, h, 0.0, 0.0),
954 Vec4::new(0.0, 0.0, 1.0, 1.0),
955 Vec4::new(0.0, 0.0, -z_near, 0.0),
956 )
957 }
958
959 #[inline]
967 #[must_use]
968 pub fn perspective_infinite_reverse_lh(
969 fov_y_radians: f32,
970 aspect_ratio: f32,
971 z_near: f32,
972 ) -> Self {
973 glam_assert!(z_near > 0.0);
974 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
975 let h = cos_fov / sin_fov;
976 let w = h / aspect_ratio;
977 Self::from_cols(
978 Vec4::new(w, 0.0, 0.0, 0.0),
979 Vec4::new(0.0, h, 0.0, 0.0),
980 Vec4::new(0.0, 0.0, 0.0, 1.0),
981 Vec4::new(0.0, 0.0, z_near, 0.0),
982 )
983 }
984
985 #[inline]
995 #[must_use]
996 pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
997 glam_assert!(z_near > 0.0);
998 let f = 1.0 / math::tan(0.5 * fov_y_radians);
999 Self::from_cols(
1000 Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1001 Vec4::new(0.0, f, 0.0, 0.0),
1002 Vec4::new(0.0, 0.0, -1.0, -1.0),
1003 Vec4::new(0.0, 0.0, -z_near, 0.0),
1004 )
1005 }
1006
1007 #[inline]
1015 #[must_use]
1016 pub fn perspective_infinite_reverse_rh(
1017 fov_y_radians: f32,
1018 aspect_ratio: f32,
1019 z_near: f32,
1020 ) -> Self {
1021 glam_assert!(z_near > 0.0);
1022 let f = 1.0 / math::tan(0.5 * fov_y_radians);
1023 Self::from_cols(
1024 Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1025 Vec4::new(0.0, f, 0.0, 0.0),
1026 Vec4::new(0.0, 0.0, 0.0, -1.0),
1027 Vec4::new(0.0, 0.0, z_near, 0.0),
1028 )
1029 }
1030
1031 #[inline]
1038 #[must_use]
1039 pub fn orthographic_rh_gl(
1040 left: f32,
1041 right: f32,
1042 bottom: f32,
1043 top: f32,
1044 near: f32,
1045 far: f32,
1046 ) -> Self {
1047 let a = 2.0 / (right - left);
1048 let b = 2.0 / (top - bottom);
1049 let c = -2.0 / (far - near);
1050 let tx = -(right + left) / (right - left);
1051 let ty = -(top + bottom) / (top - bottom);
1052 let tz = -(far + near) / (far - near);
1053
1054 Self::from_cols(
1055 Vec4::new(a, 0.0, 0.0, 0.0),
1056 Vec4::new(0.0, b, 0.0, 0.0),
1057 Vec4::new(0.0, 0.0, c, 0.0),
1058 Vec4::new(tx, ty, tz, 1.0),
1059 )
1060 }
1061
1062 #[inline]
1066 #[must_use]
1067 pub fn orthographic_lh(
1068 left: f32,
1069 right: f32,
1070 bottom: f32,
1071 top: f32,
1072 near: f32,
1073 far: f32,
1074 ) -> Self {
1075 let rcp_width = 1.0 / (right - left);
1076 let rcp_height = 1.0 / (top - bottom);
1077 let r = 1.0 / (far - near);
1078 Self::from_cols(
1079 Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1080 Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1081 Vec4::new(0.0, 0.0, r, 0.0),
1082 Vec4::new(
1083 -(left + right) * rcp_width,
1084 -(top + bottom) * rcp_height,
1085 -r * near,
1086 1.0,
1087 ),
1088 )
1089 }
1090
1091 #[inline]
1095 #[must_use]
1096 pub fn orthographic_rh(
1097 left: f32,
1098 right: f32,
1099 bottom: f32,
1100 top: f32,
1101 near: f32,
1102 far: f32,
1103 ) -> Self {
1104 let rcp_width = 1.0 / (right - left);
1105 let rcp_height = 1.0 / (top - bottom);
1106 let r = 1.0 / (near - far);
1107 Self::from_cols(
1108 Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1109 Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1110 Vec4::new(0.0, 0.0, r, 0.0),
1111 Vec4::new(
1112 -(left + right) * rcp_width,
1113 -(top + bottom) * rcp_height,
1114 r * near,
1115 1.0,
1116 ),
1117 )
1118 }
1119
1120 #[inline]
1127 #[must_use]
1128 pub fn project_point3(&self, rhs: Vec3) -> Vec3 {
1129 let mut res = self.x_axis.mul(rhs.x);
1130 res = self.y_axis.mul(rhs.y).add(res);
1131 res = self.z_axis.mul(rhs.z).add(res);
1132 res = self.w_axis.add(res);
1133 res = res.div(res.w);
1134 res.xyz()
1135 }
1136
1137 #[inline]
1150 #[must_use]
1151 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
1152 glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1153 let mut res = self.x_axis.mul(rhs.x);
1154 res = self.y_axis.mul(rhs.y).add(res);
1155 res = self.z_axis.mul(rhs.z).add(res);
1156 res = self.w_axis.add(res);
1157 res.xyz()
1158 }
1159
1160 #[inline]
1171 #[must_use]
1172 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
1173 glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1174 let mut res = self.x_axis.mul(rhs.x);
1175 res = self.y_axis.mul(rhs.y).add(res);
1176 res = self.z_axis.mul(rhs.z).add(res);
1177 res.xyz()
1178 }
1179
1180 #[inline]
1187 #[must_use]
1188 pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
1189 let mut res = self.x_axis.mul(rhs.xxxx());
1190 res = self.y_axis.mul(rhs.yyyy()).add(res);
1191 res = self.z_axis.mul(rhs.zzzz()).add(res);
1192 res = self.w_axis.add(res);
1193 res = res.div(res.wwww());
1194 Vec3A::from_vec4(res)
1195 }
1196
1197 #[inline]
1201 #[must_use]
1202 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
1203 glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1204 let mut res = self.x_axis.mul(rhs.xxxx());
1205 res = self.y_axis.mul(rhs.yyyy()).add(res);
1206 res = self.z_axis.mul(rhs.zzzz()).add(res);
1207 res = self.w_axis.add(res);
1208 Vec3A::from_vec4(res)
1209 }
1210
1211 #[inline]
1215 #[must_use]
1216 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
1217 glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1218 let mut res = self.x_axis.mul(rhs.xxxx());
1219 res = self.y_axis.mul(rhs.yyyy()).add(res);
1220 res = self.z_axis.mul(rhs.zzzz()).add(res);
1221 Vec3A::from_vec4(res)
1222 }
1223
1224 #[inline]
1226 #[must_use]
1227 pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 {
1228 let mut res = self.x_axis.mul(rhs.xxxx());
1229 res = res.add(self.y_axis.mul(rhs.yyyy()));
1230 res = res.add(self.z_axis.mul(rhs.zzzz()));
1231 res = res.add(self.w_axis.mul(rhs.wwww()));
1232 res
1233 }
1234
1235 #[inline]
1237 #[must_use]
1238 pub fn mul_mat4(&self, rhs: &Self) -> Self {
1239 Self::from_cols(
1240 self.mul(rhs.x_axis),
1241 self.mul(rhs.y_axis),
1242 self.mul(rhs.z_axis),
1243 self.mul(rhs.w_axis),
1244 )
1245 }
1246
1247 #[inline]
1249 #[must_use]
1250 pub fn add_mat4(&self, rhs: &Self) -> Self {
1251 Self::from_cols(
1252 self.x_axis.add(rhs.x_axis),
1253 self.y_axis.add(rhs.y_axis),
1254 self.z_axis.add(rhs.z_axis),
1255 self.w_axis.add(rhs.w_axis),
1256 )
1257 }
1258
1259 #[inline]
1261 #[must_use]
1262 pub fn sub_mat4(&self, rhs: &Self) -> Self {
1263 Self::from_cols(
1264 self.x_axis.sub(rhs.x_axis),
1265 self.y_axis.sub(rhs.y_axis),
1266 self.z_axis.sub(rhs.z_axis),
1267 self.w_axis.sub(rhs.w_axis),
1268 )
1269 }
1270
1271 #[inline]
1273 #[must_use]
1274 pub fn mul_scalar(&self, rhs: f32) -> Self {
1275 Self::from_cols(
1276 self.x_axis.mul(rhs),
1277 self.y_axis.mul(rhs),
1278 self.z_axis.mul(rhs),
1279 self.w_axis.mul(rhs),
1280 )
1281 }
1282
1283 #[inline]
1285 #[must_use]
1286 pub fn div_scalar(&self, rhs: f32) -> Self {
1287 let rhs = Vec4::splat(rhs);
1288 Self::from_cols(
1289 self.x_axis.div(rhs),
1290 self.y_axis.div(rhs),
1291 self.z_axis.div(rhs),
1292 self.w_axis.div(rhs),
1293 )
1294 }
1295
1296 #[inline]
1306 #[must_use]
1307 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
1308 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1309 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1310 && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1311 && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1312 }
1313
1314 #[inline]
1316 #[must_use]
1317 pub fn abs(&self) -> Self {
1318 Self::from_cols(
1319 self.x_axis.abs(),
1320 self.y_axis.abs(),
1321 self.z_axis.abs(),
1322 self.w_axis.abs(),
1323 )
1324 }
1325
1326 #[inline]
1327 pub fn as_dmat4(&self) -> DMat4 {
1328 DMat4::from_cols(
1329 self.x_axis.as_dvec4(),
1330 self.y_axis.as_dvec4(),
1331 self.z_axis.as_dvec4(),
1332 self.w_axis.as_dvec4(),
1333 )
1334 }
1335}
1336
1337impl Default for Mat4 {
1338 #[inline]
1339 fn default() -> Self {
1340 Self::IDENTITY
1341 }
1342}
1343
1344impl Add<Mat4> for Mat4 {
1345 type Output = Self;
1346 #[inline]
1347 fn add(self, rhs: Self) -> Self::Output {
1348 self.add_mat4(&rhs)
1349 }
1350}
1351
1352impl AddAssign<Mat4> for Mat4 {
1353 #[inline]
1354 fn add_assign(&mut self, rhs: Self) {
1355 *self = self.add_mat4(&rhs);
1356 }
1357}
1358
1359impl Sub<Mat4> for Mat4 {
1360 type Output = Self;
1361 #[inline]
1362 fn sub(self, rhs: Self) -> Self::Output {
1363 self.sub_mat4(&rhs)
1364 }
1365}
1366
1367impl SubAssign<Mat4> for Mat4 {
1368 #[inline]
1369 fn sub_assign(&mut self, rhs: Self) {
1370 *self = self.sub_mat4(&rhs);
1371 }
1372}
1373
1374impl Neg for Mat4 {
1375 type Output = Self;
1376 #[inline]
1377 fn neg(self) -> Self::Output {
1378 Self::from_cols(
1379 self.x_axis.neg(),
1380 self.y_axis.neg(),
1381 self.z_axis.neg(),
1382 self.w_axis.neg(),
1383 )
1384 }
1385}
1386
1387impl Mul<Mat4> for Mat4 {
1388 type Output = Self;
1389 #[inline]
1390 fn mul(self, rhs: Self) -> Self::Output {
1391 self.mul_mat4(&rhs)
1392 }
1393}
1394
1395impl MulAssign<Mat4> for Mat4 {
1396 #[inline]
1397 fn mul_assign(&mut self, rhs: Self) {
1398 *self = self.mul_mat4(&rhs);
1399 }
1400}
1401
1402impl Mul<Vec4> for Mat4 {
1403 type Output = Vec4;
1404 #[inline]
1405 fn mul(self, rhs: Vec4) -> Self::Output {
1406 self.mul_vec4(rhs)
1407 }
1408}
1409
1410impl Mul<Mat4> for f32 {
1411 type Output = Mat4;
1412 #[inline]
1413 fn mul(self, rhs: Mat4) -> Self::Output {
1414 rhs.mul_scalar(self)
1415 }
1416}
1417
1418impl Mul<f32> for Mat4 {
1419 type Output = Self;
1420 #[inline]
1421 fn mul(self, rhs: f32) -> Self::Output {
1422 self.mul_scalar(rhs)
1423 }
1424}
1425
1426impl MulAssign<f32> for Mat4 {
1427 #[inline]
1428 fn mul_assign(&mut self, rhs: f32) {
1429 *self = self.mul_scalar(rhs);
1430 }
1431}
1432
1433impl Div<Mat4> for f32 {
1434 type Output = Mat4;
1435 #[inline]
1436 fn div(self, rhs: Mat4) -> Self::Output {
1437 rhs.div_scalar(self)
1438 }
1439}
1440
1441impl Div<f32> for Mat4 {
1442 type Output = Self;
1443 #[inline]
1444 fn div(self, rhs: f32) -> Self::Output {
1445 self.div_scalar(rhs)
1446 }
1447}
1448
1449impl DivAssign<f32> for Mat4 {
1450 #[inline]
1451 fn div_assign(&mut self, rhs: f32) {
1452 *self = self.div_scalar(rhs);
1453 }
1454}
1455
1456impl Sum<Self> for Mat4 {
1457 fn sum<I>(iter: I) -> Self
1458 where
1459 I: Iterator<Item = Self>,
1460 {
1461 iter.fold(Self::ZERO, Self::add)
1462 }
1463}
1464
1465impl<'a> Sum<&'a Self> for Mat4 {
1466 fn sum<I>(iter: I) -> Self
1467 where
1468 I: Iterator<Item = &'a Self>,
1469 {
1470 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1471 }
1472}
1473
1474impl Product for Mat4 {
1475 fn product<I>(iter: I) -> Self
1476 where
1477 I: Iterator<Item = Self>,
1478 {
1479 iter.fold(Self::IDENTITY, Self::mul)
1480 }
1481}
1482
1483impl<'a> Product<&'a Self> for Mat4 {
1484 fn product<I>(iter: I) -> Self
1485 where
1486 I: Iterator<Item = &'a Self>,
1487 {
1488 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1489 }
1490}
1491
1492impl PartialEq for Mat4 {
1493 #[inline]
1494 fn eq(&self, rhs: &Self) -> bool {
1495 self.x_axis.eq(&rhs.x_axis)
1496 && self.y_axis.eq(&rhs.y_axis)
1497 && self.z_axis.eq(&rhs.z_axis)
1498 && self.w_axis.eq(&rhs.w_axis)
1499 }
1500}
1501
1502#[cfg(not(target_arch = "spirv"))]
1503impl AsRef<[f32; 16]> for Mat4 {
1504 #[inline]
1505 fn as_ref(&self) -> &[f32; 16] {
1506 unsafe { &*(self as *const Self as *const [f32; 16]) }
1507 }
1508}
1509
1510#[cfg(not(target_arch = "spirv"))]
1511impl AsMut<[f32; 16]> for Mat4 {
1512 #[inline]
1513 fn as_mut(&mut self) -> &mut [f32; 16] {
1514 unsafe { &mut *(self as *mut Self as *mut [f32; 16]) }
1515 }
1516}
1517
1518impl fmt::Debug for Mat4 {
1519 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1520 fmt.debug_struct(stringify!(Mat4))
1521 .field("x_axis", &self.x_axis)
1522 .field("y_axis", &self.y_axis)
1523 .field("z_axis", &self.z_axis)
1524 .field("w_axis", &self.w_axis)
1525 .finish()
1526 }
1527}
1528
1529impl fmt::Display for Mat4 {
1530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1531 if let Some(p) = f.precision() {
1532 write!(
1533 f,
1534 "[{:.*}, {:.*}, {:.*}, {:.*}]",
1535 p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
1536 )
1537 } else {
1538 write!(
1539 f,
1540 "[{}, {}, {}, {}]",
1541 self.x_axis, self.y_axis, self.z_axis, self.w_axis
1542 )
1543 }
1544 }
1545}