diff --git a/src/chaperone.rs b/src/chaperone.rs new file mode 100644 index 0000000..c8b377e --- /dev/null +++ b/src/chaperone.rs @@ -0,0 +1,186 @@ +use std::convert::From; + +use openvr_sys as sys; + +use {Chaperone, HmdColor_t, HmdQuad_t, HmdVector3_t}; + +/// Chaperone warning states +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum ChaperoneCalibrationWarningState { + Warning, + BaseStationMayHaveMoved, + BaseStationRemoved, + SeatedBoundsInvalid, + Unknown(u32), +} + +impl From for ChaperoneCalibrationWarningState { + fn from(state: sys::ChaperoneCalibrationState) -> Self { + use self::ChaperoneCalibrationWarningState::*; + match state { + sys::ChaperoneCalibrationState_Warning => Warning, + sys::ChaperoneCalibrationState_Warning_BaseStationMayHaveMoved => { + BaseStationMayHaveMoved + } + sys::ChaperoneCalibrationState_Warning_BaseStationRemoved => BaseStationRemoved, + sys::ChaperoneCalibrationState_Warning_SeatedBoundsInvalid => SeatedBoundsInvalid, + _ => Unknown(state as u32), + } + } +} + +/// Chaperone error states +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum ChaperoneCalibrationErrorState { + Error, + BaseStationUninitialized, + BaseStationConflict, + PlayAreaInvalid, + CollisionBoundsInvalid, + Unknown(u32), +} + +impl From for ChaperoneCalibrationErrorState { + fn from(state: sys::ChaperoneCalibrationState) -> Self { + use self::ChaperoneCalibrationErrorState::*; + match state { + sys::ChaperoneCalibrationState_Error => Error, + sys::ChaperoneCalibrationState_Error_BaseStationUninitialized => { + BaseStationUninitialized + } + sys::ChaperoneCalibrationState_Error_BaseStationConflict => BaseStationConflict, + sys::ChaperoneCalibrationState_Error_PlayAreaInvalid => CollisionBoundsInvalid, + _ => Unknown(state as u32), + } + } +} + +/// State of Chaperone calibration. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum ChaperoneCalibrationState { + Ok, + Warning(ChaperoneCalibrationWarningState), + Error(ChaperoneCalibrationErrorState), + Unknown(u32), +} + +impl From for ChaperoneCalibrationState { + fn from(state: sys::ChaperoneCalibrationState) -> Self { + use self::ChaperoneCalibrationState::*; + match state { + 1 => Ok, + 100...199 => Warning(ChaperoneCalibrationWarningState::from(state)), + 200...299 => Error(ChaperoneCalibrationErrorState::from(state)), + _ => Unknown(state as u32), + } + } +} + +impl Chaperone { + /// Get the current state of Chaperone calibration. + /// This state can change at any time during a session due to physical base station changes. + /// (NOTE: Some of these error codes are never returned as implementation for the error states + /// is still a work in progress.) + pub fn get_calibration_state(&self) -> ChaperoneCalibrationState { + unsafe { self.0.GetCalibrationState.unwrap()() }.into() + } + + /// Returns the width and depth of the Play Area. + pub fn get_play_area_size(&self) -> Option<(f32, f32)> { + let mut x: f32 = 0.0; + let mut z: f32 = 0.0; + let is_ok = unsafe { self.0.GetPlayAreaSize.unwrap()(&mut x, &mut z) }; + if is_ok { + Some((x, z)) + } else { + None + } + } + + /// Returns the 4 corner positions of the PlayArea. + pub fn get_play_area_rect(&self) -> Option { + let mut play_area_rect = HmdQuad_t { + vCorners: [HmdVector3_t { v: [0.0; 3] }; 4], + }; + let is_ok = unsafe { self.0.GetPlayAreaRect.unwrap()(&mut play_area_rect) }; + if is_ok { + Some(play_area_rect) + } else { + None + } + } + + // Do not understand what this does + /// Reload chaperone info + fn reload_info(&mut self) { + unsafe { self.0.ReloadInfo.unwrap()() }; + } + + // Do not understand what this does + /// Set scene color + fn set_scene_color(&mut self, color: HmdColor_t) { + unsafe { self.0.SetSceneColor.unwrap()(color) }; + } + + /// Are chaperone bounds visible? + pub fn are_bounds_visible(&self) -> bool { + unsafe { self.0.AreBoundsVisible.unwrap()() } + } + + /// Set chaperone bounds to always be visible. If set to false, chaperone + /// bounds will only show when near the edge. + /// + /// Caution: this change is persistent, even after your program exits. + pub fn force_bounds_visible(&self, force: bool) { + unsafe { self.0.ForceBoundsVisible.unwrap()(force) }; + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn convert_ChaperoneCalibrationState() { + assert_eq!( + ChaperoneCalibrationState::from(sys::ChaperoneCalibrationState_OK), + ChaperoneCalibrationState::Ok + ); + assert_eq!( + ChaperoneCalibrationState::from(sys::ChaperoneCalibrationState_Warning), + ChaperoneCalibrationState::Warning(ChaperoneCalibrationWarningState::Warning) + ); + assert_eq!( + ChaperoneCalibrationState::from(199), + ChaperoneCalibrationState::Warning(ChaperoneCalibrationWarningState::Unknown(199)) + ); + assert_eq!( + ChaperoneCalibrationState::from( + sys::ChaperoneCalibrationState_Warning_BaseStationRemoved + ), + ChaperoneCalibrationState::Warning( + ChaperoneCalibrationWarningState::BaseStationRemoved + ) + ); + assert_eq!( + ChaperoneCalibrationState::from(sys::ChaperoneCalibrationState_Error), + ChaperoneCalibrationState::Error(ChaperoneCalibrationErrorState::Error) + ); + assert_eq!( + ChaperoneCalibrationState::from( + sys::ChaperoneCalibrationState_Error_BaseStationUninitialized + ), + ChaperoneCalibrationState::Error( + ChaperoneCalibrationErrorState::BaseStationUninitialized + ) + ); + assert_eq!( + ChaperoneCalibrationState::from(299), + ChaperoneCalibrationState::Error(ChaperoneCalibrationErrorState::Unknown(299)) + ); + assert_eq!( + ChaperoneCalibrationState::from(2), + ChaperoneCalibrationState::Unknown(2) + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 081299a..80e8543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ mod tracking; pub mod system; pub mod compositor; pub mod render_models; +pub mod chaperone; pub mod property; pub use tracking::*; @@ -22,6 +23,9 @@ pub use sys::VkPhysicalDevice_T; pub use sys::VkDevice_T; pub use sys::VkInstance_T; pub use sys::VkQueue_T; +pub use sys::HmdQuad_t; +pub use sys::HmdVector3_t; +pub use sys::HmdColor_t; static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; @@ -55,6 +59,7 @@ pub unsafe fn init(ty: ApplicationType) -> Result { pub struct System(&'static sys::VR_IVRSystem_FnTable); pub struct Compositor(&'static sys::VR_IVRCompositor_FnTable); pub struct RenderModels(&'static sys::VR_IVRRenderModels_FnTable); +pub struct Chaperone(&'static sys::VR_IVRChaperone_FnTable); /// Entry points into OpenVR. /// @@ -78,6 +83,7 @@ impl Context { pub fn system(&self) -> Result { load(sys::IVRSystem_Version).map(|x| unsafe { System(&*x) }) } pub fn compositor(&self) -> Result { load(sys::IVRCompositor_Version).map(|x| unsafe { Compositor(&*x) }) } pub fn render_models(&self) -> Result { load(sys::IVRRenderModels_Version).map(|x| unsafe { RenderModels(&*x) }) } + pub fn chaperone(&self) -> Result { load(sys::IVRChaperone_Version).map(|x| unsafe { Chaperone(&*x) }) } } impl Drop for Context {