Bevy Rewrite, attempt 2 #46
86
Cargo.lock
generated
86
Cargo.lock
generated
@@ -77,7 +77,7 @@ dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_macos",
|
||||
"accesskit_windows",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"winit",
|
||||
]
|
||||
|
||||
@@ -173,17 +173,6 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d"
|
||||
|
||||
[[package]]
|
||||
name = "android_logger"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826"
|
||||
dependencies = [
|
||||
"android_log-sys",
|
||||
"env_filter",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@@ -1653,7 +1642,7 @@ dependencies = [
|
||||
"bevy_reflect",
|
||||
"bevy_utils",
|
||||
"log",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"smol_str",
|
||||
]
|
||||
@@ -1685,7 +1674,7 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"crossbeam-channel",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"tracing",
|
||||
"wasm-bindgen",
|
||||
@@ -2401,12 +2390,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cty"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||
|
||||
[[package]]
|
||||
name = "cursor-icon"
|
||||
version = "1.2.0"
|
||||
@@ -2703,16 +2686,6 @@ dependencies = [
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -4175,9 +4148,7 @@ dependencies = [
|
||||
"log",
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"num_enum 0.7.3",
|
||||
"raw-window-handle 0.4.3",
|
||||
"raw-window-handle 0.5.2",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
@@ -5191,21 +5162,6 @@ version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
|
||||
dependencies = [
|
||||
"cty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.6.2"
|
||||
@@ -5835,7 +5791,6 @@ dependencies = [
|
||||
"smithay",
|
||||
"stardust-xr",
|
||||
"stardust-xr-server-codegen",
|
||||
"stereokit-rust",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"toml",
|
||||
@@ -5866,31 +5821,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "stereokit-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mvvvv/StereoKit-rust.git?rev=73ffaae6f42aa369e599a6ea0391f77840d682d8#73ffaae6f42aa369e599a6ea0391f77840d682d8"
|
||||
|
||||
[[package]]
|
||||
name = "stereokit-rust"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mvvvv/StereoKit-rust.git?rev=73ffaae6f42aa369e599a6ea0391f77840d682d8#73ffaae6f42aa369e599a6ea0391f77840d682d8"
|
||||
dependencies = [
|
||||
"android-activity",
|
||||
"android_logger",
|
||||
"bitflags 2.9.1",
|
||||
"cmake",
|
||||
"glam",
|
||||
"jni 0.21.1",
|
||||
"log",
|
||||
"ndk 0.9.0",
|
||||
"ndk-context",
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"openxr-sys",
|
||||
"stereokit-macros",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strict-num"
|
||||
version = "0.1.1"
|
||||
@@ -6950,7 +6880,7 @@ dependencies = [
|
||||
"naga",
|
||||
"parking_lot 0.12.4",
|
||||
"profiling",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"static_assertions",
|
||||
"wasm-bindgen",
|
||||
@@ -6978,7 +6908,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"parking_lot 0.12.4",
|
||||
"profiling",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror 2.0.12",
|
||||
@@ -7020,7 +6950,7 @@ dependencies = [
|
||||
"parking_lot 0.12.4",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"renderdoc-sys",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
@@ -7632,7 +7562,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"raw-window-handle 0.6.2",
|
||||
"raw-window-handle",
|
||||
"redox_syscall 0.4.1",
|
||||
"rustix 0.38.44",
|
||||
"sctk-adwaita",
|
||||
|
||||
@@ -108,12 +108,6 @@ default-features = false
|
||||
features = ["desktop", "backend_drm", "renderer_gl", "wayland_frontend"]
|
||||
optional = true
|
||||
|
||||
[dependencies.stereokit-rust]
|
||||
git = "https://github.com/mvvvv/StereoKit-rust.git"
|
||||
rev = "73ffaae6f42aa369e599a6ea0391f77840d682d8"
|
||||
features = ["no-event-loop"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.stardust-xr]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ use std::{
|
||||
time::Instant,
|
||||
};
|
||||
use tokio::{net::UnixStream, sync::watch, task::JoinHandle};
|
||||
use tracing::{info, warn};
|
||||
use tracing::info;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CLIENTS: OwnedRegistry<Client> = OwnedRegistry::new();
|
||||
@@ -86,7 +86,7 @@ impl Client {
|
||||
pub fn from_connection(connection: UnixStream) -> Result<Arc<Self>> {
|
||||
let pid = connection.peer_cred().ok().and_then(|c| c.pid());
|
||||
let env = pid.and_then(|pid| get_env(pid).ok());
|
||||
let exe = pid.and_then(|pid| fs::read_link(format!("/proc/{}/exe", pid)).ok());
|
||||
let exe = pid.and_then(|pid| fs::read_link(format!("/proc/{pid}/exe")).ok());
|
||||
info!(
|
||||
pid,
|
||||
exe = exe
|
||||
|
||||
@@ -8,7 +8,6 @@ use stardust_xr::{
|
||||
flexbuffers::{DeserializationError, ReaderError},
|
||||
},
|
||||
};
|
||||
use stereokit_rust::StereoKitError;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Result<T, E = ServerError> = std::result::Result<T, E>;
|
||||
@@ -29,8 +28,6 @@ pub enum ServerError {
|
||||
DeserializationError(#[from] DeserializationError),
|
||||
#[error("Reader error: {0}")]
|
||||
ReaderError(#[from] ReaderError),
|
||||
#[error("StereoKit error: {0}")]
|
||||
StereoKitError(#[from] StereoKitError),
|
||||
#[error("Aspect {} does not exist for node", 0.to_string())]
|
||||
NoAspect(TypeId),
|
||||
#[error("{0}")]
|
||||
|
||||
191
src/main.rs
191
src/main.rs
@@ -7,8 +7,7 @@ mod session;
|
||||
mod wayland;
|
||||
|
||||
use crate::core::destroy_queue;
|
||||
use crate::nodes::items::camera;
|
||||
use crate::nodes::{drawable, input};
|
||||
use crate::nodes::input;
|
||||
|
||||
use bevy::MinimalPlugins;
|
||||
use bevy::a11y::AccessibilityPlugin;
|
||||
@@ -52,7 +51,6 @@ use nodes::drawable::lines::LinesNodePlugin;
|
||||
use nodes::drawable::model::ModelNodePlugin;
|
||||
use nodes::drawable::text::TextNodePlugin;
|
||||
use nodes::spatial::SpatialNodePlugin;
|
||||
use objects::ServerObjects;
|
||||
use objects::input::mouse_pointer::FlatscreenInputPlugin;
|
||||
use objects::input::sk_controller::ControllerPlugin;
|
||||
use objects::input::sk_hand::HandPlugin;
|
||||
@@ -64,20 +62,11 @@ use stardust_xr::server;
|
||||
use std::ops::DerefMut as _;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
use stereokit_rust::material::Material;
|
||||
use stereokit_rust::shader::Shader;
|
||||
use stereokit_rust::sk::{
|
||||
AppMode, DepthMode, DisplayBlend, OriginMode, QuitReason, SkSettings, sk_quit,
|
||||
};
|
||||
use stereokit_rust::system::{Handed, Input, LogLevel, Renderer};
|
||||
use stereokit_rust::tex::{SHCubemap, Tex, TexFormat, TexType};
|
||||
use stereokit_rust::ui::Ui;
|
||||
use stereokit_rust::util::{Color128, SphericalHarmonics, Time};
|
||||
use tokio::net::UnixListener;
|
||||
use tokio::sync::Notify;
|
||||
use tokio::task::JoinError;
|
||||
use tracing::metadata::LevelFilter;
|
||||
use tracing::{debug_span, error, info};
|
||||
use tracing::{error, info};
|
||||
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||
use zbus::Connection;
|
||||
use zbus::fdo::ObjectManager;
|
||||
@@ -123,14 +112,7 @@ static STARDUST_INSTANCE: OnceLock<String> = OnceLock::new();
|
||||
|
||||
// #[tokio::main(flavor = "current_thread")]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// let mut out = Vec::new();
|
||||
// for i in 0..8 {
|
||||
// for base in [0, 8, 1, 8, 9, 1] {
|
||||
// out.push(base + i as u16);
|
||||
// }
|
||||
// }
|
||||
// panic!("{out:?}");
|
||||
async fn main() -> Result<AppExit, JoinError> {
|
||||
color_eyre::install().unwrap();
|
||||
|
||||
let registry = tracing_subscriber::registry();
|
||||
@@ -222,15 +204,15 @@ async fn main() {
|
||||
"Couldn't make the object registry to find all objects with given interfaces in d-bus",
|
||||
);
|
||||
|
||||
let sk_ready_notifier = Arc::new(Notify::new());
|
||||
let stereokit_loop = tokio::task::spawn_blocking({
|
||||
let sk_ready_notifier = sk_ready_notifier.clone();
|
||||
let ready_notifier = Arc::new(Notify::new());
|
||||
let io_loop = tokio::task::spawn_blocking({
|
||||
let ready_notifier = ready_notifier.clone();
|
||||
let project_dirs = project_dirs.clone();
|
||||
let cli_args = cli_args.clone();
|
||||
let dbus_connection = dbus_connection.clone();
|
||||
move || {
|
||||
bevy_loop(
|
||||
sk_ready_notifier,
|
||||
ready_notifier,
|
||||
project_dirs,
|
||||
cli_args,
|
||||
dbus_connection,
|
||||
@@ -238,16 +220,12 @@ async fn main() {
|
||||
)
|
||||
}
|
||||
});
|
||||
sk_ready_notifier.notified().await;
|
||||
ready_notifier.notified().await;
|
||||
let mut startup_children = project_dirs
|
||||
.as_ref()
|
||||
.map(|project_dirs| launch_start(&cli_args, project_dirs))
|
||||
.unwrap_or_default();
|
||||
|
||||
tokio::select! {
|
||||
_ = stereokit_loop => (),
|
||||
_ = tokio::signal::ctrl_c() => unsafe {sk_quit(QuitReason::SystemClose)},
|
||||
}
|
||||
let return_value = io_loop.await;
|
||||
info!("Stopping...");
|
||||
if let Some(project_dirs) = project_dirs {
|
||||
save_session(&project_dirs).await;
|
||||
@@ -257,10 +235,11 @@ async fn main() {
|
||||
}
|
||||
|
||||
info!("Cleanly shut down Stardust");
|
||||
return_value
|
||||
}
|
||||
|
||||
static DEFAULT_SKYTEX: OnceLock<Tex> = OnceLock::new();
|
||||
static DEFAULT_SKYLIGHT: OnceLock<SphericalHarmonics> = OnceLock::new();
|
||||
// static DEFAULT_SKYTEX: OnceLock<Tex> = OnceLock::new();
|
||||
// static DEFAULT_SKYLIGHT: OnceLock<SphericalHarmonics> = OnceLock::new();
|
||||
|
||||
#[derive(ScheduleLabel, Hash, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct PreFrameWait;
|
||||
@@ -271,11 +250,11 @@ pub struct DbusConnection(Connection);
|
||||
|
||||
fn bevy_loop(
|
||||
ready_notifier: Arc<Notify>,
|
||||
project_dirs: Option<ProjectDirs>,
|
||||
_project_dirs: Option<ProjectDirs>,
|
||||
args: CliArgs,
|
||||
dbus_connection: Connection,
|
||||
object_registry: ObjectRegistry,
|
||||
) {
|
||||
) -> AppExit {
|
||||
let mut app = App::new();
|
||||
app.insert_resource(DbusConnection(dbus_connection));
|
||||
app.add_plugins(AssetPlugin {
|
||||
|
|
||||
@@ -376,8 +355,7 @@ fn bevy_loop(
|
||||
},
|
||||
bevy_sk::skytext::SphericalHarmonicsPlugin,
|
||||
));
|
||||
app.add_plugins(HandGizmosPlugin);
|
||||
// app.add_plugins(MeshTextPlugin);
|
||||
// app.add_plugins(HandGizmosPlugin);
|
||||
app.init_asset::<Font>().init_asset_loader::<FontLoader>();
|
||||
if let Some(priority) = args.overlay_priority {
|
||||
app.insert_resource(OxrOverlaySettings {
|
||||
@@ -423,7 +401,7 @@ fn bevy_loop(
|
||||
.in_set(XrHandleEvents::FrameLoop),
|
||||
);
|
||||
|
||||
app.run();
|
||||
app.run()
|
||||
}
|
||||
fn update_cameras(mut camera: Query<&mut Projection, (With<Camera3d>,)>) {
|
||||
for mut projection in &mut camera {
|
||||
@@ -465,6 +443,7 @@ fn xr_step(world: &mut World) {
|
||||
let should_wait = world
|
||||
.run_system_cached(should_run_frame_loop)
|
||||
.unwrap_or(false);
|
||||
// we might want to do an adaptive sleep when not OpenXR waiting
|
||||
if should_wait {
|
||||
world.resource_scope::<OxrFrameWaiter, _>(|world, mut waiter| {
|
||||
let state = waiter
|
||||
@@ -484,137 +463,3 @@ fn xr_step(world: &mut World) {
|
||||
// drawable::draw(token);
|
||||
// audio::update();
|
||||
}
|
||||
|
||||
fn stereokit_loop(
|
||||
sk_ready_notifier: Arc<Notify>,
|
||||
project_dirs: Option<ProjectDirs>,
|
||||
args: CliArgs,
|
||||
dbus_connection: Connection,
|
||||
object_registry: ObjectRegistry,
|
||||
) {
|
||||
let sk = SkSettings::default()
|
||||
.app_name("Stardust XR")
|
||||
.blend_preference(DisplayBlend::AnyTransparent)
|
||||
.mode(if args.flatscreen {
|
||||
AppMode::Simulator
|
||||
} else {
|
||||
AppMode::XR
|
||||
})
|
||||
.depth_mode(DepthMode::D32)
|
||||
.log_filter(match EnvFilter::from_default_env().max_level_hint() {
|
||||
Some(LevelFilter::ERROR) => LogLevel::Error,
|
||||
Some(LevelFilter::WARN) => LogLevel::Warning,
|
||||
Some(LevelFilter::INFO) => LogLevel::Inform,
|
||||
Some(LevelFilter::DEBUG) => LogLevel::Diagnostic,
|
||||
Some(LevelFilter::TRACE) => LogLevel::Diagnostic,
|
||||
Some(LevelFilter::OFF) => LogLevel::None,
|
||||
None => LogLevel::Warning,
|
||||
})
|
||||
.overlay_app(args.overlay_priority.is_some())
|
||||
.overlay_priority(args.overlay_priority.unwrap_or(u32::MAX))
|
||||
.disable_desktop_input_window(true)
|
||||
.origin(OriginMode::Local)
|
||||
.init()
|
||||
.expect("StereoKit failed to initialize");
|
||||
info!("Init StereoKit");
|
||||
|
||||
Renderer::multisample(0);
|
||||
Material::default().shader(Shader::pbr_clip());
|
||||
Ui::enable_far_interact(false);
|
||||
|
||||
let left_hand_material = Material::find("default/material_hand").unwrap();
|
||||
let mut right_hand_material = left_hand_material.copy();
|
||||
right_hand_material.id("right_hand");
|
||||
Input::hand_material(Handed::Right, Some(Material::find("right_hand").unwrap()));
|
||||
|
||||
Input::hand_visible(Handed::Left, false);
|
||||
Input::hand_visible(Handed::Right, false);
|
||||
|
||||
// Skytex/light stuff
|
||||
{
|
||||
let _ = DEFAULT_SKYTEX.set(Tex::gen_color(
|
||||
Color128::BLACK,
|
||||
1,
|
||||
1,
|
||||
TexType::Cubemap,
|
||||
TexFormat::RGBA32,
|
||||
));
|
||||
let _ = DEFAULT_SKYLIGHT.set(Renderer::get_skylight());
|
||||
if let Some(sky) = project_dirs
|
||||
.as_ref()
|
||||
.map(|dirs| dirs.config_dir().join("skytex.hdr"))
|
||||
.filter(|f| f.exists())
|
||||
.and_then(|p| SHCubemap::from_cubemap(p, true, 100).ok())
|
||||
{
|
||||
sky.render_as_sky();
|
||||
} else {
|
||||
Renderer::skytex(DEFAULT_SKYTEX.get().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
let mut wayland = wayland::Wayland::new().expect("Could not initialize wayland");
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.make_context_current();
|
||||
sk_ready_notifier.notify_waiters();
|
||||
info!("Stardust ready!");
|
||||
|
||||
let mut objects = ServerObjects::new(
|
||||
dbus_connection.clone(),
|
||||
&sk,
|
||||
[left_hand_material, right_hand_material],
|
||||
args.disable_controllers,
|
||||
args.disable_hands,
|
||||
);
|
||||
|
||||
let mut last_frame_delta = Duration::ZERO;
|
||||
let mut sleep_duration = Duration::ZERO;
|
||||
while let Some(token) = sk.step() {
|
||||
let _span = debug_span!("StereoKit step");
|
||||
let _span = _span.enter();
|
||||
|
||||
camera::update(token);
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.frame_event();
|
||||
destroy_queue::clear();
|
||||
|
||||
objects.update(&sk, token, &dbus_connection, &object_registry);
|
||||
input::process_input();
|
||||
nodes::root::Root::send_frame_events(Time::get_step_unscaled());
|
||||
adaptive_sleep(
|
||||
&mut last_frame_delta,
|
||||
&mut sleep_duration,
|
||||
Duration::from_micros(250),
|
||||
);
|
||||
|
||||
tick_internal_client();
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.update();
|
||||
drawable::draw(token);
|
||||
// audio::update();
|
||||
}
|
||||
|
||||
info!("Cleanly shut down StereoKit");
|
||||
}
|
||||
|
||||
fn adaptive_sleep(
|
||||
last_frame_delta: &mut Duration,
|
||||
sleep_duration: &mut Duration,
|
||||
sleep_duration_increase: Duration,
|
||||
) {
|
||||
let frame_delta = Duration::from_secs_f64(Time::get_step_unscaled());
|
||||
if *last_frame_delta < 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) {
|
||||
*sleep_duration = new_sleep_duration;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*sleep_duration += sleep_duration_increase;
|
||||
}
|
||||
|
||||
debug_span!("Sleep", ?sleep_duration, ?frame_delta, ?last_frame_delta).in_scope(|| {
|
||||
*last_frame_delta = frame_delta;
|
||||
std::thread::sleep(*sleep_duration); // to give clients a chance to even update anything before drawing
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pub mod lines;
|
||||
pub mod model;
|
||||
pub mod shaders;
|
||||
// pub mod shaders;
|
||||
pub mod text;
|
||||
|
||||
use self::{lines::Lines, model::Model, text::Text};
|
||||
@@ -8,43 +8,13 @@ use super::{
|
||||
Aspect, AspectIdentifier, Node,
|
||||
spatial::{Spatial, Transform},
|
||||
};
|
||||
use crate::{DEFAULT_SKYLIGHT, nodes::spatial::SPATIAL_ASPECT_ALIAS_INFO};
|
||||
use crate::{
|
||||
DEFAULT_SKYTEX,
|
||||
core::{client::Client, error::Result, resource::get_resource_file},
|
||||
};
|
||||
use crate::core::{client::Client, error::Result, resource::get_resource_file};
|
||||
use crate::nodes::spatial::SPATIAL_ASPECT_ALIAS_INFO;
|
||||
use color_eyre::eyre::eyre;
|
||||
use model::ModelPart;
|
||||
use parking_lot::Mutex;
|
||||
use stardust_xr::values::ResourceID;
|
||||
use std::{ffi::OsStr, path::PathBuf, sync::Arc};
|
||||
use stereokit_rust::{sk::MainThreadToken, system::Renderer, tex::SHCubemap};
|
||||
|
||||
// #[instrument(level = "debug", skip(sk))]
|
||||
pub fn draw(token: &MainThreadToken) {
|
||||
match QUEUED_SKYTEX.lock().take() {
|
||||
Some(Some(skytex)) => {
|
||||
if let Ok(skytex) = SHCubemap::from_cubemap(skytex, true, 100) {
|
||||
Renderer::skytex(skytex.tex);
|
||||
}
|
||||
}
|
||||
Some(None) => {
|
||||
Renderer::skytex(DEFAULT_SKYTEX.get().unwrap());
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
match QUEUED_SKYLIGHT.lock().take() {
|
||||
Some(Some(skylight)) => {
|
||||
if let Ok(skylight) = SHCubemap::from_cubemap(skylight, true, 100) {
|
||||
Renderer::skylight(skylight.sh);
|
||||
}
|
||||
}
|
||||
Some(None) => {
|
||||
Renderer::skylight(*DEFAULT_SKYLIGHT.get().unwrap());
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
static QUEUED_SKYLIGHT: Mutex<Option<Option<PathBuf>>> = Mutex::new(None);
|
||||
static QUEUED_SKYTEX: Mutex<Option<Option<PathBuf>>> = Mutex::new(None);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
use super::{Item, ItemType, create_item_acceptor_flex, register_item_ui_flex};
|
||||
use crate::bail;
|
||||
use crate::core::error::Result;
|
||||
@@ -9,7 +10,7 @@ use crate::{
|
||||
core::{client::Client, registry::Registry, scenegraph::MethodResponseSender},
|
||||
nodes::{
|
||||
Message, Node,
|
||||
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES},
|
||||
drawable::model::ModelPart,
|
||||
items::TypeInfo,
|
||||
spatial::{Spatial, Transform},
|
||||
},
|
||||
@@ -21,19 +22,6 @@ use parking_lot::Mutex;
|
||||
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use stereokit_rust::{
|
||||
material::{Material, Transparency},
|
||||
shader::Shader,
|
||||
sk::MainThreadToken,
|
||||
system::Renderer,
|
||||
tex::{Tex, TexFormat, TexType},
|
||||
util::Color128,
|
||||
};
|
||||
|
||||
pub struct TexWrapper(pub Tex);
|
||||
unsafe impl Send for TexWrapper {}
|
||||
unsafe impl Sync for TexWrapper {}
|
||||
|
||||
stardust_xr_server_codegen::codegen_item_camera_protocol!();
|
||||
lazy_static! {
|
||||
@@ -64,7 +52,6 @@ struct FrameInfo {
|
||||
pub struct CameraItem {
|
||||
space: Arc<Spatial>,
|
||||
frame_info: Mutex<FrameInfo>,
|
||||
sk_tex: OnceLock<TexWrapper>,
|
||||
applied_to: Registry<ModelPart>,
|
||||
apply_to: Registry<ModelPart>,
|
||||
}
|
||||
@@ -77,7 +64,6 @@ impl CameraItem {
|
||||
proj_matrix,
|
||||
px_size,
|
||||
}),
|
||||
sk_tex: OnceLock::new(),
|
||||
applied_to: Registry::new(),
|
||||
apply_to: Registry::new(),
|
||||
});
|
||||
@@ -122,41 +108,6 @@ impl CameraItem {
|
||||
pub fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
|
||||
let _ = camera_item_acceptor_client::capture_item(node, item);
|
||||
}
|
||||
|
||||
pub fn update(&self, token: &MainThreadToken) {
|
||||
let frame_info = self.frame_info.lock();
|
||||
let sk_tex = self.sk_tex.get_or_init(|| {
|
||||
TexWrapper(Tex::gen_color(
|
||||
Color128::default(),
|
||||
frame_info.px_size.x as i32,
|
||||
frame_info.px_size.y as i32,
|
||||
TexType::Rendertarget,
|
||||
TexFormat::RGBA32Linear,
|
||||
))
|
||||
});
|
||||
// let sk_mat = self.sk_mat.get_or_init(|| {
|
||||
// let shader = Shader::from_memory(UNLIT_SHADER_BYTES).unwrap();
|
||||
// let mut mat = Material::new(&shader, None);
|
||||
// mat.get_all_param_info().set_texture("diffuse", &sk_tex.0);
|
||||
// mat.transparency(Transparency::Blend);
|
||||
// Arc::new(MaterialWrapper(mat))
|
||||
// });
|
||||
for model_part in self.apply_to.take_valid_contents() {
|
||||
// model_part.replace_material(sk_mat.clone())
|
||||
}
|
||||
|
||||
if !self.applied_to.is_empty() {
|
||||
Renderer::render_to(
|
||||
token,
|
||||
&sk_tex.0,
|
||||
self.space.global_transform(),
|
||||
frame_info.proj_matrix,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AspectIdentifier for CameraItem {
|
||||
impl_aspect_for_camera_item_aspect_id! {}
|
||||
@@ -188,15 +139,6 @@ impl CameraItemAcceptorAspect for CameraItemAcceptor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(token: &MainThreadToken) {
|
||||
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
|
||||
let ItemType::Camera(camera) = &camera.specialization else {
|
||||
continue;
|
||||
};
|
||||
camera.update(token);
|
||||
}
|
||||
}
|
||||
|
||||
impl InterfaceAspect for Interface {
|
||||
#[doc = "Create a camera item at a specific location"]
|
||||
fn create_camera_item(
|
||||
|
||||
@@ -133,6 +133,7 @@ impl Drop for Item {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "wayland"), allow(dead_code))]
|
||||
pub enum ItemType {
|
||||
Camera(Arc<CameraItem>),
|
||||
Panel(Arc<dyn PanelItemTrait>),
|
||||
|
||||
@@ -102,6 +102,7 @@ pub struct PanelItem<B: Backend> {
|
||||
pub backend: Box<B>,
|
||||
}
|
||||
impl<B: Backend> PanelItem<B> {
|
||||
#[cfg_attr(not(feature = "wayland"), allow(dead_code))]
|
||||
pub fn create(backend: Box<B>, pid: Option<i32>) -> (Arc<Node>, Arc<PanelItem<B>>) {
|
||||
debug!(?pid, "Create panel item");
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ use glam::{Mat4, vec3};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::Arc;
|
||||
use stereokit_rust::system::Input;
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
pub struct EyeDatamap {
|
||||
@@ -49,58 +48,4 @@ impl EyePointer {
|
||||
pointer,
|
||||
})
|
||||
}
|
||||
pub fn update(&self) {
|
||||
let ray = Input::get_eyes();
|
||||
self.spatial
|
||||
.set_local_transform(Mat4::from_rotation_translation(
|
||||
ray.orientation.into(),
|
||||
ray.position.into(),
|
||||
));
|
||||
{
|
||||
// Set pointer input datamap
|
||||
*self.pointer.datamap.lock() = Datamap::from_typed(EyeDatamap { eye: 2 }).unwrap();
|
||||
}
|
||||
|
||||
// send input to all the input handlers that are the closest to the ray as possible
|
||||
let rx = INPUT_HANDLER_REGISTRY
|
||||
.get_valid_contents()
|
||||
.into_iter()
|
||||
// filter out all the disabled handlers
|
||||
.filter(|handler| {
|
||||
let Some(node) = handler.spatial.node() else {
|
||||
return false;
|
||||
};
|
||||
node.enabled()
|
||||
})
|
||||
// ray march to all the enabled handlers' fields
|
||||
.map(|handler| {
|
||||
let result = handler.field.ray_march(Ray {
|
||||
origin: vec3(0.0, 0.0, 0.0),
|
||||
direction: vec3(0.0, 0.0, -1.0),
|
||||
space: self.spatial.clone(),
|
||||
});
|
||||
(vec![handler], result)
|
||||
})
|
||||
// make sure the field isn't at the pointer origin and that it's being hit
|
||||
.filter(|(_, result)| result.deepest_point_distance > 0.01 && result.min_distance < 0.0)
|
||||
// .inspect(|(_, result)| {
|
||||
// dbg!(result);
|
||||
// })
|
||||
// now collect all handlers that are same distance if they're the closest
|
||||
.reduce(|(mut handlers_a, result_a), (handlers_b, result_b)| {
|
||||
if (result_a.deepest_point_distance - result_b.deepest_point_distance).abs() < 0.001
|
||||
{
|
||||
// distance is basically the same
|
||||
handlers_a.extend(handlers_b);
|
||||
(handlers_a, result_a)
|
||||
} else if result_a.deepest_point_distance < result_b.deepest_point_distance {
|
||||
(handlers_a, result_a)
|
||||
} else {
|
||||
(handlers_b, result_b)
|
||||
}
|
||||
})
|
||||
.map(|(rx, _)| rx)
|
||||
.unwrap_or_default();
|
||||
self.pointer.set_handler_order(rx.iter());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ use stardust_xr::{
|
||||
values::Datamap,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use stereokit_rust::system::{Input, Key};
|
||||
use tokio::task::JoinSet;
|
||||
use tokio::time::{Duration, timeout};
|
||||
use xkbcommon_rs::{Context, Keymap, KeymapFormat, xkb_keymap::CompileFlags};
|
||||
|
||||
@@ -40,12 +40,6 @@ use std::{
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
use stereokit_rust::{
|
||||
material::Material,
|
||||
sk::MainThreadToken,
|
||||
system::{Handed, Input},
|
||||
util::Color128,
|
||||
};
|
||||
use zbus::Connection;
|
||||
pub struct ControllerPlugin;
|
||||
const CURSOR_MODEL_PATH: &str = "/tmp/stardust_server/models/cursor.glb";
|
||||
|
||||
@@ -25,10 +25,6 @@ use openxr::{HandJointLocation, SpaceLocationFlags};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Datamap;
|
||||
use std::sync::Arc;
|
||||
use stereokit_rust::material::Material;
|
||||
use stereokit_rust::sk::{DisplayMode, MainThreadToken, Sk};
|
||||
use stereokit_rust::system::{HandJoint, HandSource, Handed, Input, LinePoint, Lines};
|
||||
use stereokit_rust::util::Color128;
|
||||
use zbus::Connection;
|
||||
|
||||
use super::{CaptureManager, get_sorted_handlers};
|
||||
@@ -372,11 +368,3 @@ impl SkHand {
|
||||
.set_handler_order(sorted_handlers.iter().map(|(handler, _)| handler));
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,180 +20,11 @@ use std::{
|
||||
marker::PhantomData,
|
||||
sync::{Arc, atomic::Ordering},
|
||||
};
|
||||
use stereokit_rust::{
|
||||
material::Material,
|
||||
sk::{DisplayMode, MainThreadToken, Sk},
|
||||
system::{Handed, Input, Key, World},
|
||||
util::Device,
|
||||
};
|
||||
use zbus::{Connection, interface, object_server::Interface, zvariant::OwnedObjectPath};
|
||||
|
||||
pub mod input;
|
||||
pub mod play_space;
|
||||
|
||||
enum Inputs {
|
||||
XR {
|
||||
// controller_left: SkController,
|
||||
// controller_right: SkController,
|
||||
// hand_left: SkHand,
|
||||
// hand_right: SkHand,
|
||||
eye_pointer: Option<EyePointer>,
|
||||
},
|
||||
MousePointer(MousePointer),
|
||||
// Controllers((SkController, SkController)),
|
||||
// Hands {
|
||||
// left: SkHand,
|
||||
// right: SkHand,
|
||||
// },
|
||||
}
|
||||
|
||||
pub struct ServerObjects {
|
||||
connection: Connection,
|
||||
hmd: (Arc<Spatial>, ObjectHandle<SpatialRef>),
|
||||
play_space: Option<(Arc<Spatial>, ObjectHandle<SpatialRef>)>,
|
||||
hand_materials: [Material; 2],
|
||||
inputs: Inputs,
|
||||
disable_controllers: bool,
|
||||
disable_hands: bool,
|
||||
}
|
||||
impl ServerObjects {
|
||||
pub fn new(
|
||||
connection: Connection,
|
||||
sk: &Sk,
|
||||
hand_materials: [Material; 2],
|
||||
disable_controllers: bool,
|
||||
disable_hands: bool,
|
||||
) -> ServerObjects {
|
||||
let hmd = SpatialRef::create(&connection, "/org/stardustxr/HMD");
|
||||
|
||||
let play_space = Some(SpatialRef::create(&connection, "/org/stardustxr/PlaySpace"));
|
||||
if play_space.is_some() {
|
||||
let dbus_connection = connection.clone();
|
||||
tokio::task::spawn(async move {
|
||||
let play_space_data = Arc::new(RwLock::default());
|
||||
PlaySpaceBounds::create(&dbus_connection, play_space_data).await;
|
||||
dbus_connection
|
||||
.request_name("org.stardustxr.PlaySpace")
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
tokio::task::spawn({
|
||||
let connection = connection.clone();
|
||||
async move {
|
||||
connection
|
||||
.request_name("org.stardustxr.Controllers")
|
||||
.await
|
||||
.unwrap();
|
||||
connection
|
||||
.request_name("org.stardustxr.Hands")
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let inputs = if sk.get_active_display_mode() == DisplayMode::MixedReality {
|
||||
Inputs::XR {
|
||||
// hand_left: SkHand::new(&connection, Handed::Left).unwrap(),
|
||||
// hand_right: SkHand::new(&connection, Handed::Right).unwrap(),
|
||||
eye_pointer: Device::has_eye_gaze()
|
||||
.then(EyePointer::new)
|
||||
.transpose()
|
||||
.unwrap(),
|
||||
}
|
||||
} else {
|
||||
Inputs::MousePointer(MousePointer::new().unwrap())
|
||||
};
|
||||
|
||||
ServerObjects {
|
||||
connection,
|
||||
hmd,
|
||||
play_space,
|
||||
hand_materials,
|
||||
inputs,
|
||||
disable_controllers,
|
||||
disable_hands,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
sk: &Sk,
|
||||
token: &MainThreadToken,
|
||||
dbus_connection: &Connection,
|
||||
object_registry: &ObjectRegistry,
|
||||
) {
|
||||
let hmd_pose = Input::get_head();
|
||||
self.hmd
|
||||
.0
|
||||
.set_local_transform(Mat4::from_scale_rotation_translation(
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
hmd_pose.orientation.into(),
|
||||
hmd_pose.position.into(),
|
||||
));
|
||||
|
||||
if let Some(play_space) = self.play_space.as_ref() {
|
||||
let pose = World::get_bounds_pose();
|
||||
play_space
|
||||
.0
|
||||
.set_local_transform(Mat4::from_rotation_translation(
|
||||
pose.orientation.into(),
|
||||
pose.position.into(),
|
||||
));
|
||||
}
|
||||
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if sk.get_active_display_mode() != DisplayMode::MixedReality {
|
||||
if Input::key(Key::F6).is_just_inactive() {
|
||||
self.inputs = Inputs::MousePointer(MousePointer::new().unwrap());
|
||||
}
|
||||
// if Input::key(Key::F7).is_just_inactive() {
|
||||
// self.inputs = Inputs::Controllers((
|
||||
// SkController::new(Handed::Left).unwrap(),
|
||||
// SkController::new(Handed::Right).unwrap(),
|
||||
// ));
|
||||
// }
|
||||
// if Input::key(Key::F8).is_just_inactive() {
|
||||
// self.inputs = Inputs::Hands {
|
||||
// left: SkHand::new(&self.connection, Handed::Left).unwrap(),
|
||||
// right: SkHand::new(&self.connection, Handed::Right).unwrap(),
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
||||
match &mut self.inputs {
|
||||
Inputs::XR {
|
||||
// controller_left,
|
||||
// controller_right,
|
||||
eye_pointer,
|
||||
} => {
|
||||
// if !self.disable_controllers {
|
||||
// controller_left.update(token);
|
||||
// controller_right.update(token);
|
||||
// }
|
||||
Input::hand_visible(Handed::Left, !self.disable_hands);
|
||||
Input::hand_visible(Handed::Right, !self.disable_hands);
|
||||
// if !self.disable_hands {
|
||||
// hand_left.update(sk, token, &mut self.hand_materials[0]);
|
||||
// hand_right.update(sk, token, &mut self.hand_materials[1]);
|
||||
// }
|
||||
if let Some(eye_pointer) = eye_pointer {
|
||||
eye_pointer.update();
|
||||
}
|
||||
}
|
||||
Inputs::MousePointer(mouse_pointer) => {} // Inputs::Controllers((left, right)) => {
|
||||
// left.update(token);
|
||||
// right.update(token);
|
||||
// }
|
||||
// Inputs::Hands { left, right } => {
|
||||
// left.update(sk, token, &mut self.hand_materials[0]);
|
||||
// right.update(sk, token, &mut self.hand_materials[1]);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ObjectHandle<I: Interface>(Connection, OwnedObjectPath, PhantomData<I>);
|
||||
|
||||
impl<I: Interface> Clone for ObjectHandle<I> {
|
||||
|
||||
@@ -12,7 +12,6 @@ use bevy_mod_xr::{
|
||||
};
|
||||
use openxr::SpaceLocationFlags;
|
||||
use parking_lot::RwLock;
|
||||
use stereokit_rust::system::World;
|
||||
use zbus::{Connection, ObjectServer, interface};
|
||||
|
||||
use crate::{DbusConnection, PreFrameWait, nodes::spatial::Spatial};
|
||||
|
||||
Reference in New Issue
Block a user
⚠️ Potential issue
Fix undefined
waylandvariable in xr_step function.The
waylandvariable is referenced but not defined in this function scope. This will cause compilation errors when the wayland feature is enabled.The wayland instance needs to be made accessible to the xr_step function. Consider these options:
🤖 Prompt for AI Agents
✅ Addressed in commits
d2afa00toaec875a💡 Verification agent
🧩 Analysis chain
Verify the extremely small near plane value.
The near plane is set to 0.003 meters (3mm), which is unusually small and may cause z-fighting or depth precision issues.
Consider using a more typical value like 0.01 or 0.05 meters for VR applications. The small value might be intentional for specific use cases, but it's worth verifying.
🌐 Web query:
💡 Result:
In VR/XR applications, the recommended near plane distance is typically set to a value that balances depth precision and minimizes z-fighting.
A common guideline is to set the near plane distance to around 0.1 meters (10 centimeters) or slightly above. This is because:
For VR, which often requires accurate depth perception at close range, 0.1 meters is a good starting point. Some developers go as close as 0.05 meters if their engine and hardware support higher precision depth buffers (like using 24 or 32-bit depth buffers), but going below that usually causes depth fighting.
To sum up:
If you want, I can also look up the latest best practices or guidelines from specific VR platforms or engines. Would you like me to do that?
Re-evaluate the near‐plane setting (0.003 m)
A 3 mm near plane is well below common VR/XR guidelines (typically ≥ 0.05–0.1 m) and can severely degrade depth‐buffer precision, leading to z-fighting. Please confirm whether such an ultra-close near plane is required for your use case, or consider increasing it to a more typical value (e.g., 0.05–0.1 m).
• Location:
src/main.rs, lines 415–431• All three branches set
near = 0.003(Perspective, Orthographic, andXrProjection)Suggested change example:
📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commits
d2afa00toaec875a