devotee_backend_softbuffer/
lib.rs1#![deny(missing_docs)]
2
3use std::rc::Rc;
6use std::time::{Duration, Instant};
7
8use devotee_backend::Middleware;
9use devotee_backend::middling::EventContext;
10use winit::application::ApplicationHandler;
11use winit::dpi::{PhysicalPosition, PhysicalSize};
12use winit::error::{EventLoopError, OsError};
13use winit::event::{StartCause, WindowEvent};
14use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
15use winit::window::{Window, WindowAttributes, WindowId};
16
17use surface::ScaleMode;
18
19pub use surface::SoftSurface;
20
21mod surface;
22
23pub struct SoftBackend<M> {
25 middleware: M,
26 internal: Option<Internal>,
27 settings: Settings,
28 last: Instant,
29}
30
31impl<M> SoftBackend<M> {
32 pub fn new(middleware: M) -> Self {
34 let internal = None;
35 let last = Instant::now();
36 let settings = Settings {
37 render_window_size: PhysicalSize::new(32, 32),
38 border_color: 0,
39 scale_mode: ScaleMode::Auto,
40 updates_per_seconds: 60.0,
41 };
42 Self {
43 middleware,
44 internal,
45 settings,
46 last,
47 }
48 }
49}
50
51impl<M> SoftBackend<M>
52where
53 for<'init, 'context, 'surface> M: Middleware<
54 SoftInit<'init>,
55 SoftContext<'context>,
56 SoftSurface<'surface>,
57 SoftEvent,
58 SoftEventContext,
59 (),
60 >,
61{
62 pub fn run(&mut self) -> Result<(), Error> {
64 let event_loop = EventLoop::new()?;
65
66 event_loop.set_control_flow(ControlFlow::WaitUntil(
67 Instant::now() + Duration::from_secs_f32(1.0 / self.settings.updates_per_seconds),
68 ));
69 event_loop.run_app(self)?;
70
71 Ok(())
72 }
73
74 fn init(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Error> {
75 let window = Rc::new(event_loop.create_window(WindowAttributes::default())?);
76
77 let mut init = SoftInit {
78 window: &window,
79 settings: &mut self.settings,
80 };
81
82 self.middleware.on_init(&mut init);
83 window.set_min_inner_size(Some(self.settings.render_window_size));
84 let _ = window.request_inner_size(self.settings.render_window_size);
85
86 let context = softbuffer::Context::new(Rc::clone(&window))?;
87 let surface = softbuffer::Surface::new(&context, Rc::clone(&window))?;
88 let size = window.inner_size();
89
90 window.set_visible(true);
91
92 let mut internal = Internal {
93 window,
94 surface,
95 surface_size: size,
96 };
97 let _ = internal.on_resize(size);
98
99 self.internal = Some(internal);
100
101 Ok(())
102 }
103
104 fn handle_update(&mut self, event_loop: &ActiveEventLoop) {
105 let now = Instant::now();
106 if let Some(internal) = &self.internal {
107 let delta = now - self.last;
108
109 let mut control = SoftContext {
110 shutdown: false,
111 window: &internal.window,
112 delta,
113 };
114 self.middleware.on_update(&mut control);
115
116 internal.window.request_redraw();
117
118 if control.shutdown {
119 event_loop.exit();
120 }
121 }
122 self.last = now;
123 event_loop.set_control_flow(ControlFlow::WaitUntil(
124 now + Duration::from_secs_f32(1.0 / self.settings.updates_per_seconds),
125 ));
126 }
127}
128
129impl<M> ApplicationHandler for SoftBackend<M>
130where
131 for<'init, 'control, 'surface> M: Middleware<
132 SoftInit<'init>,
133 SoftContext<'control>,
134 SoftSurface<'surface>,
135 SoftEvent,
136 SoftEventContext,
137 (),
138 >,
139{
140 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
141 if self.internal.is_none() && self.init(event_loop).is_err() {
142 event_loop.exit();
143 }
144 }
145
146 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
147 if let StartCause::ResumeTimeReached { .. } = cause {
148 self.handle_update(event_loop);
149 }
150 }
151
152 fn window_event(
153 &mut self,
154 event_loop: &ActiveEventLoop,
155 _window_id: WindowId,
156 event: WindowEvent,
157 ) {
158 if let Some(internal) = &mut self.internal {
159 let context = SoftEventContext::new(
160 internal.surface_size,
161 self.settings.scale_mode,
162 self.settings.render_window_size,
163 );
164
165 if let Some(event) = self.middleware.on_event(event, &context, &mut ()) {
166 match event {
167 WindowEvent::Resized(physical_size) => {
168 if let Some(internal) = &mut self.internal {
169 internal.on_resize(physical_size);
170 }
171 }
172 WindowEvent::CloseRequested => {
173 event_loop.exit();
174 }
175 WindowEvent::Destroyed => {
176 event_loop.exit();
177 }
178 WindowEvent::RedrawRequested => {
179 if let Ok(buffer) = internal.surface.buffer_mut() {
180 let mut surface = SoftSurface::new(
181 buffer,
182 internal.surface_size,
183 self.settings.scale_mode,
184 self.settings.render_window_size,
185 );
186 let _ = surface.clear(self.settings.border_color);
187 self.middleware.on_render(&mut surface);
188 let _ = surface.present();
189 }
190 }
191 _ => {}
192 }
193 }
194 }
195 }
196}
197
198struct Settings {
199 render_window_size: PhysicalSize<u32>,
200 border_color: u32,
201 scale_mode: ScaleMode,
202 updates_per_seconds: f32,
203}
204
205impl Settings {
206 fn set_scale(&mut self, scale: u32) {
207 if let Ok(scale) = scale.try_into() {
208 self.scale_mode = ScaleMode::Fixed(scale);
209 } else {
210 self.scale_mode = ScaleMode::Auto;
211 }
212 }
213
214 fn set_updated_per_second(&mut self, updates_per_second: f32) {
218 assert!(
219 updates_per_second > 0.0,
220 "Update rate has to be greater than 0"
221 );
222 self.updates_per_seconds = updates_per_second;
223 }
224}
225
226struct Internal {
227 window: Rc<Window>,
228 surface: softbuffer::Surface<Rc<Window>, Rc<Window>>,
229 surface_size: PhysicalSize<u32>,
230}
231
232impl Internal {
233 fn on_resize(&mut self, size: PhysicalSize<u32>) -> Option<()> {
234 self.surface
235 .resize(size.width.try_into().ok()?, size.height.try_into().ok()?)
236 .ok()?;
237
238 self.surface_size = size;
239
240 Some(())
241 }
242}
243
244pub struct SoftInit<'a> {
246 window: &'a Window,
247 settings: &'a mut Settings,
248}
249
250impl SoftInit<'_> {
251 pub fn window(&self) -> &Window {
253 self.window
254 }
255
256 pub fn set_scale(&mut self, scale: u32) {
259 self.settings.set_scale(scale);
260 }
261
262 pub fn set_updates_per_second(&mut self, updates_per_second: f32) {
268 self.settings.set_updated_per_second(updates_per_second);
269 }
270
271 pub fn set_render_window_size(&mut self, width: u32, height: u32) {
273 self.settings.render_window_size = PhysicalSize::new(width, height);
274 }
275
276 pub fn set_border_color(&mut self, color: u32) {
278 self.settings.border_color = color;
279 }
280}
281
282pub struct SoftContext<'a> {
284 shutdown: bool,
285 window: &'a Window,
286 delta: Duration,
287}
288
289impl SoftContext<'_> {
290 pub fn window(&self) -> &Window {
292 self.window
293 }
294
295 pub fn shutdown(&mut self) {
297 self.shutdown = true;
298 }
299
300 pub fn delta(&self) -> Duration {
302 self.delta
303 }
304}
305
306type SoftEvent = WindowEvent;
307
308pub struct SoftEventContext {
310 render_window: (PhysicalPosition<u32>, PhysicalSize<u32>),
311 scale: u32,
312}
313
314impl SoftEventContext {
315 fn new(
316 surface_size: PhysicalSize<u32>,
317 scale: ScaleMode,
318 render_window_size: PhysicalSize<u32>,
319 ) -> Self {
320 let (render_window_position, scale) =
321 surface::estimate_render_window_position_scale(surface_size, scale, render_window_size);
322 let render_window = (render_window_position, render_window_size);
323 Self {
324 render_window,
325 scale,
326 }
327 }
328}
329
330impl EventContext<PhysicalPosition<f64>> for SoftEventContext {
331 type SurfaceSpace = Option<PhysicalPosition<u32>>;
332
333 fn estimate_surface_space(&self, event_space: PhysicalPosition<f64>) -> Self::SurfaceSpace {
334 let PhysicalPosition { x, y } = event_space;
335 let (x, y) = (x as u32, y as u32);
336 if x > self.render_window.0.x && y > self.render_window.0.y {
337 let (x, y) = (
338 (x - self.render_window.0.x) / self.scale,
339 (y - self.render_window.0.y) / self.scale,
340 );
341 if x < self.render_window.1.width && y < self.render_window.1.height {
342 return Some(PhysicalPosition::new(x, y));
343 }
344 }
345 None
346 }
347}
348
349#[derive(Debug)]
351pub enum Error {
352 WinitEventLoopError(EventLoopError),
354 OsError(OsError),
356 SoftBufferError(softbuffer::SoftBufferError),
358}
359
360impl From<EventLoopError> for Error {
361 fn from(value: EventLoopError) -> Self {
362 Self::WinitEventLoopError(value)
363 }
364}
365
366impl From<OsError> for Error {
367 fn from(value: OsError) -> Self {
368 Self::OsError(value)
369 }
370}
371
372impl From<softbuffer::SoftBufferError> for Error {
373 fn from(value: softbuffer::SoftBufferError) -> Self {
374 Self::SoftBufferError(value)
375 }
376}