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