From aa0eaa60f496a423f40c9fee04308a805bcd4d2d Mon Sep 17 00:00:00 2001 From: Schmarni Date: Mon, 29 Apr 2024 03:02:00 +0200 Subject: [PATCH] add missing files Signed-off-by: Schmarni --- .../bevy_openxr/src/openxr/action_binding.rs | 102 ++++++++++++++++++ .../src/openxr/action_set_attaching.rs | 36 +++++++ 2 files changed, 138 insertions(+) create mode 100644 crates/bevy_openxr/src/openxr/action_binding.rs create mode 100644 crates/bevy_openxr/src/openxr/action_set_attaching.rs diff --git a/crates/bevy_openxr/src/openxr/action_binding.rs b/crates/bevy_openxr/src/openxr/action_binding.rs new file mode 100644 index 0000000..fc4b585 --- /dev/null +++ b/crates/bevy_openxr/src/openxr/action_binding.rs @@ -0,0 +1,102 @@ +use std::borrow::Cow; +use std::ptr; + +use bevy::ecs::schedule::ScheduleLabel; +use bevy::ecs::system::RunSystemOnce; +use bevy::prelude::*; +use bevy::utils::HashMap; +use bevy_xr::session::{status_changed_to, XrStatus}; +use openxr::sys::ActionSuggestedBinding; + +use crate::resources::OxrInstance; + +impl Plugin for OxrActionBindingPlugin { + fn build(&self, app: &mut App) { + app.add_schedule(Schedule::new(OxrSendActionBindings)); + app.add_systems( + Update, + run_action_binding_sugestion + .run_if(run_once().and_then(status_changed_to(XrStatus::Ready))), + ); + } +} + +// This could for now be handled better with a SystemSet, but in the future we might want to add an +// Event to allow requesting binding suggestion for new actions +fn run_action_binding_sugestion(world: &mut World) { + world.run_schedule(OxrSendActionBindings); + world.run_system_once(bind_actions); +} + +fn bind_actions(instance: Res, mut actions: EventReader) { + let mut bindings: HashMap<&str, Vec> = HashMap::new(); + for e in actions.read() { + bindings.entry(&e.interaction_profile).or_default().extend( + e.bindings + .clone() + .into_iter() + .filter_map(|b| match instance.string_to_path(&b) { + Ok(p) => Some(p), + Err(err) => { + error!( + "Unable to convert path: \"{}\"; error: {}", + b, + err.to_string() + ); + None + } + }) + .map(|p| ActionSuggestedBinding { + action: e.action, + binding: p, + }) + .collect::>(), + ); + } + use openxr::sys; + for (profile, bindings) in bindings.iter() { + let interaction_profile = match instance.string_to_path(profile) { + Ok(v) => v, + Err(err) => { + error!( + "Unable to convert interaction profile path: \"{}\"; error: \"{}\" Skipping all suggestions for this interaction profile", + profile, + err.to_string() + ); + continue; + } + }; + // Using the raw way since we want all actions through one event and we can't use the + // Bindings from the openxr crate since they can't be created from raw actions + let info = sys::InteractionProfileSuggestedBinding { + ty: sys::InteractionProfileSuggestedBinding::TYPE, + next: ptr::null(), + interaction_profile, + count_suggested_bindings: bindings.len() as u32, + suggested_bindings: bindings.as_ptr() as *const _ as _, + }; + match unsafe { + (instance.fp().suggest_interaction_profile_bindings)(instance.as_raw(), &info) + } { + openxr::sys::Result::ERROR_ACTIONSETS_ALREADY_ATTACHED => error!( + "Binding Suggested for an Action whith an ActionSet that was already attached!" + ), + openxr::sys::Result::ERROR_PATH_INVALID => error!("Invalid Path Suggested!"), + openxr::sys::Result::ERROR_PATH_UNSUPPORTED => error!("Suggested Path Unsupported!"), + _ => {} + } + } +} + +#[derive(Event, Clone)] +/// Only Send this for Actions that were not attached yet! +pub struct OxrSuggestActionBinding { + pub action: openxr::sys::Action, + pub interaction_profile: Cow<'static, str>, + pub bindings: Vec>, +} + +pub struct OxrActionBindingPlugin; +// Maybe use a SystemSet in an XrStartup Schedule? +#[derive(ScheduleLabel, Hash, Debug, Clone, Copy, PartialEq, Eq)] +pub struct OxrSendActionBindings; diff --git a/crates/bevy_openxr/src/openxr/action_set_attaching.rs b/crates/bevy_openxr/src/openxr/action_set_attaching.rs new file mode 100644 index 0000000..fa139b0 --- /dev/null +++ b/crates/bevy_openxr/src/openxr/action_set_attaching.rs @@ -0,0 +1,36 @@ +use crate::resources::OxrSession; +use bevy::prelude::*; +use bevy_xr::session::status_changed_to; + +impl Plugin for OxrActionAttachingPlugin { + fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( + PostUpdate, + attach_sets.run_if(status_changed_to(bevy_xr::session::XrStatus::Ready)), + ); + } +} + +fn attach_sets(session: Res, mut events: EventReader) { + let sets = events.read().map(|v| &v.0).collect::>(); + match session.attach_action_sets(&sets) { + Ok(_) => {} + Err(openxr::sys::Result::ERROR_ACTIONSETS_ALREADY_ATTACHED) => { + error!("Action Sets Already attached!"); + } + + Err(openxr::sys::Result::ERROR_HANDLE_INVALID) => error!("Invalid ActionSet Handle!"), + Err(e) => error!( + "Unhandled Error while attaching action sets: {}", + e.to_string() + ), + }; +} + +#[derive(Event, Clone)] +/// Send this event for every ActionSet you want to attach to the [`OxrSession`] once the Session Status changed to Ready. all requests will +/// be applied in [`PostUpdate`] +pub struct OxrAttachActionSet(pub openxr::ActionSet); + +pub struct OxrActionAttachingPlugin;