use super::events::*;
use super::*;
use crate::hal::*;
use crate::prelude::{BTerm, GameState, BACKEND_INTERNAL};
use crate::{clear_input_state, Result};
use glow::HasContext;
pub fn main_loop<GS: GameState>(mut bterm: BTerm, mut gamestate: GS) -> Result<()> {
use glow::HasRenderLoop;
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(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 render_loop = glow::RenderLoop::from_request_animation_frame();
render_loop.run(move |_running: &mut bool| {
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;
}
});
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);
} 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);
}
}
}