// TODO: reimplement with bevy // pub mod camera; pub mod panel; // use self::camera::CameraItem; use self::panel::PanelItemTrait; use super::alias::AliasList; use super::fields::{Field, FIELD_ALIAS_INFO}; use super::spatial::Spatial; use super::{Alias, Aspect, AspectIdentifier, Node}; use crate::core::client::Client; use crate::core::error::Result; use crate::core::registry::Registry; use crate::ensure; use crate::nodes::alias::AliasInfo; use crate::nodes::spatial::Transform; use crate::nodes::spatial::SPATIAL_ASPECT_ALIAS_INFO; use parking_lot::Mutex; use std::hash::Hash; use std::sync::{Arc, Weak}; stardust_xr_server_codegen::codegen_item_protocol!(); fn capture(item: &Arc, acceptor: &Arc) { if item.captured_acceptor.lock().strong_count() > 0 { release(item); } *item.captured_acceptor.lock() = Arc::downgrade(acceptor); acceptor.handle_capture(item); if let Some(ui) = item.type_info.ui.lock().upgrade() { ui.handle_capture_item(item, acceptor); } } fn release(item: &Item) { let mut captured_acceptor = item.captured_acceptor.lock(); if let Some(acceptor) = captured_acceptor.upgrade().as_ref() { *captured_acceptor = Weak::default(); acceptor.handle_release(item); if let Some(ui) = item.type_info.ui.lock().upgrade() { ui.handle_release_item(item, acceptor); } } } pub struct TypeInfo { pub type_name: &'static str, pub alias_info: AliasInfo, pub ui_node_id: u64, pub ui: Mutex>, pub items: Registry, pub acceptors: Registry, pub add_ui_aspect: fn(node: &Node), pub add_acceptor_aspect: fn(node: &Node), pub new_acceptor_fn: fn(node: &Node, acceptor: &Arc, acceptor_field: &Arc), } impl Hash for TypeInfo { fn hash(&self, state: &mut H) { self.type_name.hash(state); } } impl PartialEq for TypeInfo { fn eq(&self, other: &Self) -> bool { self.type_name == other.type_name } } impl Eq for TypeInfo {} pub struct Item { spatial: Arc, type_info: &'static TypeInfo, captured_acceptor: Mutex>, pub specialization: ItemType, } impl Item { pub fn add_to( node: &Arc, type_info: &'static TypeInfo, specialization: ItemType, ) -> Arc { let item = Item { spatial: node.aspects.get::().unwrap(), type_info, captured_acceptor: Default::default(), specialization, }; let item = type_info.items.add(item); if let Some(ui) = type_info.ui.lock().upgrade() { ui.handle_create_item(&item); } node.add_aspect_raw(item.clone()); // if let Some(auto_acceptor) = node.get_client().and_then(|client| { // client // .state // .as_ref() // .and_then(|settings| settings.acceptors.get(type_info)) // .and_then(|acceptor| acceptor.upgrade()) // }) { // capture(&item, &auto_acceptor); // } item } fn make_alias(&self, client: &Arc, alias_list: &AliasList) -> Result> { Alias::create( &self.spatial.node().unwrap(), client, self.type_info.alias_info.clone() + ITEM_ASPECT_ALIAS_INFO.clone(), Some(alias_list), ) } } impl AspectIdentifier for Item { impl_aspect_for_item_aspect_id! {} } impl Aspect for Item { impl_aspect_for_item_aspect! {} } impl ItemAspect for Item { fn release(node: Arc, _calling_client: Arc) -> Result<()> { let item = node.get_aspect::()?; release(&item); Ok(()) } } impl Drop for Item { fn drop(&mut self) { self.type_info.items.remove(self); release(self); if let Some(ui) = self.type_info.ui.lock().upgrade() { ui.handle_destroy_item(self); } } } pub enum ItemType { // Camera(CameraItem), Panel(Arc), } impl ItemType { fn send_ui_item_created(&self, node: &Node, item: &Arc) { match self { // ItemType::Camera(c) => c.send_ui_item_created(node, item), ItemType::Panel(p) => p.send_ui_item_created(node, item), } } fn send_acceptor_item_created(&self, node: &Node, item: &Arc) { match self { // ItemType::Camera(c) => c.send_acceptor_item_created(node, item), ItemType::Panel(p) => p.send_acceptor_item_created(node, item), } } } // impl Deref for ItemType { // type Target = dyn ItemSpecialization; // fn deref(&self) -> &Self::Target { // match self { // ItemType::Environment(item) => item, // ItemType::Panel(item) => item.as_ref(), // } // } // } pub struct ItemUI { node: Weak, type_info: &'static TypeInfo, item_aliases: AliasList, acceptor_aliases: AliasList, acceptor_field_aliases: AliasList, } impl ItemUI { fn add_to(node: &Arc, type_info: &'static TypeInfo) -> Result<()> { ensure!( type_info.ui.lock().upgrade().is_none(), "A UI is already active for this type of item" ); let ui = Arc::new(ItemUI { node: Arc::downgrade(node), type_info, item_aliases: AliasList::default(), acceptor_aliases: AliasList::default(), acceptor_field_aliases: AliasList::default(), }); *type_info.ui.lock() = Arc::downgrade(&ui); node.add_aspect_raw(ui.clone()); for item in type_info.items.get_valid_contents() { ui.handle_create_item(&item); } for acceptor in type_info.acceptors.get_valid_contents() { ui.handle_create_acceptor(&acceptor); } Ok(()) } fn handle_create_item(&self, item: &Item) { let Some(node) = self.node.upgrade() else { return; }; let Some(client) = node.get_client() else { return; }; let Ok(item_alias) = item.make_alias(&client, &self.item_aliases) else { return; }; item.specialization.send_ui_item_created(&node, &item_alias); } fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) { let Some(item_alias) = self.item_aliases.get_from_aspect(item) else { return; }; let Some(acceptor_alias) = self.acceptor_aliases.get_from_aspect(acceptor) else { return; }; let _ = item_ui_client::capture_item( &self.node.upgrade().unwrap(), item_alias.id, acceptor_alias.id, ); } fn handle_release_item(&self, item: &Item, acceptor: &ItemAcceptor) { let Some(item_alias) = self.item_aliases.get_from_aspect(item) else { return; }; let Some(acceptor_alias) = self.acceptor_aliases.get_from_aspect(acceptor) else { return; }; let _ = item_ui_client::release_item( &self.node.upgrade().unwrap(), item_alias.id, acceptor_alias.id, ); } fn handle_destroy_item(&self, item: &Item) { let Some(item_alias) = self .item_aliases .get_from_original_node(item.spatial.node.clone()) else { return; }; let _ = item_ui_client::destroy_item(&self.node.upgrade().unwrap(), item_alias.id); self.item_aliases.remove_aspect(item); } fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) { let Some(node) = self.node.upgrade() else { return; }; let Some(client) = node.get_client() else { return; }; let Some(acceptor_node) = acceptor.spatial.node() else { return; }; let Ok(acceptor_alias) = Alias::create( &acceptor_node, &client, ITEM_ACCEPTOR_ASPECT_ALIAS_INFO.clone(), Some(&self.acceptor_aliases), ) else { return; }; let Some(acceptor_field_node) = acceptor.field.spatial.node() else { return; }; let Ok(acceptor_field_alias) = Alias::create( &acceptor_field_node, &client, FIELD_ALIAS_INFO.clone(), Some(&self.acceptor_aliases), ) else { return; }; (acceptor.type_info.new_acceptor_fn)(&node, &acceptor_alias, &acceptor_field_alias); } fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) { let acceptor_alias = self.acceptor_aliases.get_from_aspect(acceptor).unwrap(); let _ = item_ui_client::destroy_acceptor(&self.node.upgrade().unwrap(), acceptor_alias.id); self.acceptor_aliases .remove_aspect(acceptor.spatial.as_ref()); self.acceptor_field_aliases .remove_aspect(acceptor.field.as_ref()); } } impl AspectIdentifier for ItemUI { impl_aspect_for_item_ui_aspect_id! {} } impl Aspect for ItemUI { impl_aspect_for_item_ui_aspect! {} } impl Drop for ItemUI { fn drop(&mut self) { *self.type_info.ui.lock() = Weak::new(); } } pub struct ItemAcceptor { spatial: Arc, pub type_info: &'static TypeInfo, field: Arc, accepted_aliases: AliasList, accepted_registry: Registry, } impl ItemAcceptor { fn add_to(node: &Arc, type_info: &'static TypeInfo, field: Arc) { let acceptor = type_info.acceptors.add(ItemAcceptor { spatial: node.get_aspect::().unwrap(), type_info, field, accepted_aliases: AliasList::default(), accepted_registry: Registry::new(), }); if let Some(ui) = type_info.ui.lock().upgrade() { ui.handle_create_acceptor(&acceptor); } node.add_aspect_raw(acceptor.clone()); } fn handle_capture(&self, item: &Arc) { let Some(node) = self.spatial.node() else { return; }; let Some(client) = node.get_client() else { return; }; self.accepted_registry.add_raw(item); let Ok(alias_node) = item.make_alias(&client, &self.accepted_aliases) else { return; }; item.specialization .send_acceptor_item_created(&node, &alias_node); } fn handle_release(&self, item: &Item) { self.accepted_registry.remove(item); self.accepted_aliases.remove_aspect(item); let Some(node) = self.spatial.node() else { return; }; let alias = self.accepted_aliases.get_from_aspect(item).unwrap(); let _ = item_acceptor_client::release_item(&node, alias.id); } } impl AspectIdentifier for ItemAcceptor { impl_aspect_for_item_acceptor_aspect_id! {} } impl Aspect for ItemAcceptor { impl_aspect_for_item_acceptor_aspect! {} } impl ItemAcceptorAspect for ItemAcceptor {} impl Drop for ItemAcceptor { fn drop(&mut self) { self.type_info.acceptors.remove(self); for item in self.accepted_registry.get_valid_contents() { release(&item); } if let Some(ui) = self.type_info.ui.lock().upgrade() { ui.handle_destroy_acceptor(self); } } } pub fn register_item_ui_flex( calling_client: Arc, type_info: &'static TypeInfo, ) -> Result<()> { let ui = Node::from_id(&calling_client, type_info.ui_node_id, true).add_to_scenegraph()?; ItemUI::add_to(&ui, type_info)?; (type_info.add_ui_aspect)(&ui); Ok(()) } fn create_item_acceptor_flex( calling_client: Arc, id: u64, parent: Arc, transform: Transform, type_info: &'static TypeInfo, field: Arc, ) -> Result<()> { let space = parent.get_aspect::()?; let field = field.get_aspect::()?; let transform = transform.to_mat4(true, true, false); let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?; Spatial::add_to(&node, Some(space.clone()), transform, false); ItemAcceptor::add_to(&node, type_info, field); (type_info.add_acceptor_aspect)(&node); Ok(()) } fn acceptor_capture_item_flex(node: Arc, item: Arc) -> Result<()> { let acceptor = node.get_aspect::()?; let item = item.get_aspect::()?; capture(&item, &acceptor); Ok(()) }