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, 'active_event_loop> M:
48 Middleware<
49 PixelsInit<'init>,
50 PixelsContext<'context>,
51 PixelsSurface<'surface, 'w>,
52 PixelsEvent,
53 PixelsEventContext<'event_context, 'w, 'active_event_loop>,
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, 'active_event_loop> M:
171 Middleware<
172 PixelsInit<'init>,
173 PixelsContext<'control>,
174 PixelsSurface<'surface, 'w>,
175 PixelsEvent,
176 PixelsEventContext<'event_context, 'w, 'active_event_loop>,
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 mut context = PixelsEventContext {
203 surface,
204 event_loop,
205 };
206
207 if let Some(event) = self
208 .middleware
209 .on_event(PixelsEvent::Window(event), &mut context)
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 mut context = PixelsEventContext {
234 surface,
235 event_loop,
236 };
237 let _ = self
238 .middleware
239 .on_event(PixelsEvent::Device(device_id, event), &mut context);
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, 'a> {
341 surface: PixelsSurface<'s, 'w>,
342 event_loop: &'a ActiveEventLoop,
343}
344
345impl EventContext<PhysicalPosition<f64>> for PixelsEventContext<'_, '_, '_> {
346 type SurfaceSpace = Option<PhysicalPosition<u32>>;
347
348 fn estimate_surface_space(&self, event_space: PhysicalPosition<f64>) -> Self::SurfaceSpace {
349 let PhysicalPosition { x, y } = event_space;
350 let (x, y) = (x as f32, y as f32);
351 self.surface
352 .pixels
353 .window_pos_to_pixel((x, y))
354 .ok()
355 .map(|(x, y)| PhysicalPosition::new(x as _, y as _))
356 }
357}
358
359impl PixelsEventContext<'_, '_, '_> {
360 pub fn shutdown(&self) {
362 self.event_loop.exit();
363 }
364}
365
366pub struct PixelsSurface<'s, 'w> {
368 pixels: &'s mut pixels::Pixels<'w>,
369 dimensions: PhysicalSize<u32>,
370}
371
372impl Surface for PixelsSurface<'_, '_> {
373 type Texel = [u8; 4];
374
375 fn texel(&self, x: u32, y: u32) -> Option<[u8; 4]> {
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 set_texel(&mut self, x: u32, y: u32, value: [u8; 4]) {
387 if x < self.dimensions.width && y < self.dimensions.height {
388 let buffer = self.pixels.frame_mut();
389 let offset = (4 * (x + y * self.dimensions.width)) as usize;
390 let slice = &mut buffer[offset..(offset + 4)];
391 slice.copy_from_slice(&value);
392 }
393 }
394
395 fn clear(&mut self, value: Self::Texel) {
396 let frame = self.pixels.frame_mut();
397 for pixel in frame.chunks_exact_mut(4) {
398 pixel.copy_from_slice(&value);
399 }
400 }
401
402 fn width(&self) -> u32 {
403 self.dimensions.width
404 }
405
406 fn height(&self) -> u32 {
407 self.dimensions.height
408 }
409}
410
411impl<I> Fill<I> for PixelsSurface<'_, '_>
412where
413 I: Iterator,
414 <I as Iterator>::Item: Iterator<Item = [u8; 4]>,
415{
416 fn fill_from(&mut self, data: I) {
417 let data = data.flatten();
418
419 let frame = self.pixels.frame_mut();
420 for (texel, data) in frame.chunks_exact_mut(4).zip(data) {
421 texel.copy_from_slice(&data);
422 }
423 }
424}
425
426#[derive(Debug)]
428pub enum Error {
429 WinitEventLoopError(EventLoopError),
431 OsError(OsError),
433 PixelsError(pixels::Error),
435}
436
437impl From<EventLoopError> for Error {
438 fn from(value: EventLoopError) -> Self {
439 Self::WinitEventLoopError(value)
440 }
441}
442
443impl From<OsError> for Error {
444 fn from(value: OsError) -> Self {
445 Self::OsError(value)
446 }
447}
448
449impl From<pixels::Error> for Error {
450 fn from(value: pixels::Error) -> Self {
451 Self::PixelsError(value)
452 }
453}