feat(input): custom pointers

This commit is contained in:
Nova
2023-05-31 08:50:15 -04:00
parent 34faa98dc8
commit e9089e83a9
9 changed files with 189 additions and 49 deletions

View File

@@ -8,19 +8,23 @@ use self::tip::Tip;
use super::{
alias::{Alias, AliasInfo},
fields::{find_field, Field},
fields::{find_field, Field, FIELD_ALIAS_INFO},
spatial::{find_spatial_parent, parse_transform, Spatial},
Node,
};
use crate::core::client::Client;
use crate::core::{client::Client, node_collections::LifeLinkedNodeMap};
use crate::core::{node_collections::LifeLinkedNodeList, registry::Registry};
use color_eyre::eyre::{ensure, 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::{Datamap, InputDataType};
use stardust_xr::schemas::{flat::InputData, flex::deserialize};
use stardust_xr::schemas::{
flat::{Datamap, InputDataType},
flex::serialize,
};
use stardust_xr::values::Transform;
use std::ops::Deref;
use std::sync::atomic::Ordering;
@@ -63,6 +67,8 @@ pub struct InputMethod {
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)]
@@ -78,6 +84,7 @@ impl 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),
@@ -87,26 +94,48 @@ impl InputMethod {
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);
}
let method = INPUT_METHOD_REGISTRY.add(method);
let _ = node.input_method.set(method.clone());
Ok(method)
}
fn get(node: &Node) -> Result<Arc<Self>> {
node.get_aspect("Input Method", "input method", |n| &n.input_method)
.cloned()
}
fn capture_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let method = node.get_aspect("Input Method", "input method", |n| &n.input_method)?;
let handler_node = calling_client.get_node("Input Handler", deserialize(data)?)?;
let handler =
handler_node.get_aspect("Input Handler", "input handler", |n| &n.input_handler)?;
let method = InputMethod::get(node)?;
let handler = InputHandler::find(&calling_client, deserialize(data)?)?;
method.captures.add_raw(&handler);
Ok(())
node.send_remote_signal("capture", data)
}
fn set_datamap_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let method = node.get_aspect("Input Method", "input method", |n| &n.input_method)?;
let method = InputMethod::get(node)?;
method.datamap.lock().replace(Datamap::new(data.to_vec())?);
Ok(())
}
fn set_handlers_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let method = InputMethod::get(node)?;
let handler_paths: Vec<&str> = deserialize(data)?;
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 compare_distance(&self, to: &Field) -> f32 {
self.specialization
@@ -116,6 +145,49 @@ impl InputMethod {
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!["getTransform"],
..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 Drop for InputMethod {
fn drop(&mut self) {
@@ -137,7 +209,7 @@ impl DistanceLink {
&method.uid,
&method.node.upgrade()?,
AliasInfo {
local_signals: vec!["capture"],
server_signals: vec!["capture"],
..Default::default()
},
)
@@ -173,6 +245,7 @@ impl DistanceLink {
pub struct InputHandler {
enabled: Arc<AtomicBool>,
uid: String,
node: Weak<Node>,
spatial: Arc<Spatial>,
field: Arc<Field>,
@@ -187,15 +260,26 @@ impl InputHandler {
let handler = InputHandler {
enabled: node.enabled.clone(),
uid: node.uid.clone(),
node: Arc::downgrade(node),
spatial: node.spatial.get().unwrap().clone(),
field: field.clone(),
method_aliases: LifeLinkedNodeList::default(),
};
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
method.handle_new_handler(&handler);
}
let handler = INPUT_HANDLER_REGISTRY.add(handler);
let _ = node.input_handler.set(handler);
Ok(())
}
fn find(client: &Client, path: &str) -> Result<Arc<Self>> {
InputHandler::get(&*client.get_node("Input Handler", path)?)
}
fn get(node: &Node) -> Result<Arc<Self>> {
node.get_aspect("Input Handler", "input handler", |n| &n.input_handler)
.cloned()
}
#[instrument(level = "debug", skip(self, distance_link))]
fn send_input(&self, order: u32, distance_link: &DistanceLink, datamap: Datamap) {
@@ -211,12 +295,16 @@ impl PartialEq for InputHandler {
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(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(|_| ())
}
@@ -261,25 +349,39 @@ pub fn process_input() {
for method in methods {
debug_span!("Process input method").in_scope(|| {
// Get all valid input handlers and convert them to DistanceLink objects
let mut distance_links: Vec<DistanceLink> = debug_span!("Generate distance links")
let distance_links: Vec<DistanceLink> = debug_span!("Generate distance links")
.in_scope(|| {
handlers
.iter()
.filter(|handler| handler.enabled.load(Ordering::Relaxed))
.filter_map(|handler| DistanceLink::from(method.clone(), handler.clone()))
.collect()
});
if let Some(handler_order) = method.handler_order.get() {
let handler_order = handler_order.lock();
handler_order
.iter()
.filter_map(|h| h.upgrade())
.filter(|handler| handler.enabled.load(Ordering::Relaxed))
.filter_map(|handler| DistanceLink::from(method.clone(), handler))
.collect()
} else {
let mut distance_links: Vec<_> = handlers
.iter()
.filter(|handler| handler.enabled.load(Ordering::Relaxed))
.filter_map(|handler| {
DistanceLink::from(method.clone(), handler.clone())
})
.collect();
// Sort the distance links by their distance in ascending order
debug_span!("Sort distance links").in_scope(|| {
distance_links.sort_unstable_by(|a, b| {
a.distance.abs().partial_cmp(&b.distance.abs()).unwrap()
// Sort the distance links by their distance in ascending order
debug_span!("Sort distance links").in_scope(|| {
distance_links.sort_unstable_by(|a, b| {
a.distance.abs().partial_cmp(&b.distance.abs()).unwrap()
});
});
distance_links
}
});
});
let captures = method.captures.take_valid_contents();
// Iterate over the distance links and send input to them
for (i, distance_link) in distance_links.iter().enumerate() {
for (i, distance_link) in distance_links.into_iter().enumerate() {
distance_link.send_input(i as u32, method.datamap.lock().clone().unwrap());
// If the current distance link is in the list of captured input handlers,