feat: upgrade to numerical IDs
This commit is contained in:
@@ -1,21 +1,23 @@
|
||||
use super::{
|
||||
client_state::{ClientState, CLIENT_STATES},
|
||||
client_state::{ClientStateParsed, CLIENT_STATES},
|
||||
destroy_queue,
|
||||
scenegraph::Scenegraph,
|
||||
};
|
||||
use crate::{
|
||||
core::{registry::OwnedRegistry, task},
|
||||
nodes::{audio, data, drawable, fields, hmd, input, items, root::Root, spatial, Node},
|
||||
nodes::{
|
||||
audio, data, drawable, fields, hmd, input, items,
|
||||
root::{ClientState, Root},
|
||||
spatial, Node,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use global_counter::primitive::exact::CounterU32;
|
||||
use lazy_static::lazy_static;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use stardust_xr::{
|
||||
messenger::{self, MessageSenderHandle},
|
||||
schemas::flex::serialize,
|
||||
};
|
||||
use stardust_xr::messenger::{self, MessageSenderHandle};
|
||||
use std::{fmt::Debug, fs, iter::FromIterator, path::PathBuf, sync::Arc};
|
||||
use tokio::{net::UnixStream, task::JoinHandle};
|
||||
use tracing::info;
|
||||
@@ -32,10 +34,11 @@ lazy_static! {
|
||||
disconnect_status: OnceCell::new(),
|
||||
|
||||
message_sender_handle: None,
|
||||
id_counter: CounterU32::new(0),
|
||||
scenegraph: Default::default(),
|
||||
root: OnceCell::new(),
|
||||
base_resource_prefixes: Default::default(),
|
||||
state: Arc::new(ClientState::default()),
|
||||
state: OnceCell::default(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -47,7 +50,7 @@ pub fn get_env(pid: i32) -> Result<FxHashMap<String, String>, std::io::Error> {
|
||||
.map(|(k, v)| (k.to_string(), v.to_string())),
|
||||
))
|
||||
}
|
||||
pub fn state(env: &FxHashMap<String, String>) -> Option<Arc<ClientState>> {
|
||||
pub fn state(env: &FxHashMap<String, String>) -> Option<Arc<ClientStateParsed>> {
|
||||
let token = env.get("STARDUST_STARTUP_TOKEN")?;
|
||||
CLIENT_STATES.lock().get(token).cloned()
|
||||
}
|
||||
@@ -60,11 +63,12 @@ pub struct Client {
|
||||
flush_join_handle: OnceCell<JoinHandle<Result<()>>>,
|
||||
disconnect_status: OnceCell<Result<()>>,
|
||||
|
||||
id_counter: CounterU32,
|
||||
pub message_sender_handle: Option<MessageSenderHandle>,
|
||||
pub scenegraph: Arc<Scenegraph>,
|
||||
pub root: OnceCell<Arc<Root>>,
|
||||
pub base_resource_prefixes: Mutex<Vec<PathBuf>>,
|
||||
pub state: Arc<ClientState>,
|
||||
pub state: OnceCell<ClientState>,
|
||||
}
|
||||
impl Client {
|
||||
pub fn from_connection(connection: UnixStream) -> Result<Arc<Self>> {
|
||||
@@ -84,7 +88,7 @@ impl Client {
|
||||
let state = env
|
||||
.as_ref()
|
||||
.and_then(state)
|
||||
.unwrap_or_else(|| Arc::new(ClientState::default()));
|
||||
.unwrap_or_else(|| Arc::new(ClientStateParsed::default()));
|
||||
|
||||
let client = CLIENTS.add(Client {
|
||||
pid,
|
||||
@@ -95,14 +99,15 @@ impl Client {
|
||||
flush_join_handle: OnceCell::new(),
|
||||
disconnect_status: OnceCell::new(),
|
||||
|
||||
id_counter: CounterU32::new(256),
|
||||
message_sender_handle: Some(messenger_tx.handle()),
|
||||
scenegraph: scenegraph.clone(),
|
||||
root: OnceCell::new(),
|
||||
base_resource_prefixes: Default::default(),
|
||||
state,
|
||||
state: OnceCell::default(),
|
||||
});
|
||||
let _ = client.scenegraph.client.set(Arc::downgrade(&client));
|
||||
let _ = client.root.set(Root::create(&client)?);
|
||||
let _ = client.root.set(Root::create(&client, state.root)?);
|
||||
hmd::make_alias(&client)?;
|
||||
spatial::create_interface(&client)?;
|
||||
fields::create_interface(&client)?;
|
||||
@@ -113,12 +118,7 @@ impl Client {
|
||||
items::camera::create_interface(&client)?;
|
||||
items::panel::create_interface(&client)?;
|
||||
|
||||
client
|
||||
.root
|
||||
.get()
|
||||
.unwrap()
|
||||
.node
|
||||
.send_remote_signal("restore_state", serialize(client.state.apply_to(&client))?)?;
|
||||
let _ = client.state.set(state.apply_to(&client));
|
||||
|
||||
let pid_printable = pid
|
||||
.map(|pid| pid.to_string())
|
||||
@@ -191,15 +191,19 @@ impl Client {
|
||||
let cwd_proc_path = format!("/proc/{pid}/cwd");
|
||||
std::fs::read_link(cwd_proc_path).ok()
|
||||
}
|
||||
pub async fn save_state(&self) -> Option<ClientState> {
|
||||
pub async fn save_state(&self) -> Option<ClientStateParsed> {
|
||||
let internal = self.root.get()?.save_state().await.ok()?;
|
||||
Some(ClientState::from_deserialized(self, internal))
|
||||
Some(ClientStateParsed::from_deserialized(self, internal))
|
||||
}
|
||||
|
||||
pub fn generate_id(&self) -> u64 {
|
||||
self.id_counter.inc() as u64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_node(&self, name: &'static str, path: &str) -> Result<Arc<Node>> {
|
||||
pub fn get_node(&self, name: &'static str, id: u64) -> Result<Arc<Node>> {
|
||||
self.scenegraph
|
||||
.get_node(path)
|
||||
.get_node(id)
|
||||
.ok_or_else(|| eyre!("{} not found", name))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::client::{get_env, Client};
|
||||
use crate::nodes::{spatial::Spatial, Node};
|
||||
use crate::nodes::{root::ClientState, spatial::Spatial, Node};
|
||||
use glam::Mat4;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
@@ -11,7 +11,7 @@ use std::{
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref CLIENT_STATES: Mutex<FxHashMap<String, Arc<ClientState>>> = Default::default();
|
||||
pub static ref CLIENT_STATES: Mutex<FxHashMap<String, Arc<ClientStateParsed>>> = Default::default();
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -31,28 +31,27 @@ impl LaunchInfo {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ClientState {
|
||||
pub struct ClientStateParsed {
|
||||
pub launch_info: Option<LaunchInfo>,
|
||||
pub data: Vec<u8>,
|
||||
pub root: Mat4,
|
||||
pub spatial_anchors: FxHashMap<String, Mat4>,
|
||||
}
|
||||
impl ClientState {
|
||||
pub fn from_deserialized(client: &Client, state: ClientStateInternal) -> Self {
|
||||
ClientState {
|
||||
impl ClientStateParsed {
|
||||
pub fn from_deserialized(client: &Client, state: ClientState) -> Self {
|
||||
ClientStateParsed {
|
||||
launch_info: LaunchInfo::from_client(client),
|
||||
data: state.data.unwrap_or_default(),
|
||||
root: Self::spatial_transform(client, &state.root.unwrap_or_default())
|
||||
.unwrap_or_default(),
|
||||
root: Self::spatial_transform(client, state.root).unwrap_or_default(),
|
||||
spatial_anchors: state
|
||||
.spatial_anchors
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| Some((k, Self::spatial_transform(client, &v)?)))
|
||||
.filter_map(|(k, v)| Some((k, Self::spatial_transform(client, v)?)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
fn spatial_transform(client: &Client, path: &str) -> Option<Mat4> {
|
||||
let node = client.scenegraph.get_node(path)?;
|
||||
fn spatial_transform(client: &Client, id: u64) -> Option<Mat4> {
|
||||
let node = client.scenegraph.get_node(id)?;
|
||||
let spatial = node.get_aspect::<Spatial>().ok()?;
|
||||
Some(spatial.global_transform())
|
||||
}
|
||||
@@ -79,24 +78,20 @@ impl ClientState {
|
||||
std::fs::write(state_file_path, toml::to_string(&self).unwrap()).unwrap();
|
||||
}
|
||||
|
||||
pub fn apply_to(&self, client: &Arc<Client>) -> ClientStateInternal {
|
||||
pub fn apply_to(&self, client: &Arc<Client>) -> ClientState {
|
||||
if let Some(root) = client.root.get() {
|
||||
root.set_transform(self.root)
|
||||
}
|
||||
ClientStateInternal {
|
||||
ClientState {
|
||||
data: Some(self.data.clone()),
|
||||
root: Some("/".to_string()),
|
||||
root: 0,
|
||||
spatial_anchors: self
|
||||
.spatial_anchors
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(k.clone(), {
|
||||
let node = Node::create_parent_name(client, "/spatial/anchor", k, true)
|
||||
.add_to_scenegraph()
|
||||
.unwrap();
|
||||
Spatial::add_to(&node, None, *v, false);
|
||||
k.clone()
|
||||
})
|
||||
let node = Node::generate(client, true).add_to_scenegraph().unwrap();
|
||||
Spatial::add_to(&node, None, *v, false);
|
||||
(k.clone(), node.get_id())
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
@@ -112,7 +107,7 @@ impl ClientState {
|
||||
Some(command)
|
||||
}
|
||||
}
|
||||
impl Default for ClientState {
|
||||
impl Default for ClientStateParsed {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
launch_info: None,
|
||||
@@ -122,10 +117,3 @@ impl Default for ClientState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct ClientStateInternal {
|
||||
data: Option<Vec<u8>>,
|
||||
root: Option<String>,
|
||||
spatial_anchors: FxHashMap<String, String>,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#[macro_export]
|
||||
macro_rules! create_interface {
|
||||
($iface:ident, $aspect:ident, $path:expr) => {
|
||||
($iface:ident) => {
|
||||
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
let node = Node::create_path(client, $path, false);
|
||||
<$iface as $aspect>::add_node_members(&node);
|
||||
let node = Node::from_id(client, INTERFACE_NODE_ID, false);
|
||||
<$iface as self::InterfaceAspect>::add_node_members(&node);
|
||||
node.add_to_scenegraph()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ pub mod delta;
|
||||
pub mod destroy_queue;
|
||||
pub mod eventloop;
|
||||
pub mod idl_utils;
|
||||
pub mod node_collections;
|
||||
pub mod registry;
|
||||
pub mod resource;
|
||||
pub mod scenegraph;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
use crate::nodes::Node;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
hash::Hash,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
// #[derive(Default)]
|
||||
// pub struct LifeLinkedNodeList {
|
||||
// nodes: Mutex<Vec<Weak<Node>>>,
|
||||
// }
|
||||
// impl LifeLinkedNodeList {
|
||||
// pub fn add(&self, node: Weak<Node>) {
|
||||
// self.nodes.lock().push(node);
|
||||
// }
|
||||
// pub fn clear(&self) {
|
||||
// self.nodes
|
||||
// .lock()
|
||||
// .iter()
|
||||
// .filter_map(|node| node.upgrade())
|
||||
// .for_each(|node| {
|
||||
// node.destroy();
|
||||
// });
|
||||
// self.nodes.lock().clear();
|
||||
// }
|
||||
// }
|
||||
// impl Drop for LifeLinkedNodeList {
|
||||
// fn drop(&mut self) {
|
||||
// self.clear();
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LifeLinkedNodeMap<K: Hash + Eq> {
|
||||
nodes: Mutex<FxHashMap<K, Weak<Node>>>,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl<K: Hash + Eq> LifeLinkedNodeMap<K> {
|
||||
pub fn add(&self, key: K, node: &Arc<Node>) {
|
||||
self.nodes.lock().insert(key, Arc::downgrade(node));
|
||||
}
|
||||
pub fn get<Q>(&self, key: &Q) -> Option<Arc<Node>>
|
||||
where
|
||||
Q: ?Sized,
|
||||
K: Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.nodes.lock().get(key).and_then(|n| n.upgrade())
|
||||
}
|
||||
pub fn nodes(&self) -> Vec<Arc<Node>> {
|
||||
self.nodes
|
||||
.lock()
|
||||
.values()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.collect()
|
||||
}
|
||||
pub fn remove<Q>(&self, key: &Q) -> Option<Arc<Node>>
|
||||
where
|
||||
Q: ?Sized,
|
||||
K: Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.nodes.lock().remove(key).and_then(|n| n.upgrade())
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
let mut nodes = self.nodes.lock();
|
||||
nodes
|
||||
.values()
|
||||
.filter_map(|node| node.upgrade())
|
||||
.for_each(|node| {
|
||||
node.destroy();
|
||||
});
|
||||
nodes.clear();
|
||||
}
|
||||
}
|
||||
impl<K: Hash + Eq> Drop for LifeLinkedNodeMap<K> {
|
||||
fn drop(&mut self) {
|
||||
self.clear();
|
||||
}
|
||||
}
|
||||
@@ -33,12 +33,38 @@ impl<T: Send + Sync + ?Sized> Registry<T> {
|
||||
self.lock()
|
||||
.contains_key(&(ptr::addr_of!(*t) as *const () as usize))
|
||||
}
|
||||
pub fn get_changes(old: &Registry<T>, new: &Registry<T>) -> (Vec<Arc<T>>, Vec<Arc<T>>) {
|
||||
let old = old.lock();
|
||||
let new = new.lock();
|
||||
|
||||
let mut added = Vec::new();
|
||||
let mut removed = Vec::new();
|
||||
|
||||
for (id, entry) in new.iter() {
|
||||
if let Some(entry) = entry.upgrade() {
|
||||
if !old.contains_key(id) {
|
||||
added.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (id, entry) in old.iter() {
|
||||
if let Some(entry) = entry.upgrade() {
|
||||
if !new.contains_key(id) {
|
||||
removed.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
(added, removed)
|
||||
}
|
||||
pub fn get_valid_contents(&self) -> Vec<Arc<T>> {
|
||||
self.lock()
|
||||
.iter()
|
||||
.filter_map(|pair| pair.1.upgrade())
|
||||
.collect()
|
||||
}
|
||||
pub fn set(&self, other: &Registry<T>) {
|
||||
*self.lock() = other.lock().clone();
|
||||
}
|
||||
pub fn take_valid_contents(&self) -> Vec<Arc<T>> {
|
||||
self.0
|
||||
.lock()
|
||||
@@ -48,6 +74,14 @@ impl<T: Send + Sync + ?Sized> Registry<T> {
|
||||
.filter_map(|pair| pair.1.upgrade())
|
||||
.collect()
|
||||
}
|
||||
pub fn retain<F: Fn(&T) -> bool>(&self, f: F) {
|
||||
self.lock().retain(|_, v| {
|
||||
let Some(v) = v.upgrade() else {
|
||||
return true;
|
||||
};
|
||||
(f)(&v)
|
||||
})
|
||||
}
|
||||
pub fn remove(&self, t: &T) {
|
||||
self.lock()
|
||||
.remove(&(ptr::addr_of!(*t) as *const () as usize));
|
||||
|
||||
@@ -19,7 +19,7 @@ use tracing::{debug, debug_span};
|
||||
#[derive(Default)]
|
||||
pub struct Scenegraph {
|
||||
pub(super) client: OnceCell<Weak<Client>>,
|
||||
nodes: Mutex<FxHashMap<String, Arc<Node>>>,
|
||||
nodes: Mutex<FxHashMap<u64, Arc<Node>>>,
|
||||
}
|
||||
|
||||
impl Scenegraph {
|
||||
@@ -34,12 +34,11 @@ impl Scenegraph {
|
||||
}
|
||||
pub fn add_node_raw(&self, node: Arc<Node>) {
|
||||
debug!(node = ?&*node, "Add node");
|
||||
let path = node.get_path().to_string();
|
||||
self.nodes.lock().insert(path, node);
|
||||
self.nodes.lock().insert(node.get_id(), node);
|
||||
}
|
||||
|
||||
pub fn get_node(&self, path: &str) -> Option<Arc<Node>> {
|
||||
let mut node = self.nodes.lock().get(path)?.clone();
|
||||
pub fn get_node(&self, node: u64) -> Option<Arc<Node>> {
|
||||
let mut node = self.nodes.lock().get(&node)?.clone();
|
||||
while let Ok(alias) = node.get_aspect::<Alias>() {
|
||||
if alias.enabled.load(Ordering::Acquire) {
|
||||
node = alias.original.upgrade()?;
|
||||
@@ -50,9 +49,9 @@ impl Scenegraph {
|
||||
Some(node)
|
||||
}
|
||||
|
||||
pub fn remove_node(&self, path: &str) -> Option<Arc<Node>> {
|
||||
debug!(path, "Remove node");
|
||||
self.nodes.lock().remove(path)
|
||||
pub fn remove_node(&self, node: u64) -> Option<Arc<Node>> {
|
||||
debug!(node, "Remove node");
|
||||
self.nodes.lock().remove(&node)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,16 +93,16 @@ fn map_method_return<T: Serialize>(
|
||||
impl scenegraph::Scenegraph for Scenegraph {
|
||||
fn send_signal(
|
||||
&self,
|
||||
path: &str,
|
||||
method: &str,
|
||||
node: u64,
|
||||
method: u64,
|
||||
data: &[u8],
|
||||
fds: Vec<OwnedFd>,
|
||||
) -> Result<(), ScenegraphError> {
|
||||
let Some(client) = self.get_client() else {
|
||||
return Err(ScenegraphError::SignalNotFound);
|
||||
};
|
||||
debug_span!("Handle signal", path, method).in_scope(|| {
|
||||
self.get_node(path)
|
||||
debug_span!("Handle signal", node, method).in_scope(|| {
|
||||
self.get_node(node)
|
||||
.ok_or(ScenegraphError::NodeNotFound)?
|
||||
.send_local_signal(
|
||||
client,
|
||||
@@ -117,8 +116,8 @@ impl scenegraph::Scenegraph for Scenegraph {
|
||||
}
|
||||
fn execute_method(
|
||||
&self,
|
||||
path: &str,
|
||||
method: &str,
|
||||
node: u64,
|
||||
method: u64,
|
||||
data: &[u8],
|
||||
fds: Vec<OwnedFd>,
|
||||
response: oneshot::Sender<Result<(Vec<u8>, Vec<OwnedFd>), ScenegraphError>>,
|
||||
@@ -127,8 +126,8 @@ impl scenegraph::Scenegraph for Scenegraph {
|
||||
let _ = response.send(Err(ScenegraphError::MethodNotFound));
|
||||
return;
|
||||
};
|
||||
debug!(path, method, "Handle method");
|
||||
let Some(node) = self.get_node(path) else {
|
||||
debug!(node, method, "Handle method");
|
||||
let Some(node) = self.get_node(node) else {
|
||||
let _ = response.send(Err(ScenegraphError::NodeNotFound));
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::wayland::X_DISPLAY;
|
||||
|
||||
use self::core::eventloop::EventLoop;
|
||||
use clap::Parser;
|
||||
use core::client_state::ClientState;
|
||||
use core::client_state::ClientStateParsed;
|
||||
use directories::ProjectDirs;
|
||||
use once_cell::sync::OnceCell;
|
||||
use stardust_xr::server;
|
||||
@@ -364,8 +364,8 @@ fn restore_session(
|
||||
};
|
||||
clients
|
||||
.filter_map(Result::ok)
|
||||
.filter_map(|c| ClientState::from_file(&c.path()))
|
||||
.filter_map(ClientState::launch_command)
|
||||
.filter_map(|c| ClientStateParsed::from_file(&c.path()))
|
||||
.filter_map(ClientStateParsed::launch_command)
|
||||
.filter_map(|startup_command| {
|
||||
run_client(
|
||||
startup_command,
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
use super::{Aspect, Node};
|
||||
use crate::core::client::Client;
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use crate::core::{client::Client, registry::Registry};
|
||||
use color_eyre::eyre::Result;
|
||||
use portable_atomic::AtomicBool;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::{
|
||||
ops::Add,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct AliasInfo {
|
||||
pub(super) server_signals: Vec<&'static str>,
|
||||
pub(super) server_methods: Vec<&'static str>,
|
||||
pub(super) client_signals: Vec<&'static str>,
|
||||
pub(super) server_signals: Vec<u64>,
|
||||
pub(super) server_methods: Vec<u64>,
|
||||
pub(super) client_signals: Vec<u64>,
|
||||
}
|
||||
impl Add for AliasInfo {
|
||||
type Output = AliasInfo;
|
||||
fn add(mut self, mut rhs: Self) -> Self::Output {
|
||||
self.server_signals.append(&mut rhs.server_signals);
|
||||
self.server_methods.append(&mut rhs.server_methods);
|
||||
self.client_signals.append(&mut rhs.client_signals);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Alias {
|
||||
pub enabled: Arc<AtomicBool>,
|
||||
pub(super) node: Weak<Node>,
|
||||
@@ -21,32 +32,86 @@ pub struct Alias {
|
||||
}
|
||||
impl Alias {
|
||||
pub fn create(
|
||||
client: &Arc<Client>,
|
||||
parent: &str,
|
||||
name: &str,
|
||||
original: &Arc<Node>,
|
||||
client: &Arc<Client>,
|
||||
info: AliasInfo,
|
||||
list: Option<&AliasList>,
|
||||
) -> Result<Arc<Node>> {
|
||||
ensure!(
|
||||
client
|
||||
.scenegraph
|
||||
.get_node(&(parent.to_string() + "/" + name))
|
||||
.is_none(),
|
||||
"Node already exists"
|
||||
);
|
||||
let node = Node::generate(client, true).add_to_scenegraph()?;
|
||||
Self::add_to(&node, original, info)?;
|
||||
if let Some(list) = list {
|
||||
list.add(&node);
|
||||
}
|
||||
Ok(node)
|
||||
}
|
||||
pub fn create_with_id(
|
||||
original: &Arc<Node>,
|
||||
client: &Arc<Client>,
|
||||
new_id: u64,
|
||||
info: AliasInfo,
|
||||
list: Option<&AliasList>,
|
||||
) -> Result<Arc<Node>> {
|
||||
let node = Node::from_id(client, new_id, true).add_to_scenegraph()?;
|
||||
Self::add_to(&node, original, info)?;
|
||||
if let Some(list) = list {
|
||||
list.add(&node);
|
||||
}
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
let node = Node::create_parent_name(client, parent, name, true).add_to_scenegraph()?;
|
||||
fn add_to(new_node: &Arc<Node>, original: &Arc<Node>, info: AliasInfo) -> Result<()> {
|
||||
let alias = Alias {
|
||||
enabled: Arc::new(AtomicBool::new(true)),
|
||||
node: Arc::downgrade(&node),
|
||||
node: Arc::downgrade(&new_node),
|
||||
original: Arc::downgrade(original),
|
||||
info,
|
||||
};
|
||||
let alias = original.aliases.add(alias);
|
||||
node.add_aspect_raw(alias);
|
||||
Ok(node)
|
||||
new_node.add_aspect_raw(alias);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Aspect for Alias {
|
||||
const NAME: &'static str = "Alias";
|
||||
}
|
||||
|
||||
pub fn get_original(node: Arc<Node>) -> Option<Arc<Node>> {
|
||||
let Ok(alias) = node.get_aspect::<Alias>() else {
|
||||
return Some(node);
|
||||
};
|
||||
get_original(alias.original.upgrade()?)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct AliasList(Registry<Node>);
|
||||
impl AliasList {
|
||||
fn add(&self, node: &Arc<Node>) {
|
||||
self.0.add_raw(node);
|
||||
}
|
||||
pub fn get<A: Aspect>(&self, aspect: &A) -> Option<Arc<Node>> {
|
||||
self.0.get_valid_contents().into_iter().find(|node| {
|
||||
let Ok(aspect2) = node.get_aspect::<A>() else {
|
||||
return false;
|
||||
};
|
||||
Arc::as_ptr(&aspect2) != (aspect as *const A)
|
||||
})
|
||||
}
|
||||
pub fn get_aliases(&self) -> Vec<Arc<Node>> {
|
||||
self.0.get_valid_contents()
|
||||
}
|
||||
pub fn remove_aspect<A: Aspect>(&self, aspect: &A) {
|
||||
self.0.retain(|node| {
|
||||
let Ok(aspect2) = node.get_aspect::<A>() else {
|
||||
return false;
|
||||
};
|
||||
Arc::as_ptr(&aspect2) != (aspect as *const A)
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Drop for AliasList {
|
||||
fn drop(&mut self) {
|
||||
for node in self.0.take_valid_contents() {
|
||||
node.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,20 +101,19 @@ pub fn update() {
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(AudioInterface, AudioInterfaceAspect, "/audio");
|
||||
create_interface!(AudioInterface);
|
||||
struct AudioInterface;
|
||||
impl AudioInterfaceAspect for AudioInterface {
|
||||
impl InterfaceAspect for AudioInterface {
|
||||
#[doc = "Create a sound node. WAV and MP3 are supported."]
|
||||
fn create_sound(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
resource: ResourceID,
|
||||
) -> Result<()> {
|
||||
let node =
|
||||
Node::create_parent_name(&calling_client, Self::CREATE_SOUND_PARENT_PATH, &name, true);
|
||||
let node = Node::from_id(&calling_client, id, true);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
let node = node.add_to_scenegraph()?;
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
use super::alias::AliasInfo;
|
||||
use super::alias::AliasList;
|
||||
use super::fields::Field;
|
||||
use super::spatial::{parse_transform, Spatial};
|
||||
use super::{Alias, Aspect, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::core::node_collections::LifeLinkedNodeMap;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::create_interface;
|
||||
use crate::nodes::fields::FIELD_ALIAS_INFO;
|
||||
use crate::nodes::spatial::Transform;
|
||||
use color_eyre::eyre::{bail, ensure, eyre, Result};
|
||||
use lazy_static::lazy_static;
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use slotmap::{DefaultKey, Key, KeyData, SlotMap};
|
||||
use stardust_xr::schemas::flex::flexbuffers;
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref KEYMAPS: Mutex<FxHashMap<String, String>> = Mutex::new(FxHashMap::default());
|
||||
pub static ref KEYMAPS: Mutex<SlotMap<DefaultKey, String>> = Mutex::new(SlotMap::default());
|
||||
}
|
||||
|
||||
static PULSE_SENDER_REGISTRY: Registry<PulseSender> = Registry::new();
|
||||
@@ -58,14 +56,16 @@ stardust_xr_server_codegen::codegen_data_protocol!();
|
||||
pub struct PulseSender {
|
||||
node: Weak<Node>,
|
||||
pub mask: Datamap,
|
||||
aliases: LifeLinkedNodeMap<String>,
|
||||
aliases: AliasList,
|
||||
field_aliases: AliasList,
|
||||
}
|
||||
impl PulseSender {
|
||||
pub fn add_to(node: &Arc<Node>, mask: Datamap) -> Result<Arc<PulseSender>> {
|
||||
let sender = PulseSender {
|
||||
node: Arc::downgrade(node),
|
||||
mask,
|
||||
aliases: LifeLinkedNodeMap::default(),
|
||||
aliases: AliasList::default(),
|
||||
field_aliases: AliasList::default(),
|
||||
};
|
||||
|
||||
// <PulseSender as PulseSenderAspect>::add_node_members(node);
|
||||
@@ -91,44 +91,41 @@ impl PulseSender {
|
||||
};
|
||||
// Receiver itself
|
||||
let Ok(rx_alias) = Alias::create(
|
||||
&tx_client,
|
||||
tx_node.get_path(),
|
||||
receiver.uid.as_str(),
|
||||
&rx_node,
|
||||
AliasInfo {
|
||||
server_methods: vec!["send_data"],
|
||||
..Default::default()
|
||||
},
|
||||
&tx_client,
|
||||
PULSE_RECEIVER_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&self.aliases),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.aliases.add(receiver.uid.clone(), &rx_alias);
|
||||
|
||||
// Receiver's field
|
||||
let Ok(rx_field_alias) = Alias::create(
|
||||
&rx_node
|
||||
.get_aspect::<PulseReceiver>()
|
||||
.unwrap()
|
||||
.field
|
||||
.spatial_ref()
|
||||
.node()
|
||||
.unwrap(),
|
||||
&tx_client,
|
||||
rx_alias.get_path(),
|
||||
"field",
|
||||
&rx_node.get_aspect::<PulseReceiver>().unwrap().field_node,
|
||||
FIELD_ALIAS_INFO.clone(),
|
||||
Some(&self.aliases),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.aliases
|
||||
.add(receiver.uid.clone() + "-field", &rx_field_alias);
|
||||
|
||||
let _ =
|
||||
pulse_sender_client::new_receiver(&tx_node, &receiver.uid, &rx_alias, &rx_field_alias);
|
||||
let _ = pulse_sender_client::new_receiver(&tx_node, &rx_alias, &rx_field_alias);
|
||||
}
|
||||
|
||||
fn handle_drop_receiver(&self, receiver: &PulseReceiver) {
|
||||
let uid = receiver.uid.as_str();
|
||||
self.aliases.remove(uid);
|
||||
self.aliases.remove(&(uid.to_string() + "-field"));
|
||||
let id = receiver.node.upgrade().unwrap().get_id();
|
||||
self.aliases.remove_aspect(receiver);
|
||||
self.field_aliases.remove_aspect(receiver.field.as_ref());
|
||||
let Some(tx_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let _ = pulse_sender_client::drop_receiver(&tx_node, uid);
|
||||
let _ = pulse_sender_client::drop_receiver(&tx_node, id);
|
||||
}
|
||||
}
|
||||
impl Aspect for PulseSender {
|
||||
@@ -142,21 +139,19 @@ impl Drop for PulseSender {
|
||||
}
|
||||
|
||||
pub struct PulseReceiver {
|
||||
uid: String,
|
||||
pub node: Weak<Node>,
|
||||
pub field_node: Arc<Node>,
|
||||
pub field: Arc<Field>,
|
||||
pub mask: Datamap,
|
||||
}
|
||||
impl PulseReceiver {
|
||||
pub fn add_to(
|
||||
node: &Arc<Node>,
|
||||
field_node: Arc<Node>,
|
||||
field: Arc<Field>,
|
||||
mask: Datamap,
|
||||
) -> Result<Arc<PulseReceiver>> {
|
||||
let receiver = PulseReceiver {
|
||||
uid: nanoid!(),
|
||||
node: Arc::downgrade(node),
|
||||
field_node,
|
||||
field,
|
||||
mask,
|
||||
};
|
||||
let receiver = PULSE_RECEIVER_REGISTRY.add(receiver);
|
||||
@@ -186,7 +181,7 @@ impl PulseReceiverAspect for PulseReceiver {
|
||||
"Message ({data:?}) does not contain the same keys as the receiver's mask ({:?})",
|
||||
this_receiver.mask
|
||||
);
|
||||
pulse_receiver_client::data(&node, &sender.uid, &data)?;
|
||||
pulse_receiver_client::data(&node, &sender, &data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -199,24 +194,19 @@ impl Drop for PulseReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(DataInterface, DataInterfaceAspect, "/data");
|
||||
create_interface!(DataInterface);
|
||||
struct DataInterface;
|
||||
impl DataInterfaceAspect for DataInterface {
|
||||
impl InterfaceAspect for DataInterface {
|
||||
fn create_pulse_sender(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
mask: Datamap,
|
||||
) -> Result<()> {
|
||||
get_mask(&mask)?;
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
Self::CREATE_PULSE_SENDER_PARENT_PATH,
|
||||
&name,
|
||||
true,
|
||||
);
|
||||
let node = Node::from_id(&calling_client, id, true);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, false);
|
||||
|
||||
@@ -229,22 +219,17 @@ impl DataInterfaceAspect for DataInterface {
|
||||
fn create_pulse_receiver(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
field: Arc<Node>,
|
||||
mask: Datamap,
|
||||
) -> Result<()> {
|
||||
get_mask(&mask)?;
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
Self::CREATE_PULSE_RECEIVER_PARENT_PATH,
|
||||
&name,
|
||||
true,
|
||||
);
|
||||
let node = Node::from_id(&calling_client, id, true);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = parse_transform(transform, true, true, false);
|
||||
let _ = field.get_aspect::<Field>()?;
|
||||
let field = field.get_aspect::<Field>()?;
|
||||
|
||||
let node = node.add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
@@ -256,7 +241,7 @@ impl DataInterfaceAspect for DataInterface {
|
||||
_node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
keymap: String,
|
||||
) -> Result<String> {
|
||||
) -> Result<u64> {
|
||||
let mut keymaps = KEYMAPS.lock();
|
||||
if let Some(found_keymap_id) = keymaps
|
||||
.iter()
|
||||
@@ -264,22 +249,20 @@ impl DataInterfaceAspect for DataInterface {
|
||||
.map(|(k, _v)| k)
|
||||
.last()
|
||||
{
|
||||
return Ok(found_keymap_id.clone());
|
||||
return Ok(found_keymap_id.data().as_ffi());
|
||||
}
|
||||
|
||||
let generated_id = nanoid!();
|
||||
keymaps.insert(generated_id.clone(), keymap);
|
||||
|
||||
Ok(generated_id)
|
||||
let key = keymaps.insert(keymap);
|
||||
Ok(key.data().as_ffi())
|
||||
}
|
||||
|
||||
async fn get_keymap(
|
||||
_node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
keymap_id: String,
|
||||
keymap_id: u64,
|
||||
) -> Result<String> {
|
||||
let keymaps = KEYMAPS.lock();
|
||||
let Some(keymap) = keymaps.get(&keymap_id) else {
|
||||
let Some(keymap) = keymaps.get(KeyData::from_ffi(keymap_id).into()) else {
|
||||
bail!("Could not find keymap. Try registering it")
|
||||
};
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@ static QUEUED_SKYLIGHT: Mutex<Option<PathBuf>> = Mutex::new(None);
|
||||
static QUEUED_SKYTEX: Mutex<Option<PathBuf>> = Mutex::new(None);
|
||||
|
||||
stardust_xr_server_codegen::codegen_drawable_protocol!();
|
||||
create_interface!(DrawableInterface, DrawableInterfaceAspect, "/drawable");
|
||||
create_interface!(DrawableInterface);
|
||||
|
||||
pub struct DrawableInterface;
|
||||
impl DrawableInterfaceAspect for DrawableInterface {
|
||||
impl InterfaceAspect for DrawableInterface {
|
||||
fn set_sky_tex(_node: Arc<Node>, calling_client: Arc<Client>, tex: ResourceID) -> Result<()> {
|
||||
let resource_path = get_resource_file(&tex, &calling_client, &[OsStr::new("hdr")])
|
||||
.ok_or(eyre::eyre!("Could not find resource"))?;
|
||||
@@ -65,13 +65,12 @@ impl DrawableInterfaceAspect for DrawableInterface {
|
||||
fn create_lines(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
lines: Vec<Line>,
|
||||
) -> Result<()> {
|
||||
let node =
|
||||
Node::create_parent_name(&calling_client, Self::CREATE_LINES_PARENT_PATH, &name, true);
|
||||
let node = Node::from_id(&calling_client, id, true);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
|
||||
@@ -84,13 +83,12 @@ impl DrawableInterfaceAspect for DrawableInterface {
|
||||
fn load_model(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
model: ResourceID,
|
||||
) -> Result<()> {
|
||||
let node =
|
||||
Node::create_parent_name(&calling_client, Self::LOAD_MODEL_PARENT_PATH, &name, true);
|
||||
let node = Node::from_id(&calling_client, id, true);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
let node = node.add_to_scenegraph()?;
|
||||
@@ -102,14 +100,13 @@ impl DrawableInterfaceAspect for DrawableInterface {
|
||||
fn create_text(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
text: String,
|
||||
style: TextStyle,
|
||||
) -> Result<()> {
|
||||
let node =
|
||||
Node::create_parent_name(&calling_client, Self::CREATE_TEXT_PARENT_PATH, &name, true);
|
||||
let node = Node::from_id(&calling_client, id, true);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use super::{MaterialParameter, ModelAspect, ModelPartAspect, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::core::node_collections::LifeLinkedNodeMap;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::core::resource::get_resource_file;
|
||||
use crate::nodes::alias::{Alias, AliasList};
|
||||
use crate::nodes::spatial::Spatial;
|
||||
use crate::nodes::Aspect;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use crate::nodes::{Aspect, Node};
|
||||
use color_eyre::eyre::{bail, eyre, Result};
|
||||
use glam::{Mat4, Vec2, Vec3};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
@@ -19,9 +18,10 @@ use stereokit_rust::sk::MainThreadToken;
|
||||
use stereokit_rust::{material::Material, model::Model as SKModel, tex::Tex, util::Color128};
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use super::{MaterialParameter, ModelAspect, ModelPartAspect, MODEL_PART_ASPECT_ALIAS_INFO};
|
||||
|
||||
static MODEL_REGISTRY: Registry<Model> = Registry::new();
|
||||
static HOLDOUT_MATERIAL: OnceCell<Arc<SendWrapper<Material>>> = OnceCell::new();
|
||||
|
||||
@@ -69,11 +69,12 @@ impl MaterialParameter {
|
||||
|
||||
pub struct ModelPart {
|
||||
id: i32,
|
||||
path: PathBuf,
|
||||
path: String,
|
||||
space: Arc<Spatial>,
|
||||
model: Weak<Model>,
|
||||
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
|
||||
pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>,
|
||||
aliases: AliasList,
|
||||
}
|
||||
impl ModelPart {
|
||||
fn create_for_model(model: &Arc<Model>, sk_model: &SKModel) {
|
||||
@@ -91,26 +92,21 @@ impl ModelPart {
|
||||
}
|
||||
|
||||
fn create(model: &Arc<Model>, part: &stereokit_rust::model::ModelNode) -> Option<Arc<Self>> {
|
||||
let parent_node = part
|
||||
let mut parts = model.parts.lock();
|
||||
let parent_part = part
|
||||
.get_parent()
|
||||
.and_then(|part| model.parts.get(part.get_id()));
|
||||
let parent_part = parent_node
|
||||
.as_ref()
|
||||
.and_then(|node| node.get_aspect::<ModelPart>().ok());
|
||||
.and_then(|part| parts.iter().find(|p| p.id == *part.get_id()));
|
||||
|
||||
let stardust_model_part = model.space.node()?;
|
||||
let client = stardust_model_part.get_client()?;
|
||||
let mut part_path = parent_part.map(|n| n.path.clone()).unwrap_or_default();
|
||||
part_path.push(part.get_name().unwrap());
|
||||
let mut part_path = parent_part
|
||||
.map(|n| n.path.clone() + "/")
|
||||
.unwrap_or_default();
|
||||
part_path += part.get_name().unwrap();
|
||||
|
||||
let node = client.scenegraph.add_node(Node::create_parent_name(
|
||||
&client,
|
||||
stardust_model_part.get_path(),
|
||||
part_path.to_str()?,
|
||||
false,
|
||||
));
|
||||
let spatial_parent = parent_node
|
||||
.and_then(|n| n.get_aspect::<Spatial>().ok())
|
||||
let node = client.scenegraph.add_node(Node::generate(&client, false));
|
||||
let spatial_parent = parent_part
|
||||
.map(|n| n.space.clone())
|
||||
.unwrap_or_else(|| model.space.clone());
|
||||
|
||||
let local_transform = unsafe { part.get_local_transform().m };
|
||||
@@ -121,29 +117,25 @@ impl ModelPart {
|
||||
false,
|
||||
);
|
||||
|
||||
let _ = node
|
||||
.get_aspect::<Spatial>()
|
||||
.unwrap()
|
||||
.bounding_box_calc
|
||||
.set(|node| {
|
||||
let Ok(model_part) = node.get_aspect::<ModelPart>() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let Some(model) = model_part.model.upgrade() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let Some(sk_model) = model.sk_model.get() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let nodes = sk_model.get_nodes();
|
||||
let Some(model_node) = nodes.get_index(model_part.id) else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let Some(sk_mesh) = model_node.get_mesh() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
sk_mesh.get_bounds()
|
||||
});
|
||||
let _ = space.bounding_box_calc.set(|node| {
|
||||
let Ok(model_part) = node.get_aspect::<ModelPart>() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let Some(model) = model_part.model.upgrade() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let Some(sk_model) = model.sk_model.get() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let model_nodes = sk_model.get_nodes();
|
||||
let Some(model_node) = model_nodes.get_index(model_part.id) else {
|
||||
return Bounds::default();
|
||||
};
|
||||
let Some(sk_mesh) = model_node.get_mesh() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
sk_mesh.get_bounds()
|
||||
});
|
||||
|
||||
let model_part = Arc::new(ModelPart {
|
||||
id: *part.get_id(),
|
||||
@@ -152,10 +144,11 @@ impl ModelPart {
|
||||
model: Arc::downgrade(model),
|
||||
pending_material_parameters: Mutex::new(FxHashMap::default()),
|
||||
pending_material_replacement: Mutex::new(None),
|
||||
aliases: AliasList::default(),
|
||||
});
|
||||
<ModelPart as ModelPartAspect>::add_node_members(&node);
|
||||
node.add_aspect_raw(model_part.clone());
|
||||
model.parts.add(*part.get_id(), &node);
|
||||
parts.push(model_part.clone());
|
||||
Some(model_part)
|
||||
}
|
||||
|
||||
@@ -255,9 +248,8 @@ pub struct Model {
|
||||
space: Arc<Spatial>,
|
||||
_resource_id: ResourceID,
|
||||
sk_model: OnceCell<SKModel>,
|
||||
parts: LifeLinkedNodeMap<i32>,
|
||||
parts: Mutex<Vec<Arc<ModelPart>>>,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
pub fn add_to(node: &Arc<Node>, resource_id: ResourceID) -> Result<Arc<Model>> {
|
||||
let pending_model_path = get_resource_file(
|
||||
@@ -272,8 +264,9 @@ impl Model {
|
||||
space: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
_resource_id: resource_id,
|
||||
sk_model: OnceCell::new(),
|
||||
parts: LifeLinkedNodeMap::default(),
|
||||
parts: Mutex::new(Vec::default()),
|
||||
});
|
||||
<Model as ModelAspect>::add_node_members(node);
|
||||
MODEL_REGISTRY.add_raw(&model);
|
||||
|
||||
// technically doing this in anything but the main thread isn't a good idea but dangit we need those model nodes ASAP
|
||||
@@ -291,11 +284,11 @@ impl Model {
|
||||
let Some(sk_model) = self.sk_model.get() else {
|
||||
return;
|
||||
};
|
||||
for model_node_node in self.parts.nodes() {
|
||||
if let Ok(model_node) = model_node_node.get_aspect::<ModelPart>() {
|
||||
model_node.update();
|
||||
};
|
||||
let parts = self.parts.lock();
|
||||
for model_node in &*parts {
|
||||
model_node.update();
|
||||
}
|
||||
drop(parts);
|
||||
|
||||
if self.enabled.load(Ordering::Relaxed) {
|
||||
sk_model.draw(token, self.space.global_transform(), None, None);
|
||||
@@ -308,12 +301,32 @@ unsafe impl Sync for Model {}
|
||||
impl Aspect for Model {
|
||||
const NAME: &'static str = "Model";
|
||||
}
|
||||
impl ModelAspect for Model {}
|
||||
impl ModelAspect for Model {
|
||||
#[doc = "Bind a model part to the node with the ID input."]
|
||||
fn bind_model_part(
|
||||
node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
id: u64,
|
||||
part_path: String,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
let model = node.get_aspect::<Model>()?;
|
||||
let parts = model.parts.lock();
|
||||
let Some(part) = parts.iter().find(|p| p.path == part_path) else {
|
||||
let paths = parts.iter().map(|p| &p.path).collect::<Vec<_>>();
|
||||
bail!("Couldn't find model part at path {part_path}, all available paths: {paths:?}",)
|
||||
};
|
||||
Alias::create_with_id(
|
||||
&part.space.node().unwrap(),
|
||||
&calling_client,
|
||||
id,
|
||||
MODEL_PART_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&part.aliases),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for Model {
|
||||
fn drop(&mut self) {
|
||||
// if let Some(sk_model) = self.sk_model.take() {
|
||||
// destroy_queue::add(sk_model);
|
||||
// }
|
||||
MODEL_REGISTRY.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ use self::sphere::SphereField;
|
||||
use self::torus::TorusField;
|
||||
|
||||
use super::alias::AliasInfo;
|
||||
use super::spatial::Spatial;
|
||||
use super::spatial::{
|
||||
Spatial, SPATIAL_REF_GET_LOCAL_BOUNDING_BOX_SERVER_OPCODE,
|
||||
SPATIAL_REF_GET_RELATIVE_BOUNDING_BOX_SERVER_OPCODE, SPATIAL_REF_GET_TRANSFORM_SERVER_OPCODE,
|
||||
};
|
||||
use super::{Aspect, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::create_interface;
|
||||
@@ -24,7 +27,15 @@ use std::sync::Arc;
|
||||
// TODO: get SDFs working properly with non-uniform scale and so on, output distance relative to the spatial it's compared against
|
||||
|
||||
pub static FIELD_ALIAS_INFO: Lazy<AliasInfo> = Lazy::new(|| AliasInfo {
|
||||
server_methods: vec!["distance", "normal", "closest_point", "ray_march"],
|
||||
server_methods: vec![
|
||||
SPATIAL_REF_GET_TRANSFORM_SERVER_OPCODE,
|
||||
SPATIAL_REF_GET_LOCAL_BOUNDING_BOX_SERVER_OPCODE,
|
||||
SPATIAL_REF_GET_RELATIVE_BOUNDING_BOX_SERVER_OPCODE,
|
||||
FIELD_DISTANCE_SERVER_OPCODE,
|
||||
FIELD_NORMAL_SERVER_OPCODE,
|
||||
FIELD_CLOSEST_POINT_SERVER_OPCODE,
|
||||
FIELD_RAY_MARCH_SERVER_OPCODE,
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
@@ -200,26 +211,20 @@ impl Deref for Field {
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(FieldInterface, FieldInterfaceAspect, "/field");
|
||||
create_interface!(FieldInterface);
|
||||
pub struct FieldInterface;
|
||||
impl FieldInterfaceAspect for FieldInterface {
|
||||
impl InterfaceAspect for FieldInterface {
|
||||
fn create_box_field(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
size: mint::Vector3<f32>,
|
||||
) -> Result<()> {
|
||||
let transform = transform.to_mat4(true, true, false);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
Self::CREATE_BOX_FIELD_PARENT_PATH,
|
||||
&name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
BoxField::add_to(&node, size);
|
||||
Ok(())
|
||||
@@ -228,7 +233,7 @@ impl FieldInterfaceAspect for FieldInterface {
|
||||
fn create_cylinder_field(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
length: f32,
|
||||
@@ -236,13 +241,7 @@ impl FieldInterfaceAspect for FieldInterface {
|
||||
) -> Result<()> {
|
||||
let transform = transform.to_mat4(true, true, false);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
Self::CREATE_CYLINDER_FIELD_PARENT_PATH,
|
||||
&name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
CylinderField::add_to(&node, length, radius);
|
||||
Ok(())
|
||||
@@ -251,19 +250,13 @@ impl FieldInterfaceAspect for FieldInterface {
|
||||
fn create_sphere_field(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
position: mint::Vector3<f32>,
|
||||
radius: f32,
|
||||
) -> Result<()> {
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
Self::CREATE_SPHERE_FIELD_PARENT_PATH,
|
||||
&name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(
|
||||
&node,
|
||||
Some(parent.clone()),
|
||||
@@ -277,7 +270,7 @@ impl FieldInterfaceAspect for FieldInterface {
|
||||
fn create_torus_field(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
radius_a: f32,
|
||||
@@ -285,13 +278,7 @@ impl FieldInterfaceAspect for FieldInterface {
|
||||
) -> Result<()> {
|
||||
let transform = transform.to_mat4(true, true, false);
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
Self::CREATE_TORUS_FIELD_PARENT_PATH,
|
||||
&name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
TorusField::add_to(&node, radius_a, radius_b);
|
||||
Ok(())
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use super::{alias::Alias, spatial::Spatial, Node};
|
||||
use crate::{
|
||||
core::client::{Client, INTERNAL_CLIENT},
|
||||
nodes::alias::AliasInfo,
|
||||
use super::{
|
||||
alias::Alias,
|
||||
spatial::{Spatial, SPATIAL_ASPECT_ALIAS_INFO},
|
||||
Node,
|
||||
};
|
||||
use crate::core::client::{Client, INTERNAL_CLIENT};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{vec3, Mat4};
|
||||
use std::sync::Arc;
|
||||
@@ -13,31 +14,21 @@ lazy_static::lazy_static! {
|
||||
}
|
||||
|
||||
fn create() -> Arc<Node> {
|
||||
let node = Arc::new(Node::create_parent_name(&INTERNAL_CLIENT, "", "hmd", false));
|
||||
let node = Arc::new(Node::generate(&INTERNAL_CLIENT, false));
|
||||
Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
pub fn frame() {
|
||||
let spatial = HMD.get_aspect::<Spatial>().unwrap();
|
||||
let hmd_pose = Input::get_head();
|
||||
*spatial.transform.lock() = Mat4::from_scale_rotation_translation(
|
||||
spatial.set_local_transform(Mat4::from_scale_rotation_translation(
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
hmd_pose.orientation.into(),
|
||||
hmd_pose.position.into(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
pub fn make_alias(client: &Arc<Client>) -> Result<Arc<Node>> {
|
||||
Alias::create(
|
||||
client,
|
||||
"",
|
||||
"hmd",
|
||||
&HMD,
|
||||
AliasInfo {
|
||||
server_signals: vec!["get_bounds", "get_transform"],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
Alias::create(&HMD, client, SPATIAL_ASPECT_ALIAS_INFO.clone(), None)
|
||||
}
|
||||
|
||||
@@ -2,30 +2,23 @@ use super::{
|
||||
input_handler_client, InputHandlerAspect, InputLink, INPUT_HANDLER_REGISTRY,
|
||||
INPUT_METHOD_REGISTRY,
|
||||
};
|
||||
use crate::{
|
||||
core::node_collections::LifeLinkedNodeMap,
|
||||
nodes::{fields::Field, spatial::Spatial, Aspect, Node},
|
||||
};
|
||||
use crate::nodes::{alias::AliasList, fields::Field, spatial::Spatial, Aspect, Node};
|
||||
use color_eyre::eyre::Result;
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
|
||||
pub struct InputHandler {
|
||||
pub uid: String,
|
||||
pub node: Weak<Node>,
|
||||
pub spatial: Arc<Spatial>,
|
||||
pub field: Arc<Field>,
|
||||
pub(super) method_aliases: LifeLinkedNodeMap<usize>,
|
||||
pub(super) method_aliases: AliasList,
|
||||
}
|
||||
impl InputHandler {
|
||||
pub fn add_to(node: &Arc<Node>, field: &Arc<Field>) -> Result<()> {
|
||||
let handler = InputHandler {
|
||||
uid: node.uid.clone(),
|
||||
node: Arc::downgrade(node),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
field: field.clone(),
|
||||
method_aliases: LifeLinkedNodeMap::default(),
|
||||
method_aliases: AliasList::default(),
|
||||
};
|
||||
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
|
||||
method.make_alias(&handler);
|
||||
@@ -44,20 +37,16 @@ impl InputHandler {
|
||||
input_link: &InputLink,
|
||||
datamap: Datamap,
|
||||
) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
let Some(node) = self.spatial.node() else {
|
||||
return;
|
||||
};
|
||||
let Some(method_alias) = input_link
|
||||
.handler
|
||||
.method_aliases
|
||||
.get(&(Arc::as_ptr(&input_link.method) as usize))
|
||||
else {
|
||||
let Some(method_alias) = self.method_aliases.get(input_link.method.as_ref()) else {
|
||||
return;
|
||||
};
|
||||
let _ = input_handler_client::input(
|
||||
&node,
|
||||
&method_alias,
|
||||
&input_link.serialize(order, captured, datamap),
|
||||
&input_link.serialize(method_alias.id, order, captured, datamap),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use super::{
|
||||
input_method_client, InputDataTrait, InputDataType, InputHandler, InputMethodAspect,
|
||||
InputMethodRefAspect, INPUT_HANDLER_REGISTRY, INPUT_METHOD_REGISTRY,
|
||||
InputMethodRefAspect, INPUT_HANDLER_REGISTRY, INPUT_METHOD_ASPECT_ALIAS_INFO,
|
||||
INPUT_METHOD_REF_ASPECT_ALIAS_INFO, INPUT_METHOD_REGISTRY,
|
||||
};
|
||||
use crate::{
|
||||
core::{client::Client, node_collections::LifeLinkedNodeMap, registry::Registry},
|
||||
core::{client::Client, registry::Registry},
|
||||
nodes::{
|
||||
alias::{Alias, AliasInfo},
|
||||
alias::{Alias, AliasList},
|
||||
fields::{Field, FIELD_ALIAS_INFO},
|
||||
spatial::Spatial,
|
||||
Aspect, Node,
|
||||
@@ -19,7 +20,6 @@ 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>,
|
||||
@@ -27,7 +27,8 @@ pub struct InputMethod {
|
||||
|
||||
pub capture_requests: Registry<InputHandler>,
|
||||
pub captures: Registry<InputHandler>,
|
||||
pub(super) handler_aliases: LifeLinkedNodeMap<String>,
|
||||
handler_aliases: AliasList,
|
||||
handler_field_aliases: AliasList,
|
||||
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
|
||||
}
|
||||
impl InputMethod {
|
||||
@@ -38,14 +39,15 @@ impl InputMethod {
|
||||
) -> 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),
|
||||
datamap: Mutex::new(datamap),
|
||||
|
||||
capture_requests: Registry::new(),
|
||||
captures: Registry::new(),
|
||||
datamap: Mutex::new(datamap),
|
||||
handler_aliases: LifeLinkedNodeMap::default(),
|
||||
handler_aliases: AliasList::default(),
|
||||
handler_field_aliases: AliasList::default(),
|
||||
handler_order: Mutex::new(Vec::new()),
|
||||
};
|
||||
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
||||
@@ -63,28 +65,21 @@ impl InputMethod {
|
||||
let Some(method_node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(handler_node) = handler.node.upgrade() else {
|
||||
let Some(handler_node) = handler.spatial.node() 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()
|
||||
},
|
||||
&client,
|
||||
INPUT_METHOD_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&handler.method_aliases),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
method_alias.enabled.store(false, Ordering::Relaxed);
|
||||
handler
|
||||
.method_aliases
|
||||
.add(self as *const InputMethod as usize, &method_alias);
|
||||
}
|
||||
|
||||
pub fn distance(&self, to: &Field) -> f32 {
|
||||
@@ -102,57 +97,45 @@ impl InputMethod {
|
||||
let Some(method_client) = method_node.get_client() else {
|
||||
return;
|
||||
};
|
||||
let Some(handler_node) = handler.node.upgrade() else {
|
||||
let Some(handler_node) = handler.spatial.node() 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()
|
||||
},
|
||||
&method_client,
|
||||
INPUT_METHOD_REF_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&self.handler_aliases),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.handler_aliases
|
||||
.add(handler.uid.clone(), &handler_alias);
|
||||
|
||||
let Some(handler_field_node) = handler.field.spatial_ref().node.upgrade() else {
|
||||
let Some(handler_field_node) = handler.field.spatial_ref().node() else {
|
||||
return;
|
||||
};
|
||||
// Handler's field
|
||||
let Ok(rx_field_alias) = Alias::create(
|
||||
&method_client,
|
||||
handler_alias.get_path(),
|
||||
"field",
|
||||
&handler_field_node,
|
||||
&method_client,
|
||||
FIELD_ALIAS_INFO.clone(),
|
||||
Some(&self.handler_field_aliases),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.handler_aliases
|
||||
.add(handler.uid.clone() + "-field", &rx_field_alias);
|
||||
|
||||
let _ = input_method_client::create_handler(
|
||||
&method_node,
|
||||
&handler.uid,
|
||||
&handler_node,
|
||||
&rx_field_alias,
|
||||
);
|
||||
let _ = input_method_client::create_handler(&method_node, &handler_alias, &rx_field_alias);
|
||||
}
|
||||
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::destroy_handler(&tx_node, &uid);
|
||||
let Some(handler_alias) = self.handler_aliases.get(handler) else {
|
||||
return;
|
||||
};
|
||||
let _ = input_method_client::destroy_handler(&tx_node, handler_alias.id);
|
||||
self.handler_aliases.remove_aspect(handler);
|
||||
self.handler_field_aliases
|
||||
.remove_aspect(handler.field.as_ref());
|
||||
}
|
||||
}
|
||||
impl Aspect for InputMethod {
|
||||
|
||||
@@ -38,7 +38,7 @@ impl InputLink {
|
||||
self.handler.send_input(order, captured, self, datamap);
|
||||
}
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn serialize(&self, order: u32, captured: bool, datamap: Datamap) -> InputData {
|
||||
fn serialize(&self, id: u64, order: u32, captured: bool, datamap: Datamap) -> InputData {
|
||||
let mut input = self.method.data.lock().clone();
|
||||
input.update_to(
|
||||
self,
|
||||
@@ -46,7 +46,7 @@ impl InputLink {
|
||||
);
|
||||
|
||||
InputData {
|
||||
uid: self.method.uid.clone(),
|
||||
id,
|
||||
input,
|
||||
distance: self.method.distance(&self.handler.field),
|
||||
datamap,
|
||||
@@ -77,14 +77,14 @@ impl InputDataTrait for InputDataType {
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(InputInterface, InputInterfaceAspect, "/input");
|
||||
create_interface!(InputInterface);
|
||||
pub struct InputInterface;
|
||||
impl InputInterfaceAspect for InputInterface {
|
||||
impl InterfaceAspect for InputInterface {
|
||||
#[doc = "Create an input method node"]
|
||||
fn create_input_method(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
initial_data: InputDataType,
|
||||
@@ -93,8 +93,7 @@ impl InputInterfaceAspect for InputInterface {
|
||||
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()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputMethod::add_to(&node, initial_data, datamap)?;
|
||||
Ok(())
|
||||
@@ -104,7 +103,7 @@ impl InputInterfaceAspect for InputInterface {
|
||||
fn create_input_handler(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
field: Arc<Node>,
|
||||
@@ -113,8 +112,7 @@ impl InputInterfaceAspect for InputInterface {
|
||||
let transform = transform.to_mat4(true, true, true);
|
||||
let field = field.get_aspect::<Field>()?;
|
||||
|
||||
let node = Node::create_parent_name(&calling_client, "/input/handler", &name, true)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
InputHandler::add_to(&node, &field)?;
|
||||
Ok(())
|
||||
@@ -145,7 +143,7 @@ pub fn process_input() {
|
||||
.iter()
|
||||
.filter_map(Weak::upgrade)
|
||||
.filter(|handler| {
|
||||
let Some(node) = handler.node.upgrade() else {
|
||||
let Some(node) = handler.spatial.node() else {
|
||||
return false;
|
||||
};
|
||||
node.enabled()
|
||||
@@ -159,7 +157,7 @@ pub fn process_input() {
|
||||
if let Some(method_alias) = input_link
|
||||
.handler
|
||||
.method_aliases
|
||||
.get(&(Arc::as_ptr(&input_link.method) as usize))
|
||||
.get(input_link.method.as_ref())
|
||||
.and_then(|a| a.get_aspect::<Alias>().ok())
|
||||
{
|
||||
method_alias.enabled.store(true, Ordering::Release);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use super::{create_item_acceptor_flex, register_item_ui_flex, Item, ItemInterface, ItemType};
|
||||
use super::{
|
||||
create_item_acceptor_flex, register_item_ui_flex, Item, ItemAcceptor, ItemInterface, ItemType,
|
||||
};
|
||||
use crate::{
|
||||
core::{
|
||||
client::{Client, INTERNAL_CLIENT},
|
||||
registry::Registry,
|
||||
scenegraph::MethodResponseSender,
|
||||
},
|
||||
core::{client::Client, registry::Registry, scenegraph::MethodResponseSender},
|
||||
create_interface,
|
||||
nodes::{
|
||||
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES},
|
||||
@@ -17,7 +15,6 @@ use color_eyre::eyre::{bail, eyre, Result};
|
||||
use glam::Mat4;
|
||||
use lazy_static::lazy_static;
|
||||
use mint::{ColumnMatrix4, Vector2};
|
||||
use nanoid::nanoid;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use send_wrapper::SendWrapper;
|
||||
@@ -37,14 +34,13 @@ stardust_xr_server_codegen::codegen_item_camera_protocol!();
|
||||
lazy_static! {
|
||||
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
|
||||
type_name: "camera",
|
||||
aliased_local_signals: vec!["apply_preview_material", "frame"],
|
||||
aliased_local_methods: vec![],
|
||||
aliased_remote_signals: vec![],
|
||||
alias_info: CAMERA_ITEM_ASPECT_ALIAS_INFO.clone(),
|
||||
ui_node_id: INTERFACE_NODE_ID,
|
||||
ui: Default::default(),
|
||||
items: Registry::new(),
|
||||
acceptors: Registry::new(),
|
||||
new_acceptor_fn: |node, uid, acceptor, acceptor_field| {
|
||||
let _ = camera_item_ui_client::create_acceptor(node, uid, acceptor, acceptor_field);
|
||||
new_acceptor_fn: |node, acceptor, acceptor_field| {
|
||||
let _ = camera_item_ui_client::create_acceptor(node, acceptor, acceptor_field);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -62,11 +58,11 @@ pub struct CameraItem {
|
||||
applied_to: Registry<ModelPart>,
|
||||
apply_to: Registry<ModelPart>,
|
||||
}
|
||||
#[allow(unused)]
|
||||
impl CameraItem {
|
||||
pub fn add_to(node: &Arc<Node>, proj_matrix: Mat4, px_size: Vector2<u32>) {
|
||||
Item::add_to(
|
||||
node,
|
||||
nanoid!(),
|
||||
&ITEM_TYPE_INFO_CAMERA,
|
||||
ItemType::Camera(CameraItem {
|
||||
space: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
@@ -80,11 +76,7 @@ impl CameraItem {
|
||||
apply_to: Registry::new(),
|
||||
}),
|
||||
);
|
||||
node.add_local_method("frame", CameraItem::frame_flex);
|
||||
node.add_local_signal(
|
||||
"apply_preview_material",
|
||||
CameraItem::apply_preview_material_flex,
|
||||
);
|
||||
// <CameraItem as CameraItemAspect>::node_methods(node);
|
||||
}
|
||||
|
||||
fn frame_flex(
|
||||
@@ -118,11 +110,11 @@ impl CameraItem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
|
||||
let _ = camera_item_ui_client::create_item(node, uid, item);
|
||||
pub fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
let _ = camera_item_ui_client::create_item(node, item);
|
||||
}
|
||||
pub fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
|
||||
let _ = camera_item_acceptor_client::capture_item(node, uid, item);
|
||||
pub fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
let _ = camera_item_acceptor_client::capture_item(node, item);
|
||||
}
|
||||
|
||||
pub fn update(&self, token: &MainThreadToken) {
|
||||
@@ -166,6 +158,13 @@ impl CameraItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl CameraItemAspect for CameraItem {}
|
||||
|
||||
impl CameraItemAcceptorAspect for ItemAcceptor {
|
||||
fn capture_item(node: Arc<Node>, _calling_client: Arc<Client>, item: Arc<Node>) -> Result<()> {
|
||||
super::acceptor_capture_item_flex(node, item)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(token: &MainThreadToken) {
|
||||
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
|
||||
@@ -176,31 +175,24 @@ pub fn update(token: &MainThreadToken) {
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(ItemInterface, ItemCameraInterfaceAspect, "/item/camera");
|
||||
impl ItemCameraInterfaceAspect for ItemInterface {
|
||||
create_interface!(ItemInterface);
|
||||
impl InterfaceAspect for ItemInterface {
|
||||
#[doc = "Create a camera item at a specific location"]
|
||||
fn create_camera_item(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
proj_matrix: ColumnMatrix4<f32>,
|
||||
px_size: Vector2<u32>,
|
||||
) -> Result<()> {
|
||||
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name);
|
||||
let space = parent.get_aspect::<Spatial>()?;
|
||||
let transform = transform.to_mat4(true, true, false);
|
||||
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, &parent_name, &name, false)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, false).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, None, transform * space.global_transform(), false);
|
||||
CameraItem::add_to(&node, proj_matrix.into(), px_size);
|
||||
node.get_aspect::<Item>().unwrap().make_alias_named(
|
||||
&calling_client,
|
||||
&parent_name,
|
||||
&name,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -213,14 +205,14 @@ impl ItemCameraInterfaceAspect for ItemInterface {
|
||||
fn create_camera_item_acceptor(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
field: Arc<Node>,
|
||||
) -> Result<()> {
|
||||
create_item_acceptor_flex(
|
||||
calling_client,
|
||||
name,
|
||||
id,
|
||||
parent,
|
||||
transform,
|
||||
&ITEM_TYPE_INFO_CAMERA,
|
||||
|
||||
@@ -3,41 +3,23 @@ pub mod panel;
|
||||
|
||||
use self::camera::CameraItem;
|
||||
use self::panel::PanelItemTrait;
|
||||
use super::fields::Field;
|
||||
use super::alias::AliasList;
|
||||
use super::fields::{Field, FIELD_ALIAS_INFO};
|
||||
use super::spatial::Spatial;
|
||||
use super::{Alias, Aspect, Message, Node};
|
||||
use super::{Alias, Aspect, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::core::node_collections::LifeLinkedNodeMap;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::nodes::alias::AliasInfo;
|
||||
use crate::nodes::spatial::Transform;
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use lazy_static::lazy_static;
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::Ordering;
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
|
||||
use std::hash::Hash;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
stardust_xr_server_codegen::codegen_item_protocol!();
|
||||
|
||||
lazy_static! {
|
||||
static ref ITEM_ALIAS_LOCAL_SIGNALS: Vec<&'static str> = vec![
|
||||
"get_bounds",
|
||||
"get_transform",
|
||||
"set_transform",
|
||||
"set_spatial_parent",
|
||||
"set_spatial_parent_in_place",
|
||||
"set_zoneable",
|
||||
"release",
|
||||
];
|
||||
static ref ITEM_ALIAS_LOCAL_METHODS: Vec<&'static str> = vec![];
|
||||
static ref ITEM_ALIAS_REMOTE_SIGNALS: Vec<&'static str> = vec![];
|
||||
}
|
||||
|
||||
pub fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
|
||||
fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
|
||||
if item.captured_acceptor.lock().strong_count() > 0 {
|
||||
release(item);
|
||||
}
|
||||
@@ -60,14 +42,12 @@ fn release(item: &Item) {
|
||||
|
||||
pub struct TypeInfo {
|
||||
pub type_name: &'static str,
|
||||
pub aliased_local_signals: Vec<&'static str>,
|
||||
pub aliased_local_methods: Vec<&'static str>,
|
||||
pub aliased_remote_signals: Vec<&'static str>,
|
||||
pub alias_info: AliasInfo,
|
||||
pub ui_node_id: u64,
|
||||
pub ui: Mutex<Weak<ItemUI>>,
|
||||
pub items: Registry<Item>,
|
||||
pub acceptors: Registry<ItemAcceptor>,
|
||||
pub new_acceptor_fn:
|
||||
fn(node: &Node, uid: &str, acceptor: &Arc<Node>, acceptor_field: &Arc<Node>),
|
||||
pub new_acceptor_fn: fn(node: &Node, acceptor: &Arc<Node>, acceptor_field: &Arc<Node>),
|
||||
}
|
||||
impl Hash for TypeInfo {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
@@ -83,7 +63,6 @@ impl Eq for TypeInfo {}
|
||||
|
||||
pub struct Item {
|
||||
node: Weak<Node>,
|
||||
uid: String,
|
||||
type_info: &'static TypeInfo,
|
||||
captured_acceptor: Mutex<Weak<ItemAcceptor>>,
|
||||
pub specialization: ItemType,
|
||||
@@ -91,20 +70,18 @@ pub struct Item {
|
||||
impl Item {
|
||||
pub fn add_to(
|
||||
node: &Arc<Node>,
|
||||
uid: String,
|
||||
type_info: &'static TypeInfo,
|
||||
specialization: ItemType,
|
||||
) -> Arc<Self> {
|
||||
let item = Item {
|
||||
node: Arc::downgrade(node),
|
||||
uid,
|
||||
type_info,
|
||||
captured_acceptor: Default::default(),
|
||||
specialization,
|
||||
};
|
||||
let item = type_info.items.add(item);
|
||||
|
||||
node.add_local_signal("release", Item::release_flex);
|
||||
<Item as ItemAspect>::add_node_members(node);
|
||||
if let Some(ui) = type_info.ui.lock().upgrade() {
|
||||
ui.handle_create_item(&item);
|
||||
}
|
||||
@@ -122,54 +99,25 @@ impl Item {
|
||||
|
||||
item
|
||||
}
|
||||
fn make_alias_named(
|
||||
&self,
|
||||
client: &Arc<Client>,
|
||||
parent: &str,
|
||||
name: &str,
|
||||
) -> Result<Arc<Node>> {
|
||||
fn make_alias(&self, client: &Arc<Client>, alias_list: &AliasList) -> Result<Arc<Node>> {
|
||||
Alias::create(
|
||||
client,
|
||||
parent,
|
||||
name,
|
||||
&self.node.upgrade().unwrap(),
|
||||
AliasInfo {
|
||||
server_signals: [
|
||||
&self.type_info.aliased_local_signals,
|
||||
ITEM_ALIAS_LOCAL_SIGNALS.as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
server_methods: [
|
||||
&self.type_info.aliased_local_methods,
|
||||
ITEM_ALIAS_LOCAL_METHODS.as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
client_signals: [
|
||||
&self.type_info.aliased_remote_signals,
|
||||
ITEM_ALIAS_REMOTE_SIGNALS.as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
},
|
||||
client,
|
||||
self.type_info.alias_info.clone() + ITEM_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(alias_list),
|
||||
)
|
||||
}
|
||||
fn make_alias(&self, client: &Arc<Client>, parent: &str) -> Result<Arc<Node>> {
|
||||
self.make_alias_named(client, parent, &self.uid)
|
||||
}
|
||||
|
||||
fn release_flex(
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<()> {
|
||||
let item = node.get_aspect::<Item>()?;
|
||||
release(&item);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Aspect for Item {
|
||||
const NAME: &'static str = "Item";
|
||||
}
|
||||
impl ItemAspect for Item {
|
||||
fn release(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
|
||||
let item = node.get_aspect::<Item>()?;
|
||||
release(&item);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for Item {
|
||||
fn drop(&mut self) {
|
||||
self.type_info.items.remove(self);
|
||||
@@ -185,16 +133,16 @@ pub enum ItemType {
|
||||
Panel(Arc<dyn PanelItemTrait>),
|
||||
}
|
||||
impl ItemType {
|
||||
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
|
||||
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
match self {
|
||||
ItemType::Camera(c) => c.send_ui_item_created(node, uid, item),
|
||||
ItemType::Panel(p) => p.send_ui_item_created(node, uid, item),
|
||||
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, uid: &str, item: &Arc<Node>) {
|
||||
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
match self {
|
||||
ItemType::Camera(c) => c.send_acceptor_item_created(node, uid, item),
|
||||
ItemType::Panel(p) => p.send_acceptor_item_created(node, uid, item),
|
||||
ItemType::Camera(c) => c.send_acceptor_item_created(node, item),
|
||||
ItemType::Panel(p) => p.send_acceptor_item_created(node, item),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,9 +160,9 @@ impl ItemType {
|
||||
pub struct ItemUI {
|
||||
node: Weak<Node>,
|
||||
type_info: &'static TypeInfo,
|
||||
item_aliases: LifeLinkedNodeMap<String>,
|
||||
acceptor_aliases: LifeLinkedNodeMap<String>,
|
||||
acceptor_field_aliases: LifeLinkedNodeMap<String>,
|
||||
item_aliases: AliasList,
|
||||
acceptor_aliases: AliasList,
|
||||
acceptor_field_aliases: AliasList,
|
||||
}
|
||||
impl ItemUI {
|
||||
fn add_to(node: &Arc<Node>, type_info: &'static TypeInfo) -> Result<()> {
|
||||
@@ -226,9 +174,9 @@ impl ItemUI {
|
||||
let ui = Arc::new(ItemUI {
|
||||
node: Arc::downgrade(node),
|
||||
type_info,
|
||||
item_aliases: Default::default(),
|
||||
acceptor_aliases: Default::default(),
|
||||
acceptor_field_aliases: Default::default(),
|
||||
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());
|
||||
@@ -250,26 +198,44 @@ impl ItemUI {
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(item_alias) = item.make_alias(&client, &(node.get_path().to_string() + "/item"))
|
||||
else {
|
||||
let Ok(item_alias) = item.make_alias(&client, &self.item_aliases) else {
|
||||
return;
|
||||
};
|
||||
self.item_aliases.add(item.uid.clone(), &item_alias);
|
||||
|
||||
item.specialization
|
||||
.send_ui_item_created(&node, &item.uid, &item_alias);
|
||||
item.specialization.send_ui_item_created(&node, &item_alias);
|
||||
}
|
||||
fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) {
|
||||
let _ =
|
||||
item_ui_client::capture_item(&self.node.upgrade().unwrap(), &item.uid, &acceptor.uid);
|
||||
let Some(item_alias) = self.item_aliases.get(item) else {
|
||||
return;
|
||||
};
|
||||
let Some(acceptor_alias) = self.acceptor_aliases.get(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 _ =
|
||||
item_ui_client::release_item(&self.node.upgrade().unwrap(), &item.uid, &acceptor.uid);
|
||||
let Some(item_alias) = self.item_aliases.get(item) else {
|
||||
return;
|
||||
};
|
||||
let Some(acceptor_alias) = self.acceptor_aliases.get(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 _ = item_ui_client::destroy_item(&self.node.upgrade().unwrap(), &item.uid);
|
||||
self.item_aliases.remove(&item.uid);
|
||||
let Some(item_alias) = self.item_aliases.get(item) 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 {
|
||||
@@ -279,28 +245,40 @@ impl ItemUI {
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok((acceptor_alias, acceptor_field_alias)) = acceptor.make_aliases(
|
||||
let Some(acceptor_node) = acceptor.spatial.node() else {
|
||||
return;
|
||||
};
|
||||
let Ok(acceptor_alias) = Alias::create(
|
||||
&acceptor_node,
|
||||
&client,
|
||||
&format!("/item/{}/acceptor", self.type_info.type_name),
|
||||
ITEM_ACCEPTOR_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&self.acceptor_aliases),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
self.acceptor_aliases
|
||||
.add(acceptor.uid.clone(), &acceptor_alias);
|
||||
self.acceptor_field_aliases
|
||||
.add(acceptor.uid.clone(), &acceptor_field_alias);
|
||||
|
||||
(acceptor.type_info.new_acceptor_fn)(
|
||||
&node,
|
||||
&acceptor.uid,
|
||||
&acceptor_alias,
|
||||
&acceptor_field_alias,
|
||||
);
|
||||
let Some(acceptor_field_node) = acceptor.field.spatial_ref().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 _ = item_ui_client::destroy_acceptor(&self.node.upgrade().unwrap(), &acceptor.uid);
|
||||
self.acceptor_aliases.remove(&acceptor.uid);
|
||||
self.acceptor_field_aliases.remove(&acceptor.uid);
|
||||
let acceptor_alias = self.acceptor_aliases.get(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 Aspect for ItemUI {
|
||||
@@ -313,69 +291,29 @@ impl Drop for ItemUI {
|
||||
}
|
||||
|
||||
pub struct ItemAcceptor {
|
||||
uid: String,
|
||||
node: Weak<Node>,
|
||||
spatial: Arc<Spatial>,
|
||||
pub type_info: &'static TypeInfo,
|
||||
field: Arc<Field>,
|
||||
accepted_aliases: LifeLinkedNodeMap<String>,
|
||||
accepted_aliases: AliasList,
|
||||
accepted_registry: Registry<Item>,
|
||||
}
|
||||
impl ItemAcceptor {
|
||||
fn add_to(node: &Arc<Node>, type_info: &'static TypeInfo, field: Arc<Field>) {
|
||||
let acceptor = type_info.acceptors.add(ItemAcceptor {
|
||||
uid: nanoid!(),
|
||||
node: Arc::downgrade(node),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap(),
|
||||
type_info,
|
||||
field,
|
||||
accepted_aliases: Default::default(),
|
||||
accepted_aliases: AliasList::default(),
|
||||
accepted_registry: Registry::new(),
|
||||
});
|
||||
node.add_local_signal("capture", ItemAcceptor::capture_flex);
|
||||
if let Some(ui) = type_info.ui.lock().upgrade() {
|
||||
ui.handle_create_acceptor(&acceptor);
|
||||
}
|
||||
node.add_aspect_raw(acceptor);
|
||||
node.add_aspect_raw(acceptor.clone());
|
||||
}
|
||||
|
||||
fn capture_flex(node: Arc<Node>, calling_client: Arc<Client>, message: Message) -> Result<()> {
|
||||
if !node.enabled.load(Ordering::Relaxed) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let acceptor = node.get_aspect::<ItemAcceptor>().unwrap();
|
||||
let item_path: &str = deserialize(message.as_ref())?;
|
||||
let item_node = calling_client.get_node("Item", item_path)?;
|
||||
let item = item_node.get_aspect::<Item>()?;
|
||||
capture(&item, &acceptor);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_aliases(&self, client: &Arc<Client>, parent: &str) -> Result<(Arc<Node>, Arc<Node>)> {
|
||||
let acceptor_node = &self.node.upgrade().unwrap();
|
||||
let acceptor_alias = Alias::create(
|
||||
client,
|
||||
parent,
|
||||
&self.uid,
|
||||
acceptor_node,
|
||||
AliasInfo {
|
||||
server_signals: vec!["capture"],
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
let acceptor_field_alias = Alias::create(
|
||||
client,
|
||||
acceptor_alias.get_path(),
|
||||
"field",
|
||||
&self.field.spatial_ref().node.upgrade().unwrap(),
|
||||
AliasInfo::default(),
|
||||
)?;
|
||||
|
||||
Ok((acceptor_alias, acceptor_field_alias))
|
||||
}
|
||||
fn handle_capture(&self, item: &Arc<Item>) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
let Some(node) = self.spatial.node() else {
|
||||
return;
|
||||
};
|
||||
let Some(client) = node.get_client() else {
|
||||
@@ -383,21 +321,22 @@ impl ItemAcceptor {
|
||||
};
|
||||
|
||||
self.accepted_registry.add_raw(item);
|
||||
let Ok(alias_node) = item.make_alias(&client, &node.path) else {
|
||||
let Ok(alias_node) = item.make_alias(&client, &self.accepted_aliases) else {
|
||||
return;
|
||||
};
|
||||
self.accepted_aliases.add(item.uid.clone(), &alias_node);
|
||||
|
||||
item.specialization
|
||||
.send_acceptor_item_created(&node, &item.uid, &alias_node);
|
||||
.send_acceptor_item_created(&node, &alias_node);
|
||||
}
|
||||
fn handle_release(&self, item: &Item) {
|
||||
if let Some(node) = self.node.upgrade() {
|
||||
let _ = item_acceptor_client::release_item(&node, &item.uid);
|
||||
}
|
||||
|
||||
self.accepted_registry.remove(item);
|
||||
self.accepted_aliases.remove(&item.uid);
|
||||
self.accepted_aliases.remove_aspect(item);
|
||||
|
||||
let Some(node) = self.spatial.node() else {
|
||||
return;
|
||||
};
|
||||
let alias = self.accepted_aliases.get(item).unwrap();
|
||||
let _ = item_acceptor_client::release_item(&node, alias.id);
|
||||
}
|
||||
}
|
||||
impl Aspect for ItemAcceptor {
|
||||
@@ -420,14 +359,13 @@ pub fn register_item_ui_flex(
|
||||
calling_client: Arc<Client>,
|
||||
type_info: &'static TypeInfo,
|
||||
) -> Result<()> {
|
||||
let ui = Node::create_parent_name(&calling_client, "/item", type_info.type_name, true)
|
||||
.add_to_scenegraph()?;
|
||||
let ui = Node::from_id(&calling_client, type_info.ui_node_id, true).add_to_scenegraph()?;
|
||||
ItemUI::add_to(&ui, type_info)?;
|
||||
Ok(())
|
||||
}
|
||||
fn create_item_acceptor_flex(
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
type_info: &'static TypeInfo,
|
||||
@@ -437,17 +375,19 @@ fn create_item_acceptor_flex(
|
||||
let field = field.get_aspect::<Field>()?;
|
||||
let transform = transform.to_mat4(true, true, false);
|
||||
|
||||
let node = Node::create_parent_name(
|
||||
&calling_client,
|
||||
&format!("/item/{}/acceptor", type_info.type_name),
|
||||
&name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn acceptor_capture_item_flex(node: Arc<Node>, item: Arc<Node>) -> Result<()> {
|
||||
let acceptor = node.get_aspect::<ItemAcceptor>()?;
|
||||
let item = item.get_aspect::<Item>()?;
|
||||
capture(&item, &acceptor);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct ItemInterface;
|
||||
// create_interface!(ItemInterface, ItemInterfaceAspect, "/item");
|
||||
// create_interface!(ItemInterface);
|
||||
|
||||
@@ -15,51 +15,22 @@ use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use lazy_static::lazy_static;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use super::{create_item_acceptor_flex, register_item_ui_flex, ItemInterface};
|
||||
use super::{create_item_acceptor_flex, register_item_ui_flex, ItemAcceptor, ItemInterface};
|
||||
|
||||
stardust_xr_server_codegen::codegen_item_panel_protocol!();
|
||||
lazy_static! {
|
||||
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
|
||||
type_name: "panel",
|
||||
aliased_local_signals: vec![
|
||||
"apply_surface_material",
|
||||
"close_toplevel",
|
||||
"auto_size_toplevel",
|
||||
"set_toplevel_size",
|
||||
"set_toplevel_focused_visuals",
|
||||
"pointer_motion",
|
||||
"pointer_button",
|
||||
"pointer_scroll",
|
||||
"keyboard_keymap",
|
||||
"keyboard_key",
|
||||
"touch_down",
|
||||
"touch_move",
|
||||
"touch_up",
|
||||
"reset_touches",
|
||||
],
|
||||
aliased_local_methods: vec![],
|
||||
aliased_remote_signals: vec![
|
||||
"toplevel_parent_changed",
|
||||
"toplevel_title_changed",
|
||||
"toplevel_app_id_changed",
|
||||
"toplevel_fullscreen_active",
|
||||
"toplevel_move_request",
|
||||
"toplevel_resize_request",
|
||||
"toplevel_size_changed",
|
||||
"set_cursor",
|
||||
"new_child",
|
||||
"reposition_child",
|
||||
"drop_child",
|
||||
],
|
||||
alias_info: PANEL_ITEM_ASPECT_ALIAS_INFO.clone(),
|
||||
ui_node_id: INTERFACE_NODE_ID,
|
||||
ui: Default::default(),
|
||||
items: Registry::new(),
|
||||
acceptors: Registry::new(),
|
||||
new_acceptor_fn: |node, uid, acceptor, acceptor_field| {
|
||||
let _ = panel_item_ui_client::create_acceptor(node, uid, acceptor, acceptor_field);
|
||||
new_acceptor_fn: |node, acceptor, acceptor_field| {
|
||||
let _ = panel_item_ui_client::create_acceptor(node, acceptor, acceptor_field);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -85,7 +56,7 @@ pub trait Backend: Send + Sync + 'static {
|
||||
scroll_steps: Option<Vector2<f32>>,
|
||||
);
|
||||
|
||||
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>);
|
||||
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec<i32>);
|
||||
|
||||
fn touch_down(&self, surface: &SurfaceId, id: u32, position: Vector2<f32>);
|
||||
fn touch_move(&self, id: u32, position: Vector2<f32>);
|
||||
@@ -101,13 +72,12 @@ pub fn panel_item_from_node(node: &Node) -> Option<Arc<dyn PanelItemTrait>> {
|
||||
}
|
||||
|
||||
pub trait PanelItemTrait: Backend + Send + Sync + 'static {
|
||||
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>);
|
||||
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>);
|
||||
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>);
|
||||
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>);
|
||||
}
|
||||
|
||||
pub struct PanelItem<B: Backend + ?Sized> {
|
||||
pub uid: String,
|
||||
node: Weak<Node>,
|
||||
pub node: Weak<Node>,
|
||||
pub backend: Box<B>,
|
||||
}
|
||||
impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
@@ -118,20 +88,13 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
.and_then(|pid| get_env(pid).ok())
|
||||
.and_then(|env| state(&env));
|
||||
|
||||
let uid = nanoid!();
|
||||
let node = Arc::new(Node::create_parent_name(
|
||||
&INTERNAL_CLIENT,
|
||||
"/item/panel/item",
|
||||
&uid,
|
||||
true,
|
||||
));
|
||||
let node = Arc::new(Node::generate(&INTERNAL_CLIENT, true));
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
if let Some(startup_settings) = &startup_settings {
|
||||
spatial.set_local_transform(startup_settings.root);
|
||||
}
|
||||
|
||||
let panel_item = Arc::new(PanelItem {
|
||||
uid: uid.clone(),
|
||||
node: Arc::downgrade(&node),
|
||||
backend,
|
||||
});
|
||||
@@ -139,7 +102,6 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
let generic_panel_item: Arc<dyn PanelItemTrait> = panel_item.clone();
|
||||
Item::add_to(
|
||||
&node,
|
||||
uid,
|
||||
&ITEM_TYPE_INFO_PANEL,
|
||||
ItemType::Panel(generic_panel_item),
|
||||
);
|
||||
@@ -158,7 +120,7 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
// Remote signals
|
||||
#[allow(unused)]
|
||||
impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
pub fn toplevel_parent_changed(&self, parent: &str) {
|
||||
pub fn toplevel_parent_changed(&self, parent: u64) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
@@ -212,23 +174,23 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_child(&self, uid: &str, info: ChildInfo) {
|
||||
pub fn create_child(&self, id: u64, info: &ChildInfo) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
panel_item_client::create_child(&node, uid, &info);
|
||||
panel_item_client::create_child(&node, id, info);
|
||||
}
|
||||
pub fn reposition_child(&self, uid: &str, geometry: Geometry) {
|
||||
pub fn reposition_child(&self, id: u64, geometry: &Geometry) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
panel_item_client::reposition_child(&node, uid, &geometry);
|
||||
panel_item_client::reposition_child(&node, id, geometry);
|
||||
}
|
||||
pub fn destroy_child(&self, uid: &str) {
|
||||
pub fn destroy_child(&self, id: u64) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
panel_item_client::destroy_child(&node, uid);
|
||||
panel_item_client::destroy_child(&node, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,13 +335,13 @@ impl<B: Backend + ?Sized> PanelItemAspect for PanelItem<B> {
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
surface: SurfaceId,
|
||||
keymap_id: String,
|
||||
keymap_id: u64,
|
||||
keys: Vec<i32>,
|
||||
) -> Result<()> {
|
||||
let Some(panel_item) = panel_item_from_node(&node) else {
|
||||
return Ok(());
|
||||
};
|
||||
panel_item.keyboard_keys(&surface, &keymap_id, keys);
|
||||
panel_item.keyboard_keys(&surface, keymap_id, keys);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -430,18 +392,25 @@ impl<B: Backend + ?Sized> PanelItemAspect for PanelItem<B> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
|
||||
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
|
||||
let Ok(init_data) = self.backend.start_data() else {
|
||||
return;
|
||||
};
|
||||
let _ = panel_item_ui_client::create_item(node, uid, item, init_data);
|
||||
|
||||
impl PanelItemAcceptorAspect for ItemAcceptor {
|
||||
fn capture_item(node: Arc<Node>, _calling_client: Arc<Client>, item: Arc<Node>) -> Result<()> {
|
||||
super::acceptor_capture_item_flex(node, item)
|
||||
}
|
||||
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
|
||||
}
|
||||
|
||||
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
|
||||
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
let Ok(init_data) = self.backend.start_data() else {
|
||||
return;
|
||||
};
|
||||
let _ = panel_item_acceptor_client::capture_item(node, uid, item, init_data);
|
||||
let _ = panel_item_ui_client::create_item(node, item, init_data);
|
||||
}
|
||||
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
let Ok(init_data) = self.backend.start_data() else {
|
||||
return;
|
||||
};
|
||||
let _ = panel_item_acceptor_client::capture_item(node, item, init_data);
|
||||
}
|
||||
}
|
||||
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
||||
@@ -488,7 +457,7 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
||||
.pointer_scroll(surface, scroll_distance, scroll_steps)
|
||||
}
|
||||
|
||||
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>) {
|
||||
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec<i32>) {
|
||||
self.backend.keyboard_keys(surface, keymap_id, keys)
|
||||
}
|
||||
|
||||
@@ -508,12 +477,12 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
||||
impl<B: Backend + ?Sized> Drop for PanelItem<B> {
|
||||
fn drop(&mut self) {
|
||||
// Dropped panel item, basically just a debug breakpoint place
|
||||
info!("Dropped panel item {}", self.uid);
|
||||
info!("Dropped panel item");
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(ItemInterface, ItemPanelInterfaceAspect, "/item/panel");
|
||||
impl ItemPanelInterfaceAspect for ItemInterface {
|
||||
create_interface!(ItemInterface);
|
||||
impl InterfaceAspect for ItemInterface {
|
||||
#[doc = "Register this client to manage the items of a certain type and create default 3D UI for them."]
|
||||
fn register_panel_item_ui(_node: Arc<Node>, calling_client: Arc<Client>) -> Result<()> {
|
||||
register_item_ui_flex(calling_client, &ITEM_TYPE_INFO_PANEL)
|
||||
@@ -523,14 +492,14 @@ impl ItemPanelInterfaceAspect for ItemInterface {
|
||||
fn create_panel_item_acceptor(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
field: Arc<Node>,
|
||||
) -> Result<()> {
|
||||
create_item_acceptor_flex(
|
||||
calling_client,
|
||||
name,
|
||||
id,
|
||||
parent,
|
||||
transform,
|
||||
&ITEM_TYPE_INFO_PANEL,
|
||||
|
||||
@@ -10,7 +10,6 @@ pub mod root;
|
||||
pub mod spatial;
|
||||
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
use rustc_hash::FxHashMap;
|
||||
@@ -56,13 +55,12 @@ stardust_xr_server_codegen::codegen_node_protocol!();
|
||||
|
||||
pub struct Node {
|
||||
enabled: Arc<AtomicBool>,
|
||||
pub(super) uid: String,
|
||||
path: String,
|
||||
id: u64,
|
||||
client: Weak<Client>,
|
||||
message_sender_handle: Option<MessageSenderHandle>,
|
||||
// trailing_slash_pos: usize,
|
||||
local_signals: Mutex<FxHashMap<String, Signal>>,
|
||||
local_methods: Mutex<FxHashMap<String, Method>>,
|
||||
|
||||
local_signals: Mutex<FxHashMap<u64, Signal>>,
|
||||
local_methods: Mutex<FxHashMap<u64, Method>>,
|
||||
aliases: Registry<Alias>,
|
||||
aspects: Aspects,
|
||||
destroyable: bool,
|
||||
@@ -71,32 +69,19 @@ impl Node {
|
||||
pub fn get_client(&self) -> Option<Arc<Client>> {
|
||||
self.client.upgrade()
|
||||
}
|
||||
// pub fn get_name(&self) -> &str {
|
||||
// &self.path[self.trailing_slash_pos + 1..]
|
||||
// }
|
||||
pub fn get_path(&self) -> &str {
|
||||
self.path.as_str()
|
||||
pub fn get_id(&self) -> u64 {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn create_parent_name(
|
||||
client: &Arc<Client>,
|
||||
parent: &str,
|
||||
name: &str,
|
||||
destroyable: bool,
|
||||
) -> Self {
|
||||
let mut path = parent.to_string();
|
||||
path.push('/');
|
||||
path.push_str(name);
|
||||
Self::create_path(client, path, destroyable)
|
||||
pub fn generate(client: &Arc<Client>, destroyable: bool) -> Self {
|
||||
Self::from_id(client, client.generate_id(), destroyable)
|
||||
}
|
||||
pub fn create_path(client: &Arc<Client>, path: impl ToString, destroyable: bool) -> Self {
|
||||
pub fn from_id(client: &Arc<Client>, id: u64, destroyable: bool) -> Self {
|
||||
let node = Node {
|
||||
enabled: Arc::new(AtomicBool::new(true)),
|
||||
uid: nanoid!(),
|
||||
client: Arc::downgrade(client),
|
||||
message_sender_handle: client.message_sender_handle.clone(),
|
||||
path: path.to_string(),
|
||||
// trailing_slash_pos: parent.len(),
|
||||
id,
|
||||
local_signals: Default::default(),
|
||||
local_methods: Default::default(),
|
||||
aliases: Default::default(),
|
||||
@@ -118,7 +103,7 @@ impl Node {
|
||||
}
|
||||
pub fn destroy(&self) {
|
||||
if let Some(client) = self.get_client() {
|
||||
client.scenegraph.remove_node(self.get_path());
|
||||
client.scenegraph.remove_node(self.get_id());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,11 +121,11 @@ impl Node {
|
||||
// Ok(serialize(pid)?.into())
|
||||
// }
|
||||
|
||||
pub fn add_local_signal(&self, name: &str, signal: Signal) {
|
||||
self.local_signals.lock().insert(name.to_string(), signal);
|
||||
pub fn add_local_signal(&self, id: u64, signal: Signal) {
|
||||
self.local_signals.lock().insert(id, signal);
|
||||
}
|
||||
pub fn add_local_method(&self, name: &str, method: Method) {
|
||||
self.local_methods.lock().insert(name.to_string(), method);
|
||||
pub fn add_local_method(&self, id: u64, method: Method) {
|
||||
self.local_methods.lock().insert(id, method);
|
||||
}
|
||||
|
||||
pub fn add_aspect<A: Aspect>(&self, aspect: A) -> Arc<A> {
|
||||
@@ -156,7 +141,7 @@ impl Node {
|
||||
pub fn send_local_signal(
|
||||
self: Arc<Self>,
|
||||
calling_client: Arc<Client>,
|
||||
method: &str,
|
||||
method: u64,
|
||||
message: Message,
|
||||
) -> Result<(), ScenegraphError> {
|
||||
if let Ok(alias) = self.get_aspect::<Alias>() {
|
||||
@@ -172,7 +157,7 @@ impl Node {
|
||||
let signal = self
|
||||
.local_signals
|
||||
.lock()
|
||||
.get(method)
|
||||
.get(&method)
|
||||
.cloned()
|
||||
.ok_or(ScenegraphError::SignalNotFound)?;
|
||||
signal(self, calling_client, message).map_err(|error| ScenegraphError::SignalError {
|
||||
@@ -183,7 +168,7 @@ impl Node {
|
||||
pub fn execute_local_method(
|
||||
self: Arc<Self>,
|
||||
calling_client: Arc<Client>,
|
||||
method: &str,
|
||||
method: u64,
|
||||
message: Message,
|
||||
response: MethodResponseSender,
|
||||
) {
|
||||
@@ -206,14 +191,14 @@ impl Node {
|
||||
response,
|
||||
)
|
||||
} else {
|
||||
let Some(method) = self.local_methods.lock().get(method).cloned() else {
|
||||
let Some(method) = self.local_methods.lock().get(&method).cloned() else {
|
||||
response.send(Err(ScenegraphError::MethodNotFound));
|
||||
return;
|
||||
};
|
||||
method(self, calling_client, message, response);
|
||||
}
|
||||
}
|
||||
pub fn send_remote_signal(&self, method: &str, message: impl Into<Message>) -> Result<()> {
|
||||
pub fn send_remote_signal(&self, method: u64, message: impl Into<Message>) -> Result<()> {
|
||||
let message = message.into();
|
||||
self.aliases
|
||||
.get_valid_contents()
|
||||
@@ -230,16 +215,14 @@ impl Node {
|
||||
},
|
||||
);
|
||||
});
|
||||
let path = self.path.clone();
|
||||
let method = method.to_string();
|
||||
if let Some(handle) = self.message_sender_handle.as_ref() {
|
||||
handle.signal(path.as_str(), method.as_str(), &message.data, message.fds)?;
|
||||
handle.signal(self.id, method, &message.data, message.fds)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub async fn execute_remote_method_typed<S: Serialize, D: DeserializeOwned>(
|
||||
&self,
|
||||
method: &str,
|
||||
method: u64,
|
||||
input: S,
|
||||
fds: Vec<OwnedFd>,
|
||||
) -> Result<(D, Vec<OwnedFd>)> {
|
||||
@@ -250,7 +233,7 @@ impl Node {
|
||||
|
||||
let serialized = serialize(input)?;
|
||||
let result = message_sender_handle
|
||||
.method(self.path.as_str(), method, &serialized, fds)?
|
||||
.method(self.id, method, &serialized, fds)?
|
||||
.await
|
||||
.map_err(|e| eyre!(e))?;
|
||||
|
||||
@@ -261,10 +244,7 @@ impl Node {
|
||||
}
|
||||
impl Debug for Node {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Node")
|
||||
.field("uid", &self.uid)
|
||||
.field("path", &self.path)
|
||||
.finish()
|
||||
f.debug_struct("Node").field("id", &self.id).finish()
|
||||
}
|
||||
}
|
||||
impl OwnedAspect for Node {
|
||||
|
||||
@@ -1,128 +1,73 @@
|
||||
use super::spatial::Spatial;
|
||||
use super::{Message, Node};
|
||||
use super::Node;
|
||||
use crate::core::client::Client;
|
||||
use crate::core::client_state::{ClientState, ClientStateInternal};
|
||||
use crate::core::client_state::ClientStateParsed;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::core::scenegraph::MethodResponseSender;
|
||||
#[cfg(feature = "wayland")]
|
||||
use crate::wayland::WAYLAND_DISPLAY;
|
||||
#[cfg(feature = "xwayland")]
|
||||
use crate::wayland::X_DISPLAY;
|
||||
use crate::STARDUST_INSTANCE;
|
||||
use color_eyre::eyre::Result;
|
||||
use color_eyre::eyre::{bail, Result};
|
||||
use glam::Mat4;
|
||||
use rustc_hash::FxHashMap;
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tracing::{info, instrument};
|
||||
use tracing::info;
|
||||
|
||||
static ROOT_REGISTRY: Registry<Root> = Registry::new();
|
||||
|
||||
pub struct Root {
|
||||
pub node: Arc<Node>,
|
||||
send_frame_event: AtomicBool,
|
||||
}
|
||||
stardust_xr_server_codegen::codegen_root_protocol!();
|
||||
|
||||
pub struct Root(Arc<Node>);
|
||||
impl Root {
|
||||
pub fn create(client: &Arc<Client>) -> Result<Arc<Self>> {
|
||||
let node = Node::create_parent_name(client, "", "", false);
|
||||
node.add_local_signal("subscribe_frame", Root::subscribe_frame_flex);
|
||||
node.add_local_signal("set_base_prefixes", Root::set_base_prefixes_flex);
|
||||
node.add_local_method("state_token", Root::state_token_flex);
|
||||
node.add_local_method(
|
||||
"get_connection_environment",
|
||||
get_connection_environment_flex,
|
||||
);
|
||||
pub fn create(client: &Arc<Client>, transform: Mat4) -> Result<Arc<Self>> {
|
||||
let node = Node::from_id(client, 0, false);
|
||||
<Self as RootAspect>::add_node_members(&node);
|
||||
let node = node.add_to_scenegraph()?;
|
||||
let _ = Spatial::add_to(&node, None, client.state.root, false);
|
||||
let _ = Spatial::add_to(&node, None, transform, false);
|
||||
|
||||
Ok(ROOT_REGISTRY.add(Root {
|
||||
node,
|
||||
send_frame_event: AtomicBool::from(false),
|
||||
}))
|
||||
Ok(ROOT_REGISTRY.add(Root(node)))
|
||||
}
|
||||
|
||||
fn subscribe_frame_flex(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<()> {
|
||||
calling_client
|
||||
.root
|
||||
.get()
|
||||
.unwrap()
|
||||
.send_frame_event
|
||||
.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug")]
|
||||
pub fn send_frame_events(delta: f64) {
|
||||
if let Ok(data) = serialize((delta, 0.0)) {
|
||||
for root in ROOT_REGISTRY.get_valid_contents() {
|
||||
if root.send_frame_event.load(Ordering::Relaxed) {
|
||||
let _ = root.node.send_remote_signal("frame", data.clone());
|
||||
}
|
||||
}
|
||||
let info = FrameInfo {
|
||||
delta: delta as f32,
|
||||
elapsed: 0.0,
|
||||
};
|
||||
for root in ROOT_REGISTRY.get_valid_contents() {
|
||||
let _ = root_client::frame(&root.0, &info);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_base_prefixes_flex(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
let prefixes: Vec<PathBuf> = deserialize(message.as_ref())?;
|
||||
info!(?calling_client, ?prefixes, "Set base prefixes");
|
||||
*calling_client.base_resource_prefixes.lock() = prefixes;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn state_token_flex(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
response: MethodResponseSender,
|
||||
) {
|
||||
response.wrap_sync(|| {
|
||||
let state: ClientStateInternal = deserialize(message.as_ref())?;
|
||||
let token = ClientState::from_deserialized(&calling_client, state).token();
|
||||
Ok(serialize(token)?.into())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_transform(&self, transform: Mat4) {
|
||||
let spatial = self.node.get_aspect::<Spatial>().unwrap();
|
||||
let spatial = self.0.get_aspect::<Spatial>().unwrap();
|
||||
spatial.set_spatial_parent(None).unwrap();
|
||||
spatial.set_local_transform(transform);
|
||||
}
|
||||
pub async fn save_state(&self) -> Result<ClientStateInternal> {
|
||||
self.node
|
||||
.execute_remote_method_typed("save_state", (), Vec::new())
|
||||
.await
|
||||
.map(|(m, _)| m)
|
||||
pub async fn save_state(&self) -> Result<ClientState> {
|
||||
Ok(root_client::save_state(&self.0).await?.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Root {
|
||||
fn drop(&mut self) {
|
||||
ROOT_REGISTRY.remove(self);
|
||||
impl RootAspect for Root {
|
||||
async fn get_state(_node: Arc<Node>, calling_client: Arc<Client>) -> Result<ClientState> {
|
||||
let Some(state) = calling_client.state.get() else {
|
||||
bail!("Couldn't get state");
|
||||
};
|
||||
Ok(state.clone())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! var_env_insert {
|
||||
($env:ident, $name:ident) => {
|
||||
$env.insert(stringify!($name).to_string(), $name.get().unwrap().clone());
|
||||
};
|
||||
}
|
||||
pub fn get_connection_environment_flex(
|
||||
_node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
response: MethodResponseSender,
|
||||
) {
|
||||
response.wrap_sync(move || {
|
||||
#[doc = "Get a hashmap of all the environment variables to connect a given app to the stardust server"]
|
||||
async fn get_connection_environment(
|
||||
_node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
) -> Result<stardust_xr::values::Map<String, String>> {
|
||||
macro_rules! var_env_insert {
|
||||
($env:ident, $name:ident) => {
|
||||
$env.insert(stringify!($name).to_string(), $name.get().unwrap().clone());
|
||||
};
|
||||
}
|
||||
|
||||
let mut env: FxHashMap<String, String> = FxHashMap::default();
|
||||
var_env_insert!(env, STARDUST_INSTANCE);
|
||||
#[cfg(feature = "wayland")]
|
||||
@@ -140,6 +85,38 @@ pub fn get_connection_environment_flex(
|
||||
env.insert("SDL_VIDEODRIVER".to_string(), "wayland".to_string());
|
||||
}
|
||||
|
||||
Ok(serialize(env)?.into())
|
||||
});
|
||||
Ok(env)
|
||||
}
|
||||
|
||||
#[doc = "Generate a client state token and return it back.\n\n When launching a new client, set the environment variable `STARDUST_STARTUP_TOKEN` to the returned string.\n Make sure the environment variable shows in `/proc/{pid}/environ` as that's the only reliable way to pass the value to the server (suggestions welcome).\n"]
|
||||
async fn client_state_token(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
state: ClientState,
|
||||
) -> Result<String> {
|
||||
Ok(ClientStateParsed::from_deserialized(&calling_client, state).token())
|
||||
}
|
||||
|
||||
#[doc = "Set initial list of folders to look for namespaced resources in"]
|
||||
fn set_base_prefixes(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
prefixes: Vec<String>,
|
||||
) -> Result<()> {
|
||||
info!(?calling_client, ?prefixes, "Set base prefixes");
|
||||
*calling_client.base_resource_prefixes.lock() =
|
||||
prefixes.into_iter().map(PathBuf::from).collect();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[doc = "Cleanly disconnect from the server"]
|
||||
fn disconnect(_node: Arc<Node>, calling_client: Arc<Client>) -> color_eyre::eyre::Result<()> {
|
||||
calling_client.disconnect(Ok(()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for Root {
|
||||
fn drop(&mut self) {
|
||||
ROOT_REGISTRY.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use crate::create_interface;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use glam::{vec3a, Mat4, Quat, Vec3};
|
||||
use mint::Vector3;
|
||||
use nanoid::nanoid;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use std::fmt::Debug;
|
||||
@@ -40,20 +39,18 @@ impl Transform {
|
||||
static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
|
||||
|
||||
pub struct Spatial {
|
||||
uid: String,
|
||||
pub(super) node: Weak<Node>,
|
||||
node: Weak<Node>,
|
||||
parent: Mutex<Option<Arc<Spatial>>>,
|
||||
old_parent: Mutex<Option<Arc<Spatial>>>,
|
||||
pub(super) transform: Mutex<Mat4>,
|
||||
transform: Mutex<Mat4>,
|
||||
zone: Mutex<Weak<Zone>>,
|
||||
children: Registry<Spatial>,
|
||||
pub(super) bounding_box_calc: OnceCell<fn(&Node) -> Bounds>,
|
||||
pub bounding_box_calc: OnceCell<fn(&Node) -> Bounds>,
|
||||
}
|
||||
|
||||
impl Spatial {
|
||||
pub fn new(node: Weak<Node>, parent: Option<Arc<Spatial>>, transform: Mat4) -> Arc<Self> {
|
||||
Arc::new(Spatial {
|
||||
uid: nanoid!(),
|
||||
node,
|
||||
parent: Mutex::new(parent),
|
||||
old_parent: Mutex::new(None),
|
||||
@@ -232,7 +229,7 @@ impl Spatial {
|
||||
self.zone
|
||||
.lock()
|
||||
.upgrade()
|
||||
.and_then(|zone| zone.field.upgrade())
|
||||
.map(|zone| zone.field.clone())
|
||||
.map(|field| field.distance(self, vec3a(0.0, 0.0, 0.0)))
|
||||
.unwrap_or(f32::MAX)
|
||||
}
|
||||
@@ -359,13 +356,12 @@ impl SpatialAspect for Spatial {
|
||||
}
|
||||
impl PartialEq for Spatial {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.uid == other.uid
|
||||
self.node.as_ptr() == other.node.as_ptr()
|
||||
}
|
||||
}
|
||||
impl Debug for Spatial {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Spatial")
|
||||
.field("uid", &self.uid)
|
||||
.field("parent", &self.parent)
|
||||
.field("old_parent", &self.old_parent)
|
||||
.field("transform", &self.transform)
|
||||
@@ -374,7 +370,7 @@ impl Debug for Spatial {
|
||||
}
|
||||
impl Drop for Spatial {
|
||||
fn drop(&mut self) {
|
||||
zone::release_drop(self);
|
||||
zone::release(self);
|
||||
ZONEABLE_REGISTRY.remove(self);
|
||||
}
|
||||
}
|
||||
@@ -397,26 +393,25 @@ pub fn parse_transform(transform: Transform, position: bool, rotation: bool, sca
|
||||
}
|
||||
|
||||
pub struct SpatialInterface;
|
||||
impl SpatialInterfaceAspect for SpatialInterface {
|
||||
impl InterfaceAspect for SpatialInterface {
|
||||
fn create_spatial(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
zoneable: bool,
|
||||
) -> Result<()> {
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = parse_transform(transform, true, true, true);
|
||||
let node = Node::create_parent_name(&calling_client, "/spatial/spatial", &name, true)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, zoneable);
|
||||
Ok(())
|
||||
}
|
||||
fn create_zone(
|
||||
_node: Arc<Node>,
|
||||
calling_client: Arc<Client>,
|
||||
name: String,
|
||||
id: u64,
|
||||
parent: Arc<Node>,
|
||||
transform: Transform,
|
||||
field: Arc<Node>,
|
||||
@@ -425,12 +420,11 @@ impl SpatialInterfaceAspect for SpatialInterface {
|
||||
let transform = parse_transform(transform, true, true, false);
|
||||
let field = field.get_aspect::<Field>()?;
|
||||
|
||||
let node = Node::create_parent_name(&calling_client, "/spatial/zone", &name, true)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
|
||||
let space = Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
Zone::add_to(&node, space, &field);
|
||||
Zone::add_to(&node, space, field);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
create_interface!(SpatialInterface, SpatialInterfaceAspect, "/spatial");
|
||||
create_interface!(SpatialInterface);
|
||||
|
||||
@@ -1,166 +1,147 @@
|
||||
use super::{Spatial, ZoneAspect, ZONEABLE_REGISTRY};
|
||||
use super::{
|
||||
Spatial, ZoneAspect, SPATIAL_ASPECT_ALIAS_INFO, SPATIAL_REF_ASPECT_ALIAS_INFO,
|
||||
ZONEABLE_REGISTRY,
|
||||
};
|
||||
use crate::{
|
||||
core::{client::Client, registry::Registry},
|
||||
nodes::{
|
||||
alias::{Alias, AliasInfo},
|
||||
alias::{get_original, Alias, AliasList},
|
||||
fields::Field,
|
||||
Aspect, Node,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::vec3a;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
pub fn capture(spatial: &Arc<Spatial>, zone: &Arc<Zone>) {
|
||||
let old_distance = spatial.zone_distance();
|
||||
let new_distance = zone
|
||||
.field
|
||||
.upgrade()
|
||||
.map(|field| field.distance(spatial, vec3a(0.0, 0.0, 0.0)))
|
||||
.unwrap_or(f32::MAX);
|
||||
let new_distance = zone.field.distance(spatial, vec3a(0.0, 0.0, 0.0));
|
||||
if new_distance.abs() < old_distance.abs() {
|
||||
release(spatial);
|
||||
*spatial.old_parent.lock() = spatial.get_parent();
|
||||
*spatial.zone.lock() = Arc::downgrade(zone);
|
||||
zone.captured.add_raw(spatial);
|
||||
let Some(node) = zone.spatial.node.upgrade() else {
|
||||
let Some(zone_node) = zone.spatial.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let _ = super::zone_client::capture(&node, &spatial.uid);
|
||||
let Some(spatial_node) = spatial.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Ok(spatial_alias) = Alias::create(
|
||||
&spatial_node,
|
||||
&zone_node.get_client().unwrap(),
|
||||
SPATIAL_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&zone.captured),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
let _ = super::zone_client::capture(&zone_node, &spatial_alias);
|
||||
}
|
||||
}
|
||||
pub fn release(spatial: &Arc<Spatial>) {
|
||||
pub fn release(spatial: &Spatial) {
|
||||
let Some(spatial_node) = spatial.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let spatial = spatial_node.get_aspect::<Spatial>().unwrap();
|
||||
|
||||
let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take().as_ref());
|
||||
let mut spatial_zone = spatial.zone.lock();
|
||||
|
||||
if let Some(spatial_zone) = spatial_zone.upgrade() {
|
||||
spatial_zone.captured.remove_aspect(spatial.as_ref());
|
||||
let Some(node) = spatial_zone.spatial.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
spatial_zone.captured.remove(spatial);
|
||||
let _ = super::zone_client::release(&node, &spatial.uid);
|
||||
let _ = super::zone_client::release(&node, spatial_node.id);
|
||||
}
|
||||
*spatial_zone = Weak::new();
|
||||
}
|
||||
pub(super) fn release_drop(spatial: &Spatial) {
|
||||
let spatial_zone = spatial.zone.lock();
|
||||
if let Some(spatial_zone) = spatial_zone.upgrade() {
|
||||
let Some(node) = spatial_zone.spatial.node.upgrade() else {
|
||||
return;
|
||||
};
|
||||
spatial_zone.captured.remove(spatial);
|
||||
let _ = super::zone_client::release(&node, &spatial.uid);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Zone {
|
||||
spatial: Arc<Spatial>,
|
||||
pub field: Weak<Field>,
|
||||
zoneables: Mutex<FxHashMap<String, Arc<Node>>>,
|
||||
captured: Registry<Spatial>,
|
||||
pub field: Arc<Field>,
|
||||
intersecting_spatials: Registry<Spatial>,
|
||||
intersecting: AliasList,
|
||||
captured: AliasList,
|
||||
}
|
||||
impl Zone {
|
||||
pub fn add_to(node: &Arc<Node>, spatial: Arc<Spatial>, field: &Arc<Field>) -> Arc<Zone> {
|
||||
pub fn add_to(node: &Arc<Node>, spatial: Arc<Spatial>, field: Arc<Field>) -> Arc<Zone> {
|
||||
let zone = Arc::new(Zone {
|
||||
spatial,
|
||||
field: Arc::downgrade(field),
|
||||
zoneables: Mutex::new(FxHashMap::default()),
|
||||
captured: Registry::new(),
|
||||
field,
|
||||
intersecting_spatials: Registry::default(),
|
||||
intersecting: AliasList::default(),
|
||||
captured: AliasList::default(),
|
||||
});
|
||||
<Zone as ZoneAspect>::add_node_members(node);
|
||||
node.add_aspect_raw(zone.clone());
|
||||
zone
|
||||
}
|
||||
pub fn update(&self) -> Result<()> {
|
||||
let node = self.spatial.node().unwrap();
|
||||
|
||||
let current_zoneables = Registry::new();
|
||||
for zoneable in ZONEABLE_REGISTRY.get_valid_contents() {
|
||||
let distance = self.field.distance(&zoneable, [0.0; 3].into());
|
||||
if distance > 0.0 {
|
||||
continue;
|
||||
}
|
||||
if let Some(zone) = zoneable.zone.lock().upgrade() {
|
||||
let zoneable_distance = zone.field.distance(&zoneable, [0.0; 3].into());
|
||||
if zoneable_distance < distance {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
current_zoneables.add_raw(&zoneable);
|
||||
}
|
||||
|
||||
let (added, removed) =
|
||||
Registry::get_changes(&self.intersecting_spatials, ¤t_zoneables);
|
||||
for added in added {
|
||||
let Some(added_node) = added.node() else {
|
||||
continue;
|
||||
};
|
||||
let Ok(alias) = Alias::create(
|
||||
&added_node,
|
||||
&self.spatial.node().unwrap().get_client().unwrap(),
|
||||
SPATIAL_REF_ASPECT_ALIAS_INFO.clone(),
|
||||
Some(&self.intersecting),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
let _ = super::zone_client::enter(&node, &alias);
|
||||
}
|
||||
for removed in removed {
|
||||
let Some(removed_node) = removed.node() else {
|
||||
continue;
|
||||
};
|
||||
release(&removed);
|
||||
let _ = super::zone_client::leave(&node, removed_node.id);
|
||||
self.intersecting.remove_aspect(removed.as_ref());
|
||||
}
|
||||
self.intersecting_spatials.set(¤t_zoneables);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Aspect for Zone {
|
||||
const NAME: &'static str = "Zone";
|
||||
}
|
||||
impl ZoneAspect for Zone {
|
||||
fn update(node: Arc<Node>, _calling_client: Arc<Client>) -> color_eyre::eyre::Result<()> {
|
||||
fn update(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
|
||||
let zone = node.get_aspect::<Zone>()?;
|
||||
let Some(field) = zone.field.upgrade() else {
|
||||
return Err(color_eyre::eyre::eyre!("Zone's field has been destroyed"));
|
||||
};
|
||||
let Some((zone_client, zone_node)) = zone
|
||||
.spatial
|
||||
.node
|
||||
.upgrade()
|
||||
.and_then(|n| n.get_client().zip(Some(n)))
|
||||
else {
|
||||
return Err(color_eyre::eyre::eyre!("No client on node?"));
|
||||
};
|
||||
let mut old_zoneables = zone.zoneables.lock();
|
||||
for (_uid, zoneable) in old_zoneables.iter() {
|
||||
zoneable.destroy();
|
||||
}
|
||||
let captured = zone.captured.get_valid_contents();
|
||||
let zoneables = ZONEABLE_REGISTRY
|
||||
.get_valid_contents()
|
||||
.into_iter()
|
||||
.filter(|zoneable| zoneable.node.upgrade().is_some())
|
||||
.filter(|zoneable| {
|
||||
if captured
|
||||
.iter()
|
||||
.any(|captured| Arc::ptr_eq(captured, zoneable))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
let spatial_zone_distance = zoneable.zone_distance();
|
||||
let self_zone_distance = field.distance(zoneable, vec3a(0.0, 0.0, 0.0));
|
||||
self_zone_distance < 0.0 && spatial_zone_distance > self_zone_distance
|
||||
})
|
||||
.filter_map(|zoneable| {
|
||||
let alias = Alias::create(
|
||||
&zone_client,
|
||||
zone_node.get_path(),
|
||||
&zoneable.uid,
|
||||
&zoneable.node.upgrade().unwrap(),
|
||||
AliasInfo {
|
||||
server_signals: vec![
|
||||
"set_transform",
|
||||
"set_spatial_parent",
|
||||
"set_spatial_parent_in_place",
|
||||
],
|
||||
server_methods: vec!["get_bounds", "get_transform"],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.ok()?;
|
||||
Some((zoneable.uid.clone(), alias))
|
||||
})
|
||||
.collect::<FxHashMap<String, Arc<Node>>>();
|
||||
|
||||
for (uid, zoneable) in zoneables
|
||||
.iter()
|
||||
.filter(|(k, _)| !old_zoneables.contains_key(*k))
|
||||
{
|
||||
super::zone_client::enter(&node, uid, zoneable)?;
|
||||
}
|
||||
for left_uid in old_zoneables.keys().filter(|k| !zoneables.contains_key(*k)) {
|
||||
super::zone_client::leave(&node, &left_uid)?;
|
||||
}
|
||||
|
||||
*old_zoneables = zoneables;
|
||||
|
||||
let _ = zone.update();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn capture(
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
spatial: Arc<Node>,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
fn capture(node: Arc<Node>, _calling_client: Arc<Client>, spatial: Arc<Node>) -> Result<()> {
|
||||
let zone = node.get_aspect::<Zone>()?;
|
||||
let spatial = spatial.get_aspect()?;
|
||||
capture(&spatial, &zone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release(
|
||||
_node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
spatial: Arc<Node>,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
fn release(_node: Arc<Node>, _calling_client: Arc<Client>, spatial: Arc<Node>) -> Result<()> {
|
||||
let spatial = spatial.get_aspect()?;
|
||||
release(&spatial);
|
||||
Ok(())
|
||||
@@ -168,7 +149,13 @@ impl ZoneAspect for Zone {
|
||||
}
|
||||
impl Drop for Zone {
|
||||
fn drop(&mut self) {
|
||||
for captured in self.captured.get_valid_contents() {
|
||||
for captured in self
|
||||
.captured
|
||||
.get_aliases()
|
||||
.into_iter()
|
||||
.filter_map(get_original)
|
||||
.filter_map(|n| n.get_aspect::<Spatial>().ok())
|
||||
{
|
||||
release(&captured);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use crate::{
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{vec3, Mat4};
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::Arc;
|
||||
@@ -34,8 +33,7 @@ pub struct EyePointer {
|
||||
}
|
||||
impl EyePointer {
|
||||
pub fn new() -> Result<Self> {
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
let pointer = InputMethod::add_to(
|
||||
&node,
|
||||
@@ -62,7 +60,7 @@ impl EyePointer {
|
||||
.into_iter()
|
||||
// filter out all the disabled handlers
|
||||
.filter(|handler| {
|
||||
let Some(node) = handler.node.upgrade() else {
|
||||
let Some(node) = handler.spatial.node() else {
|
||||
return false;
|
||||
};
|
||||
node.enabled()
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
data::{
|
||||
mask_matches, pulse_receiver_client, PulseSender, KEYMAPS, PULSE_RECEIVER_REGISTRY,
|
||||
},
|
||||
fields::{Field, Ray},
|
||||
fields::Ray,
|
||||
input::{InputDataType, InputHandler, InputMethod, Pointer, INPUT_HANDLER_REGISTRY},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
@@ -13,8 +13,8 @@ use crate::{
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{vec3, Mat4, Vec3};
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slotmap::DefaultKey;
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::Arc;
|
||||
use stereokit_rust::system::{Input, Key};
|
||||
@@ -62,8 +62,10 @@ impl Default for KeyboardEvent {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct MousePointer {
|
||||
node: Arc<Node>,
|
||||
keymap: DefaultKey,
|
||||
spatial: Arc<Spatial>,
|
||||
pointer: Arc<InputMethod>,
|
||||
capture: Option<Arc<InputHandler>>,
|
||||
@@ -73,8 +75,7 @@ pub struct MousePointer {
|
||||
}
|
||||
impl MousePointer {
|
||||
pub fn new() -> Result<Self> {
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
let pointer = InputMethod::add_to(
|
||||
&node,
|
||||
@@ -82,8 +83,7 @@ impl MousePointer {
|
||||
Datamap::from_typed(MouseEvent::default())?,
|
||||
)?;
|
||||
|
||||
KEYMAPS.lock().insert(
|
||||
"flatscreen".to_string(),
|
||||
let keymap = KEYMAPS.lock().insert(
|
||||
Keymap::new_from_names(&Context::new(0), "evdev", "", "", "", None, 0)
|
||||
.unwrap()
|
||||
.get_as_string(FORMAT_TEXT_V1),
|
||||
@@ -97,6 +97,7 @@ impl MousePointer {
|
||||
|
||||
Ok(MousePointer {
|
||||
node,
|
||||
keymap,
|
||||
spatial,
|
||||
pointer,
|
||||
capture: None,
|
||||
@@ -206,7 +207,7 @@ impl MousePointer {
|
||||
.into_iter()
|
||||
// filter out all the disabled handlers
|
||||
.filter(|handler| {
|
||||
let Some(node) = handler.node.upgrade() else {
|
||||
let Some(node) = handler.spatial.node() else {
|
||||
return false;
|
||||
};
|
||||
node.enabled()
|
||||
@@ -253,7 +254,7 @@ impl MousePointer {
|
||||
.into_iter()
|
||||
.filter(|rx| mask_matches(&rx.mask, &self.keyboard_sender.mask))
|
||||
.map(|rx| {
|
||||
let result = rx.field_node.get_aspect::<Field>().unwrap().ray_march(Ray {
|
||||
let result = rx.field.ray_march(Ray {
|
||||
origin: vec3(0.0, 0.0, 0.0),
|
||||
direction: vec3(0.0, 0.0, -1.0),
|
||||
space: self.spatial.clone(),
|
||||
@@ -291,7 +292,7 @@ impl MousePointer {
|
||||
if !self.keyboard_datamap.keys.is_empty() {
|
||||
pulse_receiver_client::data(
|
||||
&rx.node.upgrade().unwrap(),
|
||||
&self.node.uid,
|
||||
&self.node,
|
||||
&Datamap::from_typed(&self.keyboard_datamap).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -34,17 +34,7 @@ pub struct SkController {
|
||||
}
|
||||
impl SkController {
|
||||
pub fn new(handed: Handed) -> Result<Self> {
|
||||
let _node = Node::create_parent_name(
|
||||
&INTERNAL_CLIENT,
|
||||
"",
|
||||
if handed == Handed::Left {
|
||||
"controller_left"
|
||||
} else {
|
||||
"controller_right"
|
||||
},
|
||||
false,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
let _node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
|
||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
||||
let model = Model::from_memory("cursor.glb", include_bytes!("cursor.glb"), None)?;
|
||||
let tip = InputDataType::Tip(Tip::default());
|
||||
@@ -135,7 +125,7 @@ impl SkController {
|
||||
.into_iter()
|
||||
// filter out all the disabled handlers
|
||||
.filter(|handler| {
|
||||
let Some(node) = handler.node.upgrade() else {
|
||||
let Some(node) = handler.spatial.node() else {
|
||||
return false;
|
||||
};
|
||||
node.enabled()
|
||||
|
||||
@@ -8,7 +8,6 @@ use crate::nodes::{
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{Mat4, Quat, Vec3};
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::f32::INFINITY;
|
||||
@@ -41,8 +40,7 @@ pub struct SkHand {
|
||||
}
|
||||
impl SkHand {
|
||||
pub fn new(handed: Handed) -> Result<Self> {
|
||||
let _node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
let _node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
|
||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
||||
let hand = InputDataType::Hand(Hand {
|
||||
right: handed == Handed::Right,
|
||||
@@ -156,7 +154,7 @@ impl SkHand {
|
||||
.into_iter()
|
||||
// filter out all the disabled handlers
|
||||
.filter(|handler| {
|
||||
let Some(node) = handler.node.upgrade() else {
|
||||
let Some(node) = handler.spatial.node() else {
|
||||
return false;
|
||||
};
|
||||
node.enabled()
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::sync::Arc;
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Datamap;
|
||||
use stereokit_rust::system::World;
|
||||
@@ -40,15 +39,14 @@ pub struct PlaySpace {
|
||||
}
|
||||
impl PlaySpace {
|
||||
pub fn new() -> Result<Self> {
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||
.add_to_scenegraph()?;
|
||||
let node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
BoxField::add_to(&node, [0.0; 3].into());
|
||||
let field = node.get_aspect::<Field>()?.clone();
|
||||
|
||||
let pulse_rx = PulseReceiver::add_to(
|
||||
&node,
|
||||
node.clone(),
|
||||
field.clone(),
|
||||
Datamap::from_typed(PlaySpaceMap::default())?,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::{
|
||||
use mint::Vector2;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use slotmap::KeyData;
|
||||
use smithay::{
|
||||
backend::input::{AxisRelativeDirection, ButtonState, KeyState},
|
||||
delegate_seat,
|
||||
@@ -212,7 +213,7 @@ impl SeatWrapper {
|
||||
pointer.frame(&mut state);
|
||||
}
|
||||
|
||||
pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: &str, keys: Vec<i32>) {
|
||||
pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: u64, keys: Vec<i32>) {
|
||||
let Some(state) = self.wayland_state.upgrade() else {
|
||||
return;
|
||||
};
|
||||
@@ -220,7 +221,7 @@ impl SeatWrapper {
|
||||
return;
|
||||
};
|
||||
let keymaps = KEYMAPS.lock();
|
||||
let Some(keymap) = keymaps.get(keymap_id).cloned() else {
|
||||
let Some(keymap) = keymaps.get(KeyData::from_ffi(keymap_id).into()).cloned() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::nodes::{
|
||||
use color_eyre::eyre::Result;
|
||||
use mint::Vector2;
|
||||
use parking_lot::Mutex;
|
||||
use rand::Rng;
|
||||
use rustc_hash::FxHashMap;
|
||||
use smithay::{
|
||||
delegate_xdg_shell,
|
||||
@@ -184,7 +185,7 @@ impl XdgShellHandler for WaylandState {
|
||||
}
|
||||
|
||||
fn new_popup(&mut self, popup: PopupSurface, positioner: PositionerState) {
|
||||
let uid = nanoid::nanoid!();
|
||||
let uid = rand::thread_rng().gen_range(0..u64::MAX);
|
||||
let Some(parent) = popup.get_parent_surface() else {
|
||||
return;
|
||||
};
|
||||
@@ -194,8 +195,8 @@ impl XdgShellHandler for WaylandState {
|
||||
if popup.send_configure().is_err() {
|
||||
return;
|
||||
}
|
||||
utils::insert_data(popup.wl_surface(), SurfaceId::Child(uid.clone()));
|
||||
utils::insert_data(popup.wl_surface(), uid.clone());
|
||||
utils::insert_data(popup.wl_surface(), SurfaceId::Child(uid));
|
||||
utils::insert_data(popup.wl_surface(), uid);
|
||||
utils::insert_data(popup.wl_surface(), Arc::downgrade(&panel_item));
|
||||
CoreSurface::add_to(
|
||||
self.display_handle.clone(),
|
||||
@@ -203,9 +204,7 @@ impl XdgShellHandler for WaylandState {
|
||||
{
|
||||
let popup = popup.clone();
|
||||
move || {
|
||||
panel_item
|
||||
.backend
|
||||
.new_popup(&uid, popup.clone(), positioner);
|
||||
panel_item.backend.new_popup(uid, popup.clone(), positioner);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -228,14 +227,14 @@ impl XdgShellHandler for WaylandState {
|
||||
let Some(panel_item) = surface_panel_item(popup.wl_surface()) else {
|
||||
return;
|
||||
};
|
||||
let Some(uid) = utils::get_data::<String>(popup.wl_surface())
|
||||
let Some(SurfaceId::Child(uid)) = utils::get_data::<SurfaceId>(popup.wl_surface())
|
||||
.as_deref()
|
||||
.cloned()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
panel_item.backend.reposition_popup(&uid, popup, positioner)
|
||||
panel_item.backend.reposition_popup(uid, popup, positioner)
|
||||
}
|
||||
fn popup_destroyed(&mut self, popup: PopupSurface) {
|
||||
if let Some(core_surface) = CoreSurface::from_wl_surface(popup.wl_surface()) {
|
||||
@@ -244,14 +243,14 @@ impl XdgShellHandler for WaylandState {
|
||||
let Some(panel_item) = surface_panel_item(popup.wl_surface()) else {
|
||||
return;
|
||||
};
|
||||
let Some(uid) = utils::get_data::<String>(popup.wl_surface())
|
||||
let Some(SurfaceId::Child(uid)) = utils::get_data::<SurfaceId>(popup.wl_surface())
|
||||
.as_deref()
|
||||
.cloned()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
panel_item.backend.seat.unfocus(popup.wl_surface(), self);
|
||||
panel_item.backend.drop_popup(&uid);
|
||||
panel_item.backend.drop_popup(uid);
|
||||
}
|
||||
|
||||
fn grab(&mut self, _popup: PopupSurface, _seat: WlSeat, _serial: Serial) {}
|
||||
@@ -330,7 +329,7 @@ delegate_xdg_shell!(WaylandState);
|
||||
|
||||
pub struct XdgBackend {
|
||||
toplevel: Mutex<Option<ToplevelSurface>>,
|
||||
popups: Mutex<FxHashMap<String, (PopupSurface, PositionerState)>>,
|
||||
popups: Mutex<FxHashMap<u64, (PopupSurface, PositionerState)>>,
|
||||
pub seat: Arc<SeatWrapper>,
|
||||
}
|
||||
impl XdgBackend {
|
||||
@@ -354,20 +353,18 @@ impl XdgBackend {
|
||||
surface_panel_item(self.toplevel.lock().clone()?.wl_surface())
|
||||
}
|
||||
|
||||
pub fn new_popup(&self, uid: &str, popup: PopupSurface, positioner: PositionerState) {
|
||||
pub fn new_popup(&self, id: u64, popup: PopupSurface, positioner: PositionerState) {
|
||||
let Some(panel_item) = self.panel_item() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.popups
|
||||
.lock()
|
||||
.insert(uid.to_string(), (popup, positioner));
|
||||
self.popups.lock().insert(id, (popup, positioner));
|
||||
|
||||
panel_item.create_child(uid, self.child_data(uid).unwrap());
|
||||
panel_item.create_child(id, &self.child_data(id).unwrap());
|
||||
}
|
||||
pub fn reposition_popup(&self, uid: &str, _popup: PopupSurface, positioner: PositionerState) {
|
||||
pub fn reposition_popup(&self, id: u64, _popup: PopupSurface, positioner: PositionerState) {
|
||||
let mut popups = self.popups.lock();
|
||||
let Some((_, old_positioner)) = popups.get_mut(uid) else {
|
||||
let Some((_, old_positioner)) = popups.get_mut(&id) else {
|
||||
return;
|
||||
};
|
||||
let Some(panel_item) = self.panel_item() else {
|
||||
@@ -376,18 +373,19 @@ impl XdgBackend {
|
||||
let geometry = positioner.get_geometry();
|
||||
|
||||
*old_positioner = positioner;
|
||||
panel_item.reposition_child(uid, geometry.into());
|
||||
panel_item.reposition_child(id, &geometry.into());
|
||||
}
|
||||
pub fn drop_popup(&self, uid: &str) {
|
||||
pub fn drop_popup(&self, id: u64) {
|
||||
let Some(panel_item) = self.panel_item() else {
|
||||
return;
|
||||
};
|
||||
panel_item.destroy_child(uid);
|
||||
panel_item.destroy_child(id);
|
||||
}
|
||||
|
||||
fn child_data(&self, uid: &str) -> Option<ChildInfo> {
|
||||
let (popup, positioner) = self.popups.lock().get(uid)?.clone();
|
||||
fn child_data(&self, id: u64) -> Option<ChildInfo> {
|
||||
let (popup, positioner) = self.popups.lock().get(&id)?.clone();
|
||||
Some(ChildInfo {
|
||||
id,
|
||||
parent: (*utils::get_data::<SurfaceId>(&popup.get_parent_surface()?)?).clone(),
|
||||
geometry: positioner.get_geometry().into(),
|
||||
})
|
||||
@@ -443,12 +441,14 @@ impl Backend for XdgBackend {
|
||||
.map(|s| Vector2::from([s.w as u32, s.h as u32]))
|
||||
.or_else(|| toplevel_core_surface.size())
|
||||
.unwrap_or(Vector2::from([0; 2]));
|
||||
let parent = toplevel
|
||||
.parent()
|
||||
.as_ref()
|
||||
.and_then(surface_panel_item)
|
||||
.and_then(|p| p.node.upgrade())
|
||||
.map(|p| p.get_id());
|
||||
let toplevel = ToplevelInfo {
|
||||
parent: toplevel
|
||||
.parent()
|
||||
.as_ref()
|
||||
.and_then(surface_panel_item)
|
||||
.map(|p| p.uid.clone()),
|
||||
parent,
|
||||
title,
|
||||
app_id,
|
||||
size,
|
||||
@@ -491,7 +491,7 @@ impl Backend for XdgBackend {
|
||||
.popups
|
||||
.lock()
|
||||
.keys()
|
||||
.map(|k| (k.clone(), self.child_data(k).unwrap()))
|
||||
.map(|k| self.child_data(*k).unwrap())
|
||||
.collect();
|
||||
|
||||
Ok(PanelItemInitData {
|
||||
@@ -588,7 +588,7 @@ impl Backend for XdgBackend {
|
||||
self.seat.pointer_scroll(scroll_distance, scroll_steps)
|
||||
}
|
||||
|
||||
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>) {
|
||||
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec<i32>) {
|
||||
let Some(surface) = self.wl_surface_from_id(&surface) else {
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user