Merge pull request #128 from awtterpip/correct-pipelined-updated
correct pipelining
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
// a simple example showing basic actions using the xr utils actions
|
// a simple example showing basic actions using the xr utils actions
|
||||||
use bevy::{math::vec3, prelude::*};
|
use bevy::{math::vec3, prelude::*};
|
||||||
use bevy_openxr::{
|
use bevy_openxr::{add_xr_plugins, helper_traits::ToQuat, resources::OxrViews};
|
||||||
add_xr_plugins, helper_traits::ToQuat, init::OxrTrackingRoot, resources::OxrViews,
|
use bevy_xr::session::XrTrackingRoot;
|
||||||
};
|
|
||||||
use bevy_xr_utils::xr_utils_actions::{
|
use bevy_xr_utils::xr_utils_actions::{
|
||||||
ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystemSet,
|
ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystemSet,
|
||||||
XRUtilsActionsPlugin, XRUtilsBinding,
|
XRUtilsActionsPlugin, XRUtilsBinding,
|
||||||
@@ -114,7 +113,7 @@ fn read_action_with_marker_component(
|
|||||||
//lets add some flycam stuff
|
//lets add some flycam stuff
|
||||||
fn handle_flight_input(
|
fn handle_flight_input(
|
||||||
action_query: Query<&XRUtilsActionState, With<FlightActionMarker>>,
|
action_query: Query<&XRUtilsActionState, With<FlightActionMarker>>,
|
||||||
mut oxr_root: Query<&mut Transform, With<OxrTrackingRoot>>,
|
mut oxr_root: Query<&mut Transform, With<XrTrackingRoot>>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
//use the views for hmd orientation
|
//use the views for hmd orientation
|
||||||
views: ResMut<OxrViews>,
|
views: ResMut<OxrViews>,
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_openxr::{add_xr_plugins, init::OxrInitPlugin, types::OxrExtensions};
|
use bevy_openxr::{add_xr_plugins, init::OxrInitPlugin, types::OxrExtensions};
|
||||||
use bevy_xr::session::XrStatus;
|
use bevy_xr::session::XrState;
|
||||||
use openxr::EnvironmentBlendMode;
|
// use openxr::EnvironmentBlendMode;
|
||||||
use wgpu::TextureFormat;
|
// use wgpu::TextureFormat;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
@@ -40,11 +40,12 @@ fn main() {
|
|||||||
|
|
||||||
fn handle_input(
|
fn handle_input(
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
mut end: EventWriter<bevy_xr::session::EndXrSession>,
|
mut end: EventWriter<bevy_xr::session::XrEndSessionEvent>,
|
||||||
mut _destroy: EventWriter<bevy_xr::session::DestroyXrSession>,
|
mut destroy: EventWriter<bevy_xr::session::XrDestroySessionEvent>,
|
||||||
mut _begin: EventWriter<bevy_xr::session::BeginXrSession>,
|
mut begin: EventWriter<bevy_xr::session::XrBeginSessionEvent>,
|
||||||
mut create: EventWriter<bevy_xr::session::CreateXrSession>,
|
mut create: EventWriter<bevy_xr::session::XrCreateSessionEvent>,
|
||||||
state: Res<XrStatus>,
|
mut request_exit: EventWriter<bevy_xr::session::XrRequestExitEvent>,
|
||||||
|
state: Res<XrState>,
|
||||||
) {
|
) {
|
||||||
if keys.just_pressed(KeyCode::KeyE) {
|
if keys.just_pressed(KeyCode::KeyE) {
|
||||||
info!("sending end");
|
info!("sending end");
|
||||||
@@ -54,6 +55,18 @@ fn handle_input(
|
|||||||
info!("sending create");
|
info!("sending create");
|
||||||
create.send_default();
|
create.send_default();
|
||||||
}
|
}
|
||||||
|
if keys.just_pressed(KeyCode::KeyD) {
|
||||||
|
info!("sending destroy");
|
||||||
|
destroy.send_default();
|
||||||
|
}
|
||||||
|
if keys.just_pressed(KeyCode::KeyB) {
|
||||||
|
info!("sending begin");
|
||||||
|
begin.send_default();
|
||||||
|
}
|
||||||
|
if keys.just_pressed(KeyCode::KeyR) {
|
||||||
|
info!("sending request exit");
|
||||||
|
request_exit.send_default();
|
||||||
|
}
|
||||||
if keys.just_pressed(KeyCode::KeyI) {
|
if keys.just_pressed(KeyCode::KeyI) {
|
||||||
info!("current state: {:?}", *state);
|
info!("current state: {:?}", *state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use bevy_openxr::{
|
|||||||
action_set_attaching::OxrAttachActionSet,
|
action_set_attaching::OxrAttachActionSet,
|
||||||
action_set_syncing::{OxrActionSetSyncSet, OxrSyncActionSet},
|
action_set_syncing::{OxrActionSetSyncSet, OxrSyncActionSet},
|
||||||
add_xr_plugins,
|
add_xr_plugins,
|
||||||
init::OxrTrackingRoot,
|
init::create_xr_session,
|
||||||
resources::OxrInstance,
|
resources::OxrInstance,
|
||||||
session::OxrSession,
|
session::OxrSession,
|
||||||
spaces::OxrSpaceExt,
|
spaces::OxrSpaceExt,
|
||||||
};
|
};
|
||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
session::{session_available, XrSessionCreated},
|
session::{session_available, XrCreateSession, XrTrackingRoot},
|
||||||
spaces::XrSpace,
|
spaces::XrSpace,
|
||||||
types::XrPose,
|
types::XrPose,
|
||||||
};
|
};
|
||||||
@@ -21,8 +21,8 @@ use openxr::Posef;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_plugins(add_xr_plugins(DefaultPlugins));
|
app.add_plugins(add_xr_plugins(DefaultPlugins));
|
||||||
app.add_systems(XrSessionCreated, spawn_hands);
|
app.add_systems(XrCreateSession, spawn_hands.after(create_xr_session));
|
||||||
app.add_systems(XrSessionCreated, attach_set);
|
app.add_systems(XrCreateSession, attach_set.after(create_xr_session));
|
||||||
app.add_systems(PreUpdate, sync_actions.before(OxrActionSetSyncSet));
|
app.add_systems(PreUpdate, sync_actions.before(OxrActionSetSyncSet));
|
||||||
app.add_systems(OxrSendActionBindings, suggest_action_bindings);
|
app.add_systems(OxrSendActionBindings, suggest_action_bindings);
|
||||||
app.add_systems(Startup, create_actions.run_if(session_available));
|
app.add_systems(Startup, create_actions.run_if(session_available));
|
||||||
@@ -108,7 +108,7 @@ fn create_actions(instance: Res<OxrInstance>, mut cmds: Commands) {
|
|||||||
fn spawn_hands(
|
fn spawn_hands(
|
||||||
actions: Res<ControllerActions>,
|
actions: Res<ControllerActions>,
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
root: Query<Entity, With<OxrTrackingRoot>>,
|
root: Query<Entity, With<XrTrackingRoot>>,
|
||||||
session: Res<OxrSession>,
|
session: Res<OxrSession>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_openxr::add_xr_plugins;
|
use bevy_openxr::add_xr_plugins;
|
||||||
use bevy_xr::session::{ XrStatus};
|
use bevy_xr::session::{XrSessionPlugin, XrState};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(add_xr_plugins(DefaultPlugins))
|
.add_plugins(add_xr_plugins(DefaultPlugins).set(XrSessionPlugin { auto_handle: false }))
|
||||||
.add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin)
|
.add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin)
|
||||||
.add_systems(Startup, setup)
|
.add_systems(Startup, setup)
|
||||||
.add_systems(Update, handle_input)
|
.add_systems(Update, handle_input)
|
||||||
@@ -16,11 +16,12 @@ fn main() {
|
|||||||
|
|
||||||
fn handle_input(
|
fn handle_input(
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
mut end: EventWriter<bevy_xr::session::EndXrSession>,
|
mut end: EventWriter<bevy_xr::session::XrEndSessionEvent>,
|
||||||
mut _destroy: EventWriter<bevy_xr::session::DestroyXrSession>,
|
mut destroy: EventWriter<bevy_xr::session::XrDestroySessionEvent>,
|
||||||
mut _begin: EventWriter<bevy_xr::session::BeginXrSession>,
|
mut begin: EventWriter<bevy_xr::session::XrBeginSessionEvent>,
|
||||||
mut create: EventWriter<bevy_xr::session::CreateXrSession>,
|
mut create: EventWriter<bevy_xr::session::XrCreateSessionEvent>,
|
||||||
state: Res<XrStatus>,
|
mut request_exit: EventWriter<bevy_xr::session::XrRequestExitEvent>,
|
||||||
|
state: Res<XrState>,
|
||||||
) {
|
) {
|
||||||
if keys.just_pressed(KeyCode::KeyE) {
|
if keys.just_pressed(KeyCode::KeyE) {
|
||||||
info!("sending end");
|
info!("sending end");
|
||||||
@@ -30,6 +31,18 @@ fn handle_input(
|
|||||||
info!("sending create");
|
info!("sending create");
|
||||||
create.send_default();
|
create.send_default();
|
||||||
}
|
}
|
||||||
|
if keys.just_pressed(KeyCode::KeyD) {
|
||||||
|
info!("sending destroy");
|
||||||
|
destroy.send_default();
|
||||||
|
}
|
||||||
|
if keys.just_pressed(KeyCode::KeyB) {
|
||||||
|
info!("sending begin");
|
||||||
|
begin.send_default();
|
||||||
|
}
|
||||||
|
if keys.just_pressed(KeyCode::KeyR) {
|
||||||
|
info!("sending request exit");
|
||||||
|
request_exit.send_default();
|
||||||
|
}
|
||||||
if keys.just_pressed(KeyCode::KeyI) {
|
if keys.just_pressed(KeyCode::KeyI) {
|
||||||
info!("current state: {:?}", *state);
|
info!("current state: {:?}", *state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ use bevy::ecs::schedule::ScheduleLabel;
|
|||||||
use bevy::ecs::system::RunSystemOnce;
|
use bevy::ecs::system::RunSystemOnce;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::utils::HashMap;
|
use bevy::utils::HashMap;
|
||||||
|
use bevy_xr::session::XrSessionCreatedEvent;
|
||||||
use openxr::sys::ActionSuggestedBinding;
|
use openxr::sys::ActionSuggestedBinding;
|
||||||
|
|
||||||
use crate::{resources::OxrInstance, session::OxrSessionStatusEvent};
|
use crate::resources::OxrInstance;
|
||||||
|
|
||||||
impl Plugin for OxrActionBindingPlugin {
|
impl Plugin for OxrActionBindingPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
@@ -15,13 +16,7 @@ impl Plugin for OxrActionBindingPlugin {
|
|||||||
app.add_event::<OxrSuggestActionBinding>();
|
app.add_event::<OxrSuggestActionBinding>();
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
run_action_binding_sugestion.run_if(
|
run_action_binding_sugestion.run_if(on_event::<XrSessionCreatedEvent>()),
|
||||||
|mut session_state: EventReader<OxrSessionStatusEvent>| {
|
|
||||||
session_state
|
|
||||||
.read()
|
|
||||||
.any(|s| *s == OxrSessionStatusEvent::Created)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{action_binding::run_action_binding_sugestion, session::OxrSession};
|
||||||
action_binding::run_action_binding_sugestion,
|
|
||||||
session::{OxrSession, OxrSessionStatusEvent},
|
|
||||||
};
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy_xr::session::XrSessionCreatedEvent;
|
||||||
|
|
||||||
impl Plugin for OxrActionAttachingPlugin {
|
impl Plugin for OxrActionAttachingPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
@@ -10,13 +8,7 @@ impl Plugin for OxrActionAttachingPlugin {
|
|||||||
app.add_systems(
|
app.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
attach_sets
|
attach_sets
|
||||||
.run_if(
|
.run_if(on_event::<XrSessionCreatedEvent>())
|
||||||
|mut session_status_event: EventReader<OxrSessionStatusEvent>| {
|
|
||||||
session_status_event
|
|
||||||
.read()
|
|
||||||
.any(|s| *s == OxrSessionStatusEvent::Created)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.after(run_action_binding_sugestion),
|
.after(run_action_binding_sugestion),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_xr::hands::{LeftHand, RightHand};
|
use bevy_xr::hands::{LeftHand, RightHand};
|
||||||
|
use bevy_xr::session::{XrCreateSession, XrDestroySession, XrTrackingRoot};
|
||||||
use bevy_xr::spaces::{XrPrimaryReferenceSpace, XrReferenceSpace};
|
use bevy_xr::spaces::{XrPrimaryReferenceSpace, XrReferenceSpace};
|
||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
hands::{HandBone, HandBoneRadius},
|
hands::{HandBone, HandBoneRadius},
|
||||||
session::{session_running, XrSessionCreated, XrSessionExiting},
|
session::session_running,
|
||||||
};
|
};
|
||||||
use openxr::SpaceLocationFlags;
|
use openxr::SpaceLocationFlags;
|
||||||
|
|
||||||
|
use crate::init::create_xr_session;
|
||||||
|
use crate::resources::OxrFrameState;
|
||||||
use crate::resources::Pipelined;
|
use crate::resources::Pipelined;
|
||||||
use crate::{
|
use crate::session::OxrSession;
|
||||||
init::OxrTrackingRoot,
|
|
||||||
resources::OxrFrameState,
|
|
||||||
session::OxrSession,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct HandTrackingPlugin {
|
pub struct HandTrackingPlugin {
|
||||||
default_hands: bool,
|
default_hands: bool,
|
||||||
@@ -29,8 +28,13 @@ impl Plugin for HandTrackingPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(PreUpdate, locate_hands.run_if(session_running));
|
app.add_systems(PreUpdate, locate_hands.run_if(session_running));
|
||||||
if self.default_hands {
|
if self.default_hands {
|
||||||
app.add_systems(XrSessionExiting, clean_up_default_hands);
|
app.add_systems(XrDestroySession, clean_up_default_hands)
|
||||||
app.add_systems(XrSessionCreated, spawn_default_hands);
|
.add_systems(
|
||||||
|
XrCreateSession,
|
||||||
|
(spawn_default_hands, apply_deferred)
|
||||||
|
.chain()
|
||||||
|
.after(create_xr_session),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +42,7 @@ impl Plugin for HandTrackingPlugin {
|
|||||||
fn spawn_default_hands(
|
fn spawn_default_hands(
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
session: Res<OxrSession>,
|
session: Res<OxrSession>,
|
||||||
root: Query<Entity, With<OxrTrackingRoot>>,
|
root: Query<Entity, With<XrTrackingRoot>>,
|
||||||
) {
|
) {
|
||||||
debug!("spawning default hands");
|
debug!("spawning default hands");
|
||||||
let Ok(root) = root.get_single() else {
|
let Ok(root) = root.get_single() else {
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
use bevy::app::MainScheduleOrder;
|
|
||||||
use bevy::ecs::schedule::ScheduleLabel;
|
|
||||||
use bevy::ecs::system::RunSystemOnce;
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::extract_resource::ExtractResourcePlugin;
|
use bevy::render::extract_resource::ExtractResourcePlugin;
|
||||||
use bevy::render::renderer::RenderAdapter;
|
use bevy::render::renderer::RenderAdapter;
|
||||||
@@ -10,48 +7,38 @@ use bevy::render::renderer::RenderInstance;
|
|||||||
use bevy::render::renderer::RenderQueue;
|
use bevy::render::renderer::RenderQueue;
|
||||||
use bevy::render::settings::RenderCreation;
|
use bevy::render::settings::RenderCreation;
|
||||||
use bevy::render::MainWorld;
|
use bevy::render::MainWorld;
|
||||||
use bevy::render::Render;
|
|
||||||
use bevy::render::RenderApp;
|
use bevy::render::RenderApp;
|
||||||
use bevy::render::RenderPlugin;
|
use bevy::render::RenderPlugin;
|
||||||
use bevy::render::RenderSet;
|
|
||||||
use bevy::transform::TransformSystem;
|
|
||||||
use bevy::winit::UpdateMode;
|
use bevy::winit::UpdateMode;
|
||||||
use bevy::winit::WinitSettings;
|
use bevy::winit::WinitSettings;
|
||||||
use bevy_xr::session::session_running;
|
use bevy_xr::session::*;
|
||||||
use bevy_xr::session::status_equals;
|
|
||||||
use bevy_xr::session::BeginXrSession;
|
|
||||||
use bevy_xr::session::CreateXrSession;
|
|
||||||
use bevy_xr::session::DestroyXrSession;
|
|
||||||
use bevy_xr::session::EndXrSession;
|
|
||||||
use bevy_xr::session::XrSessionExiting;
|
|
||||||
use bevy_xr::session::XrStatus;
|
|
||||||
use bevy_xr::session::XrStatusChanged;
|
|
||||||
|
|
||||||
use crate::error::OxrError;
|
use crate::error::OxrError;
|
||||||
use crate::features::overlay::OxrOverlaySessionEvent;
|
use crate::features::overlay::OxrOverlaySessionEvent;
|
||||||
use crate::graphics::*;
|
use crate::graphics::*;
|
||||||
use crate::openxr::exts::OxrEnabledExtensions;
|
|
||||||
use crate::resources::*;
|
use crate::resources::*;
|
||||||
use crate::session::OxrSession;
|
use crate::session::OxrSession;
|
||||||
use crate::session::OxrSessionCreateNextChain;
|
use crate::session::OxrSessionCreateNextChain;
|
||||||
use crate::session::OxrSessionStatusEvent;
|
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
|
use super::exts::OxrEnabledExtensions;
|
||||||
|
|
||||||
pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool {
|
pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool {
|
||||||
started.is_some_and(|started| started.0)
|
started.is_some_and(|started| started.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn should_run_frame_loop(
|
||||||
|
started: Option<Res<OxrSessionStarted>>,
|
||||||
|
state: Option<Res<XrState>>,
|
||||||
|
) -> bool {
|
||||||
|
started.is_some_and(|started| started.0)
|
||||||
|
&& state.is_some_and(|state| *state != XrState::Stopping)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn should_render(frame_state: Option<Res<OxrFrameState>>) -> bool {
|
pub fn should_render(frame_state: Option<Res<OxrFrameState>>) -> bool {
|
||||||
frame_state.is_some_and(|frame_state| frame_state.should_render)
|
frame_state.is_some_and(|frame_state| frame_state.should_render)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO!() better name pls
|
|
||||||
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct OxrLast;
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
|
||||||
pub struct OxrHandleEvents;
|
|
||||||
|
|
||||||
pub struct OxrInitPlugin {
|
pub struct OxrInitPlugin {
|
||||||
/// Information about the app this is being used to build.
|
/// Information about the app this is being used to build.
|
||||||
pub app_info: AppInfo,
|
pub app_info: AppInfo,
|
||||||
@@ -88,9 +75,6 @@ impl Default for OxrInitPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct OxrTrackingRoot;
|
|
||||||
|
|
||||||
impl Plugin for OxrInitPlugin {
|
impl Plugin for OxrInitPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
match self.init_xr() {
|
match self.init_xr() {
|
||||||
@@ -101,8 +85,8 @@ impl Plugin for OxrInitPlugin {
|
|||||||
session_create_info,
|
session_create_info,
|
||||||
enabled_exts,
|
enabled_exts,
|
||||||
)) => {
|
)) => {
|
||||||
app.insert_resource(enabled_exts);
|
app.insert_resource(enabled_exts)
|
||||||
app.add_plugins((
|
.add_plugins((
|
||||||
RenderPlugin {
|
RenderPlugin {
|
||||||
render_creation: RenderCreation::manual(
|
render_creation: RenderCreation::manual(
|
||||||
device.into(),
|
device.into(),
|
||||||
@@ -113,91 +97,58 @@ impl Plugin for OxrInitPlugin {
|
|||||||
),
|
),
|
||||||
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
|
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
|
||||||
},
|
},
|
||||||
ExtractResourcePlugin::<OxrCleanupSession>::default(),
|
|
||||||
ExtractResourcePlugin::<XrStatus>::default(),
|
|
||||||
ExtractResourcePlugin::<OxrSessionStarted>::default(),
|
ExtractResourcePlugin::<OxrSessionStarted>::default(),
|
||||||
))
|
))
|
||||||
.init_schedule(OxrLast)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
OxrLast,
|
XrFirst,
|
||||||
(
|
poll_events
|
||||||
reset_per_frame_resources,
|
.before(XrHandleEvents)
|
||||||
poll_events,
|
.run_if(not(state_equals(XrState::Unavailable))),
|
||||||
create_xr_session
|
|
||||||
.run_if(on_event::<CreateXrSession>())
|
|
||||||
.run_if(status_equals(XrStatus::Available)),
|
|
||||||
begin_xr_session
|
|
||||||
.run_if(on_event::<BeginXrSession>())
|
|
||||||
.run_if(status_equals(XrStatus::Ready)),
|
|
||||||
end_xr_session
|
|
||||||
.run_if(on_event::<EndXrSession>())
|
|
||||||
.run_if(status_equals(XrStatus::Running)),
|
|
||||||
destroy_xr_session
|
|
||||||
.run_if(on_event::<DestroyXrSession>())
|
|
||||||
.run_if(status_equals(XrStatus::Exiting)),
|
|
||||||
)
|
|
||||||
.chain()
|
|
||||||
.in_set(OxrHandleEvents),
|
|
||||||
)
|
|
||||||
.add_systems(XrSessionExiting, destroy_xr_session)
|
|
||||||
.add_systems(
|
|
||||||
PostUpdate,
|
|
||||||
update_root_transform.after(TransformSystem::TransformPropagate),
|
|
||||||
)
|
)
|
||||||
|
.add_systems(XrCreateSession, create_xr_session)
|
||||||
|
.add_systems(XrDestroySession, destroy_xr_session)
|
||||||
|
.add_systems(XrBeginSession, begin_xr_session)
|
||||||
|
.add_systems(XrEndSession, end_xr_session)
|
||||||
|
.add_systems(XrRequestExit, request_exit_xr_session)
|
||||||
.insert_resource(instance.clone())
|
.insert_resource(instance.clone())
|
||||||
.insert_resource(system_id)
|
.insert_resource(system_id)
|
||||||
.insert_resource(XrStatus::Available)
|
.insert_resource(XrState::Available)
|
||||||
.insert_resource(WinitSettings {
|
.insert_resource(WinitSettings {
|
||||||
focused_mode: UpdateMode::Continuous,
|
focused_mode: UpdateMode::Continuous,
|
||||||
unfocused_mode: UpdateMode::Continuous,
|
unfocused_mode: UpdateMode::Continuous,
|
||||||
})
|
})
|
||||||
.init_resource::<OxrCleanupSession>()
|
.insert_resource(OxrSessionStarted(false))
|
||||||
.init_resource::<OxrRootTransform>()
|
|
||||||
.insert_non_send_resource(session_create_info)
|
.insert_non_send_resource(session_create_info)
|
||||||
.configure_sets(OxrLast, OxrHandleEvents);
|
.init_non_send_resource::<OxrSessionCreateNextChain>();
|
||||||
|
|
||||||
app.world
|
app.world
|
||||||
.resource_mut::<MainScheduleOrder>()
|
.spawn((TransformBundle::default(), XrTrackingRoot));
|
||||||
.insert_after(Last, OxrLast);
|
|
||||||
|
|
||||||
app.world
|
app.world
|
||||||
.spawn((TransformBundle::default(), OxrTrackingRoot));
|
.resource_mut::<Events<XrStateChanged>>()
|
||||||
|
.send(XrStateChanged(XrState::Available));
|
||||||
|
|
||||||
let render_app = app.sub_app_mut(RenderApp);
|
let render_app = app.sub_app_mut(RenderApp);
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
.add_systems(
|
.add_systems(ExtractSchedule, transfer_xr_resources)
|
||||||
Render,
|
|
||||||
destroy_xr_session_render
|
|
||||||
.run_if(resource_equals(OxrCleanupSession(true)))
|
|
||||||
.after(RenderSet::Cleanup),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
ExtractSchedule,
|
|
||||||
transfer_xr_resources.run_if(not(session_running)),
|
|
||||||
)
|
|
||||||
.insert_resource(instance)
|
.insert_resource(instance)
|
||||||
.insert_resource(system_id)
|
.insert_resource(system_id)
|
||||||
.init_resource::<OxrRootTransform>()
|
.insert_resource(XrState::Available)
|
||||||
.init_resource::<OxrCleanupSession>();
|
.insert_resource(OxrSessionStarted(false));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to initialize openxr: {e}");
|
error!("Failed to initialize openxr: {e}");
|
||||||
app.add_plugins(RenderPlugin::default())
|
app.add_plugins(RenderPlugin::default())
|
||||||
.insert_resource(XrStatus::Unavailable);
|
.insert_resource(XrState::Unavailable);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
app.insert_resource(OxrSessionStarted(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_root_transform(
|
fn finish(&self, app: &mut App) {
|
||||||
mut root_transform: ResMut<OxrRootTransform>,
|
app.sub_app_mut(RenderApp)
|
||||||
root: Query<&GlobalTransform, With<OxrTrackingRoot>>,
|
.add_systems(XrDestroySession, destroy_xr_session);
|
||||||
) {
|
}
|
||||||
let transform = root.single();
|
|
||||||
|
|
||||||
root_transform.0 = *transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OxrInitPlugin {
|
impl OxrInitPlugin {
|
||||||
@@ -291,6 +242,63 @@ impl OxrInitPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Polls any OpenXR events and handles them accordingly
|
||||||
|
pub fn poll_events(
|
||||||
|
instance: Res<OxrInstance>,
|
||||||
|
mut status: ResMut<XrState>,
|
||||||
|
mut changed_event: EventWriter<XrStateChanged>,
|
||||||
|
mut overlay_writer: Option<ResMut<Events<OxrOverlaySessionEvent>>>,
|
||||||
|
) {
|
||||||
|
let _span = info_span!("xr_poll_events");
|
||||||
|
let mut buffer = Default::default();
|
||||||
|
while let Some(event) = instance
|
||||||
|
.poll_event(&mut buffer)
|
||||||
|
.expect("Failed to poll event")
|
||||||
|
{
|
||||||
|
use openxr::Event::*;
|
||||||
|
match event {
|
||||||
|
SessionStateChanged(state) => {
|
||||||
|
use openxr::SessionState;
|
||||||
|
|
||||||
|
let state = state.state();
|
||||||
|
|
||||||
|
info!("entered XR state {:?}", state);
|
||||||
|
|
||||||
|
let new_status = match state {
|
||||||
|
SessionState::IDLE => XrState::Idle,
|
||||||
|
SessionState::READY => XrState::Ready,
|
||||||
|
SessionState::SYNCHRONIZED | SessionState::VISIBLE | SessionState::FOCUSED => {
|
||||||
|
XrState::Running
|
||||||
|
}
|
||||||
|
SessionState::STOPPING => XrState::Stopping,
|
||||||
|
SessionState::EXITING => XrState::Exiting {
|
||||||
|
should_restart: false,
|
||||||
|
},
|
||||||
|
SessionState::LOSS_PENDING => XrState::Exiting {
|
||||||
|
should_restart: true,
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
changed_event.send(XrStateChanged(new_status));
|
||||||
|
*status = new_status;
|
||||||
|
}
|
||||||
|
InstanceLossPending(_) => {}
|
||||||
|
EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()),
|
||||||
|
MainSessionVisibilityChangedEXTX(d) => {
|
||||||
|
if let Some(writer) = overlay_writer.as_mut() {
|
||||||
|
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
|
||||||
|
visible: d.visible(),
|
||||||
|
flags: d.flags(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
warn!("Overlay Event Recieved without the OverlayPlugin being added!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn init_xr_session(
|
fn init_xr_session(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
instance: &OxrInstance,
|
instance: &OxrInstance,
|
||||||
@@ -426,6 +434,49 @@ fn init_xr_session(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_xr_session(world: &mut World) {
|
||||||
|
let mut chain = world
|
||||||
|
.remove_non_send_resource::<OxrSessionCreateNextChain>()
|
||||||
|
.unwrap();
|
||||||
|
let device = world.resource::<RenderDevice>();
|
||||||
|
let instance = world.resource::<OxrInstance>();
|
||||||
|
let create_info = world.non_send_resource::<SessionConfigInfo>();
|
||||||
|
let system_id = world.resource::<OxrSystemId>();
|
||||||
|
match init_xr_session(
|
||||||
|
device.wgpu_device(),
|
||||||
|
&instance,
|
||||||
|
**system_id,
|
||||||
|
&mut chain,
|
||||||
|
create_info.clone(),
|
||||||
|
) {
|
||||||
|
Ok((session, frame_waiter, frame_stream, swapchain, images, graphics_info)) => {
|
||||||
|
world.insert_resource(session.clone());
|
||||||
|
world.insert_resource(frame_waiter);
|
||||||
|
world.insert_resource(images.clone());
|
||||||
|
world.insert_resource(graphics_info.clone());
|
||||||
|
world.insert_resource(OxrRenderResources {
|
||||||
|
session,
|
||||||
|
frame_stream,
|
||||||
|
swapchain,
|
||||||
|
images,
|
||||||
|
graphics_info,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => error!("Failed to initialize XrSession: {e}"),
|
||||||
|
}
|
||||||
|
world.insert_non_send_resource(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy_xr_session(world: &mut World) {
|
||||||
|
world.remove_resource::<OxrSession>();
|
||||||
|
world.remove_resource::<OxrFrameWaiter>();
|
||||||
|
world.remove_resource::<OxrFrameStream>();
|
||||||
|
world.remove_resource::<OxrSwapchain>();
|
||||||
|
world.remove_resource::<OxrSwapchainImages>();
|
||||||
|
world.remove_resource::<OxrGraphicsInfo>();
|
||||||
|
world.insert_resource(XrState::Available);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn begin_xr_session(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
pub fn begin_xr_session(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
||||||
let _span = info_span!("xr_begin_session");
|
let _span = info_span!("xr_begin_session");
|
||||||
session
|
session
|
||||||
@@ -436,10 +487,14 @@ pub fn begin_xr_session(session: Res<OxrSession>, mut session_started: ResMut<Ox
|
|||||||
|
|
||||||
pub fn end_xr_session(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
pub fn end_xr_session(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
||||||
let _span = info_span!("xr_end_session");
|
let _span = info_span!("xr_end_session");
|
||||||
session.request_exit().expect("Failed to end session");
|
session.end().expect("Failed to end session");
|
||||||
session_started.0 = false;
|
session_started.0 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request_exit_xr_session(session: Res<OxrSession>) {
|
||||||
|
session.request_exit().expect("Failed to request exit");
|
||||||
|
}
|
||||||
|
|
||||||
/// This is used solely to transport resources from the main world to the render world.
|
/// This is used solely to transport resources from the main world to the render world.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct OxrRenderResources {
|
struct OxrRenderResources {
|
||||||
@@ -450,38 +505,6 @@ struct OxrRenderResources {
|
|||||||
graphics_info: OxrGraphicsInfo,
|
graphics_info: OxrGraphicsInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_xr_session(
|
|
||||||
device: Res<RenderDevice>,
|
|
||||||
instance: Res<OxrInstance>,
|
|
||||||
create_info: NonSend<SessionConfigInfo>,
|
|
||||||
system_id: Res<OxrSystemId>,
|
|
||||||
mut chain: NonSendMut<OxrSessionCreateNextChain>,
|
|
||||||
mut commands: Commands,
|
|
||||||
) {
|
|
||||||
match init_xr_session(
|
|
||||||
device.wgpu_device(),
|
|
||||||
&instance,
|
|
||||||
**system_id,
|
|
||||||
&mut chain,
|
|
||||||
create_info.clone(),
|
|
||||||
) {
|
|
||||||
Ok((session, frame_waiter, frame_stream, swapchain, images, graphics_info)) => {
|
|
||||||
commands.insert_resource(session.clone());
|
|
||||||
commands.insert_resource(frame_waiter);
|
|
||||||
commands.insert_resource(images.clone());
|
|
||||||
commands.insert_resource(graphics_info.clone());
|
|
||||||
commands.insert_resource(OxrRenderResources {
|
|
||||||
session,
|
|
||||||
frame_stream,
|
|
||||||
swapchain,
|
|
||||||
images,
|
|
||||||
graphics_info,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(e) => error!("Failed to initialize XrSession: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This system transfers important render resources from the main world to the render world when a session is created.
|
/// This system transfers important render resources from the main world to the render world when a session is created.
|
||||||
pub fn transfer_xr_resources(mut commands: Commands, mut world: ResMut<MainWorld>) {
|
pub fn transfer_xr_resources(mut commands: Commands, mut world: ResMut<MainWorld>) {
|
||||||
let Some(OxrRenderResources {
|
let Some(OxrRenderResources {
|
||||||
@@ -501,86 +524,3 @@ pub fn transfer_xr_resources(mut commands: Commands, mut world: ResMut<MainWorld
|
|||||||
commands.insert_resource(images);
|
commands.insert_resource(images);
|
||||||
commands.insert_resource(graphics_info);
|
commands.insert_resource(graphics_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Polls any OpenXR events and handles them accordingly
|
|
||||||
pub fn poll_events(
|
|
||||||
instance: Res<OxrInstance>,
|
|
||||||
mut status: ResMut<XrStatus>,
|
|
||||||
mut changed_event: EventWriter<XrStatusChanged>,
|
|
||||||
mut session_status_events: EventWriter<OxrSessionStatusEvent>,
|
|
||||||
mut overlay_writer: Option<ResMut<Events<OxrOverlaySessionEvent>>>,
|
|
||||||
) {
|
|
||||||
let _span = info_span!("xr_poll_events");
|
|
||||||
let mut buffer = Default::default();
|
|
||||||
while let Some(event) = instance
|
|
||||||
.poll_event(&mut buffer)
|
|
||||||
.expect("Failed to poll event")
|
|
||||||
{
|
|
||||||
use openxr::Event::*;
|
|
||||||
match event {
|
|
||||||
SessionStateChanged(state) => {
|
|
||||||
use openxr::SessionState;
|
|
||||||
|
|
||||||
let state = state.state();
|
|
||||||
|
|
||||||
info!("entered XR state {:?}", state);
|
|
||||||
|
|
||||||
let new_status = match state {
|
|
||||||
SessionState::IDLE => {
|
|
||||||
if *status == XrStatus::Available {
|
|
||||||
session_status_events.send(OxrSessionStatusEvent::Created);
|
|
||||||
}
|
|
||||||
XrStatus::Idle
|
|
||||||
}
|
|
||||||
SessionState::READY => XrStatus::Ready,
|
|
||||||
SessionState::SYNCHRONIZED | SessionState::VISIBLE | SessionState::FOCUSED => {
|
|
||||||
XrStatus::Running
|
|
||||||
}
|
|
||||||
SessionState::STOPPING => XrStatus::Stopping,
|
|
||||||
SessionState::EXITING | SessionState::LOSS_PENDING => {
|
|
||||||
session_status_events.send(OxrSessionStatusEvent::AboutToBeDestroyed);
|
|
||||||
XrStatus::Exiting
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
changed_event.send(XrStatusChanged(new_status));
|
|
||||||
*status = new_status;
|
|
||||||
}
|
|
||||||
InstanceLossPending(_) => {}
|
|
||||||
EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()),
|
|
||||||
MainSessionVisibilityChangedEXTX(d) => {
|
|
||||||
if let Some(writer) = overlay_writer.as_mut() {
|
|
||||||
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
|
|
||||||
visible: d.visible(),
|
|
||||||
flags: d.flags(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
warn!("Overlay Event Recieved without the OverlayPlugin being added!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_per_frame_resources(mut cleanup: ResMut<OxrCleanupSession>) {
|
|
||||||
**cleanup = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy_xr_session(mut commands: Commands) {
|
|
||||||
commands.remove_resource::<OxrFrameWaiter>();
|
|
||||||
commands.remove_resource::<OxrSwapchainImages>();
|
|
||||||
commands.remove_resource::<OxrGraphicsInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy_xr_session_render(world: &mut World) {
|
|
||||||
world.remove_resource::<OxrSwapchain>();
|
|
||||||
world.remove_resource::<OxrFrameStream>();
|
|
||||||
world.remove_resource::<OxrSwapchainImages>();
|
|
||||||
world.remove_resource::<OxrGraphicsInfo>();
|
|
||||||
world.run_system_once(apply_deferred);
|
|
||||||
world.run_schedule(XrSessionExiting);
|
|
||||||
world.run_system_once(apply_deferred);
|
|
||||||
world.remove_resource::<OxrSession>();
|
|
||||||
world.insert_resource(OxrSessionStarted(false));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// use actions::XrActionPlugin;
|
// use actions::XrActionPlugin;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
app::{PluginGroup, PluginGroupBuilder},
|
app::{PluginGroup, PluginGroupBuilder},
|
||||||
render::{pipelined_rendering::PipelinedRenderingPlugin, RenderPlugin},
|
render::RenderPlugin,
|
||||||
utils::default,
|
utils::default,
|
||||||
window::{PresentMode, Window, WindowPlugin},
|
window::{PresentMode, Window, WindowPlugin},
|
||||||
};
|
};
|
||||||
@@ -13,7 +13,6 @@ use render::OxrRenderPlugin;
|
|||||||
use self::{
|
use self::{
|
||||||
features::{handtracking::HandTrackingPlugin, passthrough::OxrPassthroughPlugin},
|
features::{handtracking::HandTrackingPlugin, passthrough::OxrPassthroughPlugin},
|
||||||
reference_space::OxrReferenceSpacePlugin,
|
reference_space::OxrReferenceSpacePlugin,
|
||||||
session::OxrSessionPlugin,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod action_binding;
|
pub mod action_binding;
|
||||||
@@ -31,17 +30,16 @@ pub mod reference_space;
|
|||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod types;
|
|
||||||
pub mod spaces;
|
pub mod spaces;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
|
pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
|
||||||
plugins
|
plugins
|
||||||
.build()
|
.build()
|
||||||
.disable::<RenderPlugin>()
|
.disable::<RenderPlugin>()
|
||||||
.disable::<PipelinedRenderingPlugin>()
|
// .disable::<PipelinedRenderingPlugin>()
|
||||||
.add_before::<RenderPlugin, _>(XrSessionPlugin)
|
.add_before::<RenderPlugin, _>(XrSessionPlugin { auto_handle: true })
|
||||||
.add_before::<RenderPlugin, _>(OxrInitPlugin::default())
|
.add_before::<RenderPlugin, _>(OxrInitPlugin::default())
|
||||||
.add(OxrSessionPlugin)
|
|
||||||
.add(OxrReferenceSpacePlugin::default())
|
.add(OxrReferenceSpacePlugin::default())
|
||||||
.add(OxrRenderPlugin)
|
.add(OxrRenderPlugin)
|
||||||
.add(OxrPassthroughPlugin)
|
.add(OxrPassthroughPlugin)
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{extract_resource::ExtractResourcePlugin, RenderApp},
|
||||||
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
|
||||||
RenderApp,
|
|
||||||
}, utils::HashSet,
|
|
||||||
};
|
};
|
||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
session::{XrSessionCreated, XrSessionExiting},
|
session::{XrCreateSession, XrDestroySession},
|
||||||
spaces::{XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace},
|
spaces::{XrPrimaryReferenceSpace, XrReferenceSpace},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{resources::OxrInstance, session::OxrSession};
|
use crate::{init::create_xr_session, session::OxrSession};
|
||||||
|
|
||||||
pub struct OxrReferenceSpacePlugin {
|
pub struct OxrReferenceSpacePlugin {
|
||||||
pub default_primary_ref_space: openxr::ReferenceSpaceType,
|
pub default_primary_ref_space: openxr::ReferenceSpaceType,
|
||||||
@@ -25,46 +20,40 @@ impl Default for OxrReferenceSpacePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resource specifying what the type should be for [`OxrPrimaryReferenceSpace`]. Set through [`OxrReferenceSpacePlugin`].
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType);
|
struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType);
|
||||||
|
|
||||||
/// The Default Reference space used for locating things
|
/// The Default Reference space used for locating things
|
||||||
// #[derive(Resource, Deref, ExtrctResource, Clone)]
|
// #[derive(Resource, Deref, ExtrctResource, Clone)]
|
||||||
// pub struct OxrPrimaryReferenceSpace(pub Arc<openxr::Space>);
|
// pub struct OxrPrimaryReferenceSpace(pub Arc<openxr::Space>);
|
||||||
|
|
||||||
/// The Reference space used for locating spaces on this entity
|
/// The Reference space used for locating spaces on this entity
|
||||||
// #[derive(Component)]
|
#[derive(Component)]
|
||||||
// pub struct OxrReferenceSpace(pub openxr::Space);
|
pub struct OxrReferenceSpace(pub openxr::Space);
|
||||||
|
|
||||||
impl Plugin for OxrReferenceSpacePlugin {
|
impl Plugin for OxrReferenceSpacePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.insert_resource(OxrDefaultPrimaryReferenceSpaceType(
|
app.add_plugins(ExtractResourcePlugin::<XrPrimaryReferenceSpace>::default())
|
||||||
|
.insert_resource(OxrDefaultPrimaryReferenceSpaceType(
|
||||||
self.default_primary_ref_space,
|
self.default_primary_ref_space,
|
||||||
));
|
))
|
||||||
app.add_plugins(ExtractResourcePlugin::<XrPrimaryReferenceSpace>::default());
|
.add_systems(
|
||||||
app.add_systems(XrSessionCreated, set_primary_ref_space);
|
XrCreateSession,
|
||||||
app.add_systems(XrSessionExiting, cleanup);
|
set_primary_ref_space.after(create_xr_session),
|
||||||
app.sub_app_mut(RenderApp)
|
)
|
||||||
.add_systems(XrSessionExiting, cleanup);
|
.add_systems(XrDestroySession, cleanup);
|
||||||
|
|
||||||
|
let render_app = app.sub_app_mut(RenderApp);
|
||||||
|
|
||||||
|
render_app.add_systems(XrDestroySession, cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup(
|
fn cleanup(query: Query<Entity, With<XrReferenceSpace>>, mut cmds: Commands) {
|
||||||
query: Query<(Entity, &XrReferenceSpace)>,
|
|
||||||
mut cmds: Commands,
|
|
||||||
instance: Res<OxrInstance>,
|
|
||||||
ref_space: Option<Res<XrPrimaryReferenceSpace>>,
|
|
||||||
) {
|
|
||||||
let mut to_destroy = HashSet::<XrSpace>::new();
|
|
||||||
if let Some(space) = ref_space {
|
|
||||||
to_destroy.insert(***space);
|
|
||||||
}
|
|
||||||
cmds.remove_resource::<XrPrimaryReferenceSpace>();
|
cmds.remove_resource::<XrPrimaryReferenceSpace>();
|
||||||
for (e, space) in &query {
|
for e in &query {
|
||||||
cmds.entity(e).remove::<XrReferenceSpace>();
|
cmds.entity(e).remove::<XrReferenceSpace>();
|
||||||
to_destroy.insert(**space);
|
|
||||||
}
|
|
||||||
for space in to_destroy.into_iter() {
|
|
||||||
let _ = instance.destroy_space(space);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,26 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
app::{MainScheduleOrder, SubApp},
|
ecs::query::QuerySingleError,
|
||||||
ecs::{query::QuerySingleError, schedule::MainThreadExecutor},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
|
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
|
||||||
extract_resource::ExtractResourcePlugin,
|
extract_resource::ExtractResourcePlugin,
|
||||||
pipelined_rendering::{PipelinedRenderingPlugin, RenderAppChannels, RenderExtractApp},
|
pipelined_rendering::PipelinedRenderingPlugin,
|
||||||
view::ExtractedView,
|
view::ExtractedView,
|
||||||
Render, RenderApp, RenderSet,
|
Render, RenderApp,
|
||||||
},
|
},
|
||||||
tasks::ComputeTaskPool,
|
|
||||||
transform::TransformSystem,
|
transform::TransformSystem,
|
||||||
};
|
};
|
||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
camera::{XrCamera, XrCameraBundle, XrProjection},
|
camera::{XrCamera, XrCameraBundle, XrProjection},
|
||||||
session::{session_running, XrSessionExiting},
|
session::{
|
||||||
|
XrDestroySession, XrFirst, XrHandleEvents, XrRenderSet, XrRootTransform, XrTrackingRoot,
|
||||||
|
},
|
||||||
spaces::XrPrimaryReferenceSpace,
|
spaces::XrPrimaryReferenceSpace,
|
||||||
};
|
};
|
||||||
use openxr::ViewStateFlags;
|
use openxr::ViewStateFlags;
|
||||||
|
|
||||||
use crate::resources::*;
|
use crate::{init::should_run_frame_loop, resources::*};
|
||||||
use crate::spaces::OxrSpaceExt as _;
|
use crate::{layer_builder::ProjectionLayer, session::OxrSession};
|
||||||
use crate::{
|
|
||||||
init::{session_started, OxrHandleEvents, OxrLast, OxrTrackingRoot},
|
|
||||||
layer_builder::ProjectionLayer,
|
|
||||||
session::OxrSession,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
||||||
pub struct OxrRenderBegin;
|
pub struct OxrRenderBegin;
|
||||||
@@ -40,66 +35,42 @@ impl Plugin for OxrRenderPlugin {
|
|||||||
if app.is_plugin_added::<PipelinedRenderingPlugin>() {
|
if app.is_plugin_added::<PipelinedRenderingPlugin>() {
|
||||||
app.init_resource::<Pipelined>();
|
app.init_resource::<Pipelined>();
|
||||||
|
|
||||||
let mut schedule_order = app.world.resource_mut::<MainScheduleOrder>();
|
// if let Some(sub_app) = app.remove_sub_app(RenderExtractApp) {
|
||||||
|
// app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app.app, update_rendering));
|
||||||
if let Some(pos) = schedule_order
|
// }
|
||||||
.labels
|
|
||||||
.iter()
|
|
||||||
.position(|label| (**label).eq(&OxrLast))
|
|
||||||
{
|
|
||||||
schedule_order.labels.remove(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(sub_app) = app.remove_sub_app(RenderExtractApp) {
|
|
||||||
app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app.app, update_rendering));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.add_plugins((
|
app.add_plugins((
|
||||||
ExtractResourcePlugin::<OxrFrameState>::default(),
|
ExtractResourcePlugin::<OxrFrameState>::default(),
|
||||||
ExtractResourcePlugin::<OxrRootTransform>::default(),
|
|
||||||
ExtractResourcePlugin::<OxrGraphicsInfo>::default(),
|
ExtractResourcePlugin::<OxrGraphicsInfo>::default(),
|
||||||
ExtractResourcePlugin::<OxrSwapchainImages>::default(),
|
ExtractResourcePlugin::<OxrSwapchainImages>::default(),
|
||||||
ExtractResourcePlugin::<OxrViews>::default(),
|
ExtractResourcePlugin::<OxrViews>::default(),
|
||||||
))
|
))
|
||||||
|
.add_systems(XrDestroySession, clean_views)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
XrFirst,
|
||||||
|
(
|
||||||
|
wait_frame.run_if(should_run_frame_loop),
|
||||||
|
update_cameras.run_if(should_run_frame_loop),
|
||||||
|
init_views.run_if(resource_added::<OxrSession>),
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.after(XrHandleEvents),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
PostUpdate,
|
||||||
(locate_views, update_views)
|
(locate_views, update_views)
|
||||||
|
.before(TransformSystem::TransformPropagate)
|
||||||
.chain()
|
.chain()
|
||||||
// .run_if(should_render)
|
// .run_if(should_render)
|
||||||
.run_if(session_started),
|
.run_if(should_run_frame_loop),
|
||||||
)
|
)
|
||||||
.add_systems(
|
|
||||||
OxrLast,
|
|
||||||
(
|
|
||||||
wait_frame.run_if(session_started),
|
|
||||||
update_cameras.run_if(session_started),
|
|
||||||
init_views.run_if(resource_added::<OxrSession>),
|
|
||||||
apply_deferred,
|
|
||||||
)
|
|
||||||
.chain()
|
|
||||||
.after(OxrHandleEvents),
|
|
||||||
)
|
|
||||||
.add_systems(XrSessionExiting, clean_views)
|
|
||||||
.init_resource::<OxrViews>();
|
.init_resource::<OxrViews>();
|
||||||
|
|
||||||
let render_app = app.sub_app_mut(RenderApp);
|
let render_app = app.sub_app_mut(RenderApp);
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
.configure_sets(
|
.add_systems(XrDestroySession, clean_views)
|
||||||
Render,
|
|
||||||
OxrRenderBegin
|
|
||||||
.after(RenderSet::ExtractCommands)
|
|
||||||
.before(RenderSet::PrepareAssets)
|
|
||||||
.before(RenderSet::ManageViews),
|
|
||||||
)
|
|
||||||
.configure_sets(
|
|
||||||
Render,
|
|
||||||
OxrRenderEnd
|
|
||||||
.after(RenderSet::Render)
|
|
||||||
.before(RenderSet::Cleanup),
|
|
||||||
)
|
|
||||||
.add_systems(Last, wait_frame.run_if(session_started));
|
|
||||||
app.sub_app_mut(RenderApp)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
(
|
(
|
||||||
@@ -110,91 +81,47 @@ impl Plugin for OxrRenderPlugin {
|
|||||||
wait_image,
|
wait_image,
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
.run_if(session_started)
|
.in_set(XrRenderSet::PreRender)
|
||||||
.in_set(OxrRenderBegin),
|
.run_if(should_run_frame_loop),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
(release_image, end_frame)
|
(release_image, end_frame)
|
||||||
.chain()
|
.chain()
|
||||||
.run_if(session_started)
|
.run_if(should_run_frame_loop)
|
||||||
.in_set(OxrRenderEnd),
|
.in_set(XrRenderSet::PostRender),
|
||||||
)
|
)
|
||||||
.insert_resource(OxrRenderLayers(vec![Box::new(ProjectionLayer)]));
|
.insert_resource(OxrRenderLayers(vec![Box::new(ProjectionLayer)]));
|
||||||
// .add_systems(
|
|
||||||
// XrSessionExiting,
|
|
||||||
// (
|
|
||||||
// |mut cmds: Commands| cmds.remove_resource::<OxrRenderLayers>(),
|
|
||||||
// clean_views,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// app.add_systems(
|
|
||||||
// PreUpdate,
|
|
||||||
// (
|
|
||||||
// init_views.run_if(resource_added::<OxrGraphicsInfo>),
|
|
||||||
// locate_views.run_if(session_running),
|
|
||||||
// update_views.run_if(session_running),
|
|
||||||
// )
|
|
||||||
// .chain(), // .after(OxrPreUpdateSet::UpdateNonCriticalComponents),
|
|
||||||
// )
|
|
||||||
// .add_systems(
|
|
||||||
// PostUpdate,
|
|
||||||
// (locate_views, update_views)
|
|
||||||
// .chain()
|
|
||||||
// .run_if(session_running)
|
|
||||||
// .before(TransformSystem::TransformPropagate),
|
|
||||||
// )
|
|
||||||
// .add_systems(Last, wait_frame.run_if(session_started));
|
|
||||||
// app.sub_app_mut(RenderApp)
|
|
||||||
// .add_systems(
|
|
||||||
// Render,
|
|
||||||
// (
|
|
||||||
// (
|
|
||||||
// insert_texture_views,
|
|
||||||
// locate_views.run_if(resource_exists::<OxrPrimaryReferenceSpace>),
|
|
||||||
// update_views_render_world,
|
|
||||||
// )
|
|
||||||
// .chain()
|
|
||||||
// .in_set(RenderSet::PrepareAssets),
|
|
||||||
// begin_frame
|
|
||||||
// .before(RenderSet::Queue)
|
|
||||||
// .before(insert_texture_views),
|
|
||||||
// wait_image.in_set(RenderSet::Render).before(render_system),
|
|
||||||
// (release_image, end_frame)
|
|
||||||
// .chain()
|
|
||||||
// .in_set(RenderSet::Cleanup),
|
|
||||||
// )
|
|
||||||
// .run_if(session_started),
|
|
||||||
// )
|
|
||||||
// .insert_resource(OxrRenderLayers(vec![Box::new(ProjectionLayer)]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function waits for the rendering world to be received,
|
// fn update_rendering(app_world: &mut World, _sub_app: &mut App) {
|
||||||
// runs extract, and then sends the rendering world back to the render thread.
|
// app_world.resource_scope(|world, main_thread_executor: Mut<MainThreadExecutor>| {
|
||||||
//
|
// world.resource_scope(|world, mut render_channels: Mut<RenderAppChannels>| {
|
||||||
// modified pipelined rendering extract function
|
// // we use a scope here to run any main thread tasks that the render world still needs to run
|
||||||
fn update_rendering(app_world: &mut World, _sub_app: &mut App) {
|
// // while we wait for the render world to be received.
|
||||||
app_world.resource_scope(|world, main_thread_executor: Mut<MainThreadExecutor>| {
|
// let mut render_app = ComputeTaskPool::get()
|
||||||
world.resource_scope(|world, mut render_channels: Mut<RenderAppChannels>| {
|
// .scope_with_executor(true, Some(&*main_thread_executor.0), |s| {
|
||||||
// we use a scope here to run any main thread tasks that the render world still needs to run
|
// s.spawn(async { render_channels.recv().await });
|
||||||
// while we wait for the render world to be received.
|
// })
|
||||||
let mut render_app = ComputeTaskPool::get()
|
// .pop()
|
||||||
.scope_with_executor(true, Some(&*main_thread_executor.0), |s| {
|
// .unwrap();
|
||||||
s.spawn(async { render_channels.recv().await });
|
|
||||||
})
|
|
||||||
.pop()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
world.run_schedule(OxrLast);
|
// if matches!(world.resource::<XrState>(), XrState::Stopping) {
|
||||||
|
// world.run_schedule(XrEndSession);
|
||||||
|
// }
|
||||||
|
|
||||||
render_app.extract(world);
|
// if matches!(world.resource::<XrState>(), XrState::Exiting { .. }) {
|
||||||
|
// world.run_schedule(XrDestroySession);
|
||||||
|
// render_app.app.world.run_schedule(XrDestroySession);
|
||||||
|
// }
|
||||||
|
|
||||||
render_channels.send_blocking(render_app);
|
// render_app.extract(world);
|
||||||
});
|
|
||||||
});
|
// render_channels.send_blocking(render_app);
|
||||||
}
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
pub const XR_TEXTURE_INDEX: u32 = 3383858418;
|
pub const XR_TEXTURE_INDEX: u32 = 3383858418;
|
||||||
|
|
||||||
@@ -209,13 +136,11 @@ pub fn clean_views(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: have cameras initialized externally and then recieved by this function.
|
|
||||||
/// This is needed to properly initialize the texture views so that bevy will set them to the correct resolution despite them being updated in the render world.
|
|
||||||
pub fn init_views(
|
pub fn init_views(
|
||||||
graphics_info: Res<OxrGraphicsInfo>,
|
graphics_info: Res<OxrGraphicsInfo>,
|
||||||
mut manual_texture_views: ResMut<ManualTextureViews>,
|
mut manual_texture_views: ResMut<ManualTextureViews>,
|
||||||
swapchain_images: Res<OxrSwapchainImages>,
|
swapchain_images: Res<OxrSwapchainImages>,
|
||||||
root: Query<Entity, With<OxrTrackingRoot>>,
|
root: Query<Entity, With<XrTrackingRoot>>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
let _span = info_span!("xr_init_views");
|
let _span = info_span!("xr_init_views");
|
||||||
@@ -227,28 +152,24 @@ pub fn init_views(
|
|||||||
add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index);
|
add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index);
|
||||||
|
|
||||||
let cam = commands
|
let cam = commands
|
||||||
.spawn((
|
.spawn((XrCameraBundle {
|
||||||
XrCameraBundle {
|
|
||||||
camera: Camera {
|
camera: Camera {
|
||||||
target: RenderTarget::TextureView(view_handle),
|
target: RenderTarget::TextureView(view_handle),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
view: XrCamera(index),
|
view: XrCamera(index),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},))
|
||||||
// OpenXrTracker,
|
|
||||||
// XrRoot::default(),
|
|
||||||
))
|
|
||||||
.id();
|
.id();
|
||||||
match root.get_single() {
|
match root.get_single() {
|
||||||
Ok(root) => {
|
Ok(root) => {
|
||||||
commands.entity(root).add_child(cam);
|
commands.entity(root).add_child(cam);
|
||||||
}
|
}
|
||||||
Err(QuerySingleError::NoEntities(_)) => {
|
Err(QuerySingleError::NoEntities(_)) => {
|
||||||
warn!("No OxrTrackingRoot!");
|
warn!("No XrTrackingRoot!");
|
||||||
}
|
}
|
||||||
Err(QuerySingleError::MultipleEntities(_)) => {
|
Err(QuerySingleError::MultipleEntities(_)) => {
|
||||||
warn!("Multiple OxrTrackingRoots! this is not allowed");
|
warn!("Multiple XrTrackingRoots! this is not allowed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,8 +178,6 @@ pub fn init_views(
|
|||||||
pub fn wait_frame(mut frame_waiter: ResMut<OxrFrameWaiter>, mut commands: Commands) {
|
pub fn wait_frame(mut frame_waiter: ResMut<OxrFrameWaiter>, mut commands: Commands) {
|
||||||
let _span = info_span!("xr_wait_frame");
|
let _span = info_span!("xr_wait_frame");
|
||||||
let state = frame_waiter.wait().expect("Failed to wait frame");
|
let state = frame_waiter.wait().expect("Failed to wait frame");
|
||||||
// Here we insert the predicted display time for when this frame will be displayed.
|
|
||||||
// TODO: don't add predicted_display_period if pipelined rendering plugin not enabled
|
|
||||||
commands.insert_resource(OxrFrameState(state));
|
commands.insert_resource(OxrFrameState(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +263,7 @@ pub fn update_views(
|
|||||||
|
|
||||||
pub fn update_views_render_world(
|
pub fn update_views_render_world(
|
||||||
views: Res<OxrViews>,
|
views: Res<OxrViews>,
|
||||||
root: Res<OxrRootTransform>,
|
root: Res<XrRootTransform>,
|
||||||
mut query: Query<(&mut ExtractedView, &XrCamera)>,
|
mut query: Query<(&mut ExtractedView, &XrCamera)>,
|
||||||
) {
|
) {
|
||||||
for (mut extracted_view, camera) in query.iter_mut() {
|
for (mut extracted_view, camera) in query.iter_mut() {
|
||||||
@@ -504,7 +423,8 @@ pub fn add_texture_view(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin_frame(mut frame_stream: ResMut<OxrFrameStream>) {
|
pub fn begin_frame(mut frame_stream: ResMut<OxrFrameStream>) {
|
||||||
frame_stream.begin().expect("Failed to begin frame")
|
let _span = info_span!("xr_begin_frame");
|
||||||
|
frame_stream.begin().expect("Failed to begin frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release_image(mut swapchain: ResMut<OxrSwapchain>) {
|
pub fn release_image(mut swapchain: ResMut<OxrSwapchain>) {
|
||||||
@@ -537,12 +457,12 @@ pub fn end_frame(world: &mut World) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let layers: Vec<_> = layers.iter().map(Box::as_ref).collect();
|
let layers: Vec<_> = layers.iter().map(Box::as_ref).collect();
|
||||||
frame_stream
|
if let Err(e) = frame_stream.end(
|
||||||
.end(
|
|
||||||
frame_state.predicted_display_time,
|
frame_state.predicted_display_time,
|
||||||
world.resource::<OxrGraphicsInfo>().blend_mode,
|
world.resource::<OxrGraphicsInfo>().blend_mode,
|
||||||
&layers,
|
&layers,
|
||||||
)
|
) {
|
||||||
.expect("Failed to end frame");
|
error!("Failed to end frame stream: {e}");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::extract_resource::ExtractResource;
|
use bevy::render::extract_resource::ExtractResource;
|
||||||
|
|
||||||
@@ -357,14 +355,6 @@ pub struct OxrSessionStarted(pub bool);
|
|||||||
#[derive(Clone, Deref, DerefMut, Resource, ExtractResource)]
|
#[derive(Clone, Deref, DerefMut, Resource, ExtractResource)]
|
||||||
pub struct OxrFrameState(pub openxr::FrameState);
|
pub struct OxrFrameState(pub openxr::FrameState);
|
||||||
|
|
||||||
/// The root transform's global position for late latching in the render world.
|
|
||||||
#[derive(ExtractResource, Resource, Clone, Copy, Default)]
|
|
||||||
pub struct OxrRootTransform(pub GlobalTransform);
|
|
||||||
|
|
||||||
#[derive(ExtractResource, Resource, Clone, Copy, Default, Deref, DerefMut, PartialEq)]
|
|
||||||
/// This is inserted into the world to signify if the session should be cleaned up.
|
|
||||||
pub struct OxrCleanupSession(pub bool);
|
|
||||||
|
|
||||||
/// Instructs systems to add display period
|
/// Instructs systems to add display period
|
||||||
#[derive(Clone, Copy, Default, Resource)]
|
#[derive(Clone, Copy, Default, Resource)]
|
||||||
pub struct Pipelined;
|
pub struct Pipelined;
|
||||||
|
|||||||
@@ -1,101 +1,13 @@
|
|||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
|
||||||
use crate::init::{OxrHandleEvents, OxrLast};
|
|
||||||
use crate::next_chain::{OxrNextChain, OxrNextChainStructBase, OxrNextChainStructProvider};
|
use crate::next_chain::{OxrNextChain, OxrNextChainStructBase, OxrNextChainStructProvider};
|
||||||
use crate::resources::{
|
use crate::resources::{OxrPassthrough, OxrPassthroughLayer, OxrSwapchain};
|
||||||
OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSessionStarted, OxrSwapchain,
|
|
||||||
};
|
|
||||||
use crate::types::{Result, SwapchainCreateInfo};
|
use crate::types::{Result, SwapchainCreateInfo};
|
||||||
use bevy::app::AppExit;
|
|
||||||
use bevy::ecs::event::ManualEventReader;
|
|
||||||
use bevy::ecs::system::RunSystemOnce;
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::RenderApp;
|
|
||||||
use bevy_xr::session::{
|
|
||||||
session_running, status_changed_to, XrSessionCreated, XrSessionExiting, XrStatus,
|
|
||||||
};
|
|
||||||
use openxr::AnyGraphics;
|
use openxr::AnyGraphics;
|
||||||
|
|
||||||
use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap};
|
use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap};
|
||||||
|
|
||||||
#[derive(Event, Clone, Copy, PartialEq, Eq, Hash)]
|
|
||||||
pub enum OxrSessionStatusEvent {
|
|
||||||
Created,
|
|
||||||
AboutToBeDestroyed,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OxrSessionPlugin;
|
|
||||||
|
|
||||||
impl Plugin for OxrSessionPlugin {
|
|
||||||
fn build(&self, app: &mut App) {
|
|
||||||
app.init_non_send_resource::<OxrSessionCreateNextChain>();
|
|
||||||
app.add_event::<OxrSessionStatusEvent>();
|
|
||||||
app.add_systems(OxrLast, run_session_status_schedules.after(OxrHandleEvents));
|
|
||||||
app.add_systems(
|
|
||||||
OxrLast,
|
|
||||||
exits_session_on_app_exit
|
|
||||||
.before(OxrHandleEvents)
|
|
||||||
.run_if(on_event::<AppExit>().and_then(session_running)),
|
|
||||||
);
|
|
||||||
app.add_systems(XrSessionExiting, clean_session);
|
|
||||||
app.sub_app_mut(RenderApp)
|
|
||||||
.add_systems(XrSessionExiting, |mut cmds: Commands| {
|
|
||||||
cmds.remove_resource::<OxrCleanupSession>();
|
|
||||||
});
|
|
||||||
app.add_systems(
|
|
||||||
PreUpdate,
|
|
||||||
handle_stopping_state.run_if(status_changed_to(XrStatus::Stopping)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn exits_session_on_app_exit(session: Res<OxrSession>) {
|
|
||||||
session.request_exit().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_stopping_state(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
|
||||||
session.end().expect("Failed to end session");
|
|
||||||
session_started.0 = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clean_session(world: &mut World) {
|
|
||||||
world.insert_resource(OxrCleanupSession(true));
|
|
||||||
// It should be impossible to call this if the session is Unavailable
|
|
||||||
*world.get_resource_mut::<XrStatus>().unwrap() = XrStatus::Available;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
|
||||||
struct SessionStatusReader(ManualEventReader<OxrSessionStatusEvent>);
|
|
||||||
|
|
||||||
fn run_session_status_schedules(world: &mut World) {
|
|
||||||
let mut reader = world
|
|
||||||
.remove_resource::<SessionStatusReader>()
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let events = reader
|
|
||||||
.0
|
|
||||||
.read(
|
|
||||||
world
|
|
||||||
.get_resource::<Events<OxrSessionStatusEvent>>()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.copied()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for e in events.iter() {
|
|
||||||
match e {
|
|
||||||
OxrSessionStatusEvent::Created => {
|
|
||||||
world.run_schedule(XrSessionCreated);
|
|
||||||
world.run_system_once(apply_deferred);
|
|
||||||
}
|
|
||||||
OxrSessionStatusEvent::AboutToBeDestroyed => {
|
|
||||||
world.run_schedule(XrSessionExiting);
|
|
||||||
world.run_system_once(apply_deferred);
|
|
||||||
world.remove_resource::<OxrSession>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
world.insert_resource(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Graphics agnostic wrapper around [openxr::Session].
|
/// Graphics agnostic wrapper around [openxr::Session].
|
||||||
///
|
///
|
||||||
/// See [`openxr::Session`] for other available methods.
|
/// See [`openxr::Session`] for other available methods.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::{mem::MaybeUninit, ptr, sync::Mutex};
|
|||||||
|
|
||||||
use bevy::{prelude::*, utils::hashbrown::HashSet};
|
use bevy::{prelude::*, utils::hashbrown::HashSet};
|
||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
session::{session_available, session_running, XrSessionExiting},
|
session::{session_available, session_running, XrFirst, XrHandleEvents},
|
||||||
spaces::{XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrSpatialOffset},
|
spaces::{XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrSpatialOffset},
|
||||||
types::XrPose,
|
types::XrPose,
|
||||||
};
|
};
|
||||||
@@ -13,7 +13,6 @@ use openxr::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
helper_traits::{ToPosef, ToQuat, ToVec3},
|
helper_traits::{ToPosef, ToQuat, ToVec3},
|
||||||
init::{OxrHandleEvents, OxrLast},
|
|
||||||
resources::{OxrFrameState, OxrInstance, Pipelined},
|
resources::{OxrFrameState, OxrInstance, Pipelined},
|
||||||
session::OxrSession,
|
session::OxrSession,
|
||||||
};
|
};
|
||||||
@@ -21,7 +20,7 @@ use crate::{
|
|||||||
#[derive(SystemSet, Hash, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(SystemSet, Hash, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct OxrSpaceSyncSet;
|
pub struct OxrSpaceSyncSet;
|
||||||
|
|
||||||
/// VERY IMPORTENT!! only disable when you know what you are doing
|
/// VERY IMPORTANT!! only disable when you know what you are doing
|
||||||
pub struct OxrSpacePatchingPlugin;
|
pub struct OxrSpacePatchingPlugin;
|
||||||
impl Plugin for OxrSpacePatchingPlugin {
|
impl Plugin for OxrSpacePatchingPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
@@ -31,10 +30,9 @@ impl Plugin for OxrSpacePatchingPlugin {
|
|||||||
pub struct OxrSpatialPlugin;
|
pub struct OxrSpatialPlugin;
|
||||||
impl Plugin for OxrSpatialPlugin {
|
impl Plugin for OxrSpatialPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<XrDestroySpace>();
|
app.add_event::<XrDestroySpace>()
|
||||||
app.add_systems(OxrLast, destroy_space_event.before(OxrHandleEvents));
|
.add_systems(XrFirst, destroy_space_event.before(XrHandleEvents))
|
||||||
app.add_systems(XrSessionExiting, destroy_space_components);
|
.add_systems(
|
||||||
app.add_systems(
|
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
update_space_transforms
|
update_space_transforms
|
||||||
.in_set(OxrSpaceSyncSet)
|
.in_set(OxrSpaceSyncSet)
|
||||||
@@ -43,21 +41,6 @@ impl Plugin for OxrSpatialPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_space_components(
|
|
||||||
query: Query<(Entity, &XrSpace)>,
|
|
||||||
mut cmds: Commands,
|
|
||||||
mut sender: EventWriter<XrDestroySpace>,
|
|
||||||
) {
|
|
||||||
let mut to_destroy = HashSet::<XrSpace>::new();
|
|
||||||
for (e, space) in &query {
|
|
||||||
to_destroy.insert(*space);
|
|
||||||
cmds.entity(e).remove::<XrSpace>();
|
|
||||||
}
|
|
||||||
for space in to_destroy.into_iter() {
|
|
||||||
sender.send(XrDestroySpace(space));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_space_event(instance: Res<OxrInstance>, mut events: EventReader<XrDestroySpace>) {
|
fn destroy_space_event(instance: Res<OxrInstance>, mut events: EventReader<XrDestroySpace>) {
|
||||||
for space in events.read() {
|
for space in events.read() {
|
||||||
match instance.destroy_space(space.0) {
|
match instance.destroy_space(space.0) {
|
||||||
|
|||||||
@@ -1,147 +1,338 @@
|
|||||||
use bevy::{
|
use bevy::app::{AppExit, MainScheduleOrder};
|
||||||
ecs::schedule::ScheduleLabel, prelude::*, render::extract_resource::ExtractResource,
|
use bevy::ecs::schedule::ScheduleLabel;
|
||||||
render::RenderApp,
|
use bevy::prelude::*;
|
||||||
};
|
use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin};
|
||||||
|
use bevy::render::{Render, RenderApp, RenderSet};
|
||||||
|
|
||||||
pub struct XrSessionPlugin;
|
/// Event sent to instruct backends to create an XR session. Only works when the [`XrState`] is [`Available`](XrState::Available).
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct XrCreateSessionEvent;
|
||||||
|
|
||||||
|
/// A schedule thats ran whenever an [`XrCreateSessionEvent`] is recieved while the [`XrState`] is [`Available`](XrState::Available)
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
|
||||||
|
pub struct XrCreateSession;
|
||||||
|
|
||||||
|
/// Event sent when [`XrCreateSession`] is ran
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct XrSessionCreatedEvent;
|
||||||
|
|
||||||
|
/// Event sent to instruct backends to destroy an XR session. Only works when the [`XrState`] is [`Exiting`](XrState::Exiting).
|
||||||
|
/// If you would like to request that a running session be destroyed, send the [`XrRequestExitEvent`] instead.
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct XrDestroySessionEvent;
|
||||||
|
|
||||||
|
/// Resource flag thats inserted into the world and extracted to the render world to inform any session resources in the render world to drop.
|
||||||
|
#[derive(Resource, ExtractResource, Clone, Copy, Default)]
|
||||||
|
pub struct XrDestroySessionRender;
|
||||||
|
|
||||||
|
/// Schedule thats ran whenever an [`XrDestroySessionEvent`] is recieved while the [`XrState`] is [`Exiting`](XrState::Exiting).
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
|
||||||
|
pub struct XrDestroySession;
|
||||||
|
|
||||||
|
/// Event sent to instruct backends to begin an XR session. Only works when the [`XrState`] is [`Ready`](XrState::Ready).
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct XrBeginSessionEvent;
|
||||||
|
|
||||||
|
/// Schedule thats ran whenever an [`XrBeginSessionEvent`] is recieved while the [`XrState`] is [`Ready`](XrState::Ready).
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
|
||||||
|
pub struct XrBeginSession;
|
||||||
|
|
||||||
|
/// Event sent to backends to end an XR session. Only works when the [`XrState`] is [`Stopping`](XrState::Stopping).
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct XrEndSessionEvent;
|
||||||
|
|
||||||
|
/// Schedule thats rna whenever an [`XrEndSessionEvent`] is recieved while the [`XrState`] is [`Stopping`](XrState::Stopping).
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
|
||||||
|
pub struct XrEndSession;
|
||||||
|
|
||||||
|
/// Event sent to backends to request the [`XrState`] proceed to [`Exiting`](XrState::Exiting) and for the session to be exited. Can be called at any time a session exists.
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct XrRequestExitEvent;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
|
||||||
|
pub struct XrRequestExit;
|
||||||
|
|
||||||
|
/// Schedule ran before [`First`] to handle XR events.
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
|
||||||
|
pub struct XrFirst;
|
||||||
|
|
||||||
|
/// System set for systems related to handling XR session events and updating the [`XrState`]
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
||||||
|
pub struct XrHandleEvents;
|
||||||
|
|
||||||
|
/// System sets ran in the render world for XR.
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
||||||
|
pub enum XrRenderSet {
|
||||||
|
/// Ran before [`XrRenderSet::PreRender`] but after [`RenderSet::ExtractCommands`].
|
||||||
|
HandleEvents,
|
||||||
|
/// For any XR systems needing to be ran before rendering begins.
|
||||||
|
/// Ran after [`XrRenderSet::HandleEvents`] but before every render set except [`RenderSet::ExtractCommands`].
|
||||||
|
PreRender,
|
||||||
|
/// For any XR systems needing to be ran after [`RenderSet::Render`] but before [`RenderSet::Cleanup`].
|
||||||
|
PostRender,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The root transform's global position for late latching in the render world.
|
||||||
|
#[derive(ExtractResource, Resource, Clone, Copy, Default)]
|
||||||
|
pub struct XrRootTransform(pub GlobalTransform);
|
||||||
|
|
||||||
|
/// Component used to specify the entity we should use as the tracking root.
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct XrTrackingRoot;
|
||||||
|
|
||||||
|
pub struct XrSessionPlugin {
|
||||||
|
pub auto_handle: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Plugin for XrSessionPlugin {
|
impl Plugin for XrSessionPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<XrCreateSessionWhenAvailabe>();
|
let mut xr_first = Schedule::new(XrFirst);
|
||||||
app.init_schedule(XrSessionCreated);
|
xr_first.set_executor_kind(bevy::ecs::schedule::ExecutorKind::Simple);
|
||||||
app.init_schedule(XrSessionExiting);
|
app.add_event::<XrCreateSessionEvent>()
|
||||||
app.add_event::<CreateXrSession>()
|
.add_event::<XrDestroySessionEvent>()
|
||||||
.add_event::<DestroyXrSession>()
|
.add_event::<XrBeginSessionEvent>()
|
||||||
.add_event::<BeginXrSession>()
|
.add_event::<XrEndSessionEvent>()
|
||||||
.add_event::<EndXrSession>()
|
.add_event::<XrRequestExitEvent>()
|
||||||
.add_event::<XrStatusChanged>()
|
.add_event::<XrStateChanged>()
|
||||||
|
.add_event::<XrSessionCreatedEvent>()
|
||||||
|
.init_schedule(XrCreateSession)
|
||||||
|
.init_schedule(XrDestroySession)
|
||||||
|
.init_schedule(XrBeginSession)
|
||||||
|
.init_schedule(XrEndSession)
|
||||||
|
.init_schedule(XrRequestExit)
|
||||||
|
.add_schedule(xr_first)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
XrFirst,
|
||||||
handle_session.run_if(resource_exists::<XrStatus>),
|
(
|
||||||
|
exits_session_on_app_exit
|
||||||
|
.run_if(on_event::<AppExit>())
|
||||||
|
.run_if(session_created),
|
||||||
|
reset_per_frame_resources,
|
||||||
|
run_xr_create_session
|
||||||
|
.run_if(state_equals(XrState::Available))
|
||||||
|
.run_if(on_event::<XrCreateSessionEvent>()),
|
||||||
|
run_xr_destroy_session
|
||||||
|
.run_if(state_matches!(XrState::Exiting { .. }))
|
||||||
|
.run_if(on_event::<XrDestroySessionEvent>()),
|
||||||
|
run_xr_begin_session
|
||||||
|
.run_if(state_equals(XrState::Ready))
|
||||||
|
.run_if(on_event::<XrBeginSessionEvent>()),
|
||||||
|
run_xr_end_session
|
||||||
|
.run_if(state_equals(XrState::Stopping))
|
||||||
|
.run_if(on_event::<XrEndSessionEvent>()),
|
||||||
|
run_xr_request_exit
|
||||||
|
.run_if(session_created)
|
||||||
|
.run_if(on_event::<XrRequestExitEvent>()),
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.in_set(XrHandleEvents),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.world
|
||||||
|
.resource_mut::<MainScheduleOrder>()
|
||||||
|
.labels
|
||||||
|
.insert(0, XrFirst.intern());
|
||||||
|
|
||||||
|
if self.auto_handle {
|
||||||
|
app.add_systems(PreUpdate, auto_handle_session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(&self, app: &mut App) {
|
||||||
|
if app.get_sub_app(RenderApp).is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
app.add_plugins((
|
||||||
|
ExtractResourcePlugin::<XrState>::default(),
|
||||||
|
ExtractResourcePlugin::<XrDestroySessionRender>::default(),
|
||||||
|
ExtractResourcePlugin::<XrRootTransform>::default(),
|
||||||
|
))
|
||||||
|
.init_resource::<XrRootTransform>()
|
||||||
|
.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
update_root_transform.after(TransformSystem::TransformPropagate),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
XrFirst,
|
||||||
|
exits_session_on_app_exit
|
||||||
|
.before(XrHandleEvents)
|
||||||
|
.run_if(on_event::<AppExit>().and_then(session_running)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let render_app = app.sub_app_mut(RenderApp);
|
||||||
|
|
||||||
|
render_app
|
||||||
|
.init_schedule(XrDestroySession)
|
||||||
|
.init_resource::<XrRootTransform>()
|
||||||
|
.configure_sets(
|
||||||
|
Render,
|
||||||
|
(XrRenderSet::HandleEvents, XrRenderSet::PreRender).chain(),
|
||||||
|
)
|
||||||
|
.configure_sets(
|
||||||
|
Render,
|
||||||
|
XrRenderSet::HandleEvents.after(RenderSet::ExtractCommands),
|
||||||
|
)
|
||||||
|
.configure_sets(
|
||||||
|
Render,
|
||||||
|
XrRenderSet::PreRender
|
||||||
|
.before(RenderSet::ManageViews)
|
||||||
|
.before(RenderSet::PrepareAssets),
|
||||||
|
)
|
||||||
|
.configure_sets(
|
||||||
|
Render,
|
||||||
|
XrRenderSet::PostRender
|
||||||
|
.after(RenderSet::Render)
|
||||||
|
.before(RenderSet::Cleanup),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
(
|
||||||
|
run_xr_destroy_session
|
||||||
|
.run_if(resource_exists::<XrDestroySessionRender>)
|
||||||
|
.in_set(XrRenderSet::HandleEvents),
|
||||||
|
reset_per_frame_resources.in_set(RenderSet::Cleanup),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn finish(&self, app: &mut App) {
|
|
||||||
// This is in finnish because we need the RenderPlugin to already be added.
|
|
||||||
app.get_sub_app_mut(RenderApp)
|
|
||||||
.unwrap()
|
|
||||||
.init_schedule(XrSessionExiting);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Automatically starts session when it's available, gets set to false after the start event was
|
fn exits_session_on_app_exit(mut request_exit: EventWriter<XrRequestExitEvent>) {
|
||||||
/// sent
|
request_exit.send_default();
|
||||||
#[derive(Clone, Copy, Resource, Deref, DerefMut)]
|
|
||||||
pub struct XrCreateSessionWhenAvailabe(pub bool);
|
|
||||||
|
|
||||||
impl Default for XrCreateSessionWhenAvailabe {
|
|
||||||
fn default() -> Self {
|
|
||||||
XrCreateSessionWhenAvailabe(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
/// Event sent by backends whenever [`XrState`] is changed.
|
||||||
pub struct XrSessionCreated;
|
|
||||||
|
|
||||||
#[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
|
||||||
pub struct XrSessionExiting;
|
|
||||||
|
|
||||||
#[derive(Event, Clone, Copy, Deref)]
|
#[derive(Event, Clone, Copy, Deref)]
|
||||||
pub struct XrStatusChanged(pub XrStatus);
|
pub struct XrStateChanged(pub XrState);
|
||||||
|
|
||||||
|
/// A resource in the main world and render world representing the current session state.
|
||||||
#[derive(Clone, Copy, Debug, ExtractResource, Resource, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, ExtractResource, Resource, PartialEq, Eq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum XrStatus {
|
pub enum XrState {
|
||||||
/// An XR session is not available here
|
/// An XR session is not available here
|
||||||
Unavailable,
|
Unavailable,
|
||||||
/// An XR session is available and ready to be created with a [`CreateXrSession`] event.
|
/// An XR session is available and ready to be created with an [`XrCreateSessionEvent`].
|
||||||
Available,
|
Available,
|
||||||
/// An XR session is created but not ready to begin.
|
/// An XR session is created but not ready to begin. Backends are not required to use this state.
|
||||||
Idle,
|
Idle,
|
||||||
/// An XR session has been created and is ready to start rendering with a [`BeginXrSession`] event, or
|
/// An XR session has been created and is ready to start rendering with an [`XrBeginSessionEvent`].
|
||||||
Ready,
|
Ready,
|
||||||
/// The XR session is running and can be stopped with an [`EndXrSession`] event.
|
/// The XR session is running and can be stopped with an [`XrEndSessionEvent`].
|
||||||
Running,
|
Running,
|
||||||
/// The XR session is in the process of being stopped.
|
/// The runtime has requested that the session should be ended with an [`XrEndSessionEvent`].
|
||||||
Stopping,
|
Stopping,
|
||||||
/// The XR session is in the process of being destroyed
|
/// The XR session should be destroyed with an [`XrDestroySessionEvent`].
|
||||||
Exiting,
|
Exiting {
|
||||||
|
/// Whether we should automatically restart the session
|
||||||
|
should_restart: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_session(
|
pub fn run_xr_create_session(world: &mut World) {
|
||||||
current_status: Res<XrStatus>,
|
world.run_schedule(XrCreateSession);
|
||||||
mut previous_status: Local<Option<XrStatus>>,
|
world.send_event(XrSessionCreatedEvent);
|
||||||
mut create_session: EventWriter<CreateXrSession>,
|
}
|
||||||
mut begin_session: EventWriter<BeginXrSession>,
|
|
||||||
// mut end_session: EventWriter<EndXrSession>,
|
pub fn run_xr_destroy_session(world: &mut World) {
|
||||||
mut destroy_session: EventWriter<DestroyXrSession>,
|
world.run_schedule(XrDestroySession);
|
||||||
mut should_start_session: ResMut<XrCreateSessionWhenAvailabe>,
|
world.insert_resource(XrDestroySessionRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_xr_begin_session(world: &mut World) {
|
||||||
|
world.run_schedule(XrBeginSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_xr_end_session(world: &mut World) {
|
||||||
|
world.run_schedule(XrEndSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_xr_request_exit(world: &mut World) {
|
||||||
|
world.run_schedule(XrRequestExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_per_frame_resources(world: &mut World) {
|
||||||
|
world.remove_resource::<XrDestroySessionRender>();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn auto_handle_session(
|
||||||
|
mut state_changed: EventReader<XrStateChanged>,
|
||||||
|
mut create_session: EventWriter<XrCreateSessionEvent>,
|
||||||
|
mut begin_session: EventWriter<XrBeginSessionEvent>,
|
||||||
|
mut end_session: EventWriter<XrEndSessionEvent>,
|
||||||
|
mut destroy_session: EventWriter<XrDestroySessionEvent>,
|
||||||
) {
|
) {
|
||||||
if *previous_status != Some(*current_status) {
|
for XrStateChanged(state) in state_changed.read() {
|
||||||
match *current_status {
|
match state {
|
||||||
XrStatus::Unavailable => {}
|
XrState::Available => {
|
||||||
XrStatus::Available => {
|
|
||||||
if **should_start_session {
|
|
||||||
create_session.send_default();
|
create_session.send_default();
|
||||||
**should_start_session = false;
|
|
||||||
}
|
}
|
||||||
}
|
XrState::Ready => {
|
||||||
XrStatus::Idle => {}
|
|
||||||
XrStatus::Ready => {
|
|
||||||
begin_session.send_default();
|
begin_session.send_default();
|
||||||
}
|
}
|
||||||
XrStatus::Running => {}
|
XrState::Stopping => {
|
||||||
XrStatus::Stopping => {
|
end_session.send_default();
|
||||||
// end_session.send_default();
|
|
||||||
}
|
}
|
||||||
XrStatus::Exiting => {
|
XrState::Exiting { .. } => {
|
||||||
destroy_session.send_default();
|
destroy_session.send_default();
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*previous_status = Some(*current_status);
|
}
|
||||||
|
|
||||||
|
pub fn update_root_transform(
|
||||||
|
mut root_transform: ResMut<XrRootTransform>,
|
||||||
|
root: Query<&GlobalTransform, With<XrTrackingRoot>>,
|
||||||
|
) {
|
||||||
|
let Ok(transform) = root.get_single() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
root_transform.0 = *transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](bevy::ecs::schedule::Condition) that allows the system to run when the xr status changed to a specific [`XrStatus`].
|
/// A [`Condition`](bevy::ecs::schedule::Condition) that allows the system to run when the xr status changed to a specific [`XrStatus`].
|
||||||
pub fn status_changed_to(
|
pub fn status_changed_to(
|
||||||
status: XrStatus,
|
status: XrState,
|
||||||
) -> impl FnMut(EventReader<XrStatusChanged>) -> bool + Clone {
|
) -> impl FnMut(EventReader<XrStateChanged>) -> bool + Clone {
|
||||||
move |mut reader: EventReader<XrStatusChanged>| {
|
move |mut reader: EventReader<XrStateChanged>| {
|
||||||
reader.read().any(|new_status| new_status.0 == status)
|
reader.read().any(|new_status| new_status.0 == status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](bevy::ecs::schedule::Condition) system that says if the XR session is available. Returns true as long as [`XrStatus`] exists and isn't [`Unavailable`](XrStatus::Unavailable).
|
/// A [`Condition`](bevy::ecs::schedule::Condition) system that says if the XR session is available. Returns true as long as [`XrState`] exists and isn't [`Unavailable`](XrStatus::Unavailable).
|
||||||
pub fn session_available(status: Option<Res<XrStatus>>) -> bool {
|
pub fn session_available(status: Option<Res<XrState>>) -> bool {
|
||||||
status.is_some_and(|s| *s != XrStatus::Unavailable)
|
status.is_some_and(|s| *s != XrState::Unavailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_created(status: Option<Res<XrState>>) -> bool {
|
||||||
|
!matches!(
|
||||||
|
status.as_deref(),
|
||||||
|
Some(XrState::Unavailable | XrState::Available) | None
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](bevy::ecs::schedule::Condition) system that says if the XR session is ready or running
|
/// A [`Condition`](bevy::ecs::schedule::Condition) system that says if the XR session is ready or running
|
||||||
pub fn session_ready_or_running(status: Option<Res<XrStatus>>) -> bool {
|
pub fn session_ready_or_running(status: Option<Res<XrState>>) -> bool {
|
||||||
matches!(status.as_deref(), Some(XrStatus::Ready | XrStatus::Running))
|
matches!(status.as_deref(), Some(XrState::Ready | XrState::Running))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](bevy::ecs::schedule::Condition) system that says if the XR session is running
|
/// A [`Condition`](bevy::ecs::schedule::Condition) system that says if the XR session is running
|
||||||
pub fn session_running(status: Option<Res<XrStatus>>) -> bool {
|
pub fn session_running(status: Option<Res<XrState>>) -> bool {
|
||||||
matches!(status.as_deref(), Some(XrStatus::Running))
|
matches!(status.as_deref(), Some(XrState::Running))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A function that returns a [`Condition`](bevy::ecs::schedule::Condition) system that says if an the [`XrStatus`] is in a specific state
|
/// A function that returns a [`Condition`](bevy::ecs::schedule::Condition) system that says if the [`XrState`] is in a specific state
|
||||||
pub fn status_equals(status: XrStatus) -> impl FnMut(Option<Res<XrStatus>>) -> bool {
|
pub fn state_equals(status: XrState) -> impl FnMut(Option<Res<XrState>>) -> bool {
|
||||||
move |state: Option<Res<XrStatus>>| state.is_some_and(|s| *s == status)
|
move |state: Option<Res<XrState>>| state.is_some_and(|s| *s == status)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event sent to backends to create an XR session. Should only be called in the [`XrStatus::Available`] state.
|
#[macro_export]
|
||||||
#[derive(Event, Clone, Copy, Default)]
|
macro_rules! state_matches {
|
||||||
pub struct CreateXrSession;
|
($match:pat) => {
|
||||||
|
(|state: Option<Res<XrState>>| core::matches!(state.as_deref(), Some($match)))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Event sent to the backends to destroy an XR session.
|
use bevy::transform::TransformSystem;
|
||||||
#[derive(Event, Clone, Copy, Default)]
|
pub use state_matches;
|
||||||
pub struct DestroyXrSession;
|
|
||||||
|
|
||||||
/// Event sent to backends to begin an XR session. Should only be called in the [`XrStatus::Ready`] state.
|
|
||||||
#[derive(Event, Clone, Copy, Default)]
|
|
||||||
pub struct BeginXrSession;
|
|
||||||
|
|
||||||
/// Event sent to backends to end an XR session. Should only be called in the [`XrStatus::Running`] state.
|
|
||||||
#[derive(Event, Clone, Copy, Default)]
|
|
||||||
pub struct EndXrSession;
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_openxr::{
|
use bevy_openxr::{
|
||||||
helper_traits::{ToQuat, ToVec3},
|
helper_traits::{ToQuat, ToVec3},
|
||||||
init::OxrTrackingRoot,
|
|
||||||
resources::OxrViews,
|
resources::OxrViews,
|
||||||
};
|
};
|
||||||
|
use bevy_xr::session::XrTrackingRoot;
|
||||||
|
|
||||||
pub struct TransformUtilitiesPlugin;
|
pub struct TransformUtilitiesPlugin;
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ pub struct SnapToRotation(pub Quat);
|
|||||||
pub struct SnapToPosition(pub Vec3);
|
pub struct SnapToPosition(pub Vec3);
|
||||||
|
|
||||||
pub fn handle_transform_events(
|
pub fn handle_transform_events(
|
||||||
mut root_query: Query<&mut Transform, With<OxrTrackingRoot>>,
|
mut root_query: Query<&mut Transform, With<XrTrackingRoot>>,
|
||||||
views: ResMut<OxrViews>,
|
views: ResMut<OxrViews>,
|
||||||
mut position_reader: EventReader<SnapToPosition>,
|
mut position_reader: EventReader<SnapToPosition>,
|
||||||
mut rotation_reader: EventReader<SnapToRotation>,
|
mut rotation_reader: EventReader<SnapToRotation>,
|
||||||
@@ -41,16 +40,19 @@ pub fn handle_transform_events(
|
|||||||
|
|
||||||
//position
|
//position
|
||||||
for position in position_reader.read() {
|
for position in position_reader.read() {
|
||||||
root_transform.translation = position.0 - root_transform.rotation.mul_vec3(view_translation);
|
root_transform.translation =
|
||||||
|
position.0 - root_transform.rotation.mul_vec3(view_translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
//rotation
|
//rotation
|
||||||
let root_local = root_transform.translation.clone();
|
let root_local = root_transform.translation.clone();
|
||||||
let hmd_global = root_transform.rotation.mul_vec3(view_translation) + root_local;
|
let hmd_global =
|
||||||
|
root_transform.rotation.mul_vec3(view_translation) + root_local;
|
||||||
let view_rot = view.pose.orientation.to_quat();
|
let view_rot = view.pose.orientation.to_quat();
|
||||||
let root_rot = root_transform.rotation;
|
let root_rot = root_transform.rotation;
|
||||||
let view_global_rotation = root_rot.mul_quat(view_rot).normalize();
|
let view_global_rotation = root_rot.mul_quat(view_rot).normalize();
|
||||||
let (global_view_yaw, _pitch, _roll) = view_global_rotation.to_euler(bevy::math::EulerRot::YXZ);
|
let (global_view_yaw, _pitch, _roll) =
|
||||||
|
view_global_rotation.to_euler(bevy::math::EulerRot::YXZ);
|
||||||
let up = Vec3::Y;
|
let up = Vec3::Y;
|
||||||
for rotation in rotation_reader.read() {
|
for rotation in rotation_reader.read() {
|
||||||
let (target_yaw, _pitch, _roll) =
|
let (target_yaw, _pitch, _roll) =
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ use bevy_openxr::{
|
|||||||
resources::OxrInstance, session::OxrSession,
|
resources::OxrInstance, session::OxrSession,
|
||||||
};
|
};
|
||||||
use bevy_xr::session::{session_available, session_running};
|
use bevy_xr::session::{session_available, session_running};
|
||||||
use openxr::{ActiveActionSet, Path, Vector2f};
|
use openxr::{Path, Vector2f};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
@@ -77,7 +77,6 @@ impl Plugin for XRUtilsActionsPlugin {
|
|||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
|
|
||||||
create_openxr_events
|
create_openxr_events
|
||||||
.in_set(XRUtilsActionSystemSet::CreateEvents)
|
.in_set(XRUtilsActionSystemSet::CreateEvents)
|
||||||
.run_if(session_available),
|
.run_if(session_available),
|
||||||
|
|||||||
Reference in New Issue
Block a user