feat: add Tracked Interface to dbus to allow clients to query the tracking state of controllers/hands
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
@@ -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,19 +40,19 @@ pub struct SkController {
|
||||
material: Material,
|
||||
capture_manager: CaptureManager,
|
||||
datamap: ControllerDatamap,
|
||||
tracked: ObjectHandle<Tracked>,
|
||||
}
|
||||
impl SkController {
|
||||
pub fn new(connection: &Connection, handed: Handed) -> Result<Self> {
|
||||
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 model = Model::copy(Model::from_memory(
|
||||
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"),
|
||||
None,
|
||||
@@ -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(),
|
||||
|
||||
@@ -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<InputMethod>,
|
||||
capture_manager: CaptureManager,
|
||||
datamap: HandDatamap,
|
||||
tracked: ObjectHandle<Tracked>,
|
||||
}
|
||||
impl SkHand {
|
||||
pub fn new(connection: &Connection, handed: Handed) -> Result<Self> {
|
||||
@@ -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]);
|
||||
|
||||
@@ -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<I: Interface>(Connection, OwnedObjectPath, PhantomData<I>);
|
||||
|
||||
impl<I: Interface> Clone for ObjectHandle<I> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone(), self.1.clone(), PhantomData::default())
|
||||
}
|
||||
}
|
||||
impl<I: Interface> Drop for ObjectHandle<I> {
|
||||
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<Tracked> {
|
||||
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<Tracked> {
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user