diff --git a/src/core/client.rs b/src/core/client.rs index 74c9270..55aaa14 100644 --- a/src/core/client.rs +++ b/src/core/client.rs @@ -1,9 +1,9 @@ use super::{eventloop::EventLoop, scenegraph::Scenegraph}; use crate::{ core::registry::Registry, - nodes::{data, drawable, fields, hmd, input, items, root::Root, spatial, startup}, + nodes::{data, drawable, fields, hmd, input, items, root::Root, spatial, startup, Node}, }; -use anyhow::Result; +use anyhow::{anyhow, Result}; use lazy_static::lazy_static; use once_cell::sync::OnceCell; use parking_lot::Mutex; @@ -99,6 +99,13 @@ impl Client { client } + #[inline] + pub fn get_node(&self, name: &'static str, path: &str) -> Result> { + self.scenegraph + .get_node(path) + .ok_or_else(|| anyhow!("{} not found", name)) + } + pub async fn dispatch(&self) -> Result<(), std::io::Error> { match &self.messenger { Some(messenger) => messenger.dispatch(&self.scenegraph).await, diff --git a/src/nodes/data.rs b/src/nodes/data.rs index c8e9e52..b463831 100644 --- a/src/nodes/data.rs +++ b/src/nodes/data.rs @@ -1,16 +1,17 @@ use super::fields::Field; -use super::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use super::spatial::{parse_transform, Spatial}; use super::{Alias, Node}; use crate::core::client::Client; use crate::core::nodelist::LifeLinkedNodeList; use crate::core::registry::Registry; +use crate::nodes::fields::find_field; +use crate::nodes::spatial::find_spatial_parent; use anyhow::{anyhow, ensure, Result}; use glam::vec3a; use parking_lot::Mutex; use serde::Deserialize; use stardust_xr::schemas::flex::{deserialize, serialize}; use stardust_xr::values::Transform; - use std::sync::{Arc, Weak}; static PULSE_SENDER_REGISTRY: Registry = Registry::new(); @@ -253,7 +254,7 @@ pub fn create_pulse_sender_flex( } let info: CreatePulseSenderInfo = deserialize(data)?; let node = Node::create(&calling_client, "/data/sender", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + 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)?; @@ -285,16 +286,9 @@ pub fn create_pulse_receiver_flex( } let info: CreatePulseReceiverInfo = deserialize(data)?; let node = Node::create(&calling_client, "/data/sender", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let parent = find_spatial_parent(&calling_client, info.parent_path)?; let transform = parse_transform(info.transform, true, true, false)?; - let field = calling_client - .scenegraph - .get_node(info.field_path) - .ok_or_else(|| anyhow!("Field not found"))? - .field - .get() - .ok_or_else(|| anyhow!("Field node is not a field"))? - .clone(); + let field = find_field(&calling_client, info.field_path)?; let node = node.add_to_scenegraph(); Spatial::add_to(&node, Some(parent), transform)?; diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index 86e79e4..6f8e7b2 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -3,7 +3,7 @@ use crate::core::client::Client; use crate::core::destroy_queue; use crate::core::registry::Registry; use crate::core::resource::ResourceID; -use crate::nodes::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use anyhow::{anyhow, ensure, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; @@ -175,7 +175,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc, data: &[u8]) -> Re } let info: CreateModelInfo = deserialize(data)?; let node = Node::create(&calling_client, "/drawable/model", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let parent = find_spatial_parent(&calling_client, info.parent_path)?; let transform = parse_transform(info.transform, true, true, true)?; let node = node.add_to_scenegraph(); Spatial::add_to(&node, Some(parent), transform)?; diff --git a/src/nodes/drawable/text.rs b/src/nodes/drawable/text.rs index d86bc1b..462edac 100644 --- a/src/nodes/drawable/text.rs +++ b/src/nodes/drawable/text.rs @@ -1,7 +1,7 @@ use crate::{ core::{client::Client, destroy_queue, registry::Registry, resource::ResourceID}, nodes::{ - spatial::{get_spatial_parent_flex, parse_transform, Spatial}, + spatial::{find_spatial_parent, parse_transform, Spatial}, Node, }, }; @@ -190,7 +190,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc, data: &[u8]) -> Re } let info: CreateTextInfo = deserialize(data)?; let node = Node::create(&calling_client, "/drawable/text", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let parent = find_spatial_parent(&calling_client, info.parent_path)?; let transform = parse_transform(info.transform, true, true, true)?; let color = Rgba::from_slice(&info.color); diff --git a/src/nodes/fields/box.rs b/src/nodes/fields/box.rs index 7664f35..cae7a48 100644 --- a/src/nodes/fields/box.rs +++ b/src/nodes/fields/box.rs @@ -1,6 +1,6 @@ use super::{Field, FieldTrait, Node}; use crate::core::client::Client; -use crate::nodes::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use anyhow::{ensure, Result}; use glam::{vec3, vec3a, Vec3, Vec3A}; use mint::Vector3; @@ -73,7 +73,7 @@ pub fn create_box_field_flex(_node: &Node, calling_client: Arc, data: &[ } let info: CreateFieldInfo = deserialize(data)?; let node = Node::create(&calling_client, "/field", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + 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)?; diff --git a/src/nodes/fields/cylinder.rs b/src/nodes/fields/cylinder.rs index 877f328..d1befb2 100644 --- a/src/nodes/fields/cylinder.rs +++ b/src/nodes/fields/cylinder.rs @@ -1,6 +1,6 @@ use super::{Field, FieldTrait, Node}; use crate::core::client::Client; -use crate::nodes::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use anyhow::{ensure, Result}; use glam::{swizzles::*, vec2, Vec3A}; use portable_atomic::AtomicF32; @@ -80,7 +80,7 @@ pub fn create_cylinder_field_flex( } let info: CreateFieldInfo = deserialize(data)?; let node = Node::create(&calling_client, "/field", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + 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)?; diff --git a/src/nodes/fields/mod.rs b/src/nodes/fields/mod.rs index bdc7219..b4df14c 100644 --- a/src/nodes/fields/mod.rs +++ b/src/nodes/fields/mod.rs @@ -9,7 +9,8 @@ use self::sphere::{create_sphere_field_flex, SphereField}; use super::spatial::Spatial; use super::Node; use crate::core::client::Client; -use anyhow::{anyhow, Result}; +use crate::nodes::spatial::find_reference_space; +use anyhow::Result; use glam::{vec2, vec3a, Vec3, Vec3A}; use mint::Vector3; use serde::Deserialize; @@ -76,14 +77,7 @@ fn field_distance_flex(node: &Node, calling_client: Arc, data: &[u8]) -> point: Vector3, } let args: FieldInfoArgs = deserialize(data)?; - let reference_space = calling_client - .scenegraph - .get_node(args.reference_space_path) - .ok_or_else(|| anyhow!("Reference space node does not exist"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Reference space node does not have a spatial"))? - .clone(); + let reference_space = find_reference_space(&calling_client, args.reference_space_path)?; let distance = node .field @@ -100,14 +94,7 @@ fn field_normal_flex(node: &Node, calling_client: Arc, data: &[u8]) -> R radius: Option, } let args: FieldInfoArgs = deserialize(data)?; - let reference_space = calling_client - .scenegraph - .get_node(args.reference_space_path) - .ok_or_else(|| anyhow!("Reference space node does not exist"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Reference space node does not have a spatial"))? - .clone(); + let reference_space = find_reference_space(&calling_client, args.reference_space_path)?; let normal = node.field.get().as_ref().unwrap().normal( reference_space.as_ref(), @@ -128,14 +115,7 @@ fn field_closest_point_flex( radius: Option, } let args: FieldInfoArgs = deserialize(data)?; - let reference_space = calling_client - .scenegraph - .get_node(args.reference_space_path) - .ok_or_else(|| anyhow!("Reference space node does not exist"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Reference space node does not have a spatial"))? - .clone(); + let reference_space = find_reference_space(&calling_client, args.reference_space_path)?; let closest_point = node.field.get().as_ref().unwrap().closest_point( reference_space.as_ref(), @@ -224,3 +204,9 @@ pub fn ray_march(ray: Ray, field: &Field) -> RayMarchResult { result } + +pub fn find_field(client: &Client, path: &str) -> Result> { + Ok(client + .get_node("Field", path)? + .get_aspect("Field", "info", |n| &n.field)?) +} diff --git a/src/nodes/fields/sphere.rs b/src/nodes/fields/sphere.rs index e9f058a..815e28f 100644 --- a/src/nodes/fields/sphere.rs +++ b/src/nodes/fields/sphere.rs @@ -1,6 +1,6 @@ use super::{Field, FieldTrait, Node}; use crate::core::client::Client; -use crate::nodes::spatial::{get_spatial_parent_flex, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, Spatial}; use anyhow::{ensure, Result}; use glam::{Mat4, Vec3A}; use mint::Vector3; @@ -77,7 +77,7 @@ pub fn create_sphere_field_flex( } let info: CreateFieldInfo = deserialize(data)?; let node = Node::create(&calling_client, "/field", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let parent = find_spatial_parent(&calling_client, info.parent_path)?; let transform = Mat4::from_translation( info.origin .unwrap_or_else(|| Vector3::from([0.0; 3])) diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index fbdcff5..3b682c6 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -7,12 +7,13 @@ use self::pointer::Pointer; use self::tip::Tip; use super::fields::Field; -use super::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use super::spatial::{find_spatial_parent, parse_transform, Spatial}; use super::Node; use crate::core::client::Client; use crate::core::eventloop::FRAME; use crate::core::registry::Registry; -use anyhow::{anyhow, ensure, Result}; +use crate::nodes::fields::find_field; +use anyhow::{ensure, Result}; use glam::Mat4; use nanoid::nanoid; use parking_lot::Mutex; @@ -227,19 +228,11 @@ pub fn create_input_handler_flex( field_path: &'a str, } let info: CreateInputHandlerInfo = deserialize(data)?; - let node = Node::create(&calling_client, "/input/handler", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let parent = find_spatial_parent(&calling_client, info.parent_path)?; let transform = parse_transform(info.transform, true, true, false)?; - let field = calling_client - .scenegraph - .get_node(info.field_path) - .ok_or_else(|| anyhow!("Field not found"))? - .field - .get() - .ok_or_else(|| anyhow!("Field node is not a field"))? - .clone(); + let field = find_field(&calling_client, info.field_path)?; - let node = node.add_to_scenegraph(); + let node = Node::create(&calling_client, "/input/handler", info.name, true).add_to_scenegraph(); Spatial::add_to(&node, Some(parent), transform)?; InputHandler::add_to(&node, &field)?; Ok(()) diff --git a/src/nodes/input/tip.rs b/src/nodes/input/tip.rs index 5e4aa11..ac5cf87 100644 --- a/src/nodes/input/tip.rs +++ b/src/nodes/input/tip.rs @@ -2,7 +2,7 @@ use super::{DistanceLink, InputSpecialization}; use crate::core::client::Client; use crate::nodes::fields::Field; use crate::nodes::input::{InputMethod, InputType}; -use crate::nodes::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::Node; use anyhow::Result; use glam::{vec3a, Mat4}; @@ -53,7 +53,7 @@ pub fn create_tip_flex(_node: &Node, calling_client: Arc, data: &[u8]) - } let info: CreateTipInfo = deserialize(data)?; let node = Node::create(&calling_client, "/input/method/tip", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + 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(); diff --git a/src/nodes/items/environment.rs b/src/nodes/items/environment.rs index e2b0fdb..7cce788 100644 --- a/src/nodes/items/environment.rs +++ b/src/nodes/items/environment.rs @@ -2,7 +2,7 @@ use super::{Item, ItemSpecialization, ItemType, ITEM_TYPE_INFO_ENVIRONMENT}; use crate::{ core::client::{Client, INTERNAL_CLIENT}, nodes::{ - spatial::{get_spatial_parent_flex, parse_transform, Spatial}, + spatial::{find_spatial_parent, parse_transform, Spatial}, Node, }, }; @@ -56,7 +56,7 @@ pub(super) fn create_environment_item_flex( let info: CreateEnvironmentItemInfo = deserialize(data)?; let parent_name = format!("/item/{}/item/", ITEM_TYPE_INFO_ENVIRONMENT.type_name); let node = Node::create(&INTERNAL_CLIENT, &parent_name, info.name, true); - let space = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let space = 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, None, transform * space.global_transform())?; diff --git a/src/nodes/items/mod.rs b/src/nodes/items/mod.rs index 19600ff..a5da2dd 100644 --- a/src/nodes/items/mod.rs +++ b/src/nodes/items/mod.rs @@ -1,13 +1,13 @@ mod environment; use self::environment::EnvironmentItem; - use super::fields::Field; -use super::spatial::{get_spatial_parent_flex, parse_transform, Spatial}; +use super::spatial::{find_spatial_parent, parse_transform, Spatial}; use super::{Alias, Node}; use crate::core::client::{Client, INTERNAL_CLIENT}; use crate::core::nodelist::LifeLinkedNodeList; use crate::core::registry::Registry; +use crate::nodes::fields::find_field; use crate::wayland::panel_item::{register_panel_item_ui_flex, PanelItem}; use anyhow::{anyhow, ensure, Result}; use lazy_static::lazy_static; @@ -356,20 +356,13 @@ pub(self) fn create_item_acceptor_flex( } let info: CreateItemAcceptorInfo = deserialize(data)?; let parent_name = format!("/item/{}/acceptor/", ITEM_TYPE_INFO_ENVIRONMENT.type_name); - let space = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let space = find_spatial_parent(&calling_client, info.parent_path)?; let transform = parse_transform(info.transform, true, true, false)?; - let field = calling_client - .scenegraph - .get_node(info.field_path) - .ok_or_else(|| anyhow!("Field node not found"))?; - let field = field - .field - .get() - .ok_or_else(|| anyhow!("Field node is not a field"))?; + let field = find_field(&calling_client, info.field_path)?; let node = Node::create(&INTERNAL_CLIENT, &parent_name, info.name, true).add_to_scenegraph(); Spatial::add_to(&node, Some(space), transform)?; - ItemAcceptor::add_to(&node, type_info, Arc::downgrade(field)); + ItemAcceptor::add_to(&node, type_info, Arc::downgrade(&field)); node.item .get() .unwrap() diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index fc02681..93c4485 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -145,6 +145,21 @@ impl Node { self.local_methods.insert(name.to_string(), method); } + pub fn get_aspect( + &self, + node_name: &'static str, + aspect_type: &'static str, + aspect_fn: F, + ) -> Result> + where + F: FnOnce(&Node) -> &OnceCell>, + { + aspect_fn(self) + .get() + .ok_or_else(|| anyhow!("{} is not a {} node", node_name, aspect_type)) + .cloned() + } + pub fn send_local_signal( &self, calling_client: Arc, diff --git a/src/nodes/spatial.rs b/src/nodes/spatial.rs index e730ac2..e81fd0d 100644 --- a/src/nodes/spatial.rs +++ b/src/nodes/spatial.rs @@ -161,14 +161,7 @@ impl Spatial { .spatial .get() .ok_or_else(|| anyhow!("Node doesn't have a spatial?"))?; - let relative_spatial = calling_client - .scenegraph - .get_node(deserialize(data)?) - .ok_or_else(|| anyhow!("Space not found"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Reference space node is not a spatial"))? - .clone(); + let relative_spatial = find_reference_space(&calling_client, deserialize(data)?)?; let (scale, rotation, position) = Spatial::space_to_space_matrix( Some(this_spatial.as_ref()), @@ -192,16 +185,7 @@ impl Spatial { let transform_args: TransformArgs = deserialize(data)?; let reference_space_transform = transform_args .reference_space_path - .map(|path| -> Result> { - Ok(calling_client - .scenegraph - .get_node(path) - .ok_or_else(|| anyhow!("Other spatial node not found"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Node is not a Spatial!"))? - .clone()) - }) + .map(|path| find_reference_space(&calling_client, path)) .transpose()?; node.spatial.get().unwrap().set_local_transform_components( @@ -215,34 +199,18 @@ impl Spatial { calling_client: Arc, data: &[u8], ) -> Result<()> { - let parent = calling_client - .scenegraph - .get_node(deserialize(data)?) - .ok_or_else(|| anyhow!("Parent node not found"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Parent node is not a Spatial!"))? - .clone(); + let parent = find_spatial_parent(&calling_client, deserialize(data)?)?; node.spatial .get() .unwrap() - .set_spatial_parent(Some(&parent))?; - Ok(()) + .set_spatial_parent(Some(&parent)) } pub fn set_spatial_parent_in_place_flex( node: &Node, calling_client: Arc, data: &[u8], ) -> Result<()> { - let parent_path = flexbuffers::Reader::get_root(data)?.get_str()?; - let parent = calling_client - .scenegraph - .get_node(parent_path) - .ok_or_else(|| anyhow!("Parent node not found"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Parent node is not a Spatial!"))? - .clone(); + let parent = find_spatial_parent(&calling_client, deserialize(data)?)?; node.spatial .get() .unwrap() @@ -277,18 +245,27 @@ pub fn parse_transform( )) } -pub fn get_spatial_parent_flex( +pub fn find_spatial( + calling_client: &Arc, + node_name: &'static str, + node_path: &str, +) -> anyhow::Result> { + Ok(calling_client + .get_node(node_name, node_path)? + .get_aspect(node_name, "spatial", |n| &n.spatial)? + .clone()) +} +pub fn find_spatial_parent( calling_client: &Arc, node_path: &str, -) -> Result> { - Ok(calling_client - .scenegraph - .get_node(node_path) - .ok_or_else(|| anyhow!("Spatial parent node not found"))? - .spatial - .get() - .ok_or_else(|| anyhow!("Spatial parent node is not a spatial"))? - .clone()) +) -> anyhow::Result> { + find_spatial(calling_client, "Spatial parent", node_path) +} +pub fn find_reference_space( + calling_client: &Arc, + node_path: &str, +) -> anyhow::Result> { + find_spatial(calling_client, "Reference space", node_path) } pub fn create_interface(client: &Arc) { @@ -306,7 +283,7 @@ pub fn create_spatial_flex(_node: &Node, calling_client: Arc, data: &[u8 } let info: CreateSpatialInfo = deserialize(data)?; let node = Node::create(&calling_client, "/spatial/spatial", info.name, true); - let parent = get_spatial_parent_flex(&calling_client, info.parent_path)?; + let parent = find_spatial(&calling_client, "Spatial parent", info.parent_path)?; let transform = parse_transform(info.transform, true, true, true)?; let node = node.add_to_scenegraph(); Spatial::add_to(&node, Some(parent), transform)?;