feat(openxr): Monado playspace mover

Co-authored-by: RinLovesYou <xxklintan123xx@gmail.com>
This commit is contained in:
galister
2024-06-03 11:04:45 +09:00
parent 009626704c
commit 4a45683650
6 changed files with 249 additions and 2 deletions

View File

@@ -1,6 +1,9 @@
use std::path::PathBuf;
use anyhow::{bail, ensure};
use glam::{Affine3A, Quat, Vec3, Vec3A};
use openxr as xr;
use sysinfo::Process;
use xr::OverlaySessionCreateFlagsEXTX;
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
@@ -169,3 +172,44 @@ pub(super) fn transform_to_posef(transform: &Affine3A) -> xr::Posef {
let rotation = transform_to_norm_quat(transform);
translation_rotation_to_posef(translation, rotation)
}
pub(super) fn find_libmonado() -> anyhow::Result<libloading::Library> {
//check env var first
if let Ok(path) = std::env::var("LIBMONADO_PATH") {
let path = PathBuf::from(path);
if path.exists() {
return Ok(unsafe { libloading::Library::new(path)? });
} else {
bail!("LIBMONADO_PATH points to a non-existing file.");
}
}
const PROC_NAMES: [&str; 1] = ["monado-service"];
let mut system = sysinfo::System::new();
system.refresh_processes();
for p in system.processes().values() {
for proc_name in PROC_NAMES.iter() {
if p.name().contains(proc_name) {
if let Some(lib) = proc_load_libmonado(p) {
return Ok(lib);
}
}
}
}
bail!("Could not find libmonado.");
}
fn proc_load_libmonado(proc: &Process) -> Option<libloading::Library> {
let path = proc
.exe()?
.parent()?
.parent()?
.join("lib")
.join("libmonado.so");
if path.exists() {
Some(unsafe { libloading::Library::new(path).ok()? })
} else {
None
}
}

View File

@@ -51,6 +51,7 @@ pub(super) struct OpenXrHandSource {
action_scroll: xr::Action<f32>,
action_alt_click: xr::Action<f32>,
action_show_hide: xr::Action<bool>,
action_space_drag: xr::Action<bool>,
action_click_modifier_right: xr::Action<bool>,
action_click_modifier_middle: xr::Action<bool>,
action_move_mouse: xr::Action<bool>,
@@ -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::<bool>(
&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,
})
}
}
@@ -380,6 +393,10 @@ fn suggest_bindings(
&hands[1].action_move_mouse,
instance.string_to_path("/user/hand/right/input/trigger/touch")?,
),
xr::Binding::new(
&hands[0].action_space_drag,
instance.string_to_path("/user/hand/left/input/menu/click")?,
),
xr::Binding::new(
&hands[0].action_haptics,
instance.string_to_path("/user/hand/left/output/haptic")?,
@@ -439,6 +456,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")?,

View File

@@ -32,6 +32,7 @@ mod helpers;
mod input;
mod lines;
mod overlay;
mod playspace;
mod swapchain;
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
@@ -72,6 +73,9 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
notifications.run_udp();
let mut delete_queue = vec![];
let mut space_mover = playspace::PlayspaceMover::try_new()
.map_err(|e| log::warn!("Failed to initialize Monado playspace mover: {}", e))
.ok();
#[cfg(feature = "osc")]
let mut osc_sender =
@@ -204,6 +208,9 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
}
watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic
if let Some(ref mut space_mover) = space_mover {
space_mover.update(&mut overlays, &app_state);
}
for o in overlays.iter_mut() {
o.after_input(&mut app_state)?;

View File

@@ -0,0 +1,98 @@
use std::ffi::c_void;
use glam::Vec3A;
use libloading::{Library, Symbol};
use crate::{backend::common::OverlayContainer, state::AppState};
use super::{helpers, input::DoubleClickCounter, overlay::OpenXrOverlayData};
pub(super) struct PlayspaceMover {
drag_hand: Option<usize>,
offset: Vec3A,
start_position: Vec3A,
double_click_counter: DoubleClickCounter,
libmonado: Library,
mnd_root: *mut c_void,
playspace_move: extern "C" fn(*mut c_void, f32, f32, f32) -> i32,
}
impl PlayspaceMover {
pub fn try_new() -> anyhow::Result<Self> {
unsafe {
let libmonado = helpers::find_libmonado()?;
let root_create: Symbol<extern "C" fn(*mut *mut c_void) -> i32> =
libmonado.get(b"mnd_root_create\0")?;
let playspace_move: Symbol<extern "C" fn(*mut c_void, f32, f32, f32) -> i32> =
libmonado.get(b"mnd_root_playspace_move\0")?;
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 {
anyhow::bail!("Failed to create root, code: {}", ret);
}
Ok(Self {
drag_hand: None,
offset: Vec3A::ZERO,
start_position: Vec3A::ZERO,
double_click_counter: DoubleClickCounter::new(),
libmonado,
mnd_root: root,
playspace_move: playspace_move_raw,
})
}
}
pub fn update(&mut self, overlays: &mut OverlayContainer<OpenXrOverlayData>, state: &AppState) {
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 {
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
if pointer.now.space_drag
&& !pointer.before.space_drag
&& self.double_click_counter.click()
{
self.drag_hand = Some(i);
self.start_position = pointer.pose.translation;
break;
}
}
}
}
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);
}
}