From 6c172a98b64991985f5c0fb0acb70084bae78c32 Mon Sep 17 00:00:00 2001 From: Nova Date: Wed, 17 Aug 2022 19:08:48 -0400 Subject: [PATCH] feat: model node :D --- Cargo.toml | 2 + src/core/client.rs | 2 + src/main.rs | 8 +++- src/nodes/core.rs | 3 ++ src/nodes/mod.rs | 1 + src/nodes/model.rs | 116 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/nodes/model.rs diff --git a/Cargo.toml b/Cargo.toml index 6743570..cff3d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ rustc-hash = "1.1.0" slab = "0.4.6" tokio = { version = "1", features = ["full"] } thiserror = "1.0.31" +send_wrapper = "0.6.0" +prisma = "0.1.1" [dependencies.libstardustxr] path = "../libstardustxr-rs" diff --git a/src/core/client.rs b/src/core/client.rs index 4b08bfd..c885f3c 100644 --- a/src/core/client.rs +++ b/src/core/client.rs @@ -4,6 +4,7 @@ use crate::nodes::data; use crate::nodes::field; use crate::nodes::input; use crate::nodes::item; +use crate::nodes::model; use crate::nodes::root::Root; use crate::nodes::spatial; use anyhow::Result; @@ -60,6 +61,7 @@ impl Client { let _ = client.root.set(Root::create(&client)); spatial::create_interface(&client); field::create_interface(&client); + model::create_interface(&client); data::create_interface(&client); item::create_interface(&client); input::create_interface(&client); diff --git a/src/main.rs b/src/main.rs index 56a7c0a..5299032 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ mod core; mod nodes; +use crate::nodes::model::{MODELS_TO_DROP, MODEL_REGISTRY}; + use self::core::eventloop::EventLoop; use anyhow::Result; use clap::Parser; @@ -44,8 +46,12 @@ fn main() -> Result<()> { .spawn(move || event_loop(event_stop_rx))?; stereokit.run( - |_draw_ctx| { + |draw_ctx| { nodes::root::Root::logic_step(stereokit.time_elapsed()); + for model in MODEL_REGISTRY.get_valid_contents() { + model.draw(&stereokit, draw_ctx); + } + MODELS_TO_DROP.lock().clear(); }, || { println!("Cleanly shut down StereoKit"); diff --git a/src/nodes/core.rs b/src/nodes/core.rs index baff62c..1595a75 100644 --- a/src/nodes/core.rs +++ b/src/nodes/core.rs @@ -2,6 +2,7 @@ use super::data::{PulseReceiver, PulseSender}; use super::field::Field; use super::input::{InputHandler, InputMethod}; use super::item::{Item, ItemAcceptor, ItemUI}; +use super::model::Model; use super::spatial::Spatial; use crate::core::client::Client; use crate::core::registry::Registry; @@ -35,6 +36,7 @@ pub struct Node { pub spatial: OnceCell>, pub field: OnceCell>, + pub model: OnceCell>, pub pulse_sender: OnceCell>, pub pulse_receiver: OnceCell>, pub item: OnceCell>, @@ -76,6 +78,7 @@ impl Node { spatial: OnceCell::new(), field: OnceCell::new(), + model: OnceCell::new(), pulse_sender: OnceCell::new(), pulse_receiver: OnceCell::new(), item: OnceCell::new(), diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index 55755cc..7853b8c 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -4,5 +4,6 @@ pub mod field; pub mod input; pub mod input_pointer; pub mod item; +pub mod model; pub mod root; pub mod spatial; diff --git a/src/nodes/model.rs b/src/nodes/model.rs new file mode 100644 index 0000000..532d524 --- /dev/null +++ b/src/nodes/model.rs @@ -0,0 +1,116 @@ +use super::core::Node; +use super::spatial::{get_spatial_parent_flex, Spatial}; +use crate::core::client::Client; +use crate::core::registry::Registry; +use anyhow::{anyhow, ensure, Result}; +use glam::Mat4; +use lazy_static::lazy_static; +use libstardustxr::{flex_to_quat, flex_to_vec3}; +use once_cell::sync::OnceCell; +use parking_lot::Mutex; +use prisma::{Rgb, Rgba}; +use send_wrapper::SendWrapper; +use std::fmt::Error; +use std::path::PathBuf; +use std::sync::Arc; +use stereokit::enums::RenderLayer; +use stereokit::lifecycle::DrawContext; +use stereokit::model::Model as SKModel; +use stereokit::StereoKit; + +lazy_static! { + pub static ref MODEL_REGISTRY: Registry = Default::default(); + pub static ref MODELS_TO_DROP: Mutex>> = Default::default(); +} + +pub struct Model { + space: Arc, + pending_model_path: OnceCell, + sk_model: OnceCell>, +} + +impl Model { + pub fn add_to(node: &Arc, path: String) -> Result> { + ensure!( + node.spatial.get().is_some(), + "Internal: Node does not have a spatial attached!" + ); + ensure!( + node.model.get().is_none(), + "Internal: Node already has a model attached!" + ); + let model = Model { + space: node.spatial.get().unwrap().clone(), + pending_model_path: OnceCell::new(), + sk_model: OnceCell::new(), + }; + // node.add_local_method("", Spatial::get_transform_flex); + let model_arc = MODEL_REGISTRY.add(model); + let _ = model_arc.pending_model_path.set(PathBuf::from(path)); + let _ = node.model.set(model_arc.clone()); + Ok(model_arc) + } + + pub fn draw(&self, sk: &StereoKit, draw_ctx: &DrawContext) { + let sk_model = self + .sk_model + .get_or_try_init(|| { + self.pending_model_path + .get() + .and_then(|path| SKModel::from_file(sk, path.as_path(), None)) + .map(|model| SendWrapper::new(model)) + .ok_or(Error) + }) + .ok(); + + if let Some(sk_model) = sk_model { + sk_model.draw( + draw_ctx, + self.space.global_transform().into(), + Rgba::new(Rgb::new(1_f32, 1_f32, 1_f32), 1_f32), + RenderLayer::Layer0, + ); + } + } +} +impl Drop for Model { + fn drop(&mut self) { + if let Some(model) = self.sk_model.take() { + MODELS_TO_DROP.lock().push(model); + } + MODEL_REGISTRY.remove(self); + } +} + +pub fn create_interface(client: &Arc) { + let node = Node::create(client, "", "drawable", false); + node.add_local_signal("createModelFromFile", create_from_file); + node.add_to_scenegraph(); +} + +pub fn create_from_file(_node: &Node, calling_client: Arc, data: &[u8]) -> Result<()> { + let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?; + let node = Node::create( + &calling_client, + "/drawable/model", + flex_vec.idx(0).get_str()?, + true, + ); + let parent = get_spatial_parent_flex(&calling_client, flex_vec.idx(1).get_str()?)?; + let path = flex_vec.idx(2).get_str()?.to_string(); + let transform = Mat4::from_scale_rotation_translation( + flex_to_vec3!(flex_vec.idx(5)) + .ok_or_else(|| anyhow!("Scale not found"))? + .into(), + flex_to_quat!(flex_vec.idx(4)) + .ok_or_else(|| anyhow!("Rotation not found"))? + .into(), + flex_to_vec3!(flex_vec.idx(3)) + .ok_or_else(|| anyhow!("Position not found"))? + .into(), + ); + let node = node.add_to_scenegraph(); + Spatial::add_to(&node, Some(parent), transform)?; + Model::add_to(&node, path)?; + Ok(()) +}