moho 0.0.9

Barebones Rust Game Library
use super::Renderer;
use super::{Texture, Drawable, Scene};
use errors::*;

use glm;

use std::rc::Rc;

#[derive(Clone)]
pub struct TileSheet<T> {
    texture: Rc<T>,
    tiles: glm::UVec2,
    pub dimensions: glm::UVec2,
}

pub struct Tile<T> {
    pub texture: Rc<T>,
    pub src: glm::UVec4,
}

impl<T: Texture> TileSheet<T> {
    pub fn new(tiles: glm::UVec2, texture: Rc<T>) -> Self {
        let dimensions = texture.dims() / tiles;
        TileSheet {
            texture: texture,
            dimensions: dimensions,
            tiles: tiles,
        }
    }
}

impl<T> TileSheet<T> {
    pub fn tile(&self, index: u32) -> Tile<T> {
        let tile_pos = glm::uvec2(index % self.tiles.x, index / self.tiles.x);
        let position = tile_pos * self.dimensions;
        let src = glm::uvec4(position.x, position.y, self.dimensions.x, self.dimensions.y);

        Tile {
            texture: self.texture.clone(),
            src: src,
        }
    }
}

impl<T, R: Renderer<Texture = T>> Scene<R> for Tile<T> {
    fn show(&self, renderer: &mut R) -> Result<()> {
        renderer.copy(&*self.texture, None, Some(&self.src))
    }
}

impl<T, R: Renderer<Texture = T>> Drawable<R> for Tile<T> {
    fn draw(&self, dst_rect: &glm::IVec4, renderer: &mut R) -> Result<()> {
        renderer.copy(&*self.texture, Some(dst_rect), Some(&self.src))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn single_frame() {
        let texture = MockTexture { dims: glm::uvec2(10, 10) };
        let rc_texture = Rc::new(texture);
        let sheet = TileSheet::new(glm::uvec2(1, 1), rc_texture.clone());
        let tile = sheet.tile(0);
        assert_eq!(tile.texture, rc_texture);
        assert_eq!(tile.src, glm::uvec4(0, 0, 10, 10));
    }

    #[test]
    fn single_row() {
        let texture = MockTexture { dims: glm::uvec2(10, 10) };
        let rc_texture = Rc::new(texture);
        let sheet = TileSheet::new(glm::uvec2(10, 1), rc_texture.clone());
        let tile = sheet.tile(4);
        assert_eq!(tile.texture, rc_texture);
        assert_eq!(tile.src, glm::uvec4(4, 0, 1, 10));
    }

    #[test]
    fn single_column() {
        let texture = MockTexture { dims: glm::uvec2(10, 10) };
        let rc_texture = Rc::new(texture);
        let sheet = TileSheet::new(glm::uvec2(1, 5), rc_texture.clone());
        let tile = sheet.tile(4);
        assert_eq!(tile.texture, rc_texture);
        assert_eq!(tile.src, glm::uvec4(0, 8, 10, 2));
    }

    #[test]
    fn mult_frames() {
        let texture = MockTexture { dims: glm::uvec2(20, 10) };
        let rc_texture = Rc::new(texture);
        let sheet = TileSheet::new(glm::uvec2(4, 2), rc_texture.clone());
        let tile = sheet.tile(5);
        assert_eq!(tile.texture, rc_texture);
        assert_eq!(tile.src, glm::uvec4(5, 5, 5, 5));
    }

    #[derive(Debug, PartialEq)]
    struct MockTexture {
        dims: glm::UVec2,
    }

    impl Texture for MockTexture {
        fn dims(&self) -> glm::UVec2 {
            self.dims
        }
    }
}