summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/src/util.rs141
-rw-r--r--engine/src/windowing.rs55
-rw-r--r--engine/src/windowing/keyboard.rs75
3 files changed, 224 insertions, 47 deletions
diff --git a/engine/src/util.rs b/engine/src/util.rs
index 688778b..f820b64 100644
--- a/engine/src/util.rs
+++ b/engine/src/util.rs
@@ -204,6 +204,147 @@ where
}
}
+#[derive(Debug)]
+pub struct BitArray<const SIZE: usize, const BITS_PER_ITEM: usize>
+{
+ inner: [u8; SIZE],
+}
+
+impl<const SIZE: usize, const BITS_PER_ITEM: usize> BitArray<SIZE, BITS_PER_ITEM>
+{
+ const ITEM_MASK: u8 = !(u8::MAX << BITS_PER_ITEM);
+
+ pub fn new() -> Self
+ {
+ assert!(BITS_PER_ITEM > 1);
+ assert!(BITS_PER_ITEM <= 8);
+ assert_eq!(BITS_PER_ITEM % 2, 0);
+
+ Self { inner: [0; SIZE] }
+ }
+
+ pub fn get(&self, item_index: usize) -> u8
+ {
+ let bit_index = item_index * BITS_PER_ITEM;
+
+ let byte_index = bit_index / 8;
+
+ let bit_index_in_byte = bit_index - (byte_index * 8);
+
+ (self.inner[byte_index] >> (bit_index_in_byte)) & Self::ITEM_MASK
+ }
+
+ #[tracing::instrument(skip_all)]
+ pub fn set(&mut self, item_index: usize, item_bits: u8)
+ {
+ let item_bits = item_bits & Self::ITEM_MASK;
+
+ let bit_index = item_index * BITS_PER_ITEM;
+
+ let byte_index = bit_index / 8;
+
+ let bit_index_in_byte = bit_index - (byte_index * 8);
+
+ tracing::trace!(
+ item_bits,
+ bit_index,
+ byte_index,
+ bit_index_in_byte,
+ "Setting item bits"
+ );
+
+ self.inner[byte_index] &= !(Self::ITEM_MASK << bit_index_in_byte);
+
+ self.inner[byte_index] |= item_bits << bit_index_in_byte;
+ }
+
+ pub fn clear(&mut self)
+ {
+ self.inner.fill(0);
+ }
+
+ pub fn iter_occupied(&self) -> BitArrayOccupiedIter<'_, BITS_PER_ITEM>
+ {
+ BitArrayOccupiedIter {
+ inner: self.inner.iter().copied().enumerate(),
+ byte: None,
+ mask: u8::MAX,
+ }
+ }
+
+ pub fn bytes_mut(&mut self) -> &mut [u8]
+ {
+ &mut self.inner
+ }
+}
+
+impl<const SIZE: usize, const BITS_PER_ITEM: usize> Default
+ for BitArray<SIZE, BITS_PER_ITEM>
+{
+ fn default() -> Self
+ {
+ Self::new()
+ }
+}
+
+pub struct BitArrayOccupiedIter<'a, const BITS_PER_ITEM: usize>
+{
+ inner: std::iter::Enumerate<std::iter::Copied<std::slice::Iter<'a, u8>>>,
+ byte: Option<(u8, usize)>,
+ mask: u8,
+}
+
+impl<const BITS_PER_ITEM: usize> BitArrayOccupiedIter<'_, BITS_PER_ITEM>
+{
+ const ITEM_MASK: u8 = !(u8::MAX << BITS_PER_ITEM);
+}
+
+impl<const BITS_PER_ITEM: usize> Iterator for BitArrayOccupiedIter<'_, BITS_PER_ITEM>
+{
+ type Item = (usize, u8);
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ let (byte_masked, byte_index, item_bit_index_in_byte) = loop {
+ let current = self.byte.and_then(|(byte, byte_index)| {
+ let byte_masked = byte & self.mask;
+
+ let lowest_one = byte_masked.lowest_one()?;
+
+ let item_bit_index_in_byte = match lowest_one as usize % BITS_PER_ITEM {
+ 0 => lowest_one as usize,
+ remainder => lowest_one as usize - remainder,
+ };
+
+ Some((byte_masked, byte_index, item_bit_index_in_byte))
+ });
+
+ let Some((byte_masked, byte_index, item_bit_index_in_byte)) = current else {
+ let (next_byte_index, next_byte) = self.inner.next()?;
+
+ self.byte = Some((next_byte, next_byte_index));
+ self.mask = u8::MAX;
+
+ continue;
+ };
+
+ break (byte_masked, byte_index, item_bit_index_in_byte);
+ };
+
+ let item_bits = (byte_masked >> (item_bit_index_in_byte)) & Self::ITEM_MASK;
+
+ self.mask &= (!Self::ITEM_MASK) << item_bit_index_in_byte;
+
+ let item_index_in_byte = item_bit_index_in_byte as usize / BITS_PER_ITEM;
+
+ let prev_bytes_item_cnt = (byte_index * 8) / BITS_PER_ITEM;
+
+ let index = prev_bytes_item_cnt + item_index_in_byte;
+
+ Some((index, item_bits))
+ }
+}
+
macro_rules! try_option {
($expr: expr) => {
match $expr {
diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs
index 808e85e..805004a 100644
--- a/engine/src/windowing.rs
+++ b/engine/src/windowing.rs
@@ -32,7 +32,7 @@ use crate::ecs::sole::Single;
use crate::ecs::system::observer::Observe;
use crate::ecs::uid::Uid;
use crate::ecs::{declare_entity, pair, Query, Sole};
-use crate::util::MapVec;
+use crate::util::{BitArray, MapVec};
use crate::vector::Vec2;
use crate::windowing::dpi::{PhysicalPosition, PhysicalSize, Position};
use crate::windowing::keyboard::{Key, KeyState, Keyboard, UnknownKeyCodeError};
@@ -207,8 +207,21 @@ fn update_stuff(
mouse_button_input.flags.clear();
}
+ for (key_index, key_state_bits) in input.keys.iter_occupied() {
+ let key = Key::KEYS[key_index];
+
+ let key_state = match key_state_bits {
+ KEY_PRESSED_BITS => KeyState::Pressed,
+ KEY_RELEASED_BITS => KeyState::Released,
+ _ => unreachable!(),
+ };
+
+ keyboard.set_key_state(key, key_state);
+ }
+
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 };
+ input.keys.clear();
};
keyboard.set_text_keys(iter_array_queue(&context.shared_state.text_keys));
@@ -307,9 +320,6 @@ fn update_stuff(
window.set_changed();
}
- MessageFromApp::KeyboardKeyStateChanged(key, key_state) => {
- keyboard.set_key_state(key, key_state);
- }
}
}
@@ -650,7 +660,9 @@ fn create_event_loop() -> Result<EventLoop<()>, EventLoopError>
true,
);
}
- _ => { compile_error!("Unsupported platform") }
+ _ => {
+ compile_error!("Unsupported platform")
+ }
}
event_loop_builder.build()
@@ -673,7 +685,6 @@ enum MessageFromApp
WindowResized(WindowId, PhysicalSize<u32>),
WindowCloseRequested(WindowId),
WindowScaleFactorChanged(WindowId, f64),
- KeyboardKeyStateChanged(Key, KeyState),
}
#[derive(Debug)]
@@ -724,6 +735,7 @@ struct Input
absolute_mouse_pos: PhysicalPosition<f64>,
mouse_scroll_delta: MouseScrollDelta,
mouse_buttons: MapVec<MouseButton, MouseButtonInput>,
+ keys: BitArray<{ (Key::KEYS.len() * BITS_PER_KEY).div_ceil(8) }, BITS_PER_KEY>,
}
impl Default for Input
@@ -741,6 +753,7 @@ impl Default for Input
(MouseButton::Back, MouseButtonInput::default()),
(MouseButton::Forward, MouseButtonInput::default()),
]),
+ keys: BitArray::new(),
}
}
}
@@ -761,6 +774,11 @@ struct MouseButtonFlags: u8
}
}
+const BITS_PER_KEY: usize = 2;
+
+const KEY_PRESSED_BITS: u8 = 0b11;
+const KEY_RELEASED_BITS: u8 = 0b01;
+
#[derive(Debug)]
struct InitData
{
@@ -977,10 +995,17 @@ impl ApplicationHandler for App
}
};
- self.send_message(MessageFromApp::KeyboardKeyStateChanged(
- key,
- keyboard_event.state.into(),
- ));
+ let Some(mut input) = self.lock_input() else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
+ };
+
+ let key_state_bits = match keyboard_event.state.into() {
+ KeyState::Pressed => KEY_PRESSED_BITS,
+ KeyState::Released => KEY_RELEASED_BITS,
+ };
+
+ input.keys.set(key as usize, key_state_bits);
}
WindowEvent::CursorMoved { device_id: _, position } => {
{
@@ -1148,21 +1173,23 @@ fn get_monitor_native_id(
target_os = "linux" => {
use winit::platform::wayland::{
ActiveEventLoopExtWayland,
- MonitorHandleExtWayland
+ MonitorHandleExtWayland,
};
use winit::platform::x11::MonitorHandleExtX11;
if event_loop.is_wayland() {
NativeMonitorId::Wayland(
- <WinitMonitorHandle as MonitorHandleExtWayland>::native_id(monitor)
+ <WinitMonitorHandle as MonitorHandleExtWayland>::native_id(monitor),
)
} else {
NativeMonitorId::X11(
- <WinitMonitorHandle as MonitorHandleExtX11>::native_id(monitor)
+ <WinitMonitorHandle as MonitorHandleExtX11>::native_id(monitor),
)
}
}
- _ => { compile_error!("Unsupported target platform") }
+ _ => {
+ compile_error!("Unsupported target platform")
+ }
}
}
diff --git a/engine/src/windowing/keyboard.rs b/engine/src/windowing/keyboard.rs
index 4515d8a..8e0cfbe 100644
--- a/engine/src/windowing/keyboard.rs
+++ b/engine/src/windowing/keyboard.rs
@@ -1,11 +1,12 @@
-use std::collections::HashMap;
+use util_macros::VariantArr;
use crate::ecs::Sole;
+use crate::util::BitArray;
#[derive(Debug, Default, Sole)]
pub struct Keyboard
{
- map: HashMap<Key, KeyData>,
+ keys: BitArray<{ (Key::KEYS.len() * BITS_PER_KEY).div_ceil(8) }, BITS_PER_KEY>,
text_keys: String,
}
@@ -43,33 +44,49 @@ impl Keyboard
/// different state than they had the previous frame.
pub fn new_key_states(&self) -> impl Iterator<Item = (Key, KeyState)> + use<'_>
{
- self.map.iter().filter_map(|(key, key_data)| {
- if key_data.curr_state == key_data.previous_state {
+ self.keys.iter_occupied().filter_map(|(key_index, bits)| {
+ if bits == KEY_CURR_PRESSED_BITS | KEY_PREV_PRESSED_BITS {
return None;
}
- Some((*key, key_data.curr_state))
+ let key = Key::KEYS[key_index];
+
+ let curr_state = match bits & KEY_CURR_PRESSED_BITS {
+ KEY_CURR_PRESSED_BITS => KeyState::Pressed,
+ 0 => KeyState::Released,
+ _ => unreachable!(),
+ };
+
+ Some((key, curr_state))
})
}
#[must_use]
pub fn get_key_state(&self, key: Key) -> KeyState
{
- let Some(key_data) = self.map.get(&key) else {
- return KeyState::Released;
+ let bits = self.keys.get(key as usize);
+
+ let state = match bits & KEY_CURR_PRESSED_BITS {
+ KEY_CURR_PRESSED_BITS => KeyState::Pressed,
+ 0 => KeyState::Released,
+ _ => unreachable!(),
};
- key_data.curr_state
+ state
}
#[must_use]
pub fn get_prev_key_state(&self, key: Key) -> KeyState
{
- let Some(key_data) = self.map.get(&key) else {
- return KeyState::Released;
+ let bits = self.keys.get(key as usize);
+
+ let state = match bits & KEY_PREV_PRESSED_BITS {
+ KEY_PREV_PRESSED_BITS => KeyState::Pressed,
+ 0 => KeyState::Released,
+ _ => unreachable!(),
};
- key_data.previous_state
+ state
}
pub fn text_keys(&self) -> &str
@@ -79,15 +96,19 @@ impl Keyboard
pub fn set_key_state(&mut self, key: Key, key_state: KeyState)
{
- let key_data = self.map.entry(key).or_default();
-
- key_data.curr_state = key_state;
+ self.keys.set(
+ key as usize,
+ match key_state {
+ KeyState::Pressed => KEY_CURR_PRESSED_BITS,
+ KeyState::Released => 0,
+ },
+ );
}
pub fn make_key_states_previous(&mut self)
{
- for key_data in self.map.values_mut() {
- key_data.previous_state = key_data.curr_state;
+ for byte in self.keys.bytes_mut() {
+ *byte = (*byte >> 1) & 0b01010101 | *byte & 0b10101010;
}
}
@@ -98,7 +119,8 @@ impl Keyboard
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, VariantArr)]
+#[variant_arr(name = KEYS)]
#[non_exhaustive]
pub enum Key
{
@@ -797,20 +819,7 @@ impl From<winit::event::ElementState> for KeyState
}
}
-#[derive(Debug)]
-struct KeyData
-{
- curr_state: KeyState,
- previous_state: KeyState,
-}
+const BITS_PER_KEY: usize = 2;
-impl Default for KeyData
-{
- fn default() -> Self
- {
- KeyData {
- curr_state: KeyState::Released,
- previous_state: KeyState::Released,
- }
- }
-}
+const KEY_CURR_PRESSED_BITS: u8 = 0b10;
+const KEY_PREV_PRESSED_BITS: u8 = 0b01;