use super::{DistanceLink, InputSpecialization}; use crate::core::client::Client; use crate::nodes::fields::Field; use crate::nodes::input::{InputMethod, InputType}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::Node; use color_eyre::eyre::Result; use glam::{vec3a, Mat4}; use serde::Deserialize; use stardust_xr::schemas::flat::{Datamap, InputDataType, Tip as FlatTip}; use stardust_xr::schemas::flex::deserialize; use stardust_xr::values::Transform; use std::sync::Arc; #[derive(Default)] pub struct Tip { pub radius: f32, } impl Tip { fn set_radius(node: &Node, _calling_client: Arc, data: &[u8]) -> Result<()> { if let InputType::Tip(tip) = &mut *node.input_method.get().unwrap().specialization.lock() { tip.radius = deserialize(data)?; } Ok(()) } } impl InputSpecialization for Tip { fn compare_distance(&self, space: &Arc, field: &Field) -> f32 { field.distance(space, vec3a(0.0, 0.0, 0.0)).abs() } fn true_distance(&self, space: &Arc, field: &Field) -> f32 { field.distance(space, vec3a(0.0, 0.0, 0.0)) } fn serialize( &self, _distance_link: &DistanceLink, local_to_handler_matrix: Mat4, ) -> InputDataType { let (_, orientation, origin) = local_to_handler_matrix.to_scale_rotation_translation(); InputDataType::Tip(FlatTip { origin: origin.into(), orientation: orientation.into(), radius: self.radius, }) } } pub fn create_tip_flex(_node: &Node, calling_client: Arc, data: &[u8]) -> Result<()> { #[derive(Deserialize)] struct CreateTipInfo<'a> { name: &'a str, parent_path: &'a str, transform: Transform, radius: f32, datamap: Option>, } let info: CreateTipInfo = deserialize(data)?; let node = Node::create(&calling_client, "/input/method/tip", info.name, true); let parent = find_spatial_parent(&calling_client, info.parent_path)?; let transform = parse_transform(info.transform, true, true, false)?; let node = node.add_to_scenegraph(); Spatial::add_to(&node, Some(parent), transform, false)?; InputMethod::add_to( &node, InputType::Tip(Tip { radius: info.radius, }), info.datamap.and_then(|datamap| Datamap::new(datamap).ok()), )?; node.add_local_signal("set_radius", Tip::set_radius); Ok(()) }