baba/gfx/
transform.rs

1use std::ops::Mul;
2
3use crate::math::{Affine2, Mat2, Mat3, Vec2};
4
5/// Two-dimensional coordinate transformation.
6#[must_use]
7#[derive(Debug, Default, Clone, Copy)]
8pub struct Transform(Affine2);
9
10impl Transform {
11    /// The identity transform. Essentially, it does nothing.
12    pub const IDENTITY: Self = Self::from_affine(Affine2::IDENTITY);
13
14    /// Create a transform from an affine transformation matrix.
15    #[inline]
16    pub const fn from_affine(aff: Affine2) -> Self {
17        Self(aff)
18    }
19
20    /// Create a transform with translation.
21    #[inline]
22    pub fn from_translation(coords: Vec2) -> Self {
23        Self(Affine2::from_translation(coords))
24    }
25
26    /// Create a transform with scale.
27    #[inline]
28    pub fn from_scale(scale: Vec2) -> Self {
29        Self(Affine2::from_scale(scale))
30    }
31
32    /// Create a transform with `angle` (in radians).
33    #[inline]
34    pub fn from_rotation(angle: f32) -> Self {
35        Self(Affine2::from_angle(angle))
36    }
37
38    /// Translate this transform by `coords`.
39    #[inline]
40    pub fn translate(self, coords: Vec2) -> Self {
41        self * Self::from_translation(coords)
42    }
43
44    /// Scale this transform by `scale`.
45    #[inline]
46    pub fn scale(self, scale: Vec2) -> Self {
47        self * Self::from_scale(scale)
48    }
49
50    /// Rotate this transform by `angle` (in radians).
51    #[inline]
52    pub fn rotate(self, angle: f32) -> Self {
53        self * Self::from_rotation(angle)
54    }
55
56    /// Get the affine transformation matrix for this transform.
57    #[must_use]
58    pub const fn to_affine(self) -> Affine2 {
59        self.0
60    }
61
62    /// Transform a 2D point with this object.
63    ///
64    /// This may translate, scale and rotate.
65    #[must_use]
66    #[inline]
67    pub fn transform_point(&self, point: Vec2) -> Vec2 {
68        self.0.transform_point2(point)
69    }
70}
71
72impl Mul for Transform {
73    type Output = Self;
74
75    #[inline]
76    fn mul(self, rhs: Self) -> Self::Output {
77        Self(self.0 * rhs.0)
78    }
79}
80
81impl From<Mat3> for Transform {
82    #[inline]
83    fn from(value: Mat3) -> Self {
84        Self(Affine2::from_mat3(value))
85    }
86}
87
88impl From<Mat2> for Transform {
89    #[inline]
90    fn from(value: Mat2) -> Self {
91        Self(Affine2::from_mat2(value))
92    }
93}
94
95impl From<()> for Transform {
96    #[inline]
97    fn from((): ()) -> Self {
98        Self::IDENTITY
99    }
100}
101
102macro_rules! impl_translation_scale_rotation {
103    ($T:ty, $U:ty, $V:ty) => {
104        impl From<($T, $U, $V)> for Transform {
105            /// Create a transform with translation, scale and rotation.
106            #[inline]
107            fn from((translation, scale, angle): ($T, $U, $V)) -> Self {
108                Self::from_translation(translation.into())
109                    .scale(scale.into())
110                    .rotate(angle.into())
111            }
112        }
113    };
114}
115
116macro_rules! impl_translation_scale {
117    ($T:ty, $U:ty) => {
118        impl From<($T, $U)> for Transform {
119            /// Create a transform with translation and scale.
120            #[inline]
121            fn from((translation, scale): ($T, $U)) -> Self {
122                Self::from_translation(translation.into()).scale(scale.into())
123            }
124        }
125
126        impl_translation_scale_rotation!($T, $U, f32);
127    };
128}
129
130macro_rules! impl_translation {
131    ($T:ty) => {
132        impl From<$T> for Transform {
133            /// Create a transform with translation.
134            #[inline]
135            fn from(value: $T) -> Self {
136                Self::from_translation(value.into())
137            }
138        }
139
140        impl_translation_scale!($T, Vec2);
141        impl_translation_scale!($T, (f32, f32));
142        impl_translation_scale!($T, [f32; 2]);
143    };
144}
145
146impl_translation!(Vec2);
147impl_translation!((f32, f32));
148impl_translation!([f32; 2]);