diff --git a/src/game.rs b/src/game.rs index 038aa42..05d55f2 100755 --- a/src/game.rs +++ b/src/game.rs @@ -12,7 +12,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}, window::WindowOptions}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin, change_tracker::Ct}; +use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin, change_tracker::Ct}; pub struct Controls<'a> { pub world: &'a mut edict::World, diff --git a/src/input.rs b/src/input.rs deleted file mode 100755 index 46e61c5..0000000 --- a/src/input.rs +++ /dev/null @@ -1,351 +0,0 @@ -use std::{collections::{HashMap, hash_map::DefaultHasher}, hash::{Hash, Hasher}}; - -use glam::Vec2; -use tracing::debug; -use winit::event::{ElementState, MouseScrollDelta}; - -use crate::{ecs::{SimpleSystem, EventQueue}, input_event::InputEvent, plugin::Plugin,}; - -pub type KeyCode = winit::event::VirtualKeyCode; - -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub enum ButtonEvent { - Pressed(T), - Released(T), - JustPressed(T), -} - -impl ButtonEvent { - fn take_val(self) -> T { - match self { - ButtonEvent::Pressed(t) => t, - ButtonEvent::JustPressed(t) => t, - ButtonEvent::Released(t) => t, - } - } - - fn clone_val(&self) -> T { - self.clone().take_val() - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct MouseMotion { - pub delta: Vec2, -} - -#[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, -} - -impl Default for Touches { - fn default() -> Self { - Self::new() - } -} - -impl Touches { - pub fn new() -> Self { - Self { - touches: Vec::new() - } - } -} - -/// A mouse button event -/// -/// Translated `WindowEvent::MouseButton` from `winit` crate -#[derive(Clone, Copy, Debug, Eq, 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; - -#[derive(Clone)] -pub struct InputButtons { - // the u64 as the key is the hashed value of T. this makes it easier to - // search for a button and see its state - button_events: HashMap>, -} - -impl Default for InputButtons { - fn default() -> Self { - Self::new() - } -} - -impl InputButtons { - pub fn new() -> Self { - Self { - button_events: HashMap::new(), - } - } - - fn get_button_hash(button: &T) -> u64 { - let mut hasher = DefaultHasher::new(); - button.hash(&mut hasher); - hasher.finish() - } - - /// Add a button event to this input type - pub fn add_input(&mut self, button: ButtonEvent) { - let hash = Self::get_button_hash(&button.clone_val()); - - self.button_events.insert(hash, button); - } - - pub(crate) fn add_input_from_winit(&mut self, button: T, state: ElementState) { - let event = match state { - ElementState::Pressed if self.is_pressed(button.clone()) => ButtonEvent::Pressed(button), - ElementState::Pressed => ButtonEvent::JustPressed(button), - ElementState::Released => ButtonEvent::Released(button), - }; - - self.add_input(event); - } - - /// Returns true if the button is pressed (or was just pressed) - pub fn is_pressed(&self, button: T) -> bool - { - let hash = Self::get_button_hash(&button); - match self.button_events.get(&hash) { - Some(button_event) => match button_event { - // this if statement should always be true, but just in case ;) - ButtonEvent::Pressed(b) | ButtonEvent::JustPressed(b) if button == *b => true, - _ => false, - }, - None => false - } - } - - /// Returns true if the button was just pressed this tick - pub fn was_just_pressed(&self, button: T) -> bool { - let hash = Self::get_button_hash(&button); - match self.button_events.get(&hash) { - Some(button_event) => match button_event { - // this if statement should always be true, but just in case ;) - ButtonEvent::JustPressed(b) if button == *b => true, - _ => false, - }, - None => false - } - } -} - -trait InputStorage { - fn update_just_pressed(&mut self); -} - -impl InputStorage for InputButtons { - fn update_just_pressed(&mut self) { - self.button_events.retain(|_hash, button| { - match button { - // remove released, no need to keep those around. - ButtonEvent::Released(_) => { - return false; - }, - ButtonEvent::JustPressed(b) => { - *button = ButtonEvent::Pressed(b.clone()); - }, - _ => {}, - } - - true - }); - } -} - -#[derive(Default)] -pub struct InputSystem; - -impl InputSystem { - pub fn update(&mut self, event: &InputEvent, world: &mut edict::World) -> bool { - let event_queue = world.get_resource_mut::(); - if event_queue.is_none() { - return false; - } - let mut event_queue = event_queue.unwrap(); - - match event { - InputEvent::KeyboardInput { input, .. } => { - if let Some(code) = input.virtual_keycode { - drop(event_queue); - let e = world.with_resource(InputButtons::::new); - //let mut e = with_resource_mut(world, || InputButtons::::new()); - e.add_input_from_winit(code, input.state); - } - }, - InputEvent::MouseMotion { delta, .. } => { - let delta = MouseMotion { - delta: Vec2::new(delta.0 as f32, delta.1 as f32) - }; - - event_queue.trigger_event(delta); - }, - InputEvent::CursorMoved { position, .. } => { - let exact = MouseExact { - pos: Vec2::new(position.x as f32, position.y as f32) - }; - - event_queue.trigger_event(exact); - }, - InputEvent::CursorEntered { .. } => { - let event = CursorEnteredWindow {}; - event_queue.trigger_event(event); - }, - InputEvent::CursorLeft { .. } => { - let event = CursorLeftWindow {}; - event_queue.trigger_event(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)), - }, - }; - - event_queue.trigger_event(event); - }, //MouseButton - InputEvent::MouseInput { button, state, .. } => { - let button_event = 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), - }; - - event_queue.trigger_event(button_event); - drop(event_queue); - - let e = world.with_resource(InputButtons::::new); - e.add_input_from_winit(button_event, *state); - }, - InputEvent::Touch(t) => { - drop(event_queue); - - let touch = Touch { - phase: TouchPhase::from(t.phase), - location: Vec2::new(t.location.x as f32, t.location.y as f32), - force: t.force.map(Force::from), - finger_id: t.id, - }; - - let touches = world.with_resource(Touches::new); - touches.touches.push(touch); - }, - _ => {}, - } - - false - } -} - -impl SimpleSystem for InputSystem { - fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> { - let queue = world.get_resource_mut::() - .and_then(|q| q.read_events::()); - - if queue.is_none() { - return Ok(()); - } - - let mut events = queue.unwrap(); - - while let Some(event) = events.pop_front() { - self.update(&event, world); - } - - Ok(()) - } -} - -/// Plugin that runs InputSystem -#[derive(Default)] -pub struct InputPlugin; - -impl Plugin for InputPlugin { - fn setup(&self, game: &mut crate::game::Game) { - game.with_system("input", InputSystem, &[]); - } -} \ No newline at end of file diff --git a/src/input/buttons.rs b/src/input/buttons.rs new file mode 100644 index 0000000..e279b03 --- /dev/null +++ b/src/input/buttons.rs @@ -0,0 +1,95 @@ +use std::{hash::{Hash, Hasher}, collections::{HashMap, hash_map::DefaultHasher}}; + +use winit::event::ElementState; + +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub enum ButtonEvent { + Pressed(T), + Released(T), + JustPressed(T), +} + +impl ButtonEvent { + fn take_val(self) -> T { + match self { + ButtonEvent::Pressed(t) => t, + ButtonEvent::JustPressed(t) => t, + ButtonEvent::Released(t) => t, + } + } + + fn clone_val(&self) -> T { + self.clone().take_val() + } +} + +#[derive(Clone)] +pub struct InputButtons { + // the u64 as the key is the hashed value of T. this makes it easier to + // search for a button and see its state + button_events: HashMap>, +} + +impl Default for InputButtons { + fn default() -> Self { + Self::new() + } +} + +impl InputButtons { + pub fn new() -> Self { + Self { + button_events: HashMap::new(), + } + } + + fn get_button_hash(button: &T) -> u64 { + let mut hasher = DefaultHasher::new(); + button.hash(&mut hasher); + hasher.finish() + } + + /// Add a button event to this input type + pub fn add_input(&mut self, button: ButtonEvent) { + let hash = Self::get_button_hash(&button.clone_val()); + + self.button_events.insert(hash, button); + } + + pub(crate) fn add_input_from_winit(&mut self, button: T, state: ElementState) { + let event = match state { + ElementState::Pressed if self.is_pressed(button.clone()) => ButtonEvent::Pressed(button), + ElementState::Pressed => ButtonEvent::JustPressed(button), + ElementState::Released => ButtonEvent::Released(button), + }; + + self.add_input(event); + } + + /// Returns true if the button is pressed (or was just pressed) + pub fn is_pressed(&self, button: T) -> bool + { + let hash = Self::get_button_hash(&button); + match self.button_events.get(&hash) { + Some(button_event) => match button_event { + // this if statement should always be true, but just in case ;) + ButtonEvent::Pressed(b) | ButtonEvent::JustPressed(b) if button == *b => true, + _ => false, + }, + None => false + } + } + + /// Returns true if the button was just pressed this tick + pub fn was_just_pressed(&self, button: T) -> bool { + let hash = Self::get_button_hash(&button); + match self.button_events.get(&hash) { + Some(button_event) => match button_event { + // this if statement should always be true, but just in case ;) + ButtonEvent::JustPressed(b) if button == *b => true, + _ => false, + }, + None => false + } + } +} \ No newline at end of file diff --git a/src/input/events.rs b/src/input/events.rs new file mode 100644 index 0000000..3124a8d --- /dev/null +++ b/src/input/events.rs @@ -0,0 +1,109 @@ +#[derive(Clone, Debug, PartialEq)] +pub struct MouseMotion { + pub delta: glam::Vec2, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct MouseWheel { + pub delta: glam::Vec2, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct MouseExact { + pub pos: glam::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: glam::Vec2, + pub force: Option, + pub finger_id: u64, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Touches { + pub touches: Vec, +} + +impl Default for Touches { + fn default() -> Self { + Self::new() + } +} + +impl Touches { + pub fn new() -> Self { + Self { + touches: Vec::new() + } + } +} + +/// A mouse button event +/// +/// Translated `WindowEvent::MouseButton` from `winit` crate +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum MouseButton { + Left, + Right, + Middle, + Other(u16), +} + +#[derive(Clone, Debug, PartialEq)] +pub enum MouseScrollUnit { + Line(glam::Vec2), + Pixel(glam::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; \ No newline at end of file diff --git a/src/input_event.rs b/src/input/input_event.rs similarity index 100% rename from src/input_event.rs rename to src/input/input_event.rs diff --git a/src/input/mod.rs b/src/input/mod.rs new file mode 100644 index 0000000..d322eea --- /dev/null +++ b/src/input/mod.rs @@ -0,0 +1,11 @@ +pub mod system; +pub use system::*; + +pub mod input_event; +pub use input_event::*; + +pub mod events; +pub use events::*; + +pub mod buttons; +pub use buttons::*; \ No newline at end of file diff --git a/src/input/system.rs b/src/input/system.rs new file mode 100755 index 0000000..bd7f535 --- /dev/null +++ b/src/input/system.rs @@ -0,0 +1,125 @@ +use glam::Vec2; +use winit::event::MouseScrollDelta; + +use crate::{ecs::{SimpleSystem, EventQueue}, plugin::Plugin,}; + +use super::{events::*, InputButtons, InputEvent}; + +pub type KeyCode = winit::event::VirtualKeyCode; + +#[derive(Default)] +pub struct InputSystem; + +impl InputSystem { + pub fn process_event(&mut self, world: &mut edict::World, event: &InputEvent) -> bool { + let event_queue = world.get_resource_mut::(); + if event_queue.is_none() { + return false; + } + let mut event_queue = event_queue.unwrap(); + + match event { + InputEvent::KeyboardInput { input, .. } => { + if let Some(code) = input.virtual_keycode { + drop(event_queue); + let e = world.with_resource(InputButtons::::new); + //let mut e = with_resource_mut(world, || InputButtons::::new()); + e.add_input_from_winit(code, input.state); + } + }, + InputEvent::MouseMotion { delta, .. } => { + let delta = MouseMotion { + delta: Vec2::new(delta.0 as f32, delta.1 as f32) + }; + + event_queue.trigger_event(delta); + }, + InputEvent::CursorMoved { position, .. } => { + let exact = MouseExact { + pos: Vec2::new(position.x as f32, position.y as f32) + }; + + event_queue.trigger_event(exact); + }, + InputEvent::CursorEntered { .. } => { + let event = CursorEnteredWindow {}; + event_queue.trigger_event(event); + }, + InputEvent::CursorLeft { .. } => { + let event = CursorLeftWindow {}; + event_queue.trigger_event(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)), + }, + }; + + event_queue.trigger_event(event); + }, //MouseButton + InputEvent::MouseInput { button, state, .. } => { + let button_event = 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), + }; + + event_queue.trigger_event(button_event); + drop(event_queue); + + let e = world.with_resource(InputButtons::::new); + e.add_input_from_winit(button_event, *state); + }, + InputEvent::Touch(t) => { + drop(event_queue); + + let touch = Touch { + phase: TouchPhase::from(t.phase), + location: Vec2::new(t.location.x as f32, t.location.y as f32), + force: t.force.map(Force::from), + finger_id: t.id, + }; + + let touches = world.with_resource(Touches::new); + touches.touches.push(touch); + }, + _ => {}, + } + + false + } +} + +impl SimpleSystem for InputSystem { + fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> { + let queue = world.get_resource_mut::() + .and_then(|q| q.read_events::()); + + if queue.is_none() { + return Ok(()); + } + + let mut events = queue.unwrap(); + + while let Some(event) = events.pop_front() { + self.process_event(world, &event); + } + + Ok(()) + } +} + +/// Plugin that runs InputSystem +#[derive(Default)] +pub struct InputPlugin; + +impl Plugin for InputPlugin { + fn setup(&self, game: &mut crate::game::Game) { + game.with_system("input", InputSystem, &[]); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0182ed7..b776596 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ pub mod game; pub mod render; -pub mod input_event; pub mod resources; pub mod ecs; pub mod math; diff --git a/src/render/window.rs b/src/render/window.rs index 82700c5..3a42f98 100644 --- a/src/render/window.rs +++ b/src/render/window.rs @@ -6,7 +6,7 @@ use winit::{window::{Window, Fullscreen}, dpi::{LogicalPosition, LogicalSize, Ph pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel}; -use crate::{plugin::Plugin, change_tracker::Ct, ecs::EventQueue, input_event::InputEvent}; +use crate::{plugin::Plugin, change_tracker::Ct, ecs::EventQueue, input::InputEvent}; #[derive(Default, Clone)] pub enum WindowMode {