use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use crate::input::{InputController, UpdateState};
use crate::map_state::{MapState, Runnable};
use crate::platform::Instant;
use crate::window::FromWindow;
use crate::{MapBuilder, WindowSize};
impl Runnable<winit::event_loop::EventLoop<()>> for MapState<winit::window::Window> {
fn run(mut self, event_loop: winit::event_loop::EventLoop<()>, max_frames: Option<u64>) {
let mut last_render_time = Instant::now();
let mut current_frame: u64 = 0;
let mut input_controller = InputController::new(0.2, 100.0, 0.1);
event_loop.run(move |event, _, control_flow| {
#[cfg(target_os = "android")]
if !self.is_initialized() && event == Event::Resumed {
use tokio::runtime::Handle;
use tokio::task;
let state = task::block_in_place(|| {
Handle::current().block_on(async {
self.reinitialize().await;
})
});
return;
}
match event {
Event::DeviceEvent {
ref event,
.. } => {
input_controller.device_input(event);
}
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.window().id() => {
if !input_controller.window_input(event) {
match event {
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
self.resize(physical_size.width, physical_size.height);
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
self.resize(new_inner_size.width, new_inner_size.height);
}
_ => {}
}
}
}
Event::RedrawRequested(_) => {
let _span_ = tracing::span!(tracing::Level::TRACE, "redraw requested").entered();
let now = Instant::now();
let dt = now - last_render_time;
last_render_time = now;
input_controller.update_state(&mut self, dt);
match self.update_and_redraw() {
Ok(_) => {}
Err(wgpu::SurfaceError::Lost) => {
log::error!("Surface Lost");
}
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("Out of Memory");
*control_flow = ControlFlow::Exit;
}
Err(e) => eprintln!("{:?}", e),
};
if let Some(max_frames) = max_frames {
if current_frame >= max_frames {
log::info!("Exiting because maximum frames reached.");
*control_flow = ControlFlow::Exit;
}
current_frame += 1;
}
}
Event::Suspended => {
self.suspend();
}
Event::Resumed => {
self.recreate_surface();
let size = self.window().inner_size();
self.resize(size.width, size.height); self.resume();
}
Event::MainEventsCleared => {
self.window().request_redraw();
}
_ => {}
}
});
}
}
#[cfg(not(target_arch = "wasm32"))]
impl FromWindow for MapBuilder<winit::window::Window, winit::event_loop::EventLoop<()>> {
fn from_window(title: &'static str) -> Self {
let event_loop = EventLoop::new();
Self::new(Box::new(move || {
let window = WindowBuilder::new()
.with_title(title)
.build(&event_loop)
.unwrap();
let size = window.inner_size();
(window, WindowSize::new(100, 100).unwrap(), event_loop)
}))
}
}
#[cfg(target_arch = "wasm32")]
pub fn get_body_size() -> Option<winit::dpi::LogicalSize<i32>> {
let web_window: web_sys::Window = web_sys::window().unwrap();
let document = web_window.document().unwrap();
let body = document.body().unwrap();
Some(winit::dpi::LogicalSize {
width: body.client_width(),
height: body.client_height(),
})
}
#[cfg(target_arch = "wasm32")]
pub fn get_canvas(element_id: &'static str) -> web_sys::HtmlCanvasElement {
use wasm_bindgen::JsCast;
let web_window: web_sys::Window = web_sys::window().unwrap();
let document = web_window.document().unwrap();
document
.get_element_by_id(element_id)
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap()
}
#[cfg(target_arch = "wasm32")]
impl crate::window::FromCanvas
for MapBuilder<winit::window::Window, winit::event_loop::EventLoop<()>>
{
fn from_canvas(dom_id: &'static str) -> Self {
let event_loop = EventLoop::new();
Self::new(Box::new(move || {
use winit::platform::web::WindowBuilderExtWebSys;
let window: winit::window::Window = WindowBuilder::new()
.with_canvas(Some(get_canvas(dom_id)))
.build(&event_loop)
.unwrap();
let size = get_body_size().unwrap();
window.set_inner_size(size);
(
window,
WindowSize::new(
size.width.try_into().unwrap(),
size.height.try_into().unwrap(),
)
.unwrap(),
event_loop,
)
}))
}
}