devotee_backend_pixels/
lib.rs1#![deny(missing_docs)]
2
3use std::num::NonZeroU32;
6
7use devotee_backend::winit::dpi::PhysicalPosition;
8use devotee_backend::winit::window::Window;
9use devotee_backend::{Backend, BackendImage, Converter};
10use pixels::wgpu::{Color, TextureFormat};
11use pixels::{Pixels, PixelsBuilder, SurfaceTexture};
12
13pub struct PixelsBackend {
15 pixels: Pixels,
16}
17
18impl Backend for PixelsBackend {
19 fn new(window: &Window, resolution: (u32, u32), _scale: u32) -> Option<Self> {
20 let pixels = {
21 let window_size = window.inner_size();
22 let surface_texture =
23 SurfaceTexture::new(window_size.width, window_size.height, &window);
24 let builder = PixelsBuilder::new(resolution.0, resolution.1, surface_texture)
25 .texture_format(TextureFormat::Rgba8Unorm)
26 .surface_texture_format(TextureFormat::Bgra8Unorm);
27
28 #[cfg(target_arch = "wasm32")]
29 {
30 pollster::block_on(builder.build_async())
31 }
32 #[cfg(not(target_arch = "wasm32"))]
33 {
34 builder.build()
35 }
36 }
37 .ok()?;
38
39 Some(PixelsBackend { pixels })
40 }
41
42 fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Option<()> {
43 self.pixels.resize_surface(width.into(), height.into()).ok()
44 }
45
46 fn draw_image<'a, P: 'a, I>(
47 &mut self,
48 image: &'a dyn BackendImage<'a, P, Iterator = I>,
49 converter: &dyn Converter<Palette = P>,
50 _window: &Window,
51 background: u32,
52 ) -> Option<()>
53 where
54 I: Iterator<Item = &'a P>,
55 {
56 let r = (background & 0x00ff0000) >> 16;
57 let g = (background & 0x0000ff00) >> 8;
58 let b = background & 0x000000ff;
59
60 self.pixels.clear_color(Color {
61 r: r as f64 / 255.0,
62 g: g as f64 / 255.0,
63 b: b as f64 / 255.0,
64 a: 1.0,
65 });
66
67 for (chunk, pixel) in self
68 .pixels
69 .frame_mut()
70 .chunks_exact_mut(4)
71 .zip(image.pixels())
72 {
73 let argb = converter.convert(pixel);
74 let r = ((argb & 0x00ff0000) >> 16) as u8;
75 let g = ((argb & 0x0000ff00) >> 8) as u8;
76 let b = (argb & 0x000000ff) as u8;
77 chunk[0] = r;
78 chunk[1] = g;
79 chunk[2] = b;
80 chunk[3] = 0xff;
81 }
82
83 self.pixels.render().ok()
84 }
85
86 fn window_pos_to_inner(
87 &self,
88 position: PhysicalPosition<f64>,
89 _window: &Window,
90 _resolution: (u32, u32),
91 ) -> Result<(i32, i32), (i32, i32)> {
92 self.pixels
93 .window_pos_to_pixel((position.x as f32, position.y as f32))
94 .map(|(a, b)| (a as i32, b as i32))
95 .map_err(|(a, b)| (a as i32, b as i32))
96 }
97}