use vecmath::{
Vector3,
Matrix4,
vec3_normalized_sub,
vec3_cross,
vec3_dot,
};
use vecmath::col_mat4_mul as mul;
use vecmath::traits::*;
use quaternion::{Quaternion, rotate_vector};
pub fn model_view_projection<T: Float + Copy>(
model: Matrix4<T>,
view: Matrix4<T>,
projection: Matrix4<T>
) -> Matrix4<T> {
mul(mul(projection, view), model)
}
pub struct Camera<T=f32> {
pub position: Vector3<T>,
pub up: Vector3<T>,
pub right: Vector3<T>,
pub forward: Vector3<T>
}
pub struct CameraPerspective<T=f32> {
pub fov: T,
pub near_clip: T,
pub far_clip: T,
pub aspect_ratio: T,
}
impl<T: Float + Copy> Camera<T> {
pub fn new(position: Vector3<T>) -> Camera<T> {
let _0 = Zero::zero();
let _1 = One::one();
Camera {
position: position,
right: [_1, _0, _0],
up: [_0, _1, _0],
forward: [_0, _0, _1]
}
}
pub fn orthogonal(&self) -> Matrix4<T> {
let p = self.position;
let r = self.right;
let u = self.up;
let f = self.forward;
let _0 = Zero::zero();
[
[r[0], u[0], f[0], _0],
[r[1], u[1], f[1], _0],
[r[2], u[2], f[2], _0],
[-vec3_dot(r, p), -vec3_dot(u, p), -vec3_dot(f, p), One::one()]
]
}
pub fn look_at(&mut self, point: Vector3<T>) {
self.forward = vec3_normalized_sub(self.position, point);
self.update_right();
}
pub fn set_yaw_pitch(&mut self, yaw: T, pitch: T) {
let (y_s, y_c, p_s, p_c) = (yaw.sin(), yaw.cos(), pitch.sin(), pitch.cos());
self.forward = [y_s * p_c, p_s, y_c * p_c];
self.up = [y_s * -p_s, p_c, y_c * -p_s];
self.update_right();
}
pub fn set_rotation(&mut self, rotation: Quaternion<T>)
{
let _0: T = Zero::zero();
let _1: T = One::one();
let forward: Vector3<T> = [_0, _0, _1];
let up: Vector3<T> = [_0, _1, _0];
self.forward = rotate_vector(rotation, forward);
self.up = rotate_vector(rotation, up);
self.update_right();
}
fn update_right(&mut self) {
self.right = vec3_cross(self.up, self.forward);
}
}
impl<T: Float> CameraPerspective<T>
where f64: Cast<T>
{
pub fn projection(&self) -> Matrix4<T> {
let _0: T = Zero::zero();
let _1: T = One::one();
let _2: T = _1 + _1;
let pi: T = Radians::_180();
let _360: T = Cast::cast(360.0f64);
let f = _1 / (self.fov * (pi / _360)).tan();
let (far, near) = (self.far_clip, self.near_clip);
[
[f / self.aspect_ratio, _0, _0, _0],
[_0, f, _0, _0],
[_0, _0, (far + near) / (near - far), -_1],
[_0, _0, (_2 * far * near) / (near - far), _0]
]
}
}