vera_core/
matrix.rs

1/// A 4x4 matrix
2#[repr(C)]
3#[derive(Clone, Copy)]
4pub struct Mat4(pub [f32; 16]);
5
6impl std::fmt::Debug for Mat4 {
7    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8        write!(f, "[\n\t{}, {}, {}, {}, \n\t{}, {}, {}, {}, \n\t{}, {}, {}, {}, \n\t{}, {}, {}, {}, \n]", self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7], self.0[8], self.0[9], self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15])
9    }
10}
11
12impl Mat4 {
13    /// Build a new (identity) Mat4, which applies no transformations.
14    pub fn new() -> Self {
15        Mat4([
16            1.0, 0.0, 0.0, 0.0,
17            0.0, 1.0, 0.0, 0.0,
18            0.0, 0.0, 1.0, 0.0,
19            0.0, 0.0, 0.0, 1.0,
20        ])
21    }
22
23    /// Returns a pointer to the matrix, readable by OpenGL.
24    pub fn ptr(&self) -> *const f32 {
25        self.0.as_ptr()
26    }
27
28    /// Adds `mat` to `self`
29    pub fn add(&mut self, mat: Mat4) {
30        self.0.iter_mut().zip(mat.0.iter()).for_each(|(s, m)| *s+=m);
31    }
32
33    /// Multiplies this Mat4 (`self`) with another one (`mat`), further from the initial vertex position vector, so the resulting transformation will be the chaining of both matrices' transformations: first `self`, then `mat`.
34    pub fn mult(&mut self, mat: Mat4) {
35        *self = Mat4([
36            mat.0[0]  * self.0[0] + mat.0[1]  * self.0[4] + mat.0[2]  * self.0[8] + mat.0[3]  * self.0[12]  , mat.0[0]  * self.0[1] + mat.0[1]  * self.0[5] + mat.0[2]  * self.0[9] + mat.0[3]  * self.0[13]  , mat.0[0] * self.0[2]  + mat.0[1] * self.0[6]  + mat.0[2] * self.0[10]  + mat.0[3] * self.0[14]   , mat.0[0] * self.0[3]  + mat.0[1] * self.0[7]  + mat.0[2] * self.0[11]  + mat.0[3] * self.0[15], 
37            mat.0[4]  * self.0[0] + mat.0[5]  * self.0[4] + mat.0[6]  * self.0[8] + mat.0[7]  * self.0[12]  , mat.0[4]  * self.0[1] + mat.0[5]  * self.0[5] + mat.0[6]  * self.0[9] + mat.0[7]  * self.0[13]  , mat.0[4] * self.0[2]  + mat.0[5] * self.0[6]  + mat.0[6] * self.0[10]  + mat.0[7] * self.0[14]   , mat.0[4] * self.0[3]  + mat.0[5] * self.0[7]  + mat.0[6] * self.0[11]  + mat.0[7] * self.0[15], 
38            mat.0[8]  * self.0[0] + mat.0[9]  * self.0[4] + mat.0[10] * self.0[8] + mat.0[11] * self.0[12]  , mat.0[8]  * self.0[1] + mat.0[9]  * self.0[5] + mat.0[10] * self.0[9] + mat.0[11] * self.0[13]  , mat.0[8] * self.0[2]  + mat.0[9] * self.0[6]  + mat.0[10] * self.0[10] + mat.0[11] * self.0[14]  , mat.0[8] * self.0[3]  + mat.0[9] * self.0[7]  + mat.0[10] * self.0[11] + mat.0[11] * self.0[15], 
39            mat.0[12] * self.0[0] + mat.0[13] * self.0[4] + mat.0[14] * self.0[8] + mat.0[15] * self.0[12]  , mat.0[12] * self.0[1] + mat.0[13] * self.0[5] + mat.0[14] * self.0[9] + mat.0[15] * self.0[13]  , mat.0[12] * self.0[2] + mat.0[13] * self.0[6] + mat.0[14] * self.0[10] + mat.0[15] * self.0[14]  , mat.0[12] * self.0[3] + mat.0[13] * self.0[7] + mat.0[14] * self.0[11] + mat.0[15] * self.0[15], 
40        ]);
41    }
42
43    /// Divides self by a float, `scalar`.
44    pub fn div(&mut self, scalar: f32) {
45        self.0.iter_mut().for_each(|s| *s/=scalar);
46    }
47
48    /// Interpolates `self` with `mat` given the advancement (0.0 to 1.0)
49    pub fn interpolate(&mut self, mat: Mat4, advancement: f32) {
50        self.0.iter_mut().zip(mat.0.iter()).for_each(|(s, m)| *s = (1.0-advancement) * *s + advancement * m);
51    }
52
53    /// Add a scale transformation to the Mat4, for each axis.
54    /// The scale center is (0.0, 0.0, 0.0).
55    pub fn scale(x_scale: f32, y_scale: f32, z_scale: f32) -> Self {
56        Mat4([
57            x_scale ,   0.0     ,   0.0     , 0.0 , 
58            0.0     ,   y_scale ,   0.0     , 0.0 , 
59            0.0     ,   0.0     ,   z_scale , 0.0 , 
60            0.0     ,   0.0     ,   0.0     , 1.0 , 
61        ])
62    }
63
64    /// Add a rotation transformation to the Mat4 around the X axis, clockiwse.
65    /// The rotation center is (0.0, 0.0, 0.0).
66    pub fn rotate_x(angle: f32) -> Self {
67        Mat4([
68            1.0     ,   0.0         ,   0.0         , 0.0 , 
69            0.0     ,   angle.cos() ,   angle.sin() , 0.0 , 
70            0.0     ,   -angle.sin(),   angle.cos() , 0.0 , 
71            0.0     ,   0.0         ,   0.0         , 1.0 , 
72        ])
73    }
74
75    /// Add a rotation transformation to the Mat4 around the Y axis, clockiwse.
76    /// The rotation center is (0.0, 0.0, 0.0).
77    pub fn rotate_y(angle: f32) -> Self {
78        Mat4([
79            angle.cos() ,   0.0 ,   angle.sin() , 0.0 , 
80            0.0         ,   1.0 ,   0.0         , 0.0 , 
81            -angle.sin(),   0.0 ,   angle.cos() , 0.0 , 
82            0.0         ,   0.0 ,   0.0         , 1.0 , 
83        ])
84    }
85
86    /// Add a rotation transformation to the Mat4 around the Z axis, clockiwse.
87    /// The rotation center is (0.0, 0.0, 0.0).
88    pub fn rotate_z(angle: f32) -> Self {
89        Mat4([
90            angle.cos() ,   angle.sin() ,   0.0 ,   0.0 , 
91            -angle.sin(),   angle.cos() ,   0.0 ,   0.0 , 
92            0.0         ,   0.0         ,   1.0 ,   0.0 , 
93            0.0         ,   0.0         ,   0.0 ,   1.0 , 
94        ])
95    }
96
97    /// Add a translation transformation to the Mat4.
98    pub fn translate(x_move: f32, y_move: f32, z_move: f32) -> Self {
99        Mat4([
100            1.0 ,   0.0 ,   0.0 ,   x_move ,
101            0.0 ,   1.0 ,   0.0 ,   y_move ,
102            0.0 ,   0.0 ,   1.0 ,   z_move ,
103            0.0 ,   0.0 ,   0.0 ,   1.0 ,
104        ])
105    }
106
107    /// For view matrix. Moves the "camera" to (eye_x, eye_y, eye_z), looking at (target_x, target_y, target_z), with athe (up_x, up_y, up_z) up vector.
108    pub fn lookat(eye_x: f32, eye_y: f32, eye_z: f32, target_x: f32, target_y: f32, target_z: f32, mut up_x: f32, mut up_y: f32, mut up_z: f32,) -> Self {
109        // Forward vector
110        let (mut f_x, mut f_y, mut f_z) = (eye_x-target_x, eye_y-target_y, eye_z-target_z);
111        let invlen = 1.0 / (f_x*f_x+f_y*f_y+f_z*f_z).sqrt();
112        (f_x, f_y, f_z) = (f_x*invlen, f_y*invlen, f_z*invlen);
113        
114        // Left vector
115        let (mut l_x, mut l_y, mut l_z) = (up_y*f_z - up_z*f_y, up_z*f_x - up_x*f_z, up_x*f_y - up_y*f_x);
116        let invlen = 1.0 / (l_x*l_x+l_y*l_y+l_z*l_z).sqrt();
117        (l_x, l_y, l_z) = (l_x*invlen, l_y*invlen, l_z*invlen);
118        
119        // Up vector correction
120        (up_x, up_y, up_z) = (f_y*l_z - f_z*l_y, f_z*l_x - f_x*l_z, f_x*l_y - f_y*l_x);
121
122
123
124        let mut mat = Self::translate(-eye_x, -eye_y, -eye_z);
125        mat.mult(Mat4([
126            l_x ,   l_y ,   l_z ,   0.0 ,
127            up_x,   up_y,   up_z,   0.0 ,
128            f_x ,   f_y ,   f_z ,   0.0 ,
129            0.0 ,   0.0 ,   0.0 ,   1.0 ,
130        ]));
131        mat
132    }
133
134    /// For projection matrix. Defines an orthographic projection matrix with the given [left-right] - [top-bottom] - [near-far] frustrum.
135    /// The default Frustrum is set to left-right: [-1.0, 1.0], top-bottom: [-1.0, 1.0], near-far: [-1.0, 1.0]
136    pub fn project_orthographic(l: f32, r: f32, b: f32, t: f32, n: f32, f: f32) -> Self {
137        Mat4([
138            2.0 / (r - l)   ,   0.0                 ,   0.0                 ,   -(r + l) / (r - l)  ,
139            0.0             ,   2.0 / (t - b)       ,   0.0                 ,   -(t + b) / (t - b)  ,
140            0.0             ,   0.0                 ,   -2.0 / (f - n)      ,   -(f + n) / (f - n)  ,
141            0.0             ,   0.0                 ,   0.0                 ,    1.0                ,
142        ])
143    }
144
145    /// For projection matrix. Defines an perspective projection matrix with the given [left-right] - [top-bottom] - [near-far] frustrum.
146    /// The default Frustrum is set to left-right: [-1.0, 1.0], top-bottom: [-1.0, 1.0], near-far: [-1.0, 1.0]
147    pub fn project_perspective(l: f32, r: f32, b: f32, t: f32, n: f32, f: f32) -> Self {
148        Mat4([
149            2.0 * n/(r - l) ,   0.0                 ,   (r + l)/(r - l)     ,   0.0                     ,
150            0.0             ,   2.0 * n / (t - b)   ,   (t + b) / (t - b)   ,   0.0                     ,
151            0.0             ,   0.0                 ,   -(f + n) / (f - n)  ,   -(2.0 * f * n)/(f - n)  ,
152            0.0             ,   0.0                 ,   -1.0                ,   0.0                     ,
153        ])
154    }
155}