diff options
| -rw-r--r-- | engine/src/util.rs | 46 | ||||
| -rw-r--r-- | engine/src/windowing.rs | 128 | ||||
| -rw-r--r-- | engine/src/windowing/mouse.rs | 15 |
3 files changed, 164 insertions, 25 deletions
diff --git a/engine/src/util.rs b/engine/src/util.rs index a8ee893..bd69734 100644 --- a/engine/src/util.rs +++ b/engine/src/util.rs @@ -21,6 +21,15 @@ impl<Key: Ord, Value> MapVec<Key, Value> .insert_at_part_pt_by_key((key, value), |(a_key, _)| a_key); } + pub fn insert_mut(&mut self, key: Key, value: Value) -> &mut Value + { + let insert_index = self + .inner + .partition_point(|(other_key, _other_value)| other_key <= &key); + + &mut self.inner.insert_mut(insert_index, (key, value)).1 + } + pub fn remove(&mut self, key: Key) -> Option<Value> { let index = self @@ -61,6 +70,21 @@ impl<Key: Ord, Value> MapVec<Key, Value> Some(value) } + pub fn entry(&mut self, key: Key) -> MapVecEntry<'_, Key, Value> + { + let index = self + .inner + .binary_search_by_key(&&key, |(a_key, _)| a_key) + .ok(); + + MapVecEntry { map: self, key, index } + } + + pub fn iter_mut(&mut self) -> impl Iterator<Item = (&mut Key, &mut Value)> + { + self.inner.iter_mut().map(|(key, value)| (key, value)) + } + pub fn values(&self) -> impl Iterator<Item = &Value> { self.inner.iter().map(|(_, value)| value) @@ -89,6 +113,28 @@ impl<Key: Ord, Value> Default for MapVec<Key, Value> } } +pub struct MapVecEntry<'map, Key: Ord, Value> +{ + map: &'map mut MapVec<Key, Value>, + key: Key, + index: Option<usize>, +} + +impl<'map, Key: Ord, Value> MapVecEntry<'map, Key, Value> +{ + pub fn or_insert_with(self, func: impl FnOnce() -> Value) -> &'map mut Value + { + match self.index { + Some(index) => { + let (_, value) = unsafe { self.map.inner.get_unchecked_mut(index) }; + + value + } + None => self.map.insert_mut(self.key, func()), + } + } +} + pub trait OptionExt<T> { /// Substitute for the currently experimental function diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index cca8e9a..808e85e 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use std::hint::cold_path; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -5,6 +6,7 @@ use std::sync::{Arc, Condvar, Mutex, Weak}; use std::thread::Builder as ThreadBuilder; use std::time::Duration; +use bitflags::{bitflags, bitflags_match, Flags}; use crossbeam_queue::ArrayQueue; use raw_window_handle::{DisplayHandle, HandleError, HasDisplayHandle, WindowHandle}; use winit::application::ApplicationHandler; @@ -150,9 +152,8 @@ fn update_stuff( } keyboard.make_key_states_previous(); - mouse_buttons.make_states_previous(); - let input = { + { let Some(mut input) = context .shared_state .input @@ -162,18 +163,53 @@ fn update_stuff( return Ok(()); }; - let new_input = Input { - relative_mouse_pos_delta: Vec2 { x: 0.0, y: 0.0 }, - absolute_mouse_pos: input.absolute_mouse_pos.clone(), - mouse_scroll_delta: MouseScrollDelta { vert_lines: 0.0, hor_lines: 0.0 }, - }; + mouse.curr_tick_position_delta = input.relative_mouse_pos_delta; + mouse.position = input.absolute_mouse_pos.clone(); + mouse.curr_tick_scroll_delta = input.mouse_scroll_delta.clone(); - std::mem::replace(&mut *input, new_input) - }; + for (mouse_button, mouse_button_input) in input.mouse_buttons.iter_mut() { + mouse_buttons.set_previous_to_current(*mouse_button); + + if mouse_button_input.flags.is_all() { + match mouse_buttons.get_previous(*mouse_button) { + MouseButtonState::Pressed => { + mouse_buttons.set(*mouse_button, MouseButtonState::Released); + + mouse_button_input.flags.remove(MouseButtonFlags::RELEASED); + } + MouseButtonState::Released => { + mouse_buttons.set(*mouse_button, MouseButtonState::Pressed); + + mouse_button_input.flags.remove(MouseButtonFlags::PRESSED); + } + } - mouse.curr_tick_position_delta = input.relative_mouse_pos_delta; - mouse.position = input.absolute_mouse_pos; - mouse.curr_tick_scroll_delta = input.mouse_scroll_delta; + continue; + } + + let mouse_button_state = if mouse_button_input.flags.is_empty() { + let Some(mouse_button_state) = mouse_button_input.lagged.pop_front() + else { + continue; + }; + + mouse_button_state + } else { + bitflags_match!(mouse_button_input.flags, { + MouseButtonFlags::PRESSED => MouseButtonState::Pressed, + MouseButtonFlags::RELEASED => MouseButtonState::Released, + _ => unreachable!() + }) + }; + + mouse_buttons.set(*mouse_button, mouse_button_state); + + mouse_button_input.flags.clear(); + } + + input.relative_mouse_pos_delta = Vec2 { x: 0.0, y: 0.0 }; + input.mouse_scroll_delta = MouseScrollDelta { vert_lines: 0.0, hor_lines: 0.0 }; + }; keyboard.set_text_keys(iter_array_queue(&context.shared_state.text_keys)); @@ -274,9 +310,6 @@ fn update_stuff( MessageFromApp::KeyboardKeyStateChanged(key, key_state) => { keyboard.set_key_state(key, key_state); } - MessageFromApp::MouseButtonStateChanged(mouse_button, mouse_button_state) => { - mouse_buttons.set(mouse_button, mouse_button_state); - } } } @@ -641,7 +674,6 @@ enum MessageFromApp WindowCloseRequested(WindowId), WindowScaleFactorChanged(WindowId, f64), KeyboardKeyStateChanged(Key, KeyState), - MouseButtonStateChanged(MouseButton, MouseButtonState), } #[derive(Debug)] @@ -685,12 +717,48 @@ impl Default for SharedState } } -#[derive(Debug, Default, Clone)] +#[derive(Debug)] struct Input { relative_mouse_pos_delta: Vec2<f64>, absolute_mouse_pos: PhysicalPosition<f64>, mouse_scroll_delta: MouseScrollDelta, + mouse_buttons: MapVec<MouseButton, MouseButtonInput>, +} + +impl Default for Input +{ + fn default() -> Self + { + Self { + relative_mouse_pos_delta: Vec2::default(), + absolute_mouse_pos: PhysicalPosition::default(), + mouse_scroll_delta: MouseScrollDelta::default(), + mouse_buttons: MapVec::from_iter([ + (MouseButton::Left, MouseButtonInput::default()), + (MouseButton::Right, MouseButtonInput::default()), + (MouseButton::Middle, MouseButtonInput::default()), + (MouseButton::Back, MouseButtonInput::default()), + (MouseButton::Forward, MouseButtonInput::default()), + ]), + } + } +} + +#[derive(Debug, Default)] +struct MouseButtonInput +{ + flags: MouseButtonFlags, + lagged: VecDeque<MouseButtonState>, +} + +bitflags! { +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +struct MouseButtonFlags: u8 +{ + const PRESSED = 1 << 0; + const RELEASED = 1 << 1; +} } #[derive(Debug)] @@ -991,10 +1059,28 @@ impl ApplicationHandler for App input.mouse_scroll_delta.vert_lines += vert_lines; } WindowEvent::MouseInput { device_id: _, state, button } => { - self.send_message(MessageFromApp::MouseButtonStateChanged( - button.into(), - state.into(), - )); + let Some(mut input) = self.lock_input() else { + tracing::error!("Locking input mutex timed out after 100ms"); + return; + }; + + let button = MouseButton::from(button); + let button_state = MouseButtonState::from(state); + + let button_input = input + .mouse_buttons + .entry(button) + .or_insert_with(|| MouseButtonInput::default()); + + if button_input.flags.is_all() || !button_input.lagged.is_empty() { + button_input.lagged.push_back(button_state); + return; + } + + button_input.flags.insert(match button_state { + MouseButtonState::Pressed => MouseButtonFlags::PRESSED, + MouseButtonState::Released => MouseButtonFlags::RELEASED, + }); } WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: _ } => { self.send_message(MessageFromApp::WindowScaleFactorChanged( diff --git a/engine/src/windowing/mouse.rs b/engine/src/windowing/mouse.rs index 93a0d93..f6087f4 100644 --- a/engine/src/windowing/mouse.rs +++ b/engine/src/windowing/mouse.rs @@ -80,11 +80,18 @@ impl Buttons button_data.current_state = button_state; } - pub(crate) fn make_states_previous(&mut self) + pub fn set_previous(&mut self, button: Button, button_state: ButtonState) { - for button_data in self.map.values_mut() { - button_data.previous_state = button_data.current_state; - } + let button_data = self.map.entry(button).or_default(); + + button_data.previous_state = button_state; + } + + pub fn set_previous_to_current(&mut self, button: Button) + { + let button_data = self.map.entry(button).or_default(); + + button_data.previous_state = button_data.current_state; } } |
