refactor: use typemap for aspects!
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
pub mod zone;
|
||||
|
||||
use self::zone::Zone;
|
||||
use super::fields::get_field;
|
||||
use super::Node;
|
||||
use super::fields::Field;
|
||||
use super::{Aspect, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::create_interface;
|
||||
use color_eyre::eyre::{ensure, eyre, Result};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use glam::{vec3a, Mat4, Quat};
|
||||
use mint::Vector3;
|
||||
use nanoid::nanoid;
|
||||
@@ -42,7 +42,6 @@ static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
|
||||
pub struct Spatial {
|
||||
uid: String,
|
||||
pub(super) node: Weak<Node>,
|
||||
self_ref: Weak<Spatial>,
|
||||
parent: Mutex<Option<Arc<Spatial>>>,
|
||||
old_parent: Mutex<Option<Arc<Spatial>>>,
|
||||
pub(super) transform: Mutex<Mat4>,
|
||||
@@ -53,10 +52,9 @@ pub struct Spatial {
|
||||
|
||||
impl Spatial {
|
||||
pub fn new(node: Weak<Node>, parent: Option<Arc<Spatial>>, transform: Mat4) -> Arc<Self> {
|
||||
Arc::new_cyclic(|self_ref| Spatial {
|
||||
Arc::new(Spatial {
|
||||
uid: nanoid!(),
|
||||
node,
|
||||
self_ref: self_ref.clone(),
|
||||
parent: Mutex::new(parent),
|
||||
old_parent: Mutex::new(None),
|
||||
transform: Mutex::new(transform),
|
||||
@@ -70,11 +68,7 @@ impl Spatial {
|
||||
parent: Option<Arc<Spatial>>,
|
||||
transform: Mat4,
|
||||
zoneable: bool,
|
||||
) -> Result<Arc<Spatial>> {
|
||||
ensure!(
|
||||
node.spatial.get().is_none(),
|
||||
"Internal: Node already has a Spatial aspect!"
|
||||
);
|
||||
) -> Arc<Spatial> {
|
||||
let spatial = Spatial::new(Arc::downgrade(node), parent.clone(), transform);
|
||||
<Spatial as SpatialAspect>::add_node_members(node);
|
||||
if zoneable {
|
||||
@@ -83,8 +77,9 @@ impl Spatial {
|
||||
if let Some(parent) = parent {
|
||||
parent.children.add_raw(&spatial);
|
||||
}
|
||||
let _ = node.spatial.set(spatial.clone());
|
||||
Ok(spatial)
|
||||
<Spatial as SpatialAspect>::add_node_members(node);
|
||||
node.add_aspect_raw(spatial.clone());
|
||||
spatial
|
||||
}
|
||||
|
||||
pub fn node(&self) -> Option<Arc<Node>> {
|
||||
@@ -190,23 +185,21 @@ impl Spatial {
|
||||
fn get_parent(&self) -> Option<Arc<Spatial>> {
|
||||
self.parent.lock().clone()
|
||||
}
|
||||
fn set_parent(&self, new_parent: Option<Arc<Spatial>>) {
|
||||
fn set_parent(self: &Arc<Self>, new_parent: Option<&Arc<Spatial>>) {
|
||||
if let Some(parent) = self.get_parent() {
|
||||
parent.children.remove(self);
|
||||
parent.children.remove(&self);
|
||||
}
|
||||
if let Some(new_parent) = &new_parent {
|
||||
new_parent
|
||||
.children
|
||||
.add_raw(&self.self_ref.upgrade().unwrap());
|
||||
new_parent.children.add_raw(self);
|
||||
}
|
||||
|
||||
*self.parent.lock() = new_parent;
|
||||
*self.parent.lock() = new_parent.cloned();
|
||||
}
|
||||
|
||||
pub fn set_spatial_parent(&self, parent: Option<Arc<Spatial>>) -> Result<()> {
|
||||
pub fn set_spatial_parent(self: &Arc<Self>, parent: Option<&Arc<Spatial>>) -> Result<()> {
|
||||
let is_ancestor = parent
|
||||
.as_ref()
|
||||
.map(|parent| self.is_ancestor_of(parent.clone()))
|
||||
.map(|parent| self.is_ancestor_of((*parent).clone()))
|
||||
.unwrap_or(false);
|
||||
if is_ancestor {
|
||||
return Err(eyre!("Setting spatial parent would cause a loop"));
|
||||
@@ -215,18 +208,21 @@ impl Spatial {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_spatial_parent_in_place(&self, parent: Option<Arc<Spatial>>) -> Result<()> {
|
||||
pub fn set_spatial_parent_in_place(
|
||||
self: &Arc<Self>,
|
||||
parent: Option<&Arc<Spatial>>,
|
||||
) -> Result<()> {
|
||||
let is_ancestor = parent
|
||||
.as_ref()
|
||||
.map(|parent| self.is_ancestor_of(parent.clone()))
|
||||
.map(|parent| self.is_ancestor_of((*parent).clone()))
|
||||
.unwrap_or(false);
|
||||
if is_ancestor {
|
||||
return Err(eyre!("Setting spatial parent would cause a loop"));
|
||||
}
|
||||
|
||||
self.set_local_transform(Spatial::space_to_space_matrix(
|
||||
Some(self),
|
||||
parent.as_deref(),
|
||||
Some(&self),
|
||||
parent.map(AsRef::as_ref),
|
||||
));
|
||||
self.set_parent(parent);
|
||||
|
||||
@@ -242,15 +238,15 @@ impl Spatial {
|
||||
.unwrap_or(f32::MAX)
|
||||
}
|
||||
}
|
||||
impl Aspect for Spatial {
|
||||
const NAME: &'static str = "Spatial";
|
||||
}
|
||||
impl SpatialAspect for Spatial {
|
||||
async fn get_local_bounding_box(
|
||||
node: Arc<Node>,
|
||||
_calling_client: Arc<Client>,
|
||||
) -> Result<BoundingBox> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
let bounds = this_spatial.get_bounding_box();
|
||||
|
||||
Ok(BoundingBox {
|
||||
@@ -264,11 +260,8 @@ impl SpatialAspect for Spatial {
|
||||
_calling_client: Arc<Client>,
|
||||
relative_to: Arc<Node>,
|
||||
) -> Result<BoundingBox> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let relative_spatial = get_spatial(&relative_to, "Relative node")?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
let relative_spatial = relative_to.get_aspect::<Spatial>()?;
|
||||
let center = Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial))
|
||||
.transform_point3([0.0; 3].into());
|
||||
let bounds = Bounds {
|
||||
@@ -295,11 +288,8 @@ impl SpatialAspect for Spatial {
|
||||
_calling_client: Arc<Client>,
|
||||
relative_to: Arc<Node>,
|
||||
) -> Result<Transform> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let relative_spatial = get_spatial(&relative_to, "Relative node")?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
let relative_spatial = relative_to.get_aspect::<Spatial>()?;
|
||||
|
||||
let (scale, rotation, position) = Spatial::space_to_space_matrix(
|
||||
Some(this_spatial.as_ref()),
|
||||
@@ -319,10 +309,7 @@ impl SpatialAspect for Spatial {
|
||||
_calling_client: Arc<Client>,
|
||||
transform: Transform,
|
||||
) -> Result<()> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
this_spatial.set_local_transform_components(None, transform);
|
||||
Ok(())
|
||||
}
|
||||
@@ -332,11 +319,8 @@ impl SpatialAspect for Spatial {
|
||||
relative_to: Arc<Node>,
|
||||
transform: Transform,
|
||||
) -> Result<()> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let relative_spatial = get_spatial(&relative_to, "Relative node")?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
let relative_spatial = relative_to.get_aspect::<Spatial>()?;
|
||||
|
||||
this_spatial.set_local_transform_components(Some(&relative_spatial), transform);
|
||||
Ok(())
|
||||
@@ -347,13 +331,10 @@ impl SpatialAspect for Spatial {
|
||||
_calling_client: Arc<Client>,
|
||||
parent: Arc<Node>,
|
||||
) -> Result<()> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let parent = get_spatial(&parent, "Parent")?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
|
||||
this_spatial.set_spatial_parent(Some(parent))?;
|
||||
this_spatial.set_spatial_parent(Some(&parent))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -362,23 +343,20 @@ impl SpatialAspect for Spatial {
|
||||
_calling_client: Arc<Client>,
|
||||
parent: Arc<Node>,
|
||||
) -> Result<()> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let parent = get_spatial(&parent, "Parent")?;
|
||||
let this_spatial = node.get_aspect::<Spatial>()?;
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
|
||||
this_spatial.set_spatial_parent_in_place(Some(parent))?;
|
||||
this_spatial.set_spatial_parent_in_place(Some(&parent))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_zoneable(node: Arc<Node>, _calling_client: Arc<Client>, zoneable: bool) -> Result<()> {
|
||||
let spatial = node.spatial.get().unwrap();
|
||||
let spatial = node.get_aspect::<Spatial>()?;
|
||||
if zoneable {
|
||||
ZONEABLE_REGISTRY.add_raw(spatial);
|
||||
ZONEABLE_REGISTRY.add_raw(&spatial);
|
||||
} else {
|
||||
ZONEABLE_REGISTRY.remove(spatial);
|
||||
zone::release(spatial);
|
||||
ZONEABLE_REGISTRY.remove(&spatial);
|
||||
zone::release(&spatial);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -400,8 +378,8 @@ impl Debug for Spatial {
|
||||
}
|
||||
impl Drop for Spatial {
|
||||
fn drop(&mut self) {
|
||||
zone::release_drop(self);
|
||||
ZONEABLE_REGISTRY.remove(self);
|
||||
zone::release(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,24 +400,6 @@ pub fn parse_transform(transform: Transform, position: bool, rotation: bool, sca
|
||||
Mat4::from_scale_rotation_translation(scale.into(), rotation.into(), position.into())
|
||||
}
|
||||
|
||||
pub fn find_spatial(
|
||||
calling_client: &Arc<Client>,
|
||||
node_name: &'static str,
|
||||
node_path: &str,
|
||||
) -> Result<Arc<Spatial>> {
|
||||
calling_client
|
||||
.get_node(node_name, node_path)?
|
||||
.get_aspect(node_name, "spatial", |n| &n.spatial)
|
||||
.cloned()
|
||||
}
|
||||
pub fn find_spatial_parent(calling_client: &Arc<Client>, node_path: &str) -> Result<Arc<Spatial>> {
|
||||
find_spatial(calling_client, "Spatial parent", node_path)
|
||||
}
|
||||
pub fn get_spatial(node: &Arc<Node>, node_name: &str) -> Result<Arc<Spatial>> {
|
||||
node.get_aspect(node_name, "spatial", |n| &n.spatial)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub struct SpatialInterface;
|
||||
impl SpatialInterfaceAspect for SpatialInterface {
|
||||
fn create_spatial(
|
||||
@@ -450,11 +410,11 @@ impl SpatialInterfaceAspect for SpatialInterface {
|
||||
transform: Transform,
|
||||
zoneable: bool,
|
||||
) -> Result<()> {
|
||||
let parent = get_spatial(&parent, "Spatial parent")?;
|
||||
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()?;
|
||||
Spatial::add_to(&node, Some(parent), transform, zoneable)?;
|
||||
Spatial::add_to(&node, Some(parent.clone()), transform, zoneable);
|
||||
Ok(())
|
||||
}
|
||||
fn create_zone(
|
||||
@@ -465,13 +425,13 @@ impl SpatialInterfaceAspect for SpatialInterface {
|
||||
transform: Transform,
|
||||
field: Arc<Node>,
|
||||
) -> Result<()> {
|
||||
let parent = get_spatial(&parent, "Spatial parent")?;
|
||||
let parent = parent.get_aspect::<Spatial>()?;
|
||||
let transform = parse_transform(transform, true, true, false);
|
||||
let field = get_field(&field)?;
|
||||
let field = field.get_aspect::<Field>()?;
|
||||
|
||||
let node = Node::create_parent_name(&calling_client, "/spatial/zone", &name, true)
|
||||
.add_to_scenegraph()?;
|
||||
let space = Spatial::add_to(&node, Some(parent), transform, false)?;
|
||||
let space = Spatial::add_to(&node, Some(parent.clone()), transform, false);
|
||||
Zone::add_to(&node, space, &field);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::{get_spatial, Spatial, ZoneAspect, ZONEABLE_REGISTRY};
|
||||
use super::{Spatial, ZoneAspect, ZONEABLE_REGISTRY};
|
||||
use crate::{
|
||||
core::{client::Client, registry::Registry},
|
||||
nodes::{
|
||||
alias::{Alias, AliasInfo},
|
||||
fields::Field,
|
||||
Node,
|
||||
Aspect, Node,
|
||||
},
|
||||
};
|
||||
use glam::vec3a;
|
||||
@@ -30,8 +30,8 @@ pub fn capture(spatial: &Arc<Spatial>, zone: &Arc<Zone>) {
|
||||
let _ = super::zone_client::capture(&node, &spatial.uid);
|
||||
}
|
||||
}
|
||||
pub fn release(spatial: &Spatial) {
|
||||
let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take());
|
||||
pub fn release(spatial: &Arc<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 Some(node) = spatial_zone.spatial.node.upgrade() else {
|
||||
@@ -42,6 +42,16 @@ pub fn release(spatial: &Spatial) {
|
||||
}
|
||||
*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>,
|
||||
@@ -58,13 +68,16 @@ impl Zone {
|
||||
captured: Registry::new(),
|
||||
});
|
||||
<Zone as ZoneAspect>::add_node_members(node);
|
||||
let _ = node.zone.set(zone.clone());
|
||||
node.add_aspect_raw(zone.clone());
|
||||
zone
|
||||
}
|
||||
}
|
||||
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<()> {
|
||||
let zone = node.zone.get().unwrap();
|
||||
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"));
|
||||
};
|
||||
@@ -137,9 +150,9 @@ impl ZoneAspect for Zone {
|
||||
_calling_client: Arc<Client>,
|
||||
spatial: Arc<Node>,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
let zone = node.zone.get().unwrap();
|
||||
let spatial = get_spatial(&spatial, "Spatial")?;
|
||||
capture(&spatial, zone);
|
||||
let zone = node.get_aspect::<Zone>()?;
|
||||
let spatial = spatial.get_aspect()?;
|
||||
capture(&spatial, &zone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -148,7 +161,7 @@ impl ZoneAspect for Zone {
|
||||
_calling_client: Arc<Client>,
|
||||
spatial: Arc<Node>,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
let spatial = get_spatial(&spatial, "Spatial")?;
|
||||
let spatial = spatial.get_aspect()?;
|
||||
release(&spatial);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user