ezcgmath/matrix/
matrix4x4.rs

1use crate::{Degrees, Radians, Scalar};
2use crate::vector::*;
3use crate::quaternion::Quaternion;
4use super::Matrix3x3;
5
6/// A 4 x 4 Matrix.
7#[repr(C)]
8#[derive(Debug, Default, Copy, Clone, PartialEq)]
9pub struct Matrix4x4 {
10    pub c00: Scalar, pub c10: Scalar, pub c20: Scalar, pub c30: Scalar,
11    pub c01: Scalar, pub c11: Scalar, pub c21: Scalar, pub c31: Scalar,
12    pub c02: Scalar, pub c12: Scalar, pub c22: Scalar, pub c32: Scalar,
13    pub c03: Scalar, pub c13: Scalar, pub c23: Scalar, pub c33: Scalar,
14}
15impl_add_self!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
16impl_sub_self!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
17impl_mul_scalar!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
18impl_approx!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
19
20impl Matrix4x4 {
21    pub const fn identity() -> Self {
22        Self {
23            c00: 1.0, c10: 0.0, c20: 0.0, c30: 0.0,
24            c01: 0.0, c11: 1.0, c21: 0.0, c31: 0.0,
25            c02: 0.0, c12: 0.0, c22: 1.0, c32: 0.0,
26            c03: 0.0, c13: 0.0, c23: 0.0, c33: 1.0,
27        }
28    }
29
30    /// Constructs a new perspective projection. As a reminder, this will create a left-handed perspective matrix.
31    /// If you require a right-handed coordinate system, you'll have to convert to it with with a reflection matrix.
32    ///
33    /// The parameters follow convention as far as I am aware, but to clarify:
34    /// - `fovy` corresponds to the width of the field of view visible (or how far out you can hold your arms).
35    /// - `aspect ratio` is the ratio of width to height for the screen (so aspect_ratio = screen_width / screen_height).
36    /// - `near_plane` defines the start of the clipping volume for the camera along the z (the minimum distance at which objects can be rendered).
37    /// - `far_plane` defines the end of the clipping volume for the camera along the z (the maximum distance at which objects can be rendered).
38    pub fn new_perspective_projection(fov: Degrees, aspect_ratio: Scalar, near_plane: Scalar, far_plane: Scalar) -> Self {
39        assert!(aspect_ratio != 0.0);
40        assert!(near_plane - far_plane != 0.0);
41        let mut result = Self::default();
42        let x_scale = 2.0 / Radians::from(fov).0.tan();
43        result.c00 = x_scale;
44        result.c11 = x_scale / aspect_ratio;
45        result.c22 = far_plane / (far_plane - near_plane);
46        result.c32 = 1.0;
47        result.c33 = near_plane * far_plane / (near_plane - far_plane);
48        result
49    }
50
51    /// Constructs a new orthographic projection. As a reminder, this will create a left-handed orthographic matrix.
52    /// If you require a right-handed coordinate system, you'll have to convert to it with with a reflection matrix.
53    ///
54    /// I opted for simple parameters for this method, so you can create any size or shape orthographic bounding volume you desire.
55    /// However, my advice would be for your code to define an `orthographic_size` variable somehow. You can then convert to top/bottom/left/right as follows:
56    /// ```
57    /// struct OrthoBounds {
58    ///     top: f32,
59    ///     bottom: f32,
60    ///     left: f32,
61    ///     right: f32,
62    /// }
63    ///
64    /// fn get_ortho_bounds(orthographic_size: f32, aspect_ratio: f32) -> OrthoBounds {
65    ///     OrthoBounds {
66    ///         top: 0.5 * orthographic_size,
67    ///         bottom: -0.5 * orthographic_size,
68    ///         left: -0.5 * orthographic_size * aspect_ratio,
69    ///         right: 0.5 * orthographic_size * aspect_ratio,
70    ///     }
71    /// }
72    /// ```
73    /// If you choose not to use the above method, bear in mind that `top - bottom` and `right - left` should **never** equal 0. This will cause a panic.
74    pub fn new_orthographic_projection(top: Scalar, bottom: Scalar, left: Scalar, right: Scalar, near_plane: Scalar, far_plane: Scalar) -> Self {
75        assert!(top - bottom != 0.0);
76        assert!(left - right != 0.0);
77        assert!(near_plane - far_plane != 0.0);
78        let mut result = Self::default();
79        result.c00 = 2.0 / (right - left);
80        result.c11 = 2.0 / (top - bottom);
81        result.c22 = 1.0 / (far_plane - near_plane);
82        result.c23 = -near_plane / (far_plane - near_plane);
83        result.c33 = 1.0;
84        result
85    }
86
87    /// Creates a translation matrix from a `Vector3`.
88    pub const fn from_translation(translation: &Vector3) -> Self {
89        Self {
90            c00: 1.0, c10: 0.0, c20: 0.0, c30: 0.0,
91            c01: 0.0, c11: 1.0, c21: 0.0, c31: 0.0,
92            c02: 0.0, c12: 0.0, c22: 1.0, c32: 0.0,
93            c03: translation.x, c13: translation.y, c23: translation.z, c33: 1.0,
94        }
95    }
96
97    /// Creates a non-uniform scaling matrix from a `Vector3`.
98    pub const fn from_nonuniform_scale(scale: &Vector3) -> Self {
99        Self {
100            c00: scale.x, c10: 0.0,     c20: 0.0,     c30: 0.0,
101            c01: 0.0,     c11: scale.y, c21: 0.0,     c31: 0.0,
102            c02: 0.0,     c12: 0.0,     c22: scale.z, c32: 0.0,
103            c03: 0.0,     c13: 0.0,     c23: 0.0,     c33: 1.0,
104        }
105    }
106    
107    /// Creates a uniform scaling matrix from a `Scalar`.
108    pub const fn from_scale(scale: Scalar) -> Self {
109        Self {
110            c00: scale, c10: 0.0,   c20: 0.0,   c30: 0.0,
111            c01: 0.0,   c11: scale, c21: 0.0,   c31: 0.0,
112            c02: 0.0,   c12: 0.0,   c22: scale, c32: 0.0,
113            c03: 0.0,   c13: 0.0,   c23: 0.0,   c33: 1.0,
114        }
115    }
116
117    /// Compiles a matrix of minors for this matrix.
118    pub fn matrix_of_minors(&self) -> Matrix4x4 {
119        let c00 = Matrix3x3 {
120            c00: self.c11, c10: self.c21, c20: self.c31,
121            c01: self.c12, c11: self.c22, c21: self.c32,
122            c02: self.c13, c12: self.c23, c22: self.c33,
123        }.determinant();
124        let c10 = Matrix3x3 {
125            c00: self.c01, c10: self.c21, c20: self.c31,
126            c01: self.c02, c11: self.c22, c21: self.c32,
127            c02: self.c03, c12: self.c23, c22: self.c33,
128        }.determinant();
129        let c20 = Matrix3x3 {
130            c00: self.c01, c10: self.c11, c20: self.c31,
131            c01: self.c02, c11: self.c12, c21: self.c32,
132            c02: self.c03, c12: self.c13, c22: self.c33,
133        }.determinant();
134        let c30  = Matrix3x3 {
135            c00: self.c01, c10: self.c11, c20: self.c21,
136            c01: self.c02, c11: self.c12, c21: self.c22,
137            c02: self.c03, c12: self.c13, c22: self.c23,
138        }.determinant();
139
140        let c01 = Matrix3x3 {
141            c00: self.c10, c10: self.c20, c20: self.c30,
142            c01: self.c12, c11: self.c22, c21: self.c32,
143            c02: self.c13, c12: self.c23, c22: self.c33,
144        }.determinant();
145        let c11 = Matrix3x3 {
146            c00: self.c00, c10: self.c20, c20: self.c30,
147            c01: self.c02, c11: self.c22, c21: self.c32,
148            c02: self.c03, c12: self.c23, c22: self.c33,
149        }.determinant();
150        let c21 = Matrix3x3 {
151            c00: self.c00, c10: self.c10, c20: self.c30,
152            c01: self.c02, c11: self.c12, c21: self.c32,
153            c02: self.c03, c12: self.c13, c22: self.c33,
154        }.determinant();
155        let c31  = Matrix3x3 {
156            c00: self.c00, c10: self.c10, c20: self.c20,
157            c01: self.c02, c11: self.c12, c21: self.c22,
158            c02: self.c03, c12: self.c13, c22: self.c23,
159        }.determinant();
160        
161        let c02 = Matrix3x3 {
162            c00: self.c10, c10: self.c20, c20: self.c30,
163            c01: self.c11, c11: self.c21, c21: self.c31,
164            c02: self.c13, c12: self.c23, c22: self.c33,
165        }.determinant();
166        let c12 = Matrix3x3 {
167            c00: self.c00, c10: self.c20, c20: self.c30,
168            c01: self.c01, c11: self.c21, c21: self.c31,
169            c02: self.c03, c12: self.c23, c22: self.c33,
170        }.determinant();
171        let c22 = Matrix3x3 {
172            c00: self.c00, c10: self.c10, c20: self.c30,
173            c01: self.c01, c11: self.c11, c21: self.c31,
174            c02: self.c03, c12: self.c13, c22: self.c33,
175        }.determinant();
176        let c32  = Matrix3x3 {
177            c00: self.c00, c10: self.c10, c20: self.c20,
178            c01: self.c01, c11: self.c11, c21: self.c21,
179            c02: self.c03, c12: self.c13, c22: self.c23,
180        }.determinant();
181        
182        let c03 = Matrix3x3 {
183            c00: self.c10, c10: self.c20, c20: self.c30,
184            c01: self.c11, c11: self.c21, c21: self.c31,
185            c02: self.c12, c12: self.c22, c22: self.c32,
186        }.determinant();
187        let c13 = Matrix3x3 {
188            c00: self.c00, c10: self.c20, c20: self.c30,
189            c01: self.c01, c11: self.c21, c21: self.c31,
190            c02: self.c02, c12: self.c22, c22: self.c32,
191        }.determinant();
192        let c23 = Matrix3x3 {
193            c00: self.c00, c10: self.c10, c20: self.c30,
194            c01: self.c01, c11: self.c11, c21: self.c31,
195            c02: self.c02, c12: self.c12, c22: self.c32,
196        }.determinant();
197        let c33  = Matrix3x3 {
198            c00: self.c00, c10: self.c10, c20: self.c20,
199            c01: self.c01, c11: self.c11, c21: self.c21,
200            c02: self.c02, c12: self.c12, c22: self.c22,
201        }.determinant();
202
203        Matrix4x4 {
204            c00, c10, c20, c30,
205            c01, c11, c21, c31,
206            c02, c12, c22, c32,
207            c03, c13, c23, c33,
208        }
209    }
210    
211    /// Compiles a matrix of cofactors for this matrix.
212    pub fn matrix_of_cofactors(&self) -> Matrix4x4 {
213        Matrix4x4 {
214            c00:  self.c00, c10: -self.c10, c20:  self.c20, c30: -self.c30,
215            c01: -self.c01, c11:  self.c11, c21: -self.c21, c31:  self.c31,
216            c02:  self.c02, c12: -self.c12, c22:  self.c22, c32: -self.c32,
217            c03: -self.c03, c13:  self.c13, c23: -self.c23, c33:  self.c33,
218        }
219    }
220
221    /// Returns a new matrix with the elements transposed.
222    pub fn transpose(&self) -> Matrix4x4 {
223        Matrix4x4 {
224            c00: self.c00, c10: self.c01, c20: self.c02, c30: self.c03,
225            c01: self.c10, c11: self.c11, c21: self.c12, c31: self.c13,
226            c02: self.c20, c12: self.c21, c22: self.c22, c32: self.c23,
227            c03: self.c30, c13: self.c31, c23: self.c32, c33: self.c33,
228        }
229    }
230
231    /// Calculates the determinant for this matrix.
232    pub fn determinant(&self) -> f32 {
233        let minors = self.matrix_of_minors();
234        let cofactors = minors.matrix_of_cofactors();
235        self.c00 * cofactors.c00 + self.c10 * cofactors.c10 + self.c20 * cofactors.c20 + self.c30 * cofactors.c30
236    }
237
238    /// Calculates the Inverse matrix for this matrix.
239    pub fn inverse(&self) -> Matrix4x4 {
240        let minors = self.matrix_of_minors();
241        let cofactors = minors.matrix_of_cofactors();
242        let adjugate = cofactors.transpose();
243        let determinant = self.determinant();
244        adjugate * (1.0 / determinant)
245    }
246}
247
248impl std::ops::Mul for Matrix4x4 {
249    type Output = Matrix4x4;
250
251    fn mul(self, rhs: Matrix4x4) -> Matrix4x4 {
252        Matrix4x4 {
253            c00: self.c00 * rhs.c00 + self.c10 * rhs.c01 + self.c20 * rhs.c02 + self.c30 * rhs.c03,
254            c10: self.c00 * rhs.c10 + self.c10 * rhs.c11 + self.c20 * rhs.c12 + self.c30 * rhs.c13,
255            c20: self.c00 * rhs.c20 + self.c10 * rhs.c21 + self.c20 * rhs.c22 + self.c30 * rhs.c23,
256            c30: self.c00 * rhs.c30 + self.c10 * rhs.c31 + self.c20 * rhs.c32 + self.c30 * rhs.c33,
257
258            c01: self.c01 * rhs.c00 + self.c11 * rhs.c01 + self.c21 * rhs.c02 + self.c31 * rhs.c03,
259            c11: self.c01 * rhs.c10 + self.c11 * rhs.c11 + self.c21 * rhs.c12 + self.c31 * rhs.c13,
260            c21: self.c01 * rhs.c20 + self.c11 * rhs.c21 + self.c21 * rhs.c22 + self.c31 * rhs.c23,
261            c31: self.c01 * rhs.c30 + self.c11 * rhs.c31 + self.c21 * rhs.c32 + self.c31 * rhs.c33,
262
263            c02: self.c02 * rhs.c00 + self.c12 * rhs.c01 + self.c22 * rhs.c02 + self.c32 * rhs.c03,
264            c12: self.c02 * rhs.c10 + self.c12 * rhs.c11 + self.c22 * rhs.c12 + self.c32 * rhs.c13,
265            c22: self.c02 * rhs.c20 + self.c12 * rhs.c21 + self.c22 * rhs.c22 + self.c32 * rhs.c23,
266            c32: self.c02 * rhs.c30 + self.c12 * rhs.c31 + self.c22 * rhs.c32 + self.c32 * rhs.c33,
267
268            c03: self.c03 * rhs.c00 + self.c13 * rhs.c01 + self.c23 * rhs.c02 + self.c33 * rhs.c03,
269            c13: self.c03 * rhs.c10 + self.c13 * rhs.c11 + self.c23 * rhs.c12 + self.c33 * rhs.c13,
270            c23: self.c03 * rhs.c20 + self.c13 * rhs.c21 + self.c23 * rhs.c22 + self.c33 * rhs.c23,
271            c33: self.c03 * rhs.c30 + self.c13 * rhs.c31 + self.c23 * rhs.c32 + self.c33 * rhs.c33,
272        }
273    }
274}
275
276impl std::ops::MulAssign for Matrix4x4 {
277    fn mul_assign(&mut self, rhs: Matrix4x4) {
278        let c00 = self.c00 * rhs.c00 + self.c10 * rhs.c01 + self.c20 * rhs.c02 + self.c30 * rhs.c03;
279        let c10 = self.c00 * rhs.c10 + self.c10 * rhs.c11 + self.c20 * rhs.c12 + self.c30 * rhs.c13;
280        let c20 = self.c00 * rhs.c20 + self.c10 * rhs.c21 + self.c20 * rhs.c22 + self.c30 * rhs.c23;
281        let c30 = self.c00 * rhs.c30 + self.c10 * rhs.c31 + self.c20 * rhs.c32 + self.c30 * rhs.c33;
282
283        let c01 = self.c01 * rhs.c00 + self.c11 * rhs.c01 + self.c21 * rhs.c02 + self.c31 * rhs.c03;
284        let c11 = self.c01 * rhs.c10 + self.c11 * rhs.c11 + self.c21 * rhs.c12 + self.c31 * rhs.c13;
285        let c21 = self.c01 * rhs.c20 + self.c11 * rhs.c21 + self.c21 * rhs.c22 + self.c31 * rhs.c23;
286        let c31 = self.c01 * rhs.c30 + self.c11 * rhs.c31 + self.c21 * rhs.c32 + self.c31 * rhs.c33;
287
288        let c02 = self.c02 * rhs.c00 + self.c12 * rhs.c01 + self.c22 * rhs.c02 + self.c32 * rhs.c03;
289        let c12 = self.c02 * rhs.c10 + self.c12 * rhs.c11 + self.c22 * rhs.c12 + self.c32 * rhs.c13;
290        let c22 = self.c02 * rhs.c20 + self.c12 * rhs.c21 + self.c22 * rhs.c22 + self.c32 * rhs.c23;
291        let c32 = self.c02 * rhs.c30 + self.c12 * rhs.c31 + self.c22 * rhs.c32 + self.c32 * rhs.c33;
292
293        let c03 = self.c03 * rhs.c00 + self.c13 * rhs.c01 + self.c23 * rhs.c02 + self.c33 * rhs.c03;
294        let c13 = self.c03 * rhs.c10 + self.c13 * rhs.c11 + self.c23 * rhs.c12 + self.c33 * rhs.c13;
295        let c23 = self.c03 * rhs.c20 + self.c13 * rhs.c21 + self.c23 * rhs.c22 + self.c33 * rhs.c23;
296        let c33 = self.c03 * rhs.c30 + self.c13 * rhs.c31 + self.c23 * rhs.c32 + self.c33 * rhs.c33;
297
298        self.c00 = c00; self.c10 = c10; self.c20 = c20; self.c30 = c30;
299        self.c01 = c01; self.c11 = c11; self.c21 = c21; self.c31 = c31;
300        self.c02 = c02; self.c12 = c12; self.c22 = c22; self.c32 = c32;
301        self.c03 = c03; self.c13 = c13; self.c23 = c23; self.c33 = c33;
302    }
303}
304
305impl std::ops::Mul<Quaternion> for Matrix4x4 {
306    type Output = Matrix4x4;
307
308    fn mul(self, rhs: Quaternion) -> Self::Output {
309        self * Matrix4x4::from(rhs)
310    }
311}
312
313impl std::ops::MulAssign<Quaternion> for Matrix4x4 {
314    fn mul_assign(&mut self, rhs: Quaternion) {
315        *self *= Matrix4x4::from(rhs);
316    }
317}
318
319impl From<Quaternion> for Matrix4x4 {
320    fn from(rotation: Quaternion) -> Self {
321        let x = rotation.x * 2.0;
322        let y = rotation.y * 2.0;
323        let z = rotation.z * 2.0;
324        let xx = rotation.x * x;
325        let yy = rotation.y * y;
326        let zz = rotation.z * z;
327        let xy = rotation.x * y;
328        let xz = rotation.x * z;
329        let yz = rotation.y * z;
330        let wx = rotation.w * x;
331        let wy = rotation.w * y;
332        let wz = rotation.w * z;
333
334        Self {
335            c00: 1.0 - (yy + zz), c10: xy - wz,         c20: xz + wy,         c30: 0.0,
336            c01: xy + wz,         c11: 1.0 - (xx + zz), c21: yz - wx,         c31: 0.0,
337            c02: xz - wy,         c12: yz + wx,         c22: 1.0 - (xx + yy), c32: 0.0,
338            c03: 0.0,             c13: 0.0,             c23: 0.0,             c33: 1.0,
339        }
340    }
341}