simple_game_utils/tiles/
ici.rs

1use std::collections::HashMap;
2use std::rc::Rc;
3
4use ici_files::prelude::*;
5use serde::{Deserialize, Serialize};
6
7use crate::prelude::*;
8
9#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
10pub struct IciTileset {
11    pub name: String,
12    tile_size: (u8, u8),
13    palette: Vec<Color>,
14    tiles: HashMap<String, Vec<u8>>,
15}
16
17impl IciTileset {
18    pub fn new(
19        name: String,
20        tile_size: (u8, u8),
21        palette: Vec<Color>,
22        tiles: HashMap<String, Vec<u8>>,
23    ) -> Self {
24        Self {
25            name,
26            tile_size,
27            palette,
28            tiles,
29        }
30    }
31}
32
33impl IciTileset {
34    pub fn add_image(&mut self, name: &str, image: &IndexedImage) {
35        if image.get_palette() == self.palette {
36            self.tiles
37                .insert(name.to_string(), image.get_pixels().to_vec());
38        } else {
39            panic!("Image has invalid palette");
40        }
41    }
42
43    pub fn tile_size(&self) -> (u8, u8) {
44        self.tile_size
45    }
46
47    pub fn palette(&self) -> &Vec<Color> {
48        &self.palette
49    }
50
51    pub fn tiles(&self) -> &HashMap<String, Vec<u8>> {
52        &self.tiles
53    }
54}
55
56impl IciTileset {
57    pub fn into_tileset(self) -> Result<Tileset<IndexedImage>, String> {
58        let mut images = vec![];
59        let mut names = vec![];
60
61        let palette = self.palette;
62
63        for (name, pixels) in self.tiles {
64            names.push(name);
65            images.push(Rc::new(
66                IndexedImage::new(self.tile_size.0, self.tile_size.1, palette.clone(), pixels)
67                    .map_err(|e| e.to_string())?,
68            ));
69        }
70
71        Ok(Tileset::new(
72            images,
73            names,
74            (self.tile_size.0 as u32, self.tile_size.1 as u32),
75        ))
76    }
77}
78
79#[cfg(test)]
80mod test {
81    use super::*;
82
83    const SAMPLE_RON: &str = r#"(
84        name: "sample",
85        tile_size: (3,3),
86        palette: [0,4278190335,16711935,65535],
87        tiles: {
88            "trans": [0,0,0,0,0,0,0,0,0],
89            "red":   [1,1,1,1,1,1,1,1,1],
90            "green": [2,2,2,2,2,2,2,2,2],
91            "blue":  [3,3,3,3,3,3,3,3,3],
92        }
93    )
94    "#;
95
96    #[test]
97    fn serde() {
98        let tileset: IciTileset = ron::from_str(SAMPLE_RON).unwrap();
99        assert_eq!(tileset.name, String::from("sample"));
100        assert_eq!(tileset.palette, vec![TRANSPARENT, RED, GREEN, BLUE]);
101        assert_eq!(tileset.tile_size, (3, 3));
102        assert_eq!(
103            tileset.tiles,
104            HashMap::from([
105                ("trans".to_string(), vec![0; 9]),
106                ("red".to_string(), vec![1; 9]),
107                ("green".to_string(), vec![2; 9]),
108                ("blue".to_string(), vec![3; 9]),
109            ])
110        );
111    }
112
113    #[test]
114    fn converting() {
115        let tileset: Tileset<IndexedImage> = ron::from_str::<IciTileset>(SAMPLE_RON)
116            .unwrap()
117            .into_tileset()
118            .unwrap();
119        assert_eq!(tileset.tilesize(), (3, 3));
120        assert_eq!(tileset.images().len(), 4);
121        assert_eq!(tileset.find_by_name("red").unwrap().get_palette()[3], BLUE);
122        assert_eq!(tileset.find_by_name("blue").unwrap().get_palette()[1], RED);
123        assert!(tileset
124            .find_by_name("trans")
125            .unwrap()
126            .get_pixels()
127            .iter()
128            .all(|&p| p == 0));
129        assert!(tileset
130            .find_by_name("green")
131            .unwrap()
132            .get_pixels()
133            .iter()
134            .all(|&p| p == 2));
135    }
136}