1 // Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3 use crate::{
4 euler::{FromEuler, ToEuler},
5 f64::math,
6 swizzles::*,
7 DMat3, DQuat, DVec3, DVec4, EulerRot, Mat4,
8 };
9 use core::fmt;
10 use core::iter::{Product, Sum};
11 use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
12
13 /// Creates a 4x4 matrix from four column vectors.
14 #[inline(always)]
15 #[must_use]
dmat4(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> DMat416 pub const fn dmat4(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> DMat4 {
17 DMat4::from_cols(x_axis, y_axis, z_axis, w_axis)
18 }
19
20 /// A 4x4 column major matrix.
21 ///
22 /// This 4x4 matrix type features convenience methods for creating and using affine transforms and
23 /// perspective projections. If you are primarily dealing with 3D affine transformations
24 /// considering using [`DAffine3`](crate::DAffine3) which is faster than a 4x4 matrix
25 /// for some affine operations.
26 ///
27 /// Affine transformations including 3D translation, rotation and scale can be created
28 /// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
29 /// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
30 ///
31 /// Orthographic projections can be created using the methods [`Self::orthographic_lh()`] for
32 /// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed
33 /// systems. The resulting matrix is also an affine transformation.
34 ///
35 /// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
36 /// are provided for performing affine transformations on 3D vectors and points. These
37 /// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
38 /// for vectors respectively. These methods assume that `Self` contains a valid affine
39 /// transform.
40 ///
41 /// Perspective projections can be created using methods such as
42 /// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and
43 /// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and
44 /// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and
45 /// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems.
46 ///
47 /// The resulting perspective project can be use to transform 3D vectors as points with
48 /// perspective correction using the [`Self::project_point3()`] convenience method.
49 #[derive(Clone, Copy)]
50 #[cfg_attr(feature = "cuda", repr(align(16)))]
51 #[repr(C)]
52 pub struct DMat4 {
53 pub x_axis: DVec4,
54 pub y_axis: DVec4,
55 pub z_axis: DVec4,
56 pub w_axis: DVec4,
57 }
58
59 impl DMat4 {
60 /// A 4x4 matrix with all elements set to `0.0`.
61 pub const ZERO: Self = Self::from_cols(DVec4::ZERO, DVec4::ZERO, DVec4::ZERO, DVec4::ZERO);
62
63 /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
64 pub const IDENTITY: Self = Self::from_cols(DVec4::X, DVec4::Y, DVec4::Z, DVec4::W);
65
66 /// All NAN:s.
67 pub const NAN: Self = Self::from_cols(DVec4::NAN, DVec4::NAN, DVec4::NAN, DVec4::NAN);
68
69 #[allow(clippy::too_many_arguments)]
70 #[inline(always)]
71 #[must_use]
new( m00: f64, m01: f64, m02: f64, m03: f64, m10: f64, m11: f64, m12: f64, m13: f64, m20: f64, m21: f64, m22: f64, m23: f64, m30: f64, m31: f64, m32: f64, m33: f64, ) -> Self72 const fn new(
73 m00: f64,
74 m01: f64,
75 m02: f64,
76 m03: f64,
77 m10: f64,
78 m11: f64,
79 m12: f64,
80 m13: f64,
81 m20: f64,
82 m21: f64,
83 m22: f64,
84 m23: f64,
85 m30: f64,
86 m31: f64,
87 m32: f64,
88 m33: f64,
89 ) -> Self {
90 Self {
91 x_axis: DVec4::new(m00, m01, m02, m03),
92 y_axis: DVec4::new(m10, m11, m12, m13),
93 z_axis: DVec4::new(m20, m21, m22, m23),
94 w_axis: DVec4::new(m30, m31, m32, m33),
95 }
96 }
97
98 /// Creates a 4x4 matrix from four column vectors.
99 #[inline(always)]
100 #[must_use]
from_cols(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> Self101 pub const fn from_cols(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> Self {
102 Self {
103 x_axis,
104 y_axis,
105 z_axis,
106 w_axis,
107 }
108 }
109
110 /// Creates a 4x4 matrix from a `[f64; 16]` array stored in column major order.
111 /// If your data is stored in row major you will need to `transpose` the returned
112 /// matrix.
113 #[inline]
114 #[must_use]
from_cols_array(m: &[f64; 16]) -> Self115 pub const fn from_cols_array(m: &[f64; 16]) -> Self {
116 Self::new(
117 m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13],
118 m[14], m[15],
119 )
120 }
121
122 /// Creates a `[f64; 16]` array storing data in column major order.
123 /// If you require data in row major order `transpose` the matrix first.
124 #[inline]
125 #[must_use]
to_cols_array(&self) -> [f64; 16]126 pub const fn to_cols_array(&self) -> [f64; 16] {
127 [
128 self.x_axis.x,
129 self.x_axis.y,
130 self.x_axis.z,
131 self.x_axis.w,
132 self.y_axis.x,
133 self.y_axis.y,
134 self.y_axis.z,
135 self.y_axis.w,
136 self.z_axis.x,
137 self.z_axis.y,
138 self.z_axis.z,
139 self.z_axis.w,
140 self.w_axis.x,
141 self.w_axis.y,
142 self.w_axis.z,
143 self.w_axis.w,
144 ]
145 }
146
147 /// Creates a 4x4 matrix from a `[[f64; 4]; 4]` 4D array stored in column major order.
148 /// If your data is in row major order you will need to `transpose` the returned
149 /// matrix.
150 #[inline]
151 #[must_use]
from_cols_array_2d(m: &[[f64; 4]; 4]) -> Self152 pub const fn from_cols_array_2d(m: &[[f64; 4]; 4]) -> Self {
153 Self::from_cols(
154 DVec4::from_array(m[0]),
155 DVec4::from_array(m[1]),
156 DVec4::from_array(m[2]),
157 DVec4::from_array(m[3]),
158 )
159 }
160
161 /// Creates a `[[f64; 4]; 4]` 4D array storing data in column major order.
162 /// If you require data in row major order `transpose` the matrix first.
163 #[inline]
164 #[must_use]
to_cols_array_2d(&self) -> [[f64; 4]; 4]165 pub const fn to_cols_array_2d(&self) -> [[f64; 4]; 4] {
166 [
167 self.x_axis.to_array(),
168 self.y_axis.to_array(),
169 self.z_axis.to_array(),
170 self.w_axis.to_array(),
171 ]
172 }
173
174 /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0.
175 #[doc(alias = "scale")]
176 #[inline]
177 #[must_use]
from_diagonal(diagonal: DVec4) -> Self178 pub const fn from_diagonal(diagonal: DVec4) -> Self {
179 Self::new(
180 diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0,
181 0.0, 0.0, diagonal.w,
182 )
183 }
184
185 #[inline]
186 #[must_use]
quat_to_axes(rotation: DQuat) -> (DVec4, DVec4, DVec4)187 fn quat_to_axes(rotation: DQuat) -> (DVec4, DVec4, DVec4) {
188 glam_assert!(rotation.is_normalized());
189
190 let (x, y, z, w) = rotation.into();
191 let x2 = x + x;
192 let y2 = y + y;
193 let z2 = z + z;
194 let xx = x * x2;
195 let xy = x * y2;
196 let xz = x * z2;
197 let yy = y * y2;
198 let yz = y * z2;
199 let zz = z * z2;
200 let wx = w * x2;
201 let wy = w * y2;
202 let wz = w * z2;
203
204 let x_axis = DVec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
205 let y_axis = DVec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
206 let z_axis = DVec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
207 (x_axis, y_axis, z_axis)
208 }
209
210 /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and
211 /// `translation`.
212 ///
213 /// The resulting matrix can be used to transform 3D points and vectors. See
214 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
215 ///
216 /// # Panics
217 ///
218 /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
219 #[inline]
220 #[must_use]
from_scale_rotation_translation( scale: DVec3, rotation: DQuat, translation: DVec3, ) -> Self221 pub fn from_scale_rotation_translation(
222 scale: DVec3,
223 rotation: DQuat,
224 translation: DVec3,
225 ) -> Self {
226 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
227 Self::from_cols(
228 x_axis.mul(scale.x),
229 y_axis.mul(scale.y),
230 z_axis.mul(scale.z),
231 DVec4::from((translation, 1.0)),
232 )
233 }
234
235 /// Creates an affine transformation matrix from the given 3D `translation`.
236 ///
237 /// The resulting matrix can be used to transform 3D points and vectors. See
238 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
239 ///
240 /// # Panics
241 ///
242 /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
243 #[inline]
244 #[must_use]
from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self245 pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
246 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
247 Self::from_cols(x_axis, y_axis, z_axis, DVec4::from((translation, 1.0)))
248 }
249
250 /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is
251 /// expected to be a 3D affine transformation matrix otherwise the output will be invalid.
252 ///
253 /// # Panics
254 ///
255 /// Will panic if the determinant of `self` is zero or if the resulting scale vector
256 /// contains any zero elements when `glam_assert` is enabled.
257 #[inline]
258 #[must_use]
to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3)259 pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
260 let det = self.determinant();
261 glam_assert!(det != 0.0);
262
263 let scale = DVec3::new(
264 self.x_axis.length() * math::signum(det),
265 self.y_axis.length(),
266 self.z_axis.length(),
267 );
268
269 glam_assert!(scale.cmpne(DVec3::ZERO).all());
270
271 let inv_scale = scale.recip();
272
273 let rotation = DQuat::from_rotation_axes(
274 self.x_axis.mul(inv_scale.x).xyz(),
275 self.y_axis.mul(inv_scale.y).xyz(),
276 self.z_axis.mul(inv_scale.z).xyz(),
277 );
278
279 let translation = self.w_axis.xyz();
280
281 (scale, rotation, translation)
282 }
283
284 /// Creates an affine transformation matrix from the given `rotation` quaternion.
285 ///
286 /// The resulting matrix can be used to transform 3D points and vectors. See
287 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
288 ///
289 /// # Panics
290 ///
291 /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
292 #[inline]
293 #[must_use]
from_quat(rotation: DQuat) -> Self294 pub fn from_quat(rotation: DQuat) -> Self {
295 let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
296 Self::from_cols(x_axis, y_axis, z_axis, DVec4::W)
297 }
298
299 /// Creates an affine transformation matrix from the given 3x3 linear transformation
300 /// matrix.
301 ///
302 /// The resulting matrix can be used to transform 3D points and vectors. See
303 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
304 #[inline]
305 #[must_use]
from_mat3(m: DMat3) -> Self306 pub fn from_mat3(m: DMat3) -> Self {
307 Self::from_cols(
308 DVec4::from((m.x_axis, 0.0)),
309 DVec4::from((m.y_axis, 0.0)),
310 DVec4::from((m.z_axis, 0.0)),
311 DVec4::W,
312 )
313 }
314
315 /// Creates an affine transformation matrics from a 3x3 matrix (expressing scale, shear and
316 /// rotation) and a translation vector.
317 ///
318 /// Equivalent to `DMat4::from_translation(translation) * DMat4::from_mat3(mat3)`
319 #[inline]
320 #[must_use]
from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self321 pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
322 Self::from_cols(
323 DVec4::from((mat3.x_axis, 0.0)),
324 DVec4::from((mat3.y_axis, 0.0)),
325 DVec4::from((mat3.z_axis, 0.0)),
326 DVec4::from((translation, 1.0)),
327 )
328 }
329
330 /// Creates an affine transformation matrix from the given 3D `translation`.
331 ///
332 /// The resulting matrix can be used to transform 3D points and vectors. See
333 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
334 #[inline]
335 #[must_use]
from_translation(translation: DVec3) -> Self336 pub fn from_translation(translation: DVec3) -> Self {
337 Self::from_cols(
338 DVec4::X,
339 DVec4::Y,
340 DVec4::Z,
341 DVec4::new(translation.x, translation.y, translation.z, 1.0),
342 )
343 }
344
345 /// Creates an affine transformation matrix containing a 3D rotation around a normalized
346 /// rotation `axis` of `angle` (in radians).
347 ///
348 /// The resulting matrix can be used to transform 3D points and vectors. See
349 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
350 ///
351 /// # Panics
352 ///
353 /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
354 #[inline]
355 #[must_use]
from_axis_angle(axis: DVec3, angle: f64) -> Self356 pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
357 glam_assert!(axis.is_normalized());
358
359 let (sin, cos) = math::sin_cos(angle);
360 let axis_sin = axis.mul(sin);
361 let axis_sq = axis.mul(axis);
362 let omc = 1.0 - cos;
363 let xyomc = axis.x * axis.y * omc;
364 let xzomc = axis.x * axis.z * omc;
365 let yzomc = axis.y * axis.z * omc;
366 Self::from_cols(
367 DVec4::new(
368 axis_sq.x * omc + cos,
369 xyomc + axis_sin.z,
370 xzomc - axis_sin.y,
371 0.0,
372 ),
373 DVec4::new(
374 xyomc - axis_sin.z,
375 axis_sq.y * omc + cos,
376 yzomc + axis_sin.x,
377 0.0,
378 ),
379 DVec4::new(
380 xzomc + axis_sin.y,
381 yzomc - axis_sin.x,
382 axis_sq.z * omc + cos,
383 0.0,
384 ),
385 DVec4::W,
386 )
387 }
388
389 /// Creates a affine transformation matrix containing a rotation from the given euler
390 /// rotation sequence and angles (in radians).
391 ///
392 /// The resulting matrix can be used to transform 3D points and vectors. See
393 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
394 #[inline]
395 #[must_use]
from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self396 pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self {
397 Self::from_euler_angles(order, a, b, c)
398 }
399
400 /// Extract Euler angles with the given Euler rotation order.
401 ///
402 /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
403 /// then the resulting Euler angles will be ill-defined.
404 ///
405 /// # Panics
406 ///
407 /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
408 /// `glam_assert` is enabled.
409 #[inline]
410 #[must_use]
to_euler(&self, order: EulerRot) -> (f64, f64, f64)411 pub fn to_euler(&self, order: EulerRot) -> (f64, f64, f64) {
412 glam_assert!(
413 self.x_axis.xyz().is_normalized()
414 && self.y_axis.xyz().is_normalized()
415 && self.z_axis.xyz().is_normalized()
416 );
417 self.to_euler_angles(order)
418 }
419
420 /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
421 /// `angle` (in radians).
422 ///
423 /// The resulting matrix can be used to transform 3D points and vectors. See
424 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
425 #[inline]
426 #[must_use]
from_rotation_x(angle: f64) -> Self427 pub fn from_rotation_x(angle: f64) -> Self {
428 let (sina, cosa) = math::sin_cos(angle);
429 Self::from_cols(
430 DVec4::X,
431 DVec4::new(0.0, cosa, sina, 0.0),
432 DVec4::new(0.0, -sina, cosa, 0.0),
433 DVec4::W,
434 )
435 }
436
437 /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
438 /// `angle` (in radians).
439 ///
440 /// The resulting matrix can be used to transform 3D points and vectors. See
441 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
442 #[inline]
443 #[must_use]
from_rotation_y(angle: f64) -> Self444 pub fn from_rotation_y(angle: f64) -> Self {
445 let (sina, cosa) = math::sin_cos(angle);
446 Self::from_cols(
447 DVec4::new(cosa, 0.0, -sina, 0.0),
448 DVec4::Y,
449 DVec4::new(sina, 0.0, cosa, 0.0),
450 DVec4::W,
451 )
452 }
453
454 /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
455 /// `angle` (in radians).
456 ///
457 /// The resulting matrix can be used to transform 3D points and vectors. See
458 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
459 #[inline]
460 #[must_use]
from_rotation_z(angle: f64) -> Self461 pub fn from_rotation_z(angle: f64) -> Self {
462 let (sina, cosa) = math::sin_cos(angle);
463 Self::from_cols(
464 DVec4::new(cosa, sina, 0.0, 0.0),
465 DVec4::new(-sina, cosa, 0.0, 0.0),
466 DVec4::Z,
467 DVec4::W,
468 )
469 }
470
471 /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
472 ///
473 /// The resulting matrix can be used to transform 3D points and vectors. See
474 /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
475 ///
476 /// # Panics
477 ///
478 /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
479 #[inline]
480 #[must_use]
from_scale(scale: DVec3) -> Self481 pub fn from_scale(scale: DVec3) -> Self {
482 // Do not panic as long as any component is non-zero
483 glam_assert!(scale.cmpne(DVec3::ZERO).any());
484
485 Self::from_cols(
486 DVec4::new(scale.x, 0.0, 0.0, 0.0),
487 DVec4::new(0.0, scale.y, 0.0, 0.0),
488 DVec4::new(0.0, 0.0, scale.z, 0.0),
489 DVec4::W,
490 )
491 }
492
493 /// Creates a 4x4 matrix from the first 16 values in `slice`.
494 ///
495 /// # Panics
496 ///
497 /// Panics if `slice` is less than 16 elements long.
498 #[inline]
499 #[must_use]
from_cols_slice(slice: &[f64]) -> Self500 pub const fn from_cols_slice(slice: &[f64]) -> Self {
501 Self::new(
502 slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
503 slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
504 )
505 }
506
507 /// Writes the columns of `self` to the first 16 elements in `slice`.
508 ///
509 /// # Panics
510 ///
511 /// Panics if `slice` is less than 16 elements long.
512 #[inline]
write_cols_to_slice(self, slice: &mut [f64])513 pub fn write_cols_to_slice(self, slice: &mut [f64]) {
514 slice[0] = self.x_axis.x;
515 slice[1] = self.x_axis.y;
516 slice[2] = self.x_axis.z;
517 slice[3] = self.x_axis.w;
518 slice[4] = self.y_axis.x;
519 slice[5] = self.y_axis.y;
520 slice[6] = self.y_axis.z;
521 slice[7] = self.y_axis.w;
522 slice[8] = self.z_axis.x;
523 slice[9] = self.z_axis.y;
524 slice[10] = self.z_axis.z;
525 slice[11] = self.z_axis.w;
526 slice[12] = self.w_axis.x;
527 slice[13] = self.w_axis.y;
528 slice[14] = self.w_axis.z;
529 slice[15] = self.w_axis.w;
530 }
531
532 /// Returns the matrix column for the given `index`.
533 ///
534 /// # Panics
535 ///
536 /// Panics if `index` is greater than 3.
537 #[inline]
538 #[must_use]
col(&self, index: usize) -> DVec4539 pub fn col(&self, index: usize) -> DVec4 {
540 match index {
541 0 => self.x_axis,
542 1 => self.y_axis,
543 2 => self.z_axis,
544 3 => self.w_axis,
545 _ => panic!("index out of bounds"),
546 }
547 }
548
549 /// Returns a mutable reference to the matrix column for the given `index`.
550 ///
551 /// # Panics
552 ///
553 /// Panics if `index` is greater than 3.
554 #[inline]
col_mut(&mut self, index: usize) -> &mut DVec4555 pub fn col_mut(&mut self, index: usize) -> &mut DVec4 {
556 match index {
557 0 => &mut self.x_axis,
558 1 => &mut self.y_axis,
559 2 => &mut self.z_axis,
560 3 => &mut self.w_axis,
561 _ => panic!("index out of bounds"),
562 }
563 }
564
565 /// Returns the matrix row for the given `index`.
566 ///
567 /// # Panics
568 ///
569 /// Panics if `index` is greater than 3.
570 #[inline]
571 #[must_use]
row(&self, index: usize) -> DVec4572 pub fn row(&self, index: usize) -> DVec4 {
573 match index {
574 0 => DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
575 1 => DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
576 2 => DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
577 3 => DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
578 _ => panic!("index out of bounds"),
579 }
580 }
581
582 /// Returns `true` if, and only if, all elements are finite.
583 /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
584 #[inline]
585 #[must_use]
is_finite(&self) -> bool586 pub fn is_finite(&self) -> bool {
587 self.x_axis.is_finite()
588 && self.y_axis.is_finite()
589 && self.z_axis.is_finite()
590 && self.w_axis.is_finite()
591 }
592
593 /// Returns `true` if any elements are `NaN`.
594 #[inline]
595 #[must_use]
is_nan(&self) -> bool596 pub fn is_nan(&self) -> bool {
597 self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
598 }
599
600 /// Returns the transpose of `self`.
601 #[inline]
602 #[must_use]
transpose(&self) -> Self603 pub fn transpose(&self) -> Self {
604 Self {
605 x_axis: DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
606 y_axis: DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
607 z_axis: DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
608 w_axis: DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
609 }
610 }
611
612 /// Returns the determinant of `self`.
613 #[must_use]
determinant(&self) -> f64614 pub fn determinant(&self) -> f64 {
615 let (m00, m01, m02, m03) = self.x_axis.into();
616 let (m10, m11, m12, m13) = self.y_axis.into();
617 let (m20, m21, m22, m23) = self.z_axis.into();
618 let (m30, m31, m32, m33) = self.w_axis.into();
619
620 let a2323 = m22 * m33 - m23 * m32;
621 let a1323 = m21 * m33 - m23 * m31;
622 let a1223 = m21 * m32 - m22 * m31;
623 let a0323 = m20 * m33 - m23 * m30;
624 let a0223 = m20 * m32 - m22 * m30;
625 let a0123 = m20 * m31 - m21 * m30;
626
627 m00 * (m11 * a2323 - m12 * a1323 + m13 * a1223)
628 - m01 * (m10 * a2323 - m12 * a0323 + m13 * a0223)
629 + m02 * (m10 * a1323 - m11 * a0323 + m13 * a0123)
630 - m03 * (m10 * a1223 - m11 * a0223 + m12 * a0123)
631 }
632
633 /// Returns the inverse of `self`.
634 ///
635 /// If the matrix is not invertible the returned matrix will be invalid.
636 ///
637 /// # Panics
638 ///
639 /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
640 #[must_use]
inverse(&self) -> Self641 pub fn inverse(&self) -> Self {
642 let (m00, m01, m02, m03) = self.x_axis.into();
643 let (m10, m11, m12, m13) = self.y_axis.into();
644 let (m20, m21, m22, m23) = self.z_axis.into();
645 let (m30, m31, m32, m33) = self.w_axis.into();
646
647 let coef00 = m22 * m33 - m32 * m23;
648 let coef02 = m12 * m33 - m32 * m13;
649 let coef03 = m12 * m23 - m22 * m13;
650
651 let coef04 = m21 * m33 - m31 * m23;
652 let coef06 = m11 * m33 - m31 * m13;
653 let coef07 = m11 * m23 - m21 * m13;
654
655 let coef08 = m21 * m32 - m31 * m22;
656 let coef10 = m11 * m32 - m31 * m12;
657 let coef11 = m11 * m22 - m21 * m12;
658
659 let coef12 = m20 * m33 - m30 * m23;
660 let coef14 = m10 * m33 - m30 * m13;
661 let coef15 = m10 * m23 - m20 * m13;
662
663 let coef16 = m20 * m32 - m30 * m22;
664 let coef18 = m10 * m32 - m30 * m12;
665 let coef19 = m10 * m22 - m20 * m12;
666
667 let coef20 = m20 * m31 - m30 * m21;
668 let coef22 = m10 * m31 - m30 * m11;
669 let coef23 = m10 * m21 - m20 * m11;
670
671 let fac0 = DVec4::new(coef00, coef00, coef02, coef03);
672 let fac1 = DVec4::new(coef04, coef04, coef06, coef07);
673 let fac2 = DVec4::new(coef08, coef08, coef10, coef11);
674 let fac3 = DVec4::new(coef12, coef12, coef14, coef15);
675 let fac4 = DVec4::new(coef16, coef16, coef18, coef19);
676 let fac5 = DVec4::new(coef20, coef20, coef22, coef23);
677
678 let vec0 = DVec4::new(m10, m00, m00, m00);
679 let vec1 = DVec4::new(m11, m01, m01, m01);
680 let vec2 = DVec4::new(m12, m02, m02, m02);
681 let vec3 = DVec4::new(m13, m03, m03, m03);
682
683 let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2));
684 let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4));
685 let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5));
686 let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5));
687
688 let sign_a = DVec4::new(1.0, -1.0, 1.0, -1.0);
689 let sign_b = DVec4::new(-1.0, 1.0, -1.0, 1.0);
690
691 let inverse = Self::from_cols(
692 inv0.mul(sign_a),
693 inv1.mul(sign_b),
694 inv2.mul(sign_a),
695 inv3.mul(sign_b),
696 );
697
698 let col0 = DVec4::new(
699 inverse.x_axis.x,
700 inverse.y_axis.x,
701 inverse.z_axis.x,
702 inverse.w_axis.x,
703 );
704
705 let dot0 = self.x_axis.mul(col0);
706 let dot1 = dot0.x + dot0.y + dot0.z + dot0.w;
707
708 glam_assert!(dot1 != 0.0);
709
710 let rcp_det = dot1.recip();
711 inverse.mul(rcp_det)
712 }
713
714 /// Creates a left-handed view matrix using a camera position, a facing direction and an up
715 /// direction
716 ///
717 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
718 ///
719 /// # Panics
720 ///
721 /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
722 #[inline]
723 #[must_use]
look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self724 pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
725 Self::look_to_rh(eye, -dir, up)
726 }
727
728 /// Creates a right-handed view matrix using a camera position, a facing direction, and an up
729 /// direction.
730 ///
731 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
732 ///
733 /// # Panics
734 ///
735 /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
736 #[inline]
737 #[must_use]
look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self738 pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
739 glam_assert!(dir.is_normalized());
740 glam_assert!(up.is_normalized());
741 let f = dir;
742 let s = f.cross(up).normalize();
743 let u = s.cross(f);
744
745 Self::from_cols(
746 DVec4::new(s.x, u.x, -f.x, 0.0),
747 DVec4::new(s.y, u.y, -f.y, 0.0),
748 DVec4::new(s.z, u.z, -f.z, 0.0),
749 DVec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
750 )
751 }
752
753 /// Creates a left-handed view matrix using a camera position, a focal points and an up
754 /// direction.
755 ///
756 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
757 ///
758 /// # Panics
759 ///
760 /// Will panic if `up` is not normalized when `glam_assert` is enabled.
761 #[inline]
762 #[must_use]
look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self763 pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
764 Self::look_to_lh(eye, center.sub(eye).normalize(), up)
765 }
766
767 /// Creates a right-handed view matrix using a camera position, a focal point, and an up
768 /// direction.
769 ///
770 /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
771 ///
772 /// # Panics
773 ///
774 /// Will panic if `up` is not normalized when `glam_assert` is enabled.
775 #[inline]
look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self776 pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
777 Self::look_to_rh(eye, center.sub(eye).normalize(), up)
778 }
779
780 /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
781 ///
782 /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
783 ///
784 /// This is the same as the OpenGL `gluPerspective` function.
785 /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
786 #[inline]
787 #[must_use]
perspective_rh_gl( fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64, ) -> Self788 pub fn perspective_rh_gl(
789 fov_y_radians: f64,
790 aspect_ratio: f64,
791 z_near: f64,
792 z_far: f64,
793 ) -> Self {
794 let inv_length = 1.0 / (z_near - z_far);
795 let f = 1.0 / math::tan(0.5 * fov_y_radians);
796 let a = f / aspect_ratio;
797 let b = (z_near + z_far) * inv_length;
798 let c = (2.0 * z_near * z_far) * inv_length;
799 Self::from_cols(
800 DVec4::new(a, 0.0, 0.0, 0.0),
801 DVec4::new(0.0, f, 0.0, 0.0),
802 DVec4::new(0.0, 0.0, b, -1.0),
803 DVec4::new(0.0, 0.0, c, 0.0),
804 )
805 }
806
807 /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
808 ///
809 /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
810 ///
811 /// # Panics
812 ///
813 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
814 /// enabled.
815 #[inline]
816 #[must_use]
perspective_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self817 pub fn perspective_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self {
818 glam_assert!(z_near > 0.0 && z_far > 0.0);
819 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
820 let h = cos_fov / sin_fov;
821 let w = h / aspect_ratio;
822 let r = z_far / (z_far - z_near);
823 Self::from_cols(
824 DVec4::new(w, 0.0, 0.0, 0.0),
825 DVec4::new(0.0, h, 0.0, 0.0),
826 DVec4::new(0.0, 0.0, r, 1.0),
827 DVec4::new(0.0, 0.0, -r * z_near, 0.0),
828 )
829 }
830
831 /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
832 ///
833 /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
834 ///
835 /// # Panics
836 ///
837 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
838 /// enabled.
839 #[inline]
840 #[must_use]
perspective_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self841 pub fn perspective_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self {
842 glam_assert!(z_near > 0.0 && z_far > 0.0);
843 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
844 let h = cos_fov / sin_fov;
845 let w = h / aspect_ratio;
846 let r = z_far / (z_near - z_far);
847 Self::from_cols(
848 DVec4::new(w, 0.0, 0.0, 0.0),
849 DVec4::new(0.0, h, 0.0, 0.0),
850 DVec4::new(0.0, 0.0, r, -1.0),
851 DVec4::new(0.0, 0.0, r * z_near, 0.0),
852 )
853 }
854
855 /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
856 ///
857 /// Like `perspective_lh`, but with an infinite value for `z_far`.
858 /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
859 ///
860 /// # Panics
861 ///
862 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
863 /// enabled.
864 #[inline]
865 #[must_use]
perspective_infinite_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self866 pub fn perspective_infinite_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
867 glam_assert!(z_near > 0.0);
868 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
869 let h = cos_fov / sin_fov;
870 let w = h / aspect_ratio;
871 Self::from_cols(
872 DVec4::new(w, 0.0, 0.0, 0.0),
873 DVec4::new(0.0, h, 0.0, 0.0),
874 DVec4::new(0.0, 0.0, 1.0, 1.0),
875 DVec4::new(0.0, 0.0, -z_near, 0.0),
876 )
877 }
878
879 /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
880 ///
881 /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
882 ///
883 /// # Panics
884 ///
885 /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
886 #[inline]
887 #[must_use]
perspective_infinite_reverse_lh( fov_y_radians: f64, aspect_ratio: f64, z_near: f64, ) -> Self888 pub fn perspective_infinite_reverse_lh(
889 fov_y_radians: f64,
890 aspect_ratio: f64,
891 z_near: f64,
892 ) -> Self {
893 glam_assert!(z_near > 0.0);
894 let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
895 let h = cos_fov / sin_fov;
896 let w = h / aspect_ratio;
897 Self::from_cols(
898 DVec4::new(w, 0.0, 0.0, 0.0),
899 DVec4::new(0.0, h, 0.0, 0.0),
900 DVec4::new(0.0, 0.0, 0.0, 1.0),
901 DVec4::new(0.0, 0.0, z_near, 0.0),
902 )
903 }
904
905 /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
906 ///
907 /// Like `perspective_rh`, but with an infinite value for `z_far`.
908 /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
909 ///
910 /// # Panics
911 ///
912 /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
913 /// enabled.
914 #[inline]
915 #[must_use]
perspective_infinite_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self916 pub fn perspective_infinite_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
917 glam_assert!(z_near > 0.0);
918 let f = 1.0 / math::tan(0.5 * fov_y_radians);
919 Self::from_cols(
920 DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
921 DVec4::new(0.0, f, 0.0, 0.0),
922 DVec4::new(0.0, 0.0, -1.0, -1.0),
923 DVec4::new(0.0, 0.0, -z_near, 0.0),
924 )
925 }
926
927 /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
928 ///
929 /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
930 ///
931 /// # Panics
932 ///
933 /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
934 #[inline]
935 #[must_use]
perspective_infinite_reverse_rh( fov_y_radians: f64, aspect_ratio: f64, z_near: f64, ) -> Self936 pub fn perspective_infinite_reverse_rh(
937 fov_y_radians: f64,
938 aspect_ratio: f64,
939 z_near: f64,
940 ) -> Self {
941 glam_assert!(z_near > 0.0);
942 let f = 1.0 / math::tan(0.5 * fov_y_radians);
943 Self::from_cols(
944 DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
945 DVec4::new(0.0, f, 0.0, 0.0),
946 DVec4::new(0.0, 0.0, 0.0, -1.0),
947 DVec4::new(0.0, 0.0, z_near, 0.0),
948 )
949 }
950
951 /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
952 /// range. This is the same as the OpenGL `glOrtho` function in OpenGL.
953 /// See
954 /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
955 ///
956 /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
957 #[inline]
958 #[must_use]
orthographic_rh_gl( left: f64, right: f64, bottom: f64, top: f64, near: f64, far: f64, ) -> Self959 pub fn orthographic_rh_gl(
960 left: f64,
961 right: f64,
962 bottom: f64,
963 top: f64,
964 near: f64,
965 far: f64,
966 ) -> Self {
967 let a = 2.0 / (right - left);
968 let b = 2.0 / (top - bottom);
969 let c = -2.0 / (far - near);
970 let tx = -(right + left) / (right - left);
971 let ty = -(top + bottom) / (top - bottom);
972 let tz = -(far + near) / (far - near);
973
974 Self::from_cols(
975 DVec4::new(a, 0.0, 0.0, 0.0),
976 DVec4::new(0.0, b, 0.0, 0.0),
977 DVec4::new(0.0, 0.0, c, 0.0),
978 DVec4::new(tx, ty, tz, 1.0),
979 )
980 }
981
982 /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
983 ///
984 /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
985 #[inline]
986 #[must_use]
orthographic_lh( left: f64, right: f64, bottom: f64, top: f64, near: f64, far: f64, ) -> Self987 pub fn orthographic_lh(
988 left: f64,
989 right: f64,
990 bottom: f64,
991 top: f64,
992 near: f64,
993 far: f64,
994 ) -> Self {
995 let rcp_width = 1.0 / (right - left);
996 let rcp_height = 1.0 / (top - bottom);
997 let r = 1.0 / (far - near);
998 Self::from_cols(
999 DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1000 DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1001 DVec4::new(0.0, 0.0, r, 0.0),
1002 DVec4::new(
1003 -(left + right) * rcp_width,
1004 -(top + bottom) * rcp_height,
1005 -r * near,
1006 1.0,
1007 ),
1008 )
1009 }
1010
1011 /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
1012 ///
1013 /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1014 #[inline]
1015 #[must_use]
orthographic_rh( left: f64, right: f64, bottom: f64, top: f64, near: f64, far: f64, ) -> Self1016 pub fn orthographic_rh(
1017 left: f64,
1018 right: f64,
1019 bottom: f64,
1020 top: f64,
1021 near: f64,
1022 far: f64,
1023 ) -> Self {
1024 let rcp_width = 1.0 / (right - left);
1025 let rcp_height = 1.0 / (top - bottom);
1026 let r = 1.0 / (near - far);
1027 Self::from_cols(
1028 DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1029 DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1030 DVec4::new(0.0, 0.0, r, 0.0),
1031 DVec4::new(
1032 -(left + right) * rcp_width,
1033 -(top + bottom) * rcp_height,
1034 r * near,
1035 1.0,
1036 ),
1037 )
1038 }
1039
1040 /// Transforms the given 3D vector as a point, applying perspective correction.
1041 ///
1042 /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
1043 /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1044 ///
1045 /// This method assumes that `self` contains a projective transform.
1046 #[inline]
1047 #[must_use]
project_point3(&self, rhs: DVec3) -> DVec31048 pub fn project_point3(&self, rhs: DVec3) -> DVec3 {
1049 let mut res = self.x_axis.mul(rhs.x);
1050 res = self.y_axis.mul(rhs.y).add(res);
1051 res = self.z_axis.mul(rhs.z).add(res);
1052 res = self.w_axis.add(res);
1053 res = res.div(res.w);
1054 res.xyz()
1055 }
1056
1057 /// Transforms the given 3D vector as a point.
1058 ///
1059 /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1060 /// `1.0`.
1061 ///
1062 /// This method assumes that `self` contains a valid affine transform. It does not perform
1063 /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
1064 /// the [`Self::project_point3()`] method should be used instead.
1065 ///
1066 /// # Panics
1067 ///
1068 /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1069 #[inline]
1070 #[must_use]
transform_point3(&self, rhs: DVec3) -> DVec31071 pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
1072 glam_assert!(self.row(3).abs_diff_eq(DVec4::W, 1e-6));
1073 let mut res = self.x_axis.mul(rhs.x);
1074 res = self.y_axis.mul(rhs.y).add(res);
1075 res = self.z_axis.mul(rhs.z).add(res);
1076 res = self.w_axis.add(res);
1077 res.xyz()
1078 }
1079
1080 /// Transforms the give 3D vector as a direction.
1081 ///
1082 /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1083 /// `0.0`.
1084 ///
1085 /// This method assumes that `self` contains a valid affine transform.
1086 ///
1087 /// # Panics
1088 ///
1089 /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1090 #[inline]
1091 #[must_use]
transform_vector3(&self, rhs: DVec3) -> DVec31092 pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
1093 glam_assert!(self.row(3).abs_diff_eq(DVec4::W, 1e-6));
1094 let mut res = self.x_axis.mul(rhs.x);
1095 res = self.y_axis.mul(rhs.y).add(res);
1096 res = self.z_axis.mul(rhs.z).add(res);
1097 res.xyz()
1098 }
1099
1100 /// Transforms a 4D vector.
1101 #[inline]
1102 #[must_use]
mul_vec4(&self, rhs: DVec4) -> DVec41103 pub fn mul_vec4(&self, rhs: DVec4) -> DVec4 {
1104 let mut res = self.x_axis.mul(rhs.x);
1105 res = res.add(self.y_axis.mul(rhs.y));
1106 res = res.add(self.z_axis.mul(rhs.z));
1107 res = res.add(self.w_axis.mul(rhs.w));
1108 res
1109 }
1110
1111 /// Multiplies two 4x4 matrices.
1112 #[inline]
1113 #[must_use]
mul_mat4(&self, rhs: &Self) -> Self1114 pub fn mul_mat4(&self, rhs: &Self) -> Self {
1115 Self::from_cols(
1116 self.mul(rhs.x_axis),
1117 self.mul(rhs.y_axis),
1118 self.mul(rhs.z_axis),
1119 self.mul(rhs.w_axis),
1120 )
1121 }
1122
1123 /// Adds two 4x4 matrices.
1124 #[inline]
1125 #[must_use]
add_mat4(&self, rhs: &Self) -> Self1126 pub fn add_mat4(&self, rhs: &Self) -> Self {
1127 Self::from_cols(
1128 self.x_axis.add(rhs.x_axis),
1129 self.y_axis.add(rhs.y_axis),
1130 self.z_axis.add(rhs.z_axis),
1131 self.w_axis.add(rhs.w_axis),
1132 )
1133 }
1134
1135 /// Subtracts two 4x4 matrices.
1136 #[inline]
1137 #[must_use]
sub_mat4(&self, rhs: &Self) -> Self1138 pub fn sub_mat4(&self, rhs: &Self) -> Self {
1139 Self::from_cols(
1140 self.x_axis.sub(rhs.x_axis),
1141 self.y_axis.sub(rhs.y_axis),
1142 self.z_axis.sub(rhs.z_axis),
1143 self.w_axis.sub(rhs.w_axis),
1144 )
1145 }
1146
1147 /// Multiplies a 4x4 matrix by a scalar.
1148 #[inline]
1149 #[must_use]
mul_scalar(&self, rhs: f64) -> Self1150 pub fn mul_scalar(&self, rhs: f64) -> Self {
1151 Self::from_cols(
1152 self.x_axis.mul(rhs),
1153 self.y_axis.mul(rhs),
1154 self.z_axis.mul(rhs),
1155 self.w_axis.mul(rhs),
1156 )
1157 }
1158
1159 /// Divides a 4x4 matrix by a scalar.
1160 #[inline]
1161 #[must_use]
div_scalar(&self, rhs: f64) -> Self1162 pub fn div_scalar(&self, rhs: f64) -> Self {
1163 let rhs = DVec4::splat(rhs);
1164 Self::from_cols(
1165 self.x_axis.div(rhs),
1166 self.y_axis.div(rhs),
1167 self.z_axis.div(rhs),
1168 self.w_axis.div(rhs),
1169 )
1170 }
1171
1172 /// Returns true if the absolute difference of all elements between `self` and `rhs`
1173 /// is less than or equal to `max_abs_diff`.
1174 ///
1175 /// This can be used to compare if two matrices contain similar elements. It works best
1176 /// when comparing with a known value. The `max_abs_diff` that should be used used
1177 /// depends on the values being compared against.
1178 ///
1179 /// For more see
1180 /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
1181 #[inline]
1182 #[must_use]
abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool1183 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
1184 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1185 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1186 && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1187 && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1188 }
1189
1190 /// Takes the absolute value of each element in `self`
1191 #[inline]
1192 #[must_use]
abs(&self) -> Self1193 pub fn abs(&self) -> Self {
1194 Self::from_cols(
1195 self.x_axis.abs(),
1196 self.y_axis.abs(),
1197 self.z_axis.abs(),
1198 self.w_axis.abs(),
1199 )
1200 }
1201
1202 #[inline]
as_mat4(&self) -> Mat41203 pub fn as_mat4(&self) -> Mat4 {
1204 Mat4::from_cols(
1205 self.x_axis.as_vec4(),
1206 self.y_axis.as_vec4(),
1207 self.z_axis.as_vec4(),
1208 self.w_axis.as_vec4(),
1209 )
1210 }
1211 }
1212
1213 impl Default for DMat4 {
1214 #[inline]
default() -> Self1215 fn default() -> Self {
1216 Self::IDENTITY
1217 }
1218 }
1219
1220 impl Add<DMat4> for DMat4 {
1221 type Output = Self;
1222 #[inline]
add(self, rhs: Self) -> Self::Output1223 fn add(self, rhs: Self) -> Self::Output {
1224 self.add_mat4(&rhs)
1225 }
1226 }
1227
1228 impl AddAssign<DMat4> for DMat4 {
1229 #[inline]
add_assign(&mut self, rhs: Self)1230 fn add_assign(&mut self, rhs: Self) {
1231 *self = self.add_mat4(&rhs);
1232 }
1233 }
1234
1235 impl Sub<DMat4> for DMat4 {
1236 type Output = Self;
1237 #[inline]
sub(self, rhs: Self) -> Self::Output1238 fn sub(self, rhs: Self) -> Self::Output {
1239 self.sub_mat4(&rhs)
1240 }
1241 }
1242
1243 impl SubAssign<DMat4> for DMat4 {
1244 #[inline]
sub_assign(&mut self, rhs: Self)1245 fn sub_assign(&mut self, rhs: Self) {
1246 *self = self.sub_mat4(&rhs);
1247 }
1248 }
1249
1250 impl Neg for DMat4 {
1251 type Output = Self;
1252 #[inline]
neg(self) -> Self::Output1253 fn neg(self) -> Self::Output {
1254 Self::from_cols(
1255 self.x_axis.neg(),
1256 self.y_axis.neg(),
1257 self.z_axis.neg(),
1258 self.w_axis.neg(),
1259 )
1260 }
1261 }
1262
1263 impl Mul<DMat4> for DMat4 {
1264 type Output = Self;
1265 #[inline]
mul(self, rhs: Self) -> Self::Output1266 fn mul(self, rhs: Self) -> Self::Output {
1267 self.mul_mat4(&rhs)
1268 }
1269 }
1270
1271 impl MulAssign<DMat4> for DMat4 {
1272 #[inline]
mul_assign(&mut self, rhs: Self)1273 fn mul_assign(&mut self, rhs: Self) {
1274 *self = self.mul_mat4(&rhs);
1275 }
1276 }
1277
1278 impl Mul<DVec4> for DMat4 {
1279 type Output = DVec4;
1280 #[inline]
mul(self, rhs: DVec4) -> Self::Output1281 fn mul(self, rhs: DVec4) -> Self::Output {
1282 self.mul_vec4(rhs)
1283 }
1284 }
1285
1286 impl Mul<DMat4> for f64 {
1287 type Output = DMat4;
1288 #[inline]
mul(self, rhs: DMat4) -> Self::Output1289 fn mul(self, rhs: DMat4) -> Self::Output {
1290 rhs.mul_scalar(self)
1291 }
1292 }
1293
1294 impl Mul<f64> for DMat4 {
1295 type Output = Self;
1296 #[inline]
mul(self, rhs: f64) -> Self::Output1297 fn mul(self, rhs: f64) -> Self::Output {
1298 self.mul_scalar(rhs)
1299 }
1300 }
1301
1302 impl MulAssign<f64> for DMat4 {
1303 #[inline]
mul_assign(&mut self, rhs: f64)1304 fn mul_assign(&mut self, rhs: f64) {
1305 *self = self.mul_scalar(rhs);
1306 }
1307 }
1308
1309 impl Div<DMat4> for f64 {
1310 type Output = DMat4;
1311 #[inline]
div(self, rhs: DMat4) -> Self::Output1312 fn div(self, rhs: DMat4) -> Self::Output {
1313 rhs.div_scalar(self)
1314 }
1315 }
1316
1317 impl Div<f64> for DMat4 {
1318 type Output = Self;
1319 #[inline]
div(self, rhs: f64) -> Self::Output1320 fn div(self, rhs: f64) -> Self::Output {
1321 self.div_scalar(rhs)
1322 }
1323 }
1324
1325 impl DivAssign<f64> for DMat4 {
1326 #[inline]
div_assign(&mut self, rhs: f64)1327 fn div_assign(&mut self, rhs: f64) {
1328 *self = self.div_scalar(rhs);
1329 }
1330 }
1331
1332 impl Sum<Self> for DMat4 {
sum<I>(iter: I) -> Self where I: Iterator<Item = Self>,1333 fn sum<I>(iter: I) -> Self
1334 where
1335 I: Iterator<Item = Self>,
1336 {
1337 iter.fold(Self::ZERO, Self::add)
1338 }
1339 }
1340
1341 impl<'a> Sum<&'a Self> for DMat4 {
sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Self>,1342 fn sum<I>(iter: I) -> Self
1343 where
1344 I: Iterator<Item = &'a Self>,
1345 {
1346 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1347 }
1348 }
1349
1350 impl Product for DMat4 {
product<I>(iter: I) -> Self where I: Iterator<Item = Self>,1351 fn product<I>(iter: I) -> Self
1352 where
1353 I: Iterator<Item = Self>,
1354 {
1355 iter.fold(Self::IDENTITY, Self::mul)
1356 }
1357 }
1358
1359 impl<'a> Product<&'a Self> for DMat4 {
product<I>(iter: I) -> Self where I: Iterator<Item = &'a Self>,1360 fn product<I>(iter: I) -> Self
1361 where
1362 I: Iterator<Item = &'a Self>,
1363 {
1364 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1365 }
1366 }
1367
1368 impl PartialEq for DMat4 {
1369 #[inline]
eq(&self, rhs: &Self) -> bool1370 fn eq(&self, rhs: &Self) -> bool {
1371 self.x_axis.eq(&rhs.x_axis)
1372 && self.y_axis.eq(&rhs.y_axis)
1373 && self.z_axis.eq(&rhs.z_axis)
1374 && self.w_axis.eq(&rhs.w_axis)
1375 }
1376 }
1377
1378 #[cfg(not(target_arch = "spirv"))]
1379 impl AsRef<[f64; 16]> for DMat4 {
1380 #[inline]
as_ref(&self) -> &[f64; 16]1381 fn as_ref(&self) -> &[f64; 16] {
1382 unsafe { &*(self as *const Self as *const [f64; 16]) }
1383 }
1384 }
1385
1386 #[cfg(not(target_arch = "spirv"))]
1387 impl AsMut<[f64; 16]> for DMat4 {
1388 #[inline]
as_mut(&mut self) -> &mut [f64; 16]1389 fn as_mut(&mut self) -> &mut [f64; 16] {
1390 unsafe { &mut *(self as *mut Self as *mut [f64; 16]) }
1391 }
1392 }
1393
1394 impl fmt::Debug for DMat4 {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1395 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1396 fmt.debug_struct(stringify!(DMat4))
1397 .field("x_axis", &self.x_axis)
1398 .field("y_axis", &self.y_axis)
1399 .field("z_axis", &self.z_axis)
1400 .field("w_axis", &self.w_axis)
1401 .finish()
1402 }
1403 }
1404
1405 impl fmt::Display for DMat4 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1407 if let Some(p) = f.precision() {
1408 write!(
1409 f,
1410 "[{:.*}, {:.*}, {:.*}, {:.*}]",
1411 p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
1412 )
1413 } else {
1414 write!(
1415 f,
1416 "[{}, {}, {}, {}]",
1417 self.x_axis, self.y_axis, self.z_axis, self.w_axis
1418 )
1419 }
1420 }
1421 }
1422