use super::events::*;
use super::*;
use crate::hal::*;
use crate::prelude::{BTerm, GameState, BACKEND_INTERNAL};
use crate::{clear_input_state, BResult};
use glow::HasContext;
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::JsCast;
fn window() -> web_sys::Window {
web_sys::window().expect("no global `window` exists")
}
fn request_animation_frame(f: &Closure<dyn FnMut()>) {
window()
.request_animation_frame(f.as_ref().unchecked_ref())
.expect("should register `requestAnimationFrame` OK");
}
pub fn main_loop<GS: GameState>(mut bterm: BTerm, mut gamestate: GS) -> BResult<()> {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
{
let be = BACKEND.lock();
let gl = be.gl.as_ref().unwrap();
let mut bit = BACKEND_INTERNAL.lock();
for f in bit.fonts.iter_mut() {
f.setup_gl_texture(gl)?;
}
for s in bit.sprite_sheets.iter_mut() {
let mut f = Font::new(&s.filename.to_string(), 1, 1, (1, 1));
f.setup_gl_texture(gl)?;
s.backing = Some(Rc::new(Box::new(f)));
}
}
let now = wasm_timer::Instant::now();
let mut prev_seconds = now.elapsed().as_secs();
let mut prev_ms = now.elapsed().as_millis();
let mut frames = 0;
let f = Rc::new(RefCell::new(None));
let g = f.clone();
*g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
unsafe {
bterm.key = GLOBAL_KEY;
bterm.mouse_pos = (GLOBAL_MOUSE_POS.0, GLOBAL_MOUSE_POS.1);
bterm.left_click = GLOBAL_LEFT_CLICK;
bterm.shift = GLOBAL_MODIFIERS.0;
bterm.control = GLOBAL_MODIFIERS.1;
bterm.alt = GLOBAL_MODIFIERS.2;
bterm.web_button = GLOBAL_BUTTON.clone();
bterm.on_mouse_position(GLOBAL_MOUSE_POS.0 as f64, GLOBAL_MOUSE_POS.1 as f64);
}
tock(
&mut bterm,
&mut gamestate,
&mut frames,
&mut prev_seconds,
&mut prev_ms,
&now,
);
clear_input_state(&mut bterm);
unsafe {
GLOBAL_KEY = None;
GLOBAL_MODIFIERS = (false, false, false);
GLOBAL_LEFT_CLICK = false;
GLOBAL_BUTTON = None;
}
request_animation_frame(f.borrow().as_ref().unwrap());
}) as Box<dyn FnMut()>));
request_animation_frame(g.borrow().as_ref().unwrap());
Ok(())
}
fn tock<GS: GameState>(
bterm: &mut BTerm,
gamestate: &mut GS,
frames: &mut i32,
prev_seconds: &mut u64,
prev_ms: &mut u128,
now: &wasm_timer::Instant,
) {
check_console_backing();
let now_seconds = now.elapsed().as_secs();
*frames += 1;
if now_seconds > *prev_seconds {
bterm.fps = *frames as f32 / (now_seconds - *prev_seconds) as f32;
*frames = 0;
*prev_seconds = now_seconds;
}
let now_ms = now.elapsed().as_millis();
if now_ms > *prev_ms {
bterm.frame_time_ms = (now_ms - *prev_ms) as f32;
*prev_ms = now_ms;
}
gamestate.tick(bterm);
rebuild_consoles();
if bterm.post_scanlines {
let be = BACKEND.lock();
be.backing_buffer
.as_ref()
.unwrap()
.bind(be.gl.as_ref().unwrap());
}
unsafe {
let be = BACKEND.lock();
be.gl.as_ref().unwrap().clear_color(0.0, 0.0, 0.0, 1.0);
be.gl.as_ref().unwrap().clear(glow::COLOR_BUFFER_BIT);
}
render_consoles().unwrap();
{
let be = BACKEND.lock();
if let Some(callback) = be.gl_callback.as_ref() {
let gl = be.gl.as_ref().unwrap();
callback(gamestate, gl);
}
}
if bterm.post_scanlines {
let be = BACKEND.lock();
be.backing_buffer
.as_ref()
.unwrap()
.default(be.gl.as_ref().unwrap());
unsafe {
let bi = BACKEND_INTERNAL.lock();
if bterm.post_scanlines {
bi.shaders[3].useProgram(be.gl.as_ref().unwrap());
bi.shaders[3].setVec3(
be.gl.as_ref().unwrap(),
"screenSize",
bterm.width_pixels as f32,
bterm.height_pixels as f32,
0.0,
);
bi.shaders[3].setBool(be.gl.as_ref().unwrap(), "screenBurn", bterm.post_screenburn);
bi.shaders[3].setVec3(
be.gl.as_ref().unwrap(),
"screenBurnColor",
bterm.screen_burn_color.r,
bterm.screen_burn_color.g,
bterm.screen_burn_color.b,
);
} else {
bi.shaders[2].useProgram(be.gl.as_ref().unwrap());
}
be.gl
.as_ref()
.unwrap()
.bind_vertex_array(Some(be.quad_vao.unwrap()));
be.gl.as_ref().unwrap().bind_texture(
glow::TEXTURE_2D,
Some(be.backing_buffer.as_ref().unwrap().texture),
);
be.gl.as_ref().unwrap().draw_arrays(glow::TRIANGLES, 0, 6);
}
}
}