feat: upgrade stereokit
This commit is contained in:
@@ -15,7 +15,7 @@ use stardust_xr::values::ResourceID;
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::Arc;
|
||||
use std::{ffi::OsStr, path::PathBuf};
|
||||
use stereokit::{Sound as SkSound, SoundInstance, StereoKitDraw};
|
||||
use stereokit_rust::sound::{Sound as SkSound, SoundInst};
|
||||
|
||||
static SOUND_REGISTRY: Registry<Sound> = Registry::new();
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct Sound {
|
||||
volume: f32,
|
||||
pending_audio_path: PathBuf,
|
||||
sk_sound: OnceCell<SendWrapper<SkSound>>,
|
||||
instance: Mutex<Option<SoundInstance>>,
|
||||
instance: Mutex<Option<SoundInst>>,
|
||||
stop: Mutex<Option<()>>,
|
||||
play: Mutex<Option<()>>,
|
||||
}
|
||||
@@ -53,24 +53,21 @@ impl Sound {
|
||||
Ok(sound_arc)
|
||||
}
|
||||
|
||||
fn update(&self, sk: &impl StereoKitDraw) {
|
||||
fn update(&self) {
|
||||
let sound = self.sk_sound.get_or_init(|| {
|
||||
SendWrapper::new(sk.sound_create(self.pending_audio_path.clone()).unwrap())
|
||||
SendWrapper::new(SkSound::from_file(self.pending_audio_path.clone()).unwrap())
|
||||
});
|
||||
if self.stop.lock().take().is_some() {
|
||||
if let Some(instance) = self.instance.lock().take() {
|
||||
sk.sound_inst_stop(instance);
|
||||
instance.stop();
|
||||
}
|
||||
}
|
||||
if self.instance.lock().is_none() && self.play.lock().take().is_some() {
|
||||
self.instance.lock().replace(sk.sound_play(
|
||||
sound.as_ref(),
|
||||
vec3(0.0, 0.0, 0.0),
|
||||
self.volume,
|
||||
));
|
||||
let instance = sound.play(vec3(0.0, 0.0, 0.0), Some(self.volume));
|
||||
self.instance.lock().replace(instance);
|
||||
}
|
||||
if let Some(instance) = self.instance.lock().deref_mut() {
|
||||
sk.sound_inst_set_pos(*instance, self.space.global_transform().w_axis.xyz());
|
||||
instance.position(self.space.global_transform().w_axis.xyz());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,9 +95,9 @@ impl Drop for Sound {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(sk: &impl StereoKitDraw) {
|
||||
pub fn update() {
|
||||
for sound in SOUND_REGISTRY.get_valid_contents() {
|
||||
sound.update(sk)
|
||||
sound.update()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
src/nodes/drawable/assets/shaders/shader_unlit_gamma.hlsl.sks
Normal file
BIN
src/nodes/drawable/assets/shaders/shader_unlit_gamma.hlsl.sks
Normal file
Binary file not shown.
BIN
src/nodes/drawable/assets/shaders/shader_unlit_simula.hlsl.sks
Normal file
BIN
src/nodes/drawable/assets/shaders/shader_unlit_simula.hlsl.sks
Normal file
Binary file not shown.
@@ -4,12 +4,14 @@ use crate::{
|
||||
nodes::{spatial::Spatial, Aspect, Node},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Vec3A;
|
||||
use glam::Vec3;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
use prisma::Lerp;
|
||||
use std::{collections::VecDeque, sync::Arc};
|
||||
use stereokit::{bounds_grow_to_fit_pt, Bounds, Color128, LinePoint as SkLinePoint, StereoKitDraw};
|
||||
use stereokit_rust::{
|
||||
maths::Bounds, sk::MainThreadToken, system::LinePoint as SkLinePoint, util::Color128,
|
||||
};
|
||||
|
||||
static LINES_REGISTRY: Registry<Lines> = Registry::new();
|
||||
|
||||
@@ -29,7 +31,7 @@ impl Lines {
|
||||
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.grown_point(Vec3::from(point.point));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +49,7 @@ impl Lines {
|
||||
Ok(lines)
|
||||
}
|
||||
|
||||
fn draw(&self, draw_ctx: &impl StereoKitDraw) {
|
||||
fn draw(&self, token: &MainThreadToken) {
|
||||
let transform_mat = self.space.global_transform();
|
||||
let data = self.data.lock().clone();
|
||||
for line in &data {
|
||||
@@ -55,15 +57,9 @@ impl Lines {
|
||||
.points
|
||||
.iter()
|
||||
.map(|p| SkLinePoint {
|
||||
pt: transform_mat.transform_point3a(Vec3A::from(p.point)).into(),
|
||||
pt: transform_mat.transform_point3(Vec3::from(p.point)).into(),
|
||||
thickness: p.thickness,
|
||||
color: stereokit::sys::color128::from([
|
||||
p.color.c.r,
|
||||
p.color.c.g,
|
||||
p.color.c.b,
|
||||
p.color.a,
|
||||
])
|
||||
.into(),
|
||||
color: Color128::new(p.color.c.r, p.color.c.g, p.color.c.b, p.color.a).into(),
|
||||
})
|
||||
.collect();
|
||||
if line.cyclic && !points.is_empty() {
|
||||
@@ -78,9 +74,7 @@ impl Lines {
|
||||
};
|
||||
let connect_point = SkLinePoint {
|
||||
pt: transform_mat
|
||||
.transform_point3a(
|
||||
Vec3A::from(first.point).lerp(Vec3A::from(last.point), 0.5),
|
||||
)
|
||||
.transform_point3(Vec3::from(first.point).lerp(Vec3::from(last.point), 0.5))
|
||||
.into(),
|
||||
thickness: (first.thickness + last.thickness) * 0.5,
|
||||
color: color.into(),
|
||||
@@ -88,7 +82,7 @@ impl Lines {
|
||||
points.push_front(connect_point.clone());
|
||||
points.push_back(connect_point);
|
||||
}
|
||||
draw_ctx.line_add_listv(points.make_contiguous());
|
||||
stereokit_rust::system::Lines::add_list(token, points.make_contiguous());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,10 +102,10 @@ impl Drop for Lines {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_all(draw_ctx: &impl StereoKitDraw) {
|
||||
pub fn draw_all(token: &MainThreadToken) {
|
||||
for lines in LINES_REGISTRY.get_valid_contents() {
|
||||
if lines.enabled.load(Ordering::Relaxed) {
|
||||
lines.draw(draw_ctx);
|
||||
lines.draw(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,22 +16,22 @@ use color_eyre::eyre::{self, Result};
|
||||
use parking_lot::Mutex;
|
||||
use stardust_xr::values::ResourceID;
|
||||
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
|
||||
use stereokit::StereoKitDraw;
|
||||
use stereokit_rust::{sk::MainThreadToken, system::Renderer, tex::SHCubemap};
|
||||
|
||||
// #[instrument(level = "debug", skip(sk))]
|
||||
pub fn draw(sk: &impl StereoKitDraw) {
|
||||
lines::draw_all(sk);
|
||||
model::draw_all(sk);
|
||||
text::draw_all(sk);
|
||||
pub fn draw(token: &MainThreadToken) {
|
||||
lines::draw_all(token);
|
||||
model::draw_all(token);
|
||||
text::draw_all(token);
|
||||
|
||||
if let Some(skytex) = QUEUED_SKYTEX.lock().take() {
|
||||
if let Ok((_skylight, skytex)) = sk.tex_create_cubemap_file(&skytex, true, i32::MAX) {
|
||||
sk.render_set_skytex(&skytex);
|
||||
if let Ok(skytex) = SHCubemap::from_cubemap_equirectangular(&skytex, true, 100) {
|
||||
Renderer::skytex(skytex.tex);
|
||||
}
|
||||
}
|
||||
if let Some(skylight) = QUEUED_SKYLIGHT.lock().take() {
|
||||
if let Ok((skylight, _)) = sk.tex_create_cubemap_file(&skylight, true, i32::MAX) {
|
||||
sk.render_set_skylight(skylight);
|
||||
if let Ok(skylight) = SHCubemap::from_cubemap_equirectangular(&skylight, true, 100) {
|
||||
Renderer::skylight(skylight.sh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +1,54 @@
|
||||
use super::{MaterialParameter, ModelAspect, ModelPartAspect, Node};
|
||||
use crate::core::client::Client;
|
||||
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::spatial::Spatial;
|
||||
use crate::nodes::Aspect;
|
||||
use crate::SK_MULTITHREAD;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use glam::{Mat4, Vec2, Vec3};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
use rustc_hash::FxHashMap;
|
||||
use send_wrapper::SendWrapper;
|
||||
use stardust_xr::values::ResourceID;
|
||||
use stereokit_rust::material::Transparency;
|
||||
use stereokit_rust::maths::Bounds;
|
||||
use stereokit_rust::sk::MainThreadToken;
|
||||
use stereokit_rust::{material::Material, model::Model as SKModel, tex::Tex, util::Color128};
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Weak};
|
||||
use stereokit::named_colors::WHITE;
|
||||
use stereokit::{
|
||||
Bounds, Color128, Material, Model as SKModel, RenderLayer, Shader, StereoKitDraw,
|
||||
StereoKitMultiThread, Transparency,
|
||||
};
|
||||
|
||||
static MODEL_REGISTRY: Registry<Model> = Registry::new();
|
||||
static HOLDOUT_MATERIAL: OnceCell<Arc<Material>> = OnceCell::new();
|
||||
static HOLDOUT_MATERIAL: OnceCell<Arc<SendWrapper<Material>>> = OnceCell::new();
|
||||
|
||||
impl MaterialParameter {
|
||||
fn apply_to_material(
|
||||
&self,
|
||||
client: &Client,
|
||||
sk: &impl StereoKitMultiThread,
|
||||
material: &Material,
|
||||
parameter_name: &str,
|
||||
) {
|
||||
fn apply_to_material(&self, client: &Client, material: &Material, parameter_name: &str) {
|
||||
let mut params = material.get_all_param_info();
|
||||
match self {
|
||||
MaterialParameter::Bool(val) => {
|
||||
sk.material_set_bool(material, parameter_name, *val);
|
||||
params.set_bool(parameter_name, *val);
|
||||
}
|
||||
MaterialParameter::Int(val) => {
|
||||
sk.material_set_int(material, parameter_name, *val);
|
||||
params.set_int(parameter_name, &[*val]);
|
||||
}
|
||||
MaterialParameter::UInt(val) => {
|
||||
sk.material_set_uint(material, parameter_name, *val);
|
||||
params.set_uint(parameter_name, &[*val]);
|
||||
}
|
||||
MaterialParameter::Float(val) => {
|
||||
sk.material_set_float(material, parameter_name, *val);
|
||||
params.set_float(parameter_name, *val);
|
||||
}
|
||||
MaterialParameter::Vec2(val) => {
|
||||
sk.material_set_vector2(material, parameter_name, *val);
|
||||
params.set_vec2(parameter_name, Vec2::from(*val));
|
||||
}
|
||||
MaterialParameter::Vec3(val) => {
|
||||
sk.material_set_vector3(material, parameter_name, *val);
|
||||
params.set_vec3(parameter_name, Vec3::from(*val));
|
||||
}
|
||||
MaterialParameter::Color(val) => {
|
||||
sk.material_set_color(
|
||||
material,
|
||||
params.set_color(
|
||||
parameter_name,
|
||||
Color128::new(val.c.r, val.c.g, val.c.b, val.a),
|
||||
);
|
||||
@@ -66,8 +59,8 @@ impl MaterialParameter {
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if let Ok(tex) = sk.tex_create_file(texture_path, true, 0) {
|
||||
sk.material_set_texture(material, parameter_name, &tex);
|
||||
if let Ok(tex) = Tex::from_file(texture_path, true, None) {
|
||||
params.set_texture(parameter_name, &tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,57 +73,27 @@ pub struct ModelPart {
|
||||
space: Arc<Spatial>,
|
||||
model: Weak<Model>,
|
||||
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
|
||||
pending_material_replacement: Mutex<Option<Arc<Material>>>,
|
||||
pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>,
|
||||
}
|
||||
impl ModelPart {
|
||||
fn create_for_model(sk: &impl StereoKitMultiThread, model: &Arc<Model>, sk_model: &SKModel) {
|
||||
fn create_for_model(model: &Arc<Model>, sk_model: &SKModel) {
|
||||
HOLDOUT_MATERIAL.get_or_init(|| {
|
||||
let mat = sk.material_copy(Material::UNLIT);
|
||||
sk.material_set_transparency(&mat, Transparency::None);
|
||||
sk.material_set_color(
|
||||
&mat,
|
||||
"color",
|
||||
stereokit::sys::color128 {
|
||||
r: 0.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 0.0,
|
||||
},
|
||||
);
|
||||
Arc::new(mat)
|
||||
let mut mat = Material::copy(Material::unlit());
|
||||
mat.transparency(Transparency::None);
|
||||
mat.color_tint(Color128::BLACK_TRANSPARENT);
|
||||
Arc::new(SendWrapper::new(mat))
|
||||
});
|
||||
|
||||
let first_root_part = sk.model_node_get_root(sk_model);
|
||||
let mut current_option_part = Some(first_root_part);
|
||||
|
||||
while let Some(current_part) = &mut current_option_part {
|
||||
ModelPart::create(sk, model, sk_model, *current_part);
|
||||
|
||||
if let Some(child) = sk.model_node_child(sk_model, *current_part) {
|
||||
*current_part = child;
|
||||
} else if let Some(sibling) = sk.model_node_sibling(sk_model, *current_part) {
|
||||
*current_part = sibling;
|
||||
} else {
|
||||
while let Some(current_part) = &mut current_option_part {
|
||||
if let Some(sibling) = sk.model_node_sibling(sk_model, *current_part) {
|
||||
*current_part = sibling;
|
||||
break;
|
||||
}
|
||||
current_option_part = sk.model_node_parent(sk_model, *current_part);
|
||||
}
|
||||
}
|
||||
let nodes = sk_model.get_nodes();
|
||||
for part in nodes.all() {
|
||||
ModelPart::create(model, &part);
|
||||
}
|
||||
}
|
||||
|
||||
fn create(
|
||||
sk: &impl StereoKitMultiThread,
|
||||
model: &Arc<Model>,
|
||||
sk_model: &SKModel,
|
||||
id: i32,
|
||||
) -> Option<Arc<Self>> {
|
||||
let parent_node = sk
|
||||
.model_node_parent(sk_model, id)
|
||||
.and_then(|id| model.parts.get(&id));
|
||||
fn create(model: &Arc<Model>, part: &stereokit_rust::model::ModelNode) -> Option<Arc<Self>> {
|
||||
let parent_node = part
|
||||
.get_parent()
|
||||
.and_then(|part| model.parts.get(part.get_id()));
|
||||
let parent_part = parent_node
|
||||
.as_ref()
|
||||
.and_then(|node| node.get_aspect::<ModelPart>().ok());
|
||||
@@ -138,7 +101,8 @@ impl ModelPart {
|
||||
let stardust_model_part = model.space.node()?;
|
||||
let client = stardust_model_part.get_client()?;
|
||||
let mut part_path = parent_part.map(|n| n.path.clone()).unwrap_or_default();
|
||||
part_path.push(sk.model_node_get_name(sk_model, id)?);
|
||||
part_path.push(part.get_name().unwrap());
|
||||
|
||||
let node = client.scenegraph.add_node(Node::create_parent_name(
|
||||
&client,
|
||||
stardust_model_part.get_path(),
|
||||
@@ -148,10 +112,12 @@ impl ModelPart {
|
||||
let spatial_parent = parent_node
|
||||
.and_then(|n| n.get_aspect::<Spatial>().ok())
|
||||
.unwrap_or_else(|| model.space.clone());
|
||||
|
||||
let local_transform = unsafe { part.get_local_transform().m };
|
||||
let space = Spatial::add_to(
|
||||
&node,
|
||||
Some(spatial_parent),
|
||||
sk.model_node_get_transform_local(sk_model, id),
|
||||
Mat4::from_cols_array(&local_transform),
|
||||
false,
|
||||
);
|
||||
|
||||
@@ -163,23 +129,24 @@ impl ModelPart {
|
||||
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 {
|
||||
let nodes = sk_model.get_nodes();
|
||||
let Some(model_node) = nodes.get_index(model_part.id) else {
|
||||
return Bounds::default();
|
||||
};
|
||||
sk.mesh_get_bounds(sk_mesh)
|
||||
let Some(sk_mesh) = model_node.get_mesh() else {
|
||||
return Bounds::default();
|
||||
};
|
||||
sk_mesh.get_bounds()
|
||||
});
|
||||
|
||||
let model_part = Arc::new(ModelPart {
|
||||
id,
|
||||
id: *part.get_id(),
|
||||
path: part_path,
|
||||
space,
|
||||
model: Arc::downgrade(model),
|
||||
@@ -188,17 +155,31 @@ impl ModelPart {
|
||||
});
|
||||
<ModelPart as ModelPartAspect>::add_node_members(&node);
|
||||
node.add_aspect_raw(model_part.clone());
|
||||
model.parts.add(id, &node);
|
||||
model.parts.add(*part.get_id(), &node);
|
||||
Some(model_part)
|
||||
}
|
||||
|
||||
pub fn replace_material(&self, replacement: Arc<Material>) {
|
||||
pub fn replace_material(&self, replacement: Arc<SendWrapper<Material>>) {
|
||||
self.pending_material_replacement
|
||||
.lock()
|
||||
.replace(replacement);
|
||||
}
|
||||
/// only to be run on the main thread
|
||||
pub fn replace_material_now(&self, replacement: &Material) {
|
||||
let Some(model) = self.model.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(sk_model) = model.sk_model.get() else {
|
||||
return;
|
||||
};
|
||||
let nodes = sk_model.get_nodes();
|
||||
let Some(mut part) = nodes.get_index(self.id) else {
|
||||
return;
|
||||
};
|
||||
part.material(replacement);
|
||||
}
|
||||
|
||||
fn update(&self, sk: &impl StereoKitDraw) {
|
||||
fn update(&self) {
|
||||
let Some(model) = self.model.upgrade() else {
|
||||
return;
|
||||
};
|
||||
@@ -208,28 +189,37 @@ impl ModelPart {
|
||||
let Some(node) = model.space.node() else {
|
||||
return;
|
||||
};
|
||||
let nodes = sk_model.get_nodes();
|
||||
let Some(mut part) = nodes.get_index(self.id) else {
|
||||
return;
|
||||
};
|
||||
part.model_transform(Spatial::space_to_space_matrix(
|
||||
Some(&self.space),
|
||||
Some(&model.space),
|
||||
));
|
||||
|
||||
let Some(client) = node.get_client() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(material_replacement) = self.pending_material_replacement.lock().take() {
|
||||
sk.model_node_set_material(sk_model, self.id, material_replacement.as_ref().as_ref());
|
||||
part.material(&**material_replacement);
|
||||
}
|
||||
|
||||
let mut material_parameters = self.pending_material_parameters.lock();
|
||||
for (parameter_name, parameter_value) in material_parameters.drain() {
|
||||
let Some(material) = sk.model_node_get_material(sk_model, self.id) else {
|
||||
continue;
|
||||
};
|
||||
let new_material = sk.material_copy(material);
|
||||
parameter_value.apply_to_material(&client, sk, &new_material, parameter_name.as_str());
|
||||
sk.model_node_set_material(sk_model, self.id, &new_material);
|
||||
// todo: find all materials with identical parameters and batch them into 1 material again
|
||||
'mat_params: {
|
||||
let mut material_parameters = self.pending_material_parameters.lock();
|
||||
if !material_parameters.is_empty() {
|
||||
let Some(material) = part.get_material() else {
|
||||
break 'mat_params;
|
||||
};
|
||||
let new_material = Material::copy(&material);
|
||||
part.material(&new_material);
|
||||
for (parameter_name, parameter_value) in material_parameters.drain() {
|
||||
parameter_value.apply_to_material(&client, &new_material, ¶meter_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sk.model_node_set_transform_model(
|
||||
sk_model,
|
||||
self.id,
|
||||
Spatial::space_to_space_matrix(Some(&self.space), Some(&model.space)),
|
||||
);
|
||||
}
|
||||
}
|
||||
impl Aspect for ModelPart {
|
||||
@@ -261,15 +251,12 @@ impl ModelPartAspect for ModelPart {
|
||||
}
|
||||
|
||||
pub struct Model {
|
||||
self_ref: Weak<Model>,
|
||||
enabled: Arc<AtomicBool>,
|
||||
space: Arc<Spatial>,
|
||||
_resource_id: ResourceID,
|
||||
sk_model: OnceCell<SKModel>,
|
||||
parts: LifeLinkedNodeMap<i32>,
|
||||
}
|
||||
unsafe impl Send for Model {}
|
||||
unsafe impl Sync for Model {}
|
||||
|
||||
impl Model {
|
||||
pub fn add_to(node: &Arc<Node>, resource_id: ResourceID) -> Result<Arc<Model>> {
|
||||
@@ -280,8 +267,7 @@ impl Model {
|
||||
)
|
||||
.ok_or_else(|| eyre!("Resource not found"))?;
|
||||
|
||||
let model = Arc::new_cyclic(|self_ref| Model {
|
||||
self_ref: self_ref.clone(),
|
||||
let model = Arc::new(Model {
|
||||
enabled: node.enabled.clone(),
|
||||
space: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
_resource_id: resource_id,
|
||||
@@ -290,51 +276,50 @@ impl Model {
|
||||
});
|
||||
MODEL_REGISTRY.add_raw(&model);
|
||||
|
||||
let sk = SK_MULTITHREAD.get().unwrap();
|
||||
let sk_model = sk.model_copy(
|
||||
sk.model_create_file(pending_model_path.to_str().unwrap(), None::<Shader>)?,
|
||||
);
|
||||
ModelPart::create_for_model(sk, &model.self_ref.upgrade().unwrap(), &sk_model);
|
||||
// technically doing this in anything but the main thread isn't a good idea but dangit we need those model nodes ASAP
|
||||
let sk_model = SKModel::copy(SKModel::from_file(
|
||||
pending_model_path.to_str().unwrap(),
|
||||
None,
|
||||
)?);
|
||||
ModelPart::create_for_model(&model, &sk_model);
|
||||
let _ = model.sk_model.set(sk_model);
|
||||
node.add_aspect_raw(model.clone());
|
||||
Ok(model)
|
||||
}
|
||||
|
||||
fn draw(&self, sk: &impl StereoKitDraw) {
|
||||
fn draw(&self, token: &MainThreadToken) {
|
||||
let Some(sk_model) = self.sk_model.get() else {
|
||||
return;
|
||||
};
|
||||
for model_node_node in self.parts.nodes() {
|
||||
if let Ok(model_node) = model_node_node.get_aspect::<ModelPart>() {
|
||||
model_node.update(sk);
|
||||
model_node.update();
|
||||
};
|
||||
}
|
||||
|
||||
sk.model_draw(
|
||||
sk_model,
|
||||
self.space.global_transform(),
|
||||
WHITE,
|
||||
RenderLayer::LAYER0,
|
||||
);
|
||||
if self.enabled.load(Ordering::Relaxed) {
|
||||
sk_model.draw(token, self.space.global_transform(), None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: proper hread safety in stereokit_rust (probably just bind stereokit directly)
|
||||
unsafe impl Send for Model {}
|
||||
unsafe impl Sync for Model {}
|
||||
impl Aspect for Model {
|
||||
const NAME: &'static str = "Model";
|
||||
}
|
||||
impl ModelAspect for Model {}
|
||||
impl Drop for Model {
|
||||
fn drop(&mut self) {
|
||||
if let Some(sk_model) = self.sk_model.take() {
|
||||
destroy_queue::add(sk_model);
|
||||
}
|
||||
// if let Some(sk_model) = self.sk_model.take() {
|
||||
// destroy_queue::add(sk_model);
|
||||
// }
|
||||
MODEL_REGISTRY.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_all(sk: &impl StereoKitDraw) {
|
||||
pub fn draw_all(token: &MainThreadToken) {
|
||||
for model in MODEL_REGISTRY.get_valid_contents() {
|
||||
if model.enabled.load(Ordering::Relaxed) {
|
||||
model.draw(sk);
|
||||
}
|
||||
model.draw(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ use smithay::backend::renderer::gles::{
|
||||
GlesError,
|
||||
};
|
||||
use std::mem::transmute;
|
||||
use stereokit::Shader;
|
||||
use stereokit_rust::shader::Shader;
|
||||
use tracing::error;
|
||||
|
||||
// Simula shader with fancy lanzcos sampling
|
||||
pub const UNLIT_SHADER_BYTES: &[u8] = include_bytes!("shader_unlit_gamma.sks");
|
||||
pub const UNLIT_SHADER_BYTES: &[u8] = include_bytes!("assets/shaders/shader_unlit_gamma.hlsl.sks");
|
||||
|
||||
// Simula shader with fancy lanzcos sampling
|
||||
pub const PANEL_SHADER_BYTES: &[u8] = include_bytes!("shader_unlit_simula.sks");
|
||||
pub const PANEL_SHADER_BYTES: &[u8] = include_bytes!("assets/shaders/shader_unlit_simula.hlsl.sks");
|
||||
|
||||
struct FfiAssetHeader {
|
||||
asset_type: i32,
|
||||
Binary file not shown.
Binary file not shown.
@@ -8,8 +8,11 @@ use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
|
||||
use stereokit::{
|
||||
named_colors::WHITE, Color128, StereoKitDraw, TextAlign, TextFit, TextStyle as SkTextStyle,
|
||||
use stereokit_rust::{
|
||||
font::Font,
|
||||
sk::MainThreadToken,
|
||||
system::{TextAlign, TextFit, TextStyle as SkTextStyle},
|
||||
util::{Color128, Color32},
|
||||
};
|
||||
|
||||
use super::{TextAspect, TextStyle};
|
||||
@@ -18,13 +21,13 @@ static TEXT_REGISTRY: Registry<Text> = Registry::new();
|
||||
|
||||
fn convert_align(x_align: super::XAlign, y_align: super::YAlign) -> TextAlign {
|
||||
match (x_align, y_align) {
|
||||
(super::XAlign::Left, super::YAlign::Top) => TextAlign::Left,
|
||||
(super::XAlign::Left, super::YAlign::Top) => TextAlign::TopLeft,
|
||||
(super::XAlign::Left, super::YAlign::Center) => TextAlign::CenterLeft,
|
||||
(super::XAlign::Left, super::YAlign::Bottom) => TextAlign::BottomLeft,
|
||||
(super::XAlign::Center, super::YAlign::Top) => TextAlign::Center,
|
||||
(super::XAlign::Center, super::YAlign::Center) => TextAlign::Center,
|
||||
(super::XAlign::Center, super::YAlign::Bottom) => TextAlign::BottomCenter,
|
||||
(super::XAlign::Right, super::YAlign::Top) => TextAlign::Right,
|
||||
(super::XAlign::Right, super::YAlign::Top) => TextAlign::TopRight,
|
||||
(super::XAlign::Right, super::YAlign::Center) => TextAlign::CenterRight,
|
||||
(super::XAlign::Right, super::YAlign::Bottom) => TextAlign::BottomRight,
|
||||
}
|
||||
@@ -59,16 +62,16 @@ impl Text {
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
fn draw(&self, sk: &impl StereoKitDraw) {
|
||||
fn draw(&self, token: &MainThreadToken) {
|
||||
let style =
|
||||
self.style
|
||||
.get_or_try_init(|| -> Result<SkTextStyle, color_eyre::eyre::Error> {
|
||||
let font = self
|
||||
.font_path
|
||||
.as_deref()
|
||||
.and_then(|path| sk.font_create(path).ok())
|
||||
.unwrap_or_else(|| sk.font_find("default/font").unwrap());
|
||||
Ok(unsafe { sk.text_make_style(font, 1.0, WHITE) })
|
||||
.and_then(|path| Font::from_file(path).ok())
|
||||
.unwrap_or_default();
|
||||
Ok(SkTextStyle::from_font(font, 1.0, Color32::WHITE))
|
||||
});
|
||||
|
||||
if let Ok(style) = style {
|
||||
@@ -81,7 +84,8 @@ impl Text {
|
||||
data.character_height,
|
||||
));
|
||||
if let Some(bounds) = &data.bounds {
|
||||
sk.text_add_in(
|
||||
stereokit_rust::system::Text::add_in(
|
||||
token,
|
||||
&*text,
|
||||
transform,
|
||||
Vec2::from(bounds.bounds) / data.character_height,
|
||||
@@ -92,21 +96,40 @@ impl Text {
|
||||
super::TextFit::Exact => TextFit::Exact,
|
||||
super::TextFit::Overflow => TextFit::Overflow,
|
||||
},
|
||||
*style,
|
||||
convert_align(bounds.anchor_align_x, bounds.anchor_align_y),
|
||||
convert_align(data.text_align_x, data.text_align_y),
|
||||
vec3(0.0, 0.0, 0.0),
|
||||
Color128::from([data.color.c.r, data.color.c.g, data.color.c.b, data.color.a]),
|
||||
Some(style.clone()),
|
||||
Some(Color128::new(
|
||||
data.color.c.r,
|
||||
data.color.c.g,
|
||||
data.color.c.b,
|
||||
data.color.a,
|
||||
)),
|
||||
data.bounds
|
||||
.as_ref()
|
||||
.map(|b| convert_align(b.anchor_align_x, b.anchor_align_y)),
|
||||
Some(convert_align(data.text_align_x, data.text_align_y)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
sk.text_add_at(
|
||||
stereokit_rust::system::Text::add_at(
|
||||
token,
|
||||
&*text,
|
||||
transform,
|
||||
*style,
|
||||
TextAlign::Center,
|
||||
convert_align(data.text_align_x, data.text_align_y),
|
||||
vec3(0.0, 0.0, 0.0),
|
||||
Color128::from([data.color.c.r, data.color.c.g, data.color.c.b, data.color.a]),
|
||||
Some(*style),
|
||||
Some(Color128::new(
|
||||
data.color.c.r,
|
||||
data.color.c.g,
|
||||
data.color.c.b,
|
||||
data.color.a,
|
||||
)),
|
||||
data.bounds
|
||||
.as_ref()
|
||||
.map(|b| convert_align(b.anchor_align_x, b.anchor_align_y)),
|
||||
Some(convert_align(data.text_align_x, data.text_align_y)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -141,10 +164,10 @@ impl Drop for Text {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_all(sk: &impl StereoKitDraw) {
|
||||
pub fn draw_all(token: &MainThreadToken) {
|
||||
for text in TEXT_REGISTRY.get_valid_contents() {
|
||||
if text.enabled.load(Ordering::Relaxed) {
|
||||
text.draw(sk);
|
||||
text.draw(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{vec3, Mat4};
|
||||
use std::sync::Arc;
|
||||
use stereokit::StereoKitMultiThread;
|
||||
use stereokit_rust::system::Input;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref HMD: Arc<Node> = create();
|
||||
@@ -19,9 +19,9 @@ fn create() -> Arc<Node> {
|
||||
node
|
||||
}
|
||||
|
||||
pub fn frame(sk: &impl StereoKitMultiThread) {
|
||||
pub fn frame() {
|
||||
let spatial = HMD.get_aspect::<Spatial>().unwrap();
|
||||
let hmd_pose = sk.input_head();
|
||||
let hmd_pose = Input::get_head();
|
||||
*spatial.transform.lock() = Mat4::from_scale_rotation_translation(
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
hmd_pose.orientation.into(),
|
||||
|
||||
@@ -25,6 +25,7 @@ pub struct InputMethod {
|
||||
pub data: Mutex<InputDataType>,
|
||||
pub datamap: Mutex<Datamap>,
|
||||
|
||||
pub capture_requests: Registry<InputHandler>,
|
||||
pub captures: Registry<InputHandler>,
|
||||
pub(super) handler_aliases: LifeLinkedNodeMap<String>,
|
||||
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
|
||||
@@ -41,6 +42,7 @@ impl InputMethod {
|
||||
enabled: Mutex::new(true),
|
||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||
data: Mutex::new(data),
|
||||
capture_requests: Registry::new(),
|
||||
captures: Registry::new(),
|
||||
datamap: Mutex::new(datamap),
|
||||
handler_aliases: LifeLinkedNodeMap::default(),
|
||||
@@ -166,9 +168,7 @@ impl InputMethodRefAspect for InputMethod {
|
||||
let input_method = node.get_aspect::<InputMethod>()?;
|
||||
let input_handler = handler.get_aspect::<InputHandler>()?;
|
||||
|
||||
input_method.captures.add_raw(&input_handler);
|
||||
// input_method_client::
|
||||
// node.send_remote_signal("capture", message)
|
||||
input_method.capture_requests.add_raw(&input_handler);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,6 @@ pub fn process_input() {
|
||||
.collect()
|
||||
});
|
||||
|
||||
method.captures.clear();
|
||||
// Iterate over the distance links and send input to them
|
||||
for (i, input_link) in input_links.into_iter().enumerate() {
|
||||
if let Some(method_alias) = input_link
|
||||
@@ -165,8 +164,13 @@ pub fn process_input() {
|
||||
{
|
||||
method_alias.enabled.store(true, Ordering::Release);
|
||||
}
|
||||
input_link.send_input(i as u32, true, method.datamap.lock().clone());
|
||||
input_link.send_input(
|
||||
i as u32,
|
||||
method.captures.contains(&input_link.handler),
|
||||
method.datamap.lock().clone(),
|
||||
);
|
||||
}
|
||||
method.capture_requests.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,19 @@ use mint::{RowMatrix4, Vector2};
|
||||
use nanoid::nanoid;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use send_wrapper::SendWrapper;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::sync::Arc;
|
||||
use stereokit::{
|
||||
Color128, Material, Rect, RenderLayer, StereoKitDraw, Tex, TextureType, Transparency,
|
||||
use stereokit_rust::{
|
||||
material::{Material, Transparency},
|
||||
shader::Shader,
|
||||
sk::MainThreadToken,
|
||||
system::Renderer,
|
||||
tex::{Tex, TexFormat, TexType},
|
||||
util::Color128,
|
||||
};
|
||||
use tracing::error;
|
||||
|
||||
lazy_static! {
|
||||
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
|
||||
@@ -46,8 +53,8 @@ struct FrameInfo {
|
||||
pub struct CameraItem {
|
||||
space: Arc<Spatial>,
|
||||
frame_info: Mutex<FrameInfo>,
|
||||
sk_tex: OnceCell<Tex>,
|
||||
sk_mat: OnceCell<Arc<Material>>,
|
||||
sk_tex: OnceCell<SendWrapper<Tex>>,
|
||||
sk_mat: OnceCell<Arc<SendWrapper<Material>>>,
|
||||
applied_to: Registry<ModelPart>,
|
||||
apply_to: Registry<ModelPart>,
|
||||
}
|
||||
@@ -111,52 +118,54 @@ impl CameraItem {
|
||||
Ok(serialize(id)?.into())
|
||||
}
|
||||
|
||||
pub fn update(&self, sk: &impl StereoKitDraw) {
|
||||
pub fn update(&self, token: &MainThreadToken) {
|
||||
let frame_info = self.frame_info.lock();
|
||||
let sk_tex = self.sk_tex.get_or_init(|| {
|
||||
sk.tex_gen_color(
|
||||
SendWrapper::new(Tex::gen_color(
|
||||
Color128::default(),
|
||||
frame_info.px_size.x as i32,
|
||||
frame_info.px_size.y as i32,
|
||||
TextureType::RENDER_TARGET,
|
||||
stereokit::TextureFormat::RGBA32Linear,
|
||||
)
|
||||
});
|
||||
let sk_mat = self.sk_mat.get_or_init(|| {
|
||||
let shader = sk.shader_create_mem(&UNLIT_SHADER_BYTES).unwrap();
|
||||
let mat = sk.material_create(&shader);
|
||||
sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref());
|
||||
sk.material_set_transparency(&mat, Transparency::Blend);
|
||||
Arc::new(mat)
|
||||
TexType::Rendertarget,
|
||||
TexFormat::RGBA32Linear,
|
||||
))
|
||||
});
|
||||
let sk_mat = self
|
||||
.sk_mat
|
||||
.get_or_try_init(|| -> Result<Arc<SendWrapper<Material>>> {
|
||||
let shader = Shader::from_memory(&UNLIT_SHADER_BYTES)?;
|
||||
let mut mat = Material::new(&shader, None);
|
||||
mat.get_all_param_info().set_texture("diffuse", &**sk_tex);
|
||||
mat.transparency(Transparency::Blend);
|
||||
Ok(Arc::new(SendWrapper::new(mat)))
|
||||
});
|
||||
let Ok(sk_mat) = sk_mat else {
|
||||
error!("unable to make camera item stereokit texture");
|
||||
return;
|
||||
};
|
||||
for model_part in self.apply_to.take_valid_contents() {
|
||||
model_part.replace_material(sk_mat.clone())
|
||||
}
|
||||
|
||||
if !self.applied_to.is_empty() {
|
||||
sk.render_to(
|
||||
sk_tex,
|
||||
frame_info.proj_matrix,
|
||||
Renderer::render_to(
|
||||
token,
|
||||
&**sk_tex,
|
||||
self.space.global_transform(),
|
||||
RenderLayer::all(),
|
||||
stereokit::RenderClear::All,
|
||||
Rect {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
w: 0.0,
|
||||
h: 0.0,
|
||||
},
|
||||
);
|
||||
frame_info.proj_matrix,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(sk: &impl StereoKitDraw) {
|
||||
pub fn update(token: &MainThreadToken) {
|
||||
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
|
||||
let ItemType::Camera(camera) = &camera.specialization else {
|
||||
continue;
|
||||
};
|
||||
camera.update(sk);
|
||||
camera.update(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::core::client::Client;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::create_interface;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use glam::{vec3a, Mat4, Quat};
|
||||
use glam::{vec3a, Mat4, Quat, Vec3};
|
||||
use mint::Vector3;
|
||||
use nanoid::nanoid;
|
||||
use once_cell::sync::OnceCell;
|
||||
@@ -15,7 +15,7 @@ use parking_lot::Mutex;
|
||||
use std::fmt::Debug;
|
||||
use std::ptr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use stereokit::{bounds_grow_to_fit_box, Bounds};
|
||||
use stereokit_rust::maths::Bounds;
|
||||
|
||||
stardust_xr_server_codegen::codegen_spatial_protocol!();
|
||||
impl Transform {
|
||||
@@ -104,11 +104,7 @@ impl Spatial {
|
||||
.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.grown_box(child.get_bounding_box(), child.local_transform());
|
||||
}
|
||||
bounds
|
||||
}
|
||||
@@ -253,8 +249,8 @@ impl SpatialRefAspect for Spatial {
|
||||
let bounds = this_spatial.get_bounding_box();
|
||||
|
||||
Ok(BoundingBox {
|
||||
center: mint::Vector3::from(bounds.center),
|
||||
size: mint::Vector3::from(bounds.dimensions),
|
||||
center: Vec3::from(bounds.center).into(),
|
||||
size: Vec3::from(bounds.dimensions).into(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -267,21 +263,18 @@ impl SpatialRefAspect for 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_grow_to_fit_box(
|
||||
Bounds {
|
||||
center,
|
||||
dimensions: [0.0; 3].into(),
|
||||
},
|
||||
let mut bounds = Bounds {
|
||||
center: center.into(),
|
||||
dimensions: [0.0; 3].into(),
|
||||
};
|
||||
bounds.grown_box(
|
||||
this_spatial.get_bounding_box(),
|
||||
Some(Spatial::space_to_space_matrix(
|
||||
Some(&this_spatial),
|
||||
Some(&relative_spatial),
|
||||
)),
|
||||
Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial)),
|
||||
);
|
||||
|
||||
Ok(BoundingBox {
|
||||
center: mint::Vector3::from(bounds.center),
|
||||
size: mint::Vector3::from(bounds.dimensions),
|
||||
center: Vec3::from(bounds.center).into(),
|
||||
size: Vec3::from(bounds.dimensions).into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user