led_rs/
render_helpers.rs

1use crate::Project;
2
3#[derive(Clone, Default, Debug)]
4pub struct Point(pub usize, pub usize);
5
6impl From<(usize, usize)> for Point {
7    fn from(tup: (usize, usize)) -> Self {
8        Point(tup.0, tup.1)
9    }
10}
11
12/// Converts from a grid (x, y) point to a coordinate ID
13pub fn grid_point_to_coord(point: Point, grid_width: usize) -> usize {
14    point.0 + point.1 * grid_width
15}
16
17/// Converts from a coordinate ID to a grid (x, y) point
18pub fn grid_coord_to_point(coord: usize, grid_width: usize) -> Point {
19    let grid_y = coord / grid_width;
20    Point(coord - grid_y * grid_width, coord / grid_width)
21}
22
23/// Converts from an atlast sprite ID to a pixel position in the atlas
24pub fn tile_id_to_atlas_pixel(
25    tile_id: usize,
26    atlas_width: usize,
27    grid_width: usize,
28    padding: usize,
29    spacing: usize,
30) -> Point {
31    let grid_x = tile_id - atlas_width * (tile_id / atlas_width);
32    let grid_y = tile_id / atlas_width;
33
34    Point(
35        padding + grid_x * (grid_width + spacing),
36        padding + grid_y * (grid_width + spacing),
37    )
38}
39
40#[derive(Clone, Debug)]
41pub struct RenderCell {
42    pub is_empty: bool,
43    pub tile_id: usize,
44    pub atlas_pos: Point,
45}
46
47#[derive(Debug)]
48pub struct RenderGrid {
49    pub tiles: Vec<RenderCell>,
50    pub tile_size: Point,
51    pub grid_size: Point,
52}
53
54impl RenderGrid {
55    pub fn new(num_cells: usize, tile_size: Point, grid_size: Point) -> Self {
56        RenderGrid {
57            tiles: vec![
58                RenderCell {
59                    is_empty: true,
60                    tile_id: 0,
61                    atlas_pos: Point::default(),
62                };
63                num_cells
64            ],
65            tile_size,
66            grid_size,
67        }
68    }
69
70    pub fn get_tile(&self, x: usize, y: usize) -> &RenderCell {
71        let coord_id = grid_point_to_coord((x, y).into(), self.grid_size.0);
72        &self.tiles[coord_id]
73    }
74
75    // pub fn iter_tiles(&self) -> std::slice::Iter<'i, std::slice::Iter<'i, &RenderCell>> {
76    pub fn rows(&self) -> std::slice::Chunks<'_, RenderCell> {
77        self.tiles.chunks(self.grid_size.0)
78    }
79}
80
81pub trait ToRenderGrid {
82    /// Creates a render grid with the layers merged down into a single layer.
83    /// Excludes entity layers and intgrid layers but includes autotile and tile layers
84    fn to_merged_render_grid(&self, level: usize) -> Result<RenderGrid, anyhow::Error>;
85
86    // fn to_render_grid(&self, layer: isize) -> Result<Vec<RenderCell>, anyhow::Error>;
87}
88
89impl ToRenderGrid for Project {
90    fn to_merged_render_grid(&self, level: usize) -> Result<RenderGrid, anyhow::Error> {
91        if self.levels.len() < level {
92            panic!("Level not found in the parsed map");
93        }
94
95        let level = &self.levels[level];
96
97        // allocate the render grid
98        let first_layer = &level.layer_instances[0];
99        let cell_count = first_layer.grid_width * first_layer.grid_height;
100        let mut grid = RenderGrid::new(
101            cell_count,
102            Point(16, 16),
103            Point(first_layer.grid_width, first_layer.grid_height),
104        );
105
106        // iterate the layers. Run in reverse as we "draw up" the stack
107        level.layer_instances.iter().rev().for_each(|layer| {
108            layer.auto_tiles.iter().for_each(|rule| {
109                rule.tiles.iter().for_each(|tile| {
110                    grid.tiles[tile.coord_id].is_empty = false;
111                    grid.tiles[tile.coord_id].tile_id = tile.tile_id;
112                    grid.tiles[tile.coord_id].atlas_pos.0 = tile.tile_x;
113                    grid.tiles[tile.coord_id].atlas_pos.1 = tile.tile_y;
114                })
115            });
116
117            layer.grid_tiles.iter().for_each(|tile| {
118                grid.tiles[tile.coord_id].is_empty = false;
119                grid.tiles[tile.coord_id].tile_id = tile.tile_id;
120                grid.tiles[tile.coord_id].atlas_pos.0 = tile.tile_x;
121                grid.tiles[tile.coord_id].atlas_pos.1 = tile.tile_x;
122            })
123        });
124
125        Ok(grid)
126    }
127}