onyx 0.2.0

A simple engine for simple minds
Documentation
use std::ops::*;
use super::Vec3;
use super::real::Real;

pub type Elements<R> = [[R; 4]; 4];

#[derive(Copy, Clone, Debug)]
pub struct Mat4<R: Real = f32> {
    elements: Elements<R>,
}

impl<R: Real> Mat4<R> {
    pub fn zero() -> Self {
        Self::from([[R::zero(); 4]; 4])
    }

    pub fn identity() -> Self {
        let zero = R::zero();
        let one = R::one();
        Self::from([
            [one, zero, zero, zero],
            [zero, one, zero, zero],
            [zero, zero, one, zero],
            [zero, zero, zero, one],
        ])
    }
    
    pub fn ortho(left: R, right: R, top: R, bottom: R, near: R, far: R) -> Self {
        let zero = R::zero();
        let one = R::one();
        let two = R::two();
        Self::from([
            [two / (right - left), zero, zero, zero],
            [zero, two / (top - bottom), zero, zero],
            [zero, zero, two / (near - far), zero],
            [(left + right) / (left - right), (bottom + top) / (bottom - top), (near + far) / (near - far), one],
        ])
    }

    pub fn model(position: Vec3<R>, scale: Vec3<R>) -> Self {
        Self::translation(position) * Self::scale(scale)
    }

    pub fn translation(position: Vec3<R>) -> Self {
        let zero = R::zero();
        let one = R::one();
        Self::from([
            [one, zero, zero, zero],
            [zero, one, zero, zero],
            [zero, zero, one, zero],
            [position.x, position.y, position.z, one],
        ])
    }

    pub fn scale(scale: Vec3<R>) -> Mat4<R> {
        let zero = R::zero();
        let one = R::one();
        Self::from([
            [scale.x, zero, zero, zero],
            [zero, scale.y, zero, zero],
            [zero, zero, scale.z, zero],
            [zero, zero, zero, one],
        ])
    }

    pub fn elements(&self) -> Elements<R> {
        self.elements
    }
}

impl<R: Real> Index<(usize, usize)> for Mat4<R> {
    type Output = R;

    fn index(&self, index: (usize, usize)) -> &Self::Output {
        &self.elements[index.1][index.0]
    }
}

impl<R: Real> IndexMut<(usize, usize)> for Mat4<R> {
    fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
        &mut self.elements[index.1][index.0]
    }
}

impl<R: Real> Add<Self> for Mat4<R> {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        let mut result = Self::zero();
        for i in 0 .. 4 {
            for j in 0 .. 4 {
                result[(i, j)] = self[(i, j)] + other[(i, j)];
            }
        }
        return result
    }
}

impl<R: Real> AddAssign<Self> for Mat4<R> {
    fn add_assign(&mut self, other: Self) {
        for i in 0 .. 4 {
            for j in 0 .. 4 {
                self[(i, j)] += other[(i, j)];
            }
        }       
    }
}

impl<R: Real> Sub<Self> for Mat4<R> {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        let mut result = Self::zero();
        for i in 0 .. 4 {
            for j in 0 .. 4 {
                result[(i, j)] = self[(i, j)] - other[(i, j)];
            }
        }
        return result
    }
}

impl<R: Real> SubAssign<Self> for Mat4<R> {
    fn sub_assign(&mut self, other: Self) {
        for i in 0 .. 4 {
            for j in 0 .. 4 {
                self[(i, j)] -= other[(i, j)];
            }
        }       
    }
}

impl<R: Real> Mul<Self> for Mat4<R> {
    type Output = Self;

    fn mul(self, right: Self) -> Self {
        let mut result = Self::zero();
        for i in 0 .. 4 {
            for j in 0 .. 4 {
                for k in 0 .. 4 {
                    result[(i, j)] += self[(i, k)] * right[(k, j)];
                }
            }
        }
        result
    }
}

impl<R: Real> From<Elements<R>> for Mat4<R> {
    fn from(elements: Elements<R>) -> Self {
        Self { elements }
    }
}