summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-09-01 18:24:39 +0200
committerHampusM <hampus@hampusmat.com>2026-09-01 18:24:39 +0200
commit12f7283b34b9504cafe9448ede110b1fc2a3ae41 (patch)
tree529644b6722382e14461c41f28ae42f2f5404132
parent632a7188ea267c93b5317ceffd18f1dab0e97cbe (diff)
refactor(engine): replace MapVec with intmap crate
-rw-r--r--Cargo.lock7
-rw-r--r--engine/Cargo.toml1
-rw-r--r--engine/src/rendering/backend/opengl.rs21
-rw-r--r--engine/src/ui/dear_imgui.rs22
-rw-r--r--engine/src/util.rs135
-rw-r--r--engine/src/windowing.rs111
-rw-r--r--engine/src/windowing/mouse.rs19
-rw-r--r--engine/src/windowing/window.rs12
8 files changed, 103 insertions, 225 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7dc3324..0f35427 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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