Bevy Rewrite, attempt 2 #46

Merged
Schmarni-Dev merged 18 commits from bevy_for_real_this_time into dev 2025-06-30 05:04:00 -04:00
15 changed files with 35 additions and 599 deletions
Showing only changes of commit ce704489c6 - Show all commits

86
Cargo.lock generated
View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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}")]

View File

@@ -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 {
coderabbitai[bot] commented 2025-06-28 14:53:14 -04:00 (Migrated from github.com)
Review

⚠️ Potential issue

Fix undefined wayland variable in xr_step function.

The wayland variable 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:

  1. Store it as a Bevy resource:
#[cfg(feature = "wayland")]
#[derive(Resource)]
struct WaylandResource(wayland::Wayland);
  1. Or remove these calls if wayland support is not yet implemented (as mentioned in the PR description).
🤖 Prompt for AI Agents
In src/main.rs between lines 433 and 473, the xr_step function references the
wayland variable without defining or accessing it, causing compilation errors
when the wayland feature is enabled. To fix this, make the wayland instance
accessible inside xr_step by storing it as a Bevy resource (e.g., define a
WaylandResource struct wrapping wayland::Wayland and insert it into the world
resources), then retrieve and use it within xr_step. Alternatively, if wayland
support is not implemented yet, remove or comment out the wayland-related calls
to avoid undefined variable errors.

Addressed in commits d2afa00 to aec875a

_⚠️ Potential issue_ **Fix undefined `wayland` variable in xr_step function.** The `wayland` variable 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: 1. Store it as a Bevy resource: ```rust #[cfg(feature = "wayland")] #[derive(Resource)] struct WaylandResource(wayland::Wayland); ``` 2. Or remove these calls if wayland support is not yet implemented (as mentioned in the PR description). <details> <summary>🤖 Prompt for AI Agents</summary> ``` In src/main.rs between lines 433 and 473, the xr_step function references the wayland variable without defining or accessing it, causing compilation errors when the wayland feature is enabled. To fix this, make the wayland instance accessible inside xr_step by storing it as a Bevy resource (e.g., define a WaylandResource struct wrapping wayland::Wayland and insert it into the world resources), then retrieve and use it within xr_step. Alternatively, if wayland support is not implemented yet, remove or comment out the wayland-related calls to avoid undefined variable errors. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> <!-- fingerprinting:phantom:medusa:lion --> ✅ Addressed in commits d2afa00 to aec875a
coderabbitai[bot] commented 2025-06-28 14:53:14 -04:00 (Migrated from github.com)
Review

💡 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:

What is the recommended near plane distance for VR/XR applications to avoid z-fighting and maintain depth precision?

💡 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:

  • Setting the near plane too close (e.g., less than 0.01 meters) severely reduces depth buffer precision, causing z-fighting at farther distances.
  • Setting it too far can clip nearby objects that are important to the VR experience.

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:

  • Recommended near plane distance: ~0.1 meters (10 cm)
  • Ensure a far plane distance is not excessively large to maximize depth buffer precision.
  • Use a 24-bit or 32-bit depth buffer to improve precision.
  • Adjust based on your scene scale and hardware capabilities.

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, and XrProjection)

Suggested change example:

--- a/src/main.rs
+++ b/src/main.rs
@@ fn update_cameras(mut camera: Query<&mut Projection, (With<Camera3d>,)>) {
-           Projection::Perspective(p) => p.near = 0.003,
+           Projection::Perspective(p) => p.near = 0.1,     // consider 0.05–0.1 m for VR/XR
@@
-           Projection::Orthographic(o) => o.near = 0.003,
+           Projection::Orthographic(o) => o.near = 0.1,
@@
-                   xr.near = 0.003
+                   xr.near = 0.1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

fn update_cameras(mut camera: Query<&mut Projection, (With<Camera3d>,)>) {
    for mut projection in &mut camera {
        match projection.deref_mut() {
            // consider 0.05–0.1 m for VR/XR instead of 0.003 m
            Projection::Perspective(perspective_projection) => perspective_projection.near = 0.1,
            Projection::Orthographic(orthographic_projection) => {
                orthographic_projection.near = 0.1
            }
            Projection::Custom(custom_projection) => {
                if let Some(xr) = custom_projection.get_mut::<XrProjection>() {
                    xr.near = 0.1
                } else {
                    error_once!("unknown custom camera projection");
                }
            }
        }
    }
}
🤖 Prompt for AI Agents
In src/main.rs around lines 415 to 431, the near plane for all camera
projections is set to 0.003, which is unusually close and can cause depth
precision issues. Review your application's requirements to determine if such a
small near plane is necessary; if not, increase the near plane distance to a
more standard value between 0.05 and 0.1 meters by updating the assignments in
all branches of the match statement accordingly.

Addressed in commits d2afa00 to aec875a

_💡 Verification agent_ <details> <summary>🧩 Analysis chain</summary> **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: ```web What is the recommended near plane distance for VR/XR applications to avoid z-fighting and maintain depth precision? ``` 💡 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: - Setting the near plane too close (e.g., less than 0.01 meters) severely reduces depth buffer precision, causing z-fighting at farther distances. - Setting it too far can clip nearby objects that are important to the VR experience. 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: - **Recommended near plane distance:** ~0.1 meters (10 cm) - Ensure a far plane distance is not excessively large to maximize depth buffer precision. - Use a 24-bit or 32-bit depth buffer to improve precision. - Adjust based on your scene scale and hardware capabilities. 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? --- </details> **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, and `XrProjection`) Suggested change example: ```diff --- a/src/main.rs +++ b/src/main.rs @@ fn update_cameras(mut camera: Query<&mut Projection, (With<Camera3d>,)>) { - Projection::Perspective(p) => p.near = 0.003, + Projection::Perspective(p) => p.near = 0.1, // consider 0.05–0.1 m for VR/XR @@ - Projection::Orthographic(o) => o.near = 0.003, + Projection::Orthographic(o) => o.near = 0.1, @@ - xr.near = 0.003 + xr.near = 0.1 ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion fn update_cameras(mut camera: Query<&mut Projection, (With<Camera3d>,)>) { for mut projection in &mut camera { match projection.deref_mut() { // consider 0.05–0.1 m for VR/XR instead of 0.003 m Projection::Perspective(perspective_projection) => perspective_projection.near = 0.1, Projection::Orthographic(orthographic_projection) => { orthographic_projection.near = 0.1 } Projection::Custom(custom_projection) => { if let Some(xr) = custom_projection.get_mut::<XrProjection>() { xr.near = 0.1 } else { error_once!("unknown custom camera projection"); } } } } } ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In src/main.rs around lines 415 to 431, the near plane for all camera projections is set to 0.003, which is unusually close and can cause depth precision issues. Review your application's requirements to determine if such a small near plane is necessary; if not, increase the near plane distance to a more standard value between 0.05 and 0.1 meters by updating the assignments in all branches of the match statement accordingly. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> <!-- fingerprinting:phantom:medusa:lion --> ✅ Addressed in commits d2afa00 to aec875a
@@ -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
});
}

View File

@@ -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);

View File

@@ -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(

View File

@@ -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>),

View File

@@ -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");

View File

@@ -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());
}
}

View File

@@ -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};

View File

@@ -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";

View File

@@ -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(),
}
}

View File

@@ -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> {

View File

@@ -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};