feat(openxr): Monado playspace mover
Co-authored-by: RinLovesYou <xxklintan123xx@gmail.com>
This commit is contained in:
77
Cargo.lock
generated
77
Cargo.lock
generated
@@ -1040,7 +1040,7 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"windows",
|
"windows 0.54.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1052,6 +1052,25 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
@@ -2302,6 +2321,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.49.0"
|
version = "0.49.0"
|
||||||
@@ -2850,6 +2878,26 @@ version = "0.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@@ -3304,6 +3352,21 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sysinfo"
|
||||||
|
version = "0.30.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"ntapi",
|
||||||
|
"once_cell",
|
||||||
|
"rayon",
|
||||||
|
"windows 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "6.2.2"
|
version = "6.2.2"
|
||||||
@@ -3914,6 +3977,16 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.52.0",
|
||||||
|
"windows-targets 0.52.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.54.0"
|
version = "0.54.0"
|
||||||
@@ -4250,6 +4323,7 @@ dependencies = [
|
|||||||
"json",
|
"json",
|
||||||
"json5",
|
"json5",
|
||||||
"libc",
|
"libc",
|
||||||
|
"libloading 0.8.3",
|
||||||
"log",
|
"log",
|
||||||
"log-panics",
|
"log-panics",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -4263,6 +4337,7 @@ dependencies = [
|
|||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"strum",
|
"strum",
|
||||||
|
"sysinfo",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"vulkano",
|
"vulkano",
|
||||||
"vulkano-shaders",
|
"vulkano-shaders",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ input-linux = "0.6.0"
|
|||||||
json = { version = "0.12.4", optional = true }
|
json = { version = "0.12.4", optional = true }
|
||||||
json5 = "0.4.1"
|
json5 = "0.4.1"
|
||||||
libc = "0.2.153"
|
libc = "0.2.153"
|
||||||
|
libloading = "0.8.3"
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
openxr = { version = "0.17.1", features = ["linked"], optional = true }
|
openxr = { version = "0.17.1", features = ["linked"], optional = true }
|
||||||
@@ -48,6 +49,7 @@ serde_json = "1.0.113"
|
|||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
smallvec = "1.11.0"
|
smallvec = "1.11.0"
|
||||||
strum = { version = "0.26.2", features = ["derive"] }
|
strum = { version = "0.26.2", features = ["derive"] }
|
||||||
|
sysinfo = { version = "0.30.0", optional = true }
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
||||||
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
||||||
@@ -59,7 +61,7 @@ log-panics = { version = "2.1.0", features = ["with-backtrace"] }
|
|||||||
[features]
|
[features]
|
||||||
default = ["openvr", "openxr", "osc", "x11", "wayland"]
|
default = ["openvr", "openxr", "osc", "x11", "wayland"]
|
||||||
openvr = ["dep:ovr_overlay", "dep:json"]
|
openvr = ["dep:ovr_overlay", "dep:json"]
|
||||||
openxr = ["dep:openxr"]
|
openxr = ["dep:openxr", "dep:sysinfo"]
|
||||||
osc = ["dep:rosc"]
|
osc = ["dep:rosc"]
|
||||||
x11 = ["wlx-capture/xshm"]
|
x11 = ["wlx-capture/xshm"]
|
||||||
wayland = ["wlx-capture/pipewire", "wlx-capture/wlr"]
|
wayland = ["wlx-capture/pipewire", "wlx-capture/wlr"]
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::{bail, ensure};
|
use anyhow::{bail, ensure};
|
||||||
use glam::{Affine3A, Quat, Vec3, Vec3A};
|
use glam::{Affine3A, Quat, Vec3, Vec3A};
|
||||||
use openxr as xr;
|
use openxr as xr;
|
||||||
|
use sysinfo::Process;
|
||||||
use xr::OverlaySessionCreateFlagsEXTX;
|
use xr::OverlaySessionCreateFlagsEXTX;
|
||||||
|
|
||||||
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
|
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);
|
let rotation = transform_to_norm_quat(transform);
|
||||||
translation_rotation_to_posef(translation, rotation)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ pub(super) struct OpenXrHandSource {
|
|||||||
action_scroll: xr::Action<f32>,
|
action_scroll: xr::Action<f32>,
|
||||||
action_alt_click: xr::Action<f32>,
|
action_alt_click: xr::Action<f32>,
|
||||||
action_show_hide: xr::Action<bool>,
|
action_show_hide: xr::Action<bool>,
|
||||||
|
action_space_drag: xr::Action<bool>,
|
||||||
action_click_modifier_right: xr::Action<bool>,
|
action_click_modifier_right: xr::Action<bool>,
|
||||||
action_click_modifier_middle: xr::Action<bool>,
|
action_click_modifier_middle: xr::Action<bool>,
|
||||||
action_move_mouse: xr::Action<bool>,
|
action_move_mouse: xr::Action<bool>,
|
||||||
@@ -201,6 +202,12 @@ impl OpenXrHand {
|
|||||||
.state(&xr.session, xr::Path::NULL)?
|
.state(&xr.session, xr::Path::NULL)?
|
||||||
.current_state;
|
.current_state;
|
||||||
|
|
||||||
|
pointer.now.space_drag = self
|
||||||
|
.source
|
||||||
|
.action_space_drag
|
||||||
|
.state(&xr.session, xr::Path::NULL)?
|
||||||
|
.current_state;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,6 +266,11 @@ impl OpenXrHandSource {
|
|||||||
&format!("{} hand haptics", side),
|
&format!("{} hand haptics", side),
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
|
let action_space_drag = action_set.create_action::<bool>(
|
||||||
|
&format!("{}_space_drag", side),
|
||||||
|
&format!("{} hand space drag", side),
|
||||||
|
&[],
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
action_pose,
|
action_pose,
|
||||||
@@ -271,6 +283,7 @@ impl OpenXrHandSource {
|
|||||||
action_click_modifier_middle,
|
action_click_modifier_middle,
|
||||||
action_move_mouse,
|
action_move_mouse,
|
||||||
action_haptics,
|
action_haptics,
|
||||||
|
action_space_drag,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,6 +393,10 @@ fn suggest_bindings(
|
|||||||
&hands[1].action_move_mouse,
|
&hands[1].action_move_mouse,
|
||||||
instance.string_to_path("/user/hand/right/input/trigger/touch")?,
|
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(
|
xr::Binding::new(
|
||||||
&hands[0].action_haptics,
|
&hands[0].action_haptics,
|
||||||
instance.string_to_path("/user/hand/left/output/haptic")?,
|
instance.string_to_path("/user/hand/left/output/haptic")?,
|
||||||
@@ -439,6 +456,10 @@ fn suggest_bindings(
|
|||||||
&hands[0].action_show_hide,
|
&hands[0].action_show_hide,
|
||||||
instance.string_to_path("/user/hand/left/input/b/click")?,
|
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(
|
xr::Binding::new(
|
||||||
&hands[0].action_click_modifier_right,
|
&hands[0].action_click_modifier_right,
|
||||||
instance.string_to_path("/user/hand/left/input/b/touch")?,
|
instance.string_to_path("/user/hand/left/input/b/touch")?,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ mod helpers;
|
|||||||
mod input;
|
mod input;
|
||||||
mod lines;
|
mod lines;
|
||||||
mod overlay;
|
mod overlay;
|
||||||
|
mod playspace;
|
||||||
mod swapchain;
|
mod swapchain;
|
||||||
|
|
||||||
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
|
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();
|
notifications.run_udp();
|
||||||
|
|
||||||
let mut delete_queue = vec![];
|
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")]
|
#[cfg(feature = "osc")]
|
||||||
let mut osc_sender =
|
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
|
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() {
|
for o in overlays.iter_mut() {
|
||||||
o.after_input(&mut app_state)?;
|
o.after_input(&mut app_state)?;
|
||||||
|
|||||||
98
src/backend/openxr/playspace.rs
Normal file
98
src/backend/openxr/playspace.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user