1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::marker::PhantomData;
use std::ops::{Add, Div, Mul, Neg, Sub};

use num_traits::{Float, FromPrimitive};
use type_name;

use specs::{Join, Read, ReadStorage, System, WriteStorage};
use specs_transform::Transform2D;

use super::super::ScreenSize;
use super::Camera2D;

pub struct Camera2DSystem<T> {
    screen_size: Option<ScreenSize>,
    _marker: PhantomData<T>,
}

impl<T> Camera2DSystem<T> {
    #[inline]
    pub fn name() -> &'static str {
        type_name::get::<Self>()
    }
}

impl<T> Camera2DSystem<T> {
    #[inline(always)]
    pub fn new() -> Self {
        Camera2DSystem {
            screen_size: None,
            _marker: PhantomData,
        }
    }
}

impl<T> Default for Camera2DSystem<T> {
    #[inline(always)]
    fn default() -> Self {
        Camera2DSystem::new()
    }
}

impl<'system, T> System<'system> for Camera2DSystem<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>>,
        WriteStorage<'system, Camera2D<T>>,
    );

    fn run(&mut self, (size, transforms_2d, mut cameras_2d): Self::SystemData) {
        let screen_size_changed = if self.screen_size.is_some() {
            if &*size != self.screen_size.as_ref().unwrap() {
                self.screen_size = Some(*size);
                true
            } else {
                false
            }
        } else {
            self.screen_size = Some(*size);
            true
        };

        for camera_2d in (&mut cameras_2d).join() {
            let is_dirty = camera_2d.is_dirty();

            if screen_size_changed || is_dirty {
                camera_2d.update_projection(size.0, size.1);
            }
            if is_dirty {
                camera_2d.flag(false);
            }
        }

        for (transform_2d, camera_2d) in (&transforms_2d, &mut cameras_2d).join() {
            camera_2d.update_view(&transform_2d.0);
        }
    }
}

#[test]
fn test_camera_system_name() {
    assert_eq!(
        Camera2DSystem::<f32>::name(),
        "camera_2d::camera_2d_system::Camera2DSystem<f32>"
    );

    struct Example;
    assert_eq!(
        Camera2DSystem::<Example>::name(),
        "camera_2d::camera_2d_system::Camera2DSystem<camera_2d::camera_2d_system::test_camera_system_name::Example>"
    );
}