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,9 +1,9 @@
use super::{Drawable, Line, LinesAspect};
use super::{Line, LinesAspect};
use crate::{
core::{client::Client, registry::Registry},
nodes::{spatial::Spatial, Node},
nodes::{spatial::Spatial, Aspect, Node},
};
use color_eyre::eyre::{bail, ensure, Result};
use color_eyre::eyre::Result;
use glam::Vec3A;
use parking_lot::Mutex;
use portable_atomic::{AtomicBool, Ordering};
@@ -20,31 +20,29 @@ pub struct Lines {
}
impl Lines {
pub fn add_to(node: &Arc<Node>, lines: Vec<Line>) -> Result<Arc<Lines>> {
ensure!(
node.drawable.get().is_none(),
"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 line in &*lines.data.lock() {
for point in &line.points {
bounds = bounds_grow_to_fit_pt(bounds, point.point);
let _ = node
.get_aspect::<Spatial>()
.unwrap()
.bounding_box_calc
.set(|node| {
let mut bounds = Bounds::default();
if let Ok(lines) = node.get_aspect::<Lines>() {
for line in &*lines.data.lock() {
for point in &line.points {
bounds = bounds_grow_to_fit_pt(bounds, point.point);
}
}
}
}
bounds
});
bounds
});
let lines = LINES_REGISTRY.add(Lines {
enabled: node.enabled.clone(),
space: node.get_aspect("Lines", "spatial", |n| &n.spatial)?.clone(),
space: node.get_aspect::<Spatial>()?.clone(),
data: Mutex::new(lines),
});
<Lines as LinesAspect>::add_node_members(node);
let _ = node.drawable.set(Drawable::Lines(lines.clone()));
node.add_aspect_raw(lines.clone());
Ok(lines)
}
@@ -94,12 +92,12 @@ impl Lines {
}
}
}
impl Aspect for Lines {
const NAME: &'static str = "Lines";
}
impl LinesAspect for Lines {
fn set_lines(node: Arc<Node>, _calling_client: Arc<Client>, lines: Vec<Line>) -> Result<()> {
let Some(Drawable::Lines(lines_aspect)) = node.drawable.get() else {
bail!("Not a drawable??")
};
let lines_aspect = node.get_aspect::<Lines>()?;
*lines_aspect.data.lock() = lines;
Ok(())
}

View File

@@ -3,14 +3,9 @@ pub mod model;
pub mod shaders;
pub mod text;
use self::{
lines::Lines,
model::{Model, ModelPart},
text::Text,
};
use self::{lines::Lines, model::Model, text::Text};
use super::{
spatial::{get_spatial, Spatial, Transform},
spatial::{Spatial, Transform},
Node,
};
use crate::{
@@ -23,13 +18,6 @@ use stardust_xr::values::ResourceID;
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
use stereokit::StereoKitDraw;
pub enum Drawable {
Lines(Arc<Lines>),
Model(Arc<Model>),
ModelPart(Arc<ModelPart>),
Text(Arc<Text>),
}
// #[instrument(level = "debug", skip(sk))]
pub fn draw(sk: &impl StereoKitDraw) {
lines::draw_all(sk);
@@ -87,11 +75,11 @@ impl DrawableInterfaceAspect for DrawableInterface {
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::CREATE_LINES_PARENT_PATH, &name, true);
let parent = get_spatial(&parent, "Spatial parent")?;
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
let node = node.add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent), transform, false)?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
Lines::add_to(&node, lines)?;
Ok(())
}
@@ -107,10 +95,10 @@ impl DrawableInterfaceAspect for DrawableInterface {
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::LOAD_MODEL_PARENT_PATH, &name, true);
let parent = get_spatial(&parent, "Spatial parent")?;
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
let node = node.add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent), transform, false)?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
Model::add_to(&node, model)?;
Ok(())
}
@@ -127,11 +115,11 @@ impl DrawableInterfaceAspect for DrawableInterface {
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::CREATE_TEXT_PARENT_PATH, &name, true);
let parent = get_spatial(&parent, "Spatial parent")?;
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
let node = node.add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent), transform, false)?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
Text::add_to(&node, text, style)?;
Ok(())
}

View File

@@ -4,10 +4,10 @@ use crate::core::destroy_queue;
use crate::core::node_collections::LifeLinkedNodeMap;
use crate::core::registry::Registry;
use crate::core::resource::get_resource_file;
use crate::nodes::drawable::Drawable;
use crate::nodes::spatial::Spatial;
use crate::nodes::Aspect;
use crate::SK_MULTITHREAD;
use color_eyre::eyre::{bail, ensure, eyre, Result};
use color_eyre::eyre::{eyre, Result};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use portable_atomic::{AtomicBool, Ordering};
@@ -133,10 +133,7 @@ impl ModelPart {
.and_then(|id| model.parts.get(&id));
let parent_part = parent_node
.as_ref()
.and_then(|node| match node.drawable.get() {
Some(Drawable::ModelPart(model_part)) => Some(model_part),
_ => None,
});
.and_then(|node| node.get_aspect::<ModelPart>().ok());
let stardust_model_part = model.space.node()?;
let client = stardust_model_part.get_client()?;
@@ -149,34 +146,37 @@ impl ModelPart {
false,
));
let spatial_parent = parent_node
.and_then(|n| n.spatial.get().cloned())
.and_then(|n| n.get_aspect::<Spatial>().ok())
.unwrap_or_else(|| model.space.clone());
let space = Spatial::add_to(
&node,
Some(spatial_parent),
sk.model_node_get_transform_local(sk_model, id),
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 _ = node
.get_aspect::<Spatial>()
.unwrap()
.bounding_box_calc
.set(|node| {
let Ok(model_part) = node.get_aspect::<ModelPart>() 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,
@@ -187,7 +187,7 @@ impl ModelPart {
pending_material_replacement: Mutex::new(None),
});
<ModelPart as ModelPartAspect>::add_node_members(&node);
let _ = node.drawable.set(Drawable::ModelPart(model_part.clone()));
node.add_aspect_raw(model_part.clone());
model.parts.add(id, &node);
Some(model_part)
}
@@ -232,12 +232,13 @@ impl ModelPart {
);
}
}
impl Aspect for ModelPart {
const NAME: &'static str = "ModelPart";
}
impl ModelPartAspect for ModelPart {
#[doc = "Set this model part's material to one that cuts a hole in the world. Often used for overlays/passthrough where you want to show the background through an object."]
fn apply_holdout_material(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
let Some(Drawable::ModelPart(model_part)) = node.drawable.get() else {
bail!("Not a drawable??")
};
let model_part = node.get_aspect::<ModelPart>()?;
model_part.replace_material(HOLDOUT_MATERIAL.get().unwrap().clone());
Ok(())
}
@@ -249,10 +250,7 @@ impl ModelPartAspect for ModelPart {
parameter_name: String,
value: MaterialParameter,
) -> Result<()> {
let Some(Drawable::ModelPart(model_part)) = node.drawable.get() else {
bail!("Not a drawable??")
};
let model_part = node.get_aspect::<ModelPart>()?;
model_part
.pending_material_parameters
.lock()
@@ -275,15 +273,6 @@ unsafe impl Sync for Model {}
impl Model {
pub fn add_to(node: &Arc<Node>, resource_id: ResourceID) -> Result<Arc<Model>> {
ensure!(
node.spatial.get().is_some(),
"Internal: Node does not have a spatial attached!"
);
ensure!(
node.drawable.get().is_none(),
"Internal: Node already has a drawable attached!"
);
let pending_model_path = get_resource_file(
&resource_id,
&*node.get_client().ok_or_else(|| eyre!("Client not found"))?,
@@ -294,7 +283,7 @@ impl Model {
let model = Arc::new_cyclic(|self_ref| Model {
self_ref: self_ref.clone(),
enabled: node.enabled.clone(),
space: node.spatial.get().unwrap().clone(),
space: node.get_aspect::<Spatial>().unwrap().clone(),
_resource_id: resource_id,
sk_model: OnceCell::new(),
parts: LifeLinkedNodeMap::default(),
@@ -307,7 +296,7 @@ impl Model {
);
ModelPart::create_for_model(sk, &model.self_ref.upgrade().unwrap(), &sk_model);
let _ = model.sk_model.set(sk_model);
let _ = node.drawable.set(Drawable::Model(model.clone()));
node.add_aspect_raw(model.clone());
Ok(model)
}
@@ -316,10 +305,9 @@ impl Model {
return;
};
for model_node_node in self.parts.nodes() {
let Some(Drawable::ModelPart(model_node)) = model_node_node.drawable.get() else {
continue;
if let Ok(model_node) = model_node_node.get_aspect::<ModelPart>() {
model_node.update(sk);
};
model_node.update(sk);
}
sk.model_draw(
@@ -330,6 +318,9 @@ impl Model {
);
}
}
impl Aspect for Model {
const NAME: &'static str = "Model";
}
impl ModelAspect for Model {}
impl Drop for Model {
fn drop(&mut self) {

View File

@@ -1,8 +1,8 @@
use crate::{
core::{client::Client, destroy_queue, registry::Registry, resource::get_resource_file},
nodes::{drawable::Drawable, spatial::Spatial, Node},
nodes::{spatial::Spatial, Aspect, Node},
};
use color_eyre::eyre::{bail, ensure, eyre, Result};
use color_eyre::eyre::{eyre, Result};
use glam::{vec3, Mat4, Vec2};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
@@ -42,19 +42,10 @@ pub struct Text {
}
impl Text {
pub fn add_to(node: &Arc<Node>, text: String, style: TextStyle) -> Result<Arc<Text>> {
ensure!(
node.spatial.get().is_some(),
"Internal: Node does not have a spatial attached!"
);
ensure!(
node.drawable.get().is_none(),
"Internal: Node already has a drawable attached!"
);
let client = node.get_client().ok_or_else(|| eyre!("Client not found"))?;
let text = TEXT_REGISTRY.add(Text {
enabled: node.enabled.clone(),
space: node.spatial.get().unwrap().clone(),
space: node.get_aspect::<Spatial>().unwrap().clone(),
font_path: style.font.as_ref().and_then(|res| {
get_resource_file(&res, &client, &[OsStr::new("ttf"), OsStr::new("otf")])
}),
@@ -64,7 +55,7 @@ impl Text {
data: Mutex::new(style),
});
<Text as TextAspect>::add_node_members(node);
let _ = node.drawable.set(Drawable::Text(text.clone()));
node.add_aspect_raw(text.clone());
Ok(text)
}
@@ -122,26 +113,23 @@ impl Text {
}
}
}
impl Aspect for Text {
const NAME: &'static str = "Text";
}
impl TextAspect for Text {
fn set_character_height(
node: Arc<Node>,
_calling_client: Arc<Client>,
height: f32,
) -> Result<()> {
let Some(Drawable::Text(text)) = node.drawable.get() else {
bail!("Not a drawable??")
};
text.data.lock().character_height = height;
let this_text = node.get_aspect::<Text>()?;
this_text.data.lock().character_height = height;
Ok(())
}
fn set_text(node: Arc<Node>, _calling_client: Arc<Client>, text: String) -> Result<()> {
let Some(Drawable::Text(text_aspect)) = node.drawable.get() else {
bail!("Not a drawable??")
};
*text_aspect.text.lock() = text;
let this_text = node.get_aspect::<Text>()?;
*this_text.text.lock() = text;
Ok(())
}
}