diff --git a/examples/android/manifest.yaml b/examples/android/manifest.yaml index 7622de3..6cf500f 100644 --- a/examples/android/manifest.yaml +++ b/examples/android/manifest.yaml @@ -12,6 +12,8 @@ android: required: true - name: "com.oculus.experimental.enabled" required: true + uses_permission: + - name: "com.oculus.permission.HAND_TRACKING" application: label: "Bevy Openxr Android" theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen" diff --git a/examples/demo/manifest.yaml b/examples/demo/manifest.yaml index f514707..d4085c4 100644 --- a/examples/demo/manifest.yaml +++ b/examples/demo/manifest.yaml @@ -12,6 +12,8 @@ android: required: true - name: "com.oculus.experimental.enabled" required: true + uses_permission: + - name: "com.oculus.permission.HAND_TRACKING" application: label: "Bevy Openxr Android" theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen" diff --git a/src/lib.rs b/src/lib.rs index c16f10c..3b61535 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,8 +29,9 @@ use openxr as xr; use passthrough::{PassthroughPlugin, XrPassthroughLayer, XrPassthroughState}; use resources::*; use xr_init::{ - xr_after_wait_only, xr_only, xr_render_only, CleanupRenderWorld, CleanupXrData, SetupXrData, - XrCleanup, XrEarlyInitPlugin, XrHasWaited, XrPostCleanup, XrShouldRender, XrStatus, + xr_after_wait_only, xr_only, xr_render_only, CleanupRenderWorld, CleanupXrData, + ExitAppOnSessionExit, SetupXrData, StartSessionOnStartup, XrCleanup, XrEarlyInitPlugin, + XrHasWaited, XrPostCleanup, XrShouldRender, XrStatus, }; use xr_input::actions::XrActionsPlugin; use xr_input::hands::emulated::HandEmulationPlugin; @@ -55,6 +56,7 @@ pub struct OpenXrPlugin { impl Plugin for OpenXrPlugin { fn build(&self, app: &mut App) { app.insert_resource(XrSessionRunning::new(AtomicBool::new(false))); + app.insert_resource(ExitAppOnSessionExit::default()); #[cfg(not(target_arch = "wasm32"))] match graphics::initialize_xr_instance( SystemState::>>::new(&mut app.world) @@ -99,7 +101,7 @@ impl Plugin for OpenXrPlugin { synchronous_pipeline_compilation: true, }); app.insert_resource(XrStatus::Disabled); - app.world.send_event(StartXrSession); + // app.world.send_event(StartXrSession); } Err(err) => { warn!("OpenXR Instance Failed to initialize: {}", err); @@ -123,7 +125,6 @@ impl Plugin for OpenXrPlugin { ( xr_reset_per_frame_resources, xr_wait_frame.run_if(xr_only()), - // xr_begin_frame.run_if(xr_only()), locate_views.run_if(xr_only()), apply_deferred, ) @@ -131,15 +132,6 @@ impl Plugin for OpenXrPlugin { .after(xr_poll_events), ); let render_app = app.sub_app_mut(RenderApp); - // render_app.add_systems( - // Render, - // xr_begin_frame - // .run_if(xr_only()) - // .run_if(xr_after_wait_only()) - // // .run_if(xr_render_only()) - // .after(RenderSet::ExtractCommands) - // .before(xr_pre_frame), - // ); render_app.add_systems( Render, xr_pre_frame @@ -148,7 +140,6 @@ impl Plugin for OpenXrPlugin { .run_if(xr_render_only()) .before(render_system) .after(RenderSet::ExtractCommands), - // .in_set(RenderSet::Prepare), ); render_app.add_systems( Render, @@ -252,7 +243,7 @@ impl PluginGroup for DefaultXrPlugins { ..default() }, }) - .disable::() + // .disable::() .disable::() .add_before::(OpenXrPlugin { prefered_blend_mode: self.prefered_blend_mode, @@ -269,6 +260,7 @@ impl PluginGroup for DefaultXrPlugins { .add(HandEmulationPlugin) .add(PassthroughPlugin) .add(XrResourcePlugin) + .add(StartSessionOnStartup) .set(WindowPlugin { #[cfg(not(target_os = "android"))] primary_window: Some(Window { @@ -300,7 +292,9 @@ fn xr_poll_events( instance: Option>, session: Option>, session_running: Res, + exit_type: Res, mut app_exit: EventWriter, + mut start_session: EventWriter, mut setup_xr: EventWriter, mut cleanup_xr: EventWriter, ) { @@ -325,8 +319,20 @@ fn xr_poll_events( session_running.store(false, std::sync::atomic::Ordering::Relaxed); cleanup_xr.send_default(); } - xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => { - // app_exit.send(AppExit); + xr::SessionState::EXITING => { + if *exit_type == ExitAppOnSessionExit::Always + || *exit_type == ExitAppOnSessionExit::OnlyOnExit + { + app_exit.send_default(); + } + } + xr::SessionState::LOSS_PENDING => { + if *exit_type == ExitAppOnSessionExit::Always { + app_exit.send_default(); + } + if *exit_type == ExitAppOnSessionExit::OnlyOnExit { + start_session.send_default(); + } } _ => {} @@ -344,11 +350,6 @@ fn xr_poll_events( } } -fn xr_begin_frame(swapchain: Res) { - let _span = info_span!("xr_begin_frame").entered(); - swapchain.begin().unwrap() -} - pub fn xr_wait_frame( world: &mut World, // mut frame_state: ResMut, @@ -368,11 +369,19 @@ pub fn xr_wait_frame( } }; let should_render = world.get_resource::().unwrap().should_render; - // frame_state.predicted_display_time = xr::Time::from_nanos(frame_state.predicted_display_time.as_nanos() + frame_state.predicted_display_period.as_nanos()); + let mut frame_state = world.resource_mut::(); + frame_state.predicted_display_time = xr::Time::from_nanos( + frame_state.predicted_display_time.as_nanos() + + frame_state.predicted_display_period.as_nanos(), + ); **world.get_resource_mut::().unwrap() = should_render; **world.get_resource_mut::().unwrap() = true; } - world.get_resource::().unwrap().begin().unwrap(); + world + .get_resource::() + .unwrap() + .begin() + .unwrap(); } pub fn xr_pre_frame( diff --git a/src/xr_init/mod.rs b/src/xr_init/mod.rs index 3ddd629..2ff8f53 100644 --- a/src/xr_init/mod.rs +++ b/src/xr_init/mod.rs @@ -94,6 +94,27 @@ impl Plugin for XrInitPlugin { } } +#[derive(Resource, Clone, Copy, PartialEq, Eq,Default)] +pub enum ExitAppOnSessionExit { + #[default] + /// Restart XrSession when session is lost + OnlyOnExit, + /// Always exit the app + Always, + /// Keep app open when XrSession wants to exit or is lost + Never, +} + +pub struct StartSessionOnStartup; + +impl Plugin for StartSessionOnStartup { + fn build(&self, app: &mut App) { + app.add_systems(Startup, |mut event: EventWriter| { + event.send_default(); + }); + } +} + fn set_cleanup_res(mut commands: Commands) { info!("Set Cleanup Res"); commands.insert_resource(CleanupRenderWorld);