extern crate console_error_panic_hook;
use crate::gameboy::Gameboy;
use crate::input::KeypadKey;
use core::cell::{RefCell, RefMut};
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{CanvasRenderingContext2d, ImageData};
use std::panic;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: String);
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_u32(a: u32);
}
fn window() -> web_sys::Window {
web_sys::window().expect("no global `window` exists")
}
#[allow(unused)]
fn add_event_listener(listener: &str, f: &Closure<dyn FnMut(web_sys::KeyboardEvent)>) {
window()
.add_event_listener_with_callback(listener, f.as_ref().unchecked_ref())
.expect("should register `add_event_listener` OK");
}
fn request_animation_frame(f: &Closure<dyn FnMut()>) {
window()
.request_animation_frame(f.as_ref().unchecked_ref())
.expect("should register `requestAnimationFrame` OK");
}
#[wasm_bindgen]
pub async fn render(rom: Vec<u8>) -> Result<(), JsValue> {
panic::set_hook(Box::new(console_error_panic_hook::hook));
let document = web_sys::window().unwrap().document().unwrap();
let game = document.get_element_by_id("game");
let canvas = document
.create_element("canvas")?
.dyn_into::<web_sys::HtmlCanvasElement>()?;
game.unwrap().append_child(&canvas)?;
canvas.set_width(160);
canvas.set_height(144);
let context = canvas
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()
.unwrap();
let mut gb = Gameboy::new(rom, None);
let f = Rc::new(RefCell::new(None));
let g = f.clone();
let current_key_code: Rc<RefCell<i32>> = Rc::new(RefCell::new(0));
gb.frame();
{
let current_key_code = current_key_code.clone();
*g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
let key: RefMut<_> = current_key_code.borrow_mut();
match *key {
65 => gb.keydown(KeypadKey::A),
-65 => gb.keyup(KeypadKey::A),
83 => gb.keydown(KeypadKey::B),
-83 => gb.keyup(KeypadKey::B),
90 => gb.keydown(KeypadKey::Select),
-90 => gb.keyup(KeypadKey::Select),
88 => gb.keydown(KeypadKey::Start),
-88 => gb.keyup(KeypadKey::Start),
37 => gb.keydown(KeypadKey::Left),
-37 => gb.keyup(KeypadKey::Left),
39 => gb.keydown(KeypadKey::Right),
-39 => gb.keyup(KeypadKey::Right),
38 => gb.keydown(KeypadKey::Up),
-38 => gb.keyup(KeypadKey::Up),
40 => gb.keydown(KeypadKey::Down),
-40 => gb.keyup(KeypadKey::Down),
_ => (),
}
gb.frame();
let data: &mut [u8] = gb.image_mut();
let _image_data = match ImageData::new_with_u8_clamped_array_and_sh(
wasm_bindgen::Clamped(data),
160,
144,
) {
Ok(d) => {
context.put_image_data(&d, 0.0, 0.0).ok();
}
Err(err) => {
log(format!("{:?}", err));
}
};
request_animation_frame(f.borrow().as_ref().unwrap());
}) as Box<dyn FnMut()>));
}
{
let current_key_code = current_key_code.clone();
let closure =
Closure::<dyn FnMut(_)>::new(move |event: web_sys::KeyboardEvent| {
let key = event.key_code();
*current_key_code.borrow_mut() = key as i32;
});
window().add_event_listener_with_callback(
"keydown",
closure.as_ref().unchecked_ref(),
)?;
closure.forget();
}
{
let current_key_code = current_key_code.clone();
let closure =
Closure::<dyn FnMut(_)>::new(move |event: web_sys::KeyboardEvent| {
let key = event.key_code();
*current_key_code.borrow_mut() = (key as i32) * -1;
});
window().add_event_listener_with_callback(
"keyup",
closure.as_ref().unchecked_ref(),
)?;
closure.forget();
}
request_animation_frame(g.borrow().as_ref().unwrap());
Ok(())
}