feat: upgrade stereokit
This commit is contained in:
1048
Cargo.lock
generated
1048
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@ lto = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
color-eyre = { version = "0.6.2", default-features = false }
|
color-eyre = { version = "0.6.2", default-features = false }
|
||||||
clap = { version = "4.2.4", features = ["derive"] }
|
clap = { version = "4.2.4", features = ["derive"] }
|
||||||
glam = { version = "0.23.0", features = ["mint"] }
|
glam = { version = "0.27.0", features = ["mint", "serde"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
mint = "0.5.9"
|
mint = "0.5.9"
|
||||||
nanoid = "0.4.0"
|
nanoid = "0.4.0"
|
||||||
@@ -84,13 +84,10 @@ features = [
|
|||||||
"renderer_gl",
|
"renderer_gl",
|
||||||
"wayland_frontend",
|
"wayland_frontend",
|
||||||
]
|
]
|
||||||
version = "*"
|
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.stereokit]
|
[dependencies.stereokit-rust]
|
||||||
default-features = false
|
git = "https://github.com/mvvvv/StereoKit-rust.git"
|
||||||
features = ["linux-egl"]
|
|
||||||
version = "0.16.9"
|
|
||||||
|
|
||||||
[dependencies.console-subscriber]
|
[dependencies.console-subscriber]
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|||||||
142
src/main.rs
142
src/main.rs
@@ -26,11 +26,15 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::process::{Child, Command, Stdio};
|
use std::process::{Child, Command, Stdio};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use stereokit::{
|
use stereokit_rust::material::Material;
|
||||||
named_colors::BLACK, DepthMode, DisplayMode, Handed, LogLevel, StereoKitMultiThread,
|
use stereokit_rust::shader::Shader;
|
||||||
TextureFormat, TextureType,
|
use stereokit_rust::sk::{
|
||||||
|
sk_quit, AppMode, DepthMode, DisplayBlend, DisplayMode, QuitReason, SkClosures, SkSettings,
|
||||||
};
|
};
|
||||||
use stereokit::{DisplayBlend, Sk};
|
use stereokit_rust::system::{Handed, LogLevel, Renderer, World};
|
||||||
|
use stereokit_rust::tex::{SHCubemap, Tex, TexFormat, TexType};
|
||||||
|
use stereokit_rust::ui::Ui;
|
||||||
|
use stereokit_rust::util::{Color128, Device, Time};
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
use tokio::task::LocalSet;
|
use tokio::task::LocalSet;
|
||||||
use tokio::{runtime::Handle, sync::oneshot};
|
use tokio::{runtime::Handle, sync::oneshot};
|
||||||
@@ -63,7 +67,6 @@ struct CliArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static STARDUST_INSTANCE: OnceCell<String> = OnceCell::new();
|
static STARDUST_INSTANCE: OnceCell<String> = OnceCell::new();
|
||||||
static SK_MULTITHREAD: OnceCell<Sk> = OnceCell::new();
|
|
||||||
static STOP_NOTIFIER: Notify = Notify::const_new();
|
static STOP_NOTIFIER: Notify = Notify::const_new();
|
||||||
|
|
||||||
struct EventLoopInfo {
|
struct EventLoopInfo {
|
||||||
@@ -102,16 +105,16 @@ fn main() {
|
|||||||
}
|
}
|
||||||
let cli_args = Arc::new(CliArgs::parse());
|
let cli_args = Arc::new(CliArgs::parse());
|
||||||
|
|
||||||
let sk = stereokit::Settings {
|
let (sk, sk_event_loop) = SkSettings::default()
|
||||||
app_name: "Stardust XR".to_string(),
|
.app_name("Stardust XR")
|
||||||
display_preference: if cli_args.flatscreen {
|
.mode(if cli_args.flatscreen {
|
||||||
DisplayMode::Flatscreen
|
AppMode::Simulator
|
||||||
} else {
|
} else {
|
||||||
DisplayMode::MixedReality
|
AppMode::XR
|
||||||
},
|
})
|
||||||
blend_preference: DisplayBlend::AnyTransparent,
|
.blend_preference(DisplayBlend::AnyTransparent)
|
||||||
depth_mode: DepthMode::D32,
|
.depth_mode(DepthMode::D32)
|
||||||
log_filter: match EnvFilter::from_default_env().max_level_hint() {
|
.log_filter(match EnvFilter::from_default_env().max_level_hint() {
|
||||||
Some(LevelFilter::ERROR) => LogLevel::Error,
|
Some(LevelFilter::ERROR) => LogLevel::Error,
|
||||||
Some(LevelFilter::WARN) => LogLevel::Warning,
|
Some(LevelFilter::WARN) => LogLevel::Warning,
|
||||||
Some(LevelFilter::INFO) => LogLevel::Inform,
|
Some(LevelFilter::INFO) => LogLevel::Inform,
|
||||||
@@ -119,46 +122,35 @@ fn main() {
|
|||||||
Some(LevelFilter::TRACE) => LogLevel::Diagnostic,
|
Some(LevelFilter::TRACE) => LogLevel::Diagnostic,
|
||||||
Some(LevelFilter::OFF) => LogLevel::None,
|
Some(LevelFilter::OFF) => LogLevel::None,
|
||||||
None => LogLevel::Warning,
|
None => LogLevel::Warning,
|
||||||
},
|
})
|
||||||
overlay_app: cli_args.overlay_priority.is_some(),
|
.overlay_app(cli_args.overlay_priority.is_some())
|
||||||
overlay_priority: cli_args.overlay_priority.unwrap_or(u32::MAX),
|
.overlay_priority(cli_args.overlay_priority.unwrap_or(u32::MAX))
|
||||||
disable_desktop_input_window: true,
|
.disable_desktop_input_window(true)
|
||||||
render_scaling: 2.0,
|
.render_scaling(2.0)
|
||||||
..Default::default()
|
.init()
|
||||||
}
|
.expect("StereoKit failed to initialize");
|
||||||
.init()
|
|
||||||
.expect("StereoKit failed to initialize");
|
|
||||||
let _ = SK_MULTITHREAD.set(sk.multithreaded());
|
|
||||||
info!("Init StereoKit");
|
info!("Init StereoKit");
|
||||||
|
|
||||||
sk.render_set_multisample(0);
|
Renderer::multisample(0);
|
||||||
|
Material::default().shader(Shader::pbr_clip());
|
||||||
sk.material_set_shader(
|
Ui::enable_far_interact(false);
|
||||||
sk.material_find("default/material_pbr").unwrap(),
|
|
||||||
sk.shader_find("default/shader_pbr_clip").unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Skytex/light stuff
|
// Skytex/light stuff
|
||||||
{
|
{
|
||||||
if let Some((light, tex)) = project_dirs
|
if let Some(sky) = project_dirs
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|dirs| {
|
.map(|dirs| dirs.config_dir().join("skytex.hdr"))
|
||||||
let skytex_path = dirs.config_dir().join("skytex.hdr");
|
.filter(|f| f.exists())
|
||||||
skytex_path
|
.and_then(|p| SHCubemap::from_cubemap_equirectangular(p, true, 100).ok())
|
||||||
.exists()
|
|
||||||
.then(|| sk.tex_create_cubemap_file(&skytex_path, true, 100).ok())
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
{
|
{
|
||||||
sk.render_set_skytex(&tex);
|
sky.render_as_sky();
|
||||||
sk.render_set_skylight(light);
|
|
||||||
} else {
|
} else {
|
||||||
sk.render_set_skytex(sk.tex_gen_color(
|
Renderer::skytex(Tex::gen_color(
|
||||||
BLACK,
|
Color128::BLACK,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
TextureType::CUBEMAP,
|
TexType::Cubemap,
|
||||||
TextureFormat::RGBA32,
|
TexFormat::RGBA32,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,33 +162,25 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let mut hands = (!cli_args.flatscreen)
|
let mut hands = (!cli_args.flatscreen)
|
||||||
.then(|| {
|
.then(|| {
|
||||||
let left = SkHand::new(Handed::Left, &sk).ok();
|
let left = SkHand::new(Handed::Left).ok();
|
||||||
let right = SkHand::new(Handed::Right, &sk).ok();
|
let right = SkHand::new(Handed::Right).ok();
|
||||||
left.zip(right)
|
left.zip(right)
|
||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
let mut controllers = (!cli_args.flatscreen && !cli_args.disable_controller)
|
let mut controllers = (!cli_args.flatscreen && !cli_args.disable_controller)
|
||||||
.then(|| {
|
.then(|| {
|
||||||
let left = SkController::new(&sk, Handed::Left).ok();
|
let left = SkController::new(Handed::Left).ok();
|
||||||
let right = SkController::new(&sk, Handed::Right).ok();
|
let right = SkController::new(Handed::Right).ok();
|
||||||
left.zip(right)
|
left.zip(right)
|
||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
let eye_pointer = (sk.active_display_mode() == DisplayMode::MixedReality
|
let eye_pointer = (sk.get_active_display_mode() == DisplayMode::MixedReality
|
||||||
&& sk.device_has_eye_gaze())
|
&& Device::has_eye_gaze())
|
||||||
.then(EyePointer::new)
|
.then(EyePointer::new)
|
||||||
.transpose()
|
.transpose()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if hands.is_none() {
|
let play_space = World::has_bounds().then(|| PlaySpace::new().ok()).flatten();
|
||||||
sk.input_hand_visible(Handed::Left, false);
|
|
||||||
sk.input_hand_visible(Handed::Right, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
let play_space = sk
|
|
||||||
.world_has_bounds()
|
|
||||||
.then(|| PlaySpace::new().ok())
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
let (info_sender, info_receiver) = oneshot::channel::<EventLoopInfo>();
|
let (info_sender, info_receiver) = oneshot::channel::<EventLoopInfo>();
|
||||||
let event_thread = std::thread::Builder::new()
|
let event_thread = std::thread::Builder::new()
|
||||||
@@ -229,47 +213,48 @@ fn main() {
|
|||||||
let mut last_frame_delta = Duration::ZERO;
|
let mut last_frame_delta = Duration::ZERO;
|
||||||
let mut sleep_duration = Duration::ZERO;
|
let mut sleep_duration = Duration::ZERO;
|
||||||
debug_span!("StereoKit").in_scope(|| {
|
debug_span!("StereoKit").in_scope(|| {
|
||||||
sk.run(
|
SkClosures::run_app(
|
||||||
|sk| {
|
sk,
|
||||||
|
sk_event_loop,
|
||||||
|
|_sk, token| {
|
||||||
let _span = debug_span!("StereoKit step");
|
let _span = debug_span!("StereoKit step");
|
||||||
let _span = _span.enter();
|
let _span = _span.enter();
|
||||||
|
|
||||||
hmd::frame(sk);
|
hmd::frame();
|
||||||
camera::update(sk);
|
camera::update(token);
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
wayland.frame_event(sk);
|
wayland.frame_event();
|
||||||
destroy_queue::clear();
|
destroy_queue::clear();
|
||||||
|
|
||||||
if let Some(mouse_pointer) = &mut mouse_pointer {
|
if let Some(mouse_pointer) = &mut mouse_pointer {
|
||||||
mouse_pointer.update(sk);
|
mouse_pointer.update();
|
||||||
}
|
}
|
||||||
if let Some((left_hand, right_hand)) = &mut hands {
|
if let Some((left_hand, right_hand)) = &mut hands {
|
||||||
left_hand.update(!cli_args.disable_controller, sk);
|
left_hand.update(!cli_args.disable_controller, token);
|
||||||
right_hand.update(!cli_args.disable_controller, sk);
|
right_hand.update(!cli_args.disable_controller, token);
|
||||||
}
|
}
|
||||||
if let Some((left_controller, right_controller)) = &mut controllers {
|
if let Some((left_controller, right_controller)) = &mut controllers {
|
||||||
left_controller.update(sk);
|
left_controller.update(token);
|
||||||
right_controller.update(sk);
|
right_controller.update(token);
|
||||||
}
|
}
|
||||||
if let Some(eye_pointer) = &eye_pointer {
|
if let Some(eye_pointer) = &eye_pointer {
|
||||||
eye_pointer.update(sk);
|
eye_pointer.update();
|
||||||
}
|
}
|
||||||
if let Some(play_space) = &play_space {
|
if let Some(play_space) = &play_space {
|
||||||
play_space.update(sk);
|
play_space.update();
|
||||||
}
|
}
|
||||||
input::process_input();
|
input::process_input();
|
||||||
nodes::root::Root::send_frame_events(sk.time_elapsed_unscaled());
|
nodes::root::Root::send_frame_events(Time::get_step_unscaled());
|
||||||
adaptive_sleep(
|
adaptive_sleep(
|
||||||
sk,
|
|
||||||
&mut last_frame_delta,
|
&mut last_frame_delta,
|
||||||
&mut sleep_duration,
|
&mut sleep_duration,
|
||||||
Duration::from_micros(250),
|
Duration::from_micros(250),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
wayland.update(sk);
|
wayland.update();
|
||||||
drawable::draw(sk);
|
drawable::draw(token);
|
||||||
audio::update(sk);
|
audio::update();
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
wayland.make_context_current();
|
wayland.make_context_current();
|
||||||
},
|
},
|
||||||
@@ -295,12 +280,11 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn adaptive_sleep(
|
fn adaptive_sleep(
|
||||||
sk: &impl StereoKitMultiThread,
|
|
||||||
last_frame_delta: &mut Duration,
|
last_frame_delta: &mut Duration,
|
||||||
sleep_duration: &mut Duration,
|
sleep_duration: &mut Duration,
|
||||||
sleep_duration_increase: Duration,
|
sleep_duration_increase: Duration,
|
||||||
) {
|
) {
|
||||||
let frame_delta = Duration::from_secs_f64(sk.time_elapsed_unscaled());
|
let frame_delta = Duration::from_secs_f64(Time::get_step_unscaled());
|
||||||
if *last_frame_delta < frame_delta {
|
if *last_frame_delta < frame_delta {
|
||||||
if let Some(frame_delta_delta) = frame_delta.checked_sub(*last_frame_delta) {
|
if let Some(frame_delta_delta) = frame_delta.checked_sub(*last_frame_delta) {
|
||||||
if let Some(new_sleep_duration) = sleep_duration.checked_sub(frame_delta_delta) {
|
if let Some(new_sleep_duration) = sleep_duration.checked_sub(frame_delta_delta) {
|
||||||
@@ -346,7 +330,7 @@ async fn event_loop(
|
|||||||
info!("Cleanly shut down event loop");
|
info!("Cleanly shut down event loop");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
stereokit::sys::sk_quit();
|
sk_quit(QuitReason::SystemClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use stardust_xr::values::ResourceID;
|
|||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{ffi::OsStr, path::PathBuf};
|
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();
|
static SOUND_REGISTRY: Registry<Sound> = Registry::new();
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ pub struct Sound {
|
|||||||
volume: f32,
|
volume: f32,
|
||||||
pending_audio_path: PathBuf,
|
pending_audio_path: PathBuf,
|
||||||
sk_sound: OnceCell<SendWrapper<SkSound>>,
|
sk_sound: OnceCell<SendWrapper<SkSound>>,
|
||||||
instance: Mutex<Option<SoundInstance>>,
|
instance: Mutex<Option<SoundInst>>,
|
||||||
stop: Mutex<Option<()>>,
|
stop: Mutex<Option<()>>,
|
||||||
play: Mutex<Option<()>>,
|
play: Mutex<Option<()>>,
|
||||||
}
|
}
|
||||||
@@ -53,24 +53,21 @@ impl Sound {
|
|||||||
Ok(sound_arc)
|
Ok(sound_arc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&self, sk: &impl StereoKitDraw) {
|
fn update(&self) {
|
||||||
let sound = self.sk_sound.get_or_init(|| {
|
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 self.stop.lock().take().is_some() {
|
||||||
if let Some(instance) = self.instance.lock().take() {
|
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() {
|
if self.instance.lock().is_none() && self.play.lock().take().is_some() {
|
||||||
self.instance.lock().replace(sk.sound_play(
|
let instance = sound.play(vec3(0.0, 0.0, 0.0), Some(self.volume));
|
||||||
sound.as_ref(),
|
self.instance.lock().replace(instance);
|
||||||
vec3(0.0, 0.0, 0.0),
|
|
||||||
self.volume,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if let Some(instance) = self.instance.lock().deref_mut() {
|
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() {
|
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},
|
nodes::{spatial::Spatial, Aspect, Node},
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use glam::Vec3A;
|
use glam::Vec3;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use portable_atomic::{AtomicBool, Ordering};
|
use portable_atomic::{AtomicBool, Ordering};
|
||||||
use prisma::Lerp;
|
use prisma::Lerp;
|
||||||
use std::{collections::VecDeque, sync::Arc};
|
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();
|
static LINES_REGISTRY: Registry<Lines> = Registry::new();
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ impl Lines {
|
|||||||
if let Ok(lines) = node.get_aspect::<Lines>() {
|
if let Ok(lines) = node.get_aspect::<Lines>() {
|
||||||
for line in &*lines.data.lock() {
|
for line in &*lines.data.lock() {
|
||||||
for point in &line.points {
|
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)
|
Ok(lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, draw_ctx: &impl StereoKitDraw) {
|
fn draw(&self, token: &MainThreadToken) {
|
||||||
let transform_mat = self.space.global_transform();
|
let transform_mat = self.space.global_transform();
|
||||||
let data = self.data.lock().clone();
|
let data = self.data.lock().clone();
|
||||||
for line in &data {
|
for line in &data {
|
||||||
@@ -55,15 +57,9 @@ impl Lines {
|
|||||||
.points
|
.points
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| SkLinePoint {
|
.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,
|
thickness: p.thickness,
|
||||||
color: stereokit::sys::color128::from([
|
color: Color128::new(p.color.c.r, p.color.c.g, p.color.c.b, p.color.a).into(),
|
||||||
p.color.c.r,
|
|
||||||
p.color.c.g,
|
|
||||||
p.color.c.b,
|
|
||||||
p.color.a,
|
|
||||||
])
|
|
||||||
.into(),
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if line.cyclic && !points.is_empty() {
|
if line.cyclic && !points.is_empty() {
|
||||||
@@ -78,9 +74,7 @@ impl Lines {
|
|||||||
};
|
};
|
||||||
let connect_point = SkLinePoint {
|
let connect_point = SkLinePoint {
|
||||||
pt: transform_mat
|
pt: transform_mat
|
||||||
.transform_point3a(
|
.transform_point3(Vec3::from(first.point).lerp(Vec3::from(last.point), 0.5))
|
||||||
Vec3A::from(first.point).lerp(Vec3A::from(last.point), 0.5),
|
|
||||||
)
|
|
||||||
.into(),
|
.into(),
|
||||||
thickness: (first.thickness + last.thickness) * 0.5,
|
thickness: (first.thickness + last.thickness) * 0.5,
|
||||||
color: color.into(),
|
color: color.into(),
|
||||||
@@ -88,7 +82,7 @@ impl Lines {
|
|||||||
points.push_front(connect_point.clone());
|
points.push_front(connect_point.clone());
|
||||||
points.push_back(connect_point);
|
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() {
|
for lines in LINES_REGISTRY.get_valid_contents() {
|
||||||
if lines.enabled.load(Ordering::Relaxed) {
|
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 parking_lot::Mutex;
|
||||||
use stardust_xr::values::ResourceID;
|
use stardust_xr::values::ResourceID;
|
||||||
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
|
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))]
|
// #[instrument(level = "debug", skip(sk))]
|
||||||
pub fn draw(sk: &impl StereoKitDraw) {
|
pub fn draw(token: &MainThreadToken) {
|
||||||
lines::draw_all(sk);
|
lines::draw_all(token);
|
||||||
model::draw_all(sk);
|
model::draw_all(token);
|
||||||
text::draw_all(sk);
|
text::draw_all(token);
|
||||||
|
|
||||||
if let Some(skytex) = QUEUED_SKYTEX.lock().take() {
|
if let Some(skytex) = QUEUED_SKYTEX.lock().take() {
|
||||||
if let Ok((_skylight, skytex)) = sk.tex_create_cubemap_file(&skytex, true, i32::MAX) {
|
if let Ok(skytex) = SHCubemap::from_cubemap_equirectangular(&skytex, true, 100) {
|
||||||
sk.render_set_skytex(&skytex);
|
Renderer::skytex(skytex.tex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(skylight) = QUEUED_SKYLIGHT.lock().take() {
|
if let Some(skylight) = QUEUED_SKYLIGHT.lock().take() {
|
||||||
if let Ok((skylight, _)) = sk.tex_create_cubemap_file(&skylight, true, i32::MAX) {
|
if let Ok(skylight) = SHCubemap::from_cubemap_equirectangular(&skylight, true, 100) {
|
||||||
sk.render_set_skylight(skylight);
|
Renderer::skylight(skylight.sh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,54 @@
|
|||||||
use super::{MaterialParameter, ModelAspect, ModelPartAspect, Node};
|
use super::{MaterialParameter, ModelAspect, ModelPartAspect, Node};
|
||||||
use crate::core::client::Client;
|
use crate::core::client::Client;
|
||||||
use crate::core::destroy_queue;
|
|
||||||
use crate::core::node_collections::LifeLinkedNodeMap;
|
use crate::core::node_collections::LifeLinkedNodeMap;
|
||||||
use crate::core::registry::Registry;
|
use crate::core::registry::Registry;
|
||||||
use crate::core::resource::get_resource_file;
|
use crate::core::resource::get_resource_file;
|
||||||
use crate::nodes::spatial::Spatial;
|
use crate::nodes::spatial::Spatial;
|
||||||
use crate::nodes::Aspect;
|
use crate::nodes::Aspect;
|
||||||
use crate::SK_MULTITHREAD;
|
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
|
use glam::{Mat4, Vec2, Vec3};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use portable_atomic::{AtomicBool, Ordering};
|
use portable_atomic::{AtomicBool, Ordering};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use stardust_xr::values::ResourceID;
|
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::ffi::OsStr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Weak};
|
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 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 {
|
impl MaterialParameter {
|
||||||
fn apply_to_material(
|
fn apply_to_material(&self, client: &Client, material: &Material, parameter_name: &str) {
|
||||||
&self,
|
let mut params = material.get_all_param_info();
|
||||||
client: &Client,
|
|
||||||
sk: &impl StereoKitMultiThread,
|
|
||||||
material: &Material,
|
|
||||||
parameter_name: &str,
|
|
||||||
) {
|
|
||||||
match self {
|
match self {
|
||||||
MaterialParameter::Bool(val) => {
|
MaterialParameter::Bool(val) => {
|
||||||
sk.material_set_bool(material, parameter_name, *val);
|
params.set_bool(parameter_name, *val);
|
||||||
}
|
}
|
||||||
MaterialParameter::Int(val) => {
|
MaterialParameter::Int(val) => {
|
||||||
sk.material_set_int(material, parameter_name, *val);
|
params.set_int(parameter_name, &[*val]);
|
||||||
}
|
}
|
||||||
MaterialParameter::UInt(val) => {
|
MaterialParameter::UInt(val) => {
|
||||||
sk.material_set_uint(material, parameter_name, *val);
|
params.set_uint(parameter_name, &[*val]);
|
||||||
}
|
}
|
||||||
MaterialParameter::Float(val) => {
|
MaterialParameter::Float(val) => {
|
||||||
sk.material_set_float(material, parameter_name, *val);
|
params.set_float(parameter_name, *val);
|
||||||
}
|
}
|
||||||
MaterialParameter::Vec2(val) => {
|
MaterialParameter::Vec2(val) => {
|
||||||
sk.material_set_vector2(material, parameter_name, *val);
|
params.set_vec2(parameter_name, Vec2::from(*val));
|
||||||
}
|
}
|
||||||
MaterialParameter::Vec3(val) => {
|
MaterialParameter::Vec3(val) => {
|
||||||
sk.material_set_vector3(material, parameter_name, *val);
|
params.set_vec3(parameter_name, Vec3::from(*val));
|
||||||
}
|
}
|
||||||
MaterialParameter::Color(val) => {
|
MaterialParameter::Color(val) => {
|
||||||
sk.material_set_color(
|
params.set_color(
|
||||||
material,
|
|
||||||
parameter_name,
|
parameter_name,
|
||||||
Color128::new(val.c.r, val.c.g, val.c.b, val.a),
|
Color128::new(val.c.r, val.c.g, val.c.b, val.a),
|
||||||
);
|
);
|
||||||
@@ -66,8 +59,8 @@ impl MaterialParameter {
|
|||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if let Ok(tex) = sk.tex_create_file(texture_path, true, 0) {
|
if let Ok(tex) = Tex::from_file(texture_path, true, None) {
|
||||||
sk.material_set_texture(material, parameter_name, &tex);
|
params.set_texture(parameter_name, &tex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,57 +73,27 @@ pub struct ModelPart {
|
|||||||
space: Arc<Spatial>,
|
space: Arc<Spatial>,
|
||||||
model: Weak<Model>,
|
model: Weak<Model>,
|
||||||
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
|
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
|
||||||
pending_material_replacement: Mutex<Option<Arc<Material>>>,
|
pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>,
|
||||||
}
|
}
|
||||||
impl ModelPart {
|
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(|| {
|
HOLDOUT_MATERIAL.get_or_init(|| {
|
||||||
let mat = sk.material_copy(Material::UNLIT);
|
let mut mat = Material::copy(Material::unlit());
|
||||||
sk.material_set_transparency(&mat, Transparency::None);
|
mat.transparency(Transparency::None);
|
||||||
sk.material_set_color(
|
mat.color_tint(Color128::BLACK_TRANSPARENT);
|
||||||
&mat,
|
Arc::new(SendWrapper::new(mat))
|
||||||
"color",
|
|
||||||
stereokit::sys::color128 {
|
|
||||||
r: 0.0,
|
|
||||||
g: 0.0,
|
|
||||||
b: 0.0,
|
|
||||||
a: 0.0,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Arc::new(mat)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let first_root_part = sk.model_node_get_root(sk_model);
|
let nodes = sk_model.get_nodes();
|
||||||
let mut current_option_part = Some(first_root_part);
|
for part in nodes.all() {
|
||||||
|
ModelPart::create(model, &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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(
|
fn create(model: &Arc<Model>, part: &stereokit_rust::model::ModelNode) -> Option<Arc<Self>> {
|
||||||
sk: &impl StereoKitMultiThread,
|
let parent_node = part
|
||||||
model: &Arc<Model>,
|
.get_parent()
|
||||||
sk_model: &SKModel,
|
.and_then(|part| model.parts.get(part.get_id()));
|
||||||
id: i32,
|
|
||||||
) -> Option<Arc<Self>> {
|
|
||||||
let parent_node = sk
|
|
||||||
.model_node_parent(sk_model, id)
|
|
||||||
.and_then(|id| model.parts.get(&id));
|
|
||||||
let parent_part = parent_node
|
let parent_part = parent_node
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|node| node.get_aspect::<ModelPart>().ok());
|
.and_then(|node| node.get_aspect::<ModelPart>().ok());
|
||||||
@@ -138,7 +101,8 @@ impl ModelPart {
|
|||||||
let stardust_model_part = model.space.node()?;
|
let stardust_model_part = model.space.node()?;
|
||||||
let client = stardust_model_part.get_client()?;
|
let client = stardust_model_part.get_client()?;
|
||||||
let mut part_path = parent_part.map(|n| n.path.clone()).unwrap_or_default();
|
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(
|
let node = client.scenegraph.add_node(Node::create_parent_name(
|
||||||
&client,
|
&client,
|
||||||
stardust_model_part.get_path(),
|
stardust_model_part.get_path(),
|
||||||
@@ -148,10 +112,12 @@ impl ModelPart {
|
|||||||
let spatial_parent = parent_node
|
let spatial_parent = parent_node
|
||||||
.and_then(|n| n.get_aspect::<Spatial>().ok())
|
.and_then(|n| n.get_aspect::<Spatial>().ok())
|
||||||
.unwrap_or_else(|| model.space.clone());
|
.unwrap_or_else(|| model.space.clone());
|
||||||
|
|
||||||
|
let local_transform = unsafe { part.get_local_transform().m };
|
||||||
let space = Spatial::add_to(
|
let space = Spatial::add_to(
|
||||||
&node,
|
&node,
|
||||||
Some(spatial_parent),
|
Some(spatial_parent),
|
||||||
sk.model_node_get_transform_local(sk_model, id),
|
Mat4::from_cols_array(&local_transform),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -163,23 +129,24 @@ impl ModelPart {
|
|||||||
let Ok(model_part) = node.get_aspect::<ModelPart>() else {
|
let Ok(model_part) = node.get_aspect::<ModelPart>() else {
|
||||||
return Bounds::default();
|
return Bounds::default();
|
||||||
};
|
};
|
||||||
let Some(sk) = SK_MULTITHREAD.get() else {
|
|
||||||
return Bounds::default();
|
|
||||||
};
|
|
||||||
let Some(model) = model_part.model.upgrade() else {
|
let Some(model) = model_part.model.upgrade() else {
|
||||||
return Bounds::default();
|
return Bounds::default();
|
||||||
};
|
};
|
||||||
let Some(sk_model) = model.sk_model.get() else {
|
let Some(sk_model) = model.sk_model.get() else {
|
||||||
return Bounds::default();
|
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();
|
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 {
|
let model_part = Arc::new(ModelPart {
|
||||||
id,
|
id: *part.get_id(),
|
||||||
path: part_path,
|
path: part_path,
|
||||||
space,
|
space,
|
||||||
model: Arc::downgrade(model),
|
model: Arc::downgrade(model),
|
||||||
@@ -188,17 +155,31 @@ impl ModelPart {
|
|||||||
});
|
});
|
||||||
<ModelPart as ModelPartAspect>::add_node_members(&node);
|
<ModelPart as ModelPartAspect>::add_node_members(&node);
|
||||||
node.add_aspect_raw(model_part.clone());
|
node.add_aspect_raw(model_part.clone());
|
||||||
model.parts.add(id, &node);
|
model.parts.add(*part.get_id(), &node);
|
||||||
Some(model_part)
|
Some(model_part)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_material(&self, replacement: Arc<Material>) {
|
pub fn replace_material(&self, replacement: Arc<SendWrapper<Material>>) {
|
||||||
self.pending_material_replacement
|
self.pending_material_replacement
|
||||||
.lock()
|
.lock()
|
||||||
.replace(replacement);
|
.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 {
|
let Some(model) = self.model.upgrade() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -208,28 +189,37 @@ impl ModelPart {
|
|||||||
let Some(node) = model.space.node() else {
|
let Some(node) = model.space.node() else {
|
||||||
return;
|
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 {
|
let Some(client) = node.get_client() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(material_replacement) = self.pending_material_replacement.lock().take() {
|
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();
|
// todo: find all materials with identical parameters and batch them into 1 material again
|
||||||
for (parameter_name, parameter_value) in material_parameters.drain() {
|
'mat_params: {
|
||||||
let Some(material) = sk.model_node_get_material(sk_model, self.id) else {
|
let mut material_parameters = self.pending_material_parameters.lock();
|
||||||
continue;
|
if !material_parameters.is_empty() {
|
||||||
};
|
let Some(material) = part.get_material() else {
|
||||||
let new_material = sk.material_copy(material);
|
break 'mat_params;
|
||||||
parameter_value.apply_to_material(&client, sk, &new_material, parameter_name.as_str());
|
};
|
||||||
sk.model_node_set_material(sk_model, self.id, &new_material);
|
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 {
|
impl Aspect for ModelPart {
|
||||||
@@ -261,15 +251,12 @@ impl ModelPartAspect for ModelPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
self_ref: Weak<Model>,
|
|
||||||
enabled: Arc<AtomicBool>,
|
enabled: Arc<AtomicBool>,
|
||||||
space: Arc<Spatial>,
|
space: Arc<Spatial>,
|
||||||
_resource_id: ResourceID,
|
_resource_id: ResourceID,
|
||||||
sk_model: OnceCell<SKModel>,
|
sk_model: OnceCell<SKModel>,
|
||||||
parts: LifeLinkedNodeMap<i32>,
|
parts: LifeLinkedNodeMap<i32>,
|
||||||
}
|
}
|
||||||
unsafe impl Send for Model {}
|
|
||||||
unsafe impl Sync for Model {}
|
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
pub fn add_to(node: &Arc<Node>, resource_id: ResourceID) -> Result<Arc<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"))?;
|
.ok_or_else(|| eyre!("Resource not found"))?;
|
||||||
|
|
||||||
let model = Arc::new_cyclic(|self_ref| Model {
|
let model = Arc::new(Model {
|
||||||
self_ref: self_ref.clone(),
|
|
||||||
enabled: node.enabled.clone(),
|
enabled: node.enabled.clone(),
|
||||||
space: node.get_aspect::<Spatial>().unwrap().clone(),
|
space: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||||
_resource_id: resource_id,
|
_resource_id: resource_id,
|
||||||
@@ -290,51 +276,50 @@ impl Model {
|
|||||||
});
|
});
|
||||||
MODEL_REGISTRY.add_raw(&model);
|
MODEL_REGISTRY.add_raw(&model);
|
||||||
|
|
||||||
let sk = SK_MULTITHREAD.get().unwrap();
|
// 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 = sk.model_copy(
|
let sk_model = SKModel::copy(SKModel::from_file(
|
||||||
sk.model_create_file(pending_model_path.to_str().unwrap(), None::<Shader>)?,
|
pending_model_path.to_str().unwrap(),
|
||||||
);
|
None,
|
||||||
ModelPart::create_for_model(sk, &model.self_ref.upgrade().unwrap(), &sk_model);
|
)?);
|
||||||
|
ModelPart::create_for_model(&model, &sk_model);
|
||||||
let _ = model.sk_model.set(sk_model);
|
let _ = model.sk_model.set(sk_model);
|
||||||
node.add_aspect_raw(model.clone());
|
node.add_aspect_raw(model.clone());
|
||||||
Ok(model)
|
Ok(model)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, sk: &impl StereoKitDraw) {
|
fn draw(&self, token: &MainThreadToken) {
|
||||||
let Some(sk_model) = self.sk_model.get() else {
|
let Some(sk_model) = self.sk_model.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
for model_node_node in self.parts.nodes() {
|
for model_node_node in self.parts.nodes() {
|
||||||
if let Ok(model_node) = model_node_node.get_aspect::<ModelPart>() {
|
if let Ok(model_node) = model_node_node.get_aspect::<ModelPart>() {
|
||||||
model_node.update(sk);
|
model_node.update();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sk.model_draw(
|
if self.enabled.load(Ordering::Relaxed) {
|
||||||
sk_model,
|
sk_model.draw(token, self.space.global_transform(), None, None);
|
||||||
self.space.global_transform(),
|
}
|
||||||
WHITE,
|
|
||||||
RenderLayer::LAYER0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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 {
|
impl Aspect for Model {
|
||||||
const NAME: &'static str = "Model";
|
const NAME: &'static str = "Model";
|
||||||
}
|
}
|
||||||
impl ModelAspect for Model {}
|
impl ModelAspect for Model {}
|
||||||
impl Drop for Model {
|
impl Drop for Model {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(sk_model) = self.sk_model.take() {
|
// if let Some(sk_model) = self.sk_model.take() {
|
||||||
destroy_queue::add(sk_model);
|
// destroy_queue::add(sk_model);
|
||||||
}
|
// }
|
||||||
MODEL_REGISTRY.remove(self);
|
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() {
|
for model in MODEL_REGISTRY.get_valid_contents() {
|
||||||
if model.enabled.load(Ordering::Relaxed) {
|
model.draw(token);
|
||||||
model.draw(sk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ use smithay::backend::renderer::gles::{
|
|||||||
GlesError,
|
GlesError,
|
||||||
};
|
};
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use stereokit::Shader;
|
use stereokit_rust::shader::Shader;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
// Simula shader with fancy lanzcos sampling
|
// 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
|
// 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 {
|
struct FfiAssetHeader {
|
||||||
asset_type: i32,
|
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 parking_lot::Mutex;
|
||||||
use portable_atomic::{AtomicBool, Ordering};
|
use portable_atomic::{AtomicBool, Ordering};
|
||||||
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
|
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
|
||||||
use stereokit::{
|
use stereokit_rust::{
|
||||||
named_colors::WHITE, Color128, StereoKitDraw, TextAlign, TextFit, TextStyle as SkTextStyle,
|
font::Font,
|
||||||
|
sk::MainThreadToken,
|
||||||
|
system::{TextAlign, TextFit, TextStyle as SkTextStyle},
|
||||||
|
util::{Color128, Color32},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{TextAspect, TextStyle};
|
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 {
|
fn convert_align(x_align: super::XAlign, y_align: super::YAlign) -> TextAlign {
|
||||||
match (x_align, y_align) {
|
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::Center) => TextAlign::CenterLeft,
|
||||||
(super::XAlign::Left, super::YAlign::Bottom) => TextAlign::BottomLeft,
|
(super::XAlign::Left, super::YAlign::Bottom) => TextAlign::BottomLeft,
|
||||||
(super::XAlign::Center, super::YAlign::Top) => TextAlign::Center,
|
(super::XAlign::Center, super::YAlign::Top) => TextAlign::Center,
|
||||||
(super::XAlign::Center, super::YAlign::Center) => TextAlign::Center,
|
(super::XAlign::Center, super::YAlign::Center) => TextAlign::Center,
|
||||||
(super::XAlign::Center, super::YAlign::Bottom) => TextAlign::BottomCenter,
|
(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::Center) => TextAlign::CenterRight,
|
||||||
(super::XAlign::Right, super::YAlign::Bottom) => TextAlign::BottomRight,
|
(super::XAlign::Right, super::YAlign::Bottom) => TextAlign::BottomRight,
|
||||||
}
|
}
|
||||||
@@ -59,16 +62,16 @@ impl Text {
|
|||||||
Ok(text)
|
Ok(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, sk: &impl StereoKitDraw) {
|
fn draw(&self, token: &MainThreadToken) {
|
||||||
let style =
|
let style =
|
||||||
self.style
|
self.style
|
||||||
.get_or_try_init(|| -> Result<SkTextStyle, color_eyre::eyre::Error> {
|
.get_or_try_init(|| -> Result<SkTextStyle, color_eyre::eyre::Error> {
|
||||||
let font = self
|
let font = self
|
||||||
.font_path
|
.font_path
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.and_then(|path| sk.font_create(path).ok())
|
.and_then(|path| Font::from_file(path).ok())
|
||||||
.unwrap_or_else(|| sk.font_find("default/font").unwrap());
|
.unwrap_or_default();
|
||||||
Ok(unsafe { sk.text_make_style(font, 1.0, WHITE) })
|
Ok(SkTextStyle::from_font(font, 1.0, Color32::WHITE))
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Ok(style) = style {
|
if let Ok(style) = style {
|
||||||
@@ -81,7 +84,8 @@ impl Text {
|
|||||||
data.character_height,
|
data.character_height,
|
||||||
));
|
));
|
||||||
if let Some(bounds) = &data.bounds {
|
if let Some(bounds) = &data.bounds {
|
||||||
sk.text_add_in(
|
stereokit_rust::system::Text::add_in(
|
||||||
|
token,
|
||||||
&*text,
|
&*text,
|
||||||
transform,
|
transform,
|
||||||
Vec2::from(bounds.bounds) / data.character_height,
|
Vec2::from(bounds.bounds) / data.character_height,
|
||||||
@@ -92,21 +96,40 @@ impl Text {
|
|||||||
super::TextFit::Exact => TextFit::Exact,
|
super::TextFit::Exact => TextFit::Exact,
|
||||||
super::TextFit::Overflow => TextFit::Overflow,
|
super::TextFit::Overflow => TextFit::Overflow,
|
||||||
},
|
},
|
||||||
*style,
|
Some(style.clone()),
|
||||||
convert_align(bounds.anchor_align_x, bounds.anchor_align_y),
|
Some(Color128::new(
|
||||||
convert_align(data.text_align_x, data.text_align_y),
|
data.color.c.r,
|
||||||
vec3(0.0, 0.0, 0.0),
|
data.color.c.g,
|
||||||
Color128::from([data.color.c.r, data.color.c.g, data.color.c.b, data.color.a]),
|
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 {
|
} else {
|
||||||
sk.text_add_at(
|
stereokit_rust::system::Text::add_at(
|
||||||
|
token,
|
||||||
&*text,
|
&*text,
|
||||||
transform,
|
transform,
|
||||||
*style,
|
Some(*style),
|
||||||
TextAlign::Center,
|
Some(Color128::new(
|
||||||
convert_align(data.text_align_x, data.text_align_y),
|
data.color.c.r,
|
||||||
vec3(0.0, 0.0, 0.0),
|
data.color.c.g,
|
||||||
Color128::from([data.color.c.r, data.color.c.g, data.color.c.b, data.color.a]),
|
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() {
|
for text in TEXT_REGISTRY.get_valid_contents() {
|
||||||
if text.enabled.load(Ordering::Relaxed) {
|
if text.enabled.load(Ordering::Relaxed) {
|
||||||
text.draw(sk);
|
text.draw(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use glam::{vec3, Mat4};
|
use glam::{vec3, Mat4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use stereokit::StereoKitMultiThread;
|
use stereokit_rust::system::Input;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref HMD: Arc<Node> = create();
|
static ref HMD: Arc<Node> = create();
|
||||||
@@ -19,9 +19,9 @@ fn create() -> Arc<Node> {
|
|||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame(sk: &impl StereoKitMultiThread) {
|
pub fn frame() {
|
||||||
let spatial = HMD.get_aspect::<Spatial>().unwrap();
|
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(
|
*spatial.transform.lock() = Mat4::from_scale_rotation_translation(
|
||||||
vec3(1.0, 1.0, 1.0),
|
vec3(1.0, 1.0, 1.0),
|
||||||
hmd_pose.orientation.into(),
|
hmd_pose.orientation.into(),
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub struct InputMethod {
|
|||||||
pub data: Mutex<InputDataType>,
|
pub data: Mutex<InputDataType>,
|
||||||
pub datamap: Mutex<Datamap>,
|
pub datamap: Mutex<Datamap>,
|
||||||
|
|
||||||
|
pub capture_requests: Registry<InputHandler>,
|
||||||
pub captures: Registry<InputHandler>,
|
pub captures: Registry<InputHandler>,
|
||||||
pub(super) handler_aliases: LifeLinkedNodeMap<String>,
|
pub(super) handler_aliases: LifeLinkedNodeMap<String>,
|
||||||
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
|
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
|
||||||
@@ -41,6 +42,7 @@ impl InputMethod {
|
|||||||
enabled: Mutex::new(true),
|
enabled: Mutex::new(true),
|
||||||
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
|
||||||
data: Mutex::new(data),
|
data: Mutex::new(data),
|
||||||
|
capture_requests: Registry::new(),
|
||||||
captures: Registry::new(),
|
captures: Registry::new(),
|
||||||
datamap: Mutex::new(datamap),
|
datamap: Mutex::new(datamap),
|
||||||
handler_aliases: LifeLinkedNodeMap::default(),
|
handler_aliases: LifeLinkedNodeMap::default(),
|
||||||
@@ -166,9 +168,7 @@ impl InputMethodRefAspect for InputMethod {
|
|||||||
let input_method = node.get_aspect::<InputMethod>()?;
|
let input_method = node.get_aspect::<InputMethod>()?;
|
||||||
let input_handler = handler.get_aspect::<InputHandler>()?;
|
let input_handler = handler.get_aspect::<InputHandler>()?;
|
||||||
|
|
||||||
input_method.captures.add_raw(&input_handler);
|
input_method.capture_requests.add_raw(&input_handler);
|
||||||
// input_method_client::
|
|
||||||
// node.send_remote_signal("capture", message)
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ pub fn process_input() {
|
|||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
method.captures.clear();
|
|
||||||
// Iterate over the distance links and send input to them
|
// Iterate over the distance links and send input to them
|
||||||
for (i, input_link) in input_links.into_iter().enumerate() {
|
for (i, input_link) in input_links.into_iter().enumerate() {
|
||||||
if let Some(method_alias) = input_link
|
if let Some(method_alias) = input_link
|
||||||
@@ -165,8 +164,13 @@ pub fn process_input() {
|
|||||||
{
|
{
|
||||||
method_alias.enabled.store(true, Ordering::Release);
|
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 nanoid::nanoid;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use stereokit::{
|
use stereokit_rust::{
|
||||||
Color128, Material, Rect, RenderLayer, StereoKitDraw, Tex, TextureType, Transparency,
|
material::{Material, Transparency},
|
||||||
|
shader::Shader,
|
||||||
|
sk::MainThreadToken,
|
||||||
|
system::Renderer,
|
||||||
|
tex::{Tex, TexFormat, TexType},
|
||||||
|
util::Color128,
|
||||||
};
|
};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
|
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
|
||||||
@@ -46,8 +53,8 @@ struct FrameInfo {
|
|||||||
pub struct CameraItem {
|
pub struct CameraItem {
|
||||||
space: Arc<Spatial>,
|
space: Arc<Spatial>,
|
||||||
frame_info: Mutex<FrameInfo>,
|
frame_info: Mutex<FrameInfo>,
|
||||||
sk_tex: OnceCell<Tex>,
|
sk_tex: OnceCell<SendWrapper<Tex>>,
|
||||||
sk_mat: OnceCell<Arc<Material>>,
|
sk_mat: OnceCell<Arc<SendWrapper<Material>>>,
|
||||||
applied_to: Registry<ModelPart>,
|
applied_to: Registry<ModelPart>,
|
||||||
apply_to: Registry<ModelPart>,
|
apply_to: Registry<ModelPart>,
|
||||||
}
|
}
|
||||||
@@ -111,52 +118,54 @@ impl CameraItem {
|
|||||||
Ok(serialize(id)?.into())
|
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 frame_info = self.frame_info.lock();
|
||||||
let sk_tex = self.sk_tex.get_or_init(|| {
|
let sk_tex = self.sk_tex.get_or_init(|| {
|
||||||
sk.tex_gen_color(
|
SendWrapper::new(Tex::gen_color(
|
||||||
Color128::default(),
|
Color128::default(),
|
||||||
frame_info.px_size.x as i32,
|
frame_info.px_size.x as i32,
|
||||||
frame_info.px_size.y as i32,
|
frame_info.px_size.y as i32,
|
||||||
TextureType::RENDER_TARGET,
|
TexType::Rendertarget,
|
||||||
stereokit::TextureFormat::RGBA32Linear,
|
TexFormat::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)
|
|
||||||
});
|
});
|
||||||
|
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() {
|
for model_part in self.apply_to.take_valid_contents() {
|
||||||
model_part.replace_material(sk_mat.clone())
|
model_part.replace_material(sk_mat.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.applied_to.is_empty() {
|
if !self.applied_to.is_empty() {
|
||||||
sk.render_to(
|
Renderer::render_to(
|
||||||
sk_tex,
|
token,
|
||||||
frame_info.proj_matrix,
|
&**sk_tex,
|
||||||
self.space.global_transform(),
|
self.space.global_transform(),
|
||||||
RenderLayer::all(),
|
frame_info.proj_matrix,
|
||||||
stereokit::RenderClear::All,
|
None,
|
||||||
Rect {
|
None,
|
||||||
x: 0.0,
|
None,
|
||||||
y: 0.0,
|
)
|
||||||
w: 0.0,
|
|
||||||
h: 0.0,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(sk: &impl StereoKitDraw) {
|
pub fn update(token: &MainThreadToken) {
|
||||||
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
|
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
|
||||||
let ItemType::Camera(camera) = &camera.specialization else {
|
let ItemType::Camera(camera) = &camera.specialization else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
camera.update(sk);
|
camera.update(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::core::client::Client;
|
|||||||
use crate::core::registry::Registry;
|
use crate::core::registry::Registry;
|
||||||
use crate::create_interface;
|
use crate::create_interface;
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use glam::{vec3a, Mat4, Quat};
|
use glam::{vec3a, Mat4, Quat, Vec3};
|
||||||
use mint::Vector3;
|
use mint::Vector3;
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
@@ -15,7 +15,7 @@ use parking_lot::Mutex;
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::{Arc, Weak};
|
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!();
|
stardust_xr_server_codegen::codegen_spatial_protocol!();
|
||||||
impl Transform {
|
impl Transform {
|
||||||
@@ -104,11 +104,7 @@ impl Spatial {
|
|||||||
.map(|b| (b)(&node))
|
.map(|b| (b)(&node))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
for child in self.children.get_valid_contents() {
|
for child in self.children.get_valid_contents() {
|
||||||
bounds = bounds_grow_to_fit_box(
|
bounds.grown_box(child.get_bounding_box(), child.local_transform());
|
||||||
bounds,
|
|
||||||
child.get_bounding_box(),
|
|
||||||
Some(child.local_transform()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
bounds
|
bounds
|
||||||
}
|
}
|
||||||
@@ -253,8 +249,8 @@ impl SpatialRefAspect for Spatial {
|
|||||||
let bounds = this_spatial.get_bounding_box();
|
let bounds = this_spatial.get_bounding_box();
|
||||||
|
|
||||||
Ok(BoundingBox {
|
Ok(BoundingBox {
|
||||||
center: mint::Vector3::from(bounds.center),
|
center: Vec3::from(bounds.center).into(),
|
||||||
size: mint::Vector3::from(bounds.dimensions),
|
size: Vec3::from(bounds.dimensions).into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,21 +263,18 @@ impl SpatialRefAspect for Spatial {
|
|||||||
let relative_spatial = relative_to.get_aspect::<Spatial>()?;
|
let relative_spatial = relative_to.get_aspect::<Spatial>()?;
|
||||||
let center = Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial))
|
let center = Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial))
|
||||||
.transform_point3([0.0; 3].into());
|
.transform_point3([0.0; 3].into());
|
||||||
let bounds = bounds_grow_to_fit_box(
|
let mut bounds = Bounds {
|
||||||
Bounds {
|
center: center.into(),
|
||||||
center,
|
dimensions: [0.0; 3].into(),
|
||||||
dimensions: [0.0; 3].into(),
|
};
|
||||||
},
|
bounds.grown_box(
|
||||||
this_spatial.get_bounding_box(),
|
this_spatial.get_bounding_box(),
|
||||||
Some(Spatial::space_to_space_matrix(
|
Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial)),
|
||||||
Some(&this_spatial),
|
|
||||||
Some(&relative_spatial),
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(BoundingBox {
|
Ok(BoundingBox {
|
||||||
center: mint::Vector3::from(bounds.center),
|
center: Vec3::from(bounds.center).into(),
|
||||||
size: mint::Vector3::from(bounds.dimensions),
|
size: Vec3::from(bounds.dimensions).into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use nanoid::nanoid;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stardust_xr::values::Datamap;
|
use stardust_xr::values::Datamap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use stereokit::StereoKitMultiThread;
|
use stereokit_rust::system::Input;
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
pub struct EyeDatamap {
|
pub struct EyeDatamap {
|
||||||
@@ -46,13 +46,11 @@ impl EyePointer {
|
|||||||
|
|
||||||
Ok(EyePointer { spatial, pointer })
|
Ok(EyePointer { spatial, pointer })
|
||||||
}
|
}
|
||||||
pub fn update(&self, sk: &impl StereoKitMultiThread) {
|
pub fn update(&self) {
|
||||||
let ray = sk.input_eyes();
|
let ray = Input::get_eyes();
|
||||||
self.spatial
|
self.spatial.set_local_transform(
|
||||||
.set_local_transform(Mat4::from_rotation_translation(
|
Mat4::from_rotation_translation(ray.orientation.into(), ray.position.into()).into(),
|
||||||
ray.orientation,
|
);
|
||||||
ray.position,
|
|
||||||
));
|
|
||||||
{
|
{
|
||||||
// Set pointer input datamap
|
// Set pointer input datamap
|
||||||
*self.pointer.datamap.lock() = Datamap::from_typed(EyeDatamap { eye: 2 }).unwrap();
|
*self.pointer.datamap.lock() = Datamap::from_typed(EyeDatamap { eye: 2 }).unwrap();
|
||||||
|
|||||||
@@ -11,24 +11,38 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use glam::{vec2, vec3, Mat4, Vec2, Vec3};
|
use glam::{vec3, Mat4, Vec3};
|
||||||
|
use mint::Vector2;
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stardust_xr::values::Datamap;
|
use stardust_xr::values::Datamap;
|
||||||
use std::{convert::TryFrom, sync::Arc};
|
use std::sync::Arc;
|
||||||
use stereokit::{ray_from_mouse, ButtonState, Key, StereoKitMultiThread};
|
use stereokit_rust::system::{Input, Key};
|
||||||
use xkbcommon::xkb::{Context, Keymap, FORMAT_TEXT_V1};
|
use xkbcommon::xkb::{Context, Keymap, FORMAT_TEXT_V1};
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct MouseEvent {
|
struct MouseEvent {
|
||||||
select: f32,
|
select: f32,
|
||||||
middle: f32,
|
middle: f32,
|
||||||
context: f32,
|
context: f32,
|
||||||
grab: f32,
|
grab: f32,
|
||||||
scroll_continuous: Vec2,
|
scroll_continuous: Vector2<f32>,
|
||||||
scroll_discrete: Vec2,
|
scroll_discrete: Vector2<f32>,
|
||||||
raw_input_events: Vec<u32>,
|
raw_input_events: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
impl Default for MouseEvent {
|
||||||
|
fn default() -> Self {
|
||||||
|
MouseEvent {
|
||||||
|
select: 0.0,
|
||||||
|
middle: 0.0,
|
||||||
|
context: 0.0,
|
||||||
|
grab: 0.0,
|
||||||
|
scroll_continuous: [0.0; 2].into(),
|
||||||
|
scroll_discrete: [0.0; 2].into(),
|
||||||
|
raw_input_events: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct KeyboardEvent {
|
pub struct KeyboardEvent {
|
||||||
@@ -91,53 +105,48 @@ impl MousePointer {
|
|||||||
keyboard_sender,
|
keyboard_sender,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn update(&mut self, sk: &impl StereoKitMultiThread) {
|
pub fn update(&mut self) {
|
||||||
let mouse = sk.input_mouse();
|
let mouse = Input::get_mouse();
|
||||||
|
|
||||||
let ray = ray_from_mouse(mouse.pos).unwrap();
|
let ray = mouse.get_ray();
|
||||||
self.spatial.set_local_transform(
|
self.spatial.set_local_transform(
|
||||||
Mat4::look_to_rh(
|
Mat4::look_to_rh(
|
||||||
Vec3::from(ray.pos),
|
Vec3::from(ray.position),
|
||||||
Vec3::from(ray.dir),
|
Vec3::from(ray.direction),
|
||||||
vec3(0.0, 1.0, 0.0),
|
vec3(0.0, 1.0, 0.0),
|
||||||
)
|
)
|
||||||
.inverse(),
|
.inverse(),
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
// Set pointer input datamap
|
// Set pointer input datamap
|
||||||
self.mouse_datamap.select =
|
self.mouse_datamap.select = if Input::key(Key::MouseLeft).is_active() {
|
||||||
if sk.input_key(Key::MouseLeft).contains(ButtonState::ACTIVE) {
|
1.0f32
|
||||||
1.0f32
|
} else {
|
||||||
} else {
|
0.0f32
|
||||||
0.0f32
|
};
|
||||||
};
|
self.mouse_datamap.middle = if Input::key(Key::MouseCenter).is_active() {
|
||||||
self.mouse_datamap.middle =
|
1.0f32
|
||||||
if sk.input_key(Key::MouseCenter).contains(ButtonState::ACTIVE) {
|
} else {
|
||||||
1.0f32
|
0.0f32
|
||||||
} else {
|
};
|
||||||
0.0f32
|
self.mouse_datamap.context = if Input::key(Key::MouseRight).is_active() {
|
||||||
};
|
1.0f32
|
||||||
self.mouse_datamap.context =
|
} else {
|
||||||
if sk.input_key(Key::MouseRight).contains(ButtonState::ACTIVE) {
|
0.0f32
|
||||||
1.0f32
|
};
|
||||||
} else {
|
self.mouse_datamap.grab = if Input::key(Key::MouseBack).is_active()
|
||||||
0.0f32
|
|| Input::key(Key::MouseForward).is_active()
|
||||||
};
|
|
||||||
self.mouse_datamap.grab = if sk.input_key(Key::MouseBack).contains(ButtonState::ACTIVE)
|
|
||||||
|| sk
|
|
||||||
.input_key(Key::MouseForward)
|
|
||||||
.contains(ButtonState::ACTIVE)
|
|
||||||
{
|
{
|
||||||
1.0f32
|
1.0f32
|
||||||
} else {
|
} else {
|
||||||
0.0f32
|
0.0f32
|
||||||
};
|
};
|
||||||
self.mouse_datamap.scroll_continuous = vec2(0.0, mouse.scroll_change / 120.0);
|
self.mouse_datamap.scroll_continuous = [0.0, mouse.scroll_change / 120.0].into();
|
||||||
self.mouse_datamap.scroll_discrete = vec2(0.0, mouse.scroll_change / 120.0);
|
self.mouse_datamap.scroll_discrete = [0.0, mouse.scroll_change / 120.0].into();
|
||||||
*self.pointer.datamap.lock() = Datamap::from_typed(&self.mouse_datamap).unwrap();
|
*self.pointer.datamap.lock() = Datamap::from_typed(&self.mouse_datamap).unwrap();
|
||||||
}
|
}
|
||||||
self.target_pointer_input();
|
self.target_pointer_input();
|
||||||
self.send_keyboard_input(sk);
|
self.send_keyboard_input();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_pointer_input(&mut self) {
|
fn target_pointer_input(&mut self) {
|
||||||
@@ -145,7 +154,7 @@ impl MousePointer {
|
|||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
if !self
|
if !self
|
||||||
.pointer
|
.pointer
|
||||||
.captures
|
.capture_requests
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.contains(&capture)
|
.contains(&capture)
|
||||||
{
|
{
|
||||||
@@ -156,7 +165,7 @@ impl MousePointer {
|
|||||||
if self.capture.is_none() {
|
if self.capture.is_none() {
|
||||||
if let Some(new_capture) = self
|
if let Some(new_capture) = self
|
||||||
.pointer
|
.pointer
|
||||||
.captures
|
.capture_requests
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|h| {
|
.map(|h| {
|
||||||
@@ -183,8 +192,10 @@ impl MousePointer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure that if something is captured only send input to it
|
// make sure that if something is captured only send input to it
|
||||||
|
self.pointer.captures.clear();
|
||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
self.pointer.set_handler_order([capture].into_iter());
|
self.pointer.set_handler_order([capture].into_iter());
|
||||||
|
self.pointer.captures.add_raw(capture);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +247,7 @@ impl MousePointer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_keyboard_input(&mut self, sk: &impl StereoKitMultiThread) {
|
fn send_keyboard_input(&mut self) {
|
||||||
let rx = PULSE_RECEIVER_REGISTRY
|
let rx = PULSE_RECEIVER_REGISTRY
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -263,12 +274,12 @@ impl MousePointer {
|
|||||||
|
|
||||||
if let Some(rx) = rx {
|
if let Some(rx) = rx {
|
||||||
let keys = (8_u32..254)
|
let keys = (8_u32..254)
|
||||||
.filter_map(|i| Key::try_from(i).ok())
|
.map(|i| unsafe { std::mem::transmute(i) })
|
||||||
.filter_map(|k| Some((map_key(k)?, sk.input_key(k))))
|
.filter_map(|k| Some((map_key(k)?, Input::key(k))))
|
||||||
.filter_map(|(i, k)| {
|
.filter_map(|(i, k)| {
|
||||||
if k.contains(ButtonState::JUST_ACTIVE) {
|
if k.is_just_active() {
|
||||||
Some(i as i32)
|
Some(i as i32)
|
||||||
} else if k.contains(ButtonState::JUST_INACTIVE) {
|
} else if k.is_just_inactive() {
|
||||||
Some(-(i as i32))
|
Some(-(i as i32))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ use glam::{Mat4, Vec2, Vec3};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stardust_xr::values::Datamap;
|
use stardust_xr::values::Datamap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use stereokit::{
|
use stereokit_rust::{
|
||||||
named_colors::WHITE, ButtonState, Handed, Model, RenderLayer, StereoKitDraw,
|
model::Model,
|
||||||
StereoKitMultiThread,
|
sk::MainThreadToken,
|
||||||
|
system::{Handed, Input},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
@@ -32,7 +33,7 @@ pub struct SkController {
|
|||||||
datamap: ControllerDatamap,
|
datamap: ControllerDatamap,
|
||||||
}
|
}
|
||||||
impl SkController {
|
impl SkController {
|
||||||
pub fn new(sk: &impl StereoKitMultiThread, handed: Handed) -> Result<Self> {
|
pub fn new(handed: Handed) -> Result<Self> {
|
||||||
let _node = Node::create_parent_name(
|
let _node = Node::create_parent_name(
|
||||||
&INTERNAL_CLIENT,
|
&INTERNAL_CLIENT,
|
||||||
"",
|
"",
|
||||||
@@ -45,7 +46,7 @@ impl SkController {
|
|||||||
)
|
)
|
||||||
.add_to_scenegraph()?;
|
.add_to_scenegraph()?;
|
||||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
||||||
let model = sk.model_create_mem("cursor.glb", include_bytes!("cursor.glb"), None)?;
|
let model = Model::from_memory("cursor.glb", include_bytes!("cursor.glb"), None)?;
|
||||||
let tip = InputDataType::Tip(Tip::default());
|
let tip = InputDataType::Tip(Tip::default());
|
||||||
let input = InputMethod::add_to(
|
let input = InputMethod::add_to(
|
||||||
&_node,
|
&_node,
|
||||||
@@ -61,30 +62,35 @@ impl SkController {
|
|||||||
datamap: Default::default(),
|
datamap: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn update(&mut self, sk: &impl StereoKitDraw) {
|
pub fn update(&mut self, token: &MainThreadToken) {
|
||||||
let controller = sk.input_controller(self.handed);
|
let controller = Input::controller(self.handed);
|
||||||
*self.input.enabled.lock() = controller.tracked.contains(ButtonState::ACTIVE);
|
*self.input.enabled.lock() = controller.tracked.is_active();
|
||||||
if *self.input.enabled.lock() {
|
if *self.input.enabled.lock() {
|
||||||
let world_transform = Mat4::from_rotation_translation(
|
let world_transform = Mat4::from_rotation_translation(
|
||||||
controller.aim.orientation,
|
controller.aim.orientation.into(),
|
||||||
controller.aim.position,
|
controller.aim.position.into(),
|
||||||
);
|
);
|
||||||
sk.model_draw(
|
self.model.draw(
|
||||||
&self.model,
|
token,
|
||||||
world_transform * Mat4::from_scale(Vec3::ONE * 0.02),
|
world_transform * Mat4::from_scale(Vec3::ONE * 0.02),
|
||||||
WHITE,
|
None,
|
||||||
RenderLayer::LAYER0,
|
None,
|
||||||
);
|
);
|
||||||
self.input.spatial.set_local_transform(world_transform);
|
self.input.spatial.set_local_transform(world_transform);
|
||||||
}
|
}
|
||||||
self.datamap.select = controller.trigger;
|
self.datamap.select = controller.trigger;
|
||||||
self.datamap.grab = controller.grip;
|
self.datamap.grab = controller.grip;
|
||||||
self.datamap.scroll = controller.stick;
|
self.datamap.scroll = controller.stick.into();
|
||||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
||||||
|
|
||||||
// remove the capture when it's removed from captures list
|
// remove the capture when it's removed from captures list
|
||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
if !self.input.captures.get_valid_contents().contains(&capture) {
|
if !self
|
||||||
|
.input
|
||||||
|
.capture_requests
|
||||||
|
.get_valid_contents()
|
||||||
|
.contains(&capture)
|
||||||
|
{
|
||||||
self.capture.take();
|
self.capture.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +98,7 @@ impl SkController {
|
|||||||
if self.capture.is_none() {
|
if self.capture.is_none() {
|
||||||
self.capture = self
|
self.capture = self
|
||||||
.input
|
.input
|
||||||
.captures
|
.capture_requests
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|handler| {
|
.map(|handler| {
|
||||||
@@ -115,8 +121,10 @@ impl SkController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure that if something is captured only send input to it
|
// make sure that if something is captured only send input to it
|
||||||
|
self.input.captures.clear();
|
||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
self.input.set_handler_order([capture].into_iter());
|
self.input.set_handler_order([capture].into_iter());
|
||||||
|
self.input.captures.add_raw(capture);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,20 @@ use crate::nodes::{
|
|||||||
Node,
|
Node,
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use glam::Mat4;
|
use glam::{Mat4, Quat, Vec3};
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stardust_xr::values::Datamap;
|
use stardust_xr::values::Datamap;
|
||||||
use std::f32::INFINITY;
|
use std::f32::INFINITY;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use stereokit::{ButtonState, Color128, HandJoint, Handed, Material, StereoKitMultiThread};
|
use stereokit_rust::sk::MainThreadToken;
|
||||||
|
use stereokit_rust::system::{HandJoint, Handed, Input, LinePoint, Lines};
|
||||||
|
use stereokit_rust::util::Color128;
|
||||||
|
|
||||||
fn convert_joint(joint: HandJoint) -> Joint {
|
fn convert_joint(joint: HandJoint) -> Joint {
|
||||||
Joint {
|
Joint {
|
||||||
position: joint.position.into(),
|
position: Vec3::from(joint.position).into(),
|
||||||
rotation: joint.orientation.into(),
|
rotation: Quat::from(joint.orientation).into(),
|
||||||
radius: joint.radius,
|
radius: joint.radius,
|
||||||
distance: 0.0,
|
distance: 0.0,
|
||||||
}
|
}
|
||||||
@@ -33,13 +35,12 @@ struct HandDatamap {
|
|||||||
pub struct SkHand {
|
pub struct SkHand {
|
||||||
_node: Arc<Node>,
|
_node: Arc<Node>,
|
||||||
handed: Handed,
|
handed: Handed,
|
||||||
material: Material,
|
|
||||||
input: Arc<InputMethod>,
|
input: Arc<InputMethod>,
|
||||||
capture: Option<Arc<InputHandler>>,
|
capture: Option<Arc<InputHandler>>,
|
||||||
datamap: HandDatamap,
|
datamap: HandDatamap,
|
||||||
}
|
}
|
||||||
impl SkHand {
|
impl SkHand {
|
||||||
pub fn new(handed: Handed, sk: &impl StereoKitMultiThread) -> Result<Self> {
|
pub fn new(handed: Handed) -> Result<Self> {
|
||||||
let _node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
let _node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
|
||||||
.add_to_scenegraph()?;
|
.add_to_scenegraph()?;
|
||||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
|
||||||
@@ -50,29 +51,21 @@ impl SkHand {
|
|||||||
let datamap = Datamap::from_typed(HandDatamap::default())?;
|
let datamap = Datamap::from_typed(HandDatamap::default())?;
|
||||||
let input = InputMethod::add_to(&_node, hand, datamap)?;
|
let input = InputMethod::add_to(&_node, hand, datamap)?;
|
||||||
|
|
||||||
let material = sk.material_copy(Material::HAND);
|
Input::hand_visible(handed, false);
|
||||||
unsafe { sk.material_addref(&material); }
|
|
||||||
sk.input_hand_material(handed, Material(material.0));
|
|
||||||
Ok(SkHand {
|
Ok(SkHand {
|
||||||
_node,
|
_node,
|
||||||
handed,
|
handed,
|
||||||
material,
|
|
||||||
input,
|
input,
|
||||||
capture: None,
|
capture: None,
|
||||||
datamap: Default::default(),
|
datamap: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn update(&mut self, controller_enabled: bool, sk: &impl StereoKitMultiThread) {
|
pub fn update(&mut self, controller_enabled: bool, token: &MainThreadToken) {
|
||||||
let sk_hand = sk.input_hand(self.handed);
|
let sk_hand = Input::hand(self.handed);
|
||||||
if let InputDataType::Hand(hand) = &mut *self.input.data.lock() {
|
if let InputDataType::Hand(hand) = &mut *self.input.data.lock() {
|
||||||
let controller_active = controller_enabled
|
let controller_active =
|
||||||
&& sk
|
controller_enabled && Input::controller(self.handed).is_tracked();
|
||||||
.input_controller(self.handed)
|
*self.input.enabled.lock() = !controller_active && sk_hand.tracked.is_active();
|
||||||
.tracked
|
|
||||||
.contains(ButtonState::ACTIVE);
|
|
||||||
*self.input.enabled.lock() =
|
|
||||||
!controller_active && sk_hand.tracked_state.contains(ButtonState::ACTIVE);
|
|
||||||
sk.input_hand_visible(self.handed, *self.input.enabled.lock());
|
|
||||||
if *self.input.enabled.lock() {
|
if *self.input.enabled.lock() {
|
||||||
hand.thumb.tip = convert_joint(sk_hand.fingers[0][4]);
|
hand.thumb.tip = convert_joint(sk_hand.fingers[0][4]);
|
||||||
hand.thumb.distal = convert_joint(sk_hand.fingers[0][3]);
|
hand.thumb.distal = convert_joint(sk_hand.fingers[0][3]);
|
||||||
@@ -92,17 +85,27 @@ impl SkHand {
|
|||||||
finger.metacarpal = convert_joint(sk_finger[0]);
|
finger.metacarpal = convert_joint(sk_finger[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
hand.palm.position = sk_hand.palm.position.into();
|
hand.palm.position = Vec3::from(sk_hand.palm.position).into();
|
||||||
hand.palm.rotation = sk_hand.palm.orientation.into();
|
hand.palm.rotation = Quat::from(sk_hand.palm.orientation).into();
|
||||||
hand.palm.radius =
|
hand.palm.radius =
|
||||||
(sk_hand.fingers[2][0].radius + sk_hand.fingers[2][1].radius) * 0.5;
|
(sk_hand.fingers[2][0].radius + sk_hand.fingers[2][1].radius) * 0.5;
|
||||||
|
|
||||||
hand.wrist.position = sk_hand.wrist.position.into();
|
hand.wrist.position = Vec3::from(sk_hand.wrist.position).into();
|
||||||
hand.wrist.rotation = sk_hand.wrist.orientation.into();
|
hand.wrist.rotation = Quat::from(sk_hand.wrist.orientation).into();
|
||||||
hand.wrist.radius =
|
hand.wrist.radius =
|
||||||
(sk_hand.fingers[0][0].radius + sk_hand.fingers[4][0].radius) * 0.5;
|
(sk_hand.fingers[0][0].radius + sk_hand.fingers[4][0].radius) * 0.5;
|
||||||
|
|
||||||
hand.elbow = None;
|
hand.elbow = None;
|
||||||
|
|
||||||
|
self.draw(
|
||||||
|
token,
|
||||||
|
if self.capture.is_none() {
|
||||||
|
Color128::new_rgb(1.0, 1.0, 1.0)
|
||||||
|
} else {
|
||||||
|
Color128::new_rgb(0.0, 1.0, 0.75)
|
||||||
|
},
|
||||||
|
hand,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.datamap.pinch_strength = sk_hand.pinch_activation;
|
self.datamap.pinch_strength = sk_hand.pinch_activation;
|
||||||
@@ -111,16 +114,20 @@ impl SkHand {
|
|||||||
|
|
||||||
// remove the capture when it's removed from captures list
|
// remove the capture when it's removed from captures list
|
||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
if !self.input.captures.get_valid_contents().contains(&capture) {
|
if !self
|
||||||
|
.input
|
||||||
|
.capture_requests
|
||||||
|
.get_valid_contents()
|
||||||
|
.contains(&capture)
|
||||||
|
{
|
||||||
self.capture.take();
|
self.capture.take();
|
||||||
sk.material_set_color(&self.material, "color", Color128::new_rgb(1.0, 1.0, 1.0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// add the capture that's the closest if we don't have one
|
// add the capture that's the closest if we don't have one
|
||||||
if self.capture.is_none() {
|
if self.capture.is_none() {
|
||||||
self.capture = self
|
self.capture = self
|
||||||
.input
|
.input
|
||||||
.captures
|
.capture_requests
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|handler| (handler.clone(), self.compare_distance(&handler.field).abs()))
|
.map(|handler| (handler.clone(), self.compare_distance(&handler.field).abs()))
|
||||||
@@ -132,14 +139,13 @@ impl SkHand {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|(rx, _)| rx);
|
.map(|(rx, _)| rx);
|
||||||
if self.capture.is_some() {
|
|
||||||
sk.material_set_color(&self.material, "color", Color128::new_rgb(0.0, 1.0, 0.75));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that if something is captured only send input to it
|
// make sure that if something is captured only send input to it
|
||||||
|
self.input.captures.clear();
|
||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
self.input.set_handler_order([capture].into_iter());
|
self.input.set_handler_order([capture].into_iter());
|
||||||
|
self.input.captures.add_raw(capture);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +189,77 @@ impl SkHand {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw(&self, token: &MainThreadToken, color: Color128, hand: &Hand) {
|
||||||
|
// thumb
|
||||||
|
Lines::add_list(
|
||||||
|
token,
|
||||||
|
&[
|
||||||
|
joint_to_line_point(&hand.thumb.tip, color),
|
||||||
|
joint_to_line_point(&hand.thumb.distal, color),
|
||||||
|
joint_to_line_point(&hand.thumb.proximal, color),
|
||||||
|
joint_to_line_point(&hand.thumb.metacarpal, color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// index
|
||||||
|
Lines::add_list(
|
||||||
|
token,
|
||||||
|
&[
|
||||||
|
joint_to_line_point(&hand.index.tip, color),
|
||||||
|
joint_to_line_point(&hand.index.distal, color),
|
||||||
|
joint_to_line_point(&hand.index.intermediate, color),
|
||||||
|
joint_to_line_point(&hand.index.proximal, color),
|
||||||
|
joint_to_line_point(&hand.index.metacarpal, color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// middle
|
||||||
|
Lines::add_list(
|
||||||
|
token,
|
||||||
|
&[
|
||||||
|
joint_to_line_point(&hand.middle.tip, color),
|
||||||
|
joint_to_line_point(&hand.middle.distal, color),
|
||||||
|
joint_to_line_point(&hand.middle.intermediate, color),
|
||||||
|
joint_to_line_point(&hand.middle.proximal, color),
|
||||||
|
joint_to_line_point(&hand.middle.metacarpal, color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// ring
|
||||||
|
Lines::add_list(
|
||||||
|
token,
|
||||||
|
&[
|
||||||
|
joint_to_line_point(&hand.ring.tip, color),
|
||||||
|
joint_to_line_point(&hand.ring.distal, color),
|
||||||
|
joint_to_line_point(&hand.ring.intermediate, color),
|
||||||
|
joint_to_line_point(&hand.ring.proximal, color),
|
||||||
|
joint_to_line_point(&hand.ring.metacarpal, color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// little
|
||||||
|
Lines::add_list(
|
||||||
|
token,
|
||||||
|
&[
|
||||||
|
joint_to_line_point(&hand.little.tip, color),
|
||||||
|
joint_to_line_point(&hand.little.distal, color),
|
||||||
|
joint_to_line_point(&hand.little.intermediate, color),
|
||||||
|
joint_to_line_point(&hand.little.proximal, color),
|
||||||
|
joint_to_line_point(&hand.little.metacarpal, color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// palm
|
||||||
|
Lines::add_list(
|
||||||
|
token,
|
||||||
|
&[
|
||||||
|
joint_to_line_point(&hand.wrist, color),
|
||||||
|
joint_to_line_point(&hand.thumb.metacarpal, color),
|
||||||
|
joint_to_line_point(&hand.index.metacarpal, color),
|
||||||
|
joint_to_line_point(&hand.middle.metacarpal, color),
|
||||||
|
joint_to_line_point(&hand.ring.metacarpal, color),
|
||||||
|
joint_to_line_point(&hand.little.metacarpal, color),
|
||||||
|
joint_to_line_point(&hand.wrist, color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn compare_distance(&self, field: &Field) -> f32 {
|
fn compare_distance(&self, field: &Field) -> f32 {
|
||||||
let InputDataType::Hand(hand) = &*self.input.data.lock() else {
|
let InputDataType::Hand(hand) = &*self.input.data.lock() else {
|
||||||
return INFINITY;
|
return INFINITY;
|
||||||
@@ -199,3 +276,11 @@ impl SkHand {
|
|||||||
+ (ring_tip_distance * 0.15)
|
+ (ring_tip_distance * 0.15)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn joint_to_line_point(joint: &Joint, color: Color128) -> LinePoint {
|
||||||
|
LinePoint {
|
||||||
|
pt: Vec3::from(joint.position).into(),
|
||||||
|
thickness: joint.radius * 2.0,
|
||||||
|
color: color.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use mint::Vector2;
|
|||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stardust_xr::values::Datamap;
|
use stardust_xr::values::Datamap;
|
||||||
use stereokit::StereoKitMultiThread;
|
use stereokit_rust::system::World;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::client::INTERNAL_CLIENT,
|
core::client::INTERNAL_CLIENT,
|
||||||
@@ -59,23 +59,14 @@ impl PlaySpace {
|
|||||||
_pulse_rx: pulse_rx,
|
_pulse_rx: pulse_rx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn update(&self, sk: &impl StereoKitMultiThread) {
|
pub fn update(&self) {
|
||||||
let pose = sk.world_get_bounds_pose();
|
let pose = World::get_bounds_pose();
|
||||||
self.spatial
|
self.spatial.set_local_transform(
|
||||||
.set_local_transform(Mat4::from_rotation_translation(
|
Mat4::from_rotation_translation(pose.orientation.into(), pose.position.into()).into(),
|
||||||
pose.orientation,
|
);
|
||||||
pose.position,
|
|
||||||
));
|
|
||||||
let Field::Box(box_field) = self.field.as_ref() else {
|
let Field::Box(box_field) = self.field.as_ref() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
box_field.set_size(
|
box_field.set_size([World::get_bounds_size().x, 0.0, World::get_bounds_size().y].into());
|
||||||
[
|
|
||||||
sk.world_get_bounds_size().x,
|
|
||||||
0.0,
|
|
||||||
sk.world_get_bounds_size().y,
|
|
||||||
]
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ use crate::{core::task, wayland::state::ClientState};
|
|||||||
use color_eyre::eyre::{ensure, Result};
|
use color_eyre::eyre::{ensure, Result};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use sk::StereoKitDraw;
|
|
||||||
use smithay::backend::allocator::dmabuf::Dmabuf;
|
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||||
use smithay::backend::egl::EGLContext;
|
use smithay::backend::egl::EGLContext;
|
||||||
use smithay::backend::renderer::gles::GlesRenderer;
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
@@ -42,7 +41,7 @@ use std::{
|
|||||||
os::unix::{net::UnixListener, prelude::FromRawFd},
|
os::unix::{net::UnixListener, prelude::FromRawFd},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use stereokit as sk;
|
use stereokit_rust::system::{Backend, BackendGraphics};
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
|
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
|
||||||
@@ -59,16 +58,15 @@ struct EGLRawHandles {
|
|||||||
}
|
}
|
||||||
fn get_sk_egl() -> Result<EGLRawHandles> {
|
fn get_sk_egl() -> Result<EGLRawHandles> {
|
||||||
ensure!(
|
ensure!(
|
||||||
unsafe { sk::sys::backend_graphics_get() }
|
Backend::graphics() == BackendGraphics::OpenGLESEGL,
|
||||||
== sk::sys::backend_graphics__backend_graphics_opengles_egl,
|
|
||||||
"StereoKit is not running using EGL!"
|
"StereoKit is not running using EGL!"
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(unsafe {
|
Ok(unsafe {
|
||||||
EGLRawHandles {
|
EGLRawHandles {
|
||||||
display: sk::sys::backend_opengl_egl_get_display() as *const c_void,
|
display: stereokit_rust::system::backend_opengl_egl_get_display() as *const c_void,
|
||||||
config: sk::sys::backend_opengl_egl_get_config() as *const c_void,
|
config: stereokit_rust::system::backend_opengl_egl_get_config() as *const c_void,
|
||||||
context: sk::sys::backend_opengl_egl_get_context() as *const c_void,
|
context: stereokit_rust::system::backend_opengl_egl_get_context() as *const c_void,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -196,8 +194,8 @@ impl Wayland {
|
|||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", name = "Wayland frame", skip(self, sk))]
|
#[instrument(level = "debug", name = "Wayland frame", skip(self))]
|
||||||
pub fn update(&mut self, sk: &impl StereoKitDraw) {
|
pub fn update(&mut self) {
|
||||||
while let Ok((dmabuf, notifier)) = self.dmabuf_rx.try_recv() {
|
while let Ok((dmabuf, notifier)) = self.dmabuf_rx.try_recv() {
|
||||||
if self.renderer.import_dmabuf(&dmabuf, None).is_err() {
|
if self.renderer.import_dmabuf(&dmabuf, None).is_err() {
|
||||||
if let Some(notifier) = notifier {
|
if let Some(notifier) = notifier {
|
||||||
@@ -206,15 +204,15 @@ impl Wayland {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for core_surface in CORE_SURFACES.get_valid_contents() {
|
for core_surface in CORE_SURFACES.get_valid_contents() {
|
||||||
core_surface.process(sk, &mut self.renderer);
|
core_surface.process(&mut self.renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.display.flush_clients(None);
|
self.display.flush_clients(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_event(&self, sk: &impl StereoKitDraw) {
|
pub fn frame_event(&self) {
|
||||||
for core_surface in CORE_SURFACES.get_valid_contents() {
|
for core_surface in CORE_SURFACES.get_valid_contents() {
|
||||||
core_surface.frame(sk, self.output.clone());
|
core_surface.frame(self.output.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ use smithay::{
|
|||||||
wayland::compositor::{self, SurfaceData},
|
wayland::compositor::{self, SurfaceData},
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, ffi::c_void, sync::Arc, time::Duration};
|
use std::{cell::RefCell, ffi::c_void, sync::Arc, time::Duration};
|
||||||
use stereokit::{
|
use stereokit_rust::{
|
||||||
Material, Shader, StereoKitDraw, Tex, TextureAddress, TextureFormat, TextureSample,
|
material::{Material, Transparency},
|
||||||
TextureType, Transparency,
|
shader::Shader,
|
||||||
|
tex::{Tex, TexAddress, TexFormat, TexSample, TexType},
|
||||||
|
util::Time,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new();
|
pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new();
|
||||||
@@ -40,8 +42,8 @@ pub struct CoreSurface {
|
|||||||
pub dh: DisplayHandle,
|
pub dh: DisplayHandle,
|
||||||
pub weak_surface: wayland_server::Weak<WlSurface>,
|
pub weak_surface: wayland_server::Weak<WlSurface>,
|
||||||
mapped_data: Mutex<Option<CoreSurfaceData>>,
|
mapped_data: Mutex<Option<CoreSurfaceData>>,
|
||||||
sk_tex: OnceCell<Tex>,
|
sk_tex: OnceCell<SendWrapper<Mutex<Tex>>>,
|
||||||
sk_mat: OnceCell<Arc<Material>>,
|
sk_mat: OnceCell<SendWrapper<Mutex<Material>>>,
|
||||||
material_offset: Mutex<Delta<u32>>,
|
material_offset: Mutex<Delta<u32>>,
|
||||||
on_mapped: Mutex<Box<dyn Fn() + Send + Sync>>,
|
on_mapped: Mutex<Box<dyn Fn() + Send + Sync>>,
|
||||||
on_commit: Mutex<Box<dyn Fn(u32) + Send + Sync>>,
|
on_commit: Mutex<Box<dyn Fn(u32) + Send + Sync>>,
|
||||||
@@ -85,24 +87,28 @@ impl CoreSurface {
|
|||||||
*self.on_commit.lock() = Box::new(|_| {});
|
*self.on_commit.lock() = Box::new(|_| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process(&self, sk: &impl StereoKitDraw, renderer: &mut GlesRenderer) {
|
pub fn process(&self, renderer: &mut GlesRenderer) {
|
||||||
let Some(wl_surface) = self.wl_surface() else {
|
let Some(wl_surface) = self.wl_surface() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let sk_tex = self
|
let sk_tex = self.sk_tex.get_or_init(|| {
|
||||||
.sk_tex
|
SendWrapper::new(Mutex::new(Tex::new(
|
||||||
.get_or_init(|| sk.tex_create(TextureType::IMAGE_NO_MIPS, TextureFormat::RGBA32));
|
TexType::ImageNomips,
|
||||||
|
TexFormat::RGBA32Linear,
|
||||||
|
nanoid::nanoid!(),
|
||||||
|
)))
|
||||||
|
});
|
||||||
self.sk_mat.get_or_init(|| {
|
self.sk_mat.get_or_init(|| {
|
||||||
let shader = sk.shader_create_mem(&PANEL_SHADER_BYTES);
|
let shader = Shader::from_memory(&PANEL_SHADER_BYTES).unwrap();
|
||||||
// let _ = renderer.with_context(|c| unsafe {
|
// let _ = renderer.with_context(|c| unsafe {
|
||||||
// shader_inject(c, &mut shader, SIMULA_VERT_STR, SIMULA_FRAG_STR)
|
// shader_inject(c, &mut shader, SIMULA_VERT_STR, SIMULA_FRAG_STR)
|
||||||
// });
|
// });
|
||||||
|
|
||||||
let mat = sk.material_create(shader.as_ref().unwrap_or(Shader::UI.as_ref()));
|
let mut mat = Material::new(shader, None);
|
||||||
sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref());
|
mat.diffuse_tex(sk_tex.lock().as_ref());
|
||||||
sk.material_set_transparency(&mat, Transparency::Blend);
|
mat.transparency(Transparency::Blend);
|
||||||
Arc::new(mat)
|
SendWrapper::new(Mutex::new(mat))
|
||||||
});
|
});
|
||||||
|
|
||||||
// Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe)
|
// Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe)
|
||||||
@@ -146,22 +152,22 @@ impl CoreSurface {
|
|||||||
let Some(sk_mat) = self.sk_mat.get() else {
|
let Some(sk_mat) = self.sk_mat.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
unsafe {
|
sk_tex
|
||||||
sk.tex_set_surface(
|
.lock()
|
||||||
sk_tex.as_ref(),
|
.set_native_surface(
|
||||||
smithay_tex.tex_id() as usize as *mut c_void,
|
smithay_tex.tex_id() as usize as *mut c_void,
|
||||||
TextureType::IMAGE_NO_MIPS,
|
TexType::ImageNomips,
|
||||||
smithay::backend::renderer::gles::ffi::RGBA8.into(),
|
smithay::backend::renderer::gles::ffi::RGBA8.into(),
|
||||||
smithay_tex.width() as i32,
|
smithay_tex.width() as i32,
|
||||||
smithay_tex.height() as i32,
|
smithay_tex.height() as i32,
|
||||||
1,
|
1,
|
||||||
false,
|
false,
|
||||||
);
|
)
|
||||||
sk.tex_set_sample(sk_tex.as_ref(), TextureSample::Point);
|
.sample_mode(TexSample::Point)
|
||||||
sk.tex_set_address(sk_tex.as_ref(), TextureAddress::Clamp);
|
.address_mode(TexAddress::Clamp);
|
||||||
}
|
|
||||||
if let Some(material_offset) = self.material_offset.lock().delta() {
|
if let Some(material_offset) = self.material_offset.lock().delta() {
|
||||||
sk.material_set_queue_offset(sk_mat.as_ref().as_ref(), *material_offset as i32);
|
sk_mat.lock().queue_offset(*material_offset as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(surface_size) = renderer_surface_state.surface_size() else {
|
let Some(surface_size) = renderer_surface_state.surface_size() else {
|
||||||
@@ -180,7 +186,7 @@ impl CoreSurface {
|
|||||||
self.apply_surface_materials();
|
self.apply_surface_materials();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame(&self, sk: &impl StereoKitDraw, output: Output) {
|
pub fn frame(&self, output: Output) {
|
||||||
let Some(wl_surface) = self.wl_surface() else {
|
let Some(wl_surface) = self.wl_surface() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -188,7 +194,7 @@ impl CoreSurface {
|
|||||||
send_frames_surface_tree(
|
send_frames_surface_tree(
|
||||||
&wl_surface,
|
&wl_surface,
|
||||||
&output,
|
&output,
|
||||||
Duration::from_secs_f64(sk.time_get()),
|
Duration::from_secs_f64(Time::get_total_unscaled()),
|
||||||
None,
|
None,
|
||||||
|_, _| Some(output.clone()),
|
|_, _| Some(output.clone()),
|
||||||
);
|
);
|
||||||
@@ -204,8 +210,9 @@ impl CoreSurface {
|
|||||||
|
|
||||||
fn apply_surface_materials(&self) {
|
fn apply_surface_materials(&self) {
|
||||||
if let Some(sk_mat) = self.sk_mat.get() {
|
if let Some(sk_mat) = self.sk_mat.get() {
|
||||||
|
let sk_mat = sk_mat.lock();
|
||||||
for model_node in self.pending_material_applications.get_valid_contents() {
|
for model_node in self.pending_material_applications.get_valid_contents() {
|
||||||
model_node.replace_material(sk_mat.clone());
|
model_node.replace_material_now(sk_mat.as_ref());
|
||||||
}
|
}
|
||||||
self.pending_material_applications.clear();
|
self.pending_material_applications.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user