1use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
4use core::fmt;
5use core::iter::{Product, Sum};
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7
8use core::arch::aarch64::*;
9
10#[repr(C)]
11union UnionCast {
12 a: [f32; 4],
13 v: Mat2,
14}
15
16#[inline(always)]
18#[must_use]
19pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 {
20 Mat2::from_cols(x_axis, y_axis)
21}
22
23#[derive(Clone, Copy)]
29#[repr(transparent)]
30pub struct Mat2(pub(crate) float32x4_t);
31
32impl Mat2 {
33 pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO);
35
36 pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y);
38
39 pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN);
41
42 #[allow(clippy::too_many_arguments)]
43 #[inline(always)]
44 #[must_use]
45 const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self {
46 unsafe {
47 UnionCast {
48 a: [m00, m01, m10, m11],
49 }
50 .v
51 }
52 }
53
54 #[inline(always)]
56 #[must_use]
57 pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self {
58 unsafe {
59 UnionCast {
60 a: [x_axis.x, x_axis.y, y_axis.x, y_axis.y],
61 }
62 .v
63 }
64 }
65
66 #[inline]
70 #[must_use]
71 pub const fn from_cols_array(m: &[f32; 4]) -> Self {
72 Self::new(m[0], m[1], m[2], m[3])
73 }
74
75 #[inline]
78 #[must_use]
79 pub const fn to_cols_array(&self) -> [f32; 4] {
80 unsafe { *(self as *const Self as *const [f32; 4]) }
81 }
82
83 #[inline]
87 #[must_use]
88 pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self {
89 Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1]))
90 }
91
92 #[inline]
95 #[must_use]
96 pub const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] {
97 unsafe { *(self as *const Self as *const [[f32; 2]; 2]) }
98 }
99
100 #[doc(alias = "scale")]
102 #[inline]
103 #[must_use]
104 pub const fn from_diagonal(diagonal: Vec2) -> Self {
105 Self::new(diagonal.x, 0.0, 0.0, diagonal.y)
106 }
107
108 #[inline]
111 #[must_use]
112 pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self {
113 let (sin, cos) = math::sin_cos(angle);
114 Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y)
115 }
116
117 #[inline]
119 #[must_use]
120 pub fn from_angle(angle: f32) -> Self {
121 let (sin, cos) = math::sin_cos(angle);
122 Self::new(cos, sin, -sin, cos)
123 }
124
125 #[inline]
127 #[must_use]
128 pub fn from_mat3(m: Mat3) -> Self {
129 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
130 }
131
132 #[inline]
139 #[must_use]
140 pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
141 match (i, j) {
142 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
143 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
144 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
145 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
146 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
147 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
148 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
149 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
150 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
151 _ => panic!("index out of bounds"),
152 }
153 }
154
155 #[inline]
157 #[must_use]
158 pub fn from_mat3a(m: Mat3A) -> Self {
159 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
160 }
161
162 #[inline]
169 #[must_use]
170 pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
171 match (i, j) {
172 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
173 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
174 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
175 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
176 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
177 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
178 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
179 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
180 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
181 _ => panic!("index out of bounds"),
182 }
183 }
184
185 #[inline]
191 #[must_use]
192 pub const fn from_cols_slice(slice: &[f32]) -> Self {
193 Self::new(slice[0], slice[1], slice[2], slice[3])
194 }
195
196 #[inline]
202 pub fn write_cols_to_slice(self, slice: &mut [f32]) {
203 slice[0] = self.x_axis.x;
204 slice[1] = self.x_axis.y;
205 slice[2] = self.y_axis.x;
206 slice[3] = self.y_axis.y;
207 }
208
209 #[inline]
215 #[must_use]
216 pub fn col(&self, index: usize) -> Vec2 {
217 match index {
218 0 => self.x_axis,
219 1 => self.y_axis,
220 _ => panic!("index out of bounds"),
221 }
222 }
223
224 #[inline]
230 pub fn col_mut(&mut self, index: usize) -> &mut Vec2 {
231 match index {
232 0 => &mut self.x_axis,
233 1 => &mut self.y_axis,
234 _ => panic!("index out of bounds"),
235 }
236 }
237
238 #[inline]
244 #[must_use]
245 pub fn row(&self, index: usize) -> Vec2 {
246 match index {
247 0 => Vec2::new(self.x_axis.x, self.y_axis.x),
248 1 => Vec2::new(self.x_axis.y, self.y_axis.y),
249 _ => panic!("index out of bounds"),
250 }
251 }
252
253 #[inline]
256 #[must_use]
257 pub fn is_finite(&self) -> bool {
258 self.x_axis.is_finite() && self.y_axis.is_finite()
259 }
260
261 #[inline]
263 #[must_use]
264 pub fn is_nan(&self) -> bool {
265 self.x_axis.is_nan() || self.y_axis.is_nan()
266 }
267
268 #[inline]
270 #[must_use]
271 pub fn transpose(&self) -> Self {
272 Self(unsafe {
273 vsetq_lane_f32(
274 vgetq_lane_f32(self.0, 2),
275 vsetq_lane_f32(vgetq_lane_f32(self.0, 1), self.0, 2),
276 1,
277 )
278 })
279 }
280
281 #[inline]
283 #[must_use]
284 pub fn determinant(&self) -> f32 {
285 unsafe {
286 let abcd = self.0;
287 let badc = vrev64q_f32(abcd);
288 let dcba = vextq_f32(badc, badc, 2);
289 let prod = vmulq_f32(abcd, dcba);
290 let det = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
291 vgetq_lane_f32(det, 0)
292 }
293 }
294
295 #[inline]
303 #[must_use]
304 pub fn inverse(&self) -> Self {
305 unsafe {
306 const SIGN: float32x4_t = crate::neon::f32x4_from_array([1.0, -1.0, -1.0, 1.0]);
307 let abcd = self.0;
308 let badc = vrev64q_f32(abcd);
309 let dcba = vextq_f32(badc, badc, 2);
310 let prod = vmulq_f32(abcd, dcba);
311 let sub = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
312 let det = vdupq_laneq_f32(sub, 0);
313 let tmp = vdivq_f32(SIGN, det);
314 glam_assert!(Mat2(tmp).is_finite());
315 let dbca = vsetq_lane_f32(
317 vgetq_lane_f32(abcd, 0),
318 vsetq_lane_f32(vgetq_lane_f32(abcd, 3), abcd, 0),
319 3,
320 );
321 Self(vmulq_f32(dbca, tmp))
322 }
323 }
324
325 #[inline]
327 #[must_use]
328 pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 {
329 unsafe {
330 let abcd = self.0;
331 let xxyy = vld1q_f32([rhs.x, rhs.x, rhs.y, rhs.y].as_ptr());
332 let axbxcydy = vmulq_f32(abcd, xxyy);
333 let cydyaxbx = vextq_f32(axbxcydy, axbxcydy, 2);
335 let result = vaddq_f32(axbxcydy, cydyaxbx);
336 *(&result as *const float32x4_t as *const Vec2)
337 }
338 }
339
340 #[inline]
342 #[must_use]
343 pub fn mul_mat2(&self, rhs: &Self) -> Self {
344 unsafe {
345 let abcd = self.0;
346 let xxyy0 = vzip1q_f32(rhs.0, rhs.0);
347 let xxyy1 = vzip2q_f32(rhs.0, rhs.0);
348 let axbxcydy0 = vmulq_f32(abcd, xxyy0);
349 let axbxcydy1 = vmulq_f32(abcd, xxyy1);
350 let cydyaxbx0 = vextq_f32(axbxcydy0, axbxcydy0, 2);
351 let cydyaxbx1 = vextq_f32(axbxcydy1, axbxcydy1, 2);
352 let result0 = vaddq_f32(axbxcydy0, cydyaxbx0);
353 let result1 = vaddq_f32(axbxcydy1, cydyaxbx1);
354 Self(vreinterpretq_f32_u64(vsetq_lane_u64(
355 vgetq_lane_u64(vreinterpretq_u64_f32(result1), 0),
356 vreinterpretq_u64_f32(result0),
357 1,
358 )))
359 }
360 }
361
362 #[inline]
364 #[must_use]
365 pub fn add_mat2(&self, rhs: &Self) -> Self {
366 Self(unsafe { vaddq_f32(self.0, rhs.0) })
367 }
368
369 #[inline]
371 #[must_use]
372 pub fn sub_mat2(&self, rhs: &Self) -> Self {
373 Self(unsafe { vsubq_f32(self.0, rhs.0) })
374 }
375
376 #[inline]
378 #[must_use]
379 pub fn mul_scalar(&self, rhs: f32) -> Self {
380 Self(unsafe { vmulq_f32(self.0, vld1q_dup_f32(&rhs)) })
381 }
382
383 #[inline]
385 #[must_use]
386 pub fn div_scalar(&self, rhs: f32) -> Self {
387 Self(unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) })
388 }
389
390 #[inline]
400 #[must_use]
401 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
402 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
403 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
404 }
405
406 #[inline]
408 #[must_use]
409 pub fn abs(&self) -> Self {
410 Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
411 }
412
413 #[inline]
414 pub fn as_dmat2(&self) -> DMat2 {
415 DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
416 }
417}
418
419impl Default for Mat2 {
420 #[inline]
421 fn default() -> Self {
422 Self::IDENTITY
423 }
424}
425
426impl Add<Mat2> for Mat2 {
427 type Output = Self;
428 #[inline]
429 fn add(self, rhs: Self) -> Self::Output {
430 self.add_mat2(&rhs)
431 }
432}
433
434impl AddAssign<Mat2> for Mat2 {
435 #[inline]
436 fn add_assign(&mut self, rhs: Self) {
437 *self = self.add_mat2(&rhs);
438 }
439}
440
441impl Sub<Mat2> for Mat2 {
442 type Output = Self;
443 #[inline]
444 fn sub(self, rhs: Self) -> Self::Output {
445 self.sub_mat2(&rhs)
446 }
447}
448
449impl SubAssign<Mat2> for Mat2 {
450 #[inline]
451 fn sub_assign(&mut self, rhs: Self) {
452 *self = self.sub_mat2(&rhs);
453 }
454}
455
456impl Neg for Mat2 {
457 type Output = Self;
458 #[inline]
459 fn neg(self) -> Self::Output {
460 Self(unsafe { vnegq_f32(self.0) })
461 }
462}
463
464impl Mul<Mat2> for Mat2 {
465 type Output = Self;
466 #[inline]
467 fn mul(self, rhs: Self) -> Self::Output {
468 self.mul_mat2(&rhs)
469 }
470}
471
472impl MulAssign<Mat2> for Mat2 {
473 #[inline]
474 fn mul_assign(&mut self, rhs: Self) {
475 *self = self.mul_mat2(&rhs);
476 }
477}
478
479impl Mul<Vec2> for Mat2 {
480 type Output = Vec2;
481 #[inline]
482 fn mul(self, rhs: Vec2) -> Self::Output {
483 self.mul_vec2(rhs)
484 }
485}
486
487impl Mul<Mat2> for f32 {
488 type Output = Mat2;
489 #[inline]
490 fn mul(self, rhs: Mat2) -> Self::Output {
491 rhs.mul_scalar(self)
492 }
493}
494
495impl Mul<f32> for Mat2 {
496 type Output = Self;
497 #[inline]
498 fn mul(self, rhs: f32) -> Self::Output {
499 self.mul_scalar(rhs)
500 }
501}
502
503impl MulAssign<f32> for Mat2 {
504 #[inline]
505 fn mul_assign(&mut self, rhs: f32) {
506 *self = self.mul_scalar(rhs);
507 }
508}
509
510impl Div<Mat2> for f32 {
511 type Output = Mat2;
512 #[inline]
513 fn div(self, rhs: Mat2) -> Self::Output {
514 rhs.div_scalar(self)
515 }
516}
517
518impl Div<f32> for Mat2 {
519 type Output = Self;
520 #[inline]
521 fn div(self, rhs: f32) -> Self::Output {
522 self.div_scalar(rhs)
523 }
524}
525
526impl DivAssign<f32> for Mat2 {
527 #[inline]
528 fn div_assign(&mut self, rhs: f32) {
529 *self = self.div_scalar(rhs);
530 }
531}
532
533impl Sum<Self> for Mat2 {
534 fn sum<I>(iter: I) -> Self
535 where
536 I: Iterator<Item = Self>,
537 {
538 iter.fold(Self::ZERO, Self::add)
539 }
540}
541
542impl<'a> Sum<&'a Self> for Mat2 {
543 fn sum<I>(iter: I) -> Self
544 where
545 I: Iterator<Item = &'a Self>,
546 {
547 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
548 }
549}
550
551impl Product for Mat2 {
552 fn product<I>(iter: I) -> Self
553 where
554 I: Iterator<Item = Self>,
555 {
556 iter.fold(Self::IDENTITY, Self::mul)
557 }
558}
559
560impl<'a> Product<&'a Self> for Mat2 {
561 fn product<I>(iter: I) -> Self
562 where
563 I: Iterator<Item = &'a Self>,
564 {
565 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
566 }
567}
568
569impl PartialEq for Mat2 {
570 #[inline]
571 fn eq(&self, rhs: &Self) -> bool {
572 self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis)
573 }
574}
575
576#[cfg(not(target_arch = "spirv"))]
577impl AsRef<[f32; 4]> for Mat2 {
578 #[inline]
579 fn as_ref(&self) -> &[f32; 4] {
580 unsafe { &*(self as *const Self as *const [f32; 4]) }
581 }
582}
583
584#[cfg(not(target_arch = "spirv"))]
585impl AsMut<[f32; 4]> for Mat2 {
586 #[inline]
587 fn as_mut(&mut self) -> &mut [f32; 4] {
588 unsafe { &mut *(self as *mut Self as *mut [f32; 4]) }
589 }
590}
591
592impl core::ops::Deref for Mat2 {
593 type Target = crate::deref::Cols2<Vec2>;
594 #[inline]
595 fn deref(&self) -> &Self::Target {
596 unsafe { &*(self as *const Self as *const Self::Target) }
597 }
598}
599
600impl core::ops::DerefMut for Mat2 {
601 #[inline]
602 fn deref_mut(&mut self) -> &mut Self::Target {
603 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
604 }
605}
606
607impl fmt::Debug for Mat2 {
608 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
609 fmt.debug_struct(stringify!(Mat2))
610 .field("x_axis", &self.x_axis)
611 .field("y_axis", &self.y_axis)
612 .finish()
613 }
614}
615
616impl fmt::Display for Mat2 {
617 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
618 if let Some(p) = f.precision() {
619 write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
620 } else {
621 write!(f, "[{}, {}]", self.x_axis, self.y_axis)
622 }
623 }
624}