diff --git a/examples/xr.rs b/examples/xr.rs index fc10cd2..28dc988 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -2,9 +2,9 @@ use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::prelude::*; use bevy::transform::components::Transform; use bevy_openxr::input::XrInput; -use bevy_openxr::resources::XrFrameState; +use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::oculus_touch::OculusController; -use bevy_openxr::xr_input::{QuatConv, Vec3Conv}; +use bevy_openxr::xr_input::{Hand, QuatConv, Vec3Conv}; use bevy_openxr::DefaultXrPlugins; fn main() { @@ -61,29 +61,43 @@ fn hands( oculus_controller: Res, frame_state: Res, xr_input: Res, + instance: Res, + session: Res, ) { let mut func = || -> color_eyre::Result<()> { let frame_state = *frame_state.lock().unwrap(); - let right_controller = oculus_controller - .grip_space - .right - .relate(&xr_input.stage, frame_state.predicted_display_time)?; - let left_controller = oculus_controller - .grip_space - .left - .relate(&xr_input.stage, frame_state.predicted_display_time)?; + let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input); + + let right_controller = controller.grip_space(Hand::Right); + let left_controller = controller.grip_space(Hand::Left); + + let mut color = Color::YELLOW_GREEN; + if controller.a_button() { + color = Color::BLUE; + } + if controller.b_button() { + color = Color::RED; + } + if controller.trigger(Hand::Right) != 0.0 { + color = Color::rgb( + controller.trigger(Hand::Right), + 0.5, + controller.trigger(Hand::Right), + ); + } + gizmos.rect( right_controller.0.pose.position.to_vec3(), right_controller.0.pose.orientation.to_quat(), Vec2::new(0.05, 0.2), - Color::YELLOW_GREEN, + color, ); gizmos.rect( left_controller.0.pose.position.to_vec3(), left_controller.0.pose.orientation.to_quat(), Vec2::new(0.05, 0.2), - Color::YELLOW_GREEN, + color, ); Ok(()) }; diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 00cedf4..2a0a92d 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -6,8 +6,8 @@ use wgpu::Instance; use crate::input::XrInput; use crate::resources::{ - XrEnvironmentBlendMode, XrFrameState, XrFrameWaiter, XrInstance, XrSession, XrSessionRunning, - XrSwapchain, XrViews, XrResolution, XrFormat, + XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, XrInstance, XrResolution, + XrSession, XrSessionRunning, XrSwapchain, XrViews, }; use openxr as xr; @@ -41,4 +41,4 @@ pub fn xr_entry() -> xr::Entry { #[cfg(not(feature = "linked"))] let entry = unsafe { xr::Entry::load().unwrap() }; entry -} \ No newline at end of file +} diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index e8f4707..e7e0e77 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -13,8 +13,8 @@ use wgpu::Instance; use crate::input::XrInput; use crate::resources::{ - Swapchain, SwapchainInner, XrEnvironmentBlendMode, XrFrameState, XrFrameWaiter, XrInstance, - XrSession, XrSessionRunning, XrSwapchain, XrViews, XrResolution, XrFormat, + Swapchain, SwapchainInner, XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, + XrInstance, XrResolution, XrSession, XrSessionRunning, XrSwapchain, XrViews, }; use crate::VIEW_TYPE; @@ -386,7 +386,8 @@ pub fn initialize_xr_graphics( predicted_display_time: xr::Time::from_nanos(1), predicted_display_period: xr::Duration::from_nanos(1), should_render: true, - }).into(), + }) + .into(), )) } diff --git a/src/input.rs b/src/input.rs index 411cfbc..78cad05 100644 --- a/src/input.rs +++ b/src/input.rs @@ -51,8 +51,8 @@ impl XrInput { // )?; let stage = session.create_reference_space(xr::ReferenceSpaceType::STAGE, xr::Posef::IDENTITY)?; - let head = - session.create_reference_space(xr::ReferenceSpaceType::VIEW, xr::Posef::IDENTITY) + let head = session + .create_reference_space(xr::ReferenceSpaceType::VIEW, xr::Posef::IDENTITY) .unwrap(); //session.attach_action_sets(&[&action_set])?; //session.attach_action_sets(&[])?; diff --git a/src/resources.rs b/src/resources.rs index acf9ea4..2715027 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -136,7 +136,7 @@ impl SwapchainInner { let swapchain = self.handle.lock().unwrap(); if views.len() == 0 { warn!("views are len of 0"); - return Ok(()) + return Ok(()); } self.stream.lock().unwrap().end( predicted_display_time, diff --git a/src/xr_input/mod.rs b/src/xr_input/mod.rs index e6fe3c5..4623e20 100644 --- a/src/xr_input/mod.rs +++ b/src/xr_input/mod.rs @@ -6,15 +6,11 @@ use crate::resources::XrSession; use crate::xr_begin_frame; use crate::xr_input::controllers::XrControllerType; use crate::xr_input::oculus_touch::{setup_oculus_controller, ActionSets}; -use crate::xr_input::xr_camera::{ - xr_camera_head_sync, Eye, XRProjection, XrCameraBundle, -}; +use crate::xr_input::xr_camera::{xr_camera_head_sync, Eye, XRProjection, XrCameraBundle}; use bevy::app::{App, PostUpdate, Startup}; use bevy::log::warn; use bevy::prelude::IntoSystemConfigs; -use bevy::prelude::{ - Commands, Plugin, PreUpdate, Quat, Res, Vec3, -}; +use bevy::prelude::{Commands, Plugin, PreUpdate, Quat, Res, Vec3}; use bevy::render::camera::CameraProjectionPlugin; use bevy::render::view::{update_frusta, VisibilitySystems}; use bevy::transform::TransformSystem; @@ -23,6 +19,11 @@ use bevy::transform::TransformSystem; pub struct OpenXrInput { pub controller_type: XrControllerType, } +#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq)] +pub enum Hand { + Left, + Right, +} impl OpenXrInput { pub fn new(controller_type: XrControllerType) -> Self { Self { controller_type } diff --git a/src/xr_input/oculus_touch.rs b/src/xr_input/oculus_touch.rs index 1a7216c..25038b4 100644 --- a/src/xr_input/oculus_touch.rs +++ b/src/xr_input/oculus_touch.rs @@ -1,9 +1,14 @@ +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, Resource}; -use openxr::{Action, ActionSet, AnyGraphics, Binding, FrameState, Haptic, Instance, Posef, Session, Space}; -use openxr::sys::Instance; -use crate::input::XrInput; +use openxr::{ + Action, ActionSet, AnyGraphics, Binding, FrameState, Haptic, Instance, Path, Posef, Session, + Space, SpaceLocation, SpaceVelocity, +}; +use std::cell::OnceCell; +use std::sync::OnceLock; pub fn setup_oculus_controller( mut commands: Commands, @@ -35,8 +40,195 @@ pub struct OculusControllerRef<'a> { xr_input: &'a XrInput, } +static RIGHT_SUBACTION_PATH: OnceLock = OnceLock::new(); +static LEFT_SUBACTION_PATH: OnceLock = 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.left.relate( + &self.xr_input.stage, + self.frame_state.predicted_display_time, + ), + Hand::Right => self.oculus_controller.grip_space.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.left.relate( + &self.xr_input.stage, + self.frame_state.predicted_display_time, + ), + Hand::Right => self.oculus_controller.aim_space.left.relate( + &self.xr_input.stage, + self.frame_state.predicted_display_time, + ), + } + .unwrap() + } + pub fn squeeze(&self, hand: Hand) -> f32 { + let action = &self.oculus_controller.squeeze; + action + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state + } + pub fn trigger(&self, hand: Hand) -> f32 { + self.oculus_controller + .trigger + .inner + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state + } + pub fn trigger_touched(&self, hand: Hand) -> bool { + self.oculus_controller + .trigger + .touch + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state + } + pub fn x_button(&self) -> bool { + self.oculus_controller + .x_button + .inner + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn x_button_touched(&self) -> bool { + self.oculus_controller + .x_button + .touch + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn y_button(&self) -> bool { + self.oculus_controller + .y_button + .inner + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn y_button_touched(&self) -> bool { + self.oculus_controller + .y_button + .touch + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn menu_button(&self) -> bool { + self.oculus_controller + .menu_button + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn a_button(&self) -> bool { + self.oculus_controller + .a_button + .inner + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn a_button_touched(&self) -> bool { + self.oculus_controller + .a_button + .touch + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn b_button(&self) -> bool { + self.oculus_controller + .b_button + .inner + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn b_button_touched(&self) -> bool { + self.oculus_controller + .b_button + .touch + .state(&self.session, Path::NULL) + .unwrap() + .current_state + } + pub fn thumbstick_touch(&self, hand: Hand) -> bool { + self.oculus_controller + .thumbstick_touch + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state + } + pub fn thumbstick(&self, hand: Hand) -> Thumbstick { + Thumbstick { + x: self + .oculus_controller + .thumbstick_x + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state, + y: self + .oculus_controller + .thumbstick_y + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state, + click: self + .oculus_controller + .thumbstick_click + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state, + } + } + pub fn thumbrest_touch(&self, hand: Hand) -> bool { + self.oculus_controller + .thumbrest_touch + .state(&self.session, subaction_path(hand)) + .unwrap() + .current_state + } +} + +#[derive(Copy, Clone, Debug)] +pub struct Thumbstick { + x: f32, + y: f32, + click: bool, +} + impl OculusController { - pub fn get_ref(&self, instance: &Instance, session: &Session, frame_state: &FrameState, xr_input: &XrInput) -> OculusControllerRef { + pub fn get_ref<'a>( + &'a self, + instance: &'a Instance, + session: &'a Session, + frame_state: &'a FrameState, + xr_input: &'a XrInput, + ) -> OculusControllerRef { OculusControllerRef { oculus_controller: self, instance, @@ -75,6 +267,7 @@ impl OculusController { ) -> anyhow::Result { let action_set = instance.create_action_set("oculus_input", "Oculus Touch Controller Input", 0)?; + init_subaction_path(&instance); let left_path = instance.string_to_path("/user/hand/left").unwrap(); let right_path = instance.string_to_path("/user/hand/right").unwrap(); let hands = [left_path, right_path];