feat: zones
This commit is contained in:
@@ -253,7 +253,7 @@ pub fn create_pulse_sender_flex(
|
|||||||
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
let transform = parse_transform(info.transform, true, true, false)?;
|
let transform = parse_transform(info.transform, true, true, false)?;
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
PulseSender::add_to(&node)?;
|
PulseSender::add_to(&node)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -287,7 +287,7 @@ pub fn create_pulse_receiver_flex(
|
|||||||
let field = find_field(&calling_client, info.field_path)?;
|
let field = find_field(&calling_client, info.field_path)?;
|
||||||
|
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
PulseReceiver::add_to(&node, field)?;
|
PulseReceiver::add_to(&node, field)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Re
|
|||||||
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
let transform = parse_transform(info.transform, true, true, true)?;
|
let transform = parse_transform(info.transform, true, true, true)?;
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
Model::add_to(&node, info.resource)?;
|
Model::add_to(&node, info.resource)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Re
|
|||||||
let color = Rgba::from_slice(&info.color);
|
let color = Rgba::from_slice(&info.color);
|
||||||
|
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
Text::add_to(
|
Text::add_to(
|
||||||
&node,
|
&node,
|
||||||
info.font_resource,
|
info.font_resource,
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ pub fn create_box_field_flex(_node: &Node, calling_client: Arc<Client>, data: &[
|
|||||||
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
let transform = parse_transform(info.transform, true, true, false)?;
|
let transform = parse_transform(info.transform, true, true, false)?;
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
BoxField::add_to(&node, info.size)?;
|
BoxField::add_to(&node, info.size)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ pub fn create_cylinder_field_flex(
|
|||||||
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
let transform = parse_transform(info.transform, true, true, false)?;
|
let transform = parse_transform(info.transform, true, true, false)?;
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
CylinderField::add_to(&node, dbg!(info.length), dbg!(info.radius))?;
|
CylinderField::add_to(&node, dbg!(info.length), dbg!(info.radius))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ pub fn create_sphere_field_flex(
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
SphereField::add_to(&node, info.radius)?;
|
SphereField::add_to(&node, info.radius)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ lazy_static::lazy_static! {
|
|||||||
|
|
||||||
fn create() -> Arc<Node> {
|
fn create() -> Arc<Node> {
|
||||||
let node = Arc::new(Node::create(&INTERNAL_CLIENT, "", "hmd", false));
|
let node = Arc::new(Node::create(&INTERNAL_CLIENT, "", "hmd", false));
|
||||||
Spatial::add_to(&node, None, Mat4::IDENTITY).unwrap();
|
Spatial::add_to(&node, None, Mat4::IDENTITY, false).unwrap();
|
||||||
|
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ pub fn create_input_handler_flex(
|
|||||||
let field = find_field(&calling_client, info.field_path)?;
|
let field = find_field(&calling_client, info.field_path)?;
|
||||||
|
|
||||||
let node = Node::create(&calling_client, "/input/handler", info.name, true).add_to_scenegraph();
|
let node = Node::create(&calling_client, "/input/handler", info.name, true).add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
InputHandler::add_to(&node, &field)?;
|
InputHandler::add_to(&node, &field)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ pub fn create_tip_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -
|
|||||||
let transform = parse_transform(info.transform, true, true, false)?;
|
let transform = parse_transform(info.transform, true, true, false)?;
|
||||||
|
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
InputMethod::add_to(
|
InputMethod::add_to(
|
||||||
&node,
|
&node,
|
||||||
InputType::Tip(Tip {
|
InputType::Tip(Tip {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub(super) fn create_environment_item_flex(
|
|||||||
let space = find_spatial_parent(&calling_client, info.parent_path)?;
|
let space = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
let transform = parse_transform(info.transform, true, true, false)?;
|
let transform = parse_transform(info.transform, true, true, false)?;
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, None, transform * space.global_transform())?;
|
Spatial::add_to(&node, None, transform * space.global_transform(), false)?;
|
||||||
EnvironmentItem::add_to(&node, info.item_data);
|
EnvironmentItem::add_to(&node, info.item_data);
|
||||||
node.item
|
node.item
|
||||||
.get()
|
.get()
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ pub(self) fn create_item_acceptor_flex(
|
|||||||
let field = find_field(&calling_client, info.field_path)?;
|
let field = find_field(&calling_client, info.field_path)?;
|
||||||
|
|
||||||
let node = Node::create(&INTERNAL_CLIENT, &parent_name, info.name, true).add_to_scenegraph();
|
let node = Node::create(&INTERNAL_CLIENT, &parent_name, info.name, true).add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(space), transform)?;
|
Spatial::add_to(&node, Some(space), transform, false)?;
|
||||||
ItemAcceptor::add_to(&node, type_info, Arc::downgrade(&field));
|
ItemAcceptor::add_to(&node, type_info, Arc::downgrade(&field));
|
||||||
node.item
|
node.item
|
||||||
.get()
|
.get()
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use self::drawable::text::Text;
|
|||||||
use self::fields::Field;
|
use self::fields::Field;
|
||||||
use self::input::{InputHandler, InputMethod};
|
use self::input::{InputHandler, InputMethod};
|
||||||
use self::items::{Item, ItemAcceptor, ItemUI};
|
use self::items::{Item, ItemAcceptor, ItemUI};
|
||||||
|
use self::spatial::zone::Zone;
|
||||||
use self::spatial::Spatial;
|
use self::spatial::Spatial;
|
||||||
use self::startup::StartupSettings;
|
use self::startup::StartupSettings;
|
||||||
|
|
||||||
@@ -52,6 +53,7 @@ pub struct Node {
|
|||||||
|
|
||||||
pub spatial: OnceCell<Arc<Spatial>>,
|
pub spatial: OnceCell<Arc<Spatial>>,
|
||||||
pub field: OnceCell<Arc<Field>>,
|
pub field: OnceCell<Arc<Field>>,
|
||||||
|
pub zone: OnceCell<Arc<Zone>>,
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
pub pulse_sender: OnceCell<Arc<PulseSender>>,
|
pub pulse_sender: OnceCell<Arc<PulseSender>>,
|
||||||
@@ -108,6 +110,7 @@ impl Node {
|
|||||||
|
|
||||||
spatial: OnceCell::new(),
|
spatial: OnceCell::new(),
|
||||||
field: OnceCell::new(),
|
field: OnceCell::new(),
|
||||||
|
zone: OnceCell::new(),
|
||||||
pulse_sender: OnceCell::new(),
|
pulse_sender: OnceCell::new(),
|
||||||
pulse_receiver: OnceCell::new(),
|
pulse_receiver: OnceCell::new(),
|
||||||
model: OnceCell::new(),
|
model: OnceCell::new(),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ impl Root {
|
|||||||
node.add_local_signal("subscribeLogicStep", Root::subscribe_logic_step);
|
node.add_local_signal("subscribeLogicStep", Root::subscribe_logic_step);
|
||||||
node.add_local_signal("setBasePrefixes", Root::set_base_prefixes);
|
node.add_local_signal("setBasePrefixes", Root::set_base_prefixes);
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
let _ = Spatial::add_to(&node, None, Mat4::IDENTITY);
|
let _ = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||||
|
|
||||||
ROOT_REGISTRY.add(Root {
|
ROOT_REGISTRY.add(Root {
|
||||||
node,
|
node,
|
||||||
|
|||||||
@@ -1,43 +1,59 @@
|
|||||||
|
pub mod zone;
|
||||||
|
|
||||||
|
use self::zone::{create_zone_flex, Zone};
|
||||||
use super::Node;
|
use super::Node;
|
||||||
use crate::core::client::Client;
|
use crate::core::client::Client;
|
||||||
|
use crate::core::registry::Registry;
|
||||||
use anyhow::{anyhow, ensure, Result};
|
use anyhow::{anyhow, ensure, Result};
|
||||||
use glam::{Mat4, Quat};
|
use glam::{vec3a, Mat4, Quat};
|
||||||
use mint::Vector3;
|
use mint::Vector3;
|
||||||
|
use nanoid::nanoid;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||||
use stardust_xr::values::Transform;
|
use stardust_xr::values::Transform;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
|
static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
|
||||||
|
|
||||||
pub struct Spatial {
|
pub struct Spatial {
|
||||||
|
pub(self) uid: String,
|
||||||
pub(super) node: Weak<Node>,
|
pub(super) node: Weak<Node>,
|
||||||
parent: Mutex<Option<Arc<Spatial>>>,
|
parent: Mutex<Option<Arc<Spatial>>>,
|
||||||
|
pub(self) old_parent: Mutex<Option<Arc<Spatial>>>,
|
||||||
pub(super) transform: Mutex<Mat4>,
|
pub(super) transform: Mutex<Mat4>,
|
||||||
|
pub(self) zone: Mutex<Weak<Zone>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spatial {
|
impl Spatial {
|
||||||
pub fn new(node: Weak<Node>, parent: Option<Arc<Spatial>>, transform: Mat4) -> Arc<Self> {
|
pub fn new(node: Weak<Node>, parent: Option<Arc<Spatial>>, transform: Mat4) -> Arc<Self> {
|
||||||
Arc::new(Spatial {
|
Arc::new(Spatial {
|
||||||
|
uid: nanoid!(),
|
||||||
node,
|
node,
|
||||||
parent: Mutex::new(parent),
|
parent: Mutex::new(parent),
|
||||||
|
old_parent: Mutex::new(None),
|
||||||
transform: Mutex::new(transform),
|
transform: Mutex::new(transform),
|
||||||
|
zone: Mutex::new(Weak::new()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn add_to(
|
pub fn add_to(
|
||||||
node: &Arc<Node>,
|
node: &Arc<Node>,
|
||||||
parent: Option<Arc<Spatial>>,
|
parent: Option<Arc<Spatial>>,
|
||||||
transform: Mat4,
|
transform: Mat4,
|
||||||
|
zoneable: bool,
|
||||||
) -> Result<Arc<Spatial>> {
|
) -> Result<Arc<Spatial>> {
|
||||||
ensure!(
|
ensure!(
|
||||||
node.spatial.get().is_none(),
|
node.spatial.get().is_none(),
|
||||||
"Internal: Node already has a Spatial aspect!"
|
"Internal: Node already has a Spatial aspect!"
|
||||||
);
|
);
|
||||||
let spatial = Spatial {
|
let spatial = Spatial {
|
||||||
|
uid: nanoid!(),
|
||||||
node: Arc::downgrade(node),
|
node: Arc::downgrade(node),
|
||||||
parent: Mutex::new(parent),
|
parent: Mutex::new(parent),
|
||||||
|
old_parent: Mutex::new(None),
|
||||||
transform: Mutex::new(transform),
|
transform: Mutex::new(transform),
|
||||||
|
zone: Mutex::new(Weak::new()),
|
||||||
};
|
};
|
||||||
node.add_local_method("getTransform", Spatial::get_transform_flex);
|
node.add_local_method("getTransform", Spatial::get_transform_flex);
|
||||||
node.add_local_signal("setTransform", Spatial::set_transform_flex);
|
node.add_local_signal("setTransform", Spatial::set_transform_flex);
|
||||||
@@ -46,7 +62,11 @@ impl Spatial {
|
|||||||
"setSpatialParentInPlace",
|
"setSpatialParentInPlace",
|
||||||
Spatial::set_spatial_parent_in_place_flex,
|
Spatial::set_spatial_parent_in_place_flex,
|
||||||
);
|
);
|
||||||
|
node.add_local_signal("setZoneable", Spatial::set_zoneable);
|
||||||
let spatial_arc = Arc::new(spatial);
|
let spatial_arc = Arc::new(spatial);
|
||||||
|
if zoneable {
|
||||||
|
ZONEABLE_REGISTRY.add_raw(&spatial_arc);
|
||||||
|
}
|
||||||
let _ = node.spatial.set(spatial_arc.clone());
|
let _ = node.spatial.set(spatial_arc.clone());
|
||||||
Ok(spatial_arc)
|
Ok(spatial_arc)
|
||||||
}
|
}
|
||||||
@@ -217,6 +237,32 @@ impl Spatial {
|
|||||||
.set_spatial_parent_in_place(Some(&parent))?;
|
.set_spatial_parent_in_place(Some(&parent))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
pub fn set_zoneable(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||||
|
let zoneable: bool = deserialize(data)?;
|
||||||
|
let spatial = node.spatial.get().unwrap();
|
||||||
|
if zoneable {
|
||||||
|
ZONEABLE_REGISTRY.add_raw(spatial);
|
||||||
|
} else {
|
||||||
|
ZONEABLE_REGISTRY.remove(spatial);
|
||||||
|
zone::release(spatial);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(self) fn zone_distance(&self) -> f32 {
|
||||||
|
self.zone
|
||||||
|
.lock()
|
||||||
|
.upgrade()
|
||||||
|
.and_then(|zone| zone.field.upgrade())
|
||||||
|
.map(|field| field.distance(self, vec3a(0.0, 0.0, 0.0)))
|
||||||
|
.unwrap_or(f32::MAX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Drop for Spatial {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
ZONEABLE_REGISTRY.remove(self);
|
||||||
|
zone::release(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_transform(
|
pub fn parse_transform(
|
||||||
@@ -271,6 +317,7 @@ pub fn find_reference_space(
|
|||||||
pub fn create_interface(client: &Arc<Client>) {
|
pub fn create_interface(client: &Arc<Client>) {
|
||||||
let node = Node::create(client, "", "spatial", false);
|
let node = Node::create(client, "", "spatial", false);
|
||||||
node.add_local_signal("createSpatial", create_spatial_flex);
|
node.add_local_signal("createSpatial", create_spatial_flex);
|
||||||
|
node.add_local_signal("createZone", create_zone_flex);
|
||||||
node.add_to_scenegraph();
|
node.add_to_scenegraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,12 +327,13 @@ pub fn create_spatial_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8
|
|||||||
name: &'a str,
|
name: &'a str,
|
||||||
parent_path: &'a str,
|
parent_path: &'a str,
|
||||||
transform: Transform,
|
transform: Transform,
|
||||||
|
zoneable: bool,
|
||||||
}
|
}
|
||||||
let info: CreateSpatialInfo = deserialize(data)?;
|
let info: CreateSpatialInfo = deserialize(data)?;
|
||||||
let node = Node::create(&calling_client, "/spatial/spatial", info.name, true);
|
let node = Node::create(&calling_client, "/spatial/spatial", info.name, true);
|
||||||
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
let transform = parse_transform(info.transform, true, true, true)?;
|
let transform = parse_transform(info.transform, true, true, true)?;
|
||||||
let node = node.add_to_scenegraph();
|
let node = node.add_to_scenegraph();
|
||||||
Spatial::add_to(&node, Some(parent), transform)?;
|
Spatial::add_to(&node, Some(parent), transform, info.zoneable)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
176
src/nodes/spatial/zone.rs
Normal file
176
src/nodes/spatial/zone.rs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
use super::{find_spatial, Spatial, ZONEABLE_REGISTRY};
|
||||||
|
use crate::{
|
||||||
|
core::{client::Client, registry::Registry},
|
||||||
|
nodes::{
|
||||||
|
alias::{Alias, AliasInfo},
|
||||||
|
fields::{find_field, Field},
|
||||||
|
spatial::{find_spatial_parent, parse_transform},
|
||||||
|
Node,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use anyhow::Result;
|
||||||
|
use glam::vec3a;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use stardust_xr::{
|
||||||
|
schemas::flex::{deserialize, serialize},
|
||||||
|
values::Transform,
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
if new_distance.abs() < old_distance.abs() {
|
||||||
|
release(spatial);
|
||||||
|
*spatial.old_parent.lock() = spatial.parent.lock().clone();
|
||||||
|
*spatial.zone.lock() = Arc::downgrade(zone);
|
||||||
|
zone.captured.add_raw(spatial);
|
||||||
|
let node = zone.spatial.node.upgrade().unwrap();
|
||||||
|
let _ = node.send_remote_signal("capture", &serialize(&spatial.uid).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn release(spatial: &Spatial) {
|
||||||
|
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() {
|
||||||
|
let node = spatial_zone.spatial.node.upgrade().unwrap();
|
||||||
|
spatial_zone.captured.remove(spatial);
|
||||||
|
let _ = node.send_remote_signal("release", &serialize(&spatial.uid).unwrap());
|
||||||
|
}
|
||||||
|
*spatial_zone = Weak::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Zone {
|
||||||
|
spatial: Arc<Spatial>,
|
||||||
|
pub field: Weak<Field>,
|
||||||
|
zoneables: Mutex<FxHashMap<String, Arc<Node>>>,
|
||||||
|
captured: Registry<Spatial>,
|
||||||
|
}
|
||||||
|
impl 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(),
|
||||||
|
});
|
||||||
|
node.add_local_signal("capture", Zone::capture_flex);
|
||||||
|
node.add_local_signal("release", Zone::release_flex);
|
||||||
|
node.add_local_signal("update", Zone::update);
|
||||||
|
let _ = node.zone.set(zone.clone());
|
||||||
|
zone
|
||||||
|
}
|
||||||
|
fn capture_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||||
|
let zone = node.zone.get().unwrap();
|
||||||
|
let capture_uid: &str = deserialize(data)?;
|
||||||
|
let capture_path = node.path.clone() + "/" + capture_uid;
|
||||||
|
let spatial = find_spatial(&calling_client, "Spatial", &capture_path)?;
|
||||||
|
capture(&spatial, zone);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn release_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||||
|
let capture_uid: &str = deserialize(data)?;
|
||||||
|
let capture_path = node.path.clone() + "/" + capture_uid;
|
||||||
|
let spatial = find_spatial(&calling_client, "Spatial", &capture_path)?;
|
||||||
|
release(&spatial);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn update(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
|
||||||
|
let zone = node.zone.get().unwrap();
|
||||||
|
if let Some(field) = zone.field.upgrade() {
|
||||||
|
if let Some((zone_client, zone_node)) = zone
|
||||||
|
.spatial
|
||||||
|
.node
|
||||||
|
.upgrade()
|
||||||
|
.and_then(|n| n.get_client().zip(Some(n)))
|
||||||
|
{
|
||||||
|
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
|
||||||
|
})
|
||||||
|
.map(|zoneable| {
|
||||||
|
let alias = Alias::new(
|
||||||
|
&zone_client,
|
||||||
|
zone_node.get_path(),
|
||||||
|
&zoneable.uid,
|
||||||
|
&zoneable.node.upgrade().unwrap(),
|
||||||
|
AliasInfo {
|
||||||
|
local_signals: vec![
|
||||||
|
"setTransform",
|
||||||
|
"setSpatialParent",
|
||||||
|
"setSpatialParentInPlace",
|
||||||
|
],
|
||||||
|
local_methods: vec!["getTransform"],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
(zoneable.uid.clone(), alias)
|
||||||
|
})
|
||||||
|
.collect::<FxHashMap<String, Arc<Node>>>();
|
||||||
|
|
||||||
|
for entered_uid in zoneables.keys().filter(|k| !old_zoneables.contains_key(*k)) {
|
||||||
|
node.send_remote_signal("enter", &serialize(entered_uid)?)?;
|
||||||
|
}
|
||||||
|
for left_uid in old_zoneables.keys().filter(|k| !zoneables.contains_key(*k)) {
|
||||||
|
node.send_remote_signal("leave", &serialize(left_uid)?)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
*old_zoneables = zoneables;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("No client on node?"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("Zone's field has been destroyed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Drop for Zone {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for captured in self.captured.get_valid_contents() {
|
||||||
|
release(&captured);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_zone_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CreateZoneInfo<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
parent_path: &'a str,
|
||||||
|
transform: Transform,
|
||||||
|
field_path: &'a str,
|
||||||
|
}
|
||||||
|
let info: CreateZoneInfo = deserialize(data)?;
|
||||||
|
let parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
|
let transform = parse_transform(info.transform, true, true, false)?;
|
||||||
|
let field = find_field(&calling_client, info.field_path)?;
|
||||||
|
|
||||||
|
let node = Node::create(&calling_client, "/spatial/zone", info.name, true).add_to_scenegraph();
|
||||||
|
let space = Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||||
|
Zone::add_to(&node, space, &field);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -66,7 +66,7 @@ impl PanelItem {
|
|||||||
&nanoid!(),
|
&nanoid!(),
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
Spatial::add_to(&node, None, Mat4::IDENTITY).unwrap();
|
Spatial::add_to(&node, None, Mat4::IDENTITY, false).unwrap();
|
||||||
|
|
||||||
let specialization = ItemType::Panel(PanelItem {
|
let specialization = ItemType::Panel(PanelItem {
|
||||||
node: Arc::downgrade(&node),
|
node: Arc::downgrade(&node),
|
||||||
|
|||||||
Reference in New Issue
Block a user