1#![deny(missing_docs)]
2
3use std::sync::Arc;
6use std::time::{Duration, Instant};
7
8use devotee_backend::Middleware;
9use devotee_backend::middling::{EventContext, Fill, Surface};
10use winit::application::ApplicationHandler;
11use winit::dpi::{PhysicalPosition, PhysicalSize};
12use winit::error::{EventLoopError, OsError};
13use winit::event::{DeviceEvent, DeviceId, StartCause, WindowEvent};
14use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
15use winit::window::{Window, WindowAttributes, WindowId};
16
17pub use winit;
18
19pub struct PixelsBackend<'w, M> {
21 middleware: M,
22 internal: Option<Internal<'w>>,
23 settings: Settings,
24 last: Instant,
25}
26
27impl<M> PixelsBackend<'_, M> {
28 pub fn new(middleware: M) -> Self {
30 let internal = None;
31 let last = Instant::now();
32 let settings = Settings {
33 render_window_size: PhysicalSize::new(32, 32),
34 updates_per_second: 60.0,
35 };
36 Self {
37 middleware,
38 internal,
39 settings,
40 last,
41 }
42 }
43}
44
45impl<'w, M> PixelsBackend<'w, M>
46where
47 for<'init, 'context, 'surface, 'event_context, 'event_control> M: Middleware<
48 PixelsInit<'init>,
49 PixelsContext<'context>,
50 PixelsSurface<'surface, 'w>,
51 PixelsEvent,
52 PixelsEventContext<'event_context, 'w>,
53 PixelsEventControl<'event_control>,
54 >,
55{
56 pub fn run(&mut self) -> Result<(), Error> {
58 let event_loop = EventLoop::new()?;
59
60 event_loop.set_control_flow(ControlFlow::WaitUntil(
61 Instant::now() + Duration::from_secs_f32(1.0 / 60.0),
62 ));
63 event_loop.run_app(self)?;
64
65 Ok(())
66 }
67
68 fn init(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Error> {
69 let window = Arc::new(event_loop.create_window(WindowAttributes::default())?);
70
71 let mut init = PixelsInit {
72 window: &window,
73 settings: &mut self.settings,
74 };
75
76 window.set_visible(true);
77 self.middleware.on_init(&mut init);
78 window.set_min_inner_size(Some(self.settings.render_window_size));
79
80 let surface_size = window.inner_size();
81 let surface_texture =
82 pixels::SurfaceTexture::new(surface_size.width, surface_size.height, window.clone());
83
84 let pixels = pixels::PixelsBuilder::new(
85 self.settings.render_window_size.width,
86 self.settings.render_window_size.height,
87 surface_texture,
88 )
89 .build()?;
90
91 let mut internal = Internal {
92 window,
93 pixels,
94 surface_size,
95 };
96 let _ = internal.on_resize(surface_size);
97
98 self.internal = Some(internal);
99
100 Ok(())
101 }
102
103 fn handle_update(&mut self, event_loop: &ActiveEventLoop) {
104 let now = Instant::now();
105 if let Some(internal) = &self.internal {
106 let delta = now - self.last;
107
108 let mut control = PixelsContext {
109 shutdown: false,
110 window: &internal.window,
111 delta,
112 };
113 self.middleware.on_update(&mut control);
114
115 if control.shutdown {
116 event_loop.exit();
117 }
118 }
119 self.last = now;
120 event_loop.set_control_flow(ControlFlow::WaitUntil(
121 now + Duration::from_secs_f32(1.0 / self.settings.updates_per_second),
122 ));
123 }
124
125 fn handle_window_event(
126 settings: &Settings,
127 event_loop: &ActiveEventLoop,
128 middleware: &mut M,
129 internal: &mut Internal<'w>,
130 event: WindowEvent,
131 ) {
132 match event {
133 WindowEvent::Resized(physical_size) => {
134 internal.on_resize(physical_size);
135 }
136 WindowEvent::CloseRequested => {
137 event_loop.exit();
138 }
139 WindowEvent::Destroyed => {
140 event_loop.exit();
141 }
142 WindowEvent::RedrawRequested => {
143 let mut surface = PixelsSurface {
144 pixels: &mut internal.pixels,
145 dimensions: settings.render_window_size,
146 };
147 middleware.on_render(&mut surface);
148 let _ = internal.pixels.render();
149 internal.window.request_redraw();
150 }
151 _ => {}
152 }
153 }
154
155 fn handle_event(
156 settings: &Settings,
157 event_loop: &ActiveEventLoop,
158 middleware: &mut M,
159 internal: &mut Internal<'w>,
160 event: PixelsEvent,
161 ) {
162 if let PixelsEvent::Window(event) = event {
163 Self::handle_window_event(settings, event_loop, middleware, internal, event)
164 }
165 }
166}
167
168impl<'w, M> ApplicationHandler for PixelsBackend<'w, M>
169where
170 for<'init, 'control, 'surface, 'event_context, 'event_control> M: Middleware<
171 PixelsInit<'init>,
172 PixelsContext<'control>,
173 PixelsSurface<'surface, 'w>,
174 PixelsEvent,
175 PixelsEventContext<'event_context, 'w>,
176 PixelsEventControl<'event_control>,
177 >,
178{
179 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
180 if self.internal.is_none() && self.init(event_loop).is_err() {
181 event_loop.exit();
182 }
183 }
184
185 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
186 if let StartCause::ResumeTimeReached { .. } = cause {
187 self.handle_update(event_loop);
188 }
189 }
190
191 fn window_event(
192 &mut self,
193 event_loop: &ActiveEventLoop,
194 _window_id: WindowId,
195 event: WindowEvent,
196 ) {
197 if let Some(internal) = &mut self.internal {
198 let surface = PixelsSurface {
199 pixels: &mut internal.pixels,
200 dimensions: self.settings.render_window_size,
201 };
202 let context = PixelsEventContext { surface };
203 let mut control = PixelsEventControl { event_loop };
204
205 if let Some(event) =
206 self.middleware
207 .on_event(PixelsEvent::Window(event), &context, &mut control)
208 {
209 Self::handle_event(
210 &self.settings,
211 event_loop,
212 &mut self.middleware,
213 internal,
214 event,
215 );
216 }
217 }
218 }
219
220 fn device_event(
221 &mut self,
222 event_loop: &ActiveEventLoop,
223 device_id: DeviceId,
224 event: DeviceEvent,
225 ) {
226 if let Some(internal) = &mut self.internal {
227 let surface = PixelsSurface {
228 pixels: &mut internal.pixels,
229 dimensions: self.settings.render_window_size,
230 };
231 let context = PixelsEventContext { surface };
232 let mut control = PixelsEventControl { event_loop };
233 let _ = self.middleware.on_event(
234 PixelsEvent::Device(device_id, event),
235 &context,
236 &mut control,
237 );
238 }
239 }
240}
241
242struct Settings {
243 render_window_size: PhysicalSize<u32>,
244 updates_per_second: f32,
245}
246
247impl Settings {
248 fn set_updates_per_second(&mut self, updates_per_second: f32) {
252 assert!(
253 updates_per_second > 0.0,
254 "Update rate has to be greater than 0"
255 );
256 self.updates_per_second = updates_per_second;
257 }
258}
259
260struct Internal<'w> {
261 window: Arc<Window>,
262 pixels: pixels::Pixels<'w>,
263 surface_size: PhysicalSize<u32>,
264}
265
266impl Internal<'_> {
267 fn on_resize(&mut self, size: PhysicalSize<u32>) -> Option<()> {
268 self.pixels.resize_surface(size.width, size.height).ok()?;
269
270 self.surface_size = size;
271
272 Some(())
273 }
274}
275
276pub struct PixelsInit<'a> {
278 window: &'a Window,
279 settings: &'a mut Settings,
280}
281
282impl PixelsInit<'_> {
283 pub fn window(&self) -> &Window {
285 self.window
286 }
287
288 pub fn set_render_window_size(&mut self, width: u32, height: u32) {
290 let size = PhysicalSize::new(width, height);
291 self.settings.render_window_size = size;
292 let _ = self.window.request_inner_size(size);
293 }
294
295 pub fn set_updates_per_second(&mut self, updates_per_second: f32) {
301 self.settings.set_updates_per_second(updates_per_second);
302 }
303}
304
305pub struct PixelsContext<'a> {
307 shutdown: bool,
308 window: &'a Window,
309 delta: Duration,
310}
311
312impl PixelsContext<'_> {
313 pub fn window(&self) -> &Window {
315 self.window
316 }
317
318 pub fn shutdown(&mut self) {
320 self.shutdown = true;
321 }
322
323 pub fn delta(&self) -> Duration {
325 self.delta
326 }
327}
328
329pub enum PixelsEvent {
331 Window(WindowEvent),
333 Device(DeviceId, DeviceEvent),
335}
336
337pub struct PixelsEventContext<'s, 'w> {
339 surface: PixelsSurface<'s, 'w>,
340}
341
342impl EventContext<PhysicalPosition<f64>> for PixelsEventContext<'_, '_> {
343 type SurfaceSpace = Option<PhysicalPosition<u32>>;
344
345 fn estimate_surface_space(&self, event_space: PhysicalPosition<f64>) -> Self::SurfaceSpace {
346 let PhysicalPosition { x, y } = event_space;
347 let (x, y) = (x as f32, y as f32);
348 self.surface
349 .pixels
350 .window_pos_to_pixel((x, y))
351 .ok()
352 .map(|(x, y)| PhysicalPosition::new(x as _, y as _))
353 }
354}
355
356pub struct PixelsSurface<'s, 'w> {
358 pixels: &'s mut pixels::Pixels<'w>,
359 dimensions: PhysicalSize<u32>,
360}
361
362impl Surface for PixelsSurface<'_, '_> {
363 type Texel = [u8; 4];
364
365 fn texel(&self, x: u32, y: u32) -> Option<[u8; 4]> {
366 if x >= self.dimensions.width || y >= self.dimensions.height {
367 None
368 } else {
369 let buffer = self.pixels.frame();
370 let offset = (4 * (x + y * self.dimensions.width)) as usize;
371 let slice = &buffer[offset..(offset + 4)];
372 slice.try_into().ok()
373 }
374 }
375
376 fn set_texel(&mut self, x: u32, y: u32, value: [u8; 4]) {
377 if x < self.dimensions.width && y < self.dimensions.height {
378 let buffer = self.pixels.frame_mut();
379 let offset = (4 * (x + y * self.dimensions.width)) as usize;
380 let slice = &mut buffer[offset..(offset + 4)];
381 slice.copy_from_slice(&value);
382 }
383 }
384
385 unsafe fn texel_unchecked(&self, x: u32, y: u32) -> [u8; 4] {
386 let buffer = self.pixels.frame();
387 let offset = (4 * (x + y * self.dimensions.width)) as usize;
388 let slice = &buffer[offset..(offset + 4)];
389 slice.try_into().unwrap()
390 }
391
392 unsafe fn set_texel_unchecked(&mut self, x: u32, y: u32, value: [u8; 4]) {
393 let buffer = self.pixels.frame_mut();
394 let offset = (4 * (x + y * self.dimensions.width)) as usize;
395 let slice = &mut buffer[offset..(offset + 4)];
396 slice.copy_from_slice(&value);
397 }
398
399 fn clear(&mut self, value: Self::Texel) {
400 let frame = self.pixels.frame_mut();
401 for pixel in frame.chunks_exact_mut(4) {
402 pixel.copy_from_slice(&value);
403 }
404 }
405
406 fn width(&self) -> u32 {
407 self.dimensions.width
408 }
409
410 fn height(&self) -> u32 {
411 self.dimensions.height
412 }
413}
414
415impl<I> Fill<I> for PixelsSurface<'_, '_>
416where
417 I: Iterator<Item = Self::Texel>,
418{
419 fn fill_from(&mut self, data: I) {
420 let frame = self.pixels.frame_mut();
421 for (texel, data) in frame.chunks_exact_mut(4).zip(data) {
422 texel.copy_from_slice(&data);
423 }
424 }
425}
426
427pub struct PixelsEventControl<'a> {
429 event_loop: &'a ActiveEventLoop,
430}
431
432impl PixelsEventControl<'_> {
433 pub fn shutdown(&self) {
435 self.event_loop.exit();
436 }
437}
438
439#[derive(Debug)]
441pub enum Error {
442 WinitEventLoopError(EventLoopError),
444 OsError(OsError),
446 PixelsError(pixels::Error),
448}
449
450impl From<EventLoopError> for Error {
451 fn from(value: EventLoopError) -> Self {
452 Self::WinitEventLoopError(value)
453 }
454}
455
456impl From<OsError> for Error {
457 fn from(value: OsError) -> Self {
458 Self::OsError(value)
459 }
460}
461
462impl From<pixels::Error> for Error {
463 fn from(value: pixels::Error) -> Self {
464 Self::PixelsError(value)
465 }
466}