Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for Vec2 Actions, make internal Action Creation better, custom get_action_* Error #57

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 99 additions & 56 deletions src/xr_input/actions.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -16,6 +21,22 @@ impl Plugin for OpenXrActionsPlugin {
}
}

#[inline(always)]
fn create_action<T: xr::ActionTy>(
action: &SetupAction,
action_name: &'static str,
oxr_action_set: &xr::ActionSet,
hands: &[xr::Path],
) -> xr::Action<T> {
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::<SetupActionSets>().unwrap();
let instance = world.get_resource::<XrInstance>().unwrap();
Expand All @@ -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<xr::Path>> = HashMap::new();
let mut a_iter = actions.sets.into_iter();
let mut action_bindings: HashMap<
(&'static str, &'static str),
HashMap<&'static str, Vec<xr::Path>>,
> = 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() {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -155,13 +160,15 @@ pub enum ActionType {
Bool,
PoseF,
Haptic,
Vec2,
}

pub enum TypedAction {
F32(Action<f32>),
Bool(Action<bool>),
PoseF(Action<Posef>),
Haptic(Action<Haptic>),
Vec2(Action<Vector2f>),
}

pub struct SetupAction {
Expand Down Expand Up @@ -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>,
}
Expand All @@ -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<Vector2f>, 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<f32>> {
) -> Result<&Action<f32>,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<bool>> {
) -> Result<&Action<bool>,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<Posef>> {
) -> Result<&Action<Posef>,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<Haptic>> {
) -> Result<&Action<Haptic>,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),
}
}
}