#![warn(missing_docs)]
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::{prelude::*, JsCast};
use web_sys::{Document, HtmlCanvasElement, Window};
use crate::render::RenderEngine;
use crate::ui::Ui;
use crate::waterfall::Waterfall;
use crate::waterfall_interaction::WaterfallInteraction;
use crate::websocket::WebSocketClient;
pub mod array_view;
pub mod colormap;
pub mod pointer;
pub mod render;
pub mod ui;
pub mod version;
pub mod waterfall;
pub mod waterfall_interaction;
pub mod websocket;
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
Ok(())
}
#[wasm_bindgen]
pub fn maia_wasm_start() -> Result<(), JsValue> {
let (window, document) = get_window_and_document()?;
let canvas = Rc::new(
document
.get_element_by_id("canvas")
.ok_or("unable to get #canvas element")?
.dyn_into::<web_sys::HtmlCanvasElement>()?,
);
let (render_engine, waterfall, mut waterfall_interaction) =
new_waterfall(&window, &document, &canvas)?;
WebSocketClient::start(&window, Rc::clone(&waterfall))?;
let ui = Ui::new(
Rc::clone(&window),
Rc::clone(&document),
Rc::clone(&render_engine),
Rc::clone(&waterfall),
)?;
waterfall_interaction.set_ui(ui);
setup_render_loop(render_engine, waterfall);
Ok(())
}
pub fn get_window_and_document() -> Result<(Rc<Window>, Rc<Document>), JsValue> {
let window = Rc::new(web_sys::window().ok_or("unable to get window")?);
let document = Rc::new(window.document().ok_or("unable to get document")?);
Ok((window, document))
}
#[allow(clippy::type_complexity)]
pub fn new_waterfall(
window: &Rc<Window>,
document: &Document,
canvas: &Rc<HtmlCanvasElement>,
) -> Result<
(
Rc<RefCell<RenderEngine>>,
Rc<RefCell<Waterfall>>,
WaterfallInteraction,
),
JsValue,
> {
let render_engine = Rc::new(RefCell::new(RenderEngine::new(
Rc::clone(canvas),
Rc::clone(window),
document,
)?));
let waterfall = Rc::new(RefCell::new(Waterfall::new(
&mut render_engine.borrow_mut(),
window.performance().ok_or("unable to get performance")?,
)?));
let waterfall_interaction = WaterfallInteraction::new(
Rc::clone(window),
Rc::clone(canvas),
Rc::clone(&render_engine),
Rc::clone(&waterfall),
)?;
Ok((render_engine, waterfall, waterfall_interaction))
}
pub fn setup_render_loop(
render_engine: Rc<RefCell<RenderEngine>>,
waterfall: Rc<RefCell<Waterfall>>,
) {
let f = Rc::new(RefCell::new(None));
let g = f.clone();
*g.borrow_mut() = Some(Closure::new(move |dt| {
let mut render_engine = render_engine.borrow_mut();
if let Err(e) = waterfall
.borrow_mut()
.prepare_render(&mut render_engine, dt)
{
web_sys::console::error_1(&e);
return;
}
if let Err(e) = render_engine.render() {
web_sys::console::error_1(&e);
return;
}
request_animation_frame(f.borrow().as_ref().unwrap());
}));
request_animation_frame(g.borrow().as_ref().unwrap());
}
fn request_animation_frame(f: &Closure<dyn FnMut(f32)>) {
web_sys::window()
.unwrap()
.request_animation_frame(f.as_ref().unchecked_ref())
.unwrap();
}