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
100
101
102
103
104
105
106
use std::cmp::Ordering;
use std::marker::PhantomData;

use num_traits::Float;
use specs::{Entities, Entity, Join, System, Write, WriteStorage};
use type_name;

use super::{Sprite, SpriteGuide};

pub struct SpriteSystem<T, I> {
    swap: Vec<Entity>,
    _marker: PhantomData<(T, I)>,
}

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

impl<T, I> SpriteSystem<T, I>
where
    T: 'static + Float + Send + Sync,
    I: 'static + Send + Sync,
{
    #[inline(always)]
    pub fn new() -> Self {
        SpriteSystem {
            swap: Vec::new(),
            _marker: PhantomData,
        }
    }
}

impl<T, I> Default for SpriteSystem<T, I>
where
    T: 'static + Float + Send + Sync,
    I: 'static + Send + Sync,
{
    #[inline(always)]
    fn default() -> Self {
        Self::new()
    }
}

impl<'a, T, I> System<'a> for SpriteSystem<T, I>
where
    T: 'static + Float + Send + Sync,
    I: 'static + Send + Sync,
{
    type SystemData = (
        Entities<'a>,
        Write<'a, SpriteGuide<T>>,
        WriteStorage<'a, Sprite<T, I>>,
    );

    #[inline]
    fn run(&mut self, (entities, mut sprite_guide, sprites): Self::SystemData) {
        let mut needs_sort = false;

        for (entity, sprite) in (&*entities, &sprites).join() {
            if sprite.is_dirty() {
                sprite.flag(false);
                needs_sort = true;
            }
            self.swap.push(entity);
        }

        if needs_sort {
            sprite_guide.swap(&mut self.swap);

            sprite_guide.as_slice_mut().sort_by(|a, b| {
                if let Some(a) = sprites.get(*a) {
                    if let Some(b) = sprites.get(*b) {
                        if a.layer() == b.layer() {
                            a.z().cmp(b.z())
                        } else {
                            a.layer().cmp(b.layer())
                        }
                    } else {
                        Ordering::Equal
                    }
                } else {
                    Ordering::Equal
                }
            });
        }

        self.swap.clear();
    }
}

#[test]
fn test_sprite_system_name() {
    assert_eq!(
        SpriteSystem::<f32, Option<usize>>::name(),
        "sprite_system::SpriteSystem<f32, std::option::Option<usize>>"
    );

    struct Example;
    assert_eq!(
        SpriteSystem::<Example, usize>::name(),
        "sprite_system::SpriteSystem<sprite_system::test_sprite_system_name::Example, usize>"
    );
}