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}