geng_core/
context.rs

1use super::*;
2
3pub struct Geng {
4    window: Window,
5    shader_lib: ShaderLib,
6    draw_2d: Rc<Draw2D>,
7    pub(crate) asset_manager: AssetManager,
8    default_font: Rc<Font>,
9    max_delta_time: Cell<f64>,
10}
11
12pub struct ContextOptions {
13    pub title: String,
14    pub vsync: bool,
15    pub max_delta_time: f64,
16}
17
18impl Default for ContextOptions {
19    fn default() -> Self {
20        Self {
21            title: "Geng Application".to_string(),
22            vsync: true,
23            max_delta_time: 0.1,
24        }
25    }
26}
27
28impl Geng {
29    pub fn new(options: ContextOptions) -> Self {
30        let window = Window::new(&options.title, options.vsync);
31        let ugli = window.ugli().clone();
32        let shader_lib = ShaderLib::new(window.ugli());
33        let draw_2d = Rc::new(Draw2D::new(&shader_lib, &ugli));
34        let default_font = Rc::new({
35            let data = include_bytes!("font/default.ttf") as &[u8];
36            Font::new_with(window.ugli(), &shader_lib, data.to_owned()).unwrap()
37        });
38        Geng {
39            window,
40            shader_lib,
41            draw_2d,
42            asset_manager: AssetManager::new(),
43            default_font,
44            max_delta_time: Cell::new(options.max_delta_time),
45        }
46    }
47
48    pub fn window(&self) -> &Window {
49        &self.window
50    }
51
52    pub fn ugli(&self) -> &Rc<Ugli> {
53        self.window.ugli()
54    }
55
56    pub fn shader_lib(&self) -> &ShaderLib {
57        &self.shader_lib
58    }
59
60    pub fn draw_2d(&self) -> &Rc<Draw2D> {
61        &self.draw_2d
62    }
63
64    pub fn default_font(&self) -> &Rc<Font> {
65        &self.default_font
66    }
67}
68
69pub fn run(geng: Rc<Geng>, state: impl State) {
70    let state = Rc::new(RefCell::new(state));
71    geng.window.set_event_handler(Box::new({
72        let state = state.clone();
73        move |event| {
74            state.borrow_mut().handle_event(event);
75        }
76    }));
77
78    let mut timer = Timer::new();
79    let main_loop = {
80        let geng = geng.clone();
81        move || {
82            let delta_time = timer.tick();
83            let delta_time = delta_time.min(geng.max_delta_time.get());
84            state.borrow_mut().update(delta_time);
85
86            let mut framebuffer = ugli::Framebuffer::default(geng.ugli());
87            state.borrow_mut().draw(&mut framebuffer);
88
89            geng.window.swap_buffers();
90        }
91    };
92
93    #[cfg(target_arch = "wasm32")]
94    {
95        #[wasm_bindgen(inline_js = r#"
96        export function run(main_loop) {
97            function main_loop_wrapper() {
98                main_loop();
99                window.requestAnimationFrame(main_loop_wrapper);
100            }
101            main_loop_wrapper();
102        }
103        "#)]
104        extern "C" {
105            fn run(main_loop: &wasm_bindgen::JsValue);
106        }
107        let main_loop =
108            wasm_bindgen::closure::Closure::wrap(Box::new(main_loop) as Box<dyn FnMut()>);
109        run(main_loop.as_ref());
110        main_loop.forget();
111    }
112
113    #[cfg(not(target_arch = "wasm32"))]
114    {
115        let mut main_loop = main_loop;
116        while !geng.window.should_close() {
117            main_loop();
118        }
119    }
120}