cgl_rs/graphics/tilemap.rs
1//! The Tilemap module provides a way to render tilemaps to the screen.
2
3#![allow(non_camel_case_types)]
4use libc::{c_void, c_int, c_uint, c_float};
5
6
7use crate::graphics::{Texture, CGL_texture};
8
9/// The internal handle used by CGL
10#[repr(C)]
11pub(crate) struct CGL_tilemap {
12 _private: c_void
13}
14
15extern {
16 fn CGL_tilemap_create(tile_count_x: c_uint, tile_count_y: c_uint, tile_size_x: c_uint, tile_size_y: c_uint, ssbo_binding: c_uint) -> *mut CGL_tilemap;
17 fn CGL_tilemap_destroy(tilemap: *mut CGL_tilemap) -> c_void;
18 fn CGL_tilemap_set_auto_upload(tilemap: *mut CGL_tilemap, value: c_int) -> c_void;
19 fn CGL_tilemap_get_auto_upload(tilemap: *mut CGL_tilemap) -> c_int;
20 fn CGL_tilemap_upload(tilemap: *mut CGL_tilemap) -> c_int;
21 fn CGL_tilemap_set_tile_color(tilemap: *mut CGL_tilemap, tile_x: c_uint, tile_y: c_uint, r: c_float, g: c_float, b: c_float) -> c_void;
22 fn CGL_tilemap_set_tile_texture_from_array(tilemap: *mut CGL_tilemap, tile_x: c_uint, tile_y: c_uint, texture_index: c_uint) -> c_void;
23 fn CGL_tilemap_set_tile_texture_from_tileset(tilemap: *mut CGL_tilemap, tile_x: c_uint, tile_y: c_uint, texture_x_min: c_float, texture_y_min: c_float, texture_x_max: c_float, texture_y_max: c_float) -> c_void;
24 fn CGL_tilemap_set_all_tile_color(tilemap: *mut CGL_tilemap, r: c_float, g: c_float, b: c_float) -> c_void;
25 fn CGL_tilemap_set_all_tile_texture_from_array(tilemap: *mut CGL_tilemap, texture_index: c_uint) -> c_void;
26 fn CGL_tilemap_set_all_tile_texture_from_tileset(tilemap: *mut CGL_tilemap, texture_x_min: c_float, texture_y_min: c_float, texture_x_max: c_float, texture_y_max: c_float) -> c_void;
27 fn CGL_tilemap_clear_tile(tilemap: *mut CGL_tilemap, tile_x: c_uint, tile_y: c_uint) -> c_void;
28 fn CGL_tilemap_clear_all_tile(tilemap: *mut CGL_tilemap) -> c_void;
29 fn CGL_tilemap_render(tilemap: *mut CGL_tilemap, scale_x: c_float, scale_y: c_float, offset_x: c_float, offset_y: c_float, texture: *mut CGL_texture) -> c_void;
30 fn CGL_tilemap_reset(tilemap: *mut CGL_tilemap) -> c_void;
31}
32
33/// The Tilemap Object
34#[repr(C)]
35pub struct Tilemap {
36 pub(crate) handle: *mut CGL_tilemap,
37 pub(crate) has_been_destroyed: bool
38}
39
40impl Tilemap {
41
42
43 /// Creates a new Tilemap object with the specified dimensions and SSBO binding.
44 ///
45 /// # Arguments
46 ///
47 /// * `tile_count_x` - The number of tiles in the x direction.
48 /// * `tile_count_y` - The number of tiles in the y direction.
49 /// * `tile_size_x` - The width of each tile in pixels.
50 /// * `tile_size_y` - The height of each tile in pixels.
51 /// * `ssbo_binding` - The SSBO binding index to use for the tilemap.
52 ///
53 /// # Returns
54 ///
55 /// A `Result` containing the new `Tilemap` object if successful, or an error message if creation failed.
56 ///
57 /// # Example
58 ///
59 /// ```
60 /// cgl_rs::init();
61 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
62 /// cgl_rs::graphics::init();
63 /// {
64 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
65 /// // Do stuff with tilemap
66 /// }
67 /// cgl_rs::graphics::shutdown();
68 /// window.destroy();
69 /// cgl_rs::shutdown();
70 /// ```
71 pub fn new(tile_count_x: u32, tile_count_y: u32, tile_size_x: u32, tile_size_y: u32, ssbo_binding: u32) -> Result<Tilemap, &'static str> {
72 let handle = unsafe {
73 CGL_tilemap_create(tile_count_x, tile_count_y, tile_size_x, tile_size_y, ssbo_binding)
74 };
75 if handle.is_null() {
76 Err("Failed to create tilemap")
77 } else {
78 Ok(Tilemap {
79 handle,
80 has_been_destroyed: false
81 })
82 }
83 }
84
85 /// Sets whether the tilemap should automatically upload changes to the GPU.
86 ///
87 /// # Arguments
88 ///
89 /// * `value` - A boolean value indicating whether the tilemap should automatically upload changes to the GPU.
90 ///
91 /// # Example
92 ///
93 /// ```
94 /// cgl_rs::init();
95 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
96 /// cgl_rs::graphics::init();
97 /// {
98 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
99 /// tilemap.set_auto_upload(false);
100 /// // Do stuff with tilemap
101 /// }
102 /// cgl_rs::graphics::shutdown();
103 /// window.destroy();
104 /// cgl_rs::shutdown();
105 /// ```
106 pub fn set_auto_upload(&self, value: bool) {
107 unsafe {
108 CGL_tilemap_set_auto_upload(self.handle, value as c_int);
109 }
110 }
111
112 /// Returns whether the tilemap is set to automatically upload changes to the GPU.
113 ///
114 /// # Returns
115 ///
116 /// A boolean value indicating whether the tilemap is set to automatically upload changes to the GPU.
117 ///
118 /// # Example
119 ///
120 /// ```
121 /// cgl_rs::init();
122 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
123 /// cgl_rs::graphics::init();
124 /// {
125 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
126 /// let auto_upload = tilemap.get_auto_upload();
127 /// // Do stuff with tilemap
128 /// }
129 /// cgl_rs::graphics::shutdown();
130 /// window.destroy();
131 /// cgl_rs::shutdown();
132 /// ```
133 pub fn get_auto_upload(&self) -> bool {
134 unsafe {
135 CGL_tilemap_get_auto_upload(self.handle) != 0
136 }
137 }
138
139 /// Uploads any changes made to the tilemap to the GPU.
140 /// This can be slow, so it is recommended to set auto upload to false
141 /// and manually call this function when needed for large tilemaps.
142 ///
143 /// # Example
144 ///
145 /// ```
146 /// cgl_rs::init();
147 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
148 /// cgl_rs::graphics::init();
149 /// {
150 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
151 /// tilemap.set_auto_upload(false);
152 /// tilemap.set_tile_color(0, 0, 1.0, 0.0, 0.0, 1.0);
153 /// tilemap.upload();
154 /// }
155 /// cgl_rs::graphics::shutdown();
156 /// window.destroy();
157 /// cgl_rs::shutdown();
158 /// ```
159 pub fn upload(&self) {
160 unsafe {
161 CGL_tilemap_upload(self.handle);
162 }
163 }
164
165 /// Sets the color of a specific tile in the tilemap.
166 ///
167 /// # Arguments
168 ///
169 /// * `tile_x` - The x-coordinate of the tile to set the color of.
170 /// * `tile_y` - The y-coordinate of the tile to set the color of.
171 /// * `r` - The red component of the color to set.
172 /// * `g` - The green component of the color to set.
173 /// * `b` - The blue component of the color to set.
174 /// * `_a` - The alpha component of the color to set. This is currently unused.
175 ///
176 /// # Example
177 ///
178 /// ```
179 /// cgl_rs::init();
180 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
181 /// cgl_rs::graphics::init();
182 /// {
183 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
184 /// tilemap.set_tile_color(0, 0, 1.0, 0.0, 0.0, 1.0);
185 /// // Do stuff with tilemap
186 /// }
187 /// cgl_rs::graphics::shutdown();
188 /// window.destroy();
189 /// cgl_rs::shutdown();
190 /// ```
191 pub fn set_tile_color(&self, tile_x: u32, tile_y: u32, r: f32, g: f32, b: f32, _a: f32) {
192 unsafe {
193 CGL_tilemap_set_tile_color(self.handle, tile_x, tile_y, r, g, b);
194 }
195 }
196
197 /// Sets the texture of a specific tile in the tilemap using an array of textures.
198 ///
199 /// # Arguments
200 ///
201 /// * `tile_x` - The x-coordinate of the tile to set the texture of.
202 /// * `tile_y` - The y-coordinate of the tile to set the texture of.
203 /// * `texture_index` - The index of the texture to set.
204 ///
205 /// # Example
206 ///
207 /// ```
208 /// cgl_rs::init();
209 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
210 /// cgl_rs::graphics::init();
211 /// {
212 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
213 /// tilemap.set_tile_texture_from_array(0, 0, 1);
214 /// // Do stuff with tilemap
215 /// }
216 /// cgl_rs::graphics::shutdown();
217 /// window.destroy();
218 /// cgl_rs::shutdown();
219 /// ```
220 pub fn set_tile_texture_from_array(&self, tile_x: u32, tile_y: u32, texture_index: u32) {
221 unsafe {
222 CGL_tilemap_set_tile_texture_from_array(self.handle, tile_x, tile_y, texture_index);
223 }
224 }
225
226 /// Sets the texture of a specific tile in the tilemap using a tileset.
227 ///
228 /// # Arguments
229 ///
230 /// * `tile_x` - The x-coordinate of the tile to set the texture of.
231 /// * `tile_y` - The y-coordinate of the tile to set the texture of.
232 /// * `texture_x_min` - The minimum x-coordinate of the texture in the tileset.
233 /// * `texture_y_min` - The minimum y-coordinate of the texture in the tileset.
234 /// * `texture_x_max` - The maximum x-coordinate of the texture in the tileset.
235 /// * `texture_y_max` - The maximum y-coordinate of the texture in the tileset.
236 ///
237 /// # Example
238 ///
239 /// ```
240 /// cgl_rs::init();
241 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
242 /// cgl_rs::graphics::init();
243 /// {
244 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
245 /// tilemap.set_tile_texture_from_tileset(0, 0, 0.0, 0.0, 1.0, 1.0);
246 /// // Do stuff with tilemap
247 /// }
248 /// cgl_rs::graphics::shutdown();
249 /// window.destroy();
250 /// cgl_rs::shutdown();
251 /// ```
252 pub fn set_tile_texture_from_tileset(&self, tile_x: u32, tile_y: u32, texture_x_min: f32, texture_y_min: f32, texture_x_max: f32, texture_y_max: f32) {
253 unsafe {
254 CGL_tilemap_set_tile_texture_from_tileset(self.handle, tile_x, tile_y, texture_x_min, texture_y_min, texture_x_max, texture_y_max);
255 }
256 }
257
258
259 /// Sets the color of all tiles in the tilemap.
260 ///
261 /// # Arguments
262 ///
263 /// * `r` - The red component of the color.
264 /// * `g` - The green component of the color.
265 /// * `b` - The blue component of the color.
266 /// * `_a` - The alpha component of the color (currently unused).
267 ///
268 /// # Example
269 ///
270 /// ```
271 /// cgl_rs::init();
272 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
273 /// cgl_rs::graphics::init();
274 /// {
275 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
276 /// tilemap.set_all_tile_color(1.0, 0.0, 0.0, 1.0);
277 /// // Do stuff with tilemap
278 /// }
279 /// cgl_rs::graphics::shutdown();
280 /// window.destroy();
281 /// cgl_rs::shutdown();
282 /// ```
283 pub fn set_all_tile_color(&self, r: f32, g: f32, b: f32, _a: f32) {
284 unsafe {
285 CGL_tilemap_set_all_tile_color(self.handle, r, g, b);
286 }
287 }
288
289 /// Sets the texture of all tiles in the tilemap using an array of texture indices.
290 ///
291 /// # Arguments
292 ///
293 /// * `texture_index` - The index of the texture to set for all tiles.
294 ///
295 /// # Example
296 ///
297 /// ```
298 /// cgl_rs::init();
299 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
300 /// cgl_rs::graphics::init();
301 /// {
302 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
303 /// tilemap.set_all_tile_texture_from_array(0);
304 /// // Do stuff with tilemap
305 /// }
306 /// cgl_rs::graphics::shutdown();
307 /// window.destroy();
308 /// cgl_rs::shutdown();
309 /// ```
310 pub fn set_all_tile_texture_from_array(&self, texture_index: u32) {
311 unsafe {
312 CGL_tilemap_set_all_tile_texture_from_array(self.handle, texture_index);
313 }
314 }
315
316 /// Sets the texture of all tiles in the tilemap using a tileset.
317 ///
318 /// # Arguments
319 ///
320 /// * `texture_x_min` - The minimum x-coordinate of the texture in the tileset.
321 /// * `texture_y_min` - The minimum y-coordinate of the texture in the tileset.
322 /// * `texture_x_max` - The maximum x-coordinate of the texture in the tileset.
323 /// * `texture_y_max` - The maximum y-coordinate of the texture in the tileset.
324 ///
325 /// # Example
326 ///
327 /// ```
328 /// cgl_rs::init();
329 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
330 /// cgl_rs::graphics::init();
331 /// {
332 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
333 /// tilemap.set_all_tile_texture_from_tileset(0.0, 0.0, 1.0, 1.0);
334 /// // Do stuff with tilemap
335 /// }
336 /// cgl_rs::graphics::shutdown();
337 /// window.destroy();
338 /// cgl_rs::shutdown();
339 /// ```
340 pub fn set_all_tile_texture_from_tileset(&self, texture_x_min: f32, texture_y_min: f32, texture_x_max: f32, texture_y_max: f32) {
341 unsafe {
342 CGL_tilemap_set_all_tile_texture_from_tileset(self.handle, texture_x_min, texture_y_min, texture_x_max, texture_y_max);
343 }
344 }
345
346 /// Clears the tile at the specified position.
347 ///
348 /// # Arguments
349 ///
350 /// * `tile_x` - The x-coordinate of the tile to clear.
351 /// * `tile_y` - The y-coordinate of the tile to clear.
352 ///
353 /// # Example
354 ///
355 /// ```
356 /// cgl_rs::init();
357 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
358 /// cgl_rs::graphics::init();
359 /// {
360 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
361 /// tilemap.clear_tile(0, 0);
362 /// // Do stuff with tilemap
363 /// }
364 /// cgl_rs::graphics::shutdown();
365 /// window.destroy();
366 /// cgl_rs::shutdown();
367 /// ```
368 pub fn clear_tile(&self, tile_x: u32, tile_y: u32) {
369 unsafe {
370 CGL_tilemap_clear_tile(self.handle, tile_x, tile_y);
371 }
372 }
373
374 /// Clears all tiles in the tilemap.
375 ///
376 /// # Example
377 ///
378 /// ```
379 /// cgl_rs::init();
380 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
381 /// cgl_rs::graphics::init();
382 /// {
383 /// let tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
384 /// tilemap.clear_all_tile();
385 /// // Do stuff with tilemap
386 /// }
387 /// cgl_rs::graphics::shutdown();
388 /// window.destroy();
389 /// cgl_rs::shutdown();
390 /// ```
391 pub fn clear_all_tile(&self) {
392 unsafe {
393 CGL_tilemap_clear_all_tile(self.handle);
394 }
395 }
396
397 /// Renders the tilemap to the screen.
398 ///
399 /// # Arguments
400 ///
401 /// * `scale_x` - The x-axis scale factor.
402 /// * `scale_y` - The y-axis scale factor.
403 /// * `offset_x` - The x-axis offset.
404 /// * `offset_y` - The y-axis offset.
405 /// * `texture` - The texture to use for rendering (optional).
406 ///
407 /// # Example
408 ///
409 /// ```
410 /// cgl_rs::init();
411 /// let mut window = cgl_rs::Window::new("CGL Window", 800, 600).unwrap();
412 /// cgl_rs::graphics::init();
413 /// {
414 /// let mut tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
415 /// let mut texture = cgl_rs::graphics::Texture::dummy().unwrap();
416 /// tilemap.set_all_tile_texture_from_tileset(0.0, 0.0, 1.0, 1.0);
417 /// tilemap.render(1.0, 1.0, 0.0, 0.0, Some(&mut texture));
418 /// }
419 /// cgl_rs::graphics::shutdown();
420 /// window.destroy();
421 /// cgl_rs::shutdown();
422 /// ```
423 pub fn render(&self, scale_x: f32, scale_y: f32, offset_x: f32, offset_y: f32, texture: Option<&mut Texture>) {
424 unsafe {
425 let texture_handle = match texture {
426 Some(texture) => texture.handle,
427 None => std::ptr::null_mut()
428 };
429 CGL_tilemap_render(self.handle, scale_x, scale_y, offset_x, offset_y, texture_handle);
430 }
431 }
432
433 /// Destroys the tilemap object.
434 ///
435 /// # Example
436 ///
437 /// ```
438 /// cgl_rs::init();
439 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
440 /// cgl_rs::graphics::init();
441 /// {
442 /// let mut tilemap = cgl_rs::graphics::Tilemap::new(10, 10, 32, 32, 0).unwrap();
443 /// tilemap.destroy(); // Or, just let the tilemap go out of scope.
444 /// }
445 /// cgl_rs::graphics::shutdown();
446 /// window.destroy();
447 /// cgl_rs::shutdown();
448 /// ```
449 pub fn destroy(&mut self) {
450 if !self.has_been_destroyed {
451 unsafe {
452 CGL_tilemap_destroy(self.handle);
453 }
454 self.has_been_destroyed = true;
455 }
456 }
457
458}
459
460
461impl Drop for Tilemap {
462 fn drop(&mut self) {
463 self.destroy();
464 }
465}
466
467impl Clone for Tilemap {
468 fn clone(&self) -> Self {
469 Tilemap {
470 handle: self.handle.clone(),
471 has_been_destroyed: true
472 }
473 }
474}