diff --git a/src/ecs/resources/events.rs b/src/ecs/resources/events.rs new file mode 100755 index 0000000..51f3082 --- /dev/null +++ b/src/ecs/resources/events.rs @@ -0,0 +1,53 @@ +use std::{collections::VecDeque, ops::{Deref, DerefMut}}; + +use super::Resource; + +pub trait Event: Clone + Send + Sync + 'static {} +impl Event for T {} + +#[derive(Clone)] +pub struct Events { + inner: VecDeque +} + +impl Events { + pub fn new() -> Self { + Self { + inner: VecDeque::new() + } + } +} + +impl Deref for Events { + type Target = VecDeque; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Events { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Resource for Events { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } +} + +pub trait EventHolder { + fn get_data() -> T; + +} + +pub struct EventStorage { + data: T, + is_future: bool, +} \ No newline at end of file diff --git a/src/ecs/resources/mod.rs b/src/ecs/resources/mod.rs old mode 100644 new mode 100755 index 4216b06..c0f1dc6 --- a/src/ecs/resources/mod.rs +++ b/src/ecs/resources/mod.rs @@ -5,6 +5,9 @@ use winit::event::WindowEvent; pub mod window_state; pub use window_state::*; +pub mod events; +pub use events::*; + pub trait Resource: Send + Sync + 'static { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; diff --git a/src/ecs/resources/window_state.rs b/src/ecs/resources/window_state.rs old mode 100644 new mode 100755 diff --git a/src/ecs/world.rs b/src/ecs/world.rs index ac2ab1b..c2fcfaf 100755 --- a/src/ecs/world.rs +++ b/src/ecs/world.rs @@ -1,11 +1,16 @@ -use std::{any::{TypeId, Any}, collections::{HashMap, HashSet}, ops::{Deref, DerefMut}}; +use std::{any::{TypeId, Any}, collections::{HashMap, HashSet, VecDeque}, ops::{Deref, DerefMut}}; -use super::resources::Resource; +use super::resources::{Resource, Events}; pub struct World { inner: hecs::World, resources: HashMap>, updated_resources: HashSet, + + // a boolean that flip flops to clear events every other frame + events_flipflop: bool, + events: HashMap>, + event_write_queue: HashMap>,//VecDeque<(TypeId, Box)>, } impl Deref for World { @@ -33,8 +38,26 @@ impl World { inner: hecs_world, resources: HashMap::new(), updated_resources: HashSet::new(), + events_flipflop: false, + events: HashMap::new(), + event_write_queue: HashMap::new(), } } + + /// Attempts to query a resource, or will create it when its not found. + /// + /// The resource will be created by a function passed in `default`. + pub fn query_or_insert_res(&mut self, default: impl Fn() -> Box) -> &mut R + where + R: Resource, + { + let type_id = TypeId::of::(); + self.resources.entry(type_id) + .or_insert_with(default) + .as_any_mut() + .downcast_mut() + .unwrap() + } /// Insert a resource into the World. You can only have one resource of the same type. /// If you attempt to add another resource of the same type, it will be replaced. @@ -61,6 +84,48 @@ impl World { self.updated_resources.clear(); } + /// Trigger an event + pub fn trigger_event(&mut self, event: E) + where + E: Clone + Send + Sync + 'static + { + // the compiler wants me to explicit right here for some reason + let default = || Box::new(Events::::new()) as Box<(dyn Resource + 'static)>; + + // Get, or create, a list of events of this type + let type_id = TypeId::of::(); + let events: &mut Events = self.event_write_queue.entry(type_id) + .or_insert_with(default) + .as_any_mut() + .downcast_mut() + .unwrap(); + + events.push_back(event); + } + + /// Clear events, this should happen at the start of every tick since events are cloned + /// before being given to the reader. + pub fn clear_events(&mut self) { + self.events.clear(); + + // get all keys of events + let keys: Vec = self.event_write_queue.keys().map(|k| k.clone()).collect(); + + // remove all elements from self.event_write_queue and insert them to events + for k in keys.into_iter() { + self.events.insert(k, self.event_write_queue.remove(&k).unwrap()); + } + } + + pub fn read_events(&self) -> Option<&Events> + where + E: Clone + Send + Sync + 'static + { + self.events.get(&TypeId::of::()) + .map(|r| r.as_any().downcast_ref::>()) + .flatten() + } + /// Query a resource. /// /// This is O(1), resources are stored in HashMaps. diff --git a/src/game.rs b/src/game.rs index 7a7b801..366dbbf 100755 --- a/src/game.rs +++ b/src/game.rs @@ -14,7 +14,7 @@ use tracing_subscriber::{ use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}}; -use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher, world::World, resources::WindowState}, input::Input}; +use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher, world::World, resources::{WindowState, Events}}, input::Input}; pub struct Controls<'a> { pub world: &'a mut World, @@ -114,6 +114,8 @@ impl GameLoop { let mut world = self.world.lock().await; let mut resources = self.resources.lock().await; + world.clear_events(); + let mut controls = Controls { world: &mut world, resources: &mut resources @@ -210,16 +212,9 @@ impl GameLoop { // make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion if let Some(window_state) = world.query_res::() { if window_state.is_focused && window_state.is_cursor_inside_window { - - let event_queue = match world.query_res_mut::>() { - Some(i) => i, - None => { - world.insert_resource(VecDeque::::new()); - - // must succeed since it was just added - world.query_res_mut::>().unwrap() - } - }; + + let event_queue = world.query_or_insert_res::> + (|| Box::new(Events::::new())); let input_event = InputEvent::MouseMotion { device_id, delta, }; event_queue.push_back(input_event); @@ -240,17 +235,18 @@ impl GameLoop { // the InputSystem is called, so we must use a queue for the events. { let mut world = self.world.lock().await; - let event_queue = match world.query_res_mut::>() { + world.trigger_event(input_event.clone()); + /* let event_queue = match world.query_res_mut::>() { Some(i) => i, None => { world.insert_resource(VecDeque::::new()); // must succeed since it was just added - world.query_res_mut::>().unwrap() + world.query_res_mut::>().unwrap() } }; - event_queue.push_back(input_event.clone()); + event_queue.push_back(input_event.clone()); */ } if let Some(new_control) = self.input_update(&input_event).await { diff --git a/src/input.rs b/src/input.rs index d9c3d0e..c4b3149 100755 --- a/src/input.rs +++ b/src/input.rs @@ -3,9 +3,9 @@ use std::{any::{Any, TypeId}, collections::{HashMap, hash_map::DefaultHasher, Ve use gilrs_core::Gilrs; use glam::Vec2; use tracing::{warn, debug}; -use winit::event::{VirtualKeyCode, ElementState}; +use winit::event::{VirtualKeyCode, ElementState, MouseScrollDelta}; -use crate::{ecs::{SimpleSystem, resources::Resource}, input_event::InputEvent}; +use crate::{ecs::{SimpleSystem, resources::{Resource, Events}, world::World}, input_event::InputEvent}; pub type KeyCode = winit::event::VirtualKeyCode; @@ -28,7 +28,7 @@ impl SimpleSystem for InputSystem { fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> { let world = &mut controls.world; - if let Some(queue) = world.query_res_mut::>() { + if let Some(queue) = world.query_res_mut::>() { // Clone the queue, then clear it let mut queue = { let a = queue.clone(); @@ -42,7 +42,7 @@ impl SimpleSystem for InputSystem { // process the all events that happened this tick while let Some(event) = queue.pop_front() { - input.update(&event); + input.update(&event, world); } } } @@ -51,15 +51,104 @@ impl SimpleSystem for InputSystem { } } +#[derive(Clone, Debug, PartialEq)] pub struct MouseMotion { pub delta: Vec2, } -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] +pub struct MouseWheel { + pub delta: Vec2, +} + +#[derive(Clone, Debug, PartialEq)] pub struct MouseExact { pub pos: Vec2, } +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum TouchPhase { + Started, + Moved, + Ended, + Cancelled, +} + +impl From for TouchPhase { + fn from(value: winit::event::TouchPhase) -> Self { + match value { + winit::event::TouchPhase::Started => TouchPhase::Started, + winit::event::TouchPhase::Moved => TouchPhase::Moved, + winit::event::TouchPhase::Ended => TouchPhase::Ended, + winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled, + } + } +} + +/// Translated `Force` from `winit` crate +#[derive(Clone, Debug, PartialEq)] +pub enum Force { + Calibrated { + force: f64, + max_possible_force: f64, + altitude_angle: Option, + }, + Normalized(f64), +} + +impl From for Force { + fn from(value: winit::event::Force) -> Self { + match value { + winit::event::Force::Calibrated { force, max_possible_force, altitude_angle } => Self::Calibrated { force, max_possible_force, altitude_angle }, + winit::event::Force::Normalized(v) => Self::Normalized(v), + } + } +} + +/// +/// +/// Translated `WindowEvent::Touch` from `winit` crate +#[derive(Clone, Debug, PartialEq)] +pub struct Touch { + pub phase: TouchPhase, + pub location: Vec2, + pub force: Option, + pub finger_id: u64, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Touches { + pub touches: Vec, +} + +/// A mouse button event +/// +/// Translated `WindowEvent::MouseButton` from `winit` crate +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum MouseButton { + Left, + Right, + Middle, + Other(u16), +} + +#[derive(Clone, Debug, PartialEq)] +pub enum MouseScrollUnit { + Line(Vec2), + Pixel(Vec2) +} + +#[derive(Clone, Debug, PartialEq)] +pub struct MouseScroll { + pub unit: MouseScrollUnit, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CursorEnteredWindow; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CursorLeftWindow; + pub struct Input { gilrs: Option>>, // TODO // the key is a u64. This is a hash of the value stored inside of the Box @@ -77,6 +166,27 @@ impl Resource for Input { } } +/// helper function for converting +#[inline(always)] +fn button_event_retain(val: &mut Box) -> bool +where + E: Clone + Hash + 'static, +{ + if let Some(ev) = val.downcast_mut::>() { + match ev { + ButtonEvent::Released(_) => { + return false; + }, + ButtonEvent::JustPressed(v) => { + *ev = ButtonEvent::Pressed(v.clone()); + }, + _ => {} + } + } + + true +} + impl Input { pub(crate) fn new() -> Self { let gilrs = match Gilrs::new() { @@ -98,48 +208,38 @@ impl Input { pub fn clear(&mut self) { // Convert JustPressed inputs to Pressed, and remove Released events self.button_events.retain(|_, v| { - if let Some(ev) = v.downcast_mut::>() { - match ev { - ButtonEvent::Released(_) => { - return false; - }, - ButtonEvent::JustPressed(v) => { - *ev = ButtonEvent::Pressed(*v); - }, - _ => {} - } + if !button_event_retain::(v) + || !button_event_retain::(v) + { + return false; } true }); self.typed_events.retain(|_, v| { - //if v.is::() { - if v.downcast_ref::().is_some() { + if v.downcast_ref::().is_some() + || v.downcast_ref::().is_some() + || v.downcast_ref::().is_some() + || v.downcast_ref::().is_some() + || v.downcast_ref::().is_some() + { return false; } true }); + + if let Some(touches) = self.get_event_mut::() { + touches.touches.clear(); + } } - pub fn update(&mut self, event: &InputEvent) -> bool { + pub fn update(&mut self, event: &InputEvent, world: &mut World) -> bool { match event { InputEvent::KeyboardInput { input, .. } => { if let Some(code) = input.virtual_keycode { - // Get a hash of the input code - let mut hasher = DefaultHasher::new(); - code.hash(&mut hasher); - let code_hash = hasher.finish(); - - // convert state - let buttonev = Box::new(match input.state { - ElementState::Pressed if self.is_pressed(code) => ButtonEvent::Pressed(code), - ElementState::Pressed => ButtonEvent::JustPressed(code), - ElementState::Released => ButtonEvent::Released(code), - }); - - self.button_events.insert(code_hash, buttonev); + self.create_button_event(code, input.state); } }, InputEvent::MouseMotion { delta, .. } => { @@ -154,40 +254,111 @@ impl Input { pos: Vec2::new(position.x as f32, position.y as f32) }; - self.typed_events.insert(exact.type_id(), Box::new(exact.clone())); + self.typed_events.insert(exact.type_id(), Box::new(exact)); + }, + InputEvent::CursorEntered { .. } => { + let event = CursorEnteredWindow {}; + self.typed_events.insert(event.type_id(), Box::new(event)); + }, + InputEvent::CursorLeft { .. } => { + let event = CursorLeftWindow {}; + self.typed_events.insert(event.type_id(), Box::new(event)); + }, + InputEvent::MouseWheel { delta, .. } => { + let event = match delta { + MouseScrollDelta::LineDelta(x, y) => MouseScroll { + unit: MouseScrollUnit::Line(Vec2::new(*x, *y)), + }, + MouseScrollDelta::PixelDelta(delta) => MouseScroll { + unit: MouseScrollUnit::Pixel(Vec2::new(delta.x as f32, delta.y as f32)), + }, + }; + + self.typed_events.insert(event.type_id(), Box::new(event)); + }, //MouseButton + InputEvent::MouseInput { button, state, .. } => { + let button = match button { + winit::event::MouseButton::Left => MouseButton::Left, + winit::event::MouseButton::Right => MouseButton::Right, + winit::event::MouseButton::Middle => MouseButton::Middle, + winit::event::MouseButton::Other(v) => MouseButton::Other(*v), + }; + + self.create_button_event(button, *state); + }, + InputEvent::Touch(t) => { + let touch = Touch { + phase: TouchPhase::from(t.phase), + location: Vec2::new(t.location.x as f32, t.location.y as f32), + force: match t.force { + Some(f) => Some(Force::from(f)), + None => None, + }, + finger_id: t.id, + }; + + let touches = match self.get_event_mut::() { + Some(t) => t, + None => { + let t = Touches { + touches: Vec::new(), + }; + + self.typed_events.insert(t.type_id(), Box::new(t)); + self.get_event_mut::().unwrap() + } + }; + + touches.touches.push(touch); }, - /* WindowEvent::CursorMoved { position, .. } => Some(EventType::PositionChanged(position.x, position.y, InputEventCode::CursorMoved)), - WindowEvent::CursorEntered { .. } => Some(EventType::Signal(InputEventCode::CursorEnteredWindow)), - WindowEvent::CursorLeft { .. } => Some(EventType::Signal(InputEventCode::CursorLeftWindow)), */ - //WindowEvent::MouseWheel { delta, .. } => Some(EventType::AxisChanged(delta, InputEventCode::MouseWheel)), - /* WindowEvent::MouseWheel { .. } => Some(InputEventCode::MouseWheel), - WindowEvent::MouseInput { .. } => Some(InputEventCode::MouseInput), - WindowEvent::TouchpadMagnify { .. } => Some(InputEventCode::TouchpadMagnify), - WindowEvent::SmartMagnify { .. } => Some(InputEventCode::SmartMagnify), - WindowEvent::TouchpadRotate { .. } => Some(InputEventCode::TouchpadRotate), - WindowEvent::TouchpadPressure { .. } => Some(InputEventCode::TouchpadPressure), - WindowEvent::AxisMotion { .. } => Some(InputEventCode::AxisMotion), - WindowEvent::Touch { .. } => Some(InputEventCode::Touch), */ _ => {}, } false } + fn create_button_event(&mut self, button: B, state: ElementState) + where + B: Hash + PartialEq + Clone + Copy + Sync + Send + 'static + { + // Get a hash of the button + let mut hasher = DefaultHasher::new(); + button.hash(&mut hasher); + let code_hash = hasher.finish(); + + // convert state + let buttonev = Box::new(match state { + ElementState::Pressed if self.is_pressed(button) => ButtonEvent::Pressed(button), + ElementState::Pressed => ButtonEvent::JustPressed(button), + ElementState::Released => ButtonEvent::Released(button), + }); + + self.button_events.insert(code_hash, buttonev); + } + pub fn get_event(&self) -> Option<&E> { self.typed_events.get(&TypeId::of::()) .and_then(|e| e.as_ref() .downcast_ref::()) } - pub fn was_just_pressed(&self, code: VirtualKeyCode) -> bool { + pub(crate) fn get_event_mut(&mut self) -> Option<&mut E> { + self.typed_events.get_mut(&TypeId::of::()) + .and_then(|e| e.as_mut() + .downcast_mut::()) + } + + pub fn was_just_pressed(&self, code: T) -> bool + where + T: Hash + PartialEq + Clone + 'static + { // get a hash of the key code let mut hasher = DefaultHasher::new(); code.hash(&mut hasher); let inner_hash = hasher.finish(); if let Some(e) = self.button_events.get(&inner_hash) { - if let Some(ev) = e.downcast_ref::>() { + if let Some(ev) = e.downcast_ref::>() { match ev { ButtonEvent::JustPressed(v) => { if v.clone() == code { @@ -204,14 +375,17 @@ impl Input { false } - pub fn is_pressed(&self, code: VirtualKeyCode) -> bool { + pub fn is_pressed(&self, code: T) -> bool + where + T: Hash + PartialEq + Clone + 'static + { // get a hash of the key code let mut hasher = DefaultHasher::new(); code.hash(&mut hasher); let inner_hash = hasher.finish(); if let Some(e) = self.button_events.get(&inner_hash) { - if let Some(ev) = e.downcast_ref::>() { + if let Some(ev) = e.downcast_ref::>() { match ev { ButtonEvent::Pressed(v) | ButtonEvent::JustPressed(v) => { if v.clone() == code { diff --git a/src/main.rs b/src/main.rs index 49c97d2..28b5912 100755 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ use game::Game; use tracing::debug; use crate::ecs::world::World; -use crate::input::{Input, KeyCode, InputSystem, MouseMotion}; +use crate::input::{Input, KeyCode, InputSystem, MouseMotion, MouseExact, CursorEnteredWindow, MouseScroll, CursorLeftWindow, MouseButton}; use crate::render::material::Material; use crate::render::texture::Texture; use crate::ecs::components::camera::CameraComponent; @@ -113,10 +113,38 @@ async fn main() { dir_y += speed; } + if input.is_pressed(MouseButton::Left) { + debug!("left mouse button!"); + } + + if input.is_pressed(MouseButton::Middle) { + debug!("middle mouse button!"); + } + + if input.is_pressed(MouseButton::Right) { + debug!("right mouse button!"); + } + if let Some(motion) = input.get_event::() { debug!("delta: {}", motion.delta); } + if let Some(exact) = input.get_event::() { + debug!("exact pos: {:?}", exact); + } + + if let Some(scroll) = input.get_event::() { + debug!("scrolled: {:?}", scroll); + } + + if input.get_event::().is_some() { + debug!("cursor entered window!"); + } + + if input.get_event::().is_some() { + debug!("cursor left window!"); + } + for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() { let t = &mut transform.transform;