glium_types/matrices/
mat3.rs

1use glium::uniforms::AsUniformValue;
2use crate::{matrices::Mat4, quaternions::Quat, vectors::{Vec3, Vec2}};
3
4use super::Mat2;
5
6#[derive(Clone, Copy, PartialEq, Debug)]
7/// a matrix often used for transformations in glium
8pub struct Mat3 {
9    matrix: [[f32; 3]; 3]
10}
11impl Mat3{
12    pub const IDENTITY: Self = Mat3::from_values(
13        1.0, 0.0, 0.0,
14        0.0, 1.0, 0.0,
15        0.0, 0.0, 1.0,
16    );
17    pub const fn from_colum_major_array(array: [[f32; 3]; 3]) -> Self { Self { matrix: array } }
18    pub const fn into_column_major_array(self) -> [[f32; 3]; 3] { self.matrix }
19    pub const fn from_row_major_array(array: [[f32; 3]; 3]) -> Self { Self { matrix: array }.transpose() }
20    pub const fn into_row_major_array(self) -> [[f32; 3]; 3] { self.transpose().matrix }
21    pub const fn from_scale(scale: Vec3) -> Self {
22        let (x, y, z) = (scale.x, scale.y, scale.z);
23        Mat3::from_values(
24            x, 0.0, 0.0,
25            0.0, y, 0.0,
26            0.0, 0.0, z,
27        )
28    }
29    pub fn from_2d_transform(pos: Vec2, scale: Vec2, rot: f32) -> Self {
30        Self::from_values(
31            scale.x * rot.cos(), scale.y * -rot.sin(), pos.x,
32            scale.x * rot.sin(), scale.y * rot.cos(), pos.y,
33            0.0, 0.0, 1.0
34        )
35    }
36    pub fn from_transform(scale: Vec3, rot: Quat) -> Self{
37        let (r, i, j, k) = (rot.r, rot.i, rot.j, rot.k);
38        let (sx, sy, sz) = (scale.x * 2.0, scale.y * 2.0, scale.z * 2.0);
39        Mat3::from_values(
40            sx*(0.5 - (j*j + k*k)), sy*(i*j - k*r), sz*(i*k + j*r),
41            sx*(i*j + k*r), sy*(0.5 - (i*i + k*k)), sz*(j*k - i*r),
42            sx*(i*k - j*r), sy*(j*k + i*r), sz*(0.5 - (i*i + j*j)) 
43        )
44    }
45    pub fn from_rot(rot: Quat) -> Self { rot.into() }
46    ///creates a matrix with the following values.
47    ///
48    /// ```
49    /// use glium_types::matrices::Mat3;
50    /// let new_matrix = Mat3::from_values(
51    ///     1.0, 0.0, 0.0,
52    ///     0.0, 1.0, 0.0,
53    ///     0.0, 0.0, 1.0
54    /// );
55    /// assert!(new_matrix == Mat3::IDENTITY);
56    /// ```
57    #[allow(clippy::too_many_arguments)]
58    pub const fn from_values(
59        a: f32, b: f32, c: f32,
60        d: f32, e: f32, f: f32,
61        g: f32, h: f32, i: f32
62        ) -> Self{
63        Self{
64            // opengl uses a diffent matrix format to the input. this is why the order is shifted.
65            matrix: [
66                [a, d, g],
67                [b, e, h],
68                [c, f, i],
69            ]
70        }
71    }
72    pub fn scale(&self, scalar: f32) -> Mat3{
73        let Mat3 { matrix: [
74            [a, d, g],
75            [b, e, h],
76            [c, f, i],
77        ]} = self;
78        Self::from_values(
79            a * scalar, b * scalar, c * scalar,
80            d * scalar, e * scalar, f * scalar,
81            g * scalar, h * scalar, i * scalar
82        )
83    }
84    pub fn determinant(&self) -> f32{
85        let Mat3 { matrix: [
86            [a, d, g],
87            [b, e, h],
88            [c, f, i],
89        ]} = self;
90        a*(e*i - f*h) - b*(d*i - f*g) + c*(d*h - e*g)
91    }
92    #[allow(non_snake_case)]
93    pub fn inverse(&self) -> Mat3{
94        let Mat3 { matrix: [
95            [a, d, g],
96            [b, e, h],
97            [c, f, i],
98        ]} = self;
99        let A = e*i - f*h;
100        let B = -(d*i - f*g);
101        let C = d*h - e*g;
102        
103        let determinet = a*A + b*B + c*C;
104        let scalar = 1.0/determinet;
105        Self::from_values(
106            A, -(b*i - c*h), b*f - c*e,
107            B, a*i - c*g, -(a*f - c*d),
108            C, -(a*h - b*g), a*e - b*d
109        ).scale(scalar)
110    }
111    pub const fn transpose(self) -> Self {
112        let Mat3 { matrix: [
113            [a, d, g],
114            [b, e, h],
115            [c, f, i],
116        ]} = self;
117        Mat3::from_values(
118            a, d, g,
119            b, e, h,
120            c, f, i
121        )
122    }
123    pub const fn column(&self, pos: usize) -> [f32; 3] {
124        self.matrix[pos]
125    }
126    pub const fn row(&self, pos: usize) -> [f32; 3] {
127        let matrix = self.matrix;
128        [matrix[0][pos], matrix[1][pos], matrix[2][pos]]
129    }
130}
131
132impl Default for Mat3 {
133    fn default() -> Self {
134        Self { matrix: [
135            [1.0, 0.0, 0.0,],
136            [0.0, 1.0, 0.0,],
137            [0.0, 0.0, 1.0,],
138        ] }
139    }
140    
141}
142impl std::ops::Mul<Vec3> for Mat3 {
143    fn mul(self, rhs: Vec3) -> Self::Output { rhs.transform(self) }
144    type Output = Vec3;
145}
146impl std::ops::Mul<f32> for Mat3 {
147    fn mul(self, rhs: f32) -> Self::Output { self.scale(rhs) }
148    type Output = Self;
149}
150impl std::ops::Mul<Mat3> for f32 {
151    fn mul(self, rhs: Mat3) -> Self::Output { rhs * self }
152    type Output = Mat3;
153}
154impl std::ops::MulAssign<f32> for Mat3 {
155    fn mul_assign(&mut self, rhs: f32) { *self = *self * rhs }
156}
157impl std::ops::Div<Mat3> for f32 {
158    fn div(self, rhs: Mat3) -> Self::Output {
159        let Mat3 { matrix: [
160            [a, d, g],
161            [b, e, h],
162            [c, f, i],
163        ]} = rhs;
164        Mat3::from_values(
165            self/a, self/b, self/c,
166            self/d, self/e, self/f,
167            self/g, self/h, self/i
168        )
169    }
170    type Output = Mat3;
171}
172impl std::ops::Div<f32> for Mat3 {
173    fn div(self, rhs: f32) -> Self::Output { self.scale(1.0/rhs) }
174    type Output = Self;
175}
176impl std::ops::DivAssign<f32> for Mat3 {
177    fn div_assign(&mut self, rhs: f32) { *self = *self / rhs }
178}
179impl std::ops::Rem<Mat3> for f32 {
180    fn rem(self, rhs: Mat3) -> Self::Output {
181        let Mat3 { matrix: [
182            [a, d, g],
183            [b, e, h],
184            [c, f, i],
185        ]} = rhs;
186        Mat3::from_values(
187            self%a, self%b, self%c,
188            self%d, self%e, self%f,
189            self%g, self%h, self%i
190        )
191    }
192    type Output = Mat3;
193}
194impl std::ops::Rem<f32> for Mat3 {
195    fn rem(self, rhs: f32) -> Self::Output {
196        let Mat3 { matrix: [
197            [a, d, g],
198            [b, e, h],
199            [c, f, i],
200        ]} = self;
201        Mat3::from_values(
202            a%rhs, b%rhs, c%rhs,
203            d%rhs, e%rhs, f%rhs,
204            g%rhs, h%rhs, i%rhs
205        )
206    }
207    type Output = Self;
208}
209impl std::ops::RemAssign<f32> for Mat3 {
210    fn rem_assign(&mut self, rhs: f32) { *self = *self % rhs }
211}
212#[allow(clippy::needless_range_loop)]
213impl std::ops::Mul for Mat3{
214    fn mul(self, rhs: Self) -> Self::Output {
215        let mut matrix = [[0.0; 3];  3];
216        for x in 0..3 {
217            for y in 0..3 {
218                matrix[x][y] = Vec3::dot(self.row(y).into(), rhs.column(x).into());
219            }
220        }
221        Self {
222            matrix
223        }
224    }
225    type Output = Self;
226}
227impl std::ops::MulAssign for Mat3 {
228    fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs }
229}
230#[allow(clippy::suspicious_arithmetic_impl)]
231impl std::ops::Div for Mat3 {
232    fn div(self, rhs: Self) -> Self::Output { self * rhs.inverse() }
233    type Output = Self;
234}
235impl std::ops::DivAssign for Mat3 {
236    fn div_assign(&mut self, rhs: Self) { *self = *self / rhs }
237}
238impl AsUniformValue for Mat3 {
239    fn as_uniform_value(&self) -> glium::uniforms::UniformValue<'_> {
240        glium::uniforms::UniformValue::Mat3(self.matrix)
241    }
242}
243impl std::ops::Add for Mat3{
244    fn add(self, rhs: Self) -> Self::Output {
245        let a = self.matrix;
246        let b = rhs.matrix;
247        Self{
248            matrix:[
249                [a[0][0] + b[0][0], a[0][1] + b[0][1], a[0][2] + b[0][2]],
250                [a[1][0] + b[1][0], a[1][1] + b[1][1], a[1][2] + b[1][2]],
251                [a[2][0] + b[2][0], a[2][1] + b[2][1], a[2][2] + b[2][2]],
252            ]
253        }
254    }
255    type Output = Self;
256}
257impl std::ops::AddAssign for Mat3{
258    fn add_assign(&mut self, rhs: Self) {
259        let a = self.matrix;
260        let b = rhs.matrix;
261        *self = Self{
262            matrix:[
263                [a[0][0] + b[0][0], a[0][1] + b[0][1], a[0][2] + b[0][2]],
264                [a[1][0] + b[1][0], a[1][1] + b[1][1], a[1][2] + b[1][2]],
265                [a[2][0] + b[2][0], a[2][1] + b[2][1], a[2][2] + b[2][2]],
266            ]
267        };
268    }
269}
270impl std::ops::Sub for Mat3{
271    fn sub(self, rhs: Self) -> Self::Output {
272        let a = self.matrix;
273        let b = rhs.matrix;
274        Self { matrix:[
275                [a[0][0] - b[0][0], a[0][1] - b[0][1], a[0][2] - b[0][2]],
276                [a[1][0] - b[1][0], a[1][1] - b[1][1], a[1][2] - b[1][2]],
277                [a[2][0] - b[2][0], a[2][1] - b[2][1], a[2][2] - b[2][2]],
278        ] }
279    }
280    type Output = Self;
281}
282impl std::ops::SubAssign for Mat3{
283    fn sub_assign(&mut self, rhs: Self) {
284        let a = self.matrix;
285        let b = rhs.matrix;
286        *self = Self { matrix:[
287                [a[0][0] - b[0][0], a[0][1] - b[0][1], a[0][2] - b[0][2]],
288                [a[1][0] - b[1][0], a[1][1] - b[1][1], a[1][2] - b[1][2]],
289                [a[2][0] - b[2][0], a[2][1] - b[2][1], a[2][2] - b[2][2]],
290        ] };
291    }
292}
293impl From<Mat4> for Mat3{
294    fn from(value: Mat4) -> Self {
295        Self::from_values(
296            value[0][0], value[0][1], value[0][2],
297            value[1][0], value[1][1], value[1][2],
298            value[2][0], value[2][1], value[2][2]
299        )
300    }
301}
302impl From<Mat2> for Mat3{
303    fn from(value: Mat2) -> Self {
304        Self::from_values(
305            value[0][0], value[0][1], 0.0,
306            value[1][0], value[1][1], 0.0,
307            0.0, 0.0, 1.0
308        )
309    }
310}
311impl From<Quat> for Mat3 {
312    fn from(value: Quat) -> Mat3 {
313        let Quat { r, i, j, k } = value;
314        Mat3::from_values(
315            1.0 - 2.0*(j*j + k*k), 2.0*(i*j - k*r), 2.0*(i*k + j*r),
316            2.0*(i*j + k*r), 1.0 - 2.0*(i*i + k*k), 2.0*(j*k - i*r),
317            2.0*(i*k - j*r), 2.0*(j*k + i*r), 1.0 - 2.0*(i*i + j*j)
318        )
319    }
320}
321impl std::ops::Index<usize> for Mat3{
322    fn index(&self, index: usize) -> &Self::Output {
323        &self.matrix[index]
324    }
325    type Output = [f32; 3];
326}
327impl std::ops::IndexMut<usize> for Mat3{
328    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
329        &mut self.matrix[index]
330    }
331}
332#[test]
333fn test_inverse(){
334    let mut a = Mat3::from_values(
335        4.0, 0.0, 2.0,
336        1.0, 3.0, 8.0,
337        2.0, 3.0, 4.0
338    );
339    a = a.inverse() * a;
340    assert!(a == Mat3::IDENTITY)
341}