glium_types/matrices/
mat4.rs

1use glium::uniforms::AsUniformValue;
2
3use crate::{matrices::Mat3, prelude::{vec3, Vec4}, quaternions::Quat, vectors::Vec3};
4
5use super::Mat2;
6
7#[derive(Clone, Copy, PartialEq, Debug)]
8/// a matrix often used for transformations in glium
9pub struct Mat4 {
10    matrix: [[f32; 4]; 4]
11}
12impl Mat4{
13    pub const IDENTITY: Self = Mat4::from_values(
14        1.0, 0.0, 0.0, 0.0,
15        0.0, 1.0, 0.0, 0.0,
16        0.0, 0.0, 1.0, 0.0,
17        0.0, 0.0, 0.0, 1.0
18    );
19    pub const fn from_column_major_array(array: [[f32; 4]; 4]) -> Self { Self { matrix: array } }
20    pub const fn into_column_major_array(self) -> [[f32; 4]; 4] { self.matrix }
21    pub const fn from_row_major_array(array: [[f32; 4]; 4]) -> Self { Self { matrix: array }.transpose() }
22    pub const fn into_row_major_array(self) -> [[f32; 4]; 4] { self.transpose().matrix }
23    pub const fn from_scale(scale: Vec3) -> Self{
24        let (x, y, z) = (scale.x, scale.y, scale.z);
25        Mat4::from_values(
26            x, 0.0, 0.0, 0.0,
27            0.0, y, 0.0, 0.0,
28            0.0, 0.0, z, 0.0,
29            0.0, 0.0, 0.0, 1.0
30        )
31    }
32    /// transform from position, scale and rotation. much quicker than multiplying
33    ///  position * rot * scale matrices while having the same result.
34    pub fn from_transform(pos: Vec3, scale: Vec3, rot: Quat) -> Self{
35        let Quat { r, i, j, k } = rot;
36        let (sx, sy, sz) = (scale.x * 2.0, scale.y * 2.0, scale.z * 2.0);
37        Mat4::from_values(
38            sx*(0.5 - (j*j + k*k)), sy*(i*j - k*r), sz*(i*k + j*r), pos.x,
39            sx*(i*j + k*r), sy*(0.5 - (i*i + k*k)), sz*(j*k - i*r), pos.y,
40            sx*(i*k - j*r), sy*(j*k + i*r), sz*(0.5 - (i*i + j*j)), pos.z,   
41            0.0, 0.0, 0.0, 1.0
42        )
43    }
44    /// makes inverse of `from_transform`, useful for making camera transform.
45    pub fn from_inverse_transform(pos: Vec3, scale: Vec3, rot: Quat) -> Self {
46        let Quat { r, i, j, k } = rot;
47        let Vec3 { x, y, z } = Vec3::ONE / scale;
48
49        let scalar = r*r + i*i + j*j + k*k;
50        let s = 2.0/(scalar*scalar);
51        let sx = s*x;
52        let sy = s*y;
53        let sz = s*z;
54        let a = x - sx*(j*j + k*k);
55        let b = sx*(i*j + k*r);
56        let c = sx*(i*k - j*r);
57        let d = sy*(i*j - k*r);
58        let e = y - sy*(i*i + k*k);
59        let f = sy*(j*k + i*r);
60        let g = sz*(i*k + j*r);
61        let h = sz*(j*k - i*r);
62        let i = z - sz*(i*i + j*j);
63        Mat4::from_values(
64            a, b, c, -a*pos.x - b*pos.y - c*pos.z,
65            d, e, f, -d*pos.x - e*pos.y - f*pos.z,
66            g, h, i, -g*pos.x - h*pos.y - i*pos.z,
67            0.0, 0.0, 0.0, 1.0
68        )
69    }
70    pub fn from_pos_and_rot(pos: Vec3, rot: Quat) -> Self{
71        let (r, i, j, k) = (rot.r, rot.i, rot.j, rot.k);
72        Mat4::from_values(
73            1.0 - 2.0*(j*j + k*k), 2.0*(i*j - k*r), 2.0*(i*k + j*r), pos.x,
74            2.0*(i*j + k*r), 1.0 - 2.0*(i*i + k*k), 2.0*(j*k - i*r), pos.y,
75            2.0*(i*k - j*r), 2.0*(j*k + i*r), 1.0 - 2.0*(i*i + j*j), pos.z,   
76            0.0, 0.0, 0.0, 1.0
77        )
78    }
79    pub const fn from_pos_and_scale(pos: Vec3, scale: Vec3) -> Self{
80        Mat4::from_values(
81            scale.x, 0.0, 0.0, pos.x,
82            0.0, scale.y, 0.0, pos.y,
83            0.0, 0.0, scale.z, pos.z,
84            0.0, 0.0, 0.0, 1.0
85        )
86    }
87    pub fn from_scale_and_rot(scale: Vec3, rot: Quat) -> Self{
88        let (r, i, j, k) = (rot.r, rot.i, rot.j, rot.k);
89        let (sx, sy, sz) = (scale.x * 2.0, scale.y * 2.0, scale.z * 2.0);
90        Mat4::from_values(
91            sx*(0.5 - (j*j + k*k)), sy*(i*j - k*r), sz*(i*k + j*r), 0.0,
92            sx*(i*j + k*r), sy*(0.5 - (i*i + k*k)), sz*(j*k - i*r), 0.0,
93            sx*(i*k - j*r), sy*(j*k + i*r), sz*(0.5 - (i*i + j*j)), 0.0,   
94            0.0, 0.0, 0.0, 1.0
95        )
96    }
97    pub const fn from_pos(pos: Vec3) -> Self{
98        let (x, y, z) = (pos.x, pos.y, pos.z);
99        Mat4::from_values(
100            1.0, 0.0, 0.0, x,
101            0.0, 1.0, 0.0, y,
102            0.0, 0.0, 1.0, z,
103            0.0, 0.0, 0.0, 1.0
104        )
105    }
106    pub fn from_rot(rot: Quat) -> Self{
107        rot.into()
108    }
109    /// rotates the matrixs components
110    pub const fn transpose(self) -> Self {
111        let Mat4 { matrix: [
112            [a, e, i, m],
113            [b, f, j, n],
114            [c, g, k, o],
115            [d, h, l, p]
116        ] } = self;
117        Mat4::from_values(
118            a, e, i, m,
119            b, f, j, n,
120            c, g, k, o,
121            d, h, l, p
122        )
123    }
124    /// creates a 3d perspective matrix. known as `perspective` in the supplied vertex shader.
125    pub fn perspective_3d(window_dimesnsions: (u32, u32), fov: f32, zfar: f32, znear: f32) -> Self {
126        let (width, height) = window_dimesnsions;
127        let aspect_ratio = height as f32 / width as f32;
128        let f = 1.0 / (fov / 2.0).tan();
129        Self { matrix: [
130            [f * aspect_ratio, 0.0,              0.0              , 0.0],
131            [         0.0    ,  f ,              0.0              , 0.0],
132            [         0.0    , 0.0,  (zfar+znear)/(zfar-znear)    , 1.0],
133            [         0.0    , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0],
134        ] }
135    }
136    /// creates a 2d perspective matrix. known as `perspective` in the supplied vertex shader.
137    pub fn perspective_2d(window_dimesnsions: (u32, u32)) -> Self {
138        let (width, height) = window_dimesnsions;
139        let aspect_ratio = height as f32 / width as f32;
140        Mat4::from_scale(vec3(aspect_ratio, 1.0, 1.0))
141    }
142    /// creates a matrix with the following values.
143    /// ```
144    /// use glium_types::matrices::Mat4;
145    /// let new_matrix = Mat4::from_values(
146    ///     1.0, 0.0, 0.0, 0.0,
147    ///     0.0, 1.0, 0.0, 0.0,
148    ///     0.0, 0.0, 1.0, 0.0,
149    ///     0.0, 0.0, 0.0, 1.0
150    /// );
151    /// assert!(new_matrix == Mat4::IDENTITY);
152    /// ```
153    #[allow(clippy::too_many_arguments)]
154    pub const fn from_values(
155        a: f32, b: f32, c: f32, d: f32,
156        e: f32, f: f32, g: f32, h: f32,
157        i: f32, j: f32, k: f32, l: f32,
158        m: f32, n: f32, o: f32, p: f32
159        ) -> Self{
160        Self{
161            // opengl uses a diffent matrix format to the input. this is why the order is shifted.
162            matrix: [
163                [a, e, i, m],
164                [b, f, j, n],
165                [c, g, k, o],
166                [d, h, l, p]
167            ]
168        }
169    }
170    pub const fn column(&self, pos: usize) -> [f32; 4] {
171        self.matrix[pos]
172    }
173    pub const fn row(&self, pos: usize) -> [f32; 4] {
174        let matrix = self.matrix;
175        [matrix[0][pos], matrix[1][pos], matrix[2][pos], matrix[3][pos]]
176    }
177    pub fn position(&self) -> Vec3 {
178        vec3(self[3][0], self[3][1], self[3][2])
179    }
180    pub fn determinant(self) -> f32 {
181        let a = self;
182        let s0 = a[0][0] * a[1][1] - a[1][0] * a[0][1];
183        let s1 = a[0][0] * a[1][2] - a[1][0] * a[0][2];
184        let s2 = a[0][0] * a[1][3] - a[1][0] * a[0][3];
185        let s3 = a[0][1] * a[1][2] - a[1][1] * a[0][2];
186        let s4 = a[0][1] * a[1][3] - a[1][1] * a[0][3];
187        let s5 = a[0][2] * a[1][3] - a[1][2] * a[0][3];
188
189        let c5 = a[2][2] * a[3][3] - a[3][2] * a[2][3];
190        let c4 = a[2][1] * a[3][3] - a[3][1] * a[2][3];
191        let c3 = a[2][1] * a[3][2] - a[3][1] * a[2][2];
192        let c2 = a[2][0] * a[3][3] - a[3][0] * a[2][3];
193        let c1 = a[2][0] * a[3][2] - a[3][0] * a[2][2];
194        let c0 = a[2][0] * a[3][1] - a[3][0] * a[2][1];
195
196        s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0
197    }
198    /// get inverse of matrix. useful for camera.
199    pub fn inverse(self) -> Self {
200        let a = self;
201        let s0 = a[0][0] * a[1][1] - a[1][0] * a[0][1];
202        let s1 = a[0][0] * a[1][2] - a[1][0] * a[0][2];
203        let s2 = a[0][0] * a[1][3] - a[1][0] * a[0][3];
204        let s3 = a[0][1] * a[1][2] - a[1][1] * a[0][2];
205        let s4 = a[0][1] * a[1][3] - a[1][1] * a[0][3];
206        let s5 = a[0][2] * a[1][3] - a[1][2] * a[0][3];
207
208        let c5 = a[2][2] * a[3][3] - a[3][2] * a[2][3];
209        let c4 = a[2][1] * a[3][3] - a[3][1] * a[2][3];
210        let c3 = a[2][1] * a[3][2] - a[3][1] * a[2][2];
211        let c2 = a[2][0] * a[3][3] - a[3][0] * a[2][3];
212        let c1 = a[2][0] * a[3][2] - a[3][0] * a[2][2];
213        let c0 = a[2][0] * a[3][1] - a[3][0] * a[2][1];
214
215        let invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0);
216
217        let mut b = Mat4::IDENTITY;
218        
219        b[0][0] = ( a[1][1] * c5 - a[1][2] * c4 + a[1][3] * c3) * invdet;
220        b[0][1] = (-a[0][1] * c5 + a[0][2] * c4 - a[0][3] * c3) * invdet;
221        b[0][2] = ( a[3][1] * s5 - a[3][2] * s4 + a[3][3] * s3) * invdet;
222        b[0][3] = (-a[2][1] * s5 + a[2][2] * s4 - a[2][3] * s3) * invdet;
223
224        b[1][0] = (-a[1][0] * c5 + a[1][2] * c2 - a[1][3] * c1) * invdet;
225        b[1][1] = ( a[0][0] * c5 - a[0][2] * c2 + a[0][3] * c1) * invdet;
226        b[1][2] = (-a[3][0] * s5 + a[3][2] * s2 - a[3][3] * s1) * invdet;
227        b[1][3] = ( a[2][0] * s5 - a[2][2] * s2 + a[2][3] * s1) * invdet;
228
229        b[2][0] = ( a[1][0] * c4 - a[1][1] * c2 + a[1][3] * c0) * invdet;
230        b[2][1] = (-a[0][0] * c4 + a[0][1] * c2 - a[0][3] * c0) * invdet;
231        b[2][2] = ( a[3][0] * s4 - a[3][1] * s2 + a[3][3] * s0) * invdet;
232        b[2][3] = (-a[2][0] * s4 + a[2][1] * s2 - a[2][3] * s0) * invdet;
233
234        b[3][0] = (-a[1][0] * c3 + a[1][1] * c1 - a[1][2] * c0) * invdet;
235        b[3][1] = ( a[0][0] * c3 - a[0][1] * c1 + a[0][2] * c0) * invdet;
236        b[3][2] = (-a[3][0] * s3 + a[3][1] * s1 - a[3][2] * s0) * invdet;
237        b[3][3] = ( a[2][0] * s3 - a[2][1] * s1 + a[2][2] * s0) * invdet;
238
239        b
240    }
241    pub fn scale(self, scalar: f32) -> Mat4 {
242        let Mat4 { matrix: [
243            [a, e, i, m],
244            [b, f, j, n],
245            [c, g, k, o],
246            [d, h, l, p]
247        ] } = self;
248        Mat4::from_values(
249            a*scalar, b*scalar, c*scalar, d*scalar,
250            e*scalar, f*scalar, g*scalar, h*scalar,
251            i*scalar, j*scalar, k*scalar, l*scalar,
252            m*scalar, n*scalar, o*scalar, p*scalar
253        )
254    }
255}
256impl Default for Mat4{
257    fn default() -> Self {
258        Self { matrix: [
259            [1.0, 0.0, 0.0, 0.0],
260            [0.0, 1.0, 0.0, 0.0],
261            [0.0, 0.0, 1.0, 0.0],
262            [0.0, 0.0, 0.0, 1.0],
263        ] }
264    }
265}
266impl std::ops::Mul<Vec4> for Mat4 {
267    fn mul(self, rhs: Vec4) -> Self::Output { rhs.transform(self) }
268    type Output = Vec4;
269}
270impl std::ops::MulAssign<f32> for Mat4 {
271    fn mul_assign(&mut self, rhs: f32) { *self = *self * rhs }
272}
273impl std::ops::Mul<f32> for Mat4 {
274    fn mul(self, rhs: f32) -> Self::Output { self.scale(rhs) }
275    type Output = Self;
276}
277impl std::ops::Mul<Mat4> for f32 {
278    fn mul(self, rhs: Mat4) -> Self::Output { rhs * self }
279    type Output = Mat4;
280}
281impl std::ops::DivAssign<f32> for Mat4 {
282    fn div_assign(&mut self, rhs: f32) { *self = *self / rhs }
283}
284impl std::ops::Div<f32> for Mat4 {
285    fn div(self, rhs: f32) -> Self::Output { self.scale(1.0/rhs) }
286    type Output = Self;
287}
288impl std::ops::Div<Mat4> for f32 {
289    fn div(self, rhs: Mat4) -> Self::Output {
290        let Mat4 { matrix: [
291            [a, e, i, m],
292            [b, f, j, n],
293            [c, g, k, o],
294            [d, h, l, p]
295        ] } = rhs;
296        Mat4::from_values(
297            self/a, self/b, self/c, self/d,
298            self/e, self/f, self/g, self/h,
299            self/i, self/j, self/k, self/l,
300            self/m, self/n, self/o, self/p
301        )
302    }
303    type Output = Mat4;
304}
305impl std::ops::RemAssign<f32> for Mat4 {
306    fn rem_assign(&mut self, rhs: f32) { *self = *self % rhs }
307}
308impl std::ops::Rem<f32> for Mat4 {
309    fn rem(self, rhs: f32) -> Self::Output {
310        let Mat4 { matrix: [
311            [a, e, i, m],
312            [b, f, j, n],
313            [c, g, k, o],
314            [d, h, l, p]
315        ] } = self;
316        Mat4::from_values(
317            a%rhs, b%rhs, c%rhs, d%rhs,
318            e%rhs, f%rhs, g%rhs, h%rhs,
319            i%rhs, j%rhs, k%rhs, l%rhs,
320            m%rhs, n%rhs, o%rhs, p%rhs
321        )
322    }
323    type Output = Self;
324}
325impl std::ops::Rem<Mat4> for f32 {
326    fn rem(self, rhs: Mat4) -> Self::Output {
327        let Mat4 { matrix: [
328            [a, e, i, m],
329            [b, f, j, n],
330            [c, g, k, o],
331            [d, h, l, p]
332        ] } = rhs;
333        Mat4::from_values(
334            self%a, self%b, self%c, self%d,
335            self%e, self%f, self%g, self%h,
336            self%i, self%j, self%k, self%l,
337            self%m, self%n, self%o, self%p
338        )
339    }
340    type Output = Mat4;
341}
342#[allow(clippy::needless_range_loop)] // in this case i think it looks nicer :)
343impl std::ops::Mul for Mat4{
344    fn mul(self, rhs: Self) -> Self::Output {
345        let mut matrix = [[0.0; 4];  4];
346        for x in 0..4{
347            for y in 0..4{
348                matrix[x][y] = Vec4::dot(self.row(y).into(), rhs.column(x).into());
349            }
350        }
351        Self {
352            matrix
353        }
354    }
355    type Output = Self;
356}
357impl std::ops::MulAssign for Mat4{
358    fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs }
359}
360#[allow(clippy::suspicious_arithmetic_impl)]
361impl std::ops::Div for Mat4{
362    fn div(self, rhs: Self) -> Self::Output { self * rhs.inverse() }
363    type Output = Self;
364}
365impl std::ops::DivAssign for Mat4{
366    fn div_assign(&mut self, rhs: Self) { *self = *self / rhs }
367}
368impl AsUniformValue for Mat4{
369    fn as_uniform_value(&self) -> glium::uniforms::UniformValue<'_> {
370        glium::uniforms::UniformValue::Mat4(self.matrix)
371    }
372}
373impl std::ops::Add for Mat4{
374    fn add(self, rhs: Self) -> Self::Output {
375        let a = self.matrix;
376        let b = rhs.matrix;
377        Self{
378            matrix:[
379                [a[0][0] + b[0][0], a[0][1] + b[0][1], a[0][2] + b[0][2], a[0][3] + b[0][3]],
380                [a[1][0] + b[1][0], a[1][1] + b[1][1], a[1][2] + b[1][2], a[1][3] + b[1][3]],
381                [a[2][0] + b[2][0], a[2][1] + b[2][1], a[2][2] + b[2][2], a[2][3] + b[2][3]],
382                [a[3][0] + b[3][0], a[3][1] + b[3][1], a[3][2] + b[3][2], a[3][3] + b[3][3]],
383            ]
384        }
385    }
386    type Output = Self;
387}
388impl std::ops::AddAssign for Mat4{
389    fn add_assign(&mut self, rhs: Self) {
390        *self = *self + rhs
391    }
392}
393impl std::ops::Sub for Mat4{
394    fn sub(self, rhs: Self) -> Self::Output {
395        let a = self.matrix;
396        let b = rhs.matrix;
397        Self{
398            matrix:[
399                [a[0][0] - b[0][0], a[0][1] - b[0][1], a[0][2] - b[0][2], a[0][3] - b[0][3]],
400                [a[1][0] - b[1][0], a[1][1] - b[1][1], a[1][2] - b[1][2], a[1][3] - b[1][3]],
401                [a[2][0] - b[2][0], a[2][1] - b[2][1], a[2][2] - b[2][2], a[2][3] - b[2][3]],
402                [a[3][0] - b[3][0], a[3][1] - b[3][1], a[3][2] - b[3][2], a[3][3] - b[3][3]],
403            ]
404        }
405    }
406    type Output = Self;
407}
408impl std::ops::SubAssign for Mat4{
409    fn sub_assign(&mut self, rhs: Self) {
410        *self = *self - rhs
411    }
412}
413impl From<Mat3> for Mat4{
414    fn from(value: Mat3) -> Self {
415        Self::from_values(
416            value[0][0], value[0][1], value[0][2], 0.0,
417            value[1][0], value[1][1], value[1][2], 0.0,
418            value[2][0], value[2][1], value[2][2], 0.0,
419            0.0,         0.0,         0.0,         1.0
420        )
421    }
422}
423impl From<Mat2> for Mat4{
424    fn from(value: Mat2) -> Self {
425        Self::from_values(
426            value[0][0], value[0][1], 0.0, 0.0,
427            value[1][0], value[1][1], 0.0, 0.0,
428            0.0,         0.0,         1.0, 0.0,
429            0.0,         0.0,         0.0, 1.0
430        )
431    }
432}
433impl From<Quat> for Mat4 {
434    fn from(value: Quat) -> Mat4 {
435        let Quat { r, i, j, k } = value;
436         Mat4::from_values(
437            1.0 - 2.0*(j*j + k*k), 2.0*(i*j - k*r), 2.0*(i*k + j*r), 0.0,
438            2.0*(i*j + k*r), 1.0 - 2.0*(i*i + k*k), 2.0*(j*k - i*r), 0.0,
439            2.0*(i*k - j*r), 2.0*(j*k + i*r), 1.0 - 2.0*(i*i + j*j), 0.0,   
440            0.0, 0.0, 0.0, 1.0
441        )
442    }
443}
444impl std::ops::Index<usize> for Mat4{
445    fn index(&self, index: usize) -> &Self::Output {
446        &self.matrix[index]
447    }
448    
449    type Output = [f32; 4];
450}
451impl std::ops::IndexMut<usize> for Mat4{
452    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
453        &mut self.matrix[index]
454    }
455}
456#[cfg(test)]
457mod tests {
458    use super::*;
459    #[test]
460    fn test_from_inverse_transform() {
461        let rot = Quat::from_x_rot(1.3);
462        let pos = vec3(1.0, 2.0, 0.3);
463        let scale = vec3(1.1, 2.0, 3.9);
464        let transform = Mat4::from_transform(pos, scale, rot);
465        let inv_transform = Mat4::from_inverse_transform(pos, scale, rot);
466        let result = transform * inv_transform;
467        assert!(eq_mats(Mat4::IDENTITY, result));
468    }
469    #[test]
470    fn mat4_inverse() {
471        let rot = Quat::from_x_rot(1.3);
472        let pos = vec3(1.0, 2.0, 0.3);
473        let scale = vec3(1.1, 2.0, 3.9);
474        let a = Mat4::from_transform(pos, scale, rot);
475        assert!(eq_mats(Mat4::IDENTITY, a.inverse() * a));
476    }
477    #[test]
478    fn test_transform(){
479        let rot = Quat::from_x_rot(1.3);
480        let pos = vec3(1.0, 2.0, 0.3);
481        let scale = vec3(1.1, 2.0, 3.9);
482        let transform = Mat4::from_transform(pos, scale, rot);
483        let result = Mat4::from_pos(pos) * Mat4::from_rot(rot) * Mat4::from_scale(scale);
484        assert!(eq_mats(transform, result))
485    }
486    fn eq_mats(a: Mat4, b: Mat4) -> bool {
487        for x in 0..4 {
488            for y in 0..4 {
489                if f32::abs(a[x][y] - b[x][y]) > f32::EPSILON {
490                    return false;
491                }
492            }
493        }
494        true
495    }
496}