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}