diff --git a/src/xr_input/actions.rs b/src/xr_input/actions.rs index 10a0914f..47802fde 100644 --- a/src/xr_input/actions.rs +++ b/src/xr_input/actions.rs @@ -1,8 +1,13 @@ +use std::error::Error; + use bevy::{prelude::*, utils::HashMap}; use openxr as xr; -use xr::{Action, Binding, Haptic, Posef}; +use xr::{Action, Binding, Haptic, Posef, Vector2f}; -use crate::{resources::{XrInstance, XrSession}, xr_init::XrPrePostSetup}; +use crate::{ + resources::{XrInstance, XrSession}, + xr_init::XrPrePostSetup, +}; use super::oculus_touch::ActionSets; @@ -16,6 +21,22 @@ impl Plugin for OpenXrActionsPlugin { } } +#[inline(always)] +fn create_action( + action: &SetupAction, + action_name: &'static str, + oxr_action_set: &xr::ActionSet, + hands: &[xr::Path], +) -> xr::Action { + match action.handednes { + ActionHandednes::Single => oxr_action_set + .create_action(action_name, &action.pretty_name, &[]) + .unwrap_or_else(|_| panic!("Unable to create action: {}", action_name)), + ActionHandednes::Double => oxr_action_set + .create_action(action_name, &action.pretty_name, hands) + .unwrap_or_else(|_| panic!("Unable to create action: {}", action_name)), + } +} pub fn setup_oxr_actions(world: &mut World) { let actions = world.remove_resource::().unwrap(); let instance = world.get_resource::().unwrap(); @@ -27,50 +48,33 @@ pub fn setup_oxr_actions(world: &mut World) { let mut oxr_action_sets = Vec::new(); let mut action_sets = XrActionSets { sets: default() }; // let mut action_bindings: HashMap<&'static str, Vec> = HashMap::new(); - let mut a_iter = actions.sets.into_iter(); let mut action_bindings: HashMap< (&'static str, &'static str), HashMap<&'static str, Vec>, > = HashMap::new(); - while let Some((set_name, set)) = a_iter.next() { + for (set_name, set) in actions.sets.into_iter() { let mut actions: HashMap<&'static str, TypedAction> = default(); let oxr_action_set = instance .create_action_set(set_name, &set.pretty_name, set.priority) .expect("Unable to create action set"); for (action_name, action) in set.actions.into_iter() { + use self::create_action as ca; let typed_action = match action.action_type { - ActionType::F32 => TypedAction::F32(match action.handednes { - ActionHandednes::Single => oxr_action_set - .create_action(action_name, &action.pretty_name, &[]) - .expect(&format!("Unable to create action: {}", action_name)), - ActionHandednes::Double => oxr_action_set - .create_action(action_name, &action.pretty_name, &hands) - .expect(&format!("Unable to create action: {}", action_name)), - }), - ActionType::Bool => TypedAction::Bool(match action.handednes { - ActionHandednes::Single => oxr_action_set - .create_action(action_name, &action.pretty_name, &[]) - .expect(&format!("Unable to create action: {}", action_name)), - ActionHandednes::Double => oxr_action_set - .create_action(action_name, &action.pretty_name, &hands) - .expect(&format!("Unable to create action: {}", action_name)), - }), - ActionType::PoseF => TypedAction::PoseF(match action.handednes { - ActionHandednes::Single => oxr_action_set - .create_action(action_name, &action.pretty_name, &[]) - .expect(&format!("Unable to create action: {}", action_name)), - ActionHandednes::Double => oxr_action_set - .create_action(action_name, &action.pretty_name, &hands) - .expect(&format!("Unable to create action: {}", action_name)), - }), - ActionType::Haptic => TypedAction::Haptic(match action.handednes { - ActionHandednes::Single => oxr_action_set - .create_action(action_name, &action.pretty_name, &[]) - .expect(&format!("Unable to create action: {}", action_name)), - ActionHandednes::Double => oxr_action_set - .create_action(action_name, &action.pretty_name, &hands) - .expect(&format!("Unable to create action: {}", action_name)), - }), + ActionType::Vec2 => { + TypedAction::Vec2(ca(&action, action_name, &oxr_action_set, &hands)) + } + ActionType::F32 => { + TypedAction::F32(ca(&action, action_name, &oxr_action_set, &hands)) + } + ActionType::Bool => { + TypedAction::Bool(ca(&action, action_name, &oxr_action_set, &hands)) + } + ActionType::PoseF => { + TypedAction::PoseF(ca(&action, action_name, &oxr_action_set, &hands)) + } + ActionType::Haptic => { + TypedAction::Haptic(ca(&action, action_name, &oxr_action_set, &hands)) + } }; actions.insert(action_name, typed_action); for (device_path, bindings) in action.bindings.into_iter() { @@ -107,18 +111,19 @@ pub fn setup_oxr_actions(world: &mut World) { .zip([&action_bindings].into_iter().cycle()) .flat_map(move |((set_name, action_name, action), bindings)| { bindings - .get(&(set_name.clone(), action_name.clone())) + .get(&(set_name as &'static str, action_name as &'static str)) .unwrap() .iter() - .map(move |(dev, bindings)| (action.clone(), dev.clone(), bindings)) + .map(move |(dev, bindings)| (action, dev, bindings)) }) .map(|(action, dev, bindings)| { info!("Hi"); ( dev, bindings - .into_iter() + .iter() .map(move |binding| match &action { + TypedAction::Vec2(a) => Binding::new(a, *binding), TypedAction::F32(a) => Binding::new(a, *binding), TypedAction::Bool(a) => Binding::new(a, *binding), TypedAction::PoseF(a) => Binding::new(a, *binding), @@ -155,6 +160,7 @@ pub enum ActionType { Bool, PoseF, Haptic, + Vec2, } pub enum TypedAction { @@ -162,6 +168,7 @@ pub enum TypedAction { Bool(Action), PoseF(Action), Haptic(Action), + Vec2(Action), } pub struct SetupAction { @@ -247,7 +254,7 @@ impl SetupActionSets { } pub struct ActionSet { - // oxr_action_set: xr::ActionSet, + // add functionality to enable/disable action sets enabled: bool, actions: HashMap<&'static str, TypedAction>, } @@ -257,73 +264,109 @@ pub struct XrActionSets { sets: HashMap<&'static str, ActionSet>, } +use std::fmt::Display as FmtDisplay; +impl FmtDisplay for ActionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let err = match self { + ActionError::NoActionSet => "Action Set Not Found!", + ActionError::NoAction => "Action Not Found!", + ActionError::WrongActionType => "Wrong Action Type!", + }; + write!(f, "{}", err) + } +} +impl Error for ActionError {} +#[derive(Debug)] +pub enum ActionError { + NoActionSet, + NoAction, + WrongActionType, +} + impl XrActionSets { + pub fn get_action_vec2( + &self, + action_set: &'static str, + action_name: &'static str, + ) -> Result<&Action, ActionError> { + let action = self + .sets + .get(action_set) + .ok_or(ActionError::NoActionSet)? + .actions + .get(action_name) + .ok_or(ActionError::NoAction)?; + match action { + TypedAction::Vec2(a) => Ok(a), + _ => Err(ActionError::WrongActionType), + } + } pub fn get_action_f32( &self, action_set: &'static str, action_name: &'static str, - ) -> anyhow::Result<&Action> { + ) -> Result<&Action,ActionError> { let action = self .sets .get(action_set) - .ok_or(anyhow::anyhow!("Action Set Not Found!"))? + .ok_or(ActionError::NoActionSet)? .actions .get(action_name) - .ok_or(anyhow::anyhow!("Action Not Found!"))?; + .ok_or(ActionError::NoAction)?; match action { TypedAction::F32(a) => Ok(a), - _ => anyhow::bail!("wrong action type"), + _ => Err(ActionError::WrongActionType), } } pub fn get_action_bool( &self, action_set: &'static str, action_name: &'static str, - ) -> anyhow::Result<&Action> { + ) -> Result<&Action,ActionError> { let action = self .sets .get(action_set) - .ok_or(anyhow::anyhow!("Action Set Not Found!"))? + .ok_or(ActionError::NoActionSet)? .actions .get(action_name) - .ok_or(anyhow::anyhow!("Action Not Found!"))?; + .ok_or(ActionError::NoAction)?; match action { TypedAction::Bool(a) => Ok(a), - _ => anyhow::bail!("wrong action type"), + _ => Err(ActionError::WrongActionType), } } pub fn get_action_posef( &self, action_set: &'static str, action_name: &'static str, - ) -> anyhow::Result<&Action> { + ) -> Result<&Action,ActionError> { let action = self .sets .get(action_set) - .ok_or(anyhow::anyhow!("Action Set Not Found!"))? + .ok_or(ActionError::NoActionSet)? .actions .get(action_name) - .ok_or(anyhow::anyhow!("Action Not Found!"))?; + .ok_or(ActionError::NoAction)?; match action { TypedAction::PoseF(a) => Ok(a), - _ => anyhow::bail!("wrong action type"), + _ => Err(ActionError::WrongActionType), } } pub fn get_action_haptic( &self, action_set: &'static str, action_name: &'static str, - ) -> anyhow::Result<&Action> { + ) -> Result<&Action,ActionError> { let action = self .sets .get(action_set) - .ok_or(anyhow::anyhow!("Action Set Not Found!"))? + .ok_or(ActionError::NoActionSet)? .actions .get(action_name) - .ok_or(anyhow::anyhow!("Action Not Found!"))?; + .ok_or(ActionError::NoAction)?; match action { TypedAction::Haptic(a) => Ok(a), - _ => anyhow::bail!("wrong action type"), + _ => Err(ActionError::WrongActionType), } } }