geng-core 0.5.0

Game Engine (Core)
Documentation
use super::*;

pub struct Geng {
    window: Window,
    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,
            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
    }
}

pub fn run(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 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();
        }
    };

    #[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(main_loop) as Box<dyn FnMut()>);
        run(main_loop.as_ref());
        main_loop.forget();
    }

    #[cfg(not(target_arch = "wasm32"))]
    {
        let mut main_loop = main_loop;
        while !geng.window.should_close() {
            main_loop();
        }
    }
}