1use crate::{DMat3, DMat4, DQuat, DVec3};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6#[cfg(feature = "zerocopy-08")]
7use zerocopy_derive_08::*;
8
9#[derive(Copy, Clone)]
11#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
12#[cfg_attr(
13 feature = "zerocopy-08",
14 derive(FromBytes, Immutable, IntoBytes, KnownLayout)
15)]
16#[repr(C)]
17pub struct DAffine3 {
18 pub matrix3: DMat3,
19 pub translation: DVec3,
20}
21
22impl DAffine3 {
23 pub const ZERO: Self = Self {
28 matrix3: DMat3::ZERO,
29 translation: DVec3::ZERO,
30 };
31
32 pub const IDENTITY: Self = Self {
36 matrix3: DMat3::IDENTITY,
37 translation: DVec3::ZERO,
38 };
39
40 pub const NAN: Self = Self {
42 matrix3: DMat3::NAN,
43 translation: DVec3::NAN,
44 };
45
46 #[inline(always)]
48 #[must_use]
49 pub const fn from_cols(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3, w_axis: DVec3) -> Self {
50 Self {
51 matrix3: DMat3::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: &[f64; 12]) -> Self {
60 Self {
61 matrix3: DMat3::from_cols_array(&[
62 m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8],
63 ]),
64 translation: DVec3::from_array([m[9], m[10], m[11]]),
65 }
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn to_cols_array(&self) -> [f64; 12] {
72 let x = &self.matrix3.x_axis;
73 let y = &self.matrix3.y_axis;
74 let z = &self.matrix3.z_axis;
75 let w = &self.translation;
76 [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
77 }
78
79 #[inline]
84 #[must_use]
85 pub fn from_cols_array_2d(m: &[[f64; 3]; 4]) -> Self {
86 Self {
87 matrix3: DMat3::from_cols(m[0].into(), m[1].into(), m[2].into()),
88 translation: m[3].into(),
89 }
90 }
91
92 #[inline]
96 #[must_use]
97 pub fn to_cols_array_2d(&self) -> [[f64; 3]; 4] {
98 [
99 self.matrix3.x_axis.into(),
100 self.matrix3.y_axis.into(),
101 self.matrix3.z_axis.into(),
102 self.translation.into(),
103 ]
104 }
105
106 #[inline]
112 #[must_use]
113 pub fn from_cols_slice(slice: &[f64]) -> Self {
114 Self {
115 matrix3: DMat3::from_cols_slice(&slice[0..9]),
116 translation: DVec3::from_slice(&slice[9..12]),
117 }
118 }
119
120 #[inline]
126 pub fn write_cols_to_slice(&self, slice: &mut [f64]) {
127 self.matrix3.write_cols_to_slice(&mut slice[0..9]);
128 self.translation.write_to_slice(&mut slice[9..12]);
129 }
130
131 #[inline]
134 #[must_use]
135 pub fn from_scale(scale: DVec3) -> Self {
136 Self {
137 matrix3: DMat3::from_diagonal(scale),
138 translation: DVec3::ZERO,
139 }
140 }
141 #[inline]
147 #[must_use]
148 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
149 pub fn from_quat(rotation: DQuat) -> Self {
150 Self {
151 matrix3: DMat3::from_quat(rotation),
152 translation: DVec3::ZERO,
153 }
154 }
155
156 #[inline]
163 #[must_use]
164 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
165 pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
166 Self {
167 matrix3: DMat3::from_axis_angle(axis, angle),
168 translation: DVec3::ZERO,
169 }
170 }
171
172 #[inline]
175 #[must_use]
176 pub fn from_rotation_x(angle: f64) -> Self {
177 Self {
178 matrix3: DMat3::from_rotation_x(angle),
179 translation: DVec3::ZERO,
180 }
181 }
182
183 #[inline]
186 #[must_use]
187 pub fn from_rotation_y(angle: f64) -> Self {
188 Self {
189 matrix3: DMat3::from_rotation_y(angle),
190 translation: DVec3::ZERO,
191 }
192 }
193
194 #[inline]
197 #[must_use]
198 pub fn from_rotation_z(angle: f64) -> Self {
199 Self {
200 matrix3: DMat3::from_rotation_z(angle),
201 translation: DVec3::ZERO,
202 }
203 }
204
205 #[inline]
207 #[must_use]
208 pub fn from_translation(translation: DVec3) -> Self {
209 #[allow(clippy::useless_conversion)]
210 Self {
211 matrix3: DMat3::IDENTITY,
212 translation: translation.into(),
213 }
214 }
215
216 #[inline]
219 #[must_use]
220 pub fn from_mat3(mat3: DMat3) -> Self {
221 #[allow(clippy::useless_conversion)]
222 Self {
223 matrix3: mat3.into(),
224 translation: DVec3::ZERO,
225 }
226 }
227
228 #[inline]
233 #[must_use]
234 pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
235 #[allow(clippy::useless_conversion)]
236 Self {
237 matrix3: mat3.into(),
238 translation: translation.into(),
239 }
240 }
241
242 #[inline]
252 #[must_use]
253 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
254 pub fn from_scale_rotation_translation(
255 scale: DVec3,
256 rotation: DQuat,
257 translation: DVec3,
258 ) -> Self {
259 let rotation = DMat3::from_quat(rotation);
260 #[allow(clippy::useless_conversion)]
261 Self {
262 matrix3: DMat3::from_cols(
263 rotation.x_axis * scale.x,
264 rotation.y_axis * scale.y,
265 rotation.z_axis * scale.z,
266 ),
267 translation: translation.into(),
268 }
269 }
270
271 #[inline]
279 #[must_use]
280 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
281 pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
282 #[allow(clippy::useless_conversion)]
283 Self {
284 matrix3: DMat3::from_quat(rotation),
285 translation: translation.into(),
286 }
287 }
288
289 #[inline]
292 #[must_use]
293 pub fn from_mat4(m: DMat4) -> Self {
294 Self {
295 matrix3: DMat3::from_cols(
296 DVec3::from_vec4(m.x_axis),
297 DVec3::from_vec4(m.y_axis),
298 DVec3::from_vec4(m.z_axis),
299 ),
300 translation: DVec3::from_vec4(m.w_axis),
301 }
302 }
303
304 #[inline]
314 #[must_use]
315 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
316 pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
317 use crate::f64::math;
318 let det = self.matrix3.determinant();
319 glam_assert!(det != 0.0);
320
321 let scale = DVec3::new(
322 self.matrix3.x_axis.length() * math::signum(det),
323 self.matrix3.y_axis.length(),
324 self.matrix3.z_axis.length(),
325 );
326
327 glam_assert!(scale.cmpne(DVec3::ZERO).all());
328
329 let inv_scale = scale.recip();
330
331 #[allow(clippy::useless_conversion)]
332 let rotation = DQuat::from_mat3(&DMat3::from_cols(
333 (self.matrix3.x_axis * inv_scale.x).into(),
334 (self.matrix3.y_axis * inv_scale.y).into(),
335 (self.matrix3.z_axis * inv_scale.z).into(),
336 ));
337
338 #[allow(clippy::useless_conversion)]
339 (scale, rotation, self.translation.into())
340 }
341
342 #[deprecated(
352 since = "0.33.1",
353 note = "use the `glam::dcamera::lh::view::look_to_affine3` function instead"
354 )]
355 #[inline]
356 #[must_use]
357 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
358 pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
359 #[allow(deprecated)]
360 Self::look_to_rh(eye, -dir, up)
361 }
362
363 #[deprecated(
373 since = "0.33.1",
374 note = "use the `glam::dcamera::rh::view::look_to_affine3` function instead"
375 )]
376 #[inline]
377 #[must_use]
378 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
379 pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
380 let f = dir.normalize();
381 let s = f.cross(up).normalize();
382 let u = s.cross(f);
383
384 Self {
385 matrix3: DMat3::from_cols(
386 DVec3::new(s.x, u.x, -f.x),
387 DVec3::new(s.y, u.y, -f.y),
388 DVec3::new(s.z, u.z, -f.z),
389 ),
390 translation: DVec3::new(-eye.dot(s), -eye.dot(u), eye.dot(f)),
391 }
392 }
393
394 #[deprecated(
403 since = "0.33.1",
404 note = "use the `glam::dcamera::lh::view::look_at_affine3` function instead"
405 )]
406 #[inline]
407 #[must_use]
408 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
409 pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
410 glam_assert!(up.is_normalized());
411 #[allow(deprecated)]
412 Self::look_to_lh(eye, center - eye, up)
413 }
414
415 #[deprecated(
424 since = "0.33.1",
425 note = "use the `glam::dcamera::rh::view::look_at_affine3` function instead"
426 )]
427 #[inline]
428 #[must_use]
429 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
430 pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
431 glam_assert!(up.is_normalized());
432 #[allow(deprecated)]
433 Self::look_to_rh(eye, center - eye, up)
434 }
435
436 #[inline]
438 pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
439 #[allow(clippy::useless_conversion)]
440 ((self.matrix3.x_axis * rhs.x)
441 + (self.matrix3.y_axis * rhs.y)
442 + (self.matrix3.z_axis * rhs.z)
443 + self.translation)
444 .into()
445 }
446
447 #[inline]
452 #[must_use]
453 pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
454 #[allow(clippy::useless_conversion)]
455 ((self.matrix3.x_axis * rhs.x)
456 + (self.matrix3.y_axis * rhs.y)
457 + (self.matrix3.z_axis * rhs.z))
458 .into()
459 }
460
461 #[inline]
466 #[must_use]
467 pub fn is_finite(&self) -> bool {
468 self.matrix3.is_finite() && self.translation.is_finite()
469 }
470
471 #[inline]
473 #[must_use]
474 pub fn is_nan(&self) -> bool {
475 self.matrix3.is_nan() || self.translation.is_nan()
476 }
477
478 #[inline]
488 #[must_use]
489 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
490 self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
491 && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
492 }
493
494 #[inline]
502 #[must_use]
503 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
504 pub fn inverse(&self) -> Self {
505 let matrix3 = self.matrix3.inverse();
506 let translation = -(matrix3 * self.translation);
508
509 Self {
510 matrix3,
511 translation,
512 }
513 }
514
515 #[inline]
517 #[must_use]
518 pub fn as_affine3(&self) -> crate::Affine3 {
519 crate::Affine3::from_mat3_translation(self.matrix3.as_mat3(), self.translation.as_vec3())
520 }
521
522 #[inline]
524 #[must_use]
525 pub fn as_affine3a(&self) -> crate::Affine3A {
526 crate::Affine3A::from_mat3_translation(self.matrix3.as_mat3(), self.translation.as_vec3())
527 }
528}
529
530impl Default for DAffine3 {
531 #[inline(always)]
532 fn default() -> Self {
533 Self::IDENTITY
534 }
535}
536
537impl Deref for DAffine3 {
538 type Target = crate::deref::Cols4<DVec3>;
539 #[inline(always)]
540 fn deref(&self) -> &Self::Target {
541 unsafe { &*(self as *const Self as *const Self::Target) }
542 }
543}
544
545impl DerefMut for DAffine3 {
546 #[inline(always)]
547 fn deref_mut(&mut self) -> &mut Self::Target {
548 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
549 }
550}
551
552impl PartialEq for DAffine3 {
553 #[inline]
554 fn eq(&self, rhs: &Self) -> bool {
555 self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
556 }
557}
558
559impl core::fmt::Debug for DAffine3 {
560 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
561 fmt.debug_struct(stringify!(DAffine3))
562 .field("matrix3", &self.matrix3)
563 .field("translation", &self.translation)
564 .finish()
565 }
566}
567
568impl core::fmt::Display for DAffine3 {
569 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
570 if let Some(p) = f.precision() {
571 write!(
572 f,
573 "[{:.*}, {:.*}, {:.*}, {:.*}]",
574 p,
575 self.matrix3.x_axis,
576 p,
577 self.matrix3.y_axis,
578 p,
579 self.matrix3.z_axis,
580 p,
581 self.translation
582 )
583 } else {
584 write!(
585 f,
586 "[{}, {}, {}, {}]",
587 self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
588 )
589 }
590 }
591}
592
593impl<'a> core::iter::Product<&'a Self> for DAffine3 {
594 fn product<I>(iter: I) -> Self
595 where
596 I: Iterator<Item = &'a Self>,
597 {
598 iter.fold(Self::IDENTITY, |a, &b| a * b)
599 }
600}
601
602impl Mul for DAffine3 {
603 type Output = Self;
604
605 #[inline]
606 fn mul(self, rhs: Self) -> Self {
607 Self {
608 matrix3: self.matrix3 * rhs.matrix3,
609 translation: self.matrix3 * rhs.translation + self.translation,
610 }
611 }
612}
613
614impl Mul<&Self> for DAffine3 {
615 type Output = Self;
616 #[inline]
617 fn mul(self, rhs: &Self) -> Self {
618 self.mul(*rhs)
619 }
620}
621
622impl Mul<&DAffine3> for &DAffine3 {
623 type Output = DAffine3;
624 #[inline]
625 fn mul(self, rhs: &DAffine3) -> DAffine3 {
626 (*self).mul(*rhs)
627 }
628}
629
630impl Mul<DAffine3> for &DAffine3 {
631 type Output = DAffine3;
632 #[inline]
633 fn mul(self, rhs: DAffine3) -> DAffine3 {
634 (*self).mul(rhs)
635 }
636}
637
638impl MulAssign for DAffine3 {
639 #[inline]
640 fn mul_assign(&mut self, rhs: Self) {
641 *self = self.mul(rhs);
642 }
643}
644
645impl MulAssign<&Self> for DAffine3 {
646 #[inline]
647 fn mul_assign(&mut self, rhs: &Self) {
648 self.mul_assign(*rhs);
649 }
650}
651
652impl Mul<DMat4> for DAffine3 {
653 type Output = DMat4;
654
655 #[inline]
656 fn mul(self, rhs: DMat4) -> Self::Output {
657 DMat4::from(self) * rhs
658 }
659}
660
661impl Mul<&DMat4> for DAffine3 {
662 type Output = DMat4;
663 #[inline]
664 fn mul(self, rhs: &DMat4) -> DMat4 {
665 self.mul(*rhs)
666 }
667}
668
669impl Mul<&DMat4> for &DAffine3 {
670 type Output = DMat4;
671 #[inline]
672 fn mul(self, rhs: &DMat4) -> DMat4 {
673 (*self).mul(*rhs)
674 }
675}
676
677impl Mul<DMat4> for &DAffine3 {
678 type Output = DMat4;
679 #[inline]
680 fn mul(self, rhs: DMat4) -> DMat4 {
681 (*self).mul(rhs)
682 }
683}
684
685impl Mul<DAffine3> for DMat4 {
686 type Output = Self;
687
688 #[inline]
689 fn mul(self, rhs: DAffine3) -> Self {
690 self * Self::from(rhs)
691 }
692}
693
694impl Mul<&DAffine3> for DMat4 {
695 type Output = Self;
696 #[inline]
697 fn mul(self, rhs: &DAffine3) -> Self {
698 self.mul(*rhs)
699 }
700}
701
702impl Mul<&DAffine3> for &DMat4 {
703 type Output = DMat4;
704 #[inline]
705 fn mul(self, rhs: &DAffine3) -> DMat4 {
706 (*self).mul(*rhs)
707 }
708}
709
710impl Mul<DAffine3> for &DMat4 {
711 type Output = DMat4;
712 #[inline]
713 fn mul(self, rhs: DAffine3) -> DMat4 {
714 (*self).mul(rhs)
715 }
716}
717
718impl MulAssign<DAffine3> for DMat4 {
719 #[inline]
720 fn mul_assign(&mut self, rhs: DAffine3) {
721 *self = self.mul(rhs);
722 }
723}
724
725impl MulAssign<&DAffine3> for DMat4 {
726 #[inline]
727 fn mul_assign(&mut self, rhs: &DAffine3) {
728 self.mul_assign(*rhs);
729 }
730}
731
732impl From<DAffine3> for DMat4 {
733 #[inline]
734 fn from(m: DAffine3) -> Self {
735 Self::from_cols(
736 m.matrix3.x_axis.extend(0.0),
737 m.matrix3.y_axis.extend(0.0),
738 m.matrix3.z_axis.extend(0.0),
739 m.translation.extend(1.0),
740 )
741 }
742}