mod api;
mod button;
mod key;
mod mouse;
pub mod prelude;
use crate::api::Application;
use int_math::{UVec2, Vec2};
use log::trace;
use std::cmp::{max, min};
use std::sync::Arc;
use swamp_render::Render;
use swamp_wgpu_window::WgpuWindow;
use swamp_window::AppHandler;
use winit::dpi;
use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::event::{
ElementState, InnerSizeWriter, MouseButton, MouseScrollDelta, Touch, TouchPhase,
};
use winit::keyboard::PhysicalKey;
use winit::window::Window;
pub struct AppInfo<'a, T: Application> {
window: WgpuWindow<'a>,
main_render: Render,
app: T,
}
pub struct App<'a, T: Application> {
app: Option<AppInfo<'a, T>>,
virtual_surface_size: UVec2,
suggested_physical_surface_size: UVec2,
cursor_moved_delayed: Option<UVec2>,
}
impl<'a, T: Application> AppHandler for App<'a, T> {
fn min_size(&self) -> (u16, u16) {
(self.virtual_surface_size.x, self.virtual_surface_size.y)
}
fn start_size(&self) -> (u16, u16) {
(
self.suggested_physical_surface_size.x,
self.suggested_physical_surface_size.y,
)
}
fn cursor_should_be_visible(&self) -> bool {
self.app
.as_ref()
.map_or(true, |info| info.app.wants_cursor_visible())
}
fn redraw(&mut self) -> bool {
if let Some(ref mut info) = self.app {
if let Some(cursor_move_delayed) = self.cursor_moved_delayed {
info.app.cursor_moved(cursor_move_delayed);
self.cursor_moved_delayed = None;
}
info.app.tick(); if info.app.wants_to_quit() {
return false;
}
info.app.render(&mut info.main_render);
info.window
.render(info.main_render.clear_color(), |render_pass| {
info.main_render.render(render_pass)
})
.expect("TODO: panic message");
}
true
}
fn got_focus(&mut self) {}
fn lost_focus(&mut self) {}
fn window_created(&mut self, window: Arc<Window>) {
trace!("create window, boot up");
let physical_size = window.inner_size();
let wgpu_window = pollster::block_on(WgpuWindow::new(window)).expect("REASON");
let mut render = Render::new(
Arc::clone(wgpu_window.device()),
Arc::clone(wgpu_window.queue()),
wgpu_window.surface_config().format,
(physical_size.width as u16, physical_size.height as u16).into(),
self.virtual_surface_size,
);
let custom_app = T::new(&mut render);
self.app = Some(AppInfo {
window: wgpu_window,
main_render: render,
app: custom_app,
});
}
fn resized(&mut self, physical_size: dpi::PhysicalSize<u32>) {
trace!("window resized (physical_size: {:?})", physical_size);
if let Some(ref mut info) = self.app {
info.window.resize(physical_size);
info.main_render
.resize((physical_size.width as u16, physical_size.height as u16).into());
}
}
fn keyboard_input(&mut self, element_state: ElementState, physical_key: PhysicalKey) {
if let Some(ref mut info) = self.app {
if let PhysicalKey::Code(key_code) = physical_key {
if let Ok(keycode) = key_code.try_into() {
info.app.keyboard_input(element_state.into(), keycode);
}
}
}
}
fn cursor_entered(&mut self) {
if let Some(ref mut info) = self.app {
info.app.cursor_entered();
}
}
fn cursor_left(&mut self) {
if let Some(ref mut info) = self.app {
info.app.cursor_left();
}
}
fn cursor_moved(&mut self, physical_position: PhysicalPosition<f64>) {
if let Some(ref mut info) = self.app {
let viewport = info.main_render.viewport();
let relative_x = max(
0,
min(
physical_position.x as i64 - viewport.position.x as i64,
(viewport.size.x - 1) as i64,
),
);
let relative_y = max(
0,
min(
physical_position.y as i64 - viewport.position.y as i64,
(viewport.size.y - 1) as i64,
),
);
let clamped_to_viewport: UVec2 =
UVec2::new(relative_x as u16, (viewport.size.y - 1) - relative_y as u16);
let virtual_position_x = (clamped_to_viewport.x as u64
* info.main_render.virtual_surface_size().x as u64)
/ viewport.size.x as u64;
let virtual_position_y = (clamped_to_viewport.y as u64
* info.main_render.virtual_surface_size().y as u64)
/ viewport.size.y as u64;
let virtual_position = UVec2::new(virtual_position_x as u16, virtual_position_y as u16);
self.cursor_moved_delayed = Some(virtual_position);
}
}
fn mouse_input(&mut self, element_state: ElementState, button: MouseButton) {
if let Some(ref mut info) = self.app {
if let Ok(converted_button) = button.try_into() {
info.app.mouse_input(element_state.into(), converted_button);
}
}
}
fn mouse_wheel(&mut self, delta: MouseScrollDelta, _touch_phase: TouchPhase) {
if let Some(ref mut info) = self.app {
if let MouseScrollDelta::LineDelta(.., y) = delta {
info.app.mouse_wheel((-y * 120.0) as i16);
}
}
}
fn mouse_motion(&mut self, delta: (f64, f64)) {
if let Some(ref mut info) = self.app {
let factor = 65.0;
let converted = Vec2::new((delta.0 * factor) as i16, (delta.0 * factor) as i16);
info.app.mouse_motion(converted);
}
}
fn touch(&mut self, _touch: Touch) {
}
fn scale_factor_changed(&mut self, scale_factor: f64, mut inner_size_writer: InnerSizeWriter) {
if let Some(ref mut info) = self.app {
if let Some(new_inner) = info.app.scale_factor_changed(scale_factor) {
let physical_size = PhysicalSize::new(new_inner.x as u32, new_inner.y as u32);
inner_size_writer.request_inner_size(physical_size).unwrap();
}
}
}
}
impl<'a, T: Application> App<'a, T> {
pub fn run(title: &str, virtual_surface_size: UVec2, suggested_physical_surface_size: UVec2) {
env_logger::init();
let mut app = Self {
app: None,
virtual_surface_size,
suggested_physical_surface_size,
cursor_moved_delayed: None,
};
let _ = swamp_window::WindowRunner::run_app(&mut app, title);
}
}