1use crate::{Affine3A, Mat3, Mat4, Quat, Vec3};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6#[cfg(all(feature = "zerocopy-08", not(feature = "core-simd")))]
7use zerocopy_derive_08::*;
8
9#[derive(Copy, Clone)]
11#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
12#[cfg_attr(
13 all(feature = "zerocopy-08", not(feature = "core-simd")),
14 derive(FromBytes, Immutable, IntoBytes, KnownLayout)
15)]
16#[repr(C)]
17pub struct Affine3 {
18 pub matrix3: Mat3,
19 pub translation: Vec3,
20}
21
22impl Affine3 {
23 pub const ZERO: Self = Self {
28 matrix3: Mat3::ZERO,
29 translation: Vec3::ZERO,
30 };
31
32 pub const IDENTITY: Self = Self {
36 matrix3: Mat3::IDENTITY,
37 translation: Vec3::ZERO,
38 };
39
40 pub const NAN: Self = Self {
42 matrix3: Mat3::NAN,
43 translation: Vec3::NAN,
44 };
45
46 #[inline(always)]
48 #[must_use]
49 pub const fn from_cols(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3, w_axis: Vec3) -> Self {
50 Self {
51 matrix3: Mat3::from_cols(x_axis, y_axis, z_axis),
52 translation: w_axis,
53 }
54 }
55
56 #[inline]
58 #[must_use]
59 pub fn from_cols_array(m: &[f32; 12]) -> Self {
60 Self {
61 matrix3: Mat3::from_cols_array(&[m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]]),
62 translation: Vec3::from_array([m[9], m[10], m[11]]),
63 }
64 }
65
66 #[inline]
68 #[must_use]
69 pub fn to_cols_array(&self) -> [f32; 12] {
70 let x = &self.matrix3.x_axis;
71 let y = &self.matrix3.y_axis;
72 let z = &self.matrix3.z_axis;
73 let w = &self.translation;
74 [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
75 }
76
77 #[inline]
82 #[must_use]
83 pub fn from_cols_array_2d(m: &[[f32; 3]; 4]) -> Self {
84 Self {
85 matrix3: Mat3::from_cols(m[0].into(), m[1].into(), m[2].into()),
86 translation: m[3].into(),
87 }
88 }
89
90 #[inline]
94 #[must_use]
95 pub fn to_cols_array_2d(&self) -> [[f32; 3]; 4] {
96 [
97 self.matrix3.x_axis.into(),
98 self.matrix3.y_axis.into(),
99 self.matrix3.z_axis.into(),
100 self.translation.into(),
101 ]
102 }
103
104 #[inline]
110 #[must_use]
111 pub fn from_cols_slice(slice: &[f32]) -> Self {
112 Self {
113 matrix3: Mat3::from_cols_slice(&slice[0..9]),
114 translation: Vec3::from_slice(&slice[9..12]),
115 }
116 }
117
118 #[inline]
124 pub fn write_cols_to_slice(&self, slice: &mut [f32]) {
125 self.matrix3.write_cols_to_slice(&mut slice[0..9]);
126 self.translation.write_to_slice(&mut slice[9..12]);
127 }
128
129 #[inline]
132 #[must_use]
133 pub fn from_scale(scale: Vec3) -> Self {
134 Self {
135 matrix3: Mat3::from_diagonal(scale),
136 translation: Vec3::ZERO,
137 }
138 }
139 #[inline]
145 #[must_use]
146 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
147 pub fn from_quat(rotation: Quat) -> Self {
148 Self {
149 matrix3: Mat3::from_quat(rotation),
150 translation: Vec3::ZERO,
151 }
152 }
153
154 #[inline]
161 #[must_use]
162 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
163 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
164 Self {
165 matrix3: Mat3::from_axis_angle(axis, angle),
166 translation: Vec3::ZERO,
167 }
168 }
169
170 #[inline]
173 #[must_use]
174 pub fn from_rotation_x(angle: f32) -> Self {
175 Self {
176 matrix3: Mat3::from_rotation_x(angle),
177 translation: Vec3::ZERO,
178 }
179 }
180
181 #[inline]
184 #[must_use]
185 pub fn from_rotation_y(angle: f32) -> Self {
186 Self {
187 matrix3: Mat3::from_rotation_y(angle),
188 translation: Vec3::ZERO,
189 }
190 }
191
192 #[inline]
195 #[must_use]
196 pub fn from_rotation_z(angle: f32) -> Self {
197 Self {
198 matrix3: Mat3::from_rotation_z(angle),
199 translation: Vec3::ZERO,
200 }
201 }
202
203 #[inline]
205 #[must_use]
206 pub fn from_translation(translation: Vec3) -> Self {
207 #[allow(clippy::useless_conversion)]
208 Self {
209 matrix3: Mat3::IDENTITY,
210 translation: translation.into(),
211 }
212 }
213
214 #[inline]
217 #[must_use]
218 pub fn from_mat3(mat3: Mat3) -> Self {
219 #[allow(clippy::useless_conversion)]
220 Self {
221 matrix3: mat3.into(),
222 translation: Vec3::ZERO,
223 }
224 }
225
226 #[inline]
231 #[must_use]
232 pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
233 #[allow(clippy::useless_conversion)]
234 Self {
235 matrix3: mat3.into(),
236 translation: translation.into(),
237 }
238 }
239
240 #[inline]
250 #[must_use]
251 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
252 pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
253 let rotation = Mat3::from_quat(rotation);
254 #[allow(clippy::useless_conversion)]
255 Self {
256 matrix3: Mat3::from_cols(
257 rotation.x_axis * scale.x,
258 rotation.y_axis * scale.y,
259 rotation.z_axis * scale.z,
260 ),
261 translation: translation.into(),
262 }
263 }
264
265 #[inline]
273 #[must_use]
274 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
275 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
276 #[allow(clippy::useless_conversion)]
277 Self {
278 matrix3: Mat3::from_quat(rotation),
279 translation: translation.into(),
280 }
281 }
282
283 #[inline]
286 #[must_use]
287 pub fn from_mat4(m: Mat4) -> Self {
288 Self {
289 matrix3: Mat3::from_cols(
290 Vec3::from_vec4(m.x_axis),
291 Vec3::from_vec4(m.y_axis),
292 Vec3::from_vec4(m.z_axis),
293 ),
294 translation: Vec3::from_vec4(m.w_axis),
295 }
296 }
297
298 #[inline]
308 #[must_use]
309 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
310 pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
311 use crate::f32::math;
312 let det = self.matrix3.determinant();
313 glam_assert!(det != 0.0);
314
315 let scale = Vec3::new(
316 self.matrix3.x_axis.length() * math::signum(det),
317 self.matrix3.y_axis.length(),
318 self.matrix3.z_axis.length(),
319 );
320
321 glam_assert!(scale.cmpne(Vec3::ZERO).all());
322
323 let inv_scale = scale.recip();
324
325 #[allow(clippy::useless_conversion)]
326 let rotation = Quat::from_mat3(&Mat3::from_cols(
327 (self.matrix3.x_axis * inv_scale.x).into(),
328 (self.matrix3.y_axis * inv_scale.y).into(),
329 (self.matrix3.z_axis * inv_scale.z).into(),
330 ));
331
332 #[allow(clippy::useless_conversion)]
333 (scale, rotation, self.translation.into())
334 }
335
336 #[deprecated(
346 since = "0.33.1",
347 note = "use the `glam::camera::lh::view::look_to_affine3` function instead"
348 )]
349 #[inline]
350 #[must_use]
351 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
352 pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
353 #[allow(deprecated)]
354 Self::look_to_rh(eye, -dir, up)
355 }
356
357 #[deprecated(
367 since = "0.33.1",
368 note = "use the `glam::camera::rh::view::look_to_affine3` function instead"
369 )]
370 #[inline]
371 #[must_use]
372 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
373 pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
374 let f = dir.normalize();
375 let s = f.cross(up).normalize();
376 let u = s.cross(f);
377
378 Self {
379 matrix3: Mat3::from_cols(
380 Vec3::new(s.x, u.x, -f.x),
381 Vec3::new(s.y, u.y, -f.y),
382 Vec3::new(s.z, u.z, -f.z),
383 ),
384 translation: Vec3::new(-eye.dot(s), -eye.dot(u), eye.dot(f)),
385 }
386 }
387
388 #[deprecated(
397 since = "0.33.1",
398 note = "use the `glam::camera::lh::view::look_at_affine3` function instead"
399 )]
400 #[inline]
401 #[must_use]
402 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
403 pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
404 glam_assert!(up.is_normalized());
405 #[allow(deprecated)]
406 Self::look_to_lh(eye, center - eye, up)
407 }
408
409 #[deprecated(
418 since = "0.33.1",
419 note = "use the `glam::camera::rh::view::look_at_affine3` function instead"
420 )]
421 #[inline]
422 #[must_use]
423 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
424 pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
425 glam_assert!(up.is_normalized());
426 #[allow(deprecated)]
427 Self::look_to_rh(eye, center - eye, up)
428 }
429
430 #[inline]
432 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
433 #[allow(clippy::useless_conversion)]
434 ((self.matrix3.x_axis * rhs.x)
435 + (self.matrix3.y_axis * rhs.y)
436 + (self.matrix3.z_axis * rhs.z)
437 + self.translation)
438 .into()
439 }
440
441 #[inline]
446 #[must_use]
447 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
448 #[allow(clippy::useless_conversion)]
449 ((self.matrix3.x_axis * rhs.x)
450 + (self.matrix3.y_axis * rhs.y)
451 + (self.matrix3.z_axis * rhs.z))
452 .into()
453 }
454
455 #[inline]
460 #[must_use]
461 pub fn is_finite(&self) -> bool {
462 self.matrix3.is_finite() && self.translation.is_finite()
463 }
464
465 #[inline]
467 #[must_use]
468 pub fn is_nan(&self) -> bool {
469 self.matrix3.is_nan() || self.translation.is_nan()
470 }
471
472 #[inline]
482 #[must_use]
483 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
484 self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
485 && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
486 }
487
488 #[inline]
496 #[must_use]
497 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
498 pub fn inverse(&self) -> Self {
499 let matrix3 = self.matrix3.inverse();
500 let translation = -(matrix3 * self.translation);
502
503 Self {
504 matrix3,
505 translation,
506 }
507 }
508
509 #[cfg(feature = "f64")]
511 #[inline]
512 #[must_use]
513 pub fn as_daffine3(&self) -> crate::DAffine3 {
514 crate::DAffine3::from_mat3_translation(self.matrix3.as_dmat3(), self.translation.as_dvec3())
515 }
516}
517
518impl Default for Affine3 {
519 #[inline(always)]
520 fn default() -> Self {
521 Self::IDENTITY
522 }
523}
524
525impl Deref for Affine3 {
526 type Target = crate::deref::Cols4<Vec3>;
527 #[inline(always)]
528 fn deref(&self) -> &Self::Target {
529 unsafe { &*(self as *const Self as *const Self::Target) }
530 }
531}
532
533impl DerefMut for Affine3 {
534 #[inline(always)]
535 fn deref_mut(&mut self) -> &mut Self::Target {
536 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
537 }
538}
539
540impl PartialEq for Affine3 {
541 #[inline]
542 fn eq(&self, rhs: &Self) -> bool {
543 self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
544 }
545}
546
547impl core::fmt::Debug for Affine3 {
548 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
549 fmt.debug_struct(stringify!(Affine3))
550 .field("matrix3", &self.matrix3)
551 .field("translation", &self.translation)
552 .finish()
553 }
554}
555
556impl core::fmt::Display for Affine3 {
557 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
558 if let Some(p) = f.precision() {
559 write!(
560 f,
561 "[{:.*}, {:.*}, {:.*}, {:.*}]",
562 p,
563 self.matrix3.x_axis,
564 p,
565 self.matrix3.y_axis,
566 p,
567 self.matrix3.z_axis,
568 p,
569 self.translation
570 )
571 } else {
572 write!(
573 f,
574 "[{}, {}, {}, {}]",
575 self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
576 )
577 }
578 }
579}
580
581impl<'a> core::iter::Product<&'a Self> for Affine3 {
582 fn product<I>(iter: I) -> Self
583 where
584 I: Iterator<Item = &'a Self>,
585 {
586 iter.fold(Self::IDENTITY, |a, &b| a * b)
587 }
588}
589
590impl Mul for Affine3 {
591 type Output = Self;
592
593 #[inline]
594 fn mul(self, rhs: Self) -> Self {
595 Self {
596 matrix3: self.matrix3 * rhs.matrix3,
597 translation: self.matrix3 * rhs.translation + self.translation,
598 }
599 }
600}
601
602impl Mul<&Self> for Affine3 {
603 type Output = Self;
604 #[inline]
605 fn mul(self, rhs: &Self) -> Self {
606 self.mul(*rhs)
607 }
608}
609
610impl Mul<&Affine3> for &Affine3 {
611 type Output = Affine3;
612 #[inline]
613 fn mul(self, rhs: &Affine3) -> Affine3 {
614 (*self).mul(*rhs)
615 }
616}
617
618impl Mul<Affine3> for &Affine3 {
619 type Output = Affine3;
620 #[inline]
621 fn mul(self, rhs: Affine3) -> Affine3 {
622 (*self).mul(rhs)
623 }
624}
625
626impl MulAssign for Affine3 {
627 #[inline]
628 fn mul_assign(&mut self, rhs: Self) {
629 *self = self.mul(rhs);
630 }
631}
632
633impl MulAssign<&Self> for Affine3 {
634 #[inline]
635 fn mul_assign(&mut self, rhs: &Self) {
636 self.mul_assign(*rhs);
637 }
638}
639
640impl Mul<Mat4> for Affine3 {
641 type Output = Mat4;
642
643 #[inline]
644 fn mul(self, rhs: Mat4) -> Self::Output {
645 Mat4::from(self) * rhs
646 }
647}
648
649impl Mul<&Mat4> for Affine3 {
650 type Output = Mat4;
651 #[inline]
652 fn mul(self, rhs: &Mat4) -> Mat4 {
653 self.mul(*rhs)
654 }
655}
656
657impl Mul<&Mat4> for &Affine3 {
658 type Output = Mat4;
659 #[inline]
660 fn mul(self, rhs: &Mat4) -> Mat4 {
661 (*self).mul(*rhs)
662 }
663}
664
665impl Mul<Mat4> for &Affine3 {
666 type Output = Mat4;
667 #[inline]
668 fn mul(self, rhs: Mat4) -> Mat4 {
669 (*self).mul(rhs)
670 }
671}
672
673impl Mul<Affine3> for Mat4 {
674 type Output = Self;
675
676 #[inline]
677 fn mul(self, rhs: Affine3) -> Self {
678 self * Self::from(rhs)
679 }
680}
681
682impl Mul<&Affine3> for Mat4 {
683 type Output = Self;
684 #[inline]
685 fn mul(self, rhs: &Affine3) -> Self {
686 self.mul(*rhs)
687 }
688}
689
690impl Mul<&Affine3> for &Mat4 {
691 type Output = Mat4;
692 #[inline]
693 fn mul(self, rhs: &Affine3) -> Mat4 {
694 (*self).mul(*rhs)
695 }
696}
697
698impl Mul<Affine3> for &Mat4 {
699 type Output = Mat4;
700 #[inline]
701 fn mul(self, rhs: Affine3) -> Mat4 {
702 (*self).mul(rhs)
703 }
704}
705
706impl MulAssign<Affine3> for Mat4 {
707 #[inline]
708 fn mul_assign(&mut self, rhs: Affine3) {
709 *self = self.mul(rhs);
710 }
711}
712
713impl MulAssign<&Affine3> for Mat4 {
714 #[inline]
715 fn mul_assign(&mut self, rhs: &Affine3) {
716 self.mul_assign(*rhs);
717 }
718}
719
720impl From<Affine3> for Mat4 {
721 #[inline]
722 fn from(m: Affine3) -> Self {
723 Self::from_cols(
724 m.matrix3.x_axis.extend(0.0),
725 m.matrix3.y_axis.extend(0.0),
726 m.matrix3.z_axis.extend(0.0),
727 m.translation.extend(1.0),
728 )
729 }
730}
731
732impl From<Affine3A> for Affine3 {
733 #[inline]
734 fn from(a: Affine3A) -> Self {
735 Self::from_cols(
736 a.matrix3.x_axis.into(),
737 a.matrix3.y_axis.into(),
738 a.matrix3.z_axis.into(),
739 a.translation.into(),
740 )
741 }
742}