mirage_engine/
transform.rs1use bytemuck::{Pod, Zeroable};
2
3use crate::math::{Mat4, Quat, Vec3};
4
5#[repr(transparent)]
7#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
8pub struct Transform(Mat4);
9
10impl Transform {
11 pub const IDENTITY: Self = Self(Mat4::IDENTITY);
13
14 pub fn from_translation(translation: Vec3) -> Self {
16 Self(Mat4::from_translation(translation))
17 }
18
19 pub fn from_rotation(rotation: Quat) -> Self {
21 Self(Mat4::from_quat(rotation))
22 }
23
24 pub fn from_scale(scale: Vec3) -> Self {
26 Self(Mat4::from_scale(scale))
27 }
28
29 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
31 Self(Mat4::from_rotation_translation(rotation, translation))
32 }
33
34 pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
36 Self(Mat4::from_scale_rotation_translation(
37 scale,
38 rotation,
39 translation,
40 ))
41 }
42
43 pub const fn matrix(self) -> Mat4 {
45 self.0
46 }
47
48 pub(crate) fn is_finite(self) -> bool {
51 self.0.is_finite()
52 }
53}
54
55impl core::ops::Mul for Transform {
56 type Output = Self;
57
58 fn mul(self, after: Self) -> Self {
61 Self(self.0 * after.0)
62 }
63}
64
65impl Default for Transform {
66 fn default() -> Self {
68 Self::IDENTITY
69 }
70}
71
72impl From<Vec3> for Transform {
73 fn from(translation: Vec3) -> Self {
75 Self::from_translation(translation)
76 }
77}
78
79impl From<Mat4> for Transform {
80 fn from(matrix: Mat4) -> Self {
82 Self(matrix)
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn a_rotation_and_a_translation_turn_a_point_before_they_move_it() {
92 let quarter = Quat::from_rotation_y(core::f32::consts::FRAC_PI_2);
93 let placed = Transform::from_rotation_translation(quarter, Vec3::X);
94
95 let point = placed.matrix().transform_point3(Vec3::X);
96
97 assert!(
98 point.abs_diff_eq(Vec3::new(1.0, 0.0, -1.0), 1e-6),
99 "a quarter turn takes {} onto {}, which the meter out then places at {point}",
100 Vec3::X,
101 Vec3::NEG_Z
102 );
103 assert!(
104 !point.abs_diff_eq(Vec3::new(0.0, 0.0, -2.0), 1e-6),
105 "and the meter is not moved before the turn"
106 );
107 }
108}