From 9ec6d31d678df8f8d0bd4fb0cc75c3c5631625b9 Mon Sep 17 00:00:00 2001 From: Nova Date: Fri, 2 Dec 2022 11:09:23 -0500 Subject: [PATCH] fix(input): O(n log n) instead of O(n^2) --- src/nodes/input/hand.rs | 5 +++- src/nodes/input/mod.rs | 51 ++++++++++++++++++++++++-------------- src/nodes/input/pointer.rs | 9 +++++-- src/nodes/input/tip.rs | 5 +++- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/nodes/input/hand.rs b/src/nodes/input/hand.rs index 8800dea..9e231c9 100644 --- a/src/nodes/input/hand.rs +++ b/src/nodes/input/hand.rs @@ -11,7 +11,10 @@ pub struct Hand { pub base: FlatHand, } impl InputSpecialization for Hand { - fn distance(&self, space: &Arc, field: &Field) -> f32 { + fn compare_distance(&self, space: &Arc, field: &Field) -> f32 { + self.true_distance(space, field).abs() + } + fn true_distance(&self, space: &Arc, field: &Field) -> f32 { let mut min_distance = f32::MAX; for tip in [ diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index fc41c89..3757338 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -29,7 +29,8 @@ static INPUT_METHOD_REGISTRY: Registry = Registry::new(); static INPUT_HANDLER_REGISTRY: Registry = Registry::new(); pub trait InputSpecialization: Send + Sync { - fn distance(&self, space: &Arc, field: &Field) -> f32; + fn compare_distance(&self, space: &Arc, field: &Field) -> f32; + fn true_distance(&self, space: &Arc, field: &Field) -> f32; fn serialize( &self, distance_link: &DistanceLink, @@ -108,8 +109,13 @@ impl InputMethod { Ok(()) } - fn distance(&self, to: &Field) -> f32 { - self.specialization.lock().distance(&self.spatial, to) + fn compare_distance(&self, to: &Field) -> f32 { + self.specialization + .lock() + .compare_distance(&self.spatial, to) + } + fn true_distance(&self, to: &Field) -> f32 { + self.specialization.lock().true_distance(&self.spatial, to) } } impl Drop for InputMethod { @@ -128,7 +134,7 @@ impl DistanceLink { fn from(method: Arc, handler: Arc) -> Option { let handler_field = handler.field.upgrade()?; Some(DistanceLink { - distance: method.distance(&handler_field), + distance: method.compare_distance(&handler_field), method, handler, handler_field, @@ -147,7 +153,9 @@ impl DistanceLink { let root = InputData { uid: self.method.uid.clone(), input, - distance: self.distance, + distance: self + .method + .true_distance(&self.handler.field.upgrade().unwrap()), datamap, }; root.serialize() @@ -237,42 +245,47 @@ pub fn create_input_handler_flex( InputHandler::add_to(&node, &field)?; Ok(()) } - pub fn process_input() { + // Iterate over all valid input methods for method in INPUT_METHOD_REGISTRY .get_valid_contents() .into_iter() .filter(|method| *method.enabled.lock()) .filter(|method| method.datamap.lock().is_some()) { + // Get all valid input handlers and convert them to DistanceLink objects let mut distance_links: Vec = INPUT_HANDLER_REGISTRY .get_valid_contents() .into_iter() .filter(|handler| handler.field.upgrade().is_some()) .filter_map(|handler| DistanceLink::from(method.clone(), handler)) .collect(); - distance_links.sort_unstable_by(|a, b| { - a.distance - .abs() - .partial_cmp(&b.distance.abs()) - .unwrap() - .reverse() - }); - let mut last_distance = 0.0; + // Sort the distance links by their distance in ascending order + distance_links + .sort_unstable_by(|a, b| a.distance.abs().partial_cmp(&b.distance.abs()).unwrap()); + + // Get the current frame let frame = FRAME.load(Ordering::Relaxed); + + // Get the list of captured input handlers for this method let captures = method.captures.get_valid_contents(); + + // Iterate over the distance links and send input to them for distance_link in distance_links { distance_link.send_input(frame, method.datamap.lock().clone().unwrap()); - if last_distance != distance_link.distance - && captures - .iter() - .any(|c| Arc::ptr_eq(c, &distance_link.handler)) + + // If the current distance link is in the list of captured input handlers, + // break out of the loop to avoid sending input to the remaining distance links + if captures + .iter() + .any(|c| Arc::ptr_eq(c, &distance_link.handler)) { break; } - last_distance = distance_link.distance; } + + // Clear the list of captured input handlers for this method method.captures.clear(); } } diff --git a/src/nodes/input/pointer.rs b/src/nodes/input/pointer.rs index 6586abb..54d9515 100644 --- a/src/nodes/input/pointer.rs +++ b/src/nodes/input/pointer.rs @@ -26,8 +26,13 @@ impl Pointer { } impl InputSpecialization for Pointer { - fn distance(&self, space: &Arc, field: &Field) -> f32 { - self.ray_march(space, field).min_distance + fn compare_distance(&self, space: &Arc, field: &Field) -> f32 { + let ray_info = self.ray_march(space, field); + ray_info.deepest_point_distance.hypot(ray_info.min_distance) + } + fn true_distance(&self, space: &Arc, field: &Field) -> f32 { + let ray_info = self.ray_march(space, field); + ray_info.min_distance } fn serialize( &self, diff --git a/src/nodes/input/tip.rs b/src/nodes/input/tip.rs index eea929b..893003d 100644 --- a/src/nodes/input/tip.rs +++ b/src/nodes/input/tip.rs @@ -25,7 +25,10 @@ impl Tip { } } impl InputSpecialization for Tip { - fn distance(&self, space: &Arc, field: &Field) -> f32 { + fn compare_distance(&self, space: &Arc, field: &Field) -> f32 { + field.distance(space, vec3a(0.0, 0.0, 0.0)).abs() + } + fn true_distance(&self, space: &Arc, field: &Field) -> f32 { field.distance(space, vec3a(0.0, 0.0, 0.0)) } fn serialize(