use crate::vector::Vec3; #[derive(Debug, Clone)] #[repr(C)] pub struct Matrix { /// Items must be layed out this way for it to work with OpenGL shaders. items: [[Value; ROWS]; COLUMNS], } impl Matrix { pub fn new() -> Self where Value: Default + Copy, { Self { items: [[Value::default(); ROWS]; COLUMNS], } } /// Sets the value at the specified cell. pub fn set_cell(&mut self, row: usize, column: usize, value: Value) { self.items[column][row] = value; } #[must_use] pub fn as_ptr(&self) -> *const Value { self.items[0].as_ptr() } } impl Matrix { /// Creates a new identity matrix. #[must_use] pub fn new_identity() -> Self { let mut index = 0; let items = [(); ROWS_COLS].map(|()| { let mut columns = [0.0; ROWS_COLS]; columns[index] = 1.0; index += 1; columns }); Self { items } } } impl Matrix { pub fn translate(&mut self, translation: &Vec3) { self.set_cell(0, 3, translation.x); self.set_cell(1, 3, translation.y); self.set_cell(2, 3, translation.z); self.set_cell(3, 3, 1.0); } pub fn scale(&mut self, scaling: &Vec3) { self.set_cell(0, 0, scaling.x); self.set_cell(1, 1, scaling.y); self.set_cell(2, 2, scaling.z); self.set_cell(3, 3, 1.0); } pub fn look_at(&mut self, eye: &Vec3, target: &Vec3, up: &Vec3) { let rev_target_direction = (eye - target).normalize(); let camera_right = up.cross(&rev_target_direction).normalize(); let camera_up = rev_target_direction.cross(&camera_right); self.set_cell(0, 0, camera_right.x); self.set_cell(0, 1, camera_right.y); self.set_cell(0, 2, camera_right.z); self.set_cell(1, 0, camera_up.x); self.set_cell(1, 1, camera_up.y); self.set_cell(1, 2, camera_up.z); self.set_cell(2, 0, rev_target_direction.x); self.set_cell(2, 1, rev_target_direction.y); self.set_cell(2, 2, rev_target_direction.z); // The vector is negated since we want the world to be translated in the opposite // direction of where we want the camera to move. let camera_pos = -Vec3 { x: camera_right.dot(eye), y: camera_up.dot(eye), z: rev_target_direction.dot(eye), }; self.set_cell(0, 3, camera_pos.x); self.set_cell(1, 3, camera_pos.y); self.set_cell(2, 3, camera_pos.z); self.set_cell(3, 3, 1.0); } }