summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/src/util.rs46
-rw-r--r--engine/src/windowing.rs128
-rw-r--r--engine/src/windowing/mouse.rs15
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;
}
}