1use crate::canvas::{Canvas, ToIndex};
2use crate::image::SharedImage;
3use crate::utils::{f64_to_u32, parse_hex_string, simplify_string};
4
5pub type ImageTileCoord = u8;
6pub type Tile = (ImageTileCoord, ImageTileCoord);
7
8impl ToIndex for Tile {
9 fn to_index(&self) -> usize {
10 0
11 }
12}
13
14#[derive(Clone)]
15pub enum ImageSource {
16 Index(u32),
17 Image(SharedImage),
18}
19
20pub struct Tilemap {
21 pub(crate) canvas: Canvas<Tile>,
22 pub imgsrc: ImageSource,
23}
24
25pub type SharedTilemap = shared_type!(Tilemap);
26
27impl Tilemap {
28 pub fn new(width: u32, height: u32, imgsrc: ImageSource) -> SharedTilemap {
29 new_shared_type!(Self {
30 canvas: Canvas::new(width, height),
31 imgsrc,
32 })
33 }
34
35 pub const fn width(&self) -> u32 {
36 self.canvas.width()
37 }
38
39 pub const fn height(&self) -> u32 {
40 self.canvas.height()
41 }
42
43 pub fn data_ptr(&mut self) -> *mut Tile {
44 self.canvas.data_ptr()
45 }
46
47 pub fn set(&mut self, x: i32, y: i32, data_str: &[&str]) {
48 let width = simplify_string(data_str[0]).len() as u32 / 4;
49 let height = data_str.len() as u32;
50 let tilemap = Self::new(width, height, self.imgsrc.clone());
51
52 {
53 let mut tilemap = tilemap.lock();
54 for y in 0..height {
55 let src_data = simplify_string(data_str[y as usize]);
56 for x in 0..width {
57 let index = x as usize * 4;
58 let tile = parse_hex_string(&src_data[index..index + 4]).unwrap();
59 tilemap.canvas.write_data(
60 x as usize,
61 y as usize,
62 (
63 ((tile >> 8) & 0xff) as ImageTileCoord,
64 (tile & 0xff) as ImageTileCoord,
65 ),
66 );
67 }
68 }
69 }
70
71 self.blt(
72 x as f64,
73 y as f64,
74 tilemap,
75 0.0,
76 0.0,
77 width as f64,
78 height as f64,
79 None,
80 None,
81 None,
82 );
83 }
84
85 pub fn load(&mut self, x: i32, y: i32, filename: &str, layer_index: u32) {
86 let tilemap = Self::from_tmx(filename, layer_index);
87 let tilemap_width = tilemap.lock().width();
88 let tilemap_height = tilemap.lock().height();
89
90 self.blt(
91 x as f64,
92 y as f64,
93 tilemap,
94 0.0,
95 0.0,
96 tilemap_width as f64,
97 tilemap_height as f64,
98 None,
99 None,
100 None,
101 );
102 }
103
104 pub fn clip(&mut self, x: f64, y: f64, width: f64, height: f64) {
105 self.canvas.clip(x, y, width, height);
106 }
107
108 pub fn clip0(&mut self) {
109 self.canvas.clip0();
110 }
111
112 pub fn camera(&mut self, x: f64, y: f64) {
113 self.canvas.camera(x, y);
114 }
115
116 pub fn camera0(&mut self) {
117 self.canvas.camera0();
118 }
119
120 pub fn cls(&mut self, tile: Tile) {
121 self.canvas.cls(tile);
122 }
123
124 pub fn pget(&mut self, x: f64, y: f64) -> Tile {
125 self.canvas.pget(x, y)
126 }
127
128 pub fn pset(&mut self, x: f64, y: f64, tile: Tile) {
129 self.canvas.pset(x, y, tile);
130 }
131
132 pub fn line(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, tile: Tile) {
133 self.canvas.line(x1, y1, x2, y2, tile);
134 }
135
136 pub fn rect(&mut self, x: f64, y: f64, width: f64, height: f64, tile: Tile) {
137 self.canvas.rect(x, y, width, height, tile);
138 }
139
140 pub fn rectb(&mut self, x: f64, y: f64, width: f64, height: f64, tile: Tile) {
141 self.canvas.rectb(x, y, width, height, tile);
142 }
143
144 pub fn circ(&mut self, x: f64, y: f64, radius: f64, tile: Tile) {
145 self.canvas.circ(x, y, radius, tile);
146 }
147
148 pub fn circb(&mut self, x: f64, y: f64, radius: f64, tile: Tile) {
149 self.canvas.circb(x, y, radius, tile);
150 }
151
152 pub fn elli(&mut self, x: f64, y: f64, width: f64, height: f64, tile: Tile) {
153 self.canvas.elli(x, y, width, height, tile);
154 }
155
156 pub fn ellib(&mut self, x: f64, y: f64, width: f64, height: f64, tile: Tile) {
157 self.canvas.ellib(x, y, width, height, tile);
158 }
159
160 pub fn tri(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, tile: Tile) {
161 self.canvas.tri(x1, y1, x2, y2, x3, y3, tile);
162 }
163
164 pub fn trib(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, tile: Tile) {
165 self.canvas.trib(x1, y1, x2, y2, x3, y3, tile);
166 }
167
168 pub fn fill(&mut self, x: f64, y: f64, tile: Tile) {
169 self.canvas.fill(x, y, tile);
170 }
171
172 pub fn blt(
173 &mut self,
174 x: f64,
175 y: f64,
176 tilemap: SharedTilemap,
177 tilemap_x: f64,
178 tilemap_y: f64,
179 width: f64,
180 height: f64,
181 transparent: Option<Tile>,
182 rotate: Option<f64>,
183 scale: Option<f64>,
184 ) {
185 let rotate = rotate.unwrap_or(0.0);
186 let scale = scale.unwrap_or(1.0);
187
188 if rotate != 0.0 || scale != 1.0 {
189 self.blt_transform(
190 x,
191 y,
192 tilemap,
193 tilemap_x,
194 tilemap_y,
195 width,
196 height,
197 transparent,
198 rotate,
199 scale,
200 );
201 return;
202 }
203
204 if let Some(tilemap) = tilemap.try_lock() {
205 self.canvas.blt(
206 x,
207 y,
208 &tilemap.canvas,
209 tilemap_x,
210 tilemap_y,
211 width,
212 height,
213 transparent,
214 None,
215 );
216 } else {
217 let copy_width = f64_to_u32(width.abs());
218 let copy_height = f64_to_u32(height.abs());
219 let mut canvas = Canvas::new(copy_width, copy_height);
220
221 canvas.blt(
222 0.0,
223 0.0,
224 &self.canvas,
225 tilemap_x,
226 tilemap_y,
227 copy_width as f64,
228 copy_height as f64,
229 None,
230 None,
231 );
232
233 self.canvas
234 .blt(x, y, &canvas, 0.0, 0.0, width, height, transparent, None);
235 }
236 }
237
238 fn blt_transform(
239 &mut self,
240 x: f64,
241 y: f64,
242 tilemap: SharedTilemap,
243 tilemap_x: f64,
244 tilemap_y: f64,
245 width: f64,
246 height: f64,
247 transparent: Option<Tile>,
248 rotate: f64,
249 scale: f64,
250 ) {
251 if let Some(tilemap) = tilemap.try_lock() {
252 self.canvas.blt_transform(
253 x,
254 y,
255 &tilemap.canvas,
256 tilemap_x,
257 tilemap_y,
258 width,
259 height,
260 transparent,
261 None,
262 rotate,
263 scale,
264 false,
265 );
266 } else {
267 let copy_width = f64_to_u32(width.abs());
268 let copy_height = f64_to_u32(height.abs());
269 let mut canvas = Canvas::new(copy_width, copy_height);
270
271 canvas.blt(
272 0.0,
273 0.0,
274 &self.canvas,
275 tilemap_x,
276 tilemap_y,
277 copy_width as f64,
278 copy_height as f64,
279 None,
280 None,
281 );
282
283 self.canvas.blt_transform(
284 x,
285 y,
286 &canvas,
287 0.0,
288 0.0,
289 width,
290 height,
291 transparent,
292 None,
293 rotate,
294 scale,
295 false,
296 );
297 }
298 }
299}