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