From 3fe538488cc3c6898efdea3b3ee2d5c7f883e0b2 Mon Sep 17 00:00:00 2001 From: Sarah Date: Mon, 29 Apr 2024 18:43:04 +0200 Subject: [PATCH] initial naive playspace mover impl --- Cargo.lock | 1 + Cargo.toml | 1 + src/backend/openxr/input.rs | 17 ++++ src/backend/openxr/mod.rs | 3 + src/backend/openxr/playspace.rs | 134 ++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+) create mode 100644 src/backend/openxr/playspace.rs diff --git a/Cargo.lock b/Cargo.lock index 23b0d3d..c97285b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4250,6 +4250,7 @@ dependencies = [ "json", "json5", "libc", + "libloading 0.8.3", "log", "log-panics", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 4e4c112..c82c68b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ input-linux = "0.6.0" json = { version = "0.12.4", optional = true } json5 = "0.4.1" libc = "0.2.153" +libloading = "0.8.3" log = "0.4.21" once_cell = "1.19.0" openxr = { version = "0.17.1", features = ["linked"], optional = true } diff --git a/src/backend/openxr/input.rs b/src/backend/openxr/input.rs index bcc2ef3..f291b12 100644 --- a/src/backend/openxr/input.rs +++ b/src/backend/openxr/input.rs @@ -51,6 +51,7 @@ pub(super) struct OpenXrHandSource { action_scroll: xr::Action, action_alt_click: xr::Action, action_show_hide: xr::Action, + action_space_drag: xr::Action, action_click_modifier_right: xr::Action, action_click_modifier_middle: xr::Action, action_move_mouse: xr::Action, @@ -201,6 +202,12 @@ impl OpenXrHand { .state(&xr.session, xr::Path::NULL)? .current_state; + pointer.now.space_drag = self + .source + .action_space_drag + .state(&xr.session, xr::Path::NULL)? + .current_state; + Ok(()) } } @@ -259,6 +266,11 @@ impl OpenXrHandSource { &format!("{} hand haptics", side), &[], )?; + let action_space_drag = action_set.create_action::( + &format!("{}_space_drag", side), + &format!("{} hand space drag", side), + &[], + )?; Ok(Self { action_pose, @@ -271,6 +283,7 @@ impl OpenXrHandSource { action_click_modifier_middle, action_move_mouse, action_haptics, + action_space_drag, }) } } @@ -439,6 +452,10 @@ fn suggest_bindings( &hands[0].action_show_hide, instance.string_to_path("/user/hand/left/input/b/click")?, ), + xr::Binding::new( + &hands[1].action_space_drag, + instance.string_to_path("/user/hand/right/input/b/click")?, + ), xr::Binding::new( &hands[0].action_click_modifier_right, instance.string_to_path("/user/hand/left/input/b/touch")?, diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index c409564..5cc750c 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -33,6 +33,7 @@ mod input; mod lines; mod overlay; mod swapchain; +mod playspace; const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO; const VIEW_COUNT: u32 = 2; @@ -72,6 +73,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { notifications.run_udp(); let mut delete_queue = vec![]; + let mut space_mover = playspace::PlayspaceMover::new(); #[cfg(feature = "osc")] let mut osc_sender = @@ -204,6 +206,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { } watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic + space_mover.update(&mut overlays, &app_state); for o in overlays.iter_mut() { o.after_input(&mut app_state)?; diff --git a/src/backend/openxr/playspace.rs b/src/backend/openxr/playspace.rs new file mode 100644 index 0000000..85c6f66 --- /dev/null +++ b/src/backend/openxr/playspace.rs @@ -0,0 +1,134 @@ +use std::ffi::c_void; + +use glam::Vec3A; +use libloading::{Library, Symbol}; + +use crate::{ + backend::common::OverlayContainer, + state::AppState, +}; + +use super::overlay::OpenXrOverlayData; + +pub(super) struct PlayspaceMover { + drag_hand: Option, + offset: Vec3A, + start_position: Vec3A, + + has_pressed: bool, + has_unpressed: bool, + pressed_timer: std::time::Instant, + + libmonado: Library, + mnd_root: *mut c_void, + playspace_move: extern "C" fn(*mut c_void, f32, f32, f32) -> i32, +} + +impl PlayspaceMover { + pub fn new() -> Self { + unsafe { + //user currently has to manually specify this. ex: LIBMONADO_PATH="/home/sarah/.local/share/envision/prefixes/c6cea4c7-69d5-4a36-af9d-ddf14e1222a6/lib/libmonado.so" + let libmonado_path = std::env::var("LIBMONADO_PATH"); + let libmonado_path = match libmonado_path { + Ok(path) => path, + Err(_) => { + log::error!("please specify the path to libmonado.so using the LIBMONADO_PATH environment variable."); + std::process::exit(1); + } + }; + + let libmonado = Library::new(libmonado_path).unwrap(); + let root_create: Symbol i32> = + libmonado.get(b"mnd_root_create").unwrap(); + let playspace_move: Symbol i32> = + libmonado.get(b"mnd_root_playspace_move").unwrap(); + let playspace_move_raw = *playspace_move; + + let mut root: *mut c_void = std::ptr::null_mut(); + + let ret = root_create(&mut root); + + if ret != 0 { + log::error!("Failed to create root, error code: {}", ret); + } + + Self { + drag_hand: None, + offset: Vec3A::ZERO, + start_position: Vec3A::ZERO, + + has_pressed: false, + has_unpressed: false, + pressed_timer: std::time::Instant::now(), + + libmonado, + mnd_root: root, + playspace_move: playspace_move_raw, + } + } + } + + pub fn update(&mut self, overlays: &mut OverlayContainer, state: &AppState) { + if self.has_unpressed { + if self.pressed_timer.elapsed().as_secs_f32() > 0.2 { + self.has_unpressed = false; + self.has_pressed = false; + } + } + + if let Some(hand) = self.drag_hand { + let pointer = &state.input_state.pointers[hand]; + if !pointer.now.space_drag { + self.drag_hand = None; + log::info!("End space drag"); + return; + } + + let hand_pos = state.input_state.pointers[hand].pose.translation; + let relative_pos = hand_pos - self.start_position; + + overlays.iter_mut().for_each(|overlay| { + if overlay.state.grabbable { + overlay.state.dirty = true; + overlay.state.transform.translation += relative_pos * -1.0; + } + }); + + self.offset += relative_pos; + self.apply_offset(); + } else { + let mut pressed = false; + for (i, pointer) in state.input_state.pointers.iter().enumerate() { + if pointer.now.space_drag { + pressed = true; + if !self.has_pressed { + self.has_pressed = true; + break; + } + + if self.has_pressed && self.has_unpressed { + self.drag_hand = Some(i); + self.start_position = pointer.pose.translation; + self.has_pressed = false; + self.has_unpressed = false; + break; + } + } + } + + if !pressed && self.has_pressed && !self.has_unpressed { + self.has_unpressed = true; + self.pressed_timer = std::time::Instant::now(); + } + } + } + + pub fn reset(&mut self) { + self.offset = Vec3A::ZERO; + self.start_position = Vec3A::ZERO; + } + + fn apply_offset(&mut self) { + (self.playspace_move)(self.mnd_root, self.offset.x, self.offset.y, self.offset.z); + } +}