spitfire_draw/
pixels.rs

1use crate::{
2    sprite::SpriteTexture,
3    utils::{TextureRef, Vertex},
4};
5use spitfire_glow::{
6    graphics::{Graphics, Texture},
7    renderer::{GlowTextureFiltering, GlowTextureFormat},
8};
9use std::{
10    borrow::Cow,
11    ops::{Deref, DerefMut, Index, IndexMut},
12};
13use vek::{Clamp, Rgba};
14
15pub struct Pixels {
16    texture: Texture,
17    buffer: Vec<u8>,
18}
19
20impl Pixels {
21    pub fn simple(width: u32, height: u32, graphics: &Graphics<Vertex>) -> Result<Self, String> {
22        Ok(Self {
23            texture: graphics.texture(width, height, 1, GlowTextureFormat::Rgba, None)?,
24            buffer: vec![0; (width * height * 4) as usize],
25        })
26    }
27
28    pub fn from_screen(graphics: &Graphics<Vertex>) -> Result<Self, String> {
29        let width = graphics.state.main_camera.screen_size.x as u32;
30        let height = graphics.state.main_camera.screen_size.y as u32;
31        Ok(Self {
32            texture: graphics.texture(width, height, 1, GlowTextureFormat::Rgba, None)?,
33            buffer: vec![0; (width * height * 4) as usize],
34        })
35    }
36
37    pub fn texture(&self) -> &Texture {
38        &self.texture
39    }
40
41    pub fn sprite_texture(
42        &self,
43        sampler: Cow<'static, str>,
44        filtering: GlowTextureFiltering,
45    ) -> SpriteTexture {
46        SpriteTexture {
47            sampler,
48            texture: TextureRef::object(self.texture.clone()),
49            filtering,
50        }
51    }
52
53    pub fn width(&self) -> usize {
54        self.texture.width() as usize
55    }
56
57    pub fn height(&self) -> usize {
58        self.texture.height() as usize
59    }
60
61    pub fn access_bytes(&'_ mut self) -> PixelsAccessBytes<'_> {
62        PixelsAccessBytes {
63            width: self.width(),
64            height: self.height(),
65            stride: 4,
66            buffer: &mut self.buffer,
67        }
68    }
69
70    pub fn access_channels<'a>(&'a mut self) -> PixelsAccessChannels<'a> {
71        PixelsAccessChannels {
72            width: self.width(),
73            height: self.height(),
74            buffer: unsafe {
75                std::slice::from_raw_parts_mut(
76                    self.buffer.as_mut_ptr() as *mut [u8; 4],
77                    self.width() * self.height(),
78                )
79            },
80        }
81    }
82
83    pub fn access_rgba<'a>(&'a mut self) -> PixelsAccessRgba<'a> {
84        PixelsAccessRgba {
85            width: self.width(),
86            height: self.height(),
87            buffer: unsafe {
88                std::slice::from_raw_parts_mut(
89                    self.buffer.as_mut_ptr() as *mut Rgba<u8>,
90                    self.width() * self.height(),
91                )
92            },
93        }
94    }
95
96    pub fn commit(&mut self) {
97        self.texture.upload(
98            self.width() as _,
99            self.height() as _,
100            1,
101            GlowTextureFormat::Rgba,
102            Some(&self.buffer),
103        );
104    }
105}
106
107pub struct PixelsAccessBytes<'a> {
108    width: usize,
109    height: usize,
110    stride: usize,
111    buffer: &'a mut [u8],
112}
113
114impl PixelsAccessBytes<'_> {
115    pub fn width(&self) -> usize {
116        self.width
117    }
118
119    pub fn height(&self) -> usize {
120        self.height
121    }
122
123    pub fn stride(&self) -> usize {
124        self.stride
125    }
126}
127
128impl Deref for PixelsAccessBytes<'_> {
129    type Target = [u8];
130
131    fn deref(&self) -> &Self::Target {
132        self.buffer
133    }
134}
135
136impl DerefMut for PixelsAccessBytes<'_> {
137    fn deref_mut(&mut self) -> &mut Self::Target {
138        self.buffer
139    }
140}
141
142impl Index<[usize; 2]> for PixelsAccessBytes<'_> {
143    type Output = u8;
144
145    fn index(&self, index: [usize; 2]) -> &Self::Output {
146        &self.buffer[(index[1] * self.width + index[0]) * self.stride]
147    }
148}
149
150impl IndexMut<[usize; 2]> for PixelsAccessBytes<'_> {
151    fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output {
152        &mut self.buffer[(index[1] * self.width + index[0]) * self.stride]
153    }
154}
155
156pub struct PixelsAccessChannels<'a> {
157    width: usize,
158    height: usize,
159    buffer: &'a mut [[u8; 4]],
160}
161
162impl PixelsAccessChannels<'_> {
163    pub fn width(&self) -> usize {
164        self.width
165    }
166
167    pub fn height(&self) -> usize {
168        self.height
169    }
170}
171
172impl Deref for PixelsAccessChannels<'_> {
173    type Target = [[u8; 4]];
174
175    fn deref(&self) -> &Self::Target {
176        self.buffer
177    }
178}
179
180impl DerefMut for PixelsAccessChannels<'_> {
181    fn deref_mut(&mut self) -> &mut Self::Target {
182        self.buffer
183    }
184}
185
186impl Index<[usize; 2]> for PixelsAccessChannels<'_> {
187    type Output = [u8; 4];
188
189    fn index(&self, index: [usize; 2]) -> &Self::Output {
190        &self.buffer[index[1] * self.width() + index[0]]
191    }
192}
193
194impl IndexMut<[usize; 2]> for PixelsAccessChannels<'_> {
195    fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output {
196        &mut self.buffer[index[1] * self.width() + index[0]]
197    }
198}
199
200pub struct PixelsAccessRgba<'a> {
201    width: usize,
202    height: usize,
203    buffer: &'a mut [Rgba<u8>],
204}
205
206impl<'a> PixelsAccessRgba<'a> {
207    pub fn width(&self) -> usize {
208        self.width
209    }
210
211    pub fn height(&self) -> usize {
212        self.height
213    }
214
215    pub fn blend<F: Fn(Rgba<f32>, Rgba<f32>) -> Rgba<f32>>(
216        self,
217        blend: F,
218    ) -> PixelsAccessRgbaBlend<'a, F> {
219        PixelsAccessRgbaBlend {
220            access: self,
221            blend,
222        }
223    }
224}
225
226impl Deref for PixelsAccessRgba<'_> {
227    type Target = [Rgba<u8>];
228
229    fn deref(&self) -> &Self::Target {
230        self.buffer
231    }
232}
233
234impl DerefMut for PixelsAccessRgba<'_> {
235    fn deref_mut(&mut self) -> &mut Self::Target {
236        self.buffer
237    }
238}
239
240impl Index<[usize; 2]> for PixelsAccessRgba<'_> {
241    type Output = Rgba<u8>;
242
243    fn index(&self, index: [usize; 2]) -> &Self::Output {
244        &self.buffer[index[1] * self.width() + index[0]]
245    }
246}
247
248impl IndexMut<[usize; 2]> for PixelsAccessRgba<'_> {
249    fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output {
250        &mut self.buffer[index[1] * self.width() + index[0]]
251    }
252}
253
254pub struct PixelsAccessRgbaBlend<'a, F: Fn(Rgba<f32>, Rgba<f32>) -> Rgba<f32>> {
255    access: PixelsAccessRgba<'a>,
256    blend: F,
257}
258
259impl<'a, F: Fn(Rgba<f32>, Rgba<f32>) -> Rgba<f32>> PixelsAccessRgbaBlend<'a, F> {
260    pub fn into_inner(self) -> PixelsAccessRgba<'a> {
261        self.access
262    }
263
264    pub fn width(&self) -> usize {
265        self.access.width
266    }
267
268    pub fn height(&self) -> usize {
269        self.access.height
270    }
271
272    pub fn get(&self, index: [usize; 2]) -> Rgba<f32> {
273        self.access[index].numcast().unwrap() / 255.0
274    }
275
276    pub fn blend(&mut self, index: [usize; 2], color: Rgba<f32>) {
277        let rgba = &mut self.access[index];
278        let color = (self.blend)(rgba.numcast().unwrap() / 255.0, color)
279            .clamped(Rgba::<f32>::zero(), Rgba::<f32>::one());
280        *rgba = (color * 255.0).numcast().unwrap();
281    }
282}
283
284pub fn blend_overwrite(_: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
285    new
286}
287
288pub fn blend_additive(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
289    old + new
290}
291
292pub fn blend_subtractive(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
293    old - new
294}
295
296pub fn blend_multiply(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
297    old * new
298}
299
300pub fn blend_alpha(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
301    old * (1.0 - new.a) + new * new.a
302}
303
304pub fn blend_screen(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
305    Rgba::new(
306        1.0 - (1.0 - old.r) * (1.0 - new.r),
307        1.0 - (1.0 - old.g) * (1.0 - new.g),
308        1.0 - (1.0 - old.b) * (1.0 - new.b),
309        new.a,
310    )
311}
312
313pub fn blend_overlay(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
314    let r = if old.r < 0.5 {
315        2.0 * old.r * new.r
316    } else {
317        1.0 - 2.0 * (1.0 - old.r) * (1.0 - new.r)
318    };
319    let g = if old.g < 0.5 {
320        2.0 * old.g * new.g
321    } else {
322        1.0 - 2.0 * (1.0 - old.g) * (1.0 - new.g)
323    };
324    let b = if old.b < 0.5 {
325        2.0 * old.b * new.b
326    } else {
327        1.0 - 2.0 * (1.0 - old.b) * (1.0 - new.b)
328    };
329    Rgba::new(r, g, b, new.a)
330}
331
332pub fn blend_darken(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
333    Rgba::new(old.r.min(new.r), old.g.min(new.g), old.b.min(new.b), new.a)
334}
335
336pub fn blend_lighten(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
337    Rgba::new(old.r.max(new.r), old.g.max(new.g), old.b.max(new.b), new.a)
338}
339
340pub fn blend_difference(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
341    Rgba::new(
342        (old.r - new.r).abs(),
343        (old.g - new.g).abs(),
344        (old.b - new.b).abs(),
345        new.a,
346    )
347}
348
349pub fn blend_exclusion(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
350    Rgba::new(
351        old.r + new.r - 2.0 * old.r * new.r,
352        old.g + new.g - 2.0 * old.g * new.g,
353        old.b + new.b - 2.0 * old.b * new.b,
354        new.a,
355    )
356}
357
358pub fn blend_color_dodge(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
359    let r = if new.r == 0.0 {
360        0.0
361    } else {
362        (old.r / (1.0 - new.r)).min(1.0)
363    };
364    let g = if new.g == 0.0 {
365        0.0
366    } else {
367        (old.g / (1.0 - new.g)).min(1.0)
368    };
369    let b = if new.b == 0.0 {
370        0.0
371    } else {
372        (old.b / (1.0 - new.b)).min(1.0)
373    };
374    Rgba::new(r, g, b, new.a)
375}
376
377pub fn blend_color_burn(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
378    let r = if new.r == 1.0 {
379        1.0
380    } else {
381        (1.0 - (1.0 - old.r) / new.r).max(0.0)
382    };
383    let g = if new.g == 1.0 {
384        1.0
385    } else {
386        (1.0 - (1.0 - old.g) / new.g).max(0.0)
387    };
388    let b = if new.b == 1.0 {
389        1.0
390    } else {
391        (1.0 - (1.0 - old.b) / new.b).max(0.0)
392    };
393    Rgba::new(r, g, b, new.a)
394}
395
396pub fn blend_hard_light(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
397    let r = if new.r < 0.5 {
398        2.0 * old.r * new.r
399    } else {
400        1.0 - 2.0 * (1.0 - old.r) * (1.0 - new.r)
401    };
402    let g = if new.g < 0.5 {
403        2.0 * old.g * new.g
404    } else {
405        1.0 - 2.0 * (1.0 - old.g) * (1.0 - new.g)
406    };
407    let b = if new.b < 0.5 {
408        2.0 * old.b * new.b
409    } else {
410        1.0 - 2.0 * (1.0 - old.b) * (1.0 - new.b)
411    };
412    Rgba::new(r, g, b, new.a)
413}
414
415pub fn blend_soft_light(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
416    let r = old.r + (new.r * (1.0 - old.r));
417    let g = old.g + (new.g * (1.0 - old.g));
418    let b = old.b + (new.b * (1.0 - old.b));
419    Rgba::new(r, g, b, new.a)
420}
421
422pub fn blend_linear_dodge(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
423    Rgba::new(
424        (old.r + new.r).min(1.0),
425        (old.g + new.g).min(1.0),
426        (old.b + new.b).min(1.0),
427        new.a,
428    )
429}
430
431pub fn blend_linear_burn(old: Rgba<f32>, new: Rgba<f32>) -> Rgba<f32> {
432    Rgba::new(
433        (old.r + new.r - 1.0).max(0.0),
434        (old.g + new.g - 1.0).max(0.0),
435        (old.b + new.b - 1.0).max(0.0),
436        new.a,
437    )
438}