refactor: use typemap for aspects!

This commit is contained in:
Nova
2024-02-05 05:09:48 -05:00
parent 36dacb3322
commit d4b7c3f61a
36 changed files with 518 additions and 528 deletions

View File

@@ -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(())
}

View File

@@ -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(())
}