1  #[macro_use]
2  mod support;
3  
4  macro_rules! impl_mat4_tests {
5      ($t:ident, $newmat4:ident, $newvec4:ident, $newvec3:ident, $mat4:ident, $mat3:ident, $quat:ident, $vec4:ident, $vec3:ident) => {
6          use core::$t::INFINITY;
7          use core::$t::NAN;
8          use core::$t::NEG_INFINITY;
9  
10          const IDENTITY: [[$t; 4]; 4] = [
11              [1.0, 0.0, 0.0, 0.0],
12              [0.0, 1.0, 0.0, 0.0],
13              [0.0, 0.0, 1.0, 0.0],
14              [0.0, 0.0, 0.0, 1.0],
15          ];
16          const MATRIX: [[$t; 4]; 4] = [
17              [1.0, 2.0, 3.0, 4.0],
18              [5.0, 6.0, 7.0, 8.0],
19              [9.0, 10.0, 11.0, 12.0],
20              [13.0, 14.0, 15.0, 16.0],
21          ];
22  
23          const MATRIX1D: [$t; 16] = [
24              1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
25          ];
26  
27          glam_test!(test_const, {
28              const M0: $mat4 = $mat4::from_cols(
29                  $newvec4(1.0, 2.0, 3.0, 4.0),
30                  $newvec4(5.0, 6.0, 7.0, 8.0),
31                  $newvec4(9.0, 10.0, 11.0, 12.0),
32                  $newvec4(13.0, 14.0, 15.0, 16.0),
33              );
34              const M1: $mat4 = $mat4::from_cols_array(&MATRIX1D);
35              const M2: $mat4 = $mat4::from_cols_array_2d(&MATRIX);
36  
37              assert_eq!(MATRIX1D, M0.to_cols_array());
38              assert_eq!(MATRIX1D, M1.to_cols_array());
39              assert_eq!(MATRIX1D, M2.to_cols_array());
40          });
41  
42          glam_test!(test_mat4_identity, {
43              assert_eq!(
44                  $mat4::IDENTITY,
45                  $mat4::from_cols_array(&[
46                      1., 0., 0., 0., //
47                      0., 1., 0., 0., //
48                      0., 0., 1., 0., //
49                      0., 0., 0., 1., //
50                  ])
51              );
52              let identity = $mat4::IDENTITY;
53              assert_eq!(IDENTITY, identity.to_cols_array_2d());
54              assert_eq!($mat4::from_cols_array_2d(&IDENTITY), identity);
55              assert_eq!(identity, identity * identity);
56              assert_eq!(identity, $mat4::default());
57              assert_eq!(identity, $mat4::from_diagonal($vec4::ONE));
58          });
59  
60          glam_test!(test_mat4_zero, {
61              assert_eq!(
62                  $mat4::ZERO,
63                  $mat4::from_cols_array(&[
64                      0., 0., 0., 0., //
65                      0., 0., 0., 0., //
66                      0., 0., 0., 0., //
67                      0., 0., 0., 0., //
68                  ])
69              );
70          });
71  
72          glam_test!(test_mat4_nan, {
73              assert!($mat4::NAN.is_nan());
74              assert!(!$mat4::NAN.is_finite());
75          });
76  
77          glam_test!(test_mat4_accessors, {
78              let mut m = $mat4::ZERO;
79              m.x_axis = $vec4::new(1.0, 2.0, 3.0, 4.0);
80              m.y_axis = $vec4::new(5.0, 6.0, 7.0, 8.0);
81              m.z_axis = $vec4::new(9.0, 10.0, 11.0, 12.0);
82              m.w_axis = $vec4::new(13.0, 14.0, 15.0, 16.0);
83              assert_eq!($mat4::from_cols_array_2d(&MATRIX), m);
84              assert_eq!($vec4::new(1.0, 2.0, 3.0, 4.0), m.x_axis);
85              assert_eq!($vec4::new(5.0, 6.0, 7.0, 8.0), m.y_axis);
86              assert_eq!($vec4::new(9.0, 10.0, 11.0, 12.0), m.z_axis);
87              assert_eq!($vec4::new(13.0, 14.0, 15.0, 16.0), m.w_axis);
88  
89              assert_eq!($vec4::new(1.0, 2.0, 3.0, 4.0), m.col(0));
90              assert_eq!($vec4::new(5.0, 6.0, 7.0, 8.0), m.col(1));
91              assert_eq!($vec4::new(9.0, 10.0, 11.0, 12.0), m.col(2));
92              assert_eq!($vec4::new(13.0, 14.0, 15.0, 16.0), m.col(3));
93  
94              assert_eq!($newvec4(1.0, 5.0, 9.0, 13.0), m.row(0));
95              assert_eq!($newvec4(2.0, 6.0, 10.0, 14.0), m.row(1));
96              assert_eq!($newvec4(3.0, 7.0, 11.0, 15.0), m.row(2));
97              assert_eq!($newvec4(4.0, 8.0, 12.0, 16.0), m.row(3));
98  
99              *m.col_mut(0) = m.col(0).wzyx();
100              *m.col_mut(1) = m.col(1).wzyx();
101              *m.col_mut(2) = m.col(2).wzyx();
102              *m.col_mut(3) = m.col(3).wzyx();
103              assert_eq!($newvec4(4.0, 3.0, 2.0, 1.0), m.col(0));
104              assert_eq!($newvec4(8.0, 7.0, 6.0, 5.0), m.col(1));
105              assert_eq!($newvec4(12.0, 11.0, 10.0, 9.0), m.col(2));
106              assert_eq!($newvec4(16.0, 15.0, 14.0, 13.0), m.col(3));
107  
108              should_panic!({ $mat4::ZERO.col(4) });
109              should_panic!({
110                  let mut m = $mat4::ZERO;
111                  m.col_mut(4);
112              });
113              should_panic!({ $mat4::ZERO.row(4) });
114          });
115  
116          glam_test!(test_mat4_from_axes, {
117              let a = $mat4::from_cols_array_2d(&[
118                  [1.0, 2.0, 3.0, 4.0],
119                  [5.0, 6.0, 7.0, 8.0],
120                  [9.0, 10.0, 11.0, 12.0],
121                  [13.0, 14.0, 15.0, 16.0],
122              ]);
123              assert_eq!(MATRIX, a.to_cols_array_2d());
124              let b = $mat4::from_cols(
125                  $newvec4(1.0, 2.0, 3.0, 4.0),
126                  $newvec4(5.0, 6.0, 7.0, 8.0),
127                  $newvec4(9.0, 10.0, 11.0, 12.0),
128                  $newvec4(13.0, 14.0, 15.0, 16.0),
129              );
130              assert_eq!(a, b);
131              let c = $newmat4(
132                  $newvec4(1.0, 2.0, 3.0, 4.0),
133                  $newvec4(5.0, 6.0, 7.0, 8.0),
134                  $newvec4(9.0, 10.0, 11.0, 12.0),
135                  $newvec4(13.0, 14.0, 15.0, 16.0),
136              );
137              assert_eq!(a, c);
138              let d = b.to_cols_array();
139              let f = $mat4::from_cols_array(&d);
140              assert_eq!(b, f);
141          });
142  
143          glam_test!(test_mat4_translation, {
144              let translate = $mat4::from_translation($newvec3(1.0, 2.0, 3.0));
145              assert_eq!(
146                  $mat4::from_cols(
147                      $newvec4(1.0, 0.0, 0.0, 0.0),
148                      $newvec4(0.0, 1.0, 0.0, 0.0),
149                      $newvec4(0.0, 0.0, 1.0, 0.0),
150                      $newvec4(1.0, 2.0, 3.0, 1.0)
151                  ),
152                  translate
153              );
154          });
155  
156          glam_test!(test_from_rotation, {
157              let rot_x1 = $mat4::from_rotation_x(deg(180.0));
158              let rot_x2 = $mat4::from_axis_angle($vec3::X, deg(180.0));
159              assert_approx_eq!(rot_x1, rot_x2);
160              let rot_y1 = $mat4::from_rotation_y(deg(180.0));
161              let rot_y2 = $mat4::from_axis_angle($vec3::Y, deg(180.0));
162              assert_approx_eq!(rot_y1, rot_y2);
163              let rot_z1 = $mat4::from_rotation_z(deg(180.0));
164              let rot_z2 = $mat4::from_axis_angle($vec3::Z, deg(180.0));
165              assert_approx_eq!(rot_z1, rot_z2);
166  
167              assert_approx_eq!($mat4::IDENTITY, $mat4::from_quat($quat::IDENTITY));
168  
169              should_glam_assert!({ $mat4::from_axis_angle($vec3::ZERO, 0.0) });
170              should_glam_assert!({ $mat4::from_quat($quat::from_xyzw(0.0, 0.0, 0.0, 0.0)) });
171          });
172  
173          glam_test!(test_from_mat3, {
174              let m3 =
175                  $mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
176              let m4 = $mat4::from_mat3(m3);
177              assert_eq!(
178                  $mat4::from_cols_array_2d(&[
179                      [1.0, 2.0, 3.0, 0.0],
180                      [4.0, 5.0, 6.0, 0.0],
181                      [7.0, 8.0, 9.0, 0.0],
182                      [0.0, 0.0, 0.0, 1.0]
183                  ]),
184                  m4
185              );
186          });
187  
188          glam_test!(test_mat4_mul, {
189              let m = $mat4::from_axis_angle($vec3::Z, deg(90.0));
190              let result3 = m.transform_vector3($vec3::Y);
191              assert_approx_eq!($newvec3(-1.0, 0.0, 0.0), result3);
192              assert_approx_eq!(result3, (m * $vec3::Y.extend(0.0)).truncate().into());
193              let result4 = m * $vec4::Y;
194              assert_approx_eq!($newvec4(-1.0, 0.0, 0.0, 0.0), result4);
195              assert_approx_eq!(result4, m * $vec4::Y);
196  
197              let m = $mat4::from_scale_rotation_translation(
198                  $vec3::new(0.5, 1.5, 2.0),
199                  $quat::from_rotation_x(deg(90.0)),
200                  $vec3::new(1.0, 2.0, 3.0),
201              );
202              let result3 = m.transform_vector3($vec3::Y);
203              assert_approx_eq!($newvec3(0.0, 0.0, 1.5), result3, 1.0e-6);
204              assert_approx_eq!(result3, (m * $vec3::Y.extend(0.0)).truncate().into());
205  
206              let result3 = m.transform_point3($vec3::Y);
207              assert_approx_eq!($newvec3(1.0, 2.0, 4.5), result3, 1.0e-6);
208              assert_approx_eq!(result3, (m * $vec3::Y.extend(1.0)).truncate().into());
209  
210              let m = $mat4::from_cols(
211                  $newvec4(8.0, 0.0, 0.0, 0.0),
212                  $newvec4(0.0, 4.0, 0.0, 0.0),
213                  $newvec4(0.0, 0.0, 2.0, 2.0),
214                  $newvec4(0.0, 0.0, 0.0, 0.0),
215              );
216              assert_approx_eq!(
217                  $newvec3(4.0, 2.0, 1.0),
218                  m.project_point3($newvec3(2.0, 2.0, 2.0))
219              );
220  
221              should_glam_assert!({ $mat4::ZERO.transform_vector3($vec3::X) });
222              should_glam_assert!({ $mat4::ZERO.transform_point3($vec3::X) });
223          });
224  
225          glam_test!(test_from_ypr, {
226              use glam::EulerRot;
227              let zero = deg(0.0);
228              let yaw = deg(30.0);
229              let pitch = deg(60.0);
230              let roll = deg(90.0);
231              let y0 = $mat4::from_rotation_y(yaw);
232              let y1 = $mat4::from_euler(EulerRot::YXZ, yaw, zero, zero);
233              assert_approx_eq!(y0, y1);
234  
235              let x0 = $mat4::from_rotation_x(pitch);
236              let x1 = $mat4::from_euler(EulerRot::YXZ, zero, pitch, zero);
237              assert_approx_eq!(x0, x1);
238  
239              let z0 = $mat4::from_rotation_z(roll);
240              let z1 = $mat4::from_euler(EulerRot::YXZ, zero, zero, roll);
241              assert_approx_eq!(z0, z1);
242  
243              let yx0 = y0 * x0;
244              let yx1 = $mat4::from_euler(EulerRot::YXZ, yaw, pitch, zero);
245              assert_approx_eq!(yx0, yx1, 1e-6);
246  
247              let yxz0 = y0 * x0 * z0;
248              let yxz1 = $mat4::from_euler(EulerRot::YXZ, yaw, pitch, roll);
249              assert_approx_eq!(yxz0, yxz1, 1e-6);
250          });
251  
252          glam_test!(test_from_scale, {
253              let m = $mat4::from_scale($vec3::new(2.0, 4.0, 8.0));
254              assert_approx_eq!($vec4::X * 2.0, m.x_axis);
255              assert_approx_eq!($vec4::Y * 4.0, m.y_axis);
256              assert_approx_eq!($vec4::Z * 8.0, m.z_axis);
257              assert_approx_eq!($vec4::W, m.w_axis);
258              assert_approx_eq!(
259                  m.transform_point3($vec3::new(1.0, 1.0, 1.0)),
260                  $vec3::new(2.0, 4.0, 8.0)
261              );
262  
263              should_glam_assert!({ $mat4::from_scale($vec3::ZERO) });
264          });
265  
266          glam_test!(test_mat4_transpose, {
267              let m = $newmat4(
268                  $newvec4(1.0, 2.0, 3.0, 4.0),
269                  $newvec4(5.0, 6.0, 7.0, 8.0),
270                  $newvec4(9.0, 10.0, 11.0, 12.0),
271                  $newvec4(13.0, 14.0, 15.0, 16.0),
272              );
273              let mt = m.transpose();
274              assert_eq!($newvec4(1.0, 5.0, 9.0, 13.0), mt.x_axis);
275              assert_eq!($newvec4(2.0, 6.0, 10.0, 14.0), mt.y_axis);
276              assert_eq!($newvec4(3.0, 7.0, 11.0, 15.0), mt.z_axis);
277              assert_eq!($newvec4(4.0, 8.0, 12.0, 16.0), mt.w_axis);
278          });
279  
280          glam_test!(test_mat4_det, {
281              assert_eq!(0.0, $mat4::ZERO.determinant());
282              assert_eq!(1.0, $mat4::IDENTITY.determinant());
283              assert_eq!(1.0, $mat4::from_rotation_x(deg(90.0)).determinant());
284              assert_eq!(1.0, $mat4::from_rotation_y(deg(180.0)).determinant());
285              assert_eq!(1.0, $mat4::from_rotation_z(deg(270.0)).determinant());
286              assert_eq!(
287                  2.0 * 2.0 * 2.0,
288                  $mat4::from_scale($newvec3(2.0, 2.0, 2.0)).determinant()
289              );
290              assert_eq!(
291                  1.0,
292                  $newmat4(
293                      $newvec4(0.0, 0.0, 0.0, 1.0),
294                      $newvec4(1.0, 0.0, 0.0, 0.0),
295                      $newvec4(0.0, 0.0, 1.0, 0.0),
296                      $newvec4(0.0, 1.0, 0.0, 0.0),
297                  )
298                  .determinant()
299              );
300          });
301  
302          glam_test!(test_mat4_inverse, {
303              // assert_eq!(None, $mat4::ZERO.inverse());
304              let inv = $mat4::IDENTITY.inverse();
305              // assert_ne!(None, inv);
306              assert_approx_eq!($mat4::IDENTITY, inv);
307  
308              let rotz = $mat4::from_rotation_z(deg(90.0));
309              let rotz_inv = rotz.inverse();
310              // assert_ne!(None, rotz_inv);
311              // let rotz_inv = rotz_inv.unwrap();
312              assert_approx_eq!($mat4::IDENTITY, rotz * rotz_inv);
313              assert_approx_eq!($mat4::IDENTITY, rotz_inv * rotz);
314  
315              let trans = $mat4::from_translation($newvec3(1.0, 2.0, 3.0));
316              let trans_inv = trans.inverse();
317              // assert_ne!(None, trans_inv);
318              // let trans_inv = trans_inv.unwrap();
319              assert_approx_eq!($mat4::IDENTITY, trans * trans_inv);
320              assert_approx_eq!($mat4::IDENTITY, trans_inv * trans);
321  
322              let scale = $mat4::from_scale($newvec3(4.0, 5.0, 6.0));
323              let scale_inv = scale.inverse();
324              // assert_ne!(None, scale_inv);
325              // let scale_inv = scale_inv.unwrap();
326              assert_approx_eq!($mat4::IDENTITY, scale * scale_inv);
327              assert_approx_eq!($mat4::IDENTITY, scale_inv * scale);
328  
329              let m = scale * rotz * trans;
330              let m_inv = m.inverse();
331              // assert_ne!(None, m_inv);
332              // let m_inv = m_inv.unwrap();
333              assert_approx_eq!($mat4::IDENTITY, m * m_inv, 1.0e-5);
334              assert_approx_eq!($mat4::IDENTITY, m_inv * m, 1.0e-5);
335              assert_approx_eq!(m_inv, trans_inv * rotz_inv * scale_inv, 1.0e-6);
336  
337              // Make sure we can invert a "random" matrix:
338              let m = $mat4::from_cols(
339                  $newvec4(1.0, -0.3, 1.0, 1.0),
340                  $newvec4(0.5, 0.6, 0.7, 0.8),
341                  $newvec4(-0.9, -0.3, 0.0, 12.0),
342                  $newvec4(0.13, 0.14, 0.15, 0.16),
343              );
344              let m_inv = m.inverse();
345              assert_approx_eq!($mat4::IDENTITY, m * m_inv, 1.0e-5);
346              assert_approx_eq!($mat4::IDENTITY, m_inv * m, 1.0e-5);
347  
348              should_glam_assert!({ $mat4::ZERO.inverse() });
349          });
350  
351          glam_test!(test_mat4_decompose, {
352              // identity
353              let (out_scale, out_rotation, out_translation) =
354                  $mat4::IDENTITY.to_scale_rotation_translation();
355              assert_approx_eq!($vec3::ONE, out_scale);
356              assert!(out_rotation.is_near_identity());
357              assert_approx_eq!($vec3::ZERO, out_translation);
358  
359              // no scale
360              let in_scale = $vec3::ONE;
361              let in_translation = $vec3::new(-2.0, 4.0, -0.125);
362              let in_rotation = $quat::from_euler(
363                  glam::EulerRot::YXZ,
364                  $t::to_radians(-45.0),
365                  $t::to_radians(180.0),
366                  $t::to_radians(270.0),
367              );
368              let in_mat =
369                  $mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation);
370              let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation();
371              assert_approx_eq!(in_scale, out_scale, 1e-6);
372              // out_rotation is different but produces the same matrix
373              // assert_approx_eq!(in_rotation, out_rotation);
374              assert_approx_eq!(in_translation, out_translation);
375              assert_approx_eq!(
376                  in_mat,
377                  $mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation),
378                  1e-6
379              );
380  
381              // positive scale
382              let in_scale = $vec3::new(1.0, 2.0, 4.0);
383              let in_mat =
384                  $mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation);
385              let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation();
386              assert_approx_eq!(in_scale, out_scale, 1e-6);
387              // out_rotation is different but produces the same matrix
388              // assert_approx_eq!(in_rotation, out_rotation);
389              assert_approx_eq!(in_translation, out_translation);
390              assert_approx_eq!(
391                  in_mat,
392                  $mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation),
393                  1e-5
394              );
395  
396              // negative scale
397              let in_scale = $vec3::new(-4.0, 1.0, 2.0);
398              let in_mat =
399                  $mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation);
400              let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation();
401              assert_approx_eq!(in_scale, out_scale, 1e-6);
402              // out_rotation is different but produces the same matrix
403              // assert_approx_eq!(in_rotation, out_rotation);
404              assert_approx_eq!(in_translation, out_translation);
405              assert_approx_eq!(
406                  in_mat,
407                  $mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation),
408                  1e-5
409              );
410  
411              // negative scale
412              let in_scale = $vec3::new(4.0, -1.0, -2.0);
413              let in_mat =
414                  $mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation);
415              let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation();
416              // out_scale and out_rotation are different but they produce the same matrix
417              // assert_approx_eq!(in_scale, out_scale, 1e-6);
418              // assert_approx_eq!(in_rotation, out_rotation);
419              assert_approx_eq!(in_translation, out_translation);
420              assert_approx_eq!(
421                  in_mat,
422                  $mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation),
423                  1e-6
424              );
425  
426              should_glam_assert!({
427                  $mat4::from_scale_rotation_translation(
428                      $vec3::ONE,
429                      $quat::from_xyzw(0.0, 0.0, 0.0, 0.0),
430                      $vec3::ZERO,
431                  )
432              });
433              should_glam_assert!({
434                  $mat4::from_rotation_translation($quat::from_xyzw(0.0, 0.0, 0.0, 0.0), $vec3::ZERO)
435              });
436              // TODO: should check scale
437              // should_glam_assert!({ $mat4::from_scale_rotation_translation($vec3::ZERO, $quat::IDENTITY, $vec3::ZERO) });
438              should_glam_assert!({ $mat4::ZERO.to_scale_rotation_translation() });
439          });
440  
441          glam_test!(test_mat4_look_at, {
442              let eye = $vec3::new(0.0, 0.0, -5.0);
443              let center = $vec3::new(0.0, 0.0, 0.0);
444              let up = $vec3::new(1.0, 0.0, 0.0);
445  
446              let point = $vec3::new(1.0, 0.0, 0.0);
447  
448              let lh = $mat4::look_at_lh(eye, center, up);
449              let rh = $mat4::look_at_rh(eye, center, up);
450              assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0));
451              assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0));
452  
453              let dir = center - eye;
454              let lh = $mat4::look_to_lh(eye, dir, up);
455              let rh = $mat4::look_to_rh(eye, dir, up);
456              assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0));
457              assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0));
458  
459              should_glam_assert!({ $mat4::look_at_lh($vec3::ONE, $vec3::ZERO, $vec3::ZERO) });
460              should_glam_assert!({ $mat4::look_at_rh($vec3::ONE, $vec3::ZERO, $vec3::ZERO) });
461          });
462  
463          glam_test!(test_mat4_perspective_gl_rh, {
464              let projection = $mat4::perspective_rh_gl($t::to_radians(90.0), 2.0, 5.0, 15.0);
465  
466              let original = $vec3::new(5.0, 5.0, -15.0);
467              let projected = projection * original.extend(1.0);
468              assert_approx_eq!($vec4::new(2.5, 5.0, 15.0, 15.0), projected);
469  
470              let original = $vec3::new(5.0, 5.0, -5.0);
471              let projected = projection * original.extend(1.0);
472              assert_approx_eq!($vec4::new(2.5, 5.0, -5.0, 5.0), projected);
473          });
474  
475          glam_test!(test_mat4_perspective_lh, {
476              let projection = $mat4::perspective_lh($t::to_radians(90.0), 2.0, 5.0, 15.0);
477  
478              let original = $vec3::new(5.0, 5.0, 15.0);
479              let projected = projection * original.extend(1.0);
480              assert_approx_eq!($vec4::new(2.5, 5.0, 15.0, 15.0), projected, 1e-6);
481  
482              let original = $vec3::new(5.0, 5.0, 5.0);
483              let projected = projection * original.extend(1.0);
484              assert_approx_eq!($vec4::new(2.5, 5.0, 0.0, 5.0), projected, 1e-6);
485  
486              should_glam_assert!({ $mat4::perspective_lh(0.0, 1.0, 1.0, 0.0) });
487              should_glam_assert!({ $mat4::perspective_lh(0.0, 1.0, 0.0, 1.0) });
488          });
489  
490          glam_test!(test_mat4_perspective_infinite_lh, {
491              let projection = $mat4::perspective_infinite_lh($t::to_radians(90.0), 2.0, 5.0);
492  
493              let original = $vec3::new(5.0, 5.0, 15.0);
494              let projected = projection * original.extend(1.0);
495              assert_approx_eq!($vec4::new(2.5, 5.0, 10.0, 15.0), projected, 1e-6);
496  
497              let original = $vec3::new(5.0, 5.0, 5.0);
498              let projected = projection * original.extend(1.0);
499              assert_approx_eq!($vec4::new(2.5, 5.0, 0.0, 5.0), projected, 1e-6);
500  
501              should_glam_assert!({ $mat4::perspective_infinite_lh(0.0, 1.0, 0.0) });
502          });
503  
504          glam_test!(test_mat4_perspective_infinite_reverse_lh, {
505              let projection = $mat4::perspective_infinite_reverse_lh($t::to_radians(90.0), 2.0, 5.0);
506  
507              let original = $vec3::new(5.0, 5.0, 15.0);
508              let projected = projection * original.extend(1.0);
509              assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, 15.0), projected, 1e-6);
510  
511              let original = $vec3::new(5.0, 5.0, 5.0);
512              let projected = projection * original.extend(1.0);
513              assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, 5.0), projected, 1e-6);
514  
515              should_glam_assert!({ $mat4::perspective_infinite_reverse_lh(0.0, 1.0, 0.0) });
516          });
517  
518          glam_test!(test_mat4_perspective_rh, {
519              let projection = $mat4::perspective_rh($t::to_radians(90.0), 2.0, 5.0, 15.0);
520  
521              let original = $vec3::new(5.0, 5.0, 15.0);
522              let projected = projection * original.extend(1.0);
523              assert_approx_eq!($vec4::new(2.5, 5.0, -30.0, -15.0), projected, 1e-6);
524  
525              let original = $vec3::new(5.0, 5.0, 5.0);
526              let projected = projection * original.extend(1.0);
527              assert_approx_eq!($vec4::new(2.5, 5.0, -15.0, -5.0), projected, 1e-6);
528  
529              should_glam_assert!({ $mat4::perspective_rh(0.0, 1.0, 1.0, 0.0) });
530              should_glam_assert!({ $mat4::perspective_rh(0.0, 1.0, 0.0, 1.0) });
531          });
532  
533          glam_test!(test_mat4_perspective_infinite_rh, {
534              let projection = $mat4::perspective_infinite_rh($t::to_radians(90.0), 2.0, 5.0);
535  
536              let original = $vec3::new(5.0, 5.0, 15.0);
537              let projected = projection * original.extend(1.0);
538              assert_approx_eq!($vec4::new(2.5, 5.0, -20.0, -15.0), projected);
539  
540              let original = $vec3::new(5.0, 5.0, 5.0);
541              let projected = projection * original.extend(1.0);
542              assert_approx_eq!($vec4::new(2.5, 5.0, -10.0, -5.0), projected);
543  
544              should_glam_assert!({ $mat4::perspective_infinite_rh(0.0, 1.0, 0.0) });
545          });
546  
547          glam_test!(test_mat4_perspective_infinite_reverse_rh, {
548              let projection = $mat4::perspective_infinite_reverse_rh($t::to_radians(90.0), 2.0, 5.0);
549  
550              let original = $vec3::new(5.0, 5.0, 15.0);
551              let projected = projection * original.extend(1.0);
552              assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, -15.0), projected);
553  
554              let original = $vec3::new(5.0, 5.0, 5.0);
555              let projected = projection * original.extend(1.0);
556              assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, -5.0), projected);
557  
558              should_glam_assert!({ $mat4::perspective_infinite_reverse_rh(0.0, 1.0, 0.0) });
559          });
560  
561          glam_test!(test_mat4_orthographic_gl_rh, {
562              let projection = $mat4::orthographic_rh_gl(-10.0, 10.0, -5.0, 5.0, 0.0, -10.0);
563              let original = $vec4::new(5.0, 5.0, -5.0, 1.0);
564              let projected = projection.mul_vec4(original);
565              assert_approx_eq!(projected, $vec4::new(0.5, 1.0, -2.0, 1.0));
566          });
567  
568          glam_test!(test_mat4_orthographic_rh, {
569              let projection = $mat4::orthographic_rh(-10.0, 10.0, -5.0, 5.0, -10.0, 10.0);
570              let original = $vec4::new(5.0, 5.0, -5.0, 1.0);
571              let projected = projection.mul_vec4(original);
572              assert_approx_eq!(projected, $vec4::new(0.5, 1.0, 0.75, 1.0));
573  
574              let original = $vec4::new(5.0, 5.0, 5.0, 1.0);
575              let projected = projection.mul_vec4(original);
576              assert_approx_eq!(projected, $vec4::new(0.5, 1.0, 0.25, 1.0));
577          });
578  
579          glam_test!(test_mat4_orthographic_lh, {
580              let projection = $mat4::orthographic_lh(-10.0, 10.0, -5.0, 5.0, -10.0, 10.0);
581              let original = $vec4::new(5.0, 5.0, -5.0, 1.0);
582              let projected = projection.mul_vec4(original);
583              assert_approx_eq!(projected, $vec4::new(0.5, 1.0, 0.25, 1.0));
584  
585              let original = $vec4::new(5.0, 5.0, 5.0, 1.0);
586              let projected = projection.mul_vec4(original);
587              assert_approx_eq!(projected, $vec4::new(0.5, 1.0, 0.75, 1.0));
588          });
589  
590          glam_test!(test_mat4_ops, {
591              let m0 = $mat4::from_cols_array_2d(&MATRIX);
592              let m0x2 = $mat4::from_cols_array_2d(&[
593                  [2.0, 4.0, 6.0, 8.0],
594                  [10.0, 12.0, 14.0, 16.0],
595                  [18.0, 20.0, 22.0, 24.0],
596                  [26.0, 28.0, 30.0, 32.0],
597              ]);
598              let m0_neg = $mat4::from_cols_array_2d(&[
599                  [-1.0, -2.0, -3.0, -4.0],
600                  [-5.0, -6.0, -7.0, -8.0],
601                  [-9.0, -10.0, -11.0, -12.0],
602                  [-13.0, -14.0, -15.0, -16.0],
603              ]);
604              assert_eq!(m0x2, m0 * 2.0);
605              assert_eq!(m0x2, 2.0 * m0);
606              assert_eq!(m0x2, m0 + m0);
607              assert_eq!($mat4::ZERO, m0 - m0);
608              assert_eq!(m0_neg, -m0);
609              assert_approx_eq!(m0, m0 * $mat4::IDENTITY);
610              assert_approx_eq!(m0, $mat4::IDENTITY * m0);
611  
612              let mut m1 = m0;
613              m1 *= 2.0;
614              assert_eq!(m0x2, m1);
615  
616              let mut m1 = m0;
617              m1 += m0;
618              assert_eq!(m0x2, m1);
619  
620              let mut m1 = m0;
621              m1 -= m0;
622              assert_eq!($mat4::ZERO, m1);
623  
624              let mut m1 = $mat4::IDENTITY;
625              m1 *= m0;
626              assert_approx_eq!(m0, m1);
627          });
628  
629          glam_test!(test_mat4_fmt, {
630              let a = $mat4::from_cols_array_2d(&MATRIX);
631              assert_eq!(
632                  format!("{}", a),
633                  "[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]"
634              );
635          });
636  
637          glam_test!(test_mat4_to_from_slice, {
638              let m = $mat4::from_cols_slice(&MATRIX1D);
639              assert_eq!($mat4::from_cols_array(&MATRIX1D), m);
640              let mut out: [$t; 16] = Default::default();
641              m.write_cols_to_slice(&mut out);
642              assert_eq!(MATRIX1D, out);
643  
644              should_panic!({ $mat4::from_cols_slice(&[0.0; 15]) });
645              should_panic!({ $mat4::IDENTITY.write_cols_to_slice(&mut [0.0; 15]) });
646          });
647  
648          glam_test!(test_sum, {
649              let id = $mat4::IDENTITY;
650              assert_eq!([id, id].iter().sum::<$mat4>(), id + id);
651              assert_eq!([id, id].into_iter().sum::<$mat4>(), id + id);
652          });
653  
654          glam_test!(test_product, {
655              let two = $mat4::IDENTITY + $mat4::IDENTITY;
656              assert_eq!([two, two].iter().product::<$mat4>(), two * two);
657              assert_eq!([two, two].into_iter().product::<$mat4>(), two * two);
658          });
659  
660          glam_test!(test_mat4_is_finite, {
661              assert!($mat4::IDENTITY.is_finite());
662              assert!(!($mat4::IDENTITY * INFINITY).is_finite());
663              assert!(!($mat4::IDENTITY * NEG_INFINITY).is_finite());
664              assert!(!($mat4::IDENTITY * NAN).is_finite());
665          });
666      };
667  }
668  
669  macro_rules! impl_as_ref_tests {
670      ($mat:ident) => {
671          glam_test!(test_as_ref, {
672              let m = $mat::from_cols_array_2d(&MATRIX);
673              assert_eq!(MATRIX1D, *m.as_ref());
674          });
675          glam_test!(test_as_mut, {
676              let mut m = $mat::ZERO;
677              *m.as_mut() = MATRIX1D;
678              assert_eq!($mat::from_cols_array_2d(&MATRIX), m);
679          });
680      };
681  }
682  
683  mod mat4 {
684      use super::support::deg;
685      use glam::{mat4, swizzles::*, vec3, vec4, Mat3, Mat4, Quat, Vec3, Vec4};
686  
687      glam_test!(test_align, {
688          use std::mem;
689          assert_eq!(mem::align_of::<Vec4>(), mem::align_of::<Mat4>());
690          assert_eq!(64, mem::size_of::<Mat4>());
691      });
692  
693      glam_test!(test_from_mat3a, {
694          use glam::Mat3A;
695          let m3 = Mat3A::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
696          let m4 = Mat4::from_mat3a(m3);
697          assert_eq!(
698              Mat4::from_cols_array_2d(&[
699                  [1.0, 2.0, 3.0, 0.0],
700                  [4.0, 5.0, 6.0, 0.0],
701                  [7.0, 8.0, 9.0, 0.0],
702                  [0.0, 0.0, 0.0, 1.0]
703              ]),
704              m4
705          );
706      });
707  
708      glam_test!(test_as, {
709          use glam::DMat4;
710          assert_eq!(
711              DMat4::from_cols_array_2d(&[
712                  [1.0, 2.0, 3.0, 4.0],
713                  [5.0, 6.0, 7.0, 8.0],
714                  [9.0, 10.0, 11.0, 12.0],
715                  [13.0, 14.0, 15.0, 16.0]
716              ]),
717              Mat4::from_cols_array_2d(&[
718                  [1.0, 2.0, 3.0, 4.0],
719                  [5.0, 6.0, 7.0, 8.0],
720                  [9.0, 10.0, 11.0, 12.0],
721                  [13.0, 14.0, 15.0, 16.0]
722              ])
723              .as_dmat4()
724          );
725          assert_eq!(
726              Mat4::from_cols_array_2d(&[
727                  [1.0, 2.0, 3.0, 4.0],
728                  [5.0, 6.0, 7.0, 8.0],
729                  [9.0, 10.0, 11.0, 12.0],
730                  [13.0, 14.0, 15.0, 16.0]
731              ]),
732              DMat4::from_cols_array_2d(&[
733                  [1.0, 2.0, 3.0, 4.0],
734                  [5.0, 6.0, 7.0, 8.0],
735                  [9.0, 10.0, 11.0, 12.0],
736                  [13.0, 14.0, 15.0, 16.0]
737              ])
738              .as_mat4()
739          );
740      });
741  
742      impl_mat4_tests!(f32, mat4, vec4, vec3, Mat4, Mat3, Quat, Vec4, Vec3);
743      impl_as_ref_tests!(Mat4);
744  }
745  
746  mod dmat4 {
747      use super::support::deg;
748      use glam::{dmat4, dvec3, dvec4, swizzles::*, DMat3, DMat4, DQuat, DVec3, DVec4};
749  
750      glam_test!(test_align, {
751          use std::mem;
752          assert_eq!(mem::align_of::<DVec4>(), mem::align_of::<DMat4>());
753          assert_eq!(128, mem::size_of::<DMat4>());
754      });
755  
756      impl_mat4_tests!(f64, dmat4, dvec4, dvec3, DMat4, DMat3, DQuat, DVec4, DVec3);
757      impl_as_ref_tests!(DMat4);
758  }
759