cgl_rs/graphics/
bloom.rs

1//! This provices CGL's Bloom post-processing effect (based on Unity's Bloom effect)
2
3#![allow(non_camel_case_types)]
4use libc::{c_void, c_int, c_float};
5
6use crate::graphics::texture::{Texture, CGL_texture};
7
8/// The internal handle used by CGL
9#[repr(C)]
10pub(crate) struct CGL_bloom {
11    _private: c_void
12}
13
14extern {
15    fn CGL_bloom_create(width: c_int, height: c_int, iterations: c_int) -> *mut CGL_bloom;
16    fn CGL_bloom_destroy(bloom: *mut CGL_bloom) -> c_void;
17    fn CGL_bloom_set_threshold(bloom: *mut CGL_bloom, val: c_float) -> c_void;
18    fn CGL_bloom_get_threshold(bloom: *mut CGL_bloom) -> c_float;
19    fn CGL_bloom_set_knee(bloom: *mut CGL_bloom, val: c_float) -> c_void;
20    fn CGL_bloom_get_knee(bloom: *mut CGL_bloom) -> c_float;
21    fn CGL_bloom_set_offset(bloom: *mut CGL_bloom, x: c_float, y: c_float) -> c_void;
22    fn CGL_bloom_apply(bloom: *mut CGL_bloom, tex: *mut CGL_texture) -> c_void;
23    fn CGL_bloom_apply2(bloom: *mut CGL_bloom, tex_src: *mut CGL_texture, tex_dst: *mut CGL_texture) -> c_void;
24    fn CGL_bloom_get_iterations(bloom: *mut CGL_bloom) -> c_int;
25    fn CGL_bloom_get_lod_texture(bloom: *mut CGL_bloom, index: c_int) -> *mut CGL_texture;
26    fn CGL_bloom_get_prefiltered_texture(bloom: *mut CGL_bloom) -> *mut CGL_texture;
27}
28
29/// The Bloom Object
30#[repr(C)]
31pub struct Bloom {
32    pub(crate) handle: *mut CGL_bloom,
33    pub(crate) has_been_destroyed: bool
34}
35
36impl Bloom {
37    /// Creates a new Bloom object with the specified width, height, and number of iterations.
38    /// 
39    /// # Arguments
40    /// 
41    /// * `width` - The width of the Bloom effect.
42    /// * `height` - The height of the Bloom effect.
43    /// * `iterations` - The number of iterations to apply the Bloom effect.
44    /// 
45    /// # Returns
46    /// 
47    /// Returns a new Bloom object if successful, otherwise returns an error message.
48    /// 
49    /// # Example
50    /// 
51    /// ```
52    /// cgl_rs::init();
53    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
54    /// cgl_rs::graphics::init();
55    /// {
56    ///     let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
57    /// }
58    /// cgl_rs::graphics::shutdown();
59    /// window.destroy();
60    /// cgl_rs::shutdown();
61    /// ```
62    pub fn new(width: i32, height: i32, iterations: i32) -> Result<Bloom, &'static str> {
63        unsafe {
64            let handle = CGL_bloom_create(width, height, iterations);
65            if handle.is_null() {
66                Err("Failed to create Bloom")
67            } else {
68                Ok(Bloom {
69                    handle,
70                    has_been_destroyed: false
71                })
72            }
73        }
74    }
75
76    
77
78    /// Destroys the texture and frees its resources. If the texture has already been destroyed, this method does nothing.
79    /// 
80    /// # Example
81    /// 
82    /// ```
83    /// cgl_rs::init();
84    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
85    /// cgl_rs::graphics::init();
86    /// {
87    ///     let mut bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
88    ///     bloom.destroy(); // optional
89    /// }
90    /// cgl_rs::graphics::shutdown();
91    /// window.destroy();
92    /// cgl_rs::shutdown();
93    pub fn destroy(&mut self) {
94        if !self.has_been_destroyed {
95            unsafe {
96                CGL_bloom_destroy(self.handle);
97            }
98            self.has_been_destroyed = true;
99        }
100    }
101
102
103    /// Sets the threshold value for the Bloom effect.
104    /// 
105    /// # Arguments
106    /// 
107    /// * `val` - The threshold value to set.
108    /// 
109    /// # Example
110    /// 
111    /// ```
112    /// cgl_rs::init();
113    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
114    /// cgl_rs::graphics::init();
115    /// {
116    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
117    ///    bloom.set_threshold(0.5);
118    /// }
119    /// cgl_rs::graphics::shutdown();
120    /// window.destroy();
121    /// cgl_rs::shutdown();
122    /// ```
123    pub fn set_threshold(&self, val: f32) {
124        unsafe {
125            CGL_bloom_set_threshold(self.handle, val);
126        }
127    }
128
129    /// Gets the threshold value for the Bloom effect.
130    /// 
131    /// # Returns
132    /// 
133    /// Returns the current threshold value.
134    /// 
135    /// # Example
136    /// 
137    /// ```
138    /// cgl_rs::init();
139    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
140    /// cgl_rs::graphics::init();
141    /// {
142    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
143    ///    let threshold = bloom.get_threshold();
144    /// }
145    /// cgl_rs::graphics::shutdown();
146    /// window.destroy();
147    /// cgl_rs::shutdown();
148    /// ```
149    pub fn get_threshold(&self) -> f32 {
150        unsafe {
151            CGL_bloom_get_threshold(self.handle)
152        }
153    }
154
155    /// Sets the knee value for the Bloom effect.
156    /// 
157    /// # Arguments
158    /// 
159    /// * `val` - The knee value to set.
160    /// 
161    /// # Example
162    /// 
163    /// ```
164    /// cgl_rs::init();
165    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
166    /// cgl_rs::graphics::init();
167    /// {
168    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
169    ///    bloom.set_knee(0.5);
170    /// }
171    /// cgl_rs::graphics::shutdown();
172    /// window.destroy();
173    /// cgl_rs::shutdown();
174    /// ```
175    pub fn set_knee(&self, val: f32) {
176        unsafe {
177            CGL_bloom_set_knee(self.handle, val);
178        }
179    }
180
181    /// Gets the knee value for the Bloom effect.
182    /// 
183    /// # Returns
184    /// 
185    /// Returns the current knee value.
186    /// 
187    /// # Example
188    /// 
189    /// ```
190    /// cgl_rs::init();
191    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
192    /// cgl_rs::graphics::init();
193    /// {
194    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
195    ///    let knee = bloom.get_knee();
196    /// }
197    /// cgl_rs::graphics::shutdown();
198    /// window.destroy();
199    /// cgl_rs::shutdown();
200    /// ```
201    pub fn get_knee(&self) -> f32 {
202        unsafe {
203            CGL_bloom_get_knee(self.handle)
204        }
205    }
206
207    /// Sets the offset values for the Bloom effect.
208    /// 
209    /// # Arguments
210    /// 
211    /// * `x` - The x offset value to set.
212    /// * `y` - The y offset value to set.
213    /// 
214    /// # Example
215    /// 
216    /// ```
217    /// cgl_rs::init();
218    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
219    /// cgl_rs::graphics::init();
220    /// {
221    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
222    ///    bloom.set_offset(0.5, 0.5);
223    /// }
224    /// cgl_rs::graphics::shutdown();
225    /// window.destroy();
226    /// cgl_rs::shutdown();
227    /// ```
228    pub fn set_offset(&self, x: f32, y: f32) {
229        unsafe {
230            CGL_bloom_set_offset(self.handle, x, y);
231        }
232    }
233
234
235    /// Applies the Bloom effect to a texture.
236    /// 
237    /// # Arguments
238    /// 
239    /// * `tex` - The texture to apply the Bloom effect to.
240    /// 
241    /// # Example
242    /// 
243    /// ```
244    /// cgl_rs::init();
245    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
246    /// cgl_rs::graphics::init();
247    /// {
248    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
249    ///    let texture = cgl_rs::graphics::Texture::dummy2(600, 600).unwrap();
250    ///    bloom.apply(&texture);
251    /// }
252    /// cgl_rs::graphics::shutdown();
253    /// window.destroy();
254    /// cgl_rs::shutdown();
255    /// ```
256    pub fn apply(&self, tex: &Texture) {
257        unsafe {
258            CGL_bloom_apply(self.handle, tex.handle);
259        }
260    }
261
262    /// Applies the Bloom effect to a source texture and writes the result to a destination texture.
263    /// 
264    /// # Arguments
265    /// 
266    /// * `tex_src` - The source texture to apply the Bloom effect to.
267    /// * `tex_dst` - The destination texture to write the result to.
268    /// 
269    /// # Example
270    /// 
271    /// ```
272    /// cgl_rs::init();
273    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
274    /// cgl_rs::graphics::init();
275    /// {
276    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
277    ///    let texture_src = cgl_rs::graphics::Texture::dummy2(600, 600).unwrap();
278    ///    let texture_dst = cgl_rs::graphics::Texture::dummy2(600, 600).unwrap();
279    ///    bloom.apply2(&texture_src, &texture_dst);
280    /// }
281    /// cgl_rs::graphics::shutdown();
282    /// window.destroy();
283    /// cgl_rs::shutdown();
284    /// ```
285    pub fn apply2(&self, tex_src: &Texture, tex_dst: &Texture) {
286        unsafe {
287            CGL_bloom_apply2(self.handle, tex_src.handle, tex_dst.handle);
288        }
289    }
290
291    /// Gets the value of the number of iterations for the Bloom effect.
292    /// 
293    /// # Example
294    /// 
295    /// ```
296    /// cgl_rs::init();
297    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
298    /// cgl_rs::graphics::init();
299    /// {
300    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
301    ///    let iterations = bloom.get_iterations();
302    /// }
303    /// cgl_rs::graphics::shutdown();
304    /// window.destroy();
305    /// cgl_rs::shutdown();
306    /// ```
307    pub fn get_iterations(&self) -> i32 {
308        unsafe {
309            CGL_bloom_get_iterations(self.handle)
310        }
311    }
312
313    /// Gets the texture for a specific level of detail (LOD) for the Bloom effect.
314    /// 
315    /// This texture is owned and managed by the Bloom effect and should not be destroyed manually.
316    /// 
317    /// # Arguments
318    /// 
319    /// * `index` - The index of the LOD texture to retrieve.
320    /// 
321    /// # Example
322    /// 
323    /// ```
324    /// cgl_rs::init();
325    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
326    /// cgl_rs::graphics::init();
327    /// {
328    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
329    ///    let lod_texture = bloom.get_lod_texture(0);
330    /// }
331    /// cgl_rs::graphics::shutdown();
332    /// window.destroy();
333    /// cgl_rs::shutdown();
334    /// ```
335    pub fn get_lod_texture(&self, index: i32) -> Result<Texture, &'static str> {
336        unsafe {
337            let handle = CGL_bloom_get_lod_texture(self.handle, index);
338            if handle.is_null() {
339                Err("Failed to get LOD texture")
340            } else {
341                Ok(Texture {
342                    handle,
343                    has_been_destroyed: true
344                })
345            }
346        }
347    }
348
349    /// Gets the prefiltered texture for the Bloom effect.
350    /// 
351    /// This texture is owned and managed by the Bloom effect and should not be destroyed manually.
352    /// 
353    /// # Example
354    /// 
355    /// ```
356    /// cgl_rs::init();
357    /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
358    /// cgl_rs::graphics::init();
359    /// {
360    ///    let bloom = cgl_rs::graphics::Bloom::new(800, 600, 3).unwrap();
361    ///    let prefiltered_texture = bloom.get_prefiltered_texture();
362    /// }
363    /// cgl_rs::graphics::shutdown();
364    /// window.destroy();
365    /// cgl_rs::shutdown();
366    /// ```
367    pub fn get_prefiltered_texture(&self) -> Result<Texture, &'static str> {
368        unsafe {
369            let handle = CGL_bloom_get_prefiltered_texture(self.handle);
370            if handle.is_null() {
371                Err("Failed to get prefiltered texture")
372            } else {
373                Ok(Texture {
374                    handle,
375                    has_been_destroyed: true
376                })
377            }
378        }
379    }
380}
381
382
383impl Drop for Bloom {
384    fn drop(&mut self) {
385        self.destroy();
386    }
387}
388
389impl Clone for Bloom {
390    fn clone(&self) -> Self {
391        Bloom {
392            handle: self.handle.clone(),
393            has_been_destroyed: true
394        }
395    }
396}