1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use super::*;

mod extra;
mod ops;
mod projection;
mod transform;

/// 4x4 matrix
#[repr(C)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct Mat4<T>([[T; 4]; 4]);

impl<T> Mat4<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> Mat4<U> {
        fn map_arr<T, U, F: Fn(T) -> U>(arr: [T; 4], f: F) -> [U; 4] {
            let [a, b, c, d] = arr;
            [f(a), f(b), f(c), f(d)]
        }
        Mat4(map_arr(self.0, |row| map_arr(row, &f)))
    }
}

impl<T: Copy> Mat4<T> {
    /// Construct a matrix.
    ///
    /// # Examples
    /// ```
    /// use batbox::*;
    /// let matrix = Mat4::new([
    ///     [1, 2, 3, 4],
    ///     [3, 4, 5, 6],
    ///     [5, 6, 7, 8],
    ///     [0, 5, 2, 9],
    /// ]);
    /// ```
    pub fn new(values: [[T; 4]; 4]) -> Self {
        Self { 0: values }.transpose()
    }

    pub fn row(&self, row_index: usize) -> Vec4<T> {
        vec4(
            self[(row_index, 0)],
            self[(row_index, 1)],
            self[(row_index, 2)],
            self[(row_index, 3)],
        )
    }
}

impl<T> Index<(usize, usize)> for Mat4<T> {
    type Output = T;
    fn index(&self, (row, col): (usize, usize)) -> &T {
        &self.0[col][row]
    }
}

impl<T> IndexMut<(usize, usize)> for Mat4<T> {
    fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
        &mut self.0[col][row]
    }
}

impl<T> Mat4<T> {
    pub fn as_flat_array(&self) -> &[T; 16] {
        unsafe { mem::transmute(self) }
    }
    pub fn as_flat_array_mut(&mut self) -> &mut [T; 16] {
        unsafe { mem::transmute(self) }
    }
}

impl<T: Num + Copy> Mat4<T> {
    /// Construct zero matrix.
    ///
    /// # Examples
    /// ```
    /// use batbox::*;
    /// let matrix = Mat4::<i32>::zero();
    /// for i in 0..4 {
    ///     for j in 0..4 {
    ///         assert_eq!(matrix[(i, j)], 0);
    ///     }
    /// }
    /// ```
    pub fn zero() -> Self {
        Mat4([[T::ZERO; 4]; 4])
    }

    /// Construct identity matrix.
    ///
    /// # Examples
    /// ```
    /// use batbox::*;
    /// let matrix = Mat4::<i32>::identity();
    /// for i in 0..4 {
    ///     for j in 0..4 {
    ///         assert_eq!(matrix[(i, j)], if i == j { 1 } else { 0 });
    ///     }
    /// }
    /// ```
    pub fn identity() -> Self {
        let mut result = Self::zero();
        for i in 0..4 {
            result[(i, i)] = T::ONE;
        }
        result
    }
}

impl<T: Float> ApproxEq for Mat4<T> {
    fn approx_distance_to(&self, other: &Self) -> f32 {
        let mut dist = 0.0;
        for i in 0..4 {
            for j in 0..4 {
                dist = partial_max(dist, (other[(i, j)] - self[(i, j)]).abs().as_f32());
            }
        }
        dist
    }
}