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}