1use super::mat::{Mat3, Mat4};
7
8pub fn translate_2d(tx: f64, ty: f64) -> Mat3 {
14 Mat3::new([[1.0, 0.0, tx], [0.0, 1.0, ty], [0.0, 0.0, 1.0]])
15}
16
17pub fn rotate_2d(angle: f64) -> Mat3 {
19 let c = angle.cos();
20 let s = angle.sin();
21 Mat3::new([[c, -s, 0.0], [s, c, 0.0], [0.0, 0.0, 1.0]])
22}
23
24pub fn scale_2d(sx: f64, sy: f64) -> Mat3 {
26 Mat3::new([[sx, 0.0, 0.0], [0.0, sy, 0.0], [0.0, 0.0, 1.0]])
27}
28
29pub fn scale_2d_uniform(s: f64) -> Mat3 {
31 scale_2d(s, s)
32}
33
34pub fn shear_2d(shx: f64, shy: f64) -> Mat3 {
36 Mat3::new([[1.0, shx, 0.0], [shy, 1.0, 0.0], [0.0, 0.0, 1.0]])
37}
38
39pub fn compose_2d(a: &Mat3, b: &Mat3) -> Mat3 {
41 a.mul(b)
42}
43
44pub fn translate_3d(tx: f64, ty: f64, tz: f64) -> Mat4 {
50 Mat4::new([
51 [1.0, 0.0, 0.0, tx],
52 [0.0, 1.0, 0.0, ty],
53 [0.0, 0.0, 1.0, tz],
54 [0.0, 0.0, 0.0, 1.0],
55 ])
56}
57
58pub fn scale_3d(sx: f64, sy: f64, sz: f64) -> Mat4 {
60 Mat4::new([
61 [sx, 0.0, 0.0, 0.0],
62 [0.0, sy, 0.0, 0.0],
63 [0.0, 0.0, sz, 0.0],
64 [0.0, 0.0, 0.0, 1.0],
65 ])
66}
67
68pub fn rotate_x(angle: f64) -> Mat4 {
70 let c = angle.cos();
71 let s = angle.sin();
72 Mat4::new([
73 [1.0, 0.0, 0.0, 0.0],
74 [0.0, c, -s, 0.0],
75 [0.0, s, c, 0.0],
76 [0.0, 0.0, 0.0, 1.0],
77 ])
78}
79
80pub fn rotate_y(angle: f64) -> Mat4 {
82 let c = angle.cos();
83 let s = angle.sin();
84 Mat4::new([
85 [c, 0.0, s, 0.0],
86 [0.0, 1.0, 0.0, 0.0],
87 [-s, 0.0, c, 0.0],
88 [0.0, 0.0, 0.0, 1.0],
89 ])
90}
91
92pub fn rotate_z(angle: f64) -> Mat4 {
94 let c = angle.cos();
95 let s = angle.sin();
96 Mat4::new([
97 [c, -s, 0.0, 0.0],
98 [s, c, 0.0, 0.0],
99 [0.0, 0.0, 1.0, 0.0],
100 [0.0, 0.0, 0.0, 1.0],
101 ])
102}
103
104pub fn ortho(left: f64, right: f64, bottom: f64, top: f64, near: f64, far: f64) -> Mat4 {
106 let rl = right - left;
107 let tb = top - bottom;
108 let fn_ = far - near;
109 Mat4::new([
110 [2.0 / rl, 0.0, 0.0, -(right + left) / rl],
111 [0.0, 2.0 / tb, 0.0, -(top + bottom) / tb],
112 [0.0, 0.0, -2.0 / fn_, -(far + near) / fn_],
113 [0.0, 0.0, 0.0, 1.0],
114 ])
115}
116
117pub fn perspective(fov_y: f64, aspect: f64, near: f64, far: f64) -> Mat4 {
119 let f = 1.0 / (fov_y / 2.0).tan();
120 let nf = near - far;
121 Mat4::new([
122 [f / aspect, 0.0, 0.0, 0.0],
123 [0.0, f, 0.0, 0.0],
124 [0.0, 0.0, (far + near) / nf, 2.0 * far * near / nf],
125 [0.0, 0.0, -1.0, 0.0],
126 ])
127}
128
129pub fn viewport(width: f64, height: f64) -> Mat3 {
131 let hw = width / 2.0;
132 let hh = height / 2.0;
133 Mat3::new([
134 [hw, 0.0, hw],
135 [0.0, -hh, hh], [0.0, 0.0, 1.0],
137 ])
138}
139
140pub fn compose_3d(a: &Mat4, b: &Mat4) -> Mat4 {
142 a.mul(b)
143}
144
145#[cfg(test)]
150mod tests {
151 use super::super::vec::Vec2;
152 use super::*;
153
154 #[test]
155 fn translate_2d_moves_point() {
156 let m = translate_2d(10.0, 20.0);
157 let p = m.transform_point(Vec2::new(1.0, 2.0));
158 assert!((p.x - 11.0).abs() < 1e-10);
159 assert!((p.y - 22.0).abs() < 1e-10);
160 }
161
162 #[test]
163 fn rotate_2d_90_degrees() {
164 let m = rotate_2d(core::f64::consts::FRAC_PI_2);
165 let p = m.transform_point(Vec2::new(1.0, 0.0));
166 assert!((p.x - 0.0).abs() < 1e-10);
167 assert!((p.y - 1.0).abs() < 1e-10);
168 }
169
170 #[test]
171 fn scale_2d_doubles() {
172 let m = scale_2d(2.0, 3.0);
173 let p = m.transform_point(Vec2::new(5.0, 7.0));
174 assert!((p.x - 10.0).abs() < 1e-10);
175 assert!((p.y - 21.0).abs() < 1e-10);
176 }
177
178 #[test]
179 fn compose_translate_then_rotate() {
180 let t = translate_2d(1.0, 0.0);
182 let r = rotate_2d(core::f64::consts::FRAC_PI_2);
183 let m = compose_2d(&r, &t); let p = m.transform_point(Vec2::ZERO);
185 assert!((p.x - 0.0).abs() < 1e-10);
187 assert!((p.y - 1.0).abs() < 1e-10);
188 }
189
190 #[test]
191 fn viewport_maps_ndc_to_pixels() {
192 let v = viewport(800.0, 600.0);
193 let center = v.transform_point(Vec2::ZERO);
195 assert!((center.x - 400.0).abs() < 1e-10);
196 assert!((center.y - 300.0).abs() < 1e-10);
197 let tl = v.transform_point(Vec2::new(-1.0, 1.0));
199 assert!((tl.x - 0.0).abs() < 1e-10);
200 assert!((tl.y - 0.0).abs() < 1e-10);
201 }
202
203 #[test]
204 fn translate_3d_moves_point() {
205 let m = translate_3d(1.0, 2.0, 3.0);
206 let p = super::super::vec::Vec3::new(10.0, 20.0, 30.0);
207 let result = m.transform_point(p);
208 assert!((result.x - 11.0).abs() < 1e-10);
209 assert!((result.y - 22.0).abs() < 1e-10);
210 assert!((result.z - 33.0).abs() < 1e-10);
211 }
212
213 #[test]
214 fn rotate_z_90_degrees() {
215 let m = rotate_z(core::f64::consts::FRAC_PI_2);
216 let p = super::super::vec::Vec3::new(1.0, 0.0, 0.0);
217 let result = m.transform_point(p);
218 assert!((result.x - 0.0).abs() < 1e-10);
219 assert!((result.y - 1.0).abs() < 1e-10);
220 }
221}