use std::ops::{Add, Div, Mul, Neg, Sub};
use mat32;
use num_traits::{Float, FromPrimitive};
use specs::{Component, VecStorage};
pub struct Camera2D<T> {
ortho_size: T,
projection: [T; 6],
view: [T; 6],
}
impl<T> Component for Camera2D<T>
where
T: 'static + Sync + Send,
{
type Storage = VecStorage<Self>;
}
impl<T> Default for Camera2D<T>
where
T: Float + FromPrimitive,
{
#[inline(always)]
fn default() -> Self {
Camera2D {
ortho_size: T::from_usize(2).unwrap(),
projection: mat32::new_identity(),
view: mat32::new_identity(),
}
}
}
impl<T> Camera2D<T>
where
T: Float + FromPrimitive,
for<'a, 'b> &'a T: Sub<&'b T, Output = T>
+ Add<&'b T, Output = T>
+ Div<&'b T, Output = T>
+ Mul<&'b T, Output = T>
+ Neg<Output = T>,
{
#[inline(always)]
pub fn new() -> Self {
Self::default()
}
#[inline(always)]
pub fn ortho_size(&self) -> T {
self.ortho_size
}
#[inline(always)]
pub fn set_ortho_size(&mut self, ortho_size: T) {
self.ortho_size = ortho_size;
}
#[inline(always)]
pub fn projection(&self) -> &[T; 6] {
&self.projection
}
#[inline(always)]
pub fn view(&self) -> &[T; 6] {
&self.view
}
#[inline]
pub fn update_view(&mut self, matrix: &[T; 6]) {
mat32::inv(&mut self.view, matrix);
}
#[inline]
pub fn update_projection(&mut self, width: usize, height: usize) {
let w = T::from_usize(width).unwrap();
let h = T::from_usize(height).unwrap();
let w_gt_h = &w > &h;
let aspect = if w_gt_h { &w / &h } else { &h / &w };
let ortho_size_aspect = &self.ortho_size * &aspect;
let r = if w_gt_h {
ortho_size_aspect
} else {
self.ortho_size
};
let l = -&r;
let t = if w_gt_h {
self.ortho_size
} else {
ortho_size_aspect
};
let b = -&t;
mat32::orthographic(&mut self.projection, &t, &r, &b, &l);
}
}