472 lines
16 KiB
Rust
472 lines
16 KiB
Rust
use crate::input::XrInput;
|
|
use crate::resources::{XrInstance, XrSession};
|
|
use crate::xr_input::controllers::{Handed, Touchable};
|
|
use crate::xr_input::Hand;
|
|
use bevy::prelude::{Commands, Res, ResMut, Resource};
|
|
use openxr::{
|
|
Action, ActionSet, AnyGraphics, Binding, FrameState, Haptic, Instance, Path, Posef, Session,
|
|
Space, SpaceLocation, SpaceVelocity,
|
|
};
|
|
|
|
use std::convert::identity;
|
|
use std::sync::OnceLock;
|
|
|
|
use super::actions::{ActionHandednes, XrActionSets, ActionType, SetupActionSets, XrBinding};
|
|
|
|
pub fn post_action_setup_oculus_controller(
|
|
action_sets: Res<XrActionSets>,
|
|
mut controller: ResMut<OculusController>,
|
|
instance: Res<XrInstance>,
|
|
session: Res<XrSession>,
|
|
) {
|
|
let s = Session::<AnyGraphics>::clone(&session);
|
|
let left_path = instance.string_to_path("/user/hand/left").unwrap();
|
|
let right_path = instance.string_to_path("/user/hand/right").unwrap();
|
|
let grip_action = action_sets
|
|
.get_action_posef("oculus_input", "hand_pose")
|
|
.unwrap();
|
|
let aim_action = action_sets
|
|
.get_action_posef("oculus_input", "pointer_pose")
|
|
.unwrap();
|
|
controller.grip_space = Some(Handed {
|
|
left: grip_action
|
|
.create_space(
|
|
s.clone(),
|
|
left_path,
|
|
Posef::IDENTITY,
|
|
)
|
|
.unwrap(),
|
|
right: grip_action
|
|
.create_space(
|
|
s.clone(),
|
|
right_path,
|
|
Posef::IDENTITY,
|
|
)
|
|
.unwrap(),
|
|
});
|
|
controller.aim_space = Some(Handed {
|
|
left: aim_action
|
|
.create_space(
|
|
s.clone(),
|
|
left_path,
|
|
Posef::IDENTITY,
|
|
)
|
|
.unwrap(),
|
|
right: aim_action
|
|
.create_space(
|
|
s.clone(),
|
|
right_path,
|
|
Posef::IDENTITY,
|
|
)
|
|
.unwrap(),
|
|
})
|
|
}
|
|
pub fn setup_oculus_controller(
|
|
mut commands: Commands,
|
|
instance: Res<XrInstance>,
|
|
action_sets: ResMut<SetupActionSets>,
|
|
) {
|
|
let oculus_controller = OculusController::new(action_sets).unwrap();
|
|
init_subaction_path(&instance);
|
|
commands.insert_resource(oculus_controller);
|
|
}
|
|
|
|
#[derive(Resource, Clone)]
|
|
pub struct ActionSets(pub Vec<ActionSet>);
|
|
|
|
pub struct OculusControllerRef<'a> {
|
|
oculus_controller: &'a OculusController,
|
|
action_sets: &'a XrActionSets,
|
|
session: &'a Session<AnyGraphics>,
|
|
frame_state: &'a FrameState,
|
|
xr_input: &'a XrInput,
|
|
}
|
|
|
|
static RIGHT_SUBACTION_PATH: OnceLock<Path> = OnceLock::new();
|
|
static LEFT_SUBACTION_PATH: OnceLock<Path> = OnceLock::new();
|
|
|
|
pub fn init_subaction_path(instance: &Instance) {
|
|
let _ = LEFT_SUBACTION_PATH.set(instance.string_to_path("/user/hand/left").unwrap());
|
|
let _ = RIGHT_SUBACTION_PATH.set(instance.string_to_path("/user/hand/right").unwrap());
|
|
}
|
|
|
|
pub fn subaction_path(hand: Hand) -> Path {
|
|
*match hand {
|
|
Hand::Left => LEFT_SUBACTION_PATH.get().unwrap(),
|
|
Hand::Right => RIGHT_SUBACTION_PATH.get().unwrap(),
|
|
}
|
|
}
|
|
|
|
impl OculusControllerRef<'_> {
|
|
pub fn grip_space(&self, hand: Hand) -> (SpaceLocation, SpaceVelocity) {
|
|
match hand {
|
|
Hand::Left => self.oculus_controller.grip_space.as_ref().unwrap().left.relate(
|
|
&self.xr_input.stage,
|
|
self.frame_state.predicted_display_time,
|
|
),
|
|
Hand::Right => self.oculus_controller.grip_space.as_ref().unwrap().right.relate(
|
|
&self.xr_input.stage,
|
|
self.frame_state.predicted_display_time,
|
|
),
|
|
}
|
|
.unwrap()
|
|
}
|
|
pub fn aim_space(&self, hand: Hand) -> (SpaceLocation, SpaceVelocity) {
|
|
match hand {
|
|
Hand::Left => self.oculus_controller.aim_space.as_ref().unwrap().left.relate(
|
|
&self.xr_input.stage,
|
|
self.frame_state.predicted_display_time,
|
|
),
|
|
Hand::Right => self.oculus_controller.aim_space.as_ref().unwrap().right.relate(
|
|
&self.xr_input.stage,
|
|
self.frame_state.predicted_display_time,
|
|
),
|
|
}
|
|
.unwrap()
|
|
}
|
|
pub fn squeeze(&self, hand: Hand) -> f32 {
|
|
let action = &self
|
|
.action_sets
|
|
.get_action_f32("oculus_input", "squeeze")
|
|
.unwrap();
|
|
action
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn trigger(&self, hand: Hand) -> f32 {
|
|
self.action_sets
|
|
.get_action_f32("oculus_input", "trigger")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn trigger_touched(&self, hand: Hand) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "trigger_touched")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn x_button(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "x_button")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn x_button_touched(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "x_button_touch")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn y_button(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "y_button")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn y_button_touched(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "y_button_touch")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn menu_button(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "menu_button")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn a_button(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "a_button")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn a_button_touched(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "a_button_touch")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn b_button(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "b_button")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn b_button_touched(&self) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "b_button_touch")
|
|
.unwrap()
|
|
.state(&self.session, Path::NULL)
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn thumbstick_touch(&self, hand: Hand) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "thumbstick_touch")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
pub fn thumbstick(&self, hand: Hand) -> Thumbstick {
|
|
Thumbstick {
|
|
x: self
|
|
.action_sets
|
|
.get_action_f32("oculus_input", "thumbstick_x")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state,
|
|
y: self
|
|
.action_sets
|
|
.get_action_f32("oculus_input", "thumbstick_y")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state,
|
|
click: self
|
|
.action_sets
|
|
.get_action_bool("oculus_input", "thumbstick_click")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state,
|
|
}
|
|
}
|
|
pub fn thumbrest_touch(&self, hand: Hand) -> bool {
|
|
self.action_sets
|
|
.get_action_bool("oculus_input", "thumbrest_touch")
|
|
.unwrap()
|
|
.state(&self.session, subaction_path(hand))
|
|
.unwrap()
|
|
.current_state
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct Thumbstick {
|
|
pub x: f32,
|
|
pub y: f32,
|
|
pub click: bool,
|
|
}
|
|
|
|
impl OculusController {
|
|
pub fn get_ref<'a>(
|
|
&'a self,
|
|
session: &'a Session<AnyGraphics>,
|
|
frame_state: &'a FrameState,
|
|
xr_input: &'a XrInput,
|
|
action_sets: &'a XrActionSets,
|
|
) -> OculusControllerRef {
|
|
OculusControllerRef {
|
|
oculus_controller: self,
|
|
session,
|
|
frame_state,
|
|
xr_input,
|
|
action_sets,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
pub struct OculusController {
|
|
pub grip_space: Option<Handed<Space>>,
|
|
pub aim_space: Option<Handed<Space>>,
|
|
}
|
|
impl OculusController {
|
|
pub fn new(mut action_sets: ResMut<SetupActionSets>) -> anyhow::Result<Self> {
|
|
let action_set =
|
|
action_sets.add_action_set("oculus_input", "Oculus Touch Controller Input", 0);
|
|
action_set.new_action(
|
|
"hand_pose",
|
|
"Hand Pose",
|
|
ActionType::PoseF,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"pointer_pose",
|
|
"Pointer Pose",
|
|
ActionType::PoseF,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"squeeze",
|
|
"Grip Pull",
|
|
ActionType::F32,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"trigger",
|
|
"Trigger Pull",
|
|
ActionType::F32,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"trigger_touched",
|
|
"Trigger Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"haptic_feedback",
|
|
"Haptic Feedback",
|
|
ActionType::Haptic,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"x_button",
|
|
"X Button",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"x_button_touch",
|
|
"X Button Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"y_button",
|
|
"Y Button",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"y_button_touch",
|
|
"Y Button Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"a_button",
|
|
"A Button",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"a_button_touch",
|
|
"A Button Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"b_button",
|
|
"B Button",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"b_button_touch",
|
|
"B Button Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"menu_button",
|
|
"Menu Button",
|
|
ActionType::Bool,
|
|
ActionHandednes::Single,
|
|
);
|
|
action_set.new_action(
|
|
"thumbstick_x",
|
|
"Thumbstick X",
|
|
ActionType::F32,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"thumbstick_y",
|
|
"Thumbstick y",
|
|
ActionType::F32,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"thumbstick_touch",
|
|
"Thumbstick Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"thumbstick_click",
|
|
"Thumbstick Click",
|
|
ActionType::Bool,
|
|
ActionHandednes::Double,
|
|
);
|
|
action_set.new_action(
|
|
"thumbrest_touch",
|
|
"Thumbrest Touch",
|
|
ActionType::Bool,
|
|
ActionHandednes::Double,
|
|
);
|
|
|
|
let this = OculusController {
|
|
grip_space: None,
|
|
aim_space: None,
|
|
};
|
|
action_set.suggest_binding(
|
|
"/interaction_profiles/oculus/touch_controller",
|
|
&[
|
|
XrBinding::new("hand_pose", "/user/hand/left/input/grip/pose"),
|
|
XrBinding::new("hand_pose", "/user/hand/right/input/grip/pose"),
|
|
XrBinding::new("pointer_pose", "/user/hand/left/input/aim/pose"),
|
|
XrBinding::new("pointer_pose", "/user/hand/right/input/aim/pose"),
|
|
XrBinding::new("squeeze", "/user/hand/left/input/squeeze/value"),
|
|
XrBinding::new("squeeze", "/user/hand/right/input/squeeze/value"),
|
|
XrBinding::new("trigger", "/user/hand/left/input/trigger/value"),
|
|
XrBinding::new("trigger", "/user/hand/right/input/trigger/value"),
|
|
XrBinding::new("trigger_touched", "/user/hand/left/input/trigger/touch"),
|
|
XrBinding::new("trigger_touched", "/user/hand/right/input/trigger/touch"),
|
|
XrBinding::new("haptic_feedback", "/user/hand/left/output/haptic"),
|
|
XrBinding::new("haptic_feedback", "/user/hand/right/output/haptic"),
|
|
XrBinding::new("x_button", "/user/hand/left/input/x/click"),
|
|
XrBinding::new("x_button_touch", "/user/hand/left/input/x/touch"),
|
|
XrBinding::new("y_button", "/user/hand/left/input/y/click"),
|
|
XrBinding::new("y_button_touch", "/user/hand/left/input/y/touch"),
|
|
XrBinding::new("a_button", "/user/hand/right/input/a/click"),
|
|
XrBinding::new("a_button_touch", "/user/hand/right/input/a/touch"),
|
|
XrBinding::new("b_button", "/user/hand/right/input/b/click"),
|
|
XrBinding::new("b_button_touch", "/user/hand/right/input/b/touch"),
|
|
XrBinding::new("menu_button", "/user/hand/left/input/menu/click"),
|
|
XrBinding::new("thumbstick_x", "/user/hand/left/input/thumbstick/x"),
|
|
XrBinding::new("thumbstick_y", "/user/hand/left/input/thumbstick/y"),
|
|
XrBinding::new("thumbstick_x", "/user/hand/right/input/thumbstick/x"),
|
|
XrBinding::new("thumbstick_y", "/user/hand/right/input/thumbstick/y"),
|
|
XrBinding::new("thumbstick_click", "/user/hand/left/input/thumbstick/click"),
|
|
XrBinding::new(
|
|
"thumbstick_click",
|
|
"/user/hand/right/input/thumbstick/click",
|
|
),
|
|
XrBinding::new("thumbstick_touch", "/user/hand/left/input/thumbstick/touch"),
|
|
XrBinding::new(
|
|
"thumbstick_touch",
|
|
"/user/hand/right/input/thumbstick/touch",
|
|
),
|
|
XrBinding::new("thumbrest_touch", "/user/hand/left/input/thumbrest/touch"),
|
|
XrBinding::new("thumbrest_touch", "/user/hand/right/input/thumbrest/touch"),
|
|
],
|
|
);
|
|
Ok(this)
|
|
}
|
|
}
|