Work on events for the input stuff

This commit is contained in:
SeanOMik 2023-07-19 01:18:16 -04:00
parent 5a37fcf1e6
commit 77053d56ad
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
7 changed files with 384 additions and 65 deletions

53
src/ecs/resources/events.rs Executable file
View File

@ -0,0 +1,53 @@
use std::{collections::VecDeque, ops::{Deref, DerefMut}};
use super::Resource;
pub trait Event: Clone + Send + Sync + 'static {}
impl<T: Clone + Send + Sync + 'static> Event for T {}
#[derive(Clone)]
pub struct Events<T: Event> {
inner: VecDeque<T>
}
impl<T: Event> Events<T> {
pub fn new() -> Self {
Self {
inner: VecDeque::new()
}
}
}
impl<T: Event> Deref for Events<T> {
type Target = VecDeque<T>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T: Event> DerefMut for Events<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T: Event> Resource for Events<T> {
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>() -> T;
}
pub struct EventStorage<T> {
data: T,
is_future: bool,
}

3
src/ecs/resources/mod.rs Normal file → Executable file
View File

@ -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;

0
src/ecs/resources/window_state.rs Normal file → Executable file
View File

View File

@ -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<TypeId, Box<dyn Resource>>,
updated_resources: HashSet<TypeId>,
// a boolean that flip flops to clear events every other frame
events_flipflop: bool,
events: HashMap<TypeId, Box<dyn Resource>>,
event_write_queue: HashMap<TypeId, Box<dyn Resource>>,//VecDeque<(TypeId, Box<dyn Resource>)>,
}
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<R>(&mut self, default: impl Fn() -> Box<dyn Resource + 'static>) -> &mut R
where
R: Resource,
{
let type_id = TypeId::of::<R>();
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<E>(&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::<E>::new()) as Box<(dyn Resource + 'static)>;
// Get, or create, a list of events of this type
let type_id = TypeId::of::<E>();
let events: &mut Events<E> = 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<TypeId> = 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<E>(&self) -> Option<&Events<E>>
where
E: Clone + Send + Sync + 'static
{
self.events.get(&TypeId::of::<E>())
.map(|r| r.as_any().downcast_ref::<Events<E>>())
.flatten()
}
/// Query a resource.
///
/// This is O(1), resources are stored in HashMaps.

View File

@ -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::<WindowState>() {
if window_state.is_focused && window_state.is_cursor_inside_window {
let event_queue = match world.query_res_mut::<VecDeque<InputEvent>>() {
Some(i) => i,
None => {
world.insert_resource(VecDeque::<InputEvent>::new());
// must succeed since it was just added
world.query_res_mut::<VecDeque<InputEvent>>().unwrap()
}
};
let event_queue = world.query_or_insert_res::<Events<InputEvent>>
(|| Box::new(Events::<InputEvent>::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::<VecDeque<InputEvent>>() {
world.trigger_event(input_event.clone());
/* let event_queue = match world.query_res_mut::<Events<InputEvent>>() {
Some(i) => i,
None => {
world.insert_resource(VecDeque::<InputEvent>::new());
// must succeed since it was just added
world.query_res_mut::<VecDeque<InputEvent>>().unwrap()
world.query_res_mut::<Events<InputEvent>>().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 {

View File

@ -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::<VecDeque<InputEvent>>() {
if let Some(queue) = world.query_res_mut::<Events<InputEvent>>() {
// 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<winit::event::TouchPhase> 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<f64>,
},
Normalized(f64),
}
impl From<winit::event::Force> 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<Force>,
pub finger_id: u64,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Touches {
pub touches: Vec<Touch>,
}
/// 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<Arc<Mutex<Gilrs>>>, // 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<E>(val: &mut Box<dyn Any + Send + Sync>) -> bool
where
E: Clone + Hash + 'static,
{
if let Some(ev) = val.downcast_mut::<ButtonEvent<E>>() {
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::<ButtonEvent<KeyCode>>() {
match ev {
ButtonEvent::Released(_) => {
return false;
},
ButtonEvent::JustPressed(v) => {
*ev = ButtonEvent::Pressed(*v);
},
_ => {}
}
if !button_event_retain::<KeyCode>(v)
|| !button_event_retain::<MouseButton>(v)
{
return false;
}
true
});
self.typed_events.retain(|_, v| {
//if v.is::<MouseExact>() {
if v.downcast_ref::<MouseMotion>().is_some() {
if v.downcast_ref::<MouseMotion>().is_some()
|| v.downcast_ref::<MouseExact>().is_some()
|| v.downcast_ref::<CursorEnteredWindow>().is_some()
|| v.downcast_ref::<CursorLeftWindow>().is_some()
|| v.downcast_ref::<MouseScroll>().is_some()
{
return false;
}
true
});
if let Some(touches) = self.get_event_mut::<Touches>() {
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::<Touches>() {
Some(t) => t,
None => {
let t = Touches {
touches: Vec::new(),
};
self.typed_events.insert(t.type_id(), Box::new(t));
self.get_event_mut::<Touches>().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<B>(&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<E: 'static>(&self) -> Option<&E> {
self.typed_events.get(&TypeId::of::<E>())
.and_then(|e| e.as_ref()
.downcast_ref::<E>())
}
pub fn was_just_pressed(&self, code: VirtualKeyCode) -> bool {
pub(crate) fn get_event_mut<E: 'static>(&mut self) -> Option<&mut E> {
self.typed_events.get_mut(&TypeId::of::<E>())
.and_then(|e| e.as_mut()
.downcast_mut::<E>())
}
pub fn was_just_pressed<T>(&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::<ButtonEvent<KeyCode>>() {
if let Some(ev) = e.downcast_ref::<ButtonEvent<T>>() {
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<T>(&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::<ButtonEvent<KeyCode>>() {
if let Some(ev) = e.downcast_ref::<ButtonEvent<T>>() {
match ev {
ButtonEvent::Pressed(v) | ButtonEvent::JustPressed(v) => {
if v.clone() == code {

View File

@ -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::<MouseMotion>() {
debug!("delta: {}", motion.delta);
}
if let Some(exact) = input.get_event::<MouseExact>() {
debug!("exact pos: {:?}", exact);
}
if let Some(scroll) = input.get_event::<MouseScroll>() {
debug!("scrolled: {:?}", scroll);
}
if input.get_event::<CursorEnteredWindow>().is_some() {
debug!("cursor entered window!");
}
if input.get_event::<CursorLeftWindow>().is_some() {
debug!("cursor left window!");
}
for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() {
let t = &mut transform.transform;