From 80130f6ffd35a094b9df9586bac64d8b5f3e9297 Mon Sep 17 00:00:00 2001 From: Nova Date: Thu, 24 Nov 2022 18:57:11 -0500 Subject: [PATCH] feat(fields): torus field --- src/nodes/fields/mod.rs | 5 +++ src/nodes/fields/torus.rs | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/nodes/fields/torus.rs diff --git a/src/nodes/fields/mod.rs b/src/nodes/fields/mod.rs index d81b875..db87e79 100644 --- a/src/nodes/fields/mod.rs +++ b/src/nodes/fields/mod.rs @@ -1,10 +1,12 @@ mod r#box; mod cylinder; mod sphere; +pub mod torus; use self::cylinder::{create_cylinder_field_flex, CylinderField}; use self::r#box::{create_box_field_flex, BoxField}; use self::sphere::{create_sphere_field_flex, SphereField}; +use self::torus::{create_torus_field_flex, TorusField}; use super::spatial::Spatial; use super::Node; @@ -200,6 +202,7 @@ pub enum Field { Box(BoxField), Cylinder(CylinderField), Sphere(SphereField), + Torus(TorusField), } impl Deref for Field { @@ -209,6 +212,7 @@ impl Deref for Field { Field::Box(field) => field, Field::Cylinder(field) => field, Field::Sphere(field) => field, + Field::Torus(field) => field, } } } @@ -218,6 +222,7 @@ pub fn create_interface(client: &Arc) { node.add_local_signal("create_box_field", create_box_field_flex); node.add_local_signal("create_cylinder_field", create_cylinder_field_flex); node.add_local_signal("create_sphere_field", create_sphere_field_flex); + node.add_local_signal("create_torus_field", create_torus_field_flex); node.add_to_scenegraph(); } diff --git a/src/nodes/fields/torus.rs b/src/nodes/fields/torus.rs new file mode 100644 index 0000000..6cf0df2 --- /dev/null +++ b/src/nodes/fields/torus.rs @@ -0,0 +1,88 @@ +use super::{Field, FieldTrait, Node}; +use crate::core::client::Client; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use anyhow::{ensure, Result}; +use glam::{swizzles::*, vec2, Vec3A}; +use portable_atomic::AtomicF32; +use serde::Deserialize; +use stardust_xr::schemas::flex::deserialize; +use stardust_xr::values::Transform; + +use std::sync::atomic::Ordering; +use std::sync::Arc; + +pub struct TorusField { + space: Arc, + radius_a: AtomicF32, + radius_b: AtomicF32, +} + +impl TorusField { + pub fn add_to(node: &Arc, radius_a: f32, radius_b: f32) -> Result<()> { + ensure!( + node.spatial.get().is_some(), + "Internal: Node does not have a spatial attached!" + ); + ensure!( + node.field.get().is_none(), + "Internal: Node already has a field attached!" + ); + let torus_field = TorusField { + space: node.spatial.get().unwrap().clone(), + radius_a: AtomicF32::new(radius_a.abs()), + radius_b: AtomicF32::new(radius_b.abs()), + }; + torus_field.add_field_methods(node); + node.add_local_signal("set_size", TorusField::set_size_flex); + let _ = node.field.set(Arc::new(Field::Torus(torus_field))); + Ok(()) + } + + pub fn set_size(&self, radius_a: f32, radius_b: f32) { + self.radius_a.store(radius_a.abs(), Ordering::Relaxed); + self.radius_b.store(radius_b.abs(), Ordering::Relaxed); + } + + pub fn set_size_flex(node: &Node, _calling_client: Arc, data: &[u8]) -> Result<()> { + let Field::Torus(torus_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; + let (radius_a, radius_b) = deserialize(data)?; + torus_field.set_size(radius_a, radius_b); + + Ok(()) + } +} + +impl FieldTrait for TorusField { + fn local_distance(&self, p: Vec3A) -> f32 { + let radius_a = self.radius_a.load(Ordering::Relaxed); + let radius_b = self.radius_b.load(Ordering::Relaxed); + let q = vec2(p.xz().length() - radius_a, p.y); + q.length() - radius_b + } + fn spatial_ref(&self) -> &Spatial { + self.space.as_ref() + } +} + +pub fn create_torus_field_flex( + _node: &Node, + calling_client: Arc, + data: &[u8], +) -> Result<()> { + #[derive(Deserialize)] + struct CreateFieldInfo<'a> { + name: &'a str, + parent_path: &'a str, + transform: Transform, + radius_a: f32, + radius_b: f32, + } + let info: CreateFieldInfo = deserialize(data)?; + let node = Node::create(&calling_client, "/field", info.name, true); + let parent = find_spatial_parent(&calling_client, info.parent_path)?; + let transform = parse_transform(info.transform, true, true, false)?; + let node = node.add_to_scenegraph(); + Spatial::add_to(&node, Some(parent), transform, false)?; + TorusField::add_to(&node, info.radius_a, info.radius_b)?; + Ok(()) +}