use math::vector::Vector3; pub trait RenderCamera { fn get_view_matrix(&self) -> [[f32; 4]; 4]; fn get_perspective_matrix(&self, dimensions: (u32, u32)) -> [[f32; 4]; 4] { let (width, height) = dimensions; let aspect_ratio = height as f32 / width as f32; let fov = 3.141592 / 3.0; let zfar = 1024.0; let znear = 0.1; use num::Float; let f = 1.0 / (fov / 2.0).tan(); [ [f * aspect_ratio , 0.0, 0.0 , 0.0], [ 0.0 , f , 0.0 , 0.0], [ 0.0 , 0.0, (zfar+znear)/(zfar-znear) , 1.0], [ 0.0 , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0], ] } } pub fn look_at_matrix(position: [f32; 3], target: [f32; 3], up: [f32; 3]) -> [[f32; 4]; 4] { let f = { let f = [ target[0] - position[0], target[1] - position[1], target[2] - position[2], ]; let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2]; let len = len.sqrt(); [f[0] / len, f[1] / len, f[2] / len] }; let s = [up[1] * f[2] - up[2] * f[1], up[2] * f[0] - up[0] * f[2], up[0] * f[1] - up[1] * f[0]]; let s_norm = { let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2]; let len = len.sqrt(); [s[0] / len, s[1] / len, s[2] / len] }; let u = [f[1] * s_norm[2] - f[2] * s_norm[1], f[2] * s_norm[0] - f[0] * s_norm[2], f[0] * s_norm[1] - f[1] * s_norm[0]]; let p = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2], -position[0] * u[0] - position[1] * u[1] - position[2] * u[2], -position[0] * f[0] - position[1] * f[1] - position[2] * f[2]]; [ [-s_norm[0], u[0], f[0], 0.0], [-s_norm[1], u[1], f[1], 0.0], [-s_norm[2], u[2], f[2], 0.0], [-p[0], p[1], p[2], 1.0], ] } pub struct Camera { pub position: Vector3, pub target: Vector3, pub up: Vector3, } impl Camera { pub fn new(position: Vector3, target: Vector3, up: Vector3) -> Camera { Camera { position: position, target: target, up: up, } } } impl RenderCamera for Camera { fn get_view_matrix(&self) -> [[f32; 4]; 4] { look_at_matrix(self.position.into(), self.target.into(), self.up.into()) } } pub struct RotatingCamera { distance: f32, theta: f32, } impl RotatingCamera { pub fn new(distance: f32) -> RotatingCamera { RotatingCamera { distance: distance, theta: 0.0, } } pub fn increase_theta(&mut self, dt: f32) { self.theta += dt; } } impl RenderCamera for RotatingCamera { fn get_view_matrix(&self) -> [[f32; 4]; 4] { let position = Vector3::new( self.distance * self.theta.cos(), 0.0, self.distance * self.theta.sin(), ); let target = Vector3::new(0.0, 0.0, 0.0); let up = Vector3::new(0.0, 1.0, 0.0); look_at_matrix(position.into(), target.into(), up.into()) } }