refactor(input): use idl
This commit is contained in:
@@ -199,72 +199,6 @@ impl Deref for Field {
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl FieldTrait for Field {
|
||||
// fn spatial_ref(&self) -> &Spatial {
|
||||
// match self {
|
||||
// Field::Box(field) => field.spatial_ref(),
|
||||
// Field::Cylinder(field) => field.spatial_ref(),
|
||||
// Field::Sphere(field) => field.spatial_ref(),
|
||||
// Field::Torus(field) => field.spatial_ref(),
|
||||
// }
|
||||
// }
|
||||
// fn local_distance(&self, p: Vec3A) -> f32 {
|
||||
// match self {
|
||||
// Field::Box(field) => field.local_distance(p),
|
||||
// Field::Cylinder(field) => field.local_distance(p),
|
||||
// Field::Sphere(field) => field.local_distance(p),
|
||||
// Field::Torus(field) => field.local_distance(p),
|
||||
// }
|
||||
// }
|
||||
// fn local_normal(&self, p: Vec3A, r: f32) -> Vec3A {
|
||||
// match self {
|
||||
// Field::Box(field) => field.local_normal(p, r),
|
||||
// Field::Cylinder(field) => field.local_normal(p, r),
|
||||
// Field::Sphere(field) => field.local_normal(p, r),
|
||||
// Field::Torus(field) => field.local_normal(p, r),
|
||||
// }
|
||||
// }
|
||||
// fn local_closest_point(&self, p: Vec3A, r: f32) -> Vec3A {
|
||||
// match self {
|
||||
// Field::Box(field) => field.local_closest_point(p, r),
|
||||
// Field::Cylinder(field) => field.local_closest_point(p, r),
|
||||
// Field::Sphere(field) => field.local_closest_point(p, r),
|
||||
// Field::Torus(field) => field.local_closest_point(p, r),
|
||||
// }
|
||||
// }
|
||||
// fn distance(&self, reference_space: &Spatial, p: Vec3A) -> f32 {
|
||||
// match self {
|
||||
// Field::Box(field) => field.distance(reference_space, p),
|
||||
// Field::Cylinder(field) => field.distance(reference_space, p),
|
||||
// Field::Sphere(field) => field.distance(reference_space, p),
|
||||
// Field::Torus(field) => field.distance(reference_space, p),
|
||||
// }
|
||||
// }
|
||||
// fn normal(&self, reference_space: &Spatial, p: Vec3A, r: f32) -> Vec3A {
|
||||
// match self {
|
||||
// Field::Box(field) => field.normal(reference_space, p, r),
|
||||
// Field::Cylinder(field) => field.normal(reference_space, p, r),
|
||||
// Field::Sphere(field) => field.normal(reference_space, p, r),
|
||||
// Field::Torus(field) => field.normal(reference_space, p, r),
|
||||
// }
|
||||
// }
|
||||
// fn closest_point(&self, reference_space: &Spatial, p: Vec3A, r: f32) -> Vec3A {
|
||||
// match self {
|
||||
// Field::Box(field) => field.closest_point(reference_space, p, r),
|
||||
// Field::Cylinder(field) => field.closest_point(reference_space, p, r),
|
||||
// Field::Sphere(field) => field.closest_point(reference_space, p, r),
|
||||
// Field::Torus(field) => field.closest_point(reference_space, p, r),
|
||||
// }
|
||||
// }
|
||||
// fn ray_march(&self, ray: Ray) -> RayMarchResult {
|
||||
// match self {
|
||||
// Field::Box(field) => field.ray_march(ray),
|
||||
// Field::Cylinder(field) => field.ray_march(ray),
|
||||
// Field::Sphere(field) => field.ray_march(ray),
|
||||
// Field::Torus(field) => field.ray_march(ray),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
create_interface!(FieldInterface, FieldInterfaceAspect, "/field");
|
||||
pub struct FieldInterface;
|
||||
|
||||
@@ -1,16 +1,57 @@
|
||||
use super::{DistanceLink, Finger, Hand, InputDataTrait, Joint, Thumb};
|
||||
use crate::nodes::fields::Field;
|
||||
use crate::nodes::spatial::Spatial;
|
||||
use glam::{vec3a, Mat4};
|
||||
use stardust_xr::schemas::flat::{Hand as FlatHand, InputDataType, Joint};
|
||||
use glam::{vec3a, Mat4, Quat};
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{DistanceLink, InputSpecialization};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Hand {
|
||||
pub base: FlatHand,
|
||||
impl Default for Joint {
|
||||
fn default() -> Self {
|
||||
Joint {
|
||||
position: [0.0; 3].into(),
|
||||
rotation: Quat::IDENTITY.into(),
|
||||
radius: 0.0,
|
||||
distance: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl InputSpecialization for Hand {
|
||||
impl Default for Finger {
|
||||
fn default() -> Self {
|
||||
Finger {
|
||||
tip: Default::default(),
|
||||
distal: Default::default(),
|
||||
intermediate: Default::default(),
|
||||
proximal: Default::default(),
|
||||
metacarpal: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Default for Thumb {
|
||||
fn default() -> Self {
|
||||
Thumb {
|
||||
tip: Default::default(),
|
||||
distal: Default::default(),
|
||||
proximal: Default::default(),
|
||||
metacarpal: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Default for Hand {
|
||||
fn default() -> Self {
|
||||
Hand {
|
||||
right: Default::default(),
|
||||
thumb: Default::default(),
|
||||
index: Default::default(),
|
||||
middle: Default::default(),
|
||||
ring: Default::default(),
|
||||
little: Default::default(),
|
||||
palm: Default::default(),
|
||||
wrist: Default::default(),
|
||||
elbow: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputDataTrait for Hand {
|
||||
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
|
||||
self.true_distance(space, field).abs()
|
||||
}
|
||||
@@ -18,34 +59,29 @@ impl InputSpecialization for Hand {
|
||||
let mut min_distance = f32::MAX;
|
||||
|
||||
for tip in [
|
||||
&self.base.thumb.tip.position,
|
||||
&self.base.index.tip.position,
|
||||
&self.base.middle.tip.position,
|
||||
&self.base.ring.tip.position,
|
||||
&self.base.little.tip.position,
|
||||
&self.thumb.tip.position,
|
||||
&self.index.tip.position,
|
||||
&self.middle.tip.position,
|
||||
&self.ring.tip.position,
|
||||
&self.little.tip.position,
|
||||
] {
|
||||
min_distance = min_distance.min(field.distance(space, vec3a(tip.x, tip.y, tip.z)));
|
||||
}
|
||||
|
||||
min_distance
|
||||
}
|
||||
fn serialize(
|
||||
&self,
|
||||
distance_link: &DistanceLink,
|
||||
local_to_handler_matrix: Mat4,
|
||||
) -> InputDataType {
|
||||
let mut hand = self.base;
|
||||
fn update_to(&mut self, distance_link: &DistanceLink, local_to_handler_matrix: Mat4) {
|
||||
let mut joints: Vec<&mut Joint> = Vec::new();
|
||||
|
||||
joints.extend([&mut hand.palm, &mut hand.wrist]);
|
||||
if let Some(elbow) = &mut hand.elbow {
|
||||
joints.extend([&mut self.palm, &mut self.wrist]);
|
||||
if let Some(elbow) = &mut self.elbow {
|
||||
joints.push(elbow);
|
||||
}
|
||||
for finger in [
|
||||
&mut hand.index,
|
||||
&mut hand.middle,
|
||||
&mut hand.ring,
|
||||
&mut hand.little,
|
||||
&mut self.index,
|
||||
&mut self.middle,
|
||||
&mut self.ring,
|
||||
&mut self.little,
|
||||
] {
|
||||
joints.extend([
|
||||
&mut finger.tip,
|
||||
@@ -56,10 +92,10 @@ impl InputSpecialization for Hand {
|
||||
]);
|
||||
}
|
||||
joints.extend([
|
||||
&mut hand.thumb.tip,
|
||||
&mut hand.thumb.distal,
|
||||
&mut hand.thumb.proximal,
|
||||
&mut hand.thumb.metacarpal,
|
||||
&mut self.thumb.tip,
|
||||
&mut self.thumb.distal,
|
||||
&mut self.thumb.proximal,
|
||||
&mut self.thumb.metacarpal,
|
||||
]);
|
||||
|
||||
for joint in joints {
|
||||
@@ -73,7 +109,5 @@ impl InputSpecialization for Hand {
|
||||
.field
|
||||
.distance(&distance_link.handler.spatial, position.into());
|
||||
}
|
||||
|
||||
InputDataType::Hand(Box::new(hand))
|
||||
}
|
||||
}
|
||||
|
||||
83
src/nodes/input/handler.rs
Normal file
83
src/nodes/input/handler.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use super::{
|
||||
input_handler_client, DistanceLink, InputHandlerAspect, INPUT_HANDLER_REGISTRY,
|
||||
INPUT_METHOD_REGISTRY,
|
||||
};
|
||||
use crate::{
|
||||
core::node_collections::LifeLinkedNodeMap,
|
||||
nodes::{fields::Field, spatial::Spatial, Aspect, Node},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use portable_atomic::AtomicBool;
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::instrument;
|
||||
|
||||
pub struct InputHandler {
|
||||
pub enabled: Arc<AtomicBool>,
|
||||
pub uid: String,
|
||||
pub node: Weak<Node>,
|
||||
pub spatial: Arc<Spatial>,
|
||||
pub field: Arc<Field>,
|
||||
pub(super) method_aliases: LifeLinkedNodeMap<usize>,
|
||||
}
|
||||
impl InputHandler {
|
||||
pub fn add_to(node: &Arc<Node>, field: &Arc<Field>) -> Result<()> {
|
||||
let handler = InputHandler {
|
||||
enabled: node.enabled.clone(),
|
||||
uid: node.uid.clone(),
|
||||
node: Arc::downgrade(node),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
field: field.clone(),
|
||||
method_aliases: LifeLinkedNodeMap::default(),
|
||||
};
|
||||
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
|
||||
method.make_alias(&handler);
|
||||
method.handle_new_handler(&handler);
|
||||
}
|
||||
let handler = INPUT_HANDLER_REGISTRY.add(handler);
|
||||
node.add_aspect_raw(handler);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, distance_link))]
|
||||
pub(super) fn send_input(
|
||||
&self,
|
||||
order: u32,
|
||||
captured: bool,
|
||||
distance_link: &DistanceLink,
|
||||
datamap: Datamap,
|
||||
) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(method_alias) = distance_link
|
||||
.handler
|
||||
.method_aliases
|
||||
.get(&(Arc::as_ptr(&distance_link.method) as usize))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let _ = input_handler_client::input(
|
||||
&node,
|
||||
&method_alias,
|
||||
&distance_link.serialize(order, captured, datamap),
|
||||
);
|
||||
}
|
||||
}
|
||||
impl Aspect for InputHandler {
|
||||
const NAME: &'static str = "InputHandler";
|
||||
}
|
||||
impl InputHandlerAspect for InputHandler {}
|
||||
impl PartialEq for InputHandler {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.spatial == other.spatial
|
||||
}
|
||||
}
|
||||
impl Drop for InputHandler {
|
||||
fn drop(&mut self) {
|
||||
INPUT_HANDLER_REGISTRY.remove(self);
|
||||
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
|
||||
method.handle_drop_handler(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
211
src/nodes/input/method.rs
Normal file
211
src/nodes/input/method.rs
Normal file
@@ -0,0 +1,211 @@
|
||||
use super::{
|
||||
input_method_client, InputDataTrait, InputDataType, InputHandler, InputMethodAspect,
|
||||
INPUT_HANDLER_REGISTRY, INPUT_METHOD_REGISTRY,
|
||||
};
|
||||
use crate::{
|
||||
core::{client::Client, node_collections::LifeLinkedNodeMap, registry::Registry},
|
||||
nodes::{
|
||||
alias::{Alias, AliasInfo},
|
||||
fields::{Field, FIELD_ALIAS_INFO},
|
||||
spatial::Spatial,
|
||||
Aspect, Node,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::Ordering;
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
pub struct InputMethod {
|
||||
pub node: Weak<Node>,
|
||||
pub uid: String,
|
||||
pub enabled: Mutex<bool>,
|
||||
pub spatial: Arc<Spatial>,
|
||||
pub data: Mutex<InputDataType>,
|
||||
pub datamap: Mutex<Datamap>,
|
||||
|
||||
pub(super) captures: Registry<InputHandler>,
|
||||
pub(super) handler_aliases: LifeLinkedNodeMap<String>,
|
||||
pub(super) handler_order: Mutex<Option<Vec<Weak<InputHandler>>>>,
|
||||
}
|
||||
impl InputMethod {
|
||||
pub fn add_to(
|
||||
node: &Arc<Node>,
|
||||
data: InputDataType,
|
||||
datamap: Datamap,
|
||||
) -> Result<Arc<InputMethod>> {
|
||||
let method = InputMethod {
|
||||
node: Arc::downgrade(node),
|
||||
uid: node.uid.clone(),
|
||||
enabled: Mutex::new(true),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
data: Mutex::new(data),
|
||||
captures: Registry::new(),
|
||||
datamap: Mutex::new(datamap),
|
||||
handler_aliases: LifeLinkedNodeMap::default(),
|
||||
handler_order: Mutex::new(None),
|
||||
};
|
||||
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
||||
method.handle_new_handler(&handler);
|
||||
method.make_alias(&handler);
|
||||
}
|
||||
let method = INPUT_METHOD_REGISTRY.add(method);
|
||||
<InputMethod as InputMethodAspect>::add_node_members(node);
|
||||
node.add_aspect_raw(method.clone());
|
||||
Ok(method)
|
||||
}
|
||||
|
||||
pub(super) fn make_alias(&self, handler: &InputHandler) {
|
||||
let Some(method_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(handler_node) = handler.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(client) = handler_node.get_client() else {
|
||||
return;
|
||||
};
|
||||
let Ok(method_alias) = Alias::create(
|
||||
&client,
|
||||
handler_node.get_path(),
|
||||
&self.uid,
|
||||
&method_node,
|
||||
AliasInfo {
|
||||
server_signals: vec!["capture"],
|
||||
..Default::default()
|
||||
},
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
method_alias.enabled.store(false, Ordering::Relaxed);
|
||||
handler
|
||||
.method_aliases
|
||||
.add(self as *const InputMethod as usize, &method_alias);
|
||||
}
|
||||
|
||||
pub fn compare_distance(&self, to: &InputHandler) -> f32 {
|
||||
let distance = self.data.lock().compare_distance(&self.spatial, &to.field);
|
||||
if self.captures.contains(to) {
|
||||
distance * 0.5
|
||||
} else {
|
||||
distance
|
||||
}
|
||||
}
|
||||
pub fn true_distance(&self, to: &Field) -> f32 {
|
||||
self.data.lock().true_distance(&self.spatial, to)
|
||||
}
|
||||
|
||||
pub(super) fn handle_new_handler(&self, handler: &InputHandler) {
|
||||
let Some(method_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(method_client) = method_node.get_client() else {
|
||||
return;
|
||||
};
|
||||
let Some(handler_node) = handler.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
// Receiver itself
|
||||
let Ok(handler_alias) = Alias::create(
|
||||
&method_client,
|
||||
method_node.get_path(),
|
||||
handler.uid.as_str(),
|
||||
&handler_node,
|
||||
AliasInfo {
|
||||
server_methods: vec!["get_transform"],
|
||||
..Default::default()
|
||||
},
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.handler_aliases
|
||||
.add(handler.uid.clone(), &handler_alias);
|
||||
|
||||
if let Some(handler_field_node) = handler.field.spatial_ref().node.upgrade() {
|
||||
// Handler's field
|
||||
let Ok(rx_field_alias) = Alias::create(
|
||||
&method_client,
|
||||
handler_alias.get_path(),
|
||||
"field",
|
||||
&handler_field_node,
|
||||
FIELD_ALIAS_INFO.clone(),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.handler_aliases
|
||||
.add(handler.uid.clone() + "-field", &rx_field_alias);
|
||||
}
|
||||
|
||||
let _ = input_method_client::new_handler(&method_node, &handler.uid, &handler_node);
|
||||
}
|
||||
pub(super) fn handle_drop_handler(&self, handler: &InputHandler) {
|
||||
let uid = handler.uid.as_str();
|
||||
self.handler_aliases.remove(uid);
|
||||
self.handler_aliases.remove(&(uid.to_string() + "-field"));
|
||||
let Some(tx_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let _ = input_method_client::drop_handler(&tx_node, &uid);
|
||||
}
|
||||
}
|
||||
impl Aspect for InputMethod {
|
||||
const NAME: &'static str = "InputMethod";
|
||||
}
|
||||
impl InputMethodAspect for InputMethod {
|
||||
#[doc = "Set the spatial input component of this input method. You must keep the same input data type throughout the entire thing."]
|
||||
fn set_input(
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
input: InputDataType,
|
||||
) -> Result<()> {
|
||||
let input_method = node.get_aspect::<InputMethod>()?;
|
||||
*input_method.data.lock() = input;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[doc = "Set the datmap of this input method"]
|
||||
fn set_datamap(node: Arc<Node>, _calling_client: Arc<Client>, datamap: Datamap) -> Result<()> {
|
||||
let input_method = node.get_aspect::<InputMethod>()?;
|
||||
*input_method.datamap.lock() = datamap;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[doc = "Manually set the order of handlers to propagate input to, or else let the server decide."]
|
||||
fn set_handler_order(
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
handlers: Option<Vec<Arc<Node>>>,
|
||||
) -> Result<()> {
|
||||
let input_method = node.get_aspect::<InputMethod>()?;
|
||||
let Some(handlers) = handlers else {
|
||||
*input_method.handler_order.lock() = None;
|
||||
return Ok(());
|
||||
};
|
||||
let handlers = handlers
|
||||
.into_iter()
|
||||
.filter_map(|p| p.get_aspect::<InputHandler>().ok())
|
||||
.map(|i| Arc::downgrade(&i))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
*input_method.handler_order.lock() = Some(handlers);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[doc = "Have the input handler that this method reference came from capture the method for the next frame."]
|
||||
fn capture(node: Arc<Node>, _calling_client: Arc<Client>, handler: Arc<Node>) -> Result<()> {
|
||||
let input_method = node.get_aspect::<InputMethod>()?;
|
||||
let input_handler = handler.get_aspect::<InputHandler>()?;
|
||||
|
||||
input_method.captures.add_raw(&input_handler);
|
||||
// input_method_client::
|
||||
// node.send_remote_signal("capture", message)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for InputMethod {
|
||||
fn drop(&mut self) {
|
||||
INPUT_METHOD_REGISTRY.remove(self);
|
||||
}
|
||||
}
|
||||
@@ -1,255 +1,29 @@
|
||||
pub mod hand;
|
||||
pub mod pointer;
|
||||
pub mod tip;
|
||||
mod hand;
|
||||
mod handler;
|
||||
mod method;
|
||||
mod pointer;
|
||||
mod tip;
|
||||
|
||||
use self::hand::Hand;
|
||||
use self::pointer::Pointer;
|
||||
use self::tip::Tip;
|
||||
pub use handler::*;
|
||||
pub use method::*;
|
||||
|
||||
use super::{
|
||||
alias::{Alias, AliasInfo},
|
||||
fields::{find_field, Field, FIELD_ALIAS_INFO},
|
||||
spatial::{parse_transform, Spatial},
|
||||
Aspect, Message, Node,
|
||||
};
|
||||
use crate::core::{client::Client, node_collections::LifeLinkedNodeMap};
|
||||
use super::fields::Field;
|
||||
use super::spatial::Spatial;
|
||||
use crate::create_interface;
|
||||
use crate::nodes::alias::Alias;
|
||||
use crate::{core::client::Client, nodes::Node};
|
||||
use crate::{core::registry::Registry, nodes::spatial::Transform};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::AtomicBool;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::{flat::InputDataType, flex::serialize};
|
||||
use stardust_xr::{
|
||||
schemas::{flat::InputData, flex::deserialize},
|
||||
values::Datamap,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::Ordering;
|
||||
use portable_atomic::Ordering;
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{debug_span, instrument};
|
||||
|
||||
static INPUT_METHOD_REGISTRY: Registry<InputMethod> = Registry::new();
|
||||
static INPUT_HANDLER_REGISTRY: Registry<InputHandler> = Registry::new();
|
||||
|
||||
pub trait InputSpecialization: Send + Sync {
|
||||
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32;
|
||||
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32;
|
||||
fn serialize(
|
||||
&self,
|
||||
distance_link: &DistanceLink,
|
||||
local_to_handler_matrix: Mat4,
|
||||
) -> InputDataType;
|
||||
}
|
||||
pub enum InputType {
|
||||
Pointer(Pointer),
|
||||
Hand(Box<Hand>),
|
||||
Tip(Tip),
|
||||
}
|
||||
impl Deref for InputType {
|
||||
type Target = dyn InputSpecialization;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
InputType::Pointer(p) => p,
|
||||
InputType::Hand(h) => h.as_ref(),
|
||||
InputType::Tip(t) => t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InputMethod {
|
||||
node: Weak<Node>,
|
||||
uid: String,
|
||||
pub enabled: Mutex<bool>,
|
||||
pub spatial: Arc<Spatial>,
|
||||
pub specialization: Mutex<InputType>,
|
||||
captures: Registry<InputHandler>,
|
||||
pub datamap: Mutex<Option<Datamap>>,
|
||||
handler_aliases: LifeLinkedNodeMap<String>,
|
||||
handler_order: OnceCell<Mutex<Vec<Weak<InputHandler>>>>,
|
||||
}
|
||||
impl InputMethod {
|
||||
#[allow(dead_code)]
|
||||
pub fn add_to(
|
||||
node: &Arc<Node>,
|
||||
specialization: InputType,
|
||||
datamap: Option<Datamap>,
|
||||
) -> Result<Arc<InputMethod>> {
|
||||
node.add_local_signal("capture", InputMethod::capture_flex);
|
||||
node.add_local_signal("set_datamap", InputMethod::set_datamap_flex);
|
||||
node.add_local_signal("set_handlers", InputMethod::set_handlers_flex);
|
||||
|
||||
let method = InputMethod {
|
||||
node: Arc::downgrade(node),
|
||||
uid: node.uid.clone(),
|
||||
enabled: Mutex::new(true),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
specialization: Mutex::new(specialization),
|
||||
captures: Registry::new(),
|
||||
datamap: Mutex::new(datamap),
|
||||
handler_aliases: LifeLinkedNodeMap::default(),
|
||||
handler_order: OnceCell::new(),
|
||||
};
|
||||
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
||||
method.handle_new_handler(&handler);
|
||||
method.make_alias(&handler);
|
||||
}
|
||||
let method = INPUT_METHOD_REGISTRY.add(method);
|
||||
node.add_aspect_raw(method.clone());
|
||||
Ok(method)
|
||||
}
|
||||
fn get(node: &Node) -> Result<Arc<Self>> {
|
||||
node.get_aspect::<Self>()
|
||||
}
|
||||
|
||||
fn capture_flex(node: Arc<Node>, calling_client: Arc<Client>, message: Message) -> Result<()> {
|
||||
let method = InputMethod::get(&node)?;
|
||||
let handler = InputHandler::find(&calling_client, deserialize(message.as_ref())?)?;
|
||||
|
||||
method.captures.add_raw(&handler);
|
||||
node.send_remote_signal("capture", message)
|
||||
}
|
||||
fn set_datamap_flex(
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
let method = InputMethod::get(&node)?;
|
||||
method
|
||||
.datamap
|
||||
.lock()
|
||||
.replace(Datamap::from_raw(message.data)?);
|
||||
Ok(())
|
||||
}
|
||||
fn set_handlers_flex(
|
||||
node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
let method = InputMethod::get(&node)?;
|
||||
let handler_paths: Vec<&str> = deserialize(message.as_ref())?;
|
||||
let handlers: Vec<Weak<InputHandler>> = handler_paths
|
||||
.into_iter()
|
||||
.filter_map(|p| InputHandler::find(&calling_client, p).ok())
|
||||
.map(|h| Arc::downgrade(&h))
|
||||
.collect();
|
||||
|
||||
*method
|
||||
.handler_order
|
||||
.get_or_init(|| Mutex::new(Vec::new()))
|
||||
.lock() = handlers;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_alias(&self, handler: &InputHandler) {
|
||||
let Some(method_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(handler_node) = handler.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(client) = handler_node.get_client() else {
|
||||
return;
|
||||
};
|
||||
let Ok(method_alias) = Alias::create(
|
||||
&client,
|
||||
handler_node.get_path(),
|
||||
&self.uid,
|
||||
&method_node,
|
||||
AliasInfo {
|
||||
server_signals: vec!["capture"],
|
||||
..Default::default()
|
||||
},
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
method_alias.enabled.store(false, Ordering::Relaxed);
|
||||
handler
|
||||
.method_aliases
|
||||
.add(self as *const InputMethod as usize, &method_alias);
|
||||
}
|
||||
|
||||
fn compare_distance(&self, to: &InputHandler) -> f32 {
|
||||
let distance = self
|
||||
.specialization
|
||||
.lock()
|
||||
.compare_distance(&self.spatial, &to.field);
|
||||
if self.captures.contains(to) {
|
||||
distance * 0.5
|
||||
} else {
|
||||
distance
|
||||
}
|
||||
}
|
||||
fn true_distance(&self, to: &Field) -> f32 {
|
||||
self.specialization.lock().true_distance(&self.spatial, to)
|
||||
}
|
||||
|
||||
fn handle_new_handler(&self, handler: &InputHandler) {
|
||||
let Some(method_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(method_client) = method_node.get_client() else {
|
||||
return;
|
||||
};
|
||||
let Some(handler_node) = handler.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
// Receiver itself
|
||||
let Ok(handler_alias) = Alias::create(
|
||||
&method_client,
|
||||
method_node.get_path(),
|
||||
handler.uid.as_str(),
|
||||
&handler_node,
|
||||
AliasInfo {
|
||||
server_methods: vec!["get_transform"],
|
||||
..Default::default()
|
||||
},
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.handler_aliases
|
||||
.add(handler.uid.clone(), &handler_alias);
|
||||
|
||||
if let Some(handler_field_node) = handler.field.spatial_ref().node.upgrade() {
|
||||
// Handler's field
|
||||
let Ok(rx_field_alias) = Alias::create(
|
||||
&method_client,
|
||||
handler_alias.get_path(),
|
||||
"field",
|
||||
&handler_field_node,
|
||||
FIELD_ALIAS_INFO.clone(),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.handler_aliases
|
||||
.add(handler.uid.clone() + "-field", &rx_field_alias);
|
||||
}
|
||||
|
||||
let Ok(data) = serialize(&handler.uid) else {
|
||||
return;
|
||||
};
|
||||
let _ = method_node.send_remote_signal("handler_created", data);
|
||||
}
|
||||
fn handle_drop_handler(&self, handler: &InputHandler) {
|
||||
let uid = handler.uid.as_str();
|
||||
self.handler_aliases.remove(uid);
|
||||
self.handler_aliases.remove(&(uid.to_string() + "-field"));
|
||||
let Some(tx_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Ok(data) = serialize(&uid) else { return };
|
||||
let _ = tx_node.send_remote_signal("handler_destroyed", data);
|
||||
}
|
||||
}
|
||||
impl Aspect for InputMethod {
|
||||
const NAME: &'static str = "InputMethod";
|
||||
}
|
||||
impl Drop for InputMethod {
|
||||
fn drop(&mut self) {
|
||||
INPUT_METHOD_REGISTRY.remove(self);
|
||||
}
|
||||
}
|
||||
stardust_xr_server_codegen::codegen_input_protocol!();
|
||||
|
||||
pub struct DistanceLink {
|
||||
distance: f32,
|
||||
@@ -269,118 +43,98 @@ impl DistanceLink {
|
||||
self.handler.send_input(order, captured, self, datamap);
|
||||
}
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn serialize(&self, order: u32, captured: bool, datamap: Datamap) -> Vec<u8> {
|
||||
let input = self.method.specialization.lock().serialize(
|
||||
fn serialize(&self, order: u32, captured: bool, datamap: Datamap) -> InputData {
|
||||
let mut input = self.method.data.lock().clone();
|
||||
input.update_to(
|
||||
self,
|
||||
Spatial::space_to_space_matrix(Some(&self.method.spatial), Some(&self.handler.spatial)),
|
||||
);
|
||||
|
||||
let root = InputData {
|
||||
InputData {
|
||||
uid: self.method.uid.clone(),
|
||||
input,
|
||||
distance: self.method.true_distance(&self.handler.field),
|
||||
datamap,
|
||||
order,
|
||||
captured,
|
||||
};
|
||||
root.serialize()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub trait InputDataTrait {
|
||||
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32;
|
||||
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32;
|
||||
fn update_to(&mut self, distance_link: &DistanceLink, local_to_handler_matrix: Mat4);
|
||||
}
|
||||
impl InputDataTrait for InputDataType {
|
||||
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
|
||||
match self {
|
||||
InputDataType::Pointer(i) => i.compare_distance(space, field),
|
||||
InputDataType::Hand(i) => i.compare_distance(space, field),
|
||||
InputDataType::Tip(i) => i.compare_distance(space, field),
|
||||
}
|
||||
}
|
||||
|
||||
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
|
||||
match self {
|
||||
InputDataType::Pointer(i) => i.true_distance(space, field),
|
||||
InputDataType::Hand(i) => i.true_distance(space, field),
|
||||
InputDataType::Tip(i) => i.true_distance(space, field),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_to(&mut self, distance_link: &DistanceLink, local_to_handler_matrix: Mat4) {
|
||||
match self {
|
||||
InputDataType::Pointer(i) => i.update_to(distance_link, local_to_handler_matrix),
|
||||
InputDataType::Hand(i) => i.update_to(distance_link, local_to_handler_matrix),
|
||||
InputDataType::Tip(i) => i.update_to(distance_link, local_to_handler_matrix),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InputHandler {
|
||||
enabled: Arc<AtomicBool>,
|
||||
uid: String,
|
||||
node: Weak<Node>,
|
||||
spatial: Arc<Spatial>,
|
||||
field: Arc<Field>,
|
||||
method_aliases: LifeLinkedNodeMap<usize>,
|
||||
}
|
||||
impl InputHandler {
|
||||
pub fn add_to(node: &Arc<Node>, field: &Arc<Field>) -> Result<()> {
|
||||
let handler = InputHandler {
|
||||
enabled: node.enabled.clone(),
|
||||
uid: node.uid.clone(),
|
||||
node: Arc::downgrade(node),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
field: field.clone(),
|
||||
method_aliases: LifeLinkedNodeMap::default(),
|
||||
};
|
||||
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
|
||||
method.make_alias(&handler);
|
||||
method.handle_new_handler(&handler);
|
||||
}
|
||||
let handler = INPUT_HANDLER_REGISTRY.add(handler);
|
||||
node.add_aspect_raw(handler);
|
||||
create_interface!(InputInterface, InputInterfaceAspect, "/input");
|
||||
pub struct InputInterface;
|
||||
impl InputInterfaceAspect for InputInterface {
|
||||
#[doc = "Create an input method node"]
|
||||
fn create_input_method(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
initial_data: InputDataType,
|
||||
datamap: Datamap,
|
||||
) -> Result<()> {
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
|
||||
let node = Node::create_parent_name(&calling_client, "/input/method", &name, true)
|
||||
.add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputMethod::add_to(&node, initial_data, datamap)?;
|
||||
Ok(())
|
||||
}
|
||||
fn find(client: &Client, path: &str) -> Result<Arc<Self>> {
|
||||
client.get_node("Input Handler", path)?.get_aspect::<Self>()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, distance_link))]
|
||||
fn send_input(
|
||||
&self,
|
||||
order: u32,
|
||||
captured: bool,
|
||||
distance_link: &DistanceLink,
|
||||
datamap: Datamap,
|
||||
) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let _ = node.send_remote_signal("input", distance_link.serialize(order, captured, datamap));
|
||||
}
|
||||
}
|
||||
impl Aspect for InputHandler {
|
||||
const NAME: &'static str = "InputHandler";
|
||||
}
|
||||
impl PartialEq for InputHandler {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.spatial == other.spatial
|
||||
}
|
||||
}
|
||||
impl Drop for InputHandler {
|
||||
fn drop(&mut self) {
|
||||
INPUT_HANDLER_REGISTRY.remove(self);
|
||||
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
|
||||
method.handle_drop_handler(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
let node = Node::create_path(client, "/input", false);
|
||||
node.add_local_signal("create_input_handler", create_input_handler_flex);
|
||||
node.add_local_signal("create_input_method_pointer", pointer::create_pointer_flex);
|
||||
node.add_local_signal("create_input_method_tip", tip::create_tip_flex);
|
||||
node.add_to_scenegraph().map(|_| ())
|
||||
}
|
||||
|
||||
pub fn create_input_handler_flex(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateInputHandlerInfo<'a> {
|
||||
name: &'a str,
|
||||
parent_path: &'a str,
|
||||
#[doc = "Create an input handler node"]
|
||||
fn create_input_handler(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
field_path: &'a str,
|
||||
}
|
||||
let info: CreateInputHandlerInfo = deserialize(message.as_ref())?;
|
||||
let parent = calling_client
|
||||
.get_node("Spatial parent", info.parent_path)?
|
||||
.get_aspect::<Spatial>()?;
|
||||
let transform = parse_transform(info.transform, true, true, true);
|
||||
let field = find_field(&calling_client, info.field_path)?;
|
||||
field: Arc<Node>,
|
||||
) -> Result<()> {
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
let field = field.get_aspect::<Field>()?;
|
||||
|
||||
let node = Node::create_parent_name(&calling_client, "/input/handler", info.name, true)
|
||||
.add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputHandler::add_to(&node, &field)?;
|
||||
Ok(())
|
||||
let node = Node::create_parent_name(&calling_client, "/input/handler", &name, true)
|
||||
.add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputHandler::add_to(&node, &field)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug")]
|
||||
pub fn process_input() {
|
||||
// Iterate over all valid input methods
|
||||
@@ -389,7 +143,6 @@ pub fn process_input() {
|
||||
.get_valid_contents()
|
||||
.into_iter()
|
||||
.filter(|method| *method.enabled.lock())
|
||||
.filter(|method| method.datamap.lock().is_some())
|
||||
});
|
||||
let handlers = INPUT_HANDLER_REGISTRY.get_valid_contents();
|
||||
const LIMIT: usize = 50;
|
||||
@@ -402,11 +155,10 @@ pub fn process_input() {
|
||||
// Get all valid input handlers and convert them to DistanceLink objects
|
||||
let distance_links: Vec<DistanceLink> = debug_span!("Generate distance links")
|
||||
.in_scope(|| {
|
||||
if let Some(handler_order) = method.handler_order.get() {
|
||||
let handler_order = handler_order.lock();
|
||||
if let Some(handler_order) = &*method.handler_order.lock() {
|
||||
handler_order
|
||||
.iter()
|
||||
.filter_map(|h| h.upgrade())
|
||||
.filter_map(Weak::upgrade)
|
||||
.filter(|handler| handler.enabled.load(Ordering::Relaxed))
|
||||
.map(|handler| DistanceLink::from(method.clone(), handler))
|
||||
.collect()
|
||||
@@ -445,11 +197,7 @@ pub fn process_input() {
|
||||
method_alias.enabled.store(true, Ordering::Release);
|
||||
}
|
||||
let captured = captures.contains(&distance_link.handler);
|
||||
distance_link.send_input(
|
||||
i as u32,
|
||||
captured,
|
||||
method.datamap.lock().clone().unwrap(),
|
||||
);
|
||||
distance_link.send_input(i as u32, captured, method.datamap.lock().clone());
|
||||
|
||||
// If the current distance link is in the list of captured input handlers,
|
||||
// break out of the loop to avoid sending input to the remaining distance links
|
||||
|
||||
@@ -1,38 +1,34 @@
|
||||
use super::{DistanceLink, InputSpecialization};
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::fields::{Field, Ray, RayMarchResult};
|
||||
use crate::nodes::input::{InputMethod, InputType};
|
||||
use crate::nodes::spatial::{parse_transform, Spatial, Transform};
|
||||
use crate::nodes::{Message, Node};
|
||||
use glam::{vec3, Mat4};
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flat::{InputDataType, Pointer as FlatPointer};
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
use stardust_xr::values::Datamap;
|
||||
use super::{DistanceLink, InputDataTrait, Pointer};
|
||||
use crate::nodes::{
|
||||
fields::{Field, Ray, RayMarchResult},
|
||||
spatial::Spatial,
|
||||
};
|
||||
use glam::{vec3, Mat4, Quat};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Pointer;
|
||||
// impl Default for Pointer {
|
||||
// fn default() -> Self {
|
||||
// Pointer {
|
||||
// grab: Default::default(),
|
||||
// select: Default::default(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl Default for Pointer {
|
||||
fn default() -> Self {
|
||||
Pointer {
|
||||
origin: [0.0; 3].into(),
|
||||
orientation: Quat::IDENTITY.into(),
|
||||
deepest_point: [0.0; 3].into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Pointer {
|
||||
fn ray_march(&self, space: &Arc<Spatial>, field: &Field) -> RayMarchResult {
|
||||
fn ray_march(&self, method_space: &Arc<Spatial>, field: &Field) -> RayMarchResult {
|
||||
field.ray_march(Ray {
|
||||
origin: vec3(0.0, 0.0, 0.0),
|
||||
direction: vec3(0.0, 0.0, -1.0),
|
||||
space: space.clone(),
|
||||
space: Spatial::new(
|
||||
Weak::new(),
|
||||
Some(method_space.clone()),
|
||||
Mat4::from_rotation_translation(self.orientation.into(), self.origin.into()),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl InputSpecialization for Pointer {
|
||||
impl InputDataTrait for Pointer {
|
||||
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
|
||||
let ray_info = self.ray_march(space, field);
|
||||
if ray_info.min_distance > 0.0 {
|
||||
@@ -47,50 +43,20 @@ impl InputSpecialization for Pointer {
|
||||
let ray_info = self.ray_march(space, field);
|
||||
ray_info.min_distance
|
||||
}
|
||||
fn serialize(
|
||||
&self,
|
||||
distance_link: &DistanceLink,
|
||||
local_to_handler_matrix: Mat4,
|
||||
) -> InputDataType {
|
||||
fn update_to(&mut self, distance_link: &DistanceLink, mut local_to_handler_matrix: Mat4) {
|
||||
local_to_handler_matrix =
|
||||
Mat4::from_rotation_translation(self.orientation.into(), self.origin.into())
|
||||
* local_to_handler_matrix;
|
||||
let (_, orientation, origin) = local_to_handler_matrix.to_scale_rotation_translation();
|
||||
let direction = local_to_handler_matrix.transform_vector3(vec3(0.0, 0.0, -1.0));
|
||||
|
||||
let ray_march = self.ray_march(&distance_link.method.spatial, &distance_link.handler.field);
|
||||
let direction = local_to_handler_matrix
|
||||
.transform_vector3(vec3(0.0, 0.0, -1.0))
|
||||
.normalize();
|
||||
let deepest_point = (direction * ray_march.deepest_point_distance) + origin;
|
||||
|
||||
InputDataType::Pointer(FlatPointer {
|
||||
origin: origin.into(),
|
||||
orientation: orientation.into(),
|
||||
deepest_point: deepest_point.into(),
|
||||
})
|
||||
self.origin = origin.into();
|
||||
self.orientation = orientation.into();
|
||||
self.deepest_point = deepest_point.into();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_pointer_flex(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreatePointerInfo<'a> {
|
||||
name: &'a str,
|
||||
parent_path: &'a str,
|
||||
transform: Transform,
|
||||
datamap: Option<Vec<u8>>,
|
||||
}
|
||||
let info: CreatePointerInfo = deserialize(message.as_ref())?;
|
||||
let node = Node::create_parent_name(&calling_client, "/input/method/pointer", info.name, true);
|
||||
let parent = calling_client
|
||||
.get_node("Spatial parent", info.parent_path)?
|
||||
.get_aspect::<Spatial>()?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
let node = node.add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputMethod::add_to(
|
||||
&node,
|
||||
InputType::Pointer(Pointer),
|
||||
info.datamap
|
||||
.and_then(|datamap| Datamap::from_raw(datamap).ok()),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,82 +1,28 @@
|
||||
use super::{DistanceLink, InputSpecialization};
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::fields::Field;
|
||||
use crate::nodes::input::{InputMethod, InputType};
|
||||
use crate::nodes::spatial::{parse_transform, Spatial, Transform};
|
||||
use crate::nodes::{Message, Node};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{vec3a, Mat4};
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flat::{InputDataType, Tip as FlatTip};
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
use stardust_xr::values::Datamap;
|
||||
|
||||
use super::{DistanceLink, InputDataTrait, Tip};
|
||||
use crate::nodes::{fields::Field, spatial::Spatial};
|
||||
use glam::{Mat4, Quat};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Tip {
|
||||
pub radius: f32,
|
||||
}
|
||||
impl Tip {
|
||||
fn set_radius(node: Arc<Node>, _calling_client: Arc<Client>, message: Message) -> Result<()> {
|
||||
let input_method = node.get_aspect::<InputMethod>()?;
|
||||
if let InputType::Tip(tip) = &mut *input_method.specialization.lock() {
|
||||
tip.radius = deserialize(message.as_ref())?;
|
||||
impl Default for Tip {
|
||||
fn default() -> Self {
|
||||
Tip {
|
||||
origin: [0.0; 3].into(),
|
||||
orientation: Quat::IDENTITY.into(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl InputSpecialization for Tip {
|
||||
impl InputDataTrait for Tip {
|
||||
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
|
||||
field.distance(space, vec3a(0.0, 0.0, 0.0)).abs()
|
||||
field.distance(space, self.origin.into()).abs()
|
||||
}
|
||||
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
|
||||
field.distance(space, vec3a(0.0, 0.0, 0.0))
|
||||
field.distance(space, self.origin.into())
|
||||
}
|
||||
fn serialize(
|
||||
&self,
|
||||
_distance_link: &DistanceLink,
|
||||
local_to_handler_matrix: Mat4,
|
||||
) -> InputDataType {
|
||||
fn update_to(&mut self, _distance_link: &DistanceLink, mut local_to_handler_matrix: Mat4) {
|
||||
local_to_handler_matrix *=
|
||||
Mat4::from_rotation_translation(self.orientation.into(), self.origin.into());
|
||||
let (_, orientation, origin) = local_to_handler_matrix.to_scale_rotation_translation();
|
||||
InputDataType::Tip(FlatTip {
|
||||
origin: origin.into(),
|
||||
orientation: orientation.into(),
|
||||
radius: self.radius,
|
||||
})
|
||||
self.origin = origin.into();
|
||||
self.orientation = orientation.into();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tip_flex(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateTipInfo<'a> {
|
||||
name: &'a str,
|
||||
parent_path: &'a str,
|
||||
transform: Transform,
|
||||
radius: f32,
|
||||
datamap: Option<Vec<u8>>,
|
||||
}
|
||||
let info: CreateTipInfo = deserialize(message.as_ref())?;
|
||||
let node = Node::create_parent_name(&calling_client, "/input/method/tip", info.name, true);
|
||||
let parent = calling_client
|
||||
.get_node("Spatial parent", info.parent_path)?
|
||||
.get_aspect::<Spatial>()?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
let node = node.add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputMethod::add_to(
|
||||
&node,
|
||||
InputType::Tip(Tip {
|
||||
radius: info.radius,
|
||||
}),
|
||||
info.datamap
|
||||
.and_then(|datamap| Datamap::from_raw(datamap).ok()),
|
||||
)?;
|
||||
node.add_local_signal("set_radius", Tip::set_radius);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
input::{pointer::Pointer, InputMethod, InputType},
|
||||
input::{InputDataType, InputMethod, Pointer},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
},
|
||||
@@ -9,11 +9,16 @@ use crate::{
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use nanoid::nanoid;
|
||||
use serde::Serialize;
|
||||
use stardust_xr::{schemas::flex::flexbuffers, values::Datamap};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::Arc;
|
||||
use stereokit::StereoKitMultiThread;
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
pub struct EyeDatamap {
|
||||
eye: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct KeyboardEvent {
|
||||
pub keyboard: String,
|
||||
@@ -31,8 +36,12 @@ impl EyePointer {
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
let pointer =
|
||||
InputMethod::add_to(&node, InputType::Pointer(Pointer::default()), None).unwrap();
|
||||
let pointer = InputMethod::add_to(
|
||||
&node,
|
||||
InputDataType::Pointer(Pointer::default()),
|
||||
Datamap::from_typed(EyeDatamap::default())?,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(EyePointer { spatial, pointer })
|
||||
}
|
||||
@@ -45,11 +54,7 @@ impl EyePointer {
|
||||
));
|
||||
{
|
||||
// Set pointer input datamap
|
||||
let mut fbb = flexbuffers::Builder::default();
|
||||
let mut map = fbb.start_map();
|
||||
map.push("eye", 2);
|
||||
map.end_map();
|
||||
*self.pointer.datamap.lock() = Datamap::from_raw(fbb.take_buffer()).ok();
|
||||
*self.pointer.datamap.lock() = Datamap::from_typed(EyeDatamap { eye: 2 }).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
mask_matches, pulse_receiver_client, PulseSender, KEYMAPS, PULSE_RECEIVER_REGISTRY,
|
||||
},
|
||||
fields::{Field, Ray},
|
||||
input::{pointer::Pointer, InputMethod, InputType},
|
||||
input::{InputDataType, InputMethod, Pointer},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
},
|
||||
@@ -61,8 +61,11 @@ impl MousePointer {
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
let pointer =
|
||||
InputMethod::add_to(&node, InputType::Pointer(Pointer::default()), None).unwrap();
|
||||
let pointer = InputMethod::add_to(
|
||||
&node,
|
||||
InputDataType::Pointer(Pointer::default()),
|
||||
Datamap::from_typed(MouseEvent::default())?,
|
||||
)?;
|
||||
|
||||
KEYMAPS.lock().insert(
|
||||
"flatscreen".to_string(),
|
||||
@@ -129,7 +132,7 @@ impl MousePointer {
|
||||
};
|
||||
self.mouse_datamap.scroll_continuous = vec2(0.0, mouse.scroll_change / 120.0);
|
||||
self.mouse_datamap.scroll_discrete = vec2(0.0, mouse.scroll_change / 120.0);
|
||||
*self.pointer.datamap.lock() = Datamap::from_typed(&self.mouse_datamap).ok();
|
||||
*self.pointer.datamap.lock() = Datamap::from_typed(&self.mouse_datamap).unwrap();
|
||||
}
|
||||
self.send_keyboard_input(sk);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
input::{tip::Tip, InputMethod, InputType},
|
||||
input::{InputDataType, InputMethod, Tip},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
},
|
||||
@@ -45,8 +45,12 @@ impl SkController {
|
||||
.add_to_scenegraph()?;
|
||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
||||
let model = sk.model_create_mem("cursor.glb", include_bytes!("cursor.glb"), None)?;
|
||||
let tip = InputType::Tip(Tip::default());
|
||||
let input = InputMethod::add_to(&_node, tip, None)?;
|
||||
let tip = InputDataType::Tip(Tip::default());
|
||||
let input = InputMethod::add_to(
|
||||
&_node,
|
||||
tip,
|
||||
Datamap::from_typed(ControllerDatamap::default())?,
|
||||
)?;
|
||||
Ok(SkController {
|
||||
_node,
|
||||
input,
|
||||
@@ -74,6 +78,6 @@ impl SkController {
|
||||
self.datamap.select = controller.trigger;
|
||||
self.datamap.grab = controller.grip;
|
||||
self.datamap.scroll = controller.stick;
|
||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).ok();
|
||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use crate::{
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
input::{hand::Hand, InputMethod, InputType},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
},
|
||||
use crate::core::client::INTERNAL_CLIENT;
|
||||
use crate::nodes::input::InputDataType;
|
||||
use crate::nodes::{
|
||||
input::{Hand, InputMethod, Joint},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::{
|
||||
schemas::flat::{Hand as FlatHand, Joint},
|
||||
values::Datamap,
|
||||
};
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::Arc;
|
||||
use stereokit::{ButtonState, HandJoint, Handed, StereoKitMultiThread};
|
||||
|
||||
@@ -43,13 +39,12 @@ impl SkHand {
|
||||
let _node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
||||
let hand = InputType::Hand(Box::new(Hand {
|
||||
base: FlatHand {
|
||||
right: handed == Handed::Right,
|
||||
..Default::default()
|
||||
},
|
||||
}));
|
||||
let input = InputMethod::add_to(&_node, hand, None)?;
|
||||
let hand = InputDataType::Hand(Hand {
|
||||
right: handed == Handed::Right,
|
||||
..Default::default()
|
||||
});
|
||||
let datamap = Datamap::from_typed(HandDatamap::default())?;
|
||||
let input = InputMethod::add_to(&_node, hand, datamap)?;
|
||||
Ok(SkHand {
|
||||
_node,
|
||||
input,
|
||||
@@ -59,7 +54,7 @@ impl SkHand {
|
||||
}
|
||||
pub fn update(&mut self, controller_enabled: bool, sk: &impl StereoKitMultiThread) {
|
||||
let sk_hand = sk.input_hand(self.handed);
|
||||
if let InputType::Hand(hand) = &mut *self.input.specialization.lock() {
|
||||
if let InputDataType::Hand(hand) = &mut *self.input.data.lock() {
|
||||
let controller_active = controller_enabled
|
||||
&& sk
|
||||
.input_controller(self.handed)
|
||||
@@ -69,16 +64,16 @@ impl SkHand {
|
||||
!controller_active && sk_hand.tracked_state.contains(ButtonState::ACTIVE);
|
||||
sk.input_hand_visible(self.handed, *self.input.enabled.lock());
|
||||
if *self.input.enabled.lock() {
|
||||
hand.base.thumb.tip = convert_joint(sk_hand.fingers[0][4]);
|
||||
hand.base.thumb.distal = convert_joint(sk_hand.fingers[0][3]);
|
||||
hand.base.thumb.proximal = convert_joint(sk_hand.fingers[0][2]);
|
||||
hand.base.thumb.metacarpal = convert_joint(sk_hand.fingers[0][1]);
|
||||
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]);
|
||||
hand.thumb.metacarpal = convert_joint(sk_hand.fingers[0][1]);
|
||||
|
||||
for (finger, sk_finger) in [
|
||||
(&mut hand.base.index, sk_hand.fingers[1]),
|
||||
(&mut hand.base.middle, sk_hand.fingers[2]),
|
||||
(&mut hand.base.ring, sk_hand.fingers[3]),
|
||||
(&mut hand.base.little, sk_hand.fingers[4]),
|
||||
(&mut hand.index, sk_hand.fingers[1]),
|
||||
(&mut hand.middle, sk_hand.fingers[2]),
|
||||
(&mut hand.ring, sk_hand.fingers[3]),
|
||||
(&mut hand.little, sk_hand.fingers[4]),
|
||||
] {
|
||||
finger.tip = convert_joint(sk_finger[4]);
|
||||
finger.distal = convert_joint(sk_finger[3]);
|
||||
@@ -87,21 +82,21 @@ impl SkHand {
|
||||
finger.metacarpal = convert_joint(sk_finger[0]);
|
||||
}
|
||||
|
||||
hand.base.palm.position = sk_hand.palm.position.into();
|
||||
hand.base.palm.rotation = sk_hand.palm.orientation.into();
|
||||
hand.base.palm.radius =
|
||||
hand.palm.position = sk_hand.palm.position.into();
|
||||
hand.palm.rotation = sk_hand.palm.orientation.into();
|
||||
hand.palm.radius =
|
||||
(sk_hand.fingers[2][0].radius + sk_hand.fingers[2][1].radius) * 0.5;
|
||||
|
||||
hand.base.wrist.position = sk_hand.wrist.position.into();
|
||||
hand.base.wrist.rotation = sk_hand.wrist.orientation.into();
|
||||
hand.base.wrist.radius =
|
||||
hand.wrist.position = sk_hand.wrist.position.into();
|
||||
hand.wrist.rotation = sk_hand.wrist.orientation.into();
|
||||
hand.wrist.radius =
|
||||
(sk_hand.fingers[0][0].radius + sk_hand.fingers[4][0].radius) * 0.5;
|
||||
|
||||
hand.base.elbow = None;
|
||||
hand.elbow = None;
|
||||
}
|
||||
}
|
||||
self.datamap.pinch_strength = sk_hand.pinch_activation;
|
||||
self.datamap.grab_strength = sk_hand.grip_activation;
|
||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).ok();
|
||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user