openxr implementation complete
This commit is contained in:
@@ -11,6 +11,7 @@ linked = ["openxr/linked"]
|
||||
ash = "0.37.3"
|
||||
futures = "0.3.29"
|
||||
glam = "0.24.1"
|
||||
hashbrown = "0.14"
|
||||
paste = "1.0.14"
|
||||
thiserror = "1.0.51"
|
||||
tracing = "0.1.40"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use glam::Vec2;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Entry point to the API
|
||||
@@ -105,6 +107,12 @@ impl<T: ActionInputTrait<Pose> + 'static> From<T> for Action<Pose> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ActionInputTrait<Vec2> + 'static> From<T> for Action<Vec2> {
|
||||
fn from(value: T) -> Self {
|
||||
Self(Rc::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ActionInputTrait<bool> + 'static> From<T> for Action<bool> {
|
||||
fn from(value: T) -> Self {
|
||||
Self(Rc::new(value))
|
||||
|
||||
@@ -79,7 +79,7 @@ impl dyn InputTrait {
|
||||
|
||||
/// Represents input actions, such as bools, floats, and poses
|
||||
pub trait ActionInputTrait<A> {
|
||||
fn get(&self) -> A;
|
||||
fn get(&self) -> Result<A>;
|
||||
}
|
||||
|
||||
/// Represents haptic actions.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
mod graphics;
|
||||
mod utils;
|
||||
|
||||
use std::{rc::Rc, sync::Mutex};
|
||||
use std::{marker::PhantomData, rc::Rc, sync::Mutex};
|
||||
|
||||
use glam::{Mat4, UVec2};
|
||||
use openxr::EnvironmentBlendMode;
|
||||
use glam::{Mat4, UVec2, Vec2};
|
||||
use hashbrown::{hash_map, HashMap};
|
||||
use openxr::{EnvironmentBlendMode, Vector2f};
|
||||
use tracing::{info, info_span, warn};
|
||||
|
||||
use crate::{backend::oxr::graphics::VIEW_TYPE, prelude::*};
|
||||
@@ -70,7 +71,7 @@ impl InstanceTrait for OXrInstance {
|
||||
}
|
||||
}
|
||||
|
||||
enum UntypedOXrAction {
|
||||
pub(crate) enum UntypedOXrAction {
|
||||
Haptics(openxr::Action<openxr::Haptic>),
|
||||
Pose(openxr::Action<openxr::Posef>),
|
||||
Float(openxr::Action<f32>),
|
||||
@@ -79,9 +80,10 @@ enum UntypedOXrAction {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BindingState {
|
||||
sets_attached: bool,
|
||||
bindings: Vec<(UntypedOXrAction, openxr::Path)>,
|
||||
pub(crate) struct BindingState {
|
||||
sessions_attached: bool,
|
||||
bindings: Option<Bindings>,
|
||||
map: HashMap<String, UntypedOXrAction>,
|
||||
}
|
||||
|
||||
pub struct OXrSession {
|
||||
@@ -100,11 +102,11 @@ pub struct OXrSession {
|
||||
)>,
|
||||
>,
|
||||
pub(crate) bindings: Rc<Mutex<BindingState>>,
|
||||
pub(crate) frame_state: Mutex<openxr::FrameState>,
|
||||
pub(crate) frame_state: Rc<Mutex<openxr::FrameState>>,
|
||||
pub(crate) views: Mutex<[openxr::View; 2]>,
|
||||
pub(crate) frame_waiter: Mutex<openxr::FrameWaiter>,
|
||||
pub(crate) swapchain: graphics::Swapchain,
|
||||
pub(crate) stage: openxr::Space,
|
||||
pub(crate) stage: Rc<openxr::Space>,
|
||||
pub(crate) head: openxr::Space,
|
||||
pub(crate) resolution: UVec2,
|
||||
pub(crate) blend_mode: EnvironmentBlendMode,
|
||||
@@ -128,14 +130,38 @@ impl SessionTrait for OXrSession {
|
||||
}
|
||||
|
||||
fn create_input(&self, bindings: Bindings) -> Result<Input> {
|
||||
let mut binding_state = self.bindings.lock().unwrap();
|
||||
if binding_state.bindings.is_none() {
|
||||
binding_state.bindings = Some(bindings);
|
||||
} else {
|
||||
Err(XrError::Placeholder)?
|
||||
}
|
||||
|
||||
let action_set = self
|
||||
.inner_instance
|
||||
.create_action_set("xr_input", "XR Input", 0)?;
|
||||
self.action_sets.lock().unwrap().push(action_set.clone());
|
||||
todo!()
|
||||
Ok(OXrInput {
|
||||
inner_session: self.session.clone().into_any_graphics(),
|
||||
action_set,
|
||||
bindings: self.bindings.clone(),
|
||||
stage: self.stage.clone(),
|
||||
frame_state: self.frame_state.clone(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
fn begin_frame(&self) -> Result<(View, View)> {
|
||||
{
|
||||
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::<Vec<_>>())?;
|
||||
bindings.sessions_attached = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
let _span = info_span!("xr_poll_events");
|
||||
while let Some(event) = self
|
||||
@@ -259,26 +285,11 @@ impl SessionTrait for OXrSession {
|
||||
}
|
||||
|
||||
pub struct OXrInput {
|
||||
inner_instance: openxr::Instance,
|
||||
inner_session: openxr::Session<openxr::AnyGraphics>,
|
||||
action_set: openxr::ActionSet,
|
||||
bindings: Rc<Mutex<BindingState>>,
|
||||
}
|
||||
|
||||
impl OXrInput {
|
||||
fn create_action<A: openxr::ActionTy>(
|
||||
&self,
|
||||
name: &str,
|
||||
handed: bool,
|
||||
) -> openxr::Result<openxr::Action<A>> {
|
||||
if handed {
|
||||
let left_path = self.inner_instance.string_to_path("/user/hand/left")?;
|
||||
let right_path = self.inner_instance.string_to_path("/user/hand/right")?;
|
||||
self.action_set
|
||||
.create_action::<A>(name, name, &[left_path, right_path])
|
||||
} else {
|
||||
self.action_set.create_action(name, name, &[])
|
||||
}
|
||||
}
|
||||
stage: Rc<openxr::Space>,
|
||||
frame_state: Rc<Mutex<openxr::FrameState>>,
|
||||
}
|
||||
|
||||
impl InputTrait for OXrInput {
|
||||
@@ -287,7 +298,21 @@ impl InputTrait for OXrInput {
|
||||
name: &str,
|
||||
path: path::UntypedActionPath,
|
||||
) -> Result<Action<Haptic>> {
|
||||
todo!()
|
||||
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() {
|
||||
UntypedOXrAction::Haptics(action) => action.clone(),
|
||||
_ => Err(XrError::Placeholder)?,
|
||||
},
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let action = self
|
||||
.action_set
|
||||
.create_action::<openxr::Haptic>(name, name, &[])?;
|
||||
entry.insert(UntypedOXrAction::Haptics(action.clone()));
|
||||
action
|
||||
}
|
||||
};
|
||||
Ok(OXrHaptics(action, self.inner_session.clone()).into())
|
||||
}
|
||||
|
||||
fn create_action_pose(
|
||||
@@ -295,7 +320,30 @@ impl InputTrait for OXrInput {
|
||||
name: &str,
|
||||
path: path::UntypedActionPath,
|
||||
) -> Result<Action<Pose>> {
|
||||
todo!()
|
||||
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() {
|
||||
UntypedOXrAction::Pose(action) => action.clone(),
|
||||
_ => Err(XrError::Placeholder)?,
|
||||
},
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let action = self
|
||||
.action_set
|
||||
.create_action::<openxr::Posef>(name, name, &[])?;
|
||||
entry.insert(UntypedOXrAction::Pose(action.clone()));
|
||||
action
|
||||
}
|
||||
};
|
||||
Ok(OXrPoseAction {
|
||||
pose_space: action.create_space(
|
||||
self.inner_session.clone(),
|
||||
openxr::Path::NULL,
|
||||
openxr::Posef::IDENTITY,
|
||||
)?,
|
||||
stage: self.stage.clone(),
|
||||
frame_state: self.frame_state.clone(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
fn create_action_float(
|
||||
@@ -303,7 +351,19 @@ impl InputTrait for OXrInput {
|
||||
name: &str,
|
||||
path: path::UntypedActionPath,
|
||||
) -> Result<Action<f32>> {
|
||||
todo!()
|
||||
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() {
|
||||
UntypedOXrAction::Float(action) => action.clone(),
|
||||
_ => Err(XrError::Placeholder)?,
|
||||
},
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let action = self.action_set.create_action::<f32>(name, name, &[])?;
|
||||
entry.insert(UntypedOXrAction::Float(action.clone()));
|
||||
action
|
||||
}
|
||||
};
|
||||
Ok(OXrAction(action, self.inner_session.clone(), PhantomData).into())
|
||||
}
|
||||
|
||||
fn create_action_bool(
|
||||
@@ -311,15 +371,85 @@ impl InputTrait for OXrInput {
|
||||
name: &str,
|
||||
path: path::UntypedActionPath,
|
||||
) -> Result<Action<bool>> {
|
||||
todo!()
|
||||
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() {
|
||||
UntypedOXrAction::Bool(action) => action.clone(),
|
||||
_ => Err(XrError::Placeholder)?,
|
||||
},
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let action = self.action_set.create_action::<bool>(name, name, &[])?;
|
||||
entry.insert(UntypedOXrAction::Bool(action.clone()));
|
||||
action
|
||||
}
|
||||
};
|
||||
Ok(OXrAction(action, self.inner_session.clone(), PhantomData).into())
|
||||
}
|
||||
|
||||
fn create_action_vec2(
|
||||
&self,
|
||||
name: &str,
|
||||
path: path::UntypedActionPath,
|
||||
) -> Result<Action<glam::Vec2>> {
|
||||
todo!()
|
||||
) -> Result<Action<Vec2>> {
|
||||
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() {
|
||||
UntypedOXrAction::Vec2(action) => action.clone(),
|
||||
_ => Err(XrError::Placeholder)?,
|
||||
},
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let action = self.action_set.create_action::<Vector2f>(name, name, &[])?;
|
||||
entry.insert(UntypedOXrAction::Vec2(action.clone()));
|
||||
action
|
||||
}
|
||||
};
|
||||
Ok(OXrAction::<Vector2f, Vec2>(action, self.inner_session.clone(), PhantomData).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OXrHaptics(
|
||||
openxr::Action<openxr::Haptic>,
|
||||
openxr::Session<openxr::AnyGraphics>,
|
||||
);
|
||||
|
||||
impl HapticTrait for OXrHaptics {}
|
||||
|
||||
pub struct OXrPoseAction {
|
||||
pose_space: openxr::Space,
|
||||
stage: Rc<openxr::Space>,
|
||||
frame_state: Rc<Mutex<openxr::FrameState>>,
|
||||
}
|
||||
|
||||
impl ActionInputTrait<Pose> for OXrPoseAction {
|
||||
fn get(&self) -> Result<Pose> {
|
||||
let pose = self
|
||||
.pose_space
|
||||
.locate(
|
||||
&self.stage,
|
||||
self.frame_state.lock().unwrap().predicted_display_time,
|
||||
)?
|
||||
.pose;
|
||||
|
||||
Ok(pose.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OXrAction<A: openxr::ActionInput, T = ()>(
|
||||
openxr::Action<A>,
|
||||
openxr::Session<openxr::AnyGraphics>,
|
||||
PhantomData<T>,
|
||||
);
|
||||
|
||||
impl<A: ActionType + openxr::ActionInput> ActionInputTrait<A> for OXrAction<A> {
|
||||
fn get(&self) -> Result<A> {
|
||||
Ok(self.0.state(&self.1, openxr::Path::NULL)?.current_state)
|
||||
}
|
||||
}
|
||||
|
||||
impl ActionInputTrait<Vec2> for OXrAction<Vector2f, Vec2> {
|
||||
fn get(&self) -> Result<Vec2> {
|
||||
let Vector2f { x, y } = self.0.state(&self.1, openxr::Path::NULL)?.current_state;
|
||||
Ok(Vec2 { x, y })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::ffi::{c_void, CString};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use super::{Swapchain, SwapchainInner, VIEW_TYPE};
|
||||
@@ -306,15 +307,19 @@ pub fn init_oxr_graphics(
|
||||
buffers,
|
||||
image_index: Mutex::new(0),
|
||||
}),
|
||||
frame_state: Mutex::new(openxr::FrameState {
|
||||
frame_state: Rc::new(Mutex::new(openxr::FrameState {
|
||||
predicted_display_time: openxr::Time::from_nanos(1),
|
||||
predicted_display_period: openxr::Duration::from_nanos(1),
|
||||
should_render: true,
|
||||
}),
|
||||
})),
|
||||
blend_mode,
|
||||
frame_waiter: Mutex::new(frame_wait),
|
||||
stage: session
|
||||
.create_reference_space(openxr::ReferenceSpaceType::STAGE, openxr::Posef::IDENTITY)?,
|
||||
stage: Rc::new(
|
||||
session.create_reference_space(
|
||||
openxr::ReferenceSpaceType::STAGE,
|
||||
openxr::Posef::IDENTITY,
|
||||
)?,
|
||||
),
|
||||
head: session
|
||||
.create_reference_space(openxr::ReferenceSpaceType::VIEW, openxr::Posef::IDENTITY)?,
|
||||
format: swapchain_format,
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use glam::Quat;
|
||||
use openxr::Posef;
|
||||
|
||||
use crate::{error::XrError, prelude::Pose};
|
||||
use crate::{
|
||||
error::XrError,
|
||||
path::{input, Handed, InputId, PathComponent, UntypedActionPath},
|
||||
prelude::Pose,
|
||||
};
|
||||
|
||||
impl From<openxr::sys::Result> for XrError {
|
||||
fn from(_: openxr::sys::Result) -> Self {
|
||||
@@ -10,17 +14,13 @@ impl From<openxr::sys::Result> for XrError {
|
||||
}
|
||||
|
||||
impl From<Posef> for Pose {
|
||||
fn from(value: Posef) -> Self {
|
||||
let translation = {
|
||||
let openxr::Vector3f { x, y, z } = value.position;
|
||||
[x, y, z].into()
|
||||
};
|
||||
|
||||
fn from(pose: Posef) -> Self {
|
||||
// with enough sign errors anything is possible
|
||||
let rotation = {
|
||||
let openxr::Quaternionf { x, y, z, w } = value.orientation;
|
||||
|
||||
Quat::from_xyzw(x, y, z, w)
|
||||
let o = pose.orientation;
|
||||
Quat::from_rotation_x(180.0f32.to_radians()) * glam::quat(o.w, o.z, o.y, o.x)
|
||||
};
|
||||
let translation = glam::vec3(-pose.position.x, pose.position.y, -pose.position.z);
|
||||
|
||||
Pose {
|
||||
translation,
|
||||
@@ -28,3 +28,63 @@ impl From<Posef> for Pose {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UntypedActionPath {
|
||||
pub(crate) fn into_xr_path(self) -> String {
|
||||
let dev_path;
|
||||
let sub_path;
|
||||
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 => "/haptic",
|
||||
};
|
||||
match self.input {
|
||||
InputId::Left(hand) => {
|
||||
dev_path = "/user/hand/left";
|
||||
sub_path = match hand {
|
||||
Handed::PrimaryButton => "/input/x",
|
||||
Handed::SecondaryButton => "/input/y",
|
||||
Handed::Select => "/input/select",
|
||||
Handed::Menu => "/input/menu",
|
||||
Handed::Thumbstick => "/input/thumbstick",
|
||||
Handed::Trigger => "/input/trigger",
|
||||
Handed::Grip if matches!(self.comp, PathComponent::Pose) => "/input/grip",
|
||||
Handed::Grip => "/input/squeeze",
|
||||
Handed::Output => "/output",
|
||||
};
|
||||
}
|
||||
InputId::Right(hand) => {
|
||||
dev_path = "/user/hand/right";
|
||||
sub_path = match hand {
|
||||
Handed::PrimaryButton => "/input/a",
|
||||
Handed::SecondaryButton => "/input/b",
|
||||
Handed::Select => "/input/select",
|
||||
Handed::Menu => "/input/menu",
|
||||
Handed::Thumbstick => "/input/thumbstick",
|
||||
Handed::Trigger => "/input/trigger",
|
||||
Handed::Grip if matches!(self.comp, PathComponent::Pose) => "/input/grip",
|
||||
Handed::Grip => "/input/squeeze",
|
||||
Handed::Output => "/output",
|
||||
};
|
||||
}
|
||||
InputId::Head(head) => {
|
||||
use input::head::Head;
|
||||
dev_path = "/user/head";
|
||||
sub_path = match head {
|
||||
Head::VolumeUp => "/input/volume_up",
|
||||
Head::VolumeDown => "/input/volume_down",
|
||||
Head::MuteMic => "/input/mute_mic",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let mut path = dev_path.to_owned();
|
||||
path.push_str(sub_path);
|
||||
path.push_str(comp_path);
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,8 @@ impl InputTrait for WebXrInput {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OXrActionInput(openxr::Action);
|
||||
|
||||
pub struct WebXrHaptics(web_sys::GamepadHapticActuator, ActionPath);
|
||||
|
||||
impl ActionTrait for WebXrHaptics {
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use glam::Vec2;
|
||||
|
||||
use crate::prelude::ActionType;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ActionPath<P: InputComponent> {
|
||||
pub(crate) input: InputId,
|
||||
pub(crate) comp: PathComponent,
|
||||
pub(crate) hand: Option<Hand>,
|
||||
_data: PhantomData<P>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UntypedActionPath {
|
||||
pub(crate) input: InputId,
|
||||
pub(crate) comp: PathComponent,
|
||||
pub(crate) hand: Option<Hand>,
|
||||
}
|
||||
|
||||
impl<P: InputComponent> From<ActionPath<P>> for UntypedActionPath {
|
||||
@@ -24,11 +22,11 @@ impl<P: InputComponent> From<ActionPath<P>> for UntypedActionPath {
|
||||
}
|
||||
|
||||
impl<P: InputComponent> ActionPath<P> {
|
||||
const fn new(input: InputId, comp: PathComponent, hand: Option<Hand>) -> Self {
|
||||
const fn new(input: InputId, comp: PathComponent) -> Self {
|
||||
Self {
|
||||
input,
|
||||
comp,
|
||||
hand,
|
||||
// hand,
|
||||
_data: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -37,21 +35,18 @@ impl<P: InputComponent> ActionPath<P> {
|
||||
UntypedActionPath {
|
||||
input: self.input,
|
||||
comp: self.comp,
|
||||
hand: self.hand,
|
||||
// hand: self.hand,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum Hand {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum PathComponent {
|
||||
Click,
|
||||
Touch,
|
||||
Value,
|
||||
Axes,
|
||||
X,
|
||||
Y,
|
||||
Pose,
|
||||
Haptic,
|
||||
}
|
||||
@@ -74,10 +69,16 @@ impl Value {
|
||||
const COMP: PathComponent = PathComponent::Value;
|
||||
}
|
||||
|
||||
pub struct Axes;
|
||||
pub struct X;
|
||||
|
||||
impl Axes {
|
||||
const COMP: PathComponent = PathComponent::Axes;
|
||||
impl X {
|
||||
const COMP: PathComponent = PathComponent::X;
|
||||
}
|
||||
|
||||
pub struct Y;
|
||||
|
||||
impl Y {
|
||||
const COMP: PathComponent = PathComponent::Y;
|
||||
}
|
||||
|
||||
pub struct Pose;
|
||||
@@ -105,11 +106,15 @@ impl InputComponent for Touch {
|
||||
}
|
||||
|
||||
impl InputComponent for Value {
|
||||
type PathType = bool;
|
||||
type PathType = f32;
|
||||
}
|
||||
|
||||
impl InputComponent for Axes {
|
||||
type PathType = Vec2;
|
||||
impl InputComponent for X {
|
||||
type PathType = f32;
|
||||
}
|
||||
|
||||
impl InputComponent for Y {
|
||||
type PathType = f32;
|
||||
}
|
||||
|
||||
impl InputComponent for Pose {
|
||||
@@ -129,85 +134,151 @@ macro_rules! input_ids {
|
||||
$(#[$inner_handed_meta:meta])*
|
||||
$inner_handed:ident {
|
||||
$(
|
||||
$comp_name_handed:ident,
|
||||
)*
|
||||
$(#[$comp_name_handed_meta:meta])*
|
||||
$comp_name_handed:ident
|
||||
),*
|
||||
$(,)?
|
||||
}
|
||||
)*
|
||||
}
|
||||
$(
|
||||
$(#[$dev_path_meta:meta])*
|
||||
$dev_path:ident {
|
||||
$(
|
||||
$(#[$inner_meta:meta])*
|
||||
$inner:ident {
|
||||
$(
|
||||
$comp_name:ident,
|
||||
$(#[$comp_name_meta:meta])*
|
||||
$comp_name:ident
|
||||
),*
|
||||
$(,)?
|
||||
}
|
||||
)*
|
||||
}
|
||||
)*
|
||||
) => {
|
||||
paste::paste! {
|
||||
const LEFT: bool = true;
|
||||
const RIGHT: bool = false;
|
||||
|
||||
$(
|
||||
#[$id_meta]
|
||||
)*
|
||||
paste::paste! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum $id {
|
||||
Left(Handed),
|
||||
Right(Handed),
|
||||
$(
|
||||
$inner,
|
||||
$(
|
||||
#[$dev_path_meta]
|
||||
)*
|
||||
$(
|
||||
[<$inner_handed Left>],
|
||||
[<$inner_handed Right>],
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub mod left {
|
||||
const LEFT: bool = true;
|
||||
$(
|
||||
pub type $inner_handed = super::$inner_handed<LEFT>;
|
||||
[<$dev_path:camel>](input::$dev_path::[<$dev_path:camel>]),
|
||||
)*
|
||||
}
|
||||
|
||||
pub mod right {
|
||||
const RIGHT: bool = false;
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum Handed {
|
||||
$(
|
||||
pub type $inner_handed = super::$inner_handed<RIGHT>;
|
||||
$(
|
||||
#[$inner_handed_meta]
|
||||
)*
|
||||
$inner_handed,
|
||||
)*
|
||||
}
|
||||
|
||||
pub mod input {
|
||||
use super::*;
|
||||
|
||||
pub(crate) mod private {
|
||||
$(
|
||||
$(
|
||||
#[$inner_handed_meta]
|
||||
)*
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct $inner_handed<const HAND: bool>;
|
||||
)*
|
||||
}
|
||||
|
||||
pub mod hand_left {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
$(
|
||||
#[$inner_handed_meta]
|
||||
)*
|
||||
pub struct $inner_handed<const HAND: bool>;
|
||||
impl $inner_handed<true> {
|
||||
paste::paste! {
|
||||
pub type $inner_handed = private::$inner_handed<LEFT>;
|
||||
|
||||
impl $inner_handed {
|
||||
$(
|
||||
pub const [<$comp_name_handed:snake:upper>]: ActionPath<$comp_name_handed> = ActionPath::<$comp_name_handed>::new($id::[<$inner_handed Left>], $comp_name_handed::COMP, Some(Hand::Left));
|
||||
$(
|
||||
#[$comp_name_handed_meta]
|
||||
)*
|
||||
pub const [<$comp_name_handed:snake:upper>]: ActionPath<$comp_name_handed> = ActionPath::<$comp_name_handed>::new($id::Left(Handed::$inner_handed), $comp_name_handed::COMP);
|
||||
)*
|
||||
}
|
||||
}
|
||||
impl $inner_handed<false> {
|
||||
paste::paste! {
|
||||
$(
|
||||
pub const [<$comp_name_handed:snake:upper>]: ActionPath<$comp_name_handed> = ActionPath::<$comp_name_handed>::new($id::[<$inner_handed Right>], $comp_name_handed::COMP, Some(Hand::Right));
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub mod hand_right {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
$(
|
||||
#[$inner_handed_meta]
|
||||
)*
|
||||
pub type $inner_handed = private::$inner_handed<RIGHT>;
|
||||
|
||||
impl $inner_handed {
|
||||
$(
|
||||
$(
|
||||
#[$comp_name_handed_meta]
|
||||
)*
|
||||
pub const [<$comp_name_handed:snake:upper>]: ActionPath<$comp_name_handed> = ActionPath::<$comp_name_handed>::new($id::Right(Handed::$inner_handed), $comp_name_handed::COMP);
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
$(
|
||||
#[$dev_path_meta]
|
||||
)*
|
||||
pub mod $dev_path {
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum [<$dev_path:camel>] {
|
||||
$(
|
||||
$(
|
||||
#[$inner_meta]
|
||||
)*
|
||||
$inner,
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
$(
|
||||
#[$inner_meta]
|
||||
)*
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct $inner;
|
||||
|
||||
impl $inner {
|
||||
paste::paste! {
|
||||
$(
|
||||
pub const [<$comp_name:snake:upper>]: ActionPath<$comp_name> = ActionPath::<$comp_name>::new($id::$inner, $comp_name::COMP, None);
|
||||
#[$inner_meta]
|
||||
)*
|
||||
impl $inner {
|
||||
$(
|
||||
$(
|
||||
#[$comp_name_meta]
|
||||
)*
|
||||
pub const [<$comp_name:snake:upper>]: ActionPath<$comp_name> = ActionPath::<$comp_name>::new($id::[<$dev_path:camel>]([<$dev_path:camel>]::$inner), $comp_name::COMP);
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
@@ -229,7 +300,8 @@ input_ids! {
|
||||
Click,
|
||||
}
|
||||
Thumbstick {
|
||||
Axes,
|
||||
X,
|
||||
Y,
|
||||
Click,
|
||||
Touch,
|
||||
}
|
||||
@@ -242,5 +314,19 @@ input_ids! {
|
||||
Value,
|
||||
Pose,
|
||||
}
|
||||
Output {
|
||||
Haptic,
|
||||
}
|
||||
}
|
||||
head {
|
||||
VolumeUp {
|
||||
Click,
|
||||
}
|
||||
VolumeDown {
|
||||
Click,
|
||||
}
|
||||
MuteMic {
|
||||
Click,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ pub struct SessionCreateInfo {
|
||||
pub texture_format: wgpu::TextureFormat,
|
||||
}
|
||||
|
||||
pub struct Bindings {}
|
||||
pub enum Bindings {
|
||||
OculusTouch,
|
||||
}
|
||||
|
||||
pub struct Haptic;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user