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}