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();
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 {
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 {
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 {
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 {
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
}
}
}