use std::marker::PhantomData;
use std::ops::{Add, Div, Mul, Neg, Sub};
use mat32;
use mat4;
use num_traits::{Float, FromPrimitive};
use type_name;
use specs::{Join, Read, ReadStorage, System, WriteStorage};
use specs_transform::{Transform2D, Transform3D};
use super::{Camera2D, Camera3D, ScreenSize};
pub struct CameraSystem<T> {
screen_size: Option<ScreenSize>,
_marker: PhantomData<T>,
}
impl<T> CameraSystem<T> {
#[inline]
pub fn name() -> &'static str {
type_name::get::<Self>()
}
}
impl<T> CameraSystem<T> {
#[inline(always)]
pub fn new() -> Self {
CameraSystem {
screen_size: None,
_marker: PhantomData,
}
}
}
impl<T> Default for CameraSystem<T> {
#[inline(always)]
fn default() -> Self {
CameraSystem::new()
}
}
impl<'system, T> System<'system> for CameraSystem<T>
where
T: 'static + Send + Sync + 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>,
{
type SystemData = (
Read<'system, ScreenSize>,
ReadStorage<'system, Transform2D<T>>,
ReadStorage<'system, Transform3D<T>>,
WriteStorage<'system, Camera2D<T>>,
WriteStorage<'system, Camera3D<T>>,
);
fn run(
&mut self,
(size, transforms_2d, transforms_3d, mut cameras_2d, mut cameras_3d): Self::SystemData,
) {
for camera_2d in (&mut cameras_2d).join() {
if self.screen_size.is_some() {
if &*size != self.screen_size.as_ref().unwrap() {
self.screen_size = Some(*size);
camera_2d.update_projection(size.0, size.1);
}
} else {
self.screen_size = Some(*size);
camera_2d.update_projection(size.0, size.1);
}
}
for camera_3d in (&mut cameras_3d).join() {
if self.screen_size.is_some() {
if &*size != self.screen_size.as_ref().unwrap() {
self.screen_size = Some(*size);
camera_3d.update_projection(size.0, size.1);
}
} else {
self.screen_size = Some(*size);
camera_3d.update_projection(size.0, size.1);
}
}
for (transform_2d, camera_2d) in (&transforms_2d, &mut cameras_2d).join() {
camera_2d.update_view(&transform_2d.0);
}
for (transform_3d, camera_3d) in (&transforms_3d, &mut cameras_3d).join() {
camera_3d.update_view(&transform_3d.0);
}
for (transform_3d, camera_2d) in (&transforms_3d, &mut cameras_2d).join() {
let mut matrix = mat32::new_identity();
mat32::set_mat4(&mut matrix, &transform_3d.0);
camera_2d.update_view(&matrix);
}
for (transform_2d, camera_3d) in (&transforms_2d, &mut cameras_3d).join() {
let mut matrix = mat4::new_identity();
mat4::set_mat32(&mut matrix, &transform_2d.0);
camera_3d.update_view(&matrix);
}
}
}
#[test]
fn test_camera_system_name() {
assert_eq!(
CameraSystem::<f32>::name(),
"camera_system::CameraSystem<f32>"
);
struct Example;
assert_eq!(
CameraSystem::<Example>::name(),
"camera_system::CameraSystem<camera_system::test_camera_system_name::Example>"
);
}