1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2#![warn(missing_docs)]
3
4use handler::AppHandler;
5use web_time::Duration;
6use winit::{
7 event::Event,
8 event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
9};
10
11mod handler;
12mod input;
13pub use input::{Input, InputState};
14
15pub use anyhow;
16pub use winit;
17
18#[derive(Debug)]
20pub struct Context {
21 target_frame_time: Duration,
22 max_frame_time: Duration,
23 exit: bool,
24 delta_time: Duration,
25 pub input: Input,
27}
28
29impl Context {
30 #[inline]
32 pub(crate) fn new(fps: u32, max_frame_time: Duration) -> Self {
33 Self {
34 target_frame_time: Duration::from_secs_f64(1. / fps as f64),
35 max_frame_time,
36 delta_time: Duration::ZERO,
37 exit: false,
38 input: Input::new(),
39 }
40 }
41
42 #[inline]
44 pub fn frame_time(&self) -> Duration {
45 self.delta_time
46 }
47
48 #[inline]
51 pub fn set_target_frame_time(&mut self, time: Duration) {
52 self.target_frame_time = time;
53 }
54
55 #[inline]
57 pub fn set_target_fps(&mut self, fps: u32) {
58 self.target_frame_time = Duration::from_secs_f64(1. / fps as f64);
59 }
60
61 #[inline]
65 pub fn set_max_frame_time(&mut self, time: Duration) {
66 self.max_frame_time = time;
67 }
68
69 #[inline]
71 pub fn exit(&mut self) {
72 self.exit = true;
73 }
74}
75
76pub trait App {
78 fn update(&mut self, ctx: &mut Context) -> anyhow::Result<()>;
81
82 fn render(&mut self, blending_factor: f64) -> anyhow::Result<()>;
85
86 #[inline]
88 fn handle(&mut self, _event: Event<()>) -> anyhow::Result<()> {
89 Ok(())
90 }
91}
92
93pub type AppInitFunc<A> = dyn FnOnce(&ActiveEventLoop) -> anyhow::Result<A>;
95
96pub fn start<A>(
102 fps: u32,
103 max_frame_time: Duration,
104 app_init: Box<AppInitFunc<A>>,
105) -> anyhow::Result<()>
106where
107 A: App + 'static,
108{
109 let event_loop = EventLoop::new()?;
110
111 event_loop.set_control_flow(ControlFlow::Poll);
112
113 #[cfg_attr(any(target_arch = "wasm32", target_arch = "wasm64"), allow(unused_mut))]
114 let mut handler = AppHandler::new(app_init, fps, max_frame_time);
115
116 #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
117 event_loop.run_app(&mut handler)?;
118
119 #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
120 winit::platform::web::EventLoopExtWebSys::spawn_app(event_loop, handler);
121
122 Ok(())
123}