feat: spatial bounds
This commit is contained in:
@@ -14,7 +14,7 @@ use prisma::{Flatten, Lerp, Rgba};
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::{schemas::flex::deserialize, values::Transform};
|
||||
use std::{collections::VecDeque, sync::Arc};
|
||||
use stereokit::{Color128, LinePoint as SkLinePoint, StereoKitDraw};
|
||||
use stereokit::{bounds_grow_to_fit_pt, Bounds, Color128, LinePoint as SkLinePoint, StereoKitDraw};
|
||||
|
||||
use super::Drawable;
|
||||
|
||||
@@ -45,6 +45,16 @@ impl Lines {
|
||||
"Internal: Node already has a drawable attached!"
|
||||
);
|
||||
|
||||
let _ = node.spatial.get().unwrap().bounding_box_calc.set(|node| {
|
||||
let mut bounds = Bounds::default();
|
||||
let Some(Drawable::Lines(lines)) = node.drawable.get() else {return bounds};
|
||||
for point in &lines.data.lock().points {
|
||||
bounds = bounds_grow_to_fit_pt(bounds, point.point);
|
||||
}
|
||||
|
||||
bounds
|
||||
});
|
||||
|
||||
let lines = LINES_REGISTRY.add(Lines {
|
||||
enabled: node.enabled.clone(),
|
||||
space: node.get_aspect("Lines", "spatial", |n| &n.spatial)?.clone(),
|
||||
|
||||
@@ -22,7 +22,8 @@ use std::path::PathBuf;
|
||||
use std::sync::{Arc, Weak};
|
||||
use stereokit::named_colors::WHITE;
|
||||
use stereokit::{
|
||||
Color128, Material, Model as SKModel, RenderLayer, Shader, StereoKitDraw, StereoKitMultiThread,
|
||||
Bounds, Color128, Material, Model as SKModel, RenderLayer, Shader, StereoKitDraw,
|
||||
StereoKitMultiThread,
|
||||
};
|
||||
|
||||
static MODEL_REGISTRY: Registry<Model> = Registry::new();
|
||||
@@ -182,6 +183,16 @@ impl ModelPart {
|
||||
false,
|
||||
)
|
||||
.ok()?;
|
||||
|
||||
let _ = node.spatial.get().unwrap().bounding_box_calc.set(|node| {
|
||||
let Some(Drawable::ModelPart(model_part)) = node.drawable.get() else {return Bounds::default()};
|
||||
let Some(sk) = SK_MULTITHREAD.get() 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 Some(sk_mesh) = sk.model_node_get_mesh(sk_model, model_part.id) else {return Bounds::default()};
|
||||
sk.mesh_get_bounds(sk_mesh)
|
||||
});
|
||||
|
||||
let model_part = Arc::new(ModelPart {
|
||||
id,
|
||||
path: part_path,
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn make_alias(client: &Arc<Client>) -> Result<Arc<Node>> {
|
||||
"hmd",
|
||||
&HMD,
|
||||
AliasInfo {
|
||||
server_signals: vec!["get_transform"],
|
||||
server_signals: vec!["get_bounds", "get_transform"],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ use std::sync::{Arc, Weak};
|
||||
|
||||
lazy_static! {
|
||||
static ref ITEM_ALIAS_LOCAL_SIGNALS: Vec<&'static str> = vec![
|
||||
"get_bounds",
|
||||
"get_transform",
|
||||
"set_transform",
|
||||
"set_spatial_parent",
|
||||
|
||||
@@ -14,7 +14,8 @@ use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use stardust_xr::values::Transform;
|
||||
use std::fmt::Debug;
|
||||
use std::ptr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::{Arc, OnceLock, Weak};
|
||||
use stereokit::{bounds_grow_to_fit_box, Bounds};
|
||||
use tracing::instrument;
|
||||
|
||||
static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
|
||||
@@ -28,6 +29,7 @@ pub struct Spatial {
|
||||
pub(super) transform: Mutex<Mat4>,
|
||||
zone: Mutex<Weak<Zone>>,
|
||||
children: Registry<Spatial>,
|
||||
pub(super) bounding_box_calc: OnceLock<fn(&Node) -> Bounds>,
|
||||
}
|
||||
|
||||
impl Spatial {
|
||||
@@ -41,6 +43,7 @@ impl Spatial {
|
||||
transform: Mutex::new(transform),
|
||||
zone: Mutex::new(Weak::new()),
|
||||
children: Registry::new(),
|
||||
bounding_box_calc: OnceLock::default(),
|
||||
})
|
||||
}
|
||||
pub fn add_to(
|
||||
@@ -54,6 +57,7 @@ impl Spatial {
|
||||
"Internal: Node already has a Spatial aspect!"
|
||||
);
|
||||
let spatial = Spatial::new(Arc::downgrade(node), parent, transform);
|
||||
node.add_local_method("get_bounding_box", Spatial::get_bounding_box_flex);
|
||||
node.add_local_method("get_transform", Spatial::get_transform_flex);
|
||||
node.add_local_signal("set_transform", Spatial::set_transform_flex);
|
||||
node.add_local_signal("set_spatial_parent", Spatial::set_spatial_parent_flex);
|
||||
@@ -83,6 +87,25 @@ impl Spatial {
|
||||
world_to_space_matrix * space_to_world_matrix
|
||||
}
|
||||
|
||||
// the output bounds are probably way bigger than they need to be
|
||||
#[instrument(level = "debug")]
|
||||
pub fn get_bounding_box(&self) -> Bounds {
|
||||
let Some(node) = self.node() else {return Bounds::default()};
|
||||
let mut bounds = self
|
||||
.bounding_box_calc
|
||||
.get()
|
||||
.map(|b| (b)(&node))
|
||||
.unwrap_or_default();
|
||||
for child in self.children.get_valid_contents() {
|
||||
bounds = bounds_grow_to_fit_box(
|
||||
bounds,
|
||||
child.get_bounding_box(),
|
||||
Some(child.local_transform()),
|
||||
);
|
||||
}
|
||||
bounds
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn local_transform(&self) -> Mat4 {
|
||||
*self.transform.lock()
|
||||
@@ -206,6 +229,44 @@ impl Spatial {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_bounding_box_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let relative_spatial_path: Option<&str> = deserialize(data)?;
|
||||
let bounds = if let Some(relative_spatial_path) = relative_spatial_path {
|
||||
let relative_spatial = find_reference_space(&calling_client, relative_spatial_path)?;
|
||||
let center =
|
||||
Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial))
|
||||
.transform_point3([0.0; 3].into());
|
||||
let bounds: Bounds = Bounds {
|
||||
center,
|
||||
dimensions: [0.0; 3].into(),
|
||||
};
|
||||
bounds_grow_to_fit_box(
|
||||
bounds,
|
||||
this_spatial.get_bounding_box(),
|
||||
Some(Spatial::space_to_space_matrix(
|
||||
Some(&this_spatial),
|
||||
Some(&relative_spatial),
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
this_spatial.get_bounding_box()
|
||||
};
|
||||
|
||||
serialize((
|
||||
mint::Vector3::from(bounds.center),
|
||||
mint::Vector3::from(bounds.dimensions),
|
||||
))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn get_transform_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
|
||||
@@ -119,7 +119,7 @@ impl Zone {
|
||||
"set_spatial_parent",
|
||||
"set_spatial_parent_in_place",
|
||||
],
|
||||
server_methods: vec!["get_transform"],
|
||||
server_methods: vec!["get_bounds", "get_transform"],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user