diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/src/graphics.rs b/src/graphics.rs index ec748b7..9d93e9f 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -33,14 +33,14 @@ impl Vertex { step_mode: wgpu::VertexStepMode::Vertex, attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4, 2 => Uint32], }; - pub fn new_col(pos: [f32; 2], color: [f32; 4], effect: u32) -> Self { + pub const fn new_col(pos: [f32; 2], color: [f32; 4], effect: u32) -> Self { Self { pos, color, effect } } - pub fn new_tex(pos: [f32; 2], tex_pos: [u16; 2], effect: u32) -> Self { + pub const fn new_tex(pos: [f32; 2], tex_pos: [u16; 2], effect: u32) -> Self { Self { pos, color: [tex_pos[0] as f32/TEXTURE_DIMENSIONS[0] as f32, tex_pos[1] as f32/TEXTURE_DIMENSIONS[1] as f32, 0., 0.], diff --git a/src/lib.rs b/src/lib.rs index 469d8cb..a301ddc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,18 @@ mod graphics; mod state; -use std::sync::Arc; +use std::{fmt::Debug, sync::Arc}; +use log::debug; use state::State; use graphics::Graphics; use winit::{application::ApplicationHandler, dpi::PhysicalSize, event::{Event, WindowEvent}, event_loop::EventLoop, window::{Window, WindowAttributes}}; +pub fn dbg(v: V) -> V { + debug!(target: "app", "{:?}", v); + v +} + struct App<'a> { // event_loop: EventLoop<()>, window: Option>, @@ -69,44 +75,6 @@ impl ApplicationHandler for App<'_> { } } -// impl<'a> App<'a> { -// fn run(&mut self, event_loop: EventLoop<()>) { -// dbg!("run"); -// event_loop.run_app(move |event, target| { -// // dbg!(&event); -// let _ = &self; -// // let _ = (&graphics, &window, &state); -// match event { -// Event::Resumed => { -// // std::thread::sleep(Duration::from_secs(5)); -// self.graphics = Some(pollster::block_on(Graphics::init(&self))); -// }, -// Event::WindowEvent { -// event: WindowEvent::CloseRequested, -// .. -// } => target.exit(), -// Event::WindowEvent { -// event: WindowEvent::RedrawRequested, -// .. -// } => { -// if let Some(g) = &mut self.graphics { -// self.state.update_if_needed(); -// self.state.render(self.window.inner_size()); -// g.update(&self.state); -// g.render(&self.state); -// } -// } -// e => { -// if let Some(g) = &mut self.graphics { -// g.event(&e, &self.window); -// } -// self.state.event(&e, &self.window); -// } -// } -// }).unwrap(); -// } -// } - #[cfg(not(target_os = "android"))] pub fn main() { // #[cfg(target_family = "wasm")] @@ -136,52 +104,6 @@ pub fn main() { }; event_loop.run_app(&mut App::new()).unwrap(); - // static mut graphics: Option = None; - - // event_loop.run(move |event, target| { - // // let _ = (&graphics, &window, &state); - // match event { - // Event::Resumed => { - // graphics = Some(pollster::block_on(Graphics::init(&window, &mut state))); - // }, - // Event::WindowEvent { - // event: WindowEvent::CloseRequested, - // .. - // } => target.exit(), - // Event::WindowEvent { - // event: WindowEvent::RedrawRequested, - // .. - // } => { - // if let Some(g) = &mut graphics { - // g.update(&state); - // g.render(&state); - // } - // } - // _ => {} - // } - - // }).unwrap(); - - // #[cfg(not(target_arch = "wasm32"))] - // { - // let state = State::new(); - // pollster::block_on(Graphics::init(&window, state)).run(event_loop); - // } - // #[cfg(target_arch = "wasm32")] - // { - // use winit::platform::web::WindowExtWebSys; - // web_sys::window() - // .unwrap() - // .document() - // .unwrap() - // .body() - // .unwrap() - // .append_child(&window.canvas().unwrap()) - // .unwrap(); - // wasm_bindgen_futures::spawn_local(async move { - // Graphics::init(&window, State::new()).await.run(event_loop); - // }); - // } } #[cfg(target_os = "android")] @@ -195,40 +117,12 @@ fn android_main(app: winit::platform::android::activity::AndroidApp) { .with_filter(android_logger::FilterBuilder::new().parse("app").build()) ); - app.set_window_flags(WindowManagerFlags::KEEP_SCREEN_ON & WindowManagerFlags::FULLSCREEN, WindowManagerFlags::empty()); + app.set_window_flags(WindowManagerFlags::KEEP_SCREEN_ON | WindowManagerFlags::FULLSCREEN, WindowManagerFlags::empty()); let event_loop = winit::event_loop::EventLoopBuilder::new() .with_android_app(app) .build() .unwrap(); - // let window = winit::window::WindowBuilder::new().build(&event_loop).unwrap(); event_loop.run_app(&mut App::new()).unwrap(); - - // App { - // window: &window, - // graphics: None, - // state: State::new() - // }.run(event_loop); - // main(); - // use std::thread; - // use std::time::Duration; - - // use winit::platform::android::EventLoopBuilderExtAndroid; - // use winit::event_loop::EventLoopBuilder; - // use winit::window::WindowBuilder; - - // let event_loop = EventLoopBuilder::new() - // .with_android_app(app) - // .build() - // .expect("Can’t build event loop"); - - // let mut window_builder = WindowBuilder::new(); - // let window = window_builder.build(&event_loop) - // .expect("Can't create window!"); - - // thread::sleep(Duration::from_secs(2)); - - // let state = State::new(); - // pollster::block_on(Graphics::init(&window, state)).run(event_loop); } \ No newline at end of file diff --git a/src/state.rs b/src/state.rs index d62aa65..6a15be6 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,11 +1,11 @@ -use std::{collections::{BTreeMap, HashMap}, time::Instant}; +use std::{collections::{BTreeMap, HashMap}, time::{Duration, Instant}}; use log::{debug, trace}; use map::{CellKind, Map}; use rand::prelude::*; use voronoice::Point; -use winit::{dpi::PhysicalSize, event::{DeviceEvent, Event, KeyEvent, MouseButton, MouseScrollDelta, Touch, TouchPhase, WindowEvent}, keyboard::{KeyCode, PhysicalKey}, window::Window}; +use winit::{dpi::{PhysicalPosition, PhysicalSize}, event::{DeviceEvent, Event, KeyEvent, MouseButton, MouseScrollDelta, Touch as WTouch, TouchPhase, WindowEvent}, keyboard::{KeyCode, PhysicalKey}, window::Window}; -use crate::graphics::{Uniforms, Vertex}; +use crate::{dbg, graphics::{Uniforms, Vertex}}; mod entity; mod map; @@ -18,6 +18,32 @@ fn rgba_to_grayscale(c: [f32; 4]) -> [f32; 4] { [v, v, v, c[3]] } +struct Touch { + pub pos: PhysicalPosition, + /// id=1000 is for mouse + pub id: u64, + pub start: Instant +} +impl PartialEq for Touch { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} +impl From for Touch { + fn from(value: WTouch) -> Self { + Self::new(value.location, value.id) + } +} +impl Touch { + pub fn new(pos: PhysicalPosition, id: u64) -> Self { + Self { + pos, + id, + start: Instant::now() + } + } +} + pub struct State { pub vertices: Vec, pub indices: Vec, @@ -29,12 +55,13 @@ pub struct State { last_frame: Instant, t: usize, // Time in frames selected_tile: usize, - mouse_pressed: bool, framerate: f32, // Update per second pub entities: BTreeMap, // entity id --> Entities next_eid: usize, pub cells_entities: HashMap>, // cell id --> entities id - touches: Vec + /// Also acount for mouse + touches: Vec, + mouse_pos: Option> } impl State { pub fn new() -> Self { @@ -49,12 +76,12 @@ impl State { map: Map::new(0, 0), ui: UI::new(), selected_tile: 0, - mouse_pressed: false, framerate: 1., entities: BTreeMap::new(), next_eid: 0, cells_entities: HashMap::new(), - touches: Vec::new() + touches: Vec::new(), + mouse_pos: None }; // Create vertices / indices to estimate vertex / index buffer size s.render(PhysicalSize::new(1, 1)); @@ -68,46 +95,52 @@ impl State { (screen_size.height as f32 / screen_size.width as f32).max(1.) * self.zoom, (screen_size.width as f32 / screen_size.height as f32).max(1.) * self.zoom ]; + } + fn handle_click(&mut self, window: &Window, pos: &PhysicalPosition) { + } pub fn window_event(&mut self, event: &WindowEvent, window: &Window) { - if self.ui.window_event(event) { - return - } match event { WindowEvent::Touch(touch) => { match touch.phase { TouchPhase::Started => { - self.touches.push(*touch); + self.touches.push((*touch).into()); }, TouchPhase::Moved => { let w_size = window.inner_size(); let old_touch_n = self.touches.iter().position(|t| t.id == touch.id).unwrap(); - let old_touch = self.touches[old_touch_n]; + let old_touch = &self.touches[old_touch_n]; let t = [ touch.location.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0], touch.location.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1] ]; let old_t = [ - old_touch.location.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0], - old_touch.location.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1] + old_touch.pos.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0], + old_touch.pos.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1] ]; // Handle pinch zoom if self.touches.len() == 2 { - let old_touch2 = self.touches[if old_touch_n == 0 {1} else {0}]; + let old_touch2 = &self.touches[if old_touch_n == 0 {1} else {0}]; let old_t2 = [ - old_touch2.location.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0], - old_touch2.location.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1] + old_touch2.pos.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0], + old_touch2.pos.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1] ]; self.set_zoom(self.zoom + (((((t[0]-old_t2[0])*self.zoom).powi(2)+((t[0]-old_t2[0])*self.zoom).powi(2)).sqrt() - (((old_t[0]-old_t2[0])*self.zoom).powi(2)+((old_t[0]-old_t2[0])*self.zoom).powi(2)).sqrt())*4.)); } self.uniforms.camera[0] -= (t[0] - old_t[0]) / self.touches.len() as f32; self.uniforms.camera[1] += (t[1] - old_t[1]) / self.touches.len() as f32; - self.touches[old_touch_n] = *touch; - }, - TouchPhase::Cancelled => { - self.touches.remove(self.touches.iter().position(|t| t.id == touch.id).unwrap()); + dbg(&self.uniforms.camera); + self.touches[old_touch_n].pos = touch.location; }, TouchPhase::Ended => { + let old_touch_n = self.touches.iter().position(|t| t.id == touch.id).unwrap(); + let old_touch = &self.touches[old_touch_n]; + if old_touch.start.elapsed() < Duration::from_millis(500) { + self.handle_click(window, &touch.location); + } + self.touches.remove(self.touches.iter().position(|t| t.id == touch.id).unwrap()); + }, + TouchPhase::Cancelled => { self.touches.remove(self.touches.iter().position(|t| t.id == touch.id).unwrap()); } } @@ -116,7 +149,11 @@ impl State { if state.is_pressed() { match button { MouseButton::Left => { - self.mouse_pressed = true; + if !self.touches.iter().any(|t| t.id == 1000) { + if let Some(pos) = self.mouse_pos { + self.touches.push(Touch::new(pos, 1000)); + } + } }, MouseButton::Right => { self.spawn_entity(self.selected_tile, Entity::new(EntityKind::Horse, self.selected_tile)); @@ -126,13 +163,22 @@ impl State { } else { match button { MouseButton::Left => { - self.mouse_pressed = false; + if let Some(i) = self.touches.iter().position(|t| t.id == 1000) { + self.touches.remove(i); + } }, _ => {} } } }, + WindowEvent::CursorLeft { .. } => { + self.mouse_pos = None; + if let Some(i) = self.touches.iter().position(|t| t.id == 1000) { + self.touches.remove(i); + } + }, WindowEvent::CursorMoved { position, .. } => { + self.mouse_pos = Some(*position); let w_size = window.inner_size(); self.update_zooms(w_size); let pos = Point { @@ -140,7 +186,8 @@ impl State { y: -(((position.y / w_size.height as f64)*2.)-1.)/(self.uniforms.zooms[1] as f64) + self.uniforms.camera[1] as f64 }; let c = self.map.voronoi.cell(self.selected_tile); - if self.mouse_pressed { + if let Some(i) = self.touches.iter().position(|t| t.id == 1000) { + self.touches[i].pos = *position; for i in c.iter_path(pos.clone()) { self.selected_tile = i; let cd = &mut self.map.cells_data[self.selected_tile]; @@ -236,7 +283,7 @@ impl State { } } - self.ui.render(&mut self.vertices, &mut self.indices); + self.ui.render(&mut self.vertices, &mut self.indices, screen_size); } pub fn update_if_needed(&mut self) { while self.last_frame.elapsed().as_secs_f32() > 1. / self.framerate { diff --git a/src/state/ui.rs b/src/state/ui.rs index 0f7d257..4537163 100644 --- a/src/state/ui.rs +++ b/src/state/ui.rs @@ -1,8 +1,8 @@ -use winit::event::{Touch, TouchPhase, WindowEvent}; +use winit::{dpi::PhysicalSize, event::{Touch, TouchPhase, WindowEvent}}; use crate::graphics::Vertex; -const BOTTOM_TAB_BAR_HEIGHT: f32 = 0.2; const SECONDARY_COLOR: [f32; 4] = [84./255., 33./255., 32./255., 1.]; +const KIND_BUTTON_SIZE: f32 = 0.2; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Kind { @@ -12,77 +12,34 @@ pub enum Kind { } pub struct UI { - pub kind_selected: Kind, - touch: Option + pub kind_selected: Kind } impl UI { pub fn new() -> Self { Self { - kind_selected: Kind::Entities, - touch: None + kind_selected: Kind::Entities } } - // Returns true if event was handled by UI - pub fn window_event(&mut self, event: &WindowEvent) -> bool { - match event { - WindowEvent::Touch(ref t) => { - match t.phase { - TouchPhase::Started => { - if !self.touch.is_some() { - self.touch = Some(*t); - true - } else { - false - } - }, - TouchPhase::Moved => { - if let Some(old_t) = self.touch { - if old_t.id == t.id { - // TODO - true - } else { - false - } - } else { - false - } - }, - TouchPhase::Cancelled | TouchPhase::Ended => { - if let Some(old_t) = self.touch { - if old_t.id == t.id { - self.touch = None; - true - } else { - false - } - } else { - false - } - } - } - }, - _ => false - } - } - pub fn render(&self, vertices: &mut Vec, indices: &mut Vec) { + pub fn render(&self, vertices: &mut Vec, indices: &mut Vec, screen_size: PhysicalSize) { + let ratio = screen_size.height as f32/screen_size.width as f32; let vs = [ // Terrain - Vertex::new_tex([-1., -1.+(BOTTOM_TAB_BAR_HEIGHT*2.)], [0, 1], 0), - Vertex::new_tex([-1., -1.], [0, 12], 0), - Vertex::new_tex([0., -1.], [11, 12], 0), - Vertex::new_tex([0., -1.+(BOTTOM_TAB_BAR_HEIGHT*2.)], [11, 1], 0), + Vertex::new_tex([-1. + (0.02*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [0, 1], 0), + Vertex::new_tex([-1. + (0.02*ratio), -1. + 0.02], [0, 13], 0), + Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio), -1. + 0.02], [12, 13], 0), + Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [12, 1], 0), // Entities - // Vertex::new_tex([0., -1.+(BOTTOM_TAB_BAR_HEIGHT*2.)], [12, 1], 0), - // Vertex::new_tex([0., -1.], [11, 12], 0), - // Vertex::new_tex([1., -1.], [] 0), - // Vertex::new_tex([1., -1.+(BOTTOM_TAB_BAR_HEIGHT*2.)], 0) + Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+(0.02*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [12, 1], 0), + Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+(0.02*ratio), -1. + 0.02], [12, 13], 0), + Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+((0.02+KIND_BUTTON_SIZE)*ratio), -1. + 0.02], [24, 13], 0), + Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+((0.02+KIND_BUTTON_SIZE)*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [24, 1], 0), ]; let ids = [ 0,1,2, 2,3,0, - // 3,2,4, - // 4,5,3 + 4,5,6, + 6,7,4 ]; let i = vertices.len() as u32; vertices.extend_from_slice(&vs);