specs_camera 0.5.0

camera 2d and 3d component for specs
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::{Entities, Join, ReadStorage, System, WriteStorage};
use specs_transform::{GlobalTransform2D, GlobalTransform3D};

use super::{Camera2D, Camera3D};

pub struct CameraSystem<T>(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(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 = (
        Entities<'system>,
        ReadStorage<'system, GlobalTransform2D<T>>,
        ReadStorage<'system, GlobalTransform3D<T>>,
        WriteStorage<'system, Camera2D<T>>,
        WriteStorage<'system, Camera3D<T>>,
    );

    fn run(
        &mut self,
        (entities, transforms_2d, transforms_3d, mut cameras_2d, mut cameras_3d): Self::SystemData,
    ) {
        for (entity, camera_2d) in (&*entities, &mut cameras_2d).join() {
            camera_2d.update_projection(false);

            if let Some(transform_2d) = transforms_2d.get(entity) {
                camera_2d.update_view(transform_2d.as_ref());
            } else if let Some(transform_3d) = transforms_3d.get(entity) {
                let mut matrix = mat32::new_identity();
                mat32::set_mat4(&mut matrix, transform_3d.as_ref());
                camera_2d.update_view(&matrix);
            }
        }

        for (entity, camera_3d) in (&*entities, &mut cameras_3d).join() {
            camera_3d.update_projection(false);

            if let Some(transform_3d) = transforms_3d.get(entity) {
                camera_3d.update_view(transform_3d.as_ref());
            } else if let Some(transform_2d) = transforms_2d.get(entity) {
                let mut matrix = mat4::new_identity();
                mat4::set_mat32(&mut matrix, transform_2d.as_ref());
                camera_3d.update_view(&matrix);
            }
        }
    }
}