firmath 0.4.2

Math Library for Graphics
Documentation
use crate::vector3::Vector3;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct Matrix4 {
    m: [[f32; 4]; 4]
}

impl Matrix4 {
    pub fn new(m: [[f32; 4]; 4]) -> Matrix4 {
        Matrix4 {
            m
        }
    }

    pub fn identity() -> Matrix4 {
        Matrix4 {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        }
    }

    pub fn get_matrix(&self) -> [[f32; 4]; 4] {
        self.m
    }

    pub fn translate(&self, v: &Vector3) -> Matrix4 {
        let mut mat = Matrix4::identity();
        
        // translate
        mat.m[0][3] = v.x();
        mat.m[1][3] = v.y();
        mat.m[2][3] = v.z();

        return *self * mat;
    }

    pub fn rotate_x(&self, angle: &f32) -> Matrix4 {

        // rotate
        let mat = Matrix4::new([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, angle.cos(), -angle.sin(), 0.0],
            [0.0, angle.sin(), angle.cos(), 0.0],
            [0.0, 0.0, 0.0, 1.0]
        ]);

        return *self * mat;
    }
    
    pub fn rotate_y(&self, angle: &f32) -> Matrix4 {
        // rotate
        let mat = Matrix4::new([
            [angle.cos(), 0.0, angle.sin(), 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [-angle.sin(), 0.0, angle.cos(), 0.0],
            [0.0, 0.0, 0.0, 1.0]
        ]);

        return *self * mat;

    }

    pub fn rotate_z(&self, angle: &f32) -> Matrix4 {
        // rotate
        let mat = Matrix4::new([
            [angle.cos(), -angle.sin(), 0.0, 0.0],
            [angle.sin(), angle.cos(), 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0]
        ]);

        return *self * mat;
    }

    pub fn scale(&self, v: &Vector3) -> Matrix4 {
        let mat = Matrix4::new([
            [v.x(), 0.0, 0.0, 0.0],
            [0.0, v.y(), 0.0, 0.0],
            [0.0, 0.0, v.z(), 0.0],
            [0.0, 0.0, 0.0, 1.0]
        ]);

        return *self * mat;
    }

    pub fn calc_perspective(fov: &f32, aspect: &f32, z_near: &f32, z_far: &f32) -> Matrix4 {
        let tan2fov = (fov / 2.0).tan();

        let mat = Matrix4::new([
            [1.0 / (aspect * tan2fov), 0.0, 0.0, 0.0],
            [0.0, 1.0 / tan2fov, 0.0, 0.0],
            [0.0, 0.0, -((z_far + z_near) / (z_far - z_near)), -1.0],
            [0.0, 0.0, -((2.0 * z_far * z_near) / (z_far - z_near)), 0.0]
        ]);

        return mat;
    }

    pub fn calc_look_at(eye: &Vector3, at: &Vector3, up: &Vector3) -> Matrix4 {
        // calc vectors
        let z_axis = (*eye - *at).normalize();
        let x_axis = up.cross(&z_axis).normalize();
        let y_axis = z_axis.cross(&x_axis);

        let mat = Matrix4::new([
            [x_axis.x(), y_axis.x(), z_axis.x(), 0.0],
            [x_axis.y(), y_axis.y(), z_axis.y(), 0.0],
            [x_axis.z(), y_axis.z(), z_axis.z(), 0.0],
            [-x_axis.dot(&eye), -y_axis.dot(&eye), -z_axis.dot(&eye), 1.0]
        ]);

        return mat;
    }
}

impl std::ops::Mul for Matrix4 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        let mut mat = Matrix4::new([[0.0; 4]; 4]);

        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    mat.m[i][j] += self.m.concat()[i + 4 * k] * rhs.m.concat()[k + 4 * j]; 
                }
            }
        }

        Self {
            m: mat.m
        }
    } 
}