Merge pull request #162 from Schmarni-Dev/modular_poll_events
Modular OpenXR events
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use openxr::sys;
|
use openxr::{sys, Event};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
next_chain::{OxrNextChainStructBase, OxrNextChainStructProvider},
|
next_chain::{OxrNextChainStructBase, OxrNextChainStructProvider},
|
||||||
openxr::exts::OxrEnabledExtensions,
|
openxr::exts::OxrEnabledExtensions,
|
||||||
openxr_session_available,
|
openxr_session_available,
|
||||||
|
poll_events::{OxrEvent, OxrEventHandlerExt},
|
||||||
session::{OxrSessionCreateNextChain, OxrSessionCreateNextProvider},
|
session::{OxrSessionCreateNextChain, OxrSessionCreateNextProvider},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,6 +21,17 @@ impl Plugin for OxrOverlayPlugin {
|
|||||||
First,
|
First,
|
||||||
add_overlay_info_to_chain.run_if(openxr_session_available),
|
add_overlay_info_to_chain.run_if(openxr_session_available),
|
||||||
);
|
);
|
||||||
|
app.add_oxr_event_handler(handle_overlay_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_overlay_event(event: In<OxrEvent>, mut writer: EventWriter<OxrOverlaySessionEvent>) {
|
||||||
|
// this unwrap will never panic since we are in a valid scope
|
||||||
|
if let Event::MainSessionVisibilityChangedEXTX(event) = unsafe { event.get() }.unwrap() {
|
||||||
|
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
|
||||||
|
visible: event.visible(),
|
||||||
|
flags: event.flags(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ use bevy_mod_xr::session::*;
|
|||||||
use openxr::Event;
|
use openxr::Event;
|
||||||
|
|
||||||
use crate::error::OxrError;
|
use crate::error::OxrError;
|
||||||
use crate::features::overlay::OxrOverlaySessionEvent;
|
|
||||||
use crate::graphics::*;
|
use crate::graphics::*;
|
||||||
use crate::resources::*;
|
use crate::resources::*;
|
||||||
use crate::session::OxrSession;
|
use crate::session::OxrSession;
|
||||||
@@ -28,6 +27,8 @@ use crate::session::OxrSessionCreateNextChain;
|
|||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use super::exts::OxrEnabledExtensions;
|
use super::exts::OxrEnabledExtensions;
|
||||||
|
use super::poll_events::OxrEvent;
|
||||||
|
use super::poll_events::OxrEventHandlerExt;
|
||||||
|
|
||||||
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)
|
||||||
@@ -106,12 +107,7 @@ impl Plugin for OxrInitPlugin {
|
|||||||
},
|
},
|
||||||
ExtractResourcePlugin::<OxrSessionStarted>::default(),
|
ExtractResourcePlugin::<OxrSessionStarted>::default(),
|
||||||
))
|
))
|
||||||
.add_systems(
|
.add_oxr_event_handler(handle_events)
|
||||||
XrFirst,
|
|
||||||
poll_events
|
|
||||||
.in_set(XrHandleEvents::Poll)
|
|
||||||
.run_if(not(state_equals(XrState::Unavailable))),
|
|
||||||
)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
XrFirst,
|
XrFirst,
|
||||||
(
|
(
|
||||||
@@ -282,22 +278,15 @@ impl OxrInitPlugin {
|
|||||||
#[derive(Event, Clone, Copy, Debug, Default)]
|
#[derive(Event, Clone, Copy, Debug, Default)]
|
||||||
pub struct OxrInteractionProfileChanged;
|
pub struct OxrInteractionProfileChanged;
|
||||||
|
|
||||||
/// Polls any OpenXR events and handles them accordingly
|
pub fn handle_events(
|
||||||
pub fn poll_events(
|
event: In<OxrEvent>,
|
||||||
instance: Res<OxrInstance>,
|
|
||||||
mut status: ResMut<XrState>,
|
mut status: ResMut<XrState>,
|
||||||
mut changed_event: EventWriter<XrStateChanged>,
|
mut changed_event: EventWriter<XrStateChanged>,
|
||||||
mut interaction_profile_changed_event: EventWriter<OxrInteractionProfileChanged>,
|
mut interaction_profile_changed_event: EventWriter<OxrInteractionProfileChanged>,
|
||||||
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::*;
|
use openxr::Event::*;
|
||||||
match event {
|
// this unwrap will never panic since we are in a valid scope
|
||||||
|
match unsafe { event.get() }.unwrap() {
|
||||||
SessionStateChanged(state) => {
|
SessionStateChanged(state) => {
|
||||||
use openxr::SessionState;
|
use openxr::SessionState;
|
||||||
|
|
||||||
@@ -325,16 +314,6 @@ pub fn poll_events(
|
|||||||
}
|
}
|
||||||
InstanceLossPending(_) => {}
|
InstanceLossPending(_) => {}
|
||||||
EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()),
|
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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// we might want to check if this is the correct session?
|
// we might want to check if this is the correct session?
|
||||||
Event::InteractionProfileChanged(_) => {
|
Event::InteractionProfileChanged(_) => {
|
||||||
interaction_profile_changed_event.send_default();
|
interaction_profile_changed_event.send_default();
|
||||||
@@ -342,7 +321,6 @@ pub fn poll_events(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn init_xr_session(
|
fn init_xr_session(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use bevy::{
|
|||||||
use bevy_mod_xr::session::XrSessionPlugin;
|
use bevy_mod_xr::session::XrSessionPlugin;
|
||||||
use bevy_mod_xr::{camera::XrCameraPlugin, session::XrState};
|
use bevy_mod_xr::{camera::XrCameraPlugin, session::XrState};
|
||||||
use init::OxrInitPlugin;
|
use init::OxrInitPlugin;
|
||||||
|
use poll_events::OxrEventsPlugin;
|
||||||
use render::OxrRenderPlugin;
|
use render::OxrRenderPlugin;
|
||||||
use resources::OxrInstance;
|
use resources::OxrInstance;
|
||||||
use session::OxrSession;
|
use session::OxrSession;
|
||||||
@@ -29,6 +30,7 @@ pub mod helper_traits;
|
|||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod layer_builder;
|
pub mod layer_builder;
|
||||||
pub mod next_chain;
|
pub mod next_chain;
|
||||||
|
pub mod poll_events;
|
||||||
pub mod reference_space;
|
pub mod reference_space;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
@@ -60,6 +62,7 @@ pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
|
|||||||
// .disable::<PipelinedRenderingPlugin>()
|
// .disable::<PipelinedRenderingPlugin>()
|
||||||
.add_before::<RenderPlugin, _>(XrSessionPlugin { auto_handle: true })
|
.add_before::<RenderPlugin, _>(XrSessionPlugin { auto_handle: true })
|
||||||
.add_before::<RenderPlugin, _>(OxrInitPlugin::default())
|
.add_before::<RenderPlugin, _>(OxrInitPlugin::default())
|
||||||
|
.add(OxrEventsPlugin)
|
||||||
.add(OxrReferenceSpacePlugin::default())
|
.add(OxrReferenceSpacePlugin::default())
|
||||||
.add(OxrRenderPlugin)
|
.add(OxrRenderPlugin)
|
||||||
.add(OxrPassthroughPlugin)
|
.add(OxrPassthroughPlugin)
|
||||||
|
|||||||
88
crates/bevy_openxr/src/openxr/poll_events.rs
Normal file
88
crates/bevy_openxr/src/openxr/poll_events.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use std::{cell::RefCell, mem, ops::Deref, rc::Rc};
|
||||||
|
|
||||||
|
use bevy::{ecs::system::SystemId, prelude::*};
|
||||||
|
use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
|
||||||
|
use openxr::{Event, EventDataBuffer};
|
||||||
|
|
||||||
|
pub struct OxrEventsPlugin;
|
||||||
|
|
||||||
|
impl Plugin for OxrEventsPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<OxrEventHandlers>();
|
||||||
|
app.add_systems(
|
||||||
|
XrFirst,
|
||||||
|
poll_events
|
||||||
|
.in_set(XrHandleEvents::Poll)
|
||||||
|
.run_if(openxr_session_available),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Polls any OpenXR events and handles them accordingly
|
||||||
|
pub fn poll_events(world: &mut World) {
|
||||||
|
let _span = info_span!("xr_poll_events");
|
||||||
|
let instance = world.resource::<OxrInstance>().clone();
|
||||||
|
let handlers = world.remove_resource::<OxrEventHandlers>().unwrap();
|
||||||
|
let mut buffer = EventDataBuffer::default();
|
||||||
|
while let Some(event) = instance
|
||||||
|
.poll_event(&mut buffer)
|
||||||
|
.expect("Failed to poll event")
|
||||||
|
{
|
||||||
|
let event = Rc::new(RefCell::new(Some(event)));
|
||||||
|
for handler in handlers.handlers.iter() {
|
||||||
|
if let Err(err) =
|
||||||
|
world.run_system_with_input::<_, ()>(*handler, OxrEvent::new(event.clone()))
|
||||||
|
{
|
||||||
|
error!("error when running oxr event handler: {err}");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
event.deref().take();
|
||||||
|
}
|
||||||
|
world.insert_resource(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::{openxr_session_available, resources::OxrInstance};
|
||||||
|
#[derive(Resource, Debug, Default)]
|
||||||
|
pub struct OxrEventHandlers {
|
||||||
|
pub handlers: Vec<OxrEventHandler>,
|
||||||
|
}
|
||||||
|
pub type OxrEventHandler = SystemId<OxrEvent, ()>;
|
||||||
|
|
||||||
|
pub struct OxrEvent {
|
||||||
|
event: Rc<RefCell<Option<Event<'static>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OxrEvent {
|
||||||
|
pub(crate) fn new<'a>(event: Rc<RefCell<Option<Event<'a>>>>) -> Self {
|
||||||
|
Self {
|
||||||
|
event: unsafe { mem::transmute(event) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// always returns [Some] if called in a valid scope
|
||||||
|
/// # Safety
|
||||||
|
/// The event is only valid for the duration of the poll event callback,
|
||||||
|
/// don't Store the [Event] anywhere!!
|
||||||
|
#[allow(clippy::needless_lifetimes)]
|
||||||
|
pub unsafe fn get<'a>(&'a self) -> Option<Event<'a>> {
|
||||||
|
self.event.borrow().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait OxrEventHandlerExt {
|
||||||
|
fn add_oxr_event_handler<M>(
|
||||||
|
&mut self,
|
||||||
|
system: impl IntoSystem<OxrEvent, (), M> + 'static,
|
||||||
|
) -> &mut Self;
|
||||||
|
}
|
||||||
|
impl OxrEventHandlerExt for App {
|
||||||
|
fn add_oxr_event_handler<M>(
|
||||||
|
&mut self,
|
||||||
|
system: impl IntoSystem<OxrEvent, (), M> + 'static,
|
||||||
|
) -> &mut Self {
|
||||||
|
self.init_resource::<OxrEventHandlers>();
|
||||||
|
let id = self.register_system(system);
|
||||||
|
self.world_mut()
|
||||||
|
.resource_mut::<OxrEventHandlers>()
|
||||||
|
.handlers
|
||||||
|
.push(id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user