From 878dc02c22406759eeeff6ac024870c9f4cbd3a0 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Mon, 24 Feb 2025 10:13:20 +0100 Subject: [PATCH 1/2] feat: add Tracked Interface to dbus to allow clients to query the tracking state of controllers/hands Signed-off-by: Schmarni --- src/objects/input/sk_controller.rs | 29 ++++++++++----- src/objects/input/sk_hand.rs | 22 ++++++++++- src/objects/mod.rs | 60 +++++++++++++++++++++++++++++- 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/objects/input/sk_controller.rs b/src/objects/input/sk_controller.rs index 6ef4f5f..4d21ff4 100644 --- a/src/objects/input/sk_controller.rs +++ b/src/objects/input/sk_controller.rs @@ -7,7 +7,7 @@ use crate::{ input::{INPUT_HANDLER_REGISTRY, InputDataType, InputHandler, InputMethod, Tip}, spatial::Spatial, }, - objects::{ObjectHandle, SpatialRef}, + objects::{ObjectHandle, SpatialRef, Tracked}, }; use color_eyre::eyre::Result; use glam::{Mat4, Vec2, Vec3}; @@ -40,18 +40,18 @@ pub struct SkController { material: Material, capture_manager: CaptureManager, datamap: ControllerDatamap, + tracked: ObjectHandle, } impl SkController { pub fn new(connection: &Connection, handed: Handed) -> Result { Input::set_controller_model(handed, Some(Model::new())); - let (spatial, object_handle) = SpatialRef::create( - connection, - &("/org/stardustxr/Controller/".to_string() - + match handed { - Handed::Left => "left", - _ => "right", - }), - ); + let path = "/org/stardustxr/Controller/".to_string() + + match handed { + Handed::Left => "left", + _ => "right", + }; + let (spatial, object_handle) = SpatialRef::create(connection, &path); + let tracked = Tracked::new(connection, &path); let model = Model::copy(&Model::from_memory( "cursor.glb", include_bytes!("cursor.glb"), @@ -75,13 +75,22 @@ impl SkController { material, capture_manager: CaptureManager::default(), datamap: Default::default(), + tracked, }) } pub fn update(&mut self, token: &MainThreadToken) { let controller = Input::controller(self.handed); let input_node = self.input.spatial.node().unwrap(); input_node.set_enabled(controller.tracked.is_active()); - if input_node.enabled() { + let enabled = input_node.enabled(); + tokio::spawn({ + // this is suboptimal since it probably allocates a fresh string every frame + let handle = self.tracked.clone(); + async move { + handle.set_tracked(enabled).await; + } + }); + if enabled { let world_transform = Mat4::from_rotation_translation( controller.aim.orientation.into(), controller.aim.position.into(), diff --git a/src/objects/input/sk_hand.rs b/src/objects/input/sk_hand.rs index a082541..dcc1043 100644 --- a/src/objects/input/sk_hand.rs +++ b/src/objects/input/sk_hand.rs @@ -7,7 +7,7 @@ use crate::nodes::{ input::{Hand, InputMethod, Joint}, spatial::Spatial, }; -use crate::objects::{ObjectHandle, SpatialRef}; +use crate::objects::{ObjectHandle, SpatialRef, Tracked}; use color_eyre::eyre::Result; use glam::{Mat4, Quat, Vec3}; use serde::{Deserialize, Serialize}; @@ -44,6 +44,7 @@ pub struct SkHand { input: Arc, capture_manager: CaptureManager, datamap: HandDatamap, + tracked: ObjectHandle, } impl SkHand { pub fn new(connection: &Connection, handed: Handed) -> Result { @@ -55,6 +56,14 @@ impl SkHand { _ => "right", } + "/palm"), ); + let tracked = Tracked::new( + connection, + &("/org/stardustxr/Hand/".to_string() + + match handed { + Handed::Left => "left", + _ => "right", + }), + ); let _node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph_owned()?; Spatial::add_to(&_node.0, None, Mat4::IDENTITY, false); let hand = InputDataType::Hand(Hand { @@ -71,6 +80,7 @@ impl SkHand { palm_object, handed, input, + tracked, capture_manager: CaptureManager::default(), datamap: Default::default(), }) @@ -84,7 +94,15 @@ impl SkHand { (real_hand || sk.get_active_display_mode() == DisplayMode::Flatscreen) && sk_hand.tracked.is_active(), ); - if input_node.enabled() { + let enabled = input_node.enabled(); + tokio::spawn({ + // this is suboptimal since it probably allocates a fresh string every frame + let handle = self.tracked.clone(); + async move { + handle.set_tracked(enabled).await; + } + }); + if enabled { hand.thumb.tip = convert_joint(sk_hand.fingers[0][4]); hand.thumb.distal = convert_joint(sk_hand.fingers[0][3]); hand.thumb.proximal = convert_joint(sk_hand.fingers[0][2]); diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 1fc917f..bd14ed4 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -14,8 +14,12 @@ use input::{ sk_hand::SkHand, }; use play_space::PlaySpaceBounds; +use portable_atomic::AtomicBool; use stardust_xr::schemas::dbus::object_registry::ObjectRegistry; -use std::{marker::PhantomData, sync::Arc}; +use std::{ + marker::PhantomData, + sync::{atomic::Ordering, Arc}, +}; use stereokit_rust::{ material::Material, sk::{DisplayMode, MainThreadToken, Sk}, @@ -200,6 +204,12 @@ impl ServerObjects { } pub struct ObjectHandle(Connection, OwnedObjectPath, PhantomData); + +impl Clone for ObjectHandle { + fn clone(&self) -> Self { + Self(self.0.clone(), self.1.clone(), PhantomData::default()) + } +} impl Drop for ObjectHandle { fn drop(&mut self) { let connection = self.0.clone(); @@ -247,6 +257,54 @@ impl SpatialRef { } } +pub struct Tracked(bool); +impl Tracked { + pub fn new(connection: &Connection, path: &str) -> ObjectHandle { + let bool = Arc::new(AtomicBool::new(false)); + tokio::task::spawn({ + let connection = connection.clone(); + let path = path.to_string(); + let bool = bool.clone(); + async move { + connection + .object_server() + .at(path, Self(false)) + .await + .unwrap(); + } + }); + ObjectHandle( + connection.clone(), + OwnedObjectPath::try_from(path.to_string()).unwrap(), + PhantomData, + ) + } +} +impl ObjectHandle { + pub async fn set_tracked(&self, is_tracked: bool) -> zbus::Result<()> { + let tracked_ref = self + .0 + .object_server() + .interface::<_, Tracked>(self.1.as_ref()) + .await?; + let mut tracked = tracked_ref.get_mut().await; + if tracked.0 != is_tracked { + tracked.0 = is_tracked; + tracked + .is_tracked_changed(tracked_ref.signal_emitter()) + .await; + } + Ok(()) + } +} +#[interface(name = "org.stardustxr.Tracked")] +impl Tracked { + #[zbus(property)] + fn is_tracked(&self) -> bool { + self.0 + } +} + pub struct FieldRef(u64, OwnedNode); impl FieldRef { pub fn create( -- 2.49.1 From ecf55fb4b565a8950b47498e21086250105cfe67 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Tue, 25 Feb 2025 00:53:34 +0100 Subject: [PATCH 2/2] refactor: remove unneeded AtomicBool Signed-off-by: Schmarni --- src/objects/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/objects/mod.rs b/src/objects/mod.rs index bd14ed4..d7495e9 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -14,7 +14,6 @@ use input::{ sk_hand::SkHand, }; use play_space::PlaySpaceBounds; -use portable_atomic::AtomicBool; use stardust_xr::schemas::dbus::object_registry::ObjectRegistry; use std::{ marker::PhantomData, @@ -207,7 +206,7 @@ pub struct ObjectHandle(Connection, OwnedObjectPath, PhantomData Clone for ObjectHandle { fn clone(&self) -> Self { - Self(self.0.clone(), self.1.clone(), PhantomData::default()) + Self(self.0.clone(), self.1.clone(), PhantomData) } } impl Drop for ObjectHandle { @@ -260,11 +259,9 @@ impl SpatialRef { pub struct Tracked(bool); impl Tracked { pub fn new(connection: &Connection, path: &str) -> ObjectHandle { - let bool = Arc::new(AtomicBool::new(false)); tokio::task::spawn({ let connection = connection.clone(); let path = path.to_string(); - let bool = bool.clone(); async move { connection .object_server() -- 2.49.1