diff --git a/Cargo.toml b/Cargo.toml index bd61fc93..c35974ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT/Apache-2.0" [features] -default = ["linked"] -linked = ["openxr/linked"] +default = [] +force-link = ["openxr/linked"] [workspace] members = ["examples/android", "examples/demo"] @@ -24,9 +24,10 @@ wgpu = "0.17.1" wgpu-core = { version = "0.17.1", features = ["vulkan"] } wgpu-hal = "0.17.1" +[target.'cfg(windows)'.dependencies] +openxr = { version = "0.17.1", features = ["linked","static","mint"] } [target.'cfg(all(target_family = "unix", not(target_arch = "wasm32")) )'.dependencies] openxr = { version = "0.17.1", features = ["mint"] } - [target.'cfg(all(not(target_family = "unix"), not(target_arch = "wasm32")))'.dependencies] openxr = { version = "0.17.1", features = ["mint", "static"] } @@ -41,3 +42,6 @@ path = "examples/xr.rs" [profile.release] debug = true + +[patch.crates-io] +ndk = { git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } diff --git a/README.md b/README.md index 8fe5d79a..5bdf0b12 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,14 @@ To see it in action run the example in `examples` with `cargo run --example xr` - Make sure, if you're on Linux, that you have the `openxr` package installed on your system. - I'm getting poor performance. - Like other bevy projects, make sure you're building in release (example: `cargo run --example xr --release`) + +## Recommendations + +for now we recommend you to add the folowing to your root Cargo.toml +``` +[patch.crates-io] +ndk = { git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } +ndk-sys = { package = "ndk-sys", git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } +ndk-context = { package = "ndk-context", git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } +bevy_pbr = { package = "bevy_pbr", git = "https://github.com/MalekiRe/bevy", branch = "release-0.12.1" } +``` diff --git a/examples/android/Cargo.toml b/examples/android/Cargo.toml index 2a52a8af..9f3f65ac 100644 --- a/examples/android/Cargo.toml +++ b/examples/android/Cargo.toml @@ -10,13 +10,9 @@ license = "MIT OR Apache-2.0" name = "bevy_openxr_android" crate-type = ["rlib", "cdylib"] -[target.'cfg(not(target_os="android"))'.dependencies.bevy_oxr] -path = "../../" -default-features = true - [dependencies] -bevy_oxr = { path = "../..", default-features = false } +bevy_oxr.path = "../.." bevy = "0.12" openxr = { git = "https://github.com/Ralith/openxrs", features = ["mint"] } diff --git a/examples/android/src/lib.rs b/examples/android/src/lib.rs index 4f8bdeb3..4fabb2b8 100644 --- a/examples/android/src/lib.rs +++ b/examples/android/src/lib.rs @@ -1,6 +1,7 @@ use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::prelude::*; use bevy::transform::components::Transform; +use bevy_oxr::graphics::XrAppInfo; use bevy_oxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_oxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; use bevy_oxr::xr_input::trackers::{ @@ -11,7 +12,12 @@ use bevy_oxr::DefaultXrPlugins; #[bevy_main] fn main() { App::new() - .add_plugins(DefaultXrPlugins) + .add_plugins(DefaultXrPlugins { + app_info: XrAppInfo { + name: "Bevy OXR Android Example".into(), + }, + ..default() + }) .add_plugins(OpenXrDebugRenderer) .add_plugins(LogDiagnosticsPlugin::default()) .add_plugins(FrameTimeDiagnosticsPlugin) diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml index a6abbf91..14e39de4 100644 --- a/examples/demo/Cargo.toml +++ b/examples/demo/Cargo.toml @@ -10,12 +10,21 @@ crate-type = ["rlib", "cdylib"] [dependencies] bevy = "0.12" -bevy_oxr = { path = "../../", default-features = false } +bevy_oxr.path = "../../" bevy_rapier3d = { git = "https://github.com/devil-ira/bevy_rapier", branch = "bevy-0.12" } color-eyre = "0.6.2" -[target.'cfg(not(target_os="android"))'.dependencies.bevy_oxr] -path = "../../" -# May need to be more specific. needs to be false at least on linux without an active runtime to run in flat -default-features = true +# [target.'cfg(not(target_os="android"))'.dependencies.bevy_oxr] +# path = "../../" +# # May need to be more specific. needs to be false at least on linux without an active runtime to run in flat +# default-features = true + +[profile.release] +debug = true + +[patch.crates-io] +ndk = { git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } +ndk-sys = { package = "ndk-sys", git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } +ndk-context = { package = "ndk-context", git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } +ndk-glue = { package = "ndk-glue", git = "https://github.com/Schmarni-Dev/ndk.git", branch = "070" } diff --git a/examples/demo/manifest.yaml b/examples/demo/manifest.yaml index ab098d6d..730187ad 100644 --- a/examples/demo/manifest.yaml +++ b/examples/demo/manifest.yaml @@ -3,13 +3,14 @@ android: - "runtime_libs" manifest: package: "org.bevyengine.demo_openxr_android" + # Are features and permissions fliped? uses_feature: - name: "android.hardware.vr.headtracking" required: true - name: "oculus.software.handtracking" required: false - - name: "com.oculus.experimental.enabled" - required: true + # - name: "com.oculus.feature.PASSTHROUGH" + # required: true uses_permission: - name: "com.oculus.permission.HAND_TRACKING" application: diff --git a/examples/demo/src/lib.rs b/examples/demo/src/lib.rs index 9ce50002..22529c78 100644 --- a/examples/demo/src/lib.rs +++ b/examples/demo/src/lib.rs @@ -16,9 +16,10 @@ use bevy::{ transform::TransformSystem, }; use bevy_oxr::{ + graphics::{extensions::XrExtensions, XrAppInfo, XrPreferdBlendMode}, input::XrInput, - xr_init::{XrEnableRequest, XrEnableStatus, xr_only}, resources::{XrFrameState, XrInstance, XrSession}, + xr_init::{xr_only, XrEnableRequest, XrEnableStatus}, xr_input::{ actions::XrActionSets, debug_gizmos::OpenXrDebugRenderer, @@ -31,7 +32,10 @@ use bevy_oxr::{ }, oculus_touch::OculusController, prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}, - trackers::{OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker}, + trackers::{ + OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, + OpenXRTrackingRoot, + }, Hand, }, DefaultXrPlugins, @@ -61,13 +65,20 @@ pub fn main() { info!("Running bevy_openxr demo"); let mut app = App::new(); + let mut xr_extensions = XrExtensions::default(); app.add_systems(Update, input_stuff) //lets get the usual diagnostic stuff added .add_plugins(LogDiagnosticsPlugin::default()) .add_plugins(FrameTimeDiagnosticsPlugin) //lets get the xr defaults added - .add_plugins(DefaultXrPlugins) + .add_plugins(DefaultXrPlugins { + reqeusted_extensions: xr_extensions, + prefered_blend_mode: XrPreferdBlendMode::Opaque, + app_info: XrAppInfo { + name: "Bevy OXR Demo".into(), + }, + }) //lets add the debug renderer for the controllers .add_plugins(OpenXrDebugRenderer) //rapier goes here @@ -93,7 +104,9 @@ pub fn main() { //draw the interaction gizmos .add_systems( Update, - draw_interaction_gizmos.run_if(xr_only()).after(update_interactable_states), + draw_interaction_gizmos + .run_if(xr_only()) + .after(update_interactable_states), ) .add_systems(Update, draw_socket_gizmos.after(update_interactable_states)) //add our cube spawning system diff --git a/examples/demo/src/setup.rs b/examples/demo/src/setup.rs index 46d4d517..5d3157f1 100644 --- a/examples/demo/src/setup.rs +++ b/examples/demo/src/setup.rs @@ -8,7 +8,7 @@ use bevy::{ }; use bevy_oxr::xr_input::interactions::{Touched, XRInteractable, XRInteractableState}; use bevy_rapier3d::{ - prelude::{Collider, RigidBody, Group, CollisionGroups}, + prelude::{Collider, CollisionGroups, Group, RigidBody}, render::ColliderDebugColor, }; @@ -67,7 +67,7 @@ pub fn setup_scene( // }); // camera commands.spawn((Camera3dBundle { - transform: Transform::from_xyz(0.25, 1.25, 0.0).looking_at( + transform: Transform::from_xyz(5.25, 5.25, 5.0).looking_at( Vec3 { x: -0.548, y: -0.161, diff --git a/examples/globe.rs b/examples/globe.rs index fef489af..cf58bea7 100644 --- a/examples/globe.rs +++ b/examples/globe.rs @@ -1,6 +1,7 @@ use bevy::diagnostic::LogDiagnosticsPlugin; use bevy::prelude::*; use bevy::transform::components::Transform; +use bevy_oxr::graphics::XrAppInfo; use bevy_oxr::resources::XrViews; use bevy_oxr::xr_input::hands::common::{HandInputDebugRenderer, OpenXrHandInput}; use bevy_oxr::xr_input::interactions::{ @@ -19,7 +20,12 @@ fn main() { color_eyre::install().unwrap(); App::new() - .add_plugins(DefaultXrPlugins) + .add_plugins(DefaultXrPlugins { + app_info: XrAppInfo { + name: "Bevy OXR Globe Example".into(), + }, + ..default() + }) .add_plugins(LogDiagnosticsPlugin::default()) .add_systems(Startup, setup) .add_systems(Update, (proto_locomotion, pull_to_ground).chain()) diff --git a/examples/xr.rs b/examples/xr.rs index 79e1c906..b38d79a5 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -2,6 +2,7 @@ use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::prelude::*; use bevy::transform::components::Transform; +use bevy_oxr::graphics::XrAppInfo; use bevy_oxr::input::XrInput; use bevy_oxr::resources::{XrFrameState, XrSession}; @@ -25,7 +26,12 @@ fn main() { info!("Running `openxr-6dof` skill"); App::new() - .add_plugins(DefaultXrPlugins) + .add_plugins(DefaultXrPlugins { + app_info: XrAppInfo { + name: "Bevy OXR Example".into(), + }, + ..default() + }) //.add_plugins(OpenXrDebugRenderer) //new debug renderer adds gizmos to .add_plugins(LogDiagnosticsPlugin::default()) .add_plugins(FrameTimeDiagnosticsPlugin) diff --git a/src/graphics/extensions.rs b/src/graphics/extensions.rs new file mode 100644 index 00000000..908648a1 --- /dev/null +++ b/src/graphics/extensions.rs @@ -0,0 +1,242 @@ +use openxr::ExtensionSet; +use std::ops; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct XrExtensions(ExtensionSet); +impl XrExtensions { + pub fn raw_mut(&mut self) -> &mut ExtensionSet { + &mut self.0 + } + pub fn raw(&self) -> &ExtensionSet { + &self.0 + } + // pub fn enable_fb_passthrough(&mut self) -> &mut Self { + // self.0.fb_passthrough = true; + // self + // } + // pub fn disable_fb_passthrough(&mut self) -> &mut Self { + // self.0.fb_passthrough = false; + // self + // } + pub fn enable_hand_tracking(&mut self) -> &mut Self { + self.0.ext_hand_tracking = true; + self + } + pub fn disable_hand_tracking(&mut self) -> &mut Self { + self.0.ext_hand_tracking = false; + self + } +} +impl From for XrExtensions { + fn from(value: ExtensionSet) -> Self { + Self(value) + } +} +impl From for ExtensionSet { + fn from(val: XrExtensions) -> Self { + val.0 + } +} +impl Default for XrExtensions { + fn default() -> Self { + let mut exts = ExtensionSet::default(); + exts.ext_hand_tracking = true; + Self(exts) + } +} +impl ops::BitAnd for XrExtensions { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + let mut out = ExtensionSet::default(); + out.almalence_digital_lens_control = + self.0.almalence_digital_lens_control && rhs.0.almalence_digital_lens_control; + out.epic_view_configuration_fov = + self.0.epic_view_configuration_fov && rhs.0.epic_view_configuration_fov; + out.ext_performance_settings = + self.0.ext_performance_settings && rhs.0.ext_performance_settings; + out.ext_thermal_query = self.0.ext_thermal_query && rhs.0.ext_thermal_query; + out.ext_debug_utils = self.0.ext_debug_utils && rhs.0.ext_debug_utils; + out.ext_eye_gaze_interaction = + self.0.ext_eye_gaze_interaction && rhs.0.ext_eye_gaze_interaction; + out.ext_view_configuration_depth_range = + self.0.ext_view_configuration_depth_range && rhs.0.ext_view_configuration_depth_range; + out.ext_conformance_automation = + self.0.ext_conformance_automation && rhs.0.ext_conformance_automation; + out.ext_hand_tracking = self.0.ext_hand_tracking && rhs.0.ext_hand_tracking; + out.ext_dpad_binding = self.0.ext_dpad_binding && rhs.0.ext_dpad_binding; + out.ext_hand_joints_motion_range = + self.0.ext_hand_joints_motion_range && rhs.0.ext_hand_joints_motion_range; + out.ext_samsung_odyssey_controller = + self.0.ext_samsung_odyssey_controller && rhs.0.ext_samsung_odyssey_controller; + out.ext_hp_mixed_reality_controller = + self.0.ext_hp_mixed_reality_controller && rhs.0.ext_hp_mixed_reality_controller; + out.ext_palm_pose = self.0.ext_palm_pose && rhs.0.ext_palm_pose; + out.ext_uuid = self.0.ext_uuid && rhs.0.ext_uuid; + out.extx_overlay = self.0.extx_overlay && rhs.0.extx_overlay; + out.fb_composition_layer_image_layout = + self.0.fb_composition_layer_image_layout && rhs.0.fb_composition_layer_image_layout; + out.fb_composition_layer_alpha_blend = + self.0.fb_composition_layer_alpha_blend && rhs.0.fb_composition_layer_alpha_blend; + out.fb_swapchain_update_state = + self.0.fb_swapchain_update_state && rhs.0.fb_swapchain_update_state; + out.fb_composition_layer_secure_content = + self.0.fb_composition_layer_secure_content && rhs.0.fb_composition_layer_secure_content; + out.fb_display_refresh_rate = + self.0.fb_display_refresh_rate && rhs.0.fb_display_refresh_rate; + out.fb_color_space = self.0.fb_color_space && rhs.0.fb_color_space; + out.fb_hand_tracking_mesh = self.0.fb_hand_tracking_mesh && rhs.0.fb_hand_tracking_mesh; + out.fb_hand_tracking_aim = self.0.fb_hand_tracking_aim && rhs.0.fb_hand_tracking_aim; + out.fb_hand_tracking_capsules = + self.0.fb_hand_tracking_capsules && rhs.0.fb_hand_tracking_capsules; + out.fb_spatial_entity = self.0.fb_spatial_entity && rhs.0.fb_spatial_entity; + out.fb_foveation = self.0.fb_foveation && rhs.0.fb_foveation; + out.fb_foveation_configuration = + self.0.fb_foveation_configuration && rhs.0.fb_foveation_configuration; + out.fb_keyboard_tracking = self.0.fb_keyboard_tracking && rhs.0.fb_keyboard_tracking; + out.fb_triangle_mesh = self.0.fb_triangle_mesh && rhs.0.fb_triangle_mesh; + out.fb_passthrough = self.0.fb_passthrough && rhs.0.fb_passthrough; + out.fb_render_model = self.0.fb_render_model && rhs.0.fb_render_model; + out.fb_spatial_entity_query = + self.0.fb_spatial_entity_query && rhs.0.fb_spatial_entity_query; + out.fb_spatial_entity_storage = + self.0.fb_spatial_entity_storage && rhs.0.fb_spatial_entity_storage; + out.fb_foveation_vulkan = self.0.fb_foveation_vulkan && rhs.0.fb_foveation_vulkan; + out.fb_swapchain_update_state_opengl_es = + self.0.fb_swapchain_update_state_opengl_es && rhs.0.fb_swapchain_update_state_opengl_es; + out.fb_swapchain_update_state_vulkan = + self.0.fb_swapchain_update_state_vulkan && rhs.0.fb_swapchain_update_state_vulkan; + out.fb_space_warp = self.0.fb_space_warp && rhs.0.fb_space_warp; + out.fb_scene = self.0.fb_scene && rhs.0.fb_scene; + out.fb_spatial_entity_container = + self.0.fb_spatial_entity_container && rhs.0.fb_spatial_entity_container; + out.fb_passthrough_keyboard_hands = + self.0.fb_passthrough_keyboard_hands && rhs.0.fb_passthrough_keyboard_hands; + out.fb_composition_layer_settings = + self.0.fb_composition_layer_settings && rhs.0.fb_composition_layer_settings; + out.htc_vive_cosmos_controller_interaction = self.0.htc_vive_cosmos_controller_interaction + && rhs.0.htc_vive_cosmos_controller_interaction; + out.htc_facial_tracking = self.0.htc_facial_tracking && rhs.0.htc_facial_tracking; + out.htc_vive_focus3_controller_interaction = self.0.htc_vive_focus3_controller_interaction + && rhs.0.htc_vive_focus3_controller_interaction; + out.htc_hand_interaction = self.0.htc_hand_interaction && rhs.0.htc_hand_interaction; + out.htc_vive_wrist_tracker_interaction = + self.0.htc_vive_wrist_tracker_interaction && rhs.0.htc_vive_wrist_tracker_interaction; + out.htcx_vive_tracker_interaction = + self.0.htcx_vive_tracker_interaction && rhs.0.htcx_vive_tracker_interaction; + out.huawei_controller_interaction = + self.0.huawei_controller_interaction && rhs.0.huawei_controller_interaction; + out.khr_composition_layer_cube = + self.0.khr_composition_layer_cube && rhs.0.khr_composition_layer_cube; + out.khr_composition_layer_depth = + self.0.khr_composition_layer_depth && rhs.0.khr_composition_layer_depth; + out.khr_vulkan_swapchain_format_list = + self.0.khr_vulkan_swapchain_format_list && rhs.0.khr_vulkan_swapchain_format_list; + out.khr_composition_layer_cylinder = + self.0.khr_composition_layer_cylinder && rhs.0.khr_composition_layer_cylinder; + out.khr_composition_layer_equirect = + self.0.khr_composition_layer_equirect && rhs.0.khr_composition_layer_equirect; + out.khr_opengl_enable = self.0.khr_opengl_enable && rhs.0.khr_opengl_enable; + out.khr_opengl_es_enable = self.0.khr_opengl_es_enable && rhs.0.khr_opengl_es_enable; + out.khr_vulkan_enable = self.0.khr_vulkan_enable && rhs.0.khr_vulkan_enable; + out.khr_visibility_mask = self.0.khr_visibility_mask && rhs.0.khr_visibility_mask; + out.khr_composition_layer_color_scale_bias = self.0.khr_composition_layer_color_scale_bias + && rhs.0.khr_composition_layer_color_scale_bias; + out.khr_convert_timespec_time = + self.0.khr_convert_timespec_time && rhs.0.khr_convert_timespec_time; + out.khr_loader_init = self.0.khr_loader_init && rhs.0.khr_loader_init; + out.khr_vulkan_enable2 = self.0.khr_vulkan_enable2 && rhs.0.khr_vulkan_enable2; + out.khr_composition_layer_equirect2 = + self.0.khr_composition_layer_equirect2 && rhs.0.khr_composition_layer_equirect2; + out.khr_binding_modification = + self.0.khr_binding_modification && rhs.0.khr_binding_modification; + out.khr_swapchain_usage_input_attachment_bit = + self.0.khr_swapchain_usage_input_attachment_bit + && rhs.0.khr_swapchain_usage_input_attachment_bit; + out.meta_vulkan_swapchain_create_info = + self.0.meta_vulkan_swapchain_create_info && rhs.0.meta_vulkan_swapchain_create_info; + out.meta_performance_metrics = + self.0.meta_performance_metrics && rhs.0.meta_performance_metrics; + out.ml_ml2_controller_interaction = + self.0.ml_ml2_controller_interaction && rhs.0.ml_ml2_controller_interaction; + out.mnd_headless = self.0.mnd_headless && rhs.0.mnd_headless; + out.mnd_swapchain_usage_input_attachment_bit = + self.0.mnd_swapchain_usage_input_attachment_bit + && rhs.0.mnd_swapchain_usage_input_attachment_bit; + out.mndx_egl_enable = self.0.mndx_egl_enable && rhs.0.mndx_egl_enable; + out.msft_unbounded_reference_space = + self.0.msft_unbounded_reference_space && rhs.0.msft_unbounded_reference_space; + out.msft_spatial_anchor = self.0.msft_spatial_anchor && rhs.0.msft_spatial_anchor; + out.msft_spatial_graph_bridge = + self.0.msft_spatial_graph_bridge && rhs.0.msft_spatial_graph_bridge; + out.msft_hand_interaction = self.0.msft_hand_interaction && rhs.0.msft_hand_interaction; + out.msft_hand_tracking_mesh = + self.0.msft_hand_tracking_mesh && rhs.0.msft_hand_tracking_mesh; + out.msft_secondary_view_configuration = + self.0.msft_secondary_view_configuration && rhs.0.msft_secondary_view_configuration; + out.msft_first_person_observer = + self.0.msft_first_person_observer && rhs.0.msft_first_person_observer; + out.msft_controller_model = self.0.msft_controller_model && rhs.0.msft_controller_model; + out.msft_composition_layer_reprojection = + self.0.msft_composition_layer_reprojection && rhs.0.msft_composition_layer_reprojection; + out.msft_spatial_anchor_persistence = + self.0.msft_spatial_anchor_persistence && rhs.0.msft_spatial_anchor_persistence; + out.oculus_audio_device_guid = + self.0.oculus_audio_device_guid && rhs.0.oculus_audio_device_guid; + out.ultraleap_hand_tracking_forearm = + self.0.ultraleap_hand_tracking_forearm && rhs.0.ultraleap_hand_tracking_forearm; + out.valve_analog_threshold = self.0.valve_analog_threshold && rhs.0.valve_analog_threshold; + out.varjo_quad_views = self.0.varjo_quad_views && rhs.0.varjo_quad_views; + out.varjo_foveated_rendering = + self.0.varjo_foveated_rendering && rhs.0.varjo_foveated_rendering; + out.varjo_composition_layer_depth_test = + self.0.varjo_composition_layer_depth_test && rhs.0.varjo_composition_layer_depth_test; + out.varjo_environment_depth_estimation = + self.0.varjo_environment_depth_estimation && rhs.0.varjo_environment_depth_estimation; + out.varjo_marker_tracking = self.0.varjo_marker_tracking && rhs.0.varjo_marker_tracking; + out.varjo_view_offset = self.0.varjo_view_offset && rhs.0.varjo_view_offset; + and_android_only_exts(&self, &rhs, &mut out); + and_windows_only_exts(&self, &rhs, &mut out); + for ext in self.0.other { + if rhs.0.other.contains(&ext) { + out.other.push(ext); + } + } + Self(out) + } +} + +#[cfg(not(target_os = "android"))] +fn and_android_only_exts(lhs: &XrExtensions, rhs: &XrExtensions, out: &mut ExtensionSet) {} +#[cfg(not(windows))] +fn and_windows_only_exts(lhs: &XrExtensions, rhs: &XrExtensions, out: &mut ExtensionSet) {} +#[cfg(target_os = "android")] +fn and_android_only_exts(lhs: &XrExtensions, rhs: &XrExtensions, out: &mut ExtensionSet) { + out.oculus_android_session_state_enable = + lhs.0.oculus_android_session_state_enable && rhs.0.oculus_android_session_state_enable; + out.khr_loader_init_android = lhs.0.khr_loader_init_android && rhs.0.khr_loader_init_android; + out.fb_android_surface_swapchain_create = + lhs.0.fb_android_surface_swapchain_create && rhs.0.fb_android_surface_swapchain_create; + out.fb_swapchain_update_state_android_surface = lhs.0.fb_swapchain_update_state_android_surface + && rhs.0.fb_swapchain_update_state_android_surface; + out.khr_android_thread_settings = + lhs.0.khr_android_thread_settings && rhs.0.khr_android_thread_settings; + out.khr_android_surface_swapchain = + lhs.0.khr_android_surface_swapchain && rhs.0.khr_android_surface_swapchain; + out.khr_android_create_instance = + lhs.0.khr_android_create_instance && rhs.0.khr_android_create_instance; +} +#[cfg(windows)] +fn and_windows_only_exts(lhs: &XrExtensions, rhs: &XrExtensions, out: &mut ExtensionSet) { + out.ext_win32_appcontainer_compatible = + lhs.0.ext_win32_appcontainer_compatible && rhs.0.ext_win32_appcontainer_compatible; + out.khr_d3d11_enable = lhs.0.khr_d3d11_enable && rhs.0.khr_d3d11_enable; + out.khr_d3d12_enable = lhs.0.khr_d3d12_enable && rhs.0.khr_d3d12_enable; + out.khr_win32_convert_performance_counter_time = + lhs.0.khr_win32_convert_performance_counter_time + && rhs.0.khr_win32_convert_performance_counter_time; + out.msft_perception_anchor_interop = + lhs.0.msft_perception_anchor_interop && rhs.0.msft_perception_anchor_interop; + out.msft_holographic_window_attachment = + lhs.0.msft_holographic_window_attachment && rhs.0.msft_holographic_window_attachment; +} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index f881148b..0aa3dfcd 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,3 +1,4 @@ +pub mod extensions; mod vulkan; use bevy::render::renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; @@ -12,8 +13,37 @@ use crate::resources::{ use openxr as xr; +use self::extensions::XrExtensions; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum XrPreferdBlendMode { + Opaque, + Additive, + AlphaBlend, +} +impl Default for XrPreferdBlendMode { + fn default() -> Self { + Self::Opaque + } +} + +#[derive(Clone, Debug)] +pub struct XrAppInfo { + pub name: String, +} +impl Default for XrAppInfo { + fn default() -> Self { + Self { + name: "Ambient".into(), + } + } +} + pub fn initialize_xr_graphics( window: Option, + reqeusted_extensions: XrExtensions, + prefered_blend_mode: XrPreferdBlendMode, + app_info: XrAppInfo, ) -> anyhow::Result<( RenderDevice, RenderQueue, @@ -32,13 +62,13 @@ pub fn initialize_xr_graphics( XrViews, XrFrameState, )> { - vulkan::initialize_xr_graphics(window) + vulkan::initialize_xr_graphics(window, reqeusted_extensions, prefered_blend_mode, app_info) } pub fn xr_entry() -> anyhow::Result { - #[cfg(feature = "linked")] + #[cfg(windows)] let entry = Ok(xr::Entry::linked()); - #[cfg(not(feature = "linked"))] + #[cfg(not(windows))] let entry = unsafe { xr::Entry::load().map_err(|e| anyhow::anyhow!(e)) }; entry } diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index 55c5609a..ba9814ea 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -10,7 +10,9 @@ use bevy::render::renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, Ren use bevy::window::RawHandleWrapper; use openxr as xr; use wgpu::Instance; +use xr::EnvironmentBlendMode; +use crate::graphics::extensions::XrExtensions; use crate::input::XrInput; use crate::resources::{ Swapchain, SwapchainInner, XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, @@ -18,10 +20,13 @@ use crate::resources::{ }; use crate::VIEW_TYPE; +use super::{XrAppInfo, XrPreferdBlendMode}; + pub fn initialize_xr_graphics( window: Option, - // Horrible hack to get the Handtacking extension Loaded, Replace with good system to load - // any extension at some point + reqeusted_extensions: XrExtensions, + prefered_blend_mode: XrPreferdBlendMode, + app_info: XrAppInfo, ) -> anyhow::Result<( RenderDevice, RenderQueue, @@ -39,8 +44,6 @@ pub fn initialize_xr_graphics( XrInput, XrViews, XrFrameState, - // Horrible hack to get the Handtacking extension Loaded, Replace with good system to load - // any extension at some point )> { use wgpu_hal::{api::Vulkan as V, Api}; @@ -49,26 +52,25 @@ pub fn initialize_xr_graphics( #[cfg(target_os = "android")] xr_entry.initialize_android_loader()?; - let available_extensions = xr_entry.enumerate_extensions()?; - assert!(available_extensions.khr_vulkan_enable2); + let available_extensions: XrExtensions = xr_entry.enumerate_extensions()?.into(); + assert!(available_extensions.raw().khr_vulkan_enable2); info!("available xr exts: {:#?}", available_extensions); - let mut enabled_extensions = xr::ExtensionSet::default(); + let mut enabled_extensions: xr::ExtensionSet = + (available_extensions & reqeusted_extensions).into(); enabled_extensions.khr_vulkan_enable2 = true; #[cfg(target_os = "android")] { enabled_extensions.khr_android_create_instance = true; } - enabled_extensions.ext_hand_tracking = available_extensions.ext_hand_tracking; - // enabled_extensions.ext_hand_joints_motion_range = available_extensions.ext_hand_joints_motion_range; - let available_layers = xr_entry.enumerate_layers()?; info!("available xr layers: {:#?}", available_layers); let xr_instance = xr_entry.create_instance( &xr::ApplicationInfo { - application_name: "Ambient", + application_name: &app_info.name, + engine_name: "Bevy", ..Default::default() }, &enabled_extensions, @@ -90,7 +92,22 @@ pub fn initialize_xr_graphics( } ); - let blend_mode = xr_instance.enumerate_environment_blend_modes(xr_system_id, VIEW_TYPE)?[0]; + let blend_modes = xr_instance.enumerate_environment_blend_modes(xr_system_id, VIEW_TYPE)?; + let blend_mode: EnvironmentBlendMode = match prefered_blend_mode { + XrPreferdBlendMode::Opaque if blend_modes.contains(&EnvironmentBlendMode::OPAQUE) => { + EnvironmentBlendMode::OPAQUE + } + XrPreferdBlendMode::Additive if blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) => { + EnvironmentBlendMode::ADDITIVE + } + XrPreferdBlendMode::AlphaBlend + if blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) => + { + EnvironmentBlendMode::ALPHA_BLEND + } + _ => EnvironmentBlendMode::OPAQUE, + }; + #[cfg(not(target_os = "android"))] let vk_target_version = vk::make_api_version(0, 1, 2, 0); @@ -131,7 +148,7 @@ pub fn initialize_xr_graphics( let vk_instance = unsafe { let extensions_cchar: Vec<_> = extensions.iter().map(|s| s.as_ptr()).collect(); - let app_name = CString::new("Ambient")?; + let app_name = CString::new(app_info.name)?; let vk_app_info = vk::ApplicationInfo::builder() .application_name(&app_name) .application_version(1) @@ -409,8 +426,6 @@ pub fn initialize_xr_graphics( should_render: true, }) .into(), - // Horrible hack to get the Handtacking extension Loaded, Replace with good system to load - // any extension at some point )) } diff --git a/src/input.rs b/src/input.rs index 78cad050..33b17852 100644 --- a/src/input.rs +++ b/src/input.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use bevy::prelude::*; use openxr as xr; +use xr::{FrameState, FrameWaiter, ViewConfigurationType}; #[derive(Clone, Resource)] pub struct XrInput { @@ -14,13 +15,12 @@ pub struct XrInput { } impl XrInput { - pub fn new(_instance: xr::Instance, session: xr::Session) -> xr::Result { - // let action_set = instance.create_action_set("input", "input pose information", 0)?; - // let left_hand_subaction_path = instance.string_to_path("/user/hand/left").unwrap(); + pub fn new( + instance: xr::Instance, + session: xr::Session, + // frame_state: &FrameState, + ) -> xr::Result { // let right_hand_subaction_path = instance.string_to_path("/user/hand/right").unwrap(); - // let left_hand_grip_pose_path = instance - // .string_to_path("/user/hand/left/input/grip/pose") - // .unwrap(); // let right_hand_grip_pose_path = instance // .string_to_path("/user/hand/right/input/grip/pose") // .unwrap(); @@ -49,11 +49,23 @@ impl XrInput { // left_hand_subaction_path, // xr::Posef::IDENTITY, // )?; + let stage = session.create_reference_space(xr::ReferenceSpaceType::STAGE, xr::Posef::IDENTITY)?; - let head = session - .create_reference_space(xr::ReferenceSpaceType::VIEW, xr::Posef::IDENTITY) - .unwrap(); + let head = + session.create_reference_space(xr::ReferenceSpaceType::VIEW, xr::Posef::IDENTITY)?; + // let y = stage + // .locate(&head, frame_state.predicted_display_time).unwrap() + // .pose + // .position + // .y; + // let local = session.create_reference_space( + // xr::ReferenceSpaceType::LOCAL, + // xr::Posef { + // position: xr::Vector3f { x: 0.0, y, z: 0.0 }, + // orientation: xr::Quaternionf::IDENTITY, + // }, + // ).unwrap(); //session.attach_action_sets(&[&action_set])?; //session.attach_action_sets(&[])?; Ok(Self { diff --git a/src/lib.rs b/src/lib.rs index 3957e5e8..9a77e87f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ -mod graphics; +pub mod graphics; pub mod input; +// pub mod passthrough; pub mod resource_macros; pub mod resources; pub mod xr_init; @@ -10,33 +11,23 @@ use std::sync::{Arc, Mutex}; use crate::xr_init::RenderRestartPlugin; use crate::xr_input::hands::hand_tracking::DisableHandTracking; use crate::xr_input::oculus_touch::ActionSets; -use bevy::app::PluginGroupBuilder; -use bevy::ecs::system::{RunSystemOnce, SystemState}; +use bevy::app::{AppExit, PluginGroupBuilder}; +use bevy::ecs::system::SystemState; use bevy::prelude::*; -use bevy::render::camera::{ - CameraPlugin, ManualTextureView, ManualTextureViewHandle, ManualTextureViews, -}; -use bevy::render::globals::GlobalsPlugin; -use bevy::render::mesh::morph::MorphPlugin; -use bevy::render::mesh::MeshPlugin; +use bevy::render::camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews}; use bevy::render::pipelined_rendering::PipelinedRenderingPlugin; -use bevy::render::render_asset::RenderAssetDependency; -use bevy::render::render_resource::ShaderLoader; -use bevy::render::renderer::{ - render_system, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue, -}; +use bevy::render::renderer::{render_system, RenderInstance}; use bevy::render::settings::RenderCreation; -use bevy::render::view::{self, ViewPlugin, WindowRenderPlugin}; -use bevy::render::{color, primitives, Render, RenderApp, RenderPlugin, RenderSet}; +use bevy::render::{Render, RenderApp, RenderPlugin, RenderSet}; use bevy::window::{PresentMode, PrimaryWindow, RawHandleWrapper}; +use graphics::extensions::XrExtensions; +use graphics::{XrAppInfo, XrPreferdBlendMode}; use input::XrInput; use openxr as xr; +// use passthrough::{start_passthrough, supports_passthrough, XrPassthroughLayer}; use resources::*; use xr::FormFactor; -use xr_init::{ - init_non_xr_graphics, update_xr_stuff, xr_only, RenderCreationData, XrEnableRequest, - XrEnableStatus, XrRenderData, XrRenderUpdate, -}; +use xr_init::{xr_only, XrEnableStatus, XrRenderData}; use xr_input::controllers::XrControllerType; use xr_input::hands::emulated::HandEmulationPlugin; use xr_input::hands::hand_tracking::{HandTrackingData, HandTrackingPlugin}; @@ -48,12 +39,11 @@ pub const LEFT_XR_TEXTURE_HANDLE: ManualTextureViewHandle = ManualTextureViewHan pub const RIGHT_XR_TEXTURE_HANDLE: ManualTextureViewHandle = ManualTextureViewHandle(3383858418); /// Adds OpenXR support to an App -pub struct OpenXrPlugin; - -impl Default for OpenXrPlugin { - fn default() -> Self { - OpenXrPlugin - } +#[derive(Default)] +pub struct OpenXrPlugin { + reqeusted_extensions: XrExtensions, + prefered_blend_mode: XrPreferdBlendMode, + app_info: XrAppInfo, } #[derive(Resource)] @@ -76,6 +66,9 @@ pub struct FutureXrResources( >, >, ); +// fn mr_test(mut commands: Commands, passthrough_layer: Option>) { +// commands.insert_resource(ClearColor(Color::rgba(0.0, 0.0, 0.0, 0.0))); +// } impl Plugin for OpenXrPlugin { fn build(&self, app: &mut App) { @@ -84,7 +77,12 @@ impl Plugin for OpenXrPlugin { let primary_window = system_state.get(&app.world).get_single().ok().cloned(); #[cfg(not(target_arch = "wasm32"))] - match graphics::initialize_xr_graphics(primary_window.clone()) { + match graphics::initialize_xr_graphics( + primary_window.clone(), + self.reqeusted_extensions.clone(), + self.prefered_blend_mode, + self.app_info.clone(), + ) { Ok(( device, queue, @@ -149,6 +147,7 @@ impl Plugin for OpenXrPlugin { app.insert_resource(XrEnableStatus::Disabled); } } + // app.add_systems(PreUpdate, mr_test); #[cfg(target_arch = "wasm32")] { app.add_plugins(RenderPlugin::default()); @@ -180,6 +179,23 @@ impl Plugin for OpenXrPlugin { } else { app.insert_resource(DisableHandTracking::Both); } + // let passthrough = data.xr_instance.exts().fb_passthrough.is_some() + // && supports_passthrough( + // &data.xr_instance, + // data.xr_instance + // .system(FormFactor::HEAD_MOUNTED_DISPLAY) + // .unwrap(), + // ) + // .is_ok_and(|v| v); + // if passthrough { + // info!("Passthrough!"); + // let (pl, p) = start_passthrough(&data); + // app.insert_resource(pl); + // app.insert_resource(p); + // // if !app.world.contains_resource::() { + // // info!("ClearColor!"); + // // } + // } let (left, right) = data.xr_swapchain.get_render_views(); let left = ManualTextureView { @@ -225,7 +241,12 @@ impl Plugin for OpenXrPlugin { } } -pub struct DefaultXrPlugins; +#[derive(Default)] +pub struct DefaultXrPlugins { + pub reqeusted_extensions: XrExtensions, + pub prefered_blend_mode: XrPreferdBlendMode, + pub app_info: XrAppInfo, +} impl PluginGroup for DefaultXrPlugins { fn build(self) -> PluginGroupBuilder { @@ -233,7 +254,11 @@ impl PluginGroup for DefaultXrPlugins { .build() .disable::() .disable::() - .add_before::(OpenXrPlugin) + .add_before::(OpenXrPlugin { + prefered_blend_mode: self.prefered_blend_mode, + reqeusted_extensions: self.reqeusted_extensions, + app_info: self.app_info.clone(), + }) .add_after::(OpenXrInput::new(XrControllerType::OculusTouch)) .add_before::(RenderRestartPlugin) .add(HandEmulationPlugin) @@ -241,7 +266,9 @@ impl PluginGroup for DefaultXrPlugins { .set(WindowPlugin { #[cfg(not(target_os = "android"))] primary_window: Some(Window { + transparent: true, present_mode: PresentMode::AutoNoVsync, + title: self.app_info.name.clone(), ..default() }), #[cfg(target_os = "android")] @@ -264,6 +291,7 @@ pub fn xr_begin_frame( swapchain: Res, views: Res, input: Res, + mut app_exit: EventWriter, ) { { let _span = info_span!("xr_poll_events"); @@ -282,8 +310,12 @@ pub fn xr_begin_frame( xr::SessionState::STOPPING => { session.end().unwrap(); session_running.store(false, std::sync::atomic::Ordering::Relaxed); + app_exit.send(AppExit); + } + xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => { + app_exit.send(AppExit); + return; } - xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => return, _ => {} } } @@ -361,6 +393,7 @@ pub fn end_frame( swapchain: Res, resolution: Res, environment_blend_mode: Res, + // passthrough_layer: Option>, ) { { let _span = info_span!("xr_release_image").entered(); @@ -370,10 +403,11 @@ pub fn end_frame( let _span = info_span!("xr_end_frame").entered(); let result = swapchain.end( xr_frame_state.lock().unwrap().predicted_display_time, - &*views.lock().unwrap(), + &views.lock().unwrap(), &input.stage, **resolution, **environment_blend_mode, + // passthrough_layer.map(|p| p.into_inner()), ); match result { Ok(_) => {} diff --git a/src/resources.rs b/src/resources.rs index 27150276..a798955a 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,6 +1,7 @@ use std::sync::atomic::AtomicBool; use std::sync::Mutex; +// use crate::passthrough::XrPassthroughLayer; use crate::resource_macros::*; use bevy::prelude::*; use openxr as xr; @@ -58,6 +59,7 @@ impl Swapchain { stage: &xr::Space, resolution: UVec2, environment_blend_mode: xr::EnvironmentBlendMode, + // passthrough_layer: Option<&XrPassthroughLayer>, ) -> xr::Result<()> { match self { Swapchain::Vulkan(swapchain) => swapchain.end( @@ -66,6 +68,7 @@ impl Swapchain { stage, resolution, environment_blend_mode, + // passthrough_layer, ), } } @@ -125,6 +128,7 @@ impl SwapchainInner { stage: &xr::Space, resolution: UVec2, environment_blend_mode: xr::EnvironmentBlendMode, + // passthrough_layer: Option<&XrPassthroughLayer>, ) -> xr::Result<()> { let rect = xr::Rect2Di { offset: xr::Offset2Di { x: 0, y: 0 }, @@ -138,6 +142,51 @@ impl SwapchainInner { warn!("views are len of 0"); return Ok(()); } + // match passthrough_layer { + // Some(pass) => { + // // info!("Rendering with pass through"); + // let passthrough_layer = xr::sys::CompositionLayerPassthroughFB { + // ty: CompositionLayerPassthroughFB::TYPE, + // next: ptr::null(), + // flags: CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA, + // space: xr::sys::Space::NULL, + // layer_handle: pass.0, + // }; + // self.stream.lock().unwrap().end( + // predicted_display_time, + // environment_blend_mode, + // &[ + // &xr::CompositionLayerProjection::new() + // .layer_flags(CompositionLayerFlags::UNPREMULTIPLIED_ALPHA) + // .space(stage) + // .views(&[ + // xr::CompositionLayerProjectionView::new() + // .pose(views[0].pose) + // .fov(views[0].fov) + // .sub_image( + // xr::SwapchainSubImage::new() + // .swapchain(&swapchain) + // .image_array_index(0) + // .image_rect(rect), + // ), + // xr::CompositionLayerProjectionView::new() + // .pose(views[1].pose) + // .fov(views[1].fov) + // .sub_image( + // xr::SwapchainSubImage::new() + // .swapchain(&swapchain) + // .image_array_index(1) + // .image_rect(rect), + // ), + // ]), + // unsafe { + // &*(&passthrough_layer as *const _ as *const CompositionLayerBase) + // }, + // ], + // ) + // } + + // None => self.stream.lock().unwrap().end( predicted_display_time, environment_blend_mode, @@ -162,5 +211,6 @@ impl SwapchainInner { ), ])], ) + // } } } diff --git a/src/xr_input/actions.rs b/src/xr_input/actions.rs index 47802fde..9964ce64 100644 --- a/src/xr_input/actions.rs +++ b/src/xr_input/actions.rs @@ -79,7 +79,7 @@ pub fn setup_oxr_actions(world: &mut World) { actions.insert(action_name, typed_action); for (device_path, bindings) in action.bindings.into_iter() { for b in bindings { - info!("binding {} to {}", action_name, b); + // info!("binding {} to {}", action_name, b); action_bindings .entry((set_name, action_name)) .or_default() @@ -117,7 +117,6 @@ pub fn setup_oxr_actions(world: &mut World) { .map(move |(dev, bindings)| (action, dev, bindings)) }) .map(|(action, dev, bindings)| { - info!("Hi"); ( dev, bindings @@ -136,7 +135,6 @@ pub fn setup_oxr_actions(world: &mut World) { b_indings.entry(dev).or_default().append(&mut bindings); } for (dev, bindings) in b_indings.into_iter() { - info!(dev); instance .suggest_interaction_profile_bindings(instance.string_to_path(dev).unwrap(), &bindings) .expect("Unable to suggest interaction bindings!"); @@ -305,7 +303,7 @@ impl XrActionSets { &self, action_set: &'static str, action_name: &'static str, - ) -> Result<&Action,ActionError> { + ) -> Result<&Action, ActionError> { let action = self .sets .get(action_set) @@ -322,7 +320,7 @@ impl XrActionSets { &self, action_set: &'static str, action_name: &'static str, - ) -> Result<&Action,ActionError> { + ) -> Result<&Action, ActionError> { let action = self .sets .get(action_set) @@ -339,7 +337,7 @@ impl XrActionSets { &self, action_set: &'static str, action_name: &'static str, - ) -> Result<&Action,ActionError> { + ) -> Result<&Action, ActionError> { let action = self .sets .get(action_set) @@ -356,7 +354,7 @@ impl XrActionSets { &self, action_set: &'static str, action_name: &'static str, - ) -> Result<&Action,ActionError> { + ) -> Result<&Action, ActionError> { let action = self .sets .get(action_set) diff --git a/src/xr_input/hands/common.rs b/src/xr_input/hands/common.rs index 2c88b08b..104c6b35 100644 --- a/src/xr_input/hands/common.rs +++ b/src/xr_input/hands/common.rs @@ -3,9 +3,9 @@ use bevy::prelude::{ Query, Resource, SpatialBundle, Startup, Transform, }; -use crate::xr_input::{Hand, trackers::OpenXRTracker}; +use crate::xr_input::{trackers::OpenXRTracker, Hand}; -use super::{HandBone, BoneTrackingStatus}; +use super::{BoneTrackingStatus, HandBone}; /// add debug renderer for controllers #[derive(Default)] diff --git a/src/xr_input/hands/hand_tracking.rs b/src/xr_input/hands/hand_tracking.rs index 05d6d95b..1af55df4 100644 --- a/src/xr_input/hands/hand_tracking.rs +++ b/src/xr_input/hands/hand_tracking.rs @@ -1,16 +1,13 @@ use bevy::prelude::*; use openxr::{HandTracker, Result, SpaceLocationFlags}; +use super::common::HandBoneRadius; use crate::{ input::XrInput, - resources::{XrFrameState, XrSession}, - xr_input::{ - hands::HandBone, trackers::OpenXRTrackingRoot, Hand, QuatConv, - Vec3Conv, - }, xr_init::xr_only, + xr_init::xr_only, + xr_input::{hands::HandBone, trackers::OpenXRTrackingRoot, Hand, QuatConv, Vec3Conv}, }; -use super::common::HandBoneRadius; use super::BoneTrackingStatus; @@ -126,9 +123,11 @@ impl Plugin for HandTrackingPlugin { app.add_systems( PreUpdate, ( - update_hand_bones.run_if(|dh: Option>| { - !dh.is_some_and(|v| *v == DisableHandTracking::Both) - }).run_if(xr_only()), + update_hand_bones + .run_if(|dh: Option>| { + !dh.is_some_and(|v| *v == DisableHandTracking::Both) + }) + .run_if(xr_only()), update_tracking_state_on_disable, ), ); diff --git a/src/xr_input/hands/mod.rs b/src/xr_input/hands/mod.rs index db760dcb..06eb5c19 100644 --- a/src/xr_input/hands/mod.rs +++ b/src/xr_input/hands/mod.rs @@ -2,9 +2,9 @@ use bevy::{app::PluginGroupBuilder, prelude::*}; use self::{emulated::HandEmulationPlugin, hand_tracking::HandTrackingPlugin}; +pub mod common; pub mod emulated; pub mod hand_tracking; -pub mod common; pub struct XrHandPlugins; diff --git a/src/xr_input/mod.rs b/src/xr_input/mod.rs index 50268c88..540f2e25 100644 --- a/src/xr_input/mod.rs +++ b/src/xr_input/mod.rs @@ -11,7 +11,7 @@ pub mod xr_camera; use crate::resources::{XrInstance, XrSession}; use crate::xr_begin_frame; -use crate::xr_init::{xr_only, XrPostSetup, XrSetup}; +use crate::xr_init::{xr_only, XrPostSetup, XrSetup, XrPreSetup}; use crate::xr_input::controllers::XrControllerType; use crate::xr_input::oculus_touch::setup_oculus_controller; use crate::xr_input::xr_camera::{xr_camera_head_sync, Eye, XRProjection, XrCameraBundle}; @@ -30,7 +30,7 @@ use bevy::utils::HashMap; use openxr::Binding; use self::actions::{setup_oxr_actions, OpenXrActionsPlugin}; -use self::oculus_touch::{post_action_setup_oculus_controller, ActionSets}; +use self::oculus_touch::{post_action_setup_oculus_controller, ActionSets, init_subaction_path}; use self::trackers::{ adopt_open_xr_trackers, update_open_xr_controllers, OpenXRLeftEye, OpenXRRightEye, OpenXRTrackingRoot, @@ -77,6 +77,7 @@ impl Plugin for OpenXrInput { .after(TransformSystem::TransformPropagate) .before(VisibilitySystems::UpdatePerspectiveFrusta), ); + app.add_systems(XrPreSetup, init_subaction_path); app.add_systems(XrSetup, setup_xr_cameras); } } diff --git a/src/xr_input/oculus_touch.rs b/src/xr_input/oculus_touch.rs index 6d416bb0..6f405f8b 100644 --- a/src/xr_input/oculus_touch.rs +++ b/src/xr_input/oculus_touch.rs @@ -2,7 +2,7 @@ use crate::input::XrInput; use crate::resources::{XrInstance, XrSession}; use crate::xr_input::controllers::Handed; use crate::xr_input::Hand; -use bevy::prelude::{Commands, Res, ResMut, Resource}; +use bevy::prelude::{default, Commands, Res, ResMut, Resource}; use openxr::{ ActionSet, AnyGraphics, FrameState, Instance, Path, Posef, Session, Space, SpaceLocation, SpaceVelocity, @@ -50,7 +50,6 @@ pub fn setup_oculus_controller( action_sets: ResMut, ) { let oculus_controller = OculusController::new(action_sets).unwrap(); - init_subaction_path(&instance); commands.insert_resource(oculus_controller); } @@ -65,10 +64,10 @@ pub struct OculusControllerRef<'a> { xr_input: &'a XrInput, } -static RIGHT_SUBACTION_PATH: OnceLock = OnceLock::new(); -static LEFT_SUBACTION_PATH: OnceLock = OnceLock::new(); +pub static RIGHT_SUBACTION_PATH: OnceLock = OnceLock::new(); +pub static LEFT_SUBACTION_PATH: OnceLock = OnceLock::new(); -pub fn init_subaction_path(instance: &Instance) { +pub fn init_subaction_path(instance: Res) { let _ = LEFT_SUBACTION_PATH.set(instance.string_to_path("/user/hand/left").unwrap()); let _ = RIGHT_SUBACTION_PATH.set(instance.string_to_path("/user/hand/right").unwrap()); } @@ -82,7 +81,7 @@ pub fn subaction_path(hand: Hand) -> Path { impl OculusControllerRef<'_> { pub fn grip_space(&self, hand: Hand) -> (SpaceLocation, SpaceVelocity) { - match hand { + let d = match hand { Hand::Left => self .oculus_controller .grip_space @@ -103,11 +102,14 @@ impl OculusControllerRef<'_> { &self.xr_input.stage, self.frame_state.predicted_display_time, ), + }; + match d { + Ok(d) => d, + Err(_) => (SpaceLocation::default(), SpaceVelocity::default()), } - .unwrap() } pub fn aim_space(&self, hand: Hand) -> (SpaceLocation, SpaceVelocity) { - match hand { + let d = match hand { Hand::Left => self .oculus_controller .aim_space @@ -128,147 +130,213 @@ impl OculusControllerRef<'_> { &self.xr_input.stage, self.frame_state.predicted_display_time, ), + }; + match d { + Ok(d) => d, + Err(_) => (SpaceLocation::default(), SpaceVelocity::default()), } - .unwrap() } pub fn squeeze(&self, hand: Hand) -> f32 { - let action = &self + match &self .action_sets .get_action_f32("oculus_input", "squeeze") - .unwrap(); - action - .state(&self.session, subaction_path(hand)) .unwrap() - .current_state + .state(&self.session, subaction_path(hand)) + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn trigger(&self, hand: Hand) -> f32 { - self.action_sets + match self + .action_sets .get_action_f32("oculus_input", "trigger") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn trigger_touched(&self, hand: Hand) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "trigger_touched") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn x_button(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "x_button") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn x_button_touched(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "x_button_touch") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn y_button(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "y_button") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn y_button_touched(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "y_button_touch") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn menu_button(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "menu_button") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn a_button(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "a_button") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn a_button_touched(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "a_button_touch") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn b_button(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "b_button") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn b_button_touched(&self) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "b_button_touch") .unwrap() .state(&self.session, Path::NULL) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn thumbstick_touch(&self, hand: Hand) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "thumbstick_touch") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } pub fn thumbstick(&self, hand: Hand) -> Thumbstick { Thumbstick { - x: self + x: match self .action_sets .get_action_f32("oculus_input", "thumbstick_x") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state, - y: self + .map(|v| v.current_state) + { + Ok(v) => v, + Err(_) => default(), + }, + y: match self .action_sets .get_action_f32("oculus_input", "thumbstick_y") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state, - click: self + .map(|v| v.current_state) + { + Ok(v) => v, + Err(_) => default(), + }, + click: match self .action_sets .get_action_bool("oculus_input", "thumbstick_click") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state, + .map(|v| v.current_state) + { + Ok(v) => v, + Err(_) => default(), + }, } } pub fn thumbrest_touch(&self, hand: Hand) -> bool { - self.action_sets + match self + .action_sets .get_action_bool("oculus_input", "thumbrest_touch") .unwrap() .state(&self.session, subaction_path(hand)) - .unwrap() - .current_state + { + Ok(v) => v, + Err(_) => return default(), + } + .current_state } }