diff options
| author | HampusM <hampus@hampusmat.com> | 2026-09-01 18:24:39 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-09-01 18:24:39 +0200 |
| commit | 12f7283b34b9504cafe9448ede110b1fc2a3ae41 (patch) | |
| tree | 529644b6722382e14461c41f28ae42f2f5404132 | |
| parent | 632a7188ea267c93b5317ceffd18f1dab0e97cbe (diff) | |
refactor(engine): replace MapVec with intmap crate
| -rw-r--r-- | Cargo.lock | 7 | ||||
| -rw-r--r-- | engine/Cargo.toml | 1 | ||||
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 21 | ||||
| -rw-r--r-- | engine/src/ui/dear_imgui.rs | 22 | ||||
| -rw-r--r-- | engine/src/util.rs | 135 | ||||
| -rw-r--r-- | engine/src/windowing.rs | 111 | ||||
| -rw-r--r-- | engine/src/windowing/mouse.rs | 19 | ||||
| -rw-r--r-- | engine/src/windowing/window.rs | 12 |
8 files changed, 103 insertions, 225 deletions
@@ -591,6 +591,7 @@ dependencies = [ "engine-reflection", "glutin", "image", + "intmap", "opengl-bindings", "parking_lot", "paste", @@ -1019,6 +1020,12 @@ dependencies = [ ] [[package]] +name = "intmap" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e611826a1868311677fdcdfbec9e8621d104c732d080f546a854530232f0ee" + +[[package]] name = "is-terminal" version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 63c86ea..322e6c3 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -15,6 +15,7 @@ safer-ffi = "0.1.13" crossbeam-queue = "0.3.12" parking_lot = "0.12.3" circular-buffer = "2.0.0" +intmap = "3.1.3" engine-macros = { workspace = true } engine-ecs = { workspace = true } engine-reflection = { workspace = true } diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 381a609..2f373fc 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -16,6 +16,7 @@ use glutin::surface::{ Surface as GlutinSurface, WindowSurface as GlutinWindowSurface, }; +use intmap::IntMap; use opengl_bindings::blending::{ configure as gl_blending_configure, Configuration as GlBlendingConfig, @@ -138,7 +139,7 @@ use crate::texture::{ Properties as TextureProperties, Wrapping as TextureWrapping, }; -use crate::util::{MapVec, OptionExt}; +use crate::util::OptionExt; use crate::vector::{Vec2, Vec3}; use crate::windowing::dpi::PhysicalSize; use crate::windowing::window::{ @@ -171,7 +172,7 @@ struct GraphicsContext #[derive(Debug, Default)] struct BackendResourceStore { - inner: MapVec<BackendResourceId, BackendResource>, + inner: IntMap<BackendResourceId, BackendResource>, next_id: BackendResourceId, } @@ -237,7 +238,7 @@ impl BackendResourceStore let resource_id = BackendResourceId(object.as_raw()); - let Some(resource) = self.inner.get(&resource_id) else { + let Some(resource) = self.inner.get(resource_id) else { cold_path(); tracing::error!(?object_id, ?resource_id, "Backend resource does not exist"); return None; @@ -285,7 +286,7 @@ impl BackendResourceStore let resource_id = BackendResourceId(object.as_raw()); - let Some(resource) = self.inner.get_mut(&resource_id) else { + let Some(resource) = self.inner.get_mut(resource_id) else { cold_path(); tracing::error!(?object_id, ?resource_id, "Backend resource does not exist"); return None; @@ -348,6 +349,18 @@ impl BackendResourceStore #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct BackendResourceId(ObjectRawValue); +impl intmap::IntKey for BackendResourceId +{ + type Int = ObjectRawValue; + + const PRIME: Self::Int = <ObjectRawValue as intmap::IntKey>::PRIME; + + fn into_int(self) -> Self::Int + { + self.0.into_int() + } +} + #[derive(Debug)] struct GraphicsContextSurface { diff --git a/engine/src/ui/dear_imgui.rs b/engine/src/ui/dear_imgui.rs index 0ae8a3b..b589696 100644 --- a/engine/src/ui/dear_imgui.rs +++ b/engine/src/ui/dear_imgui.rs @@ -20,6 +20,7 @@ use ecs::system::observer::Observe; use ecs::system::Into; use ecs::time::Time; use ecs::{Component, Query, Sole}; +use intmap::IntMap; use crate::asset::{Assets, Handle as AssetHandle, Label as AssetLabel}; use crate::data_types::dimens::Dimens; @@ -72,7 +73,6 @@ use crate::rendering::{ PRE_RENDER_PHASE, }; use crate::texture::Properties as TextureProperties; -use crate::util::MapVec; use crate::vector::Vec2; use crate::windowing::dpi::PhysicalSize; use crate::windowing::window::Window; @@ -95,7 +95,7 @@ pub struct Context { pub enabled: bool, ctx: inner_context_wrapper::InnerContextWrapper, - texture_lookup: MapVec<TextureLookupId, RenderingObjectId>, + texture_lookup: IntMap<TextureLookupId, RenderingObjectId>, texture_id_lookup: HashMap<dear_imgui_rs::SnapshotTextureId, dear_imgui_rs::TextureId>, } @@ -153,7 +153,7 @@ impl ecs::extension::Extension for Extension let mut context = Context { enabled: self.start_enabled, ctx: inner_context_wrapper::InnerContextWrapper::new(), - texture_lookup: MapVec::with_capacity(8), + texture_lookup: IntMap::with_capacity(8), texture_id_lookup: HashMap::with_capacity(8), }; @@ -585,7 +585,7 @@ fn add_drawing_render_pass( "Performing texture operation: Update" ); - let Some(texture_object_id) = texture_lookup.get(&texture_lookup_id) + let Some(texture_object_id) = texture_lookup.get(texture_lookup_id) else { tracing::error!( snapshot_tex_id = ?texture_request.texture(), @@ -741,7 +741,7 @@ fn add_drawing_render_pass( let tex_id = cmd_params.texture_id; let Some(texture_object_id) = - texture_lookup.get(&TextureLookupId::from(tex_id)) + texture_lookup.get(TextureLookupId::from(tex_id)) else { tracing::error!( "Unknown texture {}. Skipping skipping draw command", @@ -1046,6 +1046,18 @@ impl TextureLookupId } } +impl intmap::IntKey for TextureLookupId +{ + type Int = u64; + + const PRIME: Self::Int = <u64 as intmap::IntKey>::PRIME; + + fn into_int(self) -> Self::Int + { + self.inner + } +} + impl From<dear_imgui_rs::TextureId> for TextureLookupId { fn from(texture_id: dear_imgui_rs::TextureId) -> Self diff --git a/engine/src/util.rs b/engine/src/util.rs index e845340..a7caa2a 100644 --- a/engine/src/util.rs +++ b/engine/src/util.rs @@ -1,139 +1,6 @@ use std::fmt::{Debug, Display}; -use crate::ecs::util::{StreamingIterator, VecExt}; - -#[derive(Debug, Clone)] -pub struct MapVec<Key: Ord, Value> -{ - inner: Vec<(Key, Value)>, -} - -impl<Key: Ord, Value> MapVec<Key, Value> -{ - pub fn with_capacity(capacity: usize) -> Self - { - Self { inner: Vec::with_capacity(capacity) } - } - - pub fn insert(&mut self, key: Key, value: Value) - { - self.inner - .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 - .inner - .binary_search_by_key(&&key, |(a_key, _)| a_key) - .ok()?; - - let (_, value) = self.inner.remove(index); - - Some(value) - } - - pub fn get(&self, key: &Key) -> Option<&Value> - { - let index = self - .inner - .binary_search_by_key(&key, |(a_key, _)| a_key) - .ok()?; - - let Some((_, value)) = self.inner.get(index) else { - unreachable!(); // Reason: Index from binary search cannot be OOB - }; - - Some(value) - } - - pub fn get_mut(&mut self, key: &Key) -> Option<&mut Value> - { - let index = self - .inner - .binary_search_by_key(&key, |(a_key, _)| a_key) - .ok()?; - - let Some((_, value)) = self.inner.get_mut(index) else { - unreachable!(); // Reason: Index from binary search cannot be OOB - }; - - 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) - } -} - -impl<Key: Ord, Value> FromIterator<(Key, Value)> for MapVec<Key, Value> -{ - fn from_iter<Iter: IntoIterator<Item = (Key, Value)>>(iter: Iter) -> Self - { - let mut items = iter.into_iter().collect::<Vec<_>>(); - - if !items.is_sorted_by_key(|(key, _)| key) { - items.sort_by(|(key_a, _), (key_b, _)| key_a.cmp(key_b)); - } - - Self { inner: items } - } -} - -impl<Key: Ord, Value> Default for MapVec<Key, Value> -{ - fn default() -> Self - { - Self { inner: Vec::new() } - } -} - -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()), - } - } -} +use crate::ecs::util::StreamingIterator; pub trait OptionExt<T> { diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index aa86f01..2493851 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -8,6 +8,7 @@ use std::time::Duration; use bitflags::{bitflags, bitflags_match, Flags}; use crossbeam_queue::ArrayQueue; +use intmap::IntMap; use raw_window_handle::{DisplayHandle, HandleError, HasDisplayHandle, WindowHandle}; use winit::application::ApplicationHandler; use winit::error::EventLoopError; @@ -19,7 +20,6 @@ use winit::event_loop::{ OwnedDisplayHandle, }; use winit::keyboard::PhysicalKey; -use winit::monitor::MonitorHandle as WinitMonitorHandle; use winit::window::{Window as WinitWindow, WindowId as WinitWindowId}; use crate::ecs::actions::Actions; @@ -33,7 +33,7 @@ use crate::ecs::system::observer::Observe; use crate::ecs::uid::Uid; use crate::ecs::util::StreamingIterator; use crate::ecs::{declare_entity, pair, Query, Sole}; -use crate::util::{BitArray, MapVec}; +use crate::util::BitArray; use crate::vector::Vec2; use crate::windowing::dpi::{PhysicalPosition, PhysicalSize, Position}; use crate::windowing::keyboard::{Key, KeyState, Keyboard, UnknownKeyCodeError}; @@ -169,17 +169,17 @@ fn update_stuff( mouse.curr_tick_scroll_delta = input.mouse_scroll_delta.clone(); for (mouse_button, mouse_button_input) in input.mouse_buttons.iter_mut() { - mouse_buttons.set_previous_to_current(*mouse_button); + mouse_buttons.set_previous_to_current(mouse_button); if mouse_button_input.flags.is_all() { - match mouse_buttons.get_previous(*mouse_button) { + match mouse_buttons.get_previous(mouse_button) { MouseButtonState::Pressed => { - mouse_buttons.set(*mouse_button, MouseButtonState::Released); + mouse_buttons.set(mouse_button, MouseButtonState::Released); mouse_button_input.flags.remove(MouseButtonFlags::RELEASED); } MouseButtonState::Released => { - mouse_buttons.set(*mouse_button, MouseButtonState::Pressed); + mouse_buttons.set(mouse_button, MouseButtonState::Pressed); mouse_button_input.flags.remove(MouseButtonFlags::PRESSED); } @@ -203,7 +203,7 @@ fn update_stuff( }) }; - mouse_buttons.set(*mouse_button, mouse_button_state); + mouse_buttons.set(mouse_button, mouse_button_state); mouse_button_input.flags.clear(); } @@ -284,7 +284,7 @@ fn update_stuff( ); let Some(window_ent_id) = - windows.get(&window_id).map(|(_, ent_id)| ent_id) + windows.get(window_id).map(|(_, ent_id)| ent_id) else { tracing::error!( wid = ?window_id, @@ -307,7 +307,7 @@ fn update_stuff( } MessageFromApp::WindowCloseRequested(window_id) => { let Some(window_ent_id) = - windows.get(&window_id).map(|(_, ent_id)| ent_id) + windows.get(window_id).map(|(_, ent_id)| ent_id) else { tracing::error!( wid = ?window_id, @@ -320,7 +320,7 @@ fn update_stuff( } MessageFromApp::WindowScaleFactorChanged(window_id, scale_factor) => { let Some(window_ent_id) = - windows.get(&window_id).map(|(_, ent_id)| ent_id) + windows.get(window_id).map(|(_, ent_id)| ent_id) else { tracing::error!( wid = ?window_id, @@ -384,7 +384,7 @@ fn handle_window_changed( let mut window = evt_match.get_ent_target_comp_mut(); - let Some((winit_window, _)) = context.windows.get(&window.wid()) else { + let Some((winit_window, _)) = context.windows.get(window.wid()) else { tracing::error!( wid = ?window.wid(), entity_id = %window_ent_id, @@ -435,8 +435,8 @@ pub struct Context { shared_state: Arc<SharedState>, display_handle: Option<OwnedDisplayHandle>, - windows: MapVec<WindowId, (Arc<WinitWindow>, Uid)>, - available_monitors: MapVec<NativeMonitorId, MonitorHandle>, + windows: IntMap<WindowId, (Arc<WinitWindow>, Uid)>, + available_monitors: Vec<MonitorHandle>, primary_monitor: Option<MonitorHandle>, } @@ -456,7 +456,7 @@ impl Context window_id: &WindowId, ) -> Option<Result<WindowHandle<'_>, HandleError>> { - self.windows.get(window_id).map(|(winit_window, _)| { + self.windows.get(*window_id).map(|(winit_window, _)| { #[cfg(windows)] { use winit::platform::windows::WindowExtWindows; @@ -485,7 +485,7 @@ impl Context /// may not exist any longer. pub fn available_monitors(&self) -> impl Iterator<Item = &MonitorHandle> { - self.available_monitors.values() + self.available_monitors.iter() } fn try_send_message_to_app(&self, message: MessageToApp) @@ -526,7 +526,7 @@ impl Context match catch_unwind(move || { let mut app = App { shared_state: shared_state_b, - windows: MapVec::default(), + windows: IntMap::with_capacity(1), }; let event_loop = match create_event_loop() { @@ -583,8 +583,8 @@ impl Context return Self { shared_state, display_handle: None, - windows: MapVec::default(), - available_monitors: MapVec::default(), + windows: IntMap::with_capacity(1), + available_monitors: Vec::with_capacity(2), primary_monitor: None, }; } @@ -640,8 +640,8 @@ impl Context return Self { shared_state, display_handle: None, - windows: MapVec::default(), - available_monitors: MapVec::default(), + windows: IntMap::with_capacity(1), + available_monitors: Vec::with_capacity(2), primary_monitor: None, }; }; @@ -649,7 +649,7 @@ impl Context Self { shared_state, display_handle: Some(init_data.display), - windows: MapVec::default(), + windows: IntMap::with_capacity(1), available_monitors: init_data.available_monitors, primary_monitor: init_data.primary_monitor, } @@ -755,7 +755,7 @@ struct Input relative_mouse_pos_delta: Vec2<f64>, absolute_mouse_pos: PhysicalPosition<f64>, mouse_scroll_delta: MouseScrollDelta, - mouse_buttons: MapVec<MouseButton, MouseButtonInput>, + mouse_buttons: IntMap<MouseButton, MouseButtonInput>, keys: BitArray<{ (Key::KEYS.len() * BITS_PER_KEY).div_ceil(8) }, BITS_PER_KEY>, } @@ -767,7 +767,7 @@ impl Default for Input relative_mouse_pos_delta: Vec2::default(), absolute_mouse_pos: PhysicalPosition::default(), mouse_scroll_delta: MouseScrollDelta::default(), - mouse_buttons: MapVec::from_iter([ + mouse_buttons: IntMap::from_iter([ (MouseButton::Left, MouseButtonInput::default()), (MouseButton::Right, MouseButtonInput::default()), (MouseButton::Middle, MouseButtonInput::default()), @@ -804,7 +804,7 @@ const KEY_RELEASED_BITS: u8 = 0b01; struct InitData { display: OwnedDisplayHandle, - available_monitors: MapVec<NativeMonitorId, MonitorHandle>, + available_monitors: Vec<MonitorHandle>, primary_monitor: Option<MonitorHandle>, } @@ -812,7 +812,7 @@ struct InitData struct App { shared_state: Arc<SharedState>, - windows: MapVec<WindowId, (Weak<WinitWindow>, WindowSettings)>, + windows: IntMap<WindowId, (Weak<WinitWindow>, WindowSettings)>, } impl App @@ -862,7 +862,7 @@ impl App )); } MessageToApp::SetWindowCursorGrabMode(window_id, cursor_grab_mode) => { - let Some((_, window_settings)) = self.windows.get_mut(&window_id) + let Some((_, window_settings)) = self.windows.get_mut(window_id) else { tracing::warn!( window_id=?window_id, @@ -906,13 +906,8 @@ impl ApplicationHandler for App StartCause::Init => { let available_monitors = event_loop .available_monitors() - .map(|monitor| { - ( - get_monitor_native_id(&monitor, event_loop), - MonitorHandle::from_winit_monitor_handle(monitor), - ) - }) - .collect::<MapVec<_, _>>(); + .map(MonitorHandle::from_winit_monitor_handle) + .collect::<Vec<_>>(); let Ok(mut init_data) = self.shared_state.init_data.lock() else { tracing::error!("Init data mutex is poisoned, exiting event loop"); @@ -1039,7 +1034,7 @@ impl ApplicationHandler for App } let Some((window, window_settings)) = - self.windows.get(&WindowId::from_inner(window_id)) + self.windows.get(WindowId::from_inner(window_id)) else { cold_path(); return; @@ -1166,54 +1161,6 @@ struct WindowSettings cursor_grab_mode: CursorGrabMode, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -enum NativeMonitorId -{ - #[cfg(windows)] - Windows(String), - - #[cfg(target_os = "linux")] - X11(u32), - - #[cfg(target_os = "linux")] - Wayland(u32), -} - -fn get_monitor_native_id( - monitor: &WinitMonitorHandle, - #[allow(unused)] // Only used when target OS is linux - event_loop: &ActiveEventLoop, -) -> NativeMonitorId -{ - cfg_select! { - windows => { - use winit::platform::windows::MonitorHandleExtWindows; - - NativeMonitorId::Windows(monitor.native_id()) - } - target_os = "linux" => { - use winit::platform::wayland::{ - ActiveEventLoopExtWayland, - MonitorHandleExtWayland, - }; - use winit::platform::x11::MonitorHandleExtX11; - - if event_loop.is_wayland() { - NativeMonitorId::Wayland( - <WinitMonitorHandle as MonitorHandleExtWayland>::native_id(monitor), - ) - } else { - NativeMonitorId::X11( - <WinitMonitorHandle as MonitorHandleExtX11>::native_id(monitor), - ) - } - } - _ => { - compile_error!("Unsupported target platform") - } - } -} - fn iter_array_queue<Item>( queue: &ArrayQueue<Item>, ) -> impl Iterator<Item = Item> + use<'_, Item> diff --git a/engine/src/windowing/mouse.rs b/engine/src/windowing/mouse.rs index f6087f4..3a43e79 100644 --- a/engine/src/windowing/mouse.rs +++ b/engine/src/windowing/mouse.rs @@ -106,6 +106,25 @@ pub enum Button Other(u16), } +impl intmap::IntKey for Button +{ + type Int = u32; + + const PRIME: Self::Int = <u32 as intmap::IntKey>::PRIME; + + fn into_int(self) -> Self::Int + { + match &self { + Self::Left => 0, + Self::Right => 1, + Self::Middle => 2, + Self::Back => 3, + Self::Forward => 4, + Self::Other(other) => 5 + *other as u32, + } + } +} + impl From<winit::event::MouseButton> for Button { fn from(mouse_button: winit::event::MouseButton) -> Self diff --git a/engine/src/windowing/window.rs b/engine/src/windowing/window.rs index 54c24ac..6d7a464 100644 --- a/engine/src/windowing/window.rs +++ b/engine/src/windowing/window.rs @@ -13,6 +13,18 @@ pub struct Id inner: winit::window::WindowId, } +impl intmap::IntKey for Id +{ + type Int = u64; + + const PRIME: Self::Int = <u64 as intmap::IntKey>::PRIME; + + fn into_int(self) -> Self::Int + { + self.inner.into() + } +} + impl Id { pub(crate) fn from_inner(inner: winit::window::WindowId) -> Self |
