#![cfg(target_arch = "wasm32")] use std::rc::Rc; use instant::Instant; use wasm_bindgen::prelude::*; use winit::dpi::LogicalSize; use winit::event_loop::EventLoop; use winit::window::{Window, WindowBuilder}; use moa_core::{Clock, System}; use crate::settings; use crate::frontend::{self, PixelsFrontend, LoadSystemFn}; pub fn start(load: LoadSystemFn) { settings::set_rom_data(include_bytes!("../sonic.bin").to_vec()); std::panic::set_hook(Box::new(console_error_panic_hook::hook)); console_log::init_with_level(log::Level::Warn).expect("error initializing logger"); //wasm_bindgen_futures::spawn_local(frontend::run(load)); } #[wasm_bindgen] pub fn set_rom_data(rom_data: Vec) { settings::set_rom_data(rom_data); } #[wasm_bindgen] pub fn request_stop() { settings::request_stop(); } #[wasm_bindgen] pub fn toggle_run() { settings::toggle_run(); } #[wasm_bindgen] pub fn is_running() -> bool { settings::get().run } #[wasm_bindgen] pub fn set_speed(speed: f32) { //settings::get().speed = speed; } #[wasm_bindgen] pub fn get_speed() -> f32 { settings::get().speed } #[wasm_bindgen] pub fn get_frames_since() -> usize { settings::get_frames_since() } #[wasm_bindgen] pub struct HostHandle(PixelsFrontend); #[wasm_bindgen] pub fn new_host() -> HostHandle { HostHandle(PixelsFrontend::new()) } #[wasm_bindgen] pub fn host_run_loop(handle: HostHandle) { wasm_bindgen_futures::spawn_local(frontend::run_loop(handle.0)); } #[wasm_bindgen] pub struct SystemHandle(System); #[wasm_bindgen] pub struct LoadSystemFnHandle(LoadSystemFn); impl LoadSystemFnHandle { pub fn new(load: LoadSystemFn) -> Self { Self(load) } } #[wasm_bindgen] pub fn load_system(handle: &mut HostHandle, load: LoadSystemFnHandle) -> SystemHandle { let system = load.0(&mut handle.0, settings::get().rom_data.clone()).unwrap(); SystemHandle(system) } #[wasm_bindgen] pub fn run_system_for(handle: &mut SystemHandle, nanos: u32) -> usize { let run_timer = Instant::now(); let nanoseconds_per_frame = nanos as Clock; //let nanoseconds_per_frame = (16_600_000 as f32 * settings::get().speed) as Clock; if let Err(err) = handle.0.run_for(nanoseconds_per_frame) { log::error!("{:?}", err); } let run_time = run_timer.elapsed().as_millis(); log::debug!("ran simulation for {:?}ms in {:?}ms", nanoseconds_per_frame / 1_000_000, run_time); run_time as usize } pub fn create_window(event_loop: &EventLoop) -> Rc { use web_sys::HtmlCanvasElement; use wasm_bindgen::JsCast; use winit::platform::web::{WindowExtWebSys, WindowBuilderExtWebSys}; let canvas = web_sys::window() .and_then(|win| win.document()) .and_then(|doc| doc.get_element_by_id("video")) .and_then(|el| el.dyn_into::().ok()) .expect("document to have canvas"); let window = { let size = LogicalSize::new(frontend::WIDTH as f64, frontend::HEIGHT as f64); WindowBuilder::new() .with_canvas(Some(canvas)) .with_title("Hello Pixels + Web") //.with_inner_size(size) //.with_min_inner_size(size) .build(event_loop) .expect("WindowBuilder error") }; let window = Rc::new(window); /* // Retrieve current width and height dimensions of browser client window let get_window_size = || { let client_window = web_sys::window().unwrap(); LogicalSize::new( client_window.inner_width().unwrap().as_f64().unwrap(), client_window.inner_height().unwrap().as_f64().unwrap(), ) }; // Initialize winit window with current dimensions of browser client window.set_inner_size(get_window_size()); */ let client_window = web_sys::window().unwrap(); /* // Attach winit canvas to body element web_sys::window() .and_then(|win| win.document()) .and_then(|doc| doc.get_element_by_id("video-screen")) .and_then(|el| { while let Some(child) = el.first_child() { el.remove_child(&child); } el.append_child(&web_sys::Element::from(window.canvas())) .ok() }) .expect("couldn't append canvas to document body"); */ /* { let window = window.clone(); // Listen for resize event on browser client. Adjust winit window dimensions // on event trigger let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move |_e: web_sys::Event| { let size = get_window_size(); window.set_inner_size(size) }) as Box); client_window .add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref()) .unwrap(); closure.forget(); } */ /* let mut update_timer = Instant::now(); let mut system = load(&mut host, settings::get().rom_data.clone()).unwrap(); let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move |_e: web_sys::Event| { let run_timer = Instant::now(); let nanoseconds_per_frame = (16_600_000 as f32 * settings::get().speed) as Clock; if let Err(err) = system.run_for(nanoseconds_per_frame) { log::error!("{:?}", err); } log::info!("ran simulation for {:?}ms in {:?}ms", nanoseconds_per_frame / 1_000_000, run_timer.elapsed().as_millis()); let settings = settings::get(); if settings.run { //match load(&mut host.lock().unwrap(), settings.rom_data.clone()) { // Ok(s) => { system = s; }, // Err(err) => log::error!("{:?}", err), //} } }) as Box); client_window .set_interval_with_callback_and_timeout_and_arguments_0(closure.as_ref().unchecked_ref(), 17) .unwrap(); closure.forget(); */ window }