diff --git a/xr_api/src/api_traits.rs b/xr_api/src/api_traits.rs index 80695f1..d85acb5 100644 --- a/xr_api/src/api_traits.rs +++ b/xr_api/src/api_traits.rs @@ -3,7 +3,7 @@ use wgpu::{Adapter, AdapterInfo, Device, Queue, TextureView}; use crate::prelude::*; -use self::path::{InputComponent, UntypedActionPath}; +use crate::path::{InputComponent, UntypedActionPath}; pub trait EntryTrait { /// Return currently available extensions @@ -54,15 +54,15 @@ pub trait ViewTrait { pub trait InputTrait { /// Get the haptic action at the specified path. - fn create_action_haptics(&self, name: &str, path: UntypedActionPath) -> Result>; + fn create_action_haptics(&self, path: UntypedActionPath) -> Result>; /// Get the pose action at the specified path. - fn create_action_pose(&self, name: &str, path: UntypedActionPath) -> Result>; + fn create_action_pose(&self, path: UntypedActionPath) -> Result>; /// Get the float action at the specified path. - fn create_action_float(&self, name: &str, path: UntypedActionPath) -> Result>; + fn create_action_float(&self, path: UntypedActionPath) -> Result>; /// Get the boolean action at the specified path. - fn create_action_bool(&self, name: &str, path: UntypedActionPath) -> Result>; + fn create_action_bool(&self, path: UntypedActionPath) -> Result>; /// Get the Vec2 action at the specified path. - fn create_action_vec2(&self, name: &str, path: UntypedActionPath) -> Result>; + fn create_action_vec2(&self, path: UntypedActionPath) -> Result>; } // This impl is moved outside of the trait to ensure that InputTrait stays object safe. @@ -70,10 +70,9 @@ impl dyn InputTrait { /// Get the action at the specified path. pub fn create_action( &self, - name: &str, path: ActionPath

, ) -> Result> { - P::PathType::get(self, name, path.untyped()) + P::PathType::get(self, path.untyped()) } } diff --git a/xr_api/src/backend/oxr.rs b/xr_api/src/backend/oxr.rs index 5bc8361..bd7ce7e 100644 --- a/xr_api/src/backend/oxr.rs +++ b/xr_api/src/backend/oxr.rs @@ -8,7 +8,7 @@ use hashbrown::{hash_map, HashMap}; use openxr::{EnvironmentBlendMode, Vector2f}; use tracing::{info, info_span, warn}; -use crate::{backend::oxr::graphics::VIEW_TYPE, prelude::*}; +use crate::{backend::oxr::graphics::VIEW_TYPE, path, prelude::*}; pub struct OXrEntry(openxr::Entry); @@ -155,10 +155,49 @@ impl SessionTrait for OXrSession { { let mut bindings = self.bindings.lock().unwrap(); if !bindings.sessions_attached { - let _span = info_span!("xr_attach_actions"); - let action_sets = self.action_sets.lock().unwrap(); - self.session - .attach_action_sets(&action_sets.iter().collect::>())?; + if let Some(interaction_profile) = bindings.bindings { + let _span = info_span!("xr_attach_actions"); + let controller_bindings: Vec = bindings + .map + .iter() + .filter_map(|(path, action)| { + let path = match self.inner_instance.string_to_path(path) { + Ok(path) => path, + Err(e) => { + warn!("{e}"); + return None; + } + }; + Some(match action { + UntypedOXrAction::Haptics(action) => { + openxr::Binding::new(action, path) + } + UntypedOXrAction::Pose(action) => { + openxr::Binding::new(action, path) + } + UntypedOXrAction::Float(action) => { + openxr::Binding::new(action, path) + } + UntypedOXrAction::Bool(action) => { + openxr::Binding::new(action, path) + } + UntypedOXrAction::Vec2(action) => { + openxr::Binding::new(action, path) + } + }) + }) + .collect(); + self.inner_instance.suggest_interaction_profile_bindings( + self.inner_instance + .string_to_path(interaction_profile.get_interaction_profile())?, + &controller_bindings, + )?; + + let action_sets = self.action_sets.lock().unwrap(); + self.session + .attach_action_sets(&action_sets.iter().collect::>())?; + } + bindings.sessions_attached = true; } } @@ -219,6 +258,11 @@ impl SessionTrait for OXrSession { let _span = info_span!("xr_wait_image").entered(); self.swapchain.wait_image().unwrap(); } + { + let action_sets = self.action_sets.lock().unwrap(); + self.session + .sync_actions(&action_sets.iter().map(Into::into).collect::>())?; + } let views = { let _span = info_span!("xr_locate_views").entered(); self.session @@ -293,11 +337,7 @@ pub struct OXrInput { } impl InputTrait for OXrInput { - fn create_action_haptics( - &self, - name: &str, - path: path::UntypedActionPath, - ) -> Result> { + fn create_action_haptics(&self, path: path::UntypedActionPath) -> Result> { let mut bindings = self.bindings.lock().unwrap(); let action = match bindings.map.entry(path.into_xr_path()) { hash_map::Entry::Occupied(entry) => match entry.get() { @@ -305,6 +345,7 @@ impl InputTrait for OXrInput { _ => Err(XrError::Placeholder)?, }, hash_map::Entry::Vacant(entry) => { + let name = &path.into_name(); let action = self .action_set .create_action::(name, name, &[])?; @@ -315,11 +356,7 @@ impl InputTrait for OXrInput { Ok(OXrHaptics(action, self.inner_session.clone()).into()) } - fn create_action_pose( - &self, - name: &str, - path: path::UntypedActionPath, - ) -> Result> { + fn create_action_pose(&self, path: path::UntypedActionPath) -> Result> { let mut bindings = self.bindings.lock().unwrap(); let action = match bindings.map.entry(path.into_xr_path()) { hash_map::Entry::Occupied(entry) => match entry.get() { @@ -327,6 +364,7 @@ impl InputTrait for OXrInput { _ => Err(XrError::Placeholder)?, }, hash_map::Entry::Vacant(entry) => { + let name = &path.into_name(); let action = self .action_set .create_action::(name, name, &[])?; @@ -346,11 +384,7 @@ impl InputTrait for OXrInput { .into()) } - fn create_action_float( - &self, - name: &str, - path: path::UntypedActionPath, - ) -> Result> { + fn create_action_float(&self, path: path::UntypedActionPath) -> Result> { let mut bindings = self.bindings.lock().unwrap(); let action = match bindings.map.entry(path.into_xr_path()) { hash_map::Entry::Occupied(entry) => match entry.get() { @@ -358,6 +392,7 @@ impl InputTrait for OXrInput { _ => Err(XrError::Placeholder)?, }, hash_map::Entry::Vacant(entry) => { + let name = &path.into_name(); let action = self.action_set.create_action::(name, name, &[])?; entry.insert(UntypedOXrAction::Float(action.clone())); action @@ -366,11 +401,7 @@ impl InputTrait for OXrInput { Ok(OXrAction(action, self.inner_session.clone(), PhantomData).into()) } - fn create_action_bool( - &self, - name: &str, - path: path::UntypedActionPath, - ) -> Result> { + fn create_action_bool(&self, path: path::UntypedActionPath) -> Result> { let mut bindings = self.bindings.lock().unwrap(); let action = match bindings.map.entry(path.into_xr_path()) { hash_map::Entry::Occupied(entry) => match entry.get() { @@ -378,6 +409,7 @@ impl InputTrait for OXrInput { _ => Err(XrError::Placeholder)?, }, hash_map::Entry::Vacant(entry) => { + let name = &path.into_name(); let action = self.action_set.create_action::(name, name, &[])?; entry.insert(UntypedOXrAction::Bool(action.clone())); action @@ -386,11 +418,7 @@ impl InputTrait for OXrInput { Ok(OXrAction(action, self.inner_session.clone(), PhantomData).into()) } - fn create_action_vec2( - &self, - name: &str, - path: path::UntypedActionPath, - ) -> Result> { + fn create_action_vec2(&self, path: path::UntypedActionPath) -> Result> { let mut bindings = self.bindings.lock().unwrap(); let action = match bindings.map.entry(path.into_xr_path()) { hash_map::Entry::Occupied(entry) => match entry.get() { @@ -398,6 +426,7 @@ impl InputTrait for OXrInput { _ => Err(XrError::Placeholder)?, }, hash_map::Entry::Vacant(entry) => { + let name = &path.into_name(); let action = self.action_set.create_action::(name, name, &[])?; entry.insert(UntypedOXrAction::Vec2(action.clone())); action diff --git a/xr_api/src/backend/oxr/utils.rs b/xr_api/src/backend/oxr/utils.rs index 793d40f..ce1da0b 100644 --- a/xr_api/src/backend/oxr/utils.rs +++ b/xr_api/src/backend/oxr/utils.rs @@ -7,6 +7,8 @@ use crate::{ prelude::Pose, }; +use super::Bindings; + impl From for XrError { fn from(_: openxr::sys::Result) -> Self { XrError::Placeholder @@ -87,4 +89,57 @@ impl UntypedActionPath { path.push_str(comp_path); path } + + pub(crate) fn into_name(&self) -> String { + let comp_path = match self.comp { + PathComponent::Click => "_click", + PathComponent::Touch => "_touch", + PathComponent::Value => "_value", + PathComponent::X => "_x", + PathComponent::Y => "_y", + PathComponent::Pose => "_pose", + PathComponent::Haptic => "", + }; + let dev_path = match self.input { + InputId::Left(hand) => match hand { + Handed::PrimaryButton => "left_primary_button", + Handed::SecondaryButton => "left_secondary_button", + Handed::Select => "left_select", + Handed::Menu => "left_menu", + Handed::Thumbstick => "left_thumbstick", + Handed::Trigger => "left_trigger", + Handed::Grip => "left_grip", + Handed::Output => "left_output", + }, + InputId::Right(hand) => match hand { + Handed::PrimaryButton => "right_primary_button", + Handed::SecondaryButton => "right_secondary_button", + Handed::Select => "right_select", + Handed::Menu => "right_menu", + Handed::Thumbstick => "right_thumbstick", + Handed::Trigger => "right_trigger", + Handed::Grip => "right_grip", + Handed::Output => "right_output", + }, + InputId::Head(head) => { + use input::head::Head; + match head { + Head::VolumeUp => "volume_up", + Head::VolumeDown => "volume_down", + Head::MuteMic => "mute_mic", + } + } + }; + let mut path = dev_path.to_string(); + path.push_str(comp_path); + path + } +} + +impl Bindings { + pub(crate) fn get_interaction_profile(&self) -> &'static str { + match self { + Bindings::OculusTouch => "/interaction_profiles/oculus/touch_controller", + } + } } diff --git a/xr_api/src/lib.rs b/xr_api/src/lib.rs index b0c372f..d548c2a 100644 --- a/xr_api/src/lib.rs +++ b/xr_api/src/lib.rs @@ -16,7 +16,7 @@ pub mod prelude { pub use super::api::*; pub use super::api_traits::*; pub use super::error::*; - pub use super::path::{self, ActionPath}; + pub use super::path::{input, ActionPath}; pub use super::types::*; } diff --git a/xr_api/src/types.rs b/xr_api/src/types.rs index 395091b..93b44c1 100644 --- a/xr_api/src/types.rs +++ b/xr_api/src/types.rs @@ -15,6 +15,7 @@ pub struct SessionCreateInfo { pub texture_format: wgpu::TextureFormat, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Bindings { OculusTouch, } @@ -29,45 +30,45 @@ pub struct Pose { pub trait ActionType: Sized { type Inner: ?Sized; - fn get(input: &dyn InputTrait, name: &str, path: UntypedActionPath) -> Result>; + fn get(input: &dyn InputTrait, path: UntypedActionPath) -> Result>; } impl ActionType for Haptic { type Inner = dyn HapticTrait; - fn get(input: &dyn InputTrait, name: &str, path: UntypedActionPath) -> Result> { - input.create_action_haptics(name, path) + fn get(input: &dyn InputTrait, path: UntypedActionPath) -> Result> { + input.create_action_haptics(path) } } impl ActionType for Pose { type Inner = dyn ActionInputTrait; - fn get(input: &dyn InputTrait, name: &str, path: UntypedActionPath) -> Result> { - input.create_action_pose(name, path) + fn get(input: &dyn InputTrait, path: UntypedActionPath) -> Result> { + input.create_action_pose(path) } } impl ActionType for f32 { type Inner = dyn ActionInputTrait; - fn get(input: &dyn InputTrait, name: &str, path: UntypedActionPath) -> Result> { - input.create_action_float(name, path) + fn get(input: &dyn InputTrait, path: UntypedActionPath) -> Result> { + input.create_action_float(path) } } impl ActionType for bool { type Inner = dyn ActionInputTrait; - fn get(input: &dyn InputTrait, name: &str, path: UntypedActionPath) -> Result> { - input.create_action_bool(name, path) + fn get(input: &dyn InputTrait, path: UntypedActionPath) -> Result> { + input.create_action_bool(path) } } impl ActionType for Vec2 { type Inner = dyn ActionInputTrait; - fn get(input: &dyn InputTrait, name: &str, path: UntypedActionPath) -> Result> { - input.create_action_vec2(name, path) + fn get(input: &dyn InputTrait, path: UntypedActionPath) -> Result> { + input.create_action_vec2(path) } }