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}