pixelated/
app.rs

1use crate::{
2    context::Context, input::InputContext, render::RenderContext, time::TimeContext, window,
3};
4use winit::event_loop::EventLoop;
5
6/// User callbacks
7///
8/// Will be called from the main event loop
9pub trait Callbacks {
10    /// Called before initalization
11    #[allow(unused_variables)]
12    fn init(&self, ctx: &mut Context) {}
13
14    /// Called once per frame before render
15    ///
16    /// Return value determines wether to exit game or not
17    #[allow(unused_variables)]
18    fn update(&mut self, ctx: &mut Context) -> bool {
19        false
20    }
21}
22
23/// Main App
24/// Contains all data to run application
25pub(crate) struct App<C: Callbacks> {
26    pub(crate) callbacks: C,
27}
28
29/// Functions implemented on App
30impl<C> App<C>
31where
32    C: Callbacks + 'static,
33{
34    /// Main loop which is called from window event loop
35    /// Returns true if app should exit
36    pub(crate) fn update(&mut self, ctx: &mut Context) -> bool {
37        // Update time
38        ctx.time.update_time();
39
40        // Update callback
41        if self.callbacks.update(ctx) {
42            return true;
43        }
44
45        // Reset input
46        ctx.input.keyboard.save_keys();
47        ctx.input.keyboard.save_modifiers();
48        ctx.input.mouse.save_buttons();
49        ctx.input.mouse.set_mouse_delta((0.0, 0.0));
50
51        false
52    }
53}
54
55/// Runs the event loop
56///
57/// Calls user defined functions thorugh Callback trait
58pub fn run<C: Callbacks + 'static>(callbacks: C)
59where
60    C: Callbacks + 'static,
61{
62    env_logger::init();
63    let app = App { callbacks };
64
65    let (mut ctx, event_loop) = pollster::block_on(build_context());
66
67    app.callbacks.init(&mut ctx);
68
69    pollster::block_on(window::run_window(event_loop, app, ctx));
70}
71
72async fn build_context() -> (Context, EventLoop<()>) {
73    let (window, event_loop) = window::new_window();
74
75    let time = TimeContext::default();
76    let input = InputContext::default();
77    let render = RenderContext::new(window).await;
78    let context = Context {
79        render,
80        time,
81        input,
82    };
83
84    (context, event_loop)
85}