diff --git a/Cargo.toml b/Cargo.toml index d16f89d..21422fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ repository = "https://github.com/rust-openvr/rust-openvr" description = "A safe binding for openvr." [dependencies] -openvr_sys = { git = "https://github.com/Ralith/rust-openvr-sys.git", branch = "update" } +openvr_sys = { git = "https://github.com/Ralith/rust-openvr-sys.git", branch = "enum-rename" } [dev_dependencies] glium = "0.14.0" diff --git a/examples/test.rs b/examples/test.rs index bc464e5..00bf5b6 100644 --- a/examples/test.rs +++ b/examples/test.rs @@ -16,7 +16,7 @@ fn print_matrix_4x3(offset: u32, mat: [[f32; 4]; 3]) { } fn main() { - let context = match openvr::init(openvr::ApplicationType::Other) { + let context = match unsafe { openvr::init(openvr::ApplicationType::Other) } { Ok(ivr) => ivr, Err(err) => { println!("Failed to initialize openvr {:?}", err); diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 82d5bd0..5967974 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -21,27 +21,14 @@ use super::*; impl<'a> Compositor<'a> { pub fn vulkan_instance_extensions_required(&self) -> Vec { - let temp = unsafe { - let n = self.0.GetVulkanInstanceExtensionsRequired.unwrap()(ptr::null_mut(), 0); - let mut buffer: Vec = Vec::new(); - buffer.resize(n as usize, mem::uninitialized()); - (self.0.GetVulkanInstanceExtensionsRequired.unwrap())(buffer.as_mut_ptr() as *mut i8, n); - buffer.truncate((n-1) as usize); // Strip trailing null - buffer - }; - temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect() + let temp = unsafe { get_string(|ptr, n| self.0.GetVulkanInstanceExtensionsRequired.unwrap()(ptr, n)) }.unwrap(); + temp.as_bytes().split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect() } - pub fn vulkan_device_extensions_required(&self, physical_device: *mut VkPhysicalDevice_T) -> Vec { - let temp = unsafe { - let n = self.0.GetVulkanDeviceExtensionsRequired.unwrap()(physical_device, ptr::null_mut(), 0); - let mut buffer: Vec = Vec::new(); - buffer.resize(n as usize, mem::uninitialized()); - (self.0.GetVulkanDeviceExtensionsRequired.unwrap())(physical_device as *mut _, buffer.as_mut_ptr() as *mut i8, n); - buffer.truncate((n-1) as usize); // Strip trailing null - buffer - }; - temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect() + /// Safety: physical_device must be a valid VkPhysicalDevice + pub unsafe fn vulkan_device_extensions_required(&self, physical_device: *mut VkPhysicalDevice_T) -> Vec { + let temp = get_string(|ptr, n| self.0.GetVulkanDeviceExtensionsRequired.unwrap()(physical_device, ptr, n)).unwrap(); + temp.as_bytes().split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect() } /// Sets tracking space returned by WaitGetPoses @@ -58,7 +45,7 @@ impl<'a> Compositor<'a> { let mut result: WaitPoses = mem::uninitialized(); let e = self.0.WaitGetPoses.unwrap()(result.render.as_mut().as_mut_ptr() as *mut _, result.render.len() as u32, result.game.as_mut().as_mut_ptr() as *mut _, result.game.len() as u32); - if e == sys::EVRCompositorError_EVRCompositorError_VRCompositorError_None { + if e == sys::EVRCompositorError_VRCompositorError_None { Ok(result) } else { Err(CompositorError(e)) @@ -69,12 +56,16 @@ impl<'a> Compositor<'a> { /// Display the supplied texture for the next frame. /// /// If `bounds` is None, the entire texture will be used. Lens distortion is handled by the OpenVR implementation. - pub fn submit(&self, eye: Eye, texture: &Texture, bounds: Option<&texture::Bounds>) -> Result<(), CompositorError> { + /// + /// # Safety + /// + /// The handles you supply must be valid and comply with the graphics API's synchronization requirements. + pub unsafe fn submit(&self, eye: Eye, texture: &Texture, bounds: Option<&texture::Bounds>) -> Result<(), CompositorError> { use self::texture::Handle::*; let flags = match texture.handle { - Vulkan(_) => sys::EVRSubmitFlags_EVRSubmitFlags_Submit_Default, - OpenGLTexture(_) => sys::EVRSubmitFlags_EVRSubmitFlags_Submit_Default, - OpenGLRenderBuffer(_) => sys::EVRSubmitFlags_EVRSubmitFlags_Submit_GlRenderBuffer, + Vulkan(_) => sys::EVRSubmitFlags_Submit_Default, + OpenGLTexture(_) => sys::EVRSubmitFlags_Submit_Default, + OpenGLRenderBuffer(_) => sys::EVRSubmitFlags_Submit_GlRenderBuffer, }; let texture = sys::Texture_t { handle: match texture.handle { @@ -83,25 +74,32 @@ impl<'a> Compositor<'a> { OpenGLRenderBuffer(x) => x as *mut _, }, eType: match texture.handle { - Vulkan(_) => sys::ETextureType_ETextureType_TextureType_Vulkan, - OpenGLTexture(_) => sys::ETextureType_ETextureType_TextureType_OpenGL, - OpenGLRenderBuffer(_) => sys::ETextureType_ETextureType_TextureType_OpenGL, + Vulkan(_) => sys::ETextureType_TextureType_Vulkan, + OpenGLTexture(_) => sys::ETextureType_TextureType_OpenGL, + OpenGLRenderBuffer(_) => sys::ETextureType_TextureType_OpenGL, }, eColorSpace: texture.color_space as sys::EColorSpace, }; - let e = unsafe { - self.0.Submit.unwrap()(eye as sys::EVREye, - &texture as *const _ as *mut _, - bounds.map(|x| x as *const _ as *mut texture::Bounds as *mut _).unwrap_or(ptr::null_mut()), - flags) - }; - if e == sys::EVRCompositorError_EVRCompositorError_VRCompositorError_None { + let e = self.0.Submit.unwrap()( + eye as sys::EVREye, + &texture as *const _ as *mut _, + bounds.map(|x| x as *const _ as *mut texture::Bounds as *mut _).unwrap_or(ptr::null_mut()), + flags); + if e == sys::EVRCompositorError_VRCompositorError_None { Ok(()) } else { Err(CompositorError(e)) } } + /// Call immediately after presenting your app's window (i.e. companion window) to unblock the compositor. + /// + /// This is an optional call, which only needs to be used if you can't instead call `wait_get_poses` immediately + /// after submitting frames. For example, if your engine's render and game loop are not on separate threads, or + /// blocking the render thread until 3ms before the next vsync would introduce a deadlock of some sort. This + /// function tells the compositor that you have finished all rendering after having Submitted buffers for both eyes, + /// and it is free to start its rendering work. This should only be called from the same thread you are rendering + /// on. pub fn post_present_handoff(&self) { unsafe { (self.0.PostPresentHandoff.unwrap())() }; } @@ -110,6 +108,13 @@ impl<'a> Compositor<'a> { pub fn is_fullscreen(&self) -> bool { unsafe { (self.0.IsFullscreen.unwrap())() } } + + /// Clears the frame that was sent with the last call to `submit. + /// + /// This will cause the compositor to show the grid until `submit` is called again. + pub fn clear_last_submitted_frame(&self) { + unsafe { self.0.ClearLastSubmittedFrame.unwrap()() } + } } #[derive(Debug, Copy, Clone)] @@ -126,16 +131,17 @@ pub struct CompositorError(sys::EVRCompositorError); pub mod compositor_error { use super::*; - pub const REQUEST_FAILED: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_RequestFailed); - pub const INCOMPATIBLE_VERSION: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_IncompatibleVersion); - pub const DO_NOT_HAVE_FOCUS: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_DoNotHaveFocus); - pub const INVALID_TEXTURE: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_InvalidTexture); - pub const IS_NOT_SCENE_APPLICATION: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_IsNotSceneApplication); - pub const TEXTURE_IS_ON_WRONG_DEVICE: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_TextureIsOnWrongDevice); - pub const TEXTURE_USES_UNSUPPORTED_FORMAT: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_TextureUsesUnsupportedFormat); - pub const SHARED_TEXTURES_NOT_SUPPORTED: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_SharedTexturesNotSupported); - pub const INDEX_OUT_OF_RANGE: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_IndexOutOfRange); - pub const ALREADY_SUBMITTED: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_AlreadySubmitted); + pub const REQUEST_FAILED: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_RequestFailed); + pub const INCOMPATIBLE_VERSION: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_IncompatibleVersion); + pub const DO_NOT_HAVE_FOCUS: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_DoNotHaveFocus); + pub const INVALID_TEXTURE: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_InvalidTexture); + pub const IS_NOT_SCENE_APPLICATION: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_IsNotSceneApplication); + pub const TEXTURE_IS_ON_WRONG_DEVICE: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_TextureIsOnWrongDevice); + pub const TEXTURE_USES_UNSUPPORTED_FORMAT: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_TextureUsesUnsupportedFormat); + pub const SHARED_TEXTURES_NOT_SUPPORTED: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_SharedTexturesNotSupported); + pub const INDEX_OUT_OF_RANGE: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_IndexOutOfRange); + pub const ALREADY_SUBMITTED: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_AlreadySubmitted); + pub const INVALID_BOUNDS: CompositorError = CompositorError(sys::EVRCompositorError_VRCompositorError_InvalidBounds); } impl fmt::Debug for CompositorError { @@ -158,6 +164,7 @@ impl error::Error for CompositorError { SHARED_TEXTURES_NOT_SUPPORTED => "SHARED_TEXTURES_NOT_SUPPORTED", INDEX_OUT_OF_RANGE => "INDEX_OUT_OF_RANGE", ALREADY_SUBMITTED => "ALREADY_SUBMITTED", + INVALID_BOUNDS => "INVALID_BOUNDS", _ => "UNKNOWN", } } @@ -168,8 +175,3 @@ impl fmt::Display for CompositorError { f.pad(error::Error::description(self)) } } - -pub use sys::VkPhysicalDevice_T; -pub use sys::VkDevice_T; -pub use sys::VkInstance_T; -pub use sys::VkQueue_T; diff --git a/src/compositor/texture.rs b/src/compositor/texture.rs index 2ae3cdf..b45439e 100644 --- a/src/compositor/texture.rs +++ b/src/compositor/texture.rs @@ -39,7 +39,7 @@ pub enum Handle { #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ColorSpace { - Auto = sys::EColorSpace_EColorSpace_ColorSpace_Auto as isize, - Gamma = sys::EColorSpace_EColorSpace_ColorSpace_Gamma as isize, - Linear = sys::EColorSpace_EColorSpace_ColorSpace_Linear as isize, + Auto = sys::EColorSpace_ColorSpace_Auto as isize, + Gamma = sys::EColorSpace_ColorSpace_Gamma as isize, + Linear = sys::EColorSpace_ColorSpace_Linear as isize, } diff --git a/src/lib.rs b/src/lib.rs index e4bb737..f413249 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,39 +1,52 @@ extern crate openvr_sys; use std::sync::atomic::{Ordering, AtomicBool, ATOMIC_BOOL_INIT}; -use std::{fmt, error}; -use std::ffi::CStr; +use std::{fmt, error, ptr, mem}; +use std::ffi::{CStr, CString}; +use std::cell::Cell; use openvr_sys as sys; mod tracking; -mod system; -mod compositor; +pub mod system; +pub mod compositor; +pub mod render_models; +pub mod property; pub use tracking::*; +pub use sys::VkPhysicalDevice_T; +pub use sys::VkDevice_T; +pub use sys::VkInstance_T; +pub use sys::VkQueue_T; + static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; /// Initialize OpenVR /// /// # Panics +/// /// When the library has already been initialized -pub fn init(ty: ApplicationType) -> Result { +/// +/// # Safety +/// +/// The `Context` MUST be dropped or shut down with `Context::shutdown` before shutting down the graphics API. +pub unsafe fn init(ty: ApplicationType) -> Result { if INITIALIZED.swap(true, Ordering::Acquire) { panic!("OpenVR has already been initialized!"); } - let mut error = sys::EVRInitError_EVRInitError_VRInitError_None; - unsafe { sys::VR_InitInternal(&mut error, ty as sys::EVRApplicationType) }; - if error != sys::EVRInitError_EVRInitError_VRInitError_None { + let mut error = sys::EVRInitError_VRInitError_None; + sys::VR_InitInternal(&mut error, ty as sys::EVRApplicationType); + if error != sys::EVRInitError_VRInitError_None { return Err(InitError(error)); } - if !unsafe { sys::VR_IsInterfaceVersionValid(sys::IVRSystem_Version.as_ptr() as *const i8) } { - unsafe { sys::VR_ShutdownInternal() } - return Err(InitError(sys::EVRInitError_EVRInitError_VRInitError_Init_InterfaceNotFound)); + if !sys::VR_IsInterfaceVersionValid(sys::IVRSystem_Version.as_ptr() as *const i8) { + sys::VR_ShutdownInternal(); + return Err(InitError(sys::EVRInitError_VRInitError_Init_InterfaceNotFound)); } - Ok(Context {}) + Ok(Context { live: Cell::new(true) }) } pub struct System<'a>(&'a sys::VR_IVRSystem_FnTable); @@ -43,15 +56,15 @@ pub struct RenderModels<'a>(&'a sys::VR_IVRRenderModels_FnTable); /// Entry points into OpenVR. /// /// At most one of this object may exist at a time. -pub struct Context {} +pub struct Context { live: Cell } fn load(suffix: &[u8]) -> Result<*const T, InitError> { let mut magic = Vec::from(b"FnTable:".as_ref()); magic.extend(suffix); - let mut error = sys::EVRInitError_EVRInitError_VRInitError_None; + let mut error = sys::EVRInitError_VRInitError_None; let result = unsafe { sys::VR_GetGenericInterface(magic.as_ptr() as *const i8, &mut error) }; - if error != sys::EVRInitError_EVRInitError_VRInitError_None { - return Err(InitError(sys::EVRInitError_EVRInitError_VRInitError_Init_InterfaceNotFound)); + if error != sys::EVRInitError_VRInitError_None { + return Err(InitError(sys::EVRInitError_VRInitError_Init_InterfaceNotFound)); } Ok(result as *const T) } @@ -64,31 +77,47 @@ impl Context { impl Drop for Context { fn drop(&mut self) { - unsafe { sys::VR_ShutdownInternal() } - INITIALIZED.store(false, Ordering::Release); + unsafe { self.shutdown() } + } +} + +impl Context { + /// Shut down OpenVR. Repeated calls are safe. + /// + /// Called implicitly by `Context::drop`. This MUST be called before shutting down the graphics API, or OpenVR may + /// invoke undefined behavior. + /// + /// # Safety + /// + /// No OpenVR calls may be made after this has been called unless a new `Context` is subsequently constructed. + pub unsafe fn shutdown(&self) { + if self.live.replace(false) { + sys::VR_ShutdownInternal(); + INITIALIZED.store(false, Ordering::Release); + } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ApplicationType { /// Some other kind of application that isn't covered by the other entries - Other = sys::EVRApplicationType_EVRApplicationType_VRApplication_Other as isize, + Other = sys::EVRApplicationType_VRApplication_Other as isize, /// Application will submit 3D frames - Scene = sys::EVRApplicationType_EVRApplicationType_VRApplication_Scene as isize, + Scene = sys::EVRApplicationType_VRApplication_Scene as isize, /// Application only interacts with overlays - Overlay = sys::EVRApplicationType_EVRApplicationType_VRApplication_Overlay as isize, + Overlay = sys::EVRApplicationType_VRApplication_Overlay as isize, /// Application should not start SteamVR if it's not already running, and should not keep it running if everything /// else quits. - Background = sys::EVRApplicationType_EVRApplicationType_VRApplication_Background as isize, + Background = sys::EVRApplicationType_VRApplication_Background as isize, /// Init should not try to load any drivers. The application needs access to utility interfaces (like IVRSettings /// and IVRApplications) but not hardware. - Utility = sys::EVRApplicationType_EVRApplicationType_VRApplication_Utility as isize, + Utility = sys::EVRApplicationType_VRApplication_Utility as isize, /// Reserved for vrmonitor - VRMonitor = sys::EVRApplicationType_EVRApplicationType_VRApplication_VRMonitor as isize, + VRMonitor = sys::EVRApplicationType_VRApplication_VRMonitor as isize, /// Reserved for Steam - SteamWatchdog = sys::EVRApplicationType_EVRApplicationType_VRApplication_SteamWatchdog as isize, + SteamWatchdog = sys::EVRApplicationType_VRApplication_SteamWatchdog as isize, /// Start up SteamVR - Bootstrapper = sys::EVRApplicationType_EVRApplicationType_VRApplication_Bootstrapper as isize, + Bootstrapper = sys::EVRApplicationType_VRApplication_Bootstrapper as isize, } #[derive(Copy, Clone)] @@ -120,6 +149,57 @@ impl fmt::Display for InitError { #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Eye { - Left = sys::EVREye_EVREye_Eye_Left as isize, - Right = sys::EVREye_EVREye_Eye_Right as isize, + Left = sys::EVREye_Eye_Left as isize, + Right = sys::EVREye_Eye_Right as isize, +} + +/// Helper to call OpenVR functions that return strings +unsafe fn get_string u32>(mut f: F) -> Option { + let n = f(ptr::null_mut(), 0); + if n == 0 { return None } + let mut storage = Vec::new(); + storage.reserve_exact(n as usize); + storage.resize(n as usize, mem::uninitialized()); + let n_ = f(storage.as_mut_ptr() as *mut _, n); + assert!(n == n_); + storage.truncate((n-1) as usize); // Strip trailing null + Some(CString::from_vec_unchecked(storage)) +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ControllerAxis { + pub x: f32, + pub y: f32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ControllerState { + pub packet_num: u32, + pub button_pressed: u64, + pub button_touched: u64, + pub axis: [ControllerAxis; 5], +} + +pub mod button_id { + use super::sys; + pub const SYSTEM: sys::EVRButtonId = sys::EVRButtonId_k_EButton_System; + pub const APPLICATION_MENU: sys::EVRButtonId = sys::EVRButtonId_k_EButton_ApplicationMenu; + pub const GRIP: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Grip; + pub const DPAD_LEFT: sys::EVRButtonId = sys::EVRButtonId_k_EButton_DPad_Left; + pub const DPAD_UP: sys::EVRButtonId = sys::EVRButtonId_k_EButton_DPad_Up; + pub const DPAD_RIGHT: sys::EVRButtonId = sys::EVRButtonId_k_EButton_DPad_Right; + pub const DPAD_DOWN: sys::EVRButtonId = sys::EVRButtonId_k_EButton_DPad_Down; + pub const A: sys::EVRButtonId = sys::EVRButtonId_k_EButton_A; + pub const PROXIMITY_SENSOR: sys::EVRButtonId = sys::EVRButtonId_k_EButton_ProximitySensor; + pub const AXIS0: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Axis0; + pub const AXIS1: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Axis1; + pub const AXIS2: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Axis2; + pub const AXIS3: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Axis3; + pub const AXIS4: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Axis4; + pub const STEAM_VR_TOUCHPAD: sys::EVRButtonId = sys::EVRButtonId_k_EButton_SteamVR_Touchpad; + pub const STEAM_VR_TRIGGER: sys::EVRButtonId = sys::EVRButtonId_k_EButton_SteamVR_Trigger; + pub const DASHBOARD_BACK: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Dashboard_Back; + pub const MAX: sys::EVRButtonId = sys::EVRButtonId_k_EButton_Max; } diff --git a/src/property.rs b/src/property.rs new file mode 100644 index 0000000..25c7f38 --- /dev/null +++ b/src/property.rs @@ -0,0 +1,123 @@ +#![allow(non_upper_case_globals)] + +use openvr_sys as sys; +use super::TrackedDeviceProperty; + +pub const Invalid: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Invalid; +pub const TrackingSystemName_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_TrackingSystemName_String; +pub const ModelNumber_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ModelNumber_String; +pub const SerialNumber_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_SerialNumber_String; +pub const RenderModelName_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_RenderModelName_String; +pub const WillDriftInYaw_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_WillDriftInYaw_Bool; +pub const ManufacturerName_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ManufacturerName_String; +pub const TrackingFirmwareVersion_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_TrackingFirmwareVersion_String; +pub const HardwareRevision_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HardwareRevision_String; +pub const AllWirelessDongleDescriptions_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_AllWirelessDongleDescriptions_String; +pub const ConnectedWirelessDongle_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ConnectedWirelessDongle_String; +pub const DeviceIsWireless_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DeviceIsWireless_Bool; +pub const DeviceIsCharging_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DeviceIsCharging_Bool; +pub const DeviceBatteryPercentage_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DeviceBatteryPercentage_Float; +pub const StatusDisplayTransform_Matrix34: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_StatusDisplayTransform_Matrix34; +pub const Firmware_UpdateAvailable_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Firmware_UpdateAvailable_Bool; +pub const Firmware_ManualUpdate_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Firmware_ManualUpdate_Bool; +pub const Firmware_ManualUpdateURL_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Firmware_ManualUpdateURL_String; +pub const HardwareRevision_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HardwareRevision_Uint64; +pub const FirmwareVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_FirmwareVersion_Uint64; +pub const FPGAVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_FPGAVersion_Uint64; +pub const VRCVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_VRCVersion_Uint64; +pub const RadioVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_RadioVersion_Uint64; +pub const DongleVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DongleVersion_Uint64; +pub const BlockServerShutdown_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_BlockServerShutdown_Bool; +pub const CanUnifyCoordinateSystemWithHmd_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_CanUnifyCoordinateSystemWithHmd_Bool; +pub const ContainsProximitySensor_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ContainsProximitySensor_Bool; +pub const DeviceProvidesBatteryStatus_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DeviceProvidesBatteryStatus_Bool; +pub const DeviceCanPowerOff_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DeviceCanPowerOff_Bool; +pub const Firmware_ProgrammingTarget_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Firmware_ProgrammingTarget_String; +pub const DeviceClass_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DeviceClass_Int32; +pub const HasCamera_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HasCamera_Bool; +pub const DriverVersion_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DriverVersion_String; +pub const Firmware_ForceUpdateRequired_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Firmware_ForceUpdateRequired_Bool; +pub const ViveSystemButtonFixRequired_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ViveSystemButtonFixRequired_Bool; +pub const ParentDriver_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ParentDriver_Uint64; +pub const ResourceRoot_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ResourceRoot_String; +pub const ReportsTimeSinceVSync_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ReportsTimeSinceVSync_Bool; +pub const SecondsFromVsyncToPhotons_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_SecondsFromVsyncToPhotons_Float; +pub const DisplayFrequency_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayFrequency_Float; +pub const UserIpdMeters_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_UserIpdMeters_Float; +pub const CurrentUniverseId_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_CurrentUniverseId_Uint64; +pub const PreviousUniverseId_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_PreviousUniverseId_Uint64; +pub const DisplayFirmwareVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayFirmwareVersion_Uint64; +pub const IsOnDesktop_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_IsOnDesktop_Bool; +pub const DisplayMCType_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCType_Int32; +pub const DisplayMCOffset_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCOffset_Float; +pub const DisplayMCScale_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCScale_Float; +pub const EdidVendorID_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_EdidVendorID_Int32; +pub const DisplayMCImageLeft_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCImageLeft_String; +pub const DisplayMCImageRight_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCImageRight_String; +pub const DisplayGCBlackClamp_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayGCBlackClamp_Float; +pub const EdidProductID_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_EdidProductID_Int32; +pub const CameraToHeadTransform_Matrix34: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_CameraToHeadTransform_Matrix34; +pub const DisplayGCType_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayGCType_Int32; +pub const DisplayGCOffset_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayGCOffset_Float; +pub const DisplayGCScale_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayGCScale_Float; +pub const DisplayGCPrescale_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayGCPrescale_Float; +pub const DisplayGCImage_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayGCImage_String; +pub const LensCenterLeftU_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_LensCenterLeftU_Float; +pub const LensCenterLeftV_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_LensCenterLeftV_Float; +pub const LensCenterRightU_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_LensCenterRightU_Float; +pub const LensCenterRightV_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_LensCenterRightV_Float; +pub const UserHeadToEyeDepthMeters_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_UserHeadToEyeDepthMeters_Float; +pub const CameraFirmwareVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_CameraFirmwareVersion_Uint64; +pub const CameraFirmwareDescription_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_CameraFirmwareDescription_String; +pub const DisplayFPGAVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayFPGAVersion_Uint64; +pub const DisplayBootloaderVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayBootloaderVersion_Uint64; +pub const DisplayHardwareVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayHardwareVersion_Uint64; +pub const AudioFirmwareVersion_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_AudioFirmwareVersion_Uint64; +pub const CameraCompatibilityMode_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_CameraCompatibilityMode_Int32; +pub const ScreenshotHorizontalFieldOfViewDegrees_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ScreenshotHorizontalFieldOfViewDegrees_Float; +pub const ScreenshotVerticalFieldOfViewDegrees_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ScreenshotVerticalFieldOfViewDegrees_Float; +pub const DisplaySuppressed_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplaySuppressed_Bool; +pub const DisplayAllowNightMode_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayAllowNightMode_Bool; +pub const DisplayMCImageWidth_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCImageWidth_Int32; +pub const DisplayMCImageHeight_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCImageHeight_Int32; +pub const DisplayMCImageNumChannels_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCImageNumChannels_Int32; +pub const DisplayMCImageData_Binary: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayMCImageData_Binary; +pub const SecondsFromPhotonsToVblank_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_SecondsFromPhotonsToVblank_Float; +pub const DriverDirectModeSendsVsyncEvents_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DriverDirectModeSendsVsyncEvents_Bool; +pub const DisplayDebugMode_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayDebugMode_Bool; +pub const GraphicsAdapterLuid_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_GraphicsAdapterLuid_Uint64; +pub const AttachedDeviceId_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_AttachedDeviceId_String; +pub const SupportedButtons_Uint64: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_SupportedButtons_Uint64; +pub const Axis0Type_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Axis0Type_Int32; +pub const Axis1Type_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Axis1Type_Int32; +pub const Axis2Type_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Axis2Type_Int32; +pub const Axis3Type_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Axis3Type_Int32; +pub const Axis4Type_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_Axis4Type_Int32; +pub const ControllerRoleHint_Int32: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ControllerRoleHint_Int32; +pub const FieldOfViewLeftDegrees_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_FieldOfViewLeftDegrees_Float; +pub const FieldOfViewRightDegrees_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_FieldOfViewRightDegrees_Float; +pub const FieldOfViewTopDegrees_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_FieldOfViewTopDegrees_Float; +pub const FieldOfViewBottomDegrees_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_FieldOfViewBottomDegrees_Float; +pub const TrackingRangeMinimumMeters_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_TrackingRangeMinimumMeters_Float; +pub const TrackingRangeMaximumMeters_Float: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_TrackingRangeMaximumMeters_Float; +pub const ModeLabel_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_ModeLabel_String; +pub const IconPathName_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_IconPathName_String; +pub const NamedIconPathDeviceOff_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceOff_String; +pub const NamedIconPathDeviceSearching_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceSearching_String; +pub const NamedIconPathDeviceSearchingAlert_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceSearchingAlert_String; +pub const NamedIconPathDeviceReady_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceReady_String; +pub const NamedIconPathDeviceReadyAlert_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceReadyAlert_String; +pub const NamedIconPathDeviceNotReady_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceNotReady_String; +pub const NamedIconPathDeviceStandby_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceStandby_String; +pub const NamedIconPathDeviceAlertLow_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_NamedIconPathDeviceAlertLow_String; +pub const DisplayHiddenArea_Binary_Start: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayHiddenArea_Binary_Start; +pub const DisplayHiddenArea_Binary_End: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_DisplayHiddenArea_Binary_End; +pub const UserConfigPath_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_UserConfigPath_String; +pub const InstallPath_String: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_InstallPath_String; +pub const HasDisplayComponent_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HasDisplayComponent_Bool; +pub const HasControllerComponent_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HasControllerComponent_Bool; +pub const HasCameraComponent_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HasCameraComponent_Bool; +pub const HasDriverDirectModeComponent_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HasDriverDirectModeComponent_Bool; +pub const HasVirtualDisplayComponent_Bool: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_HasVirtualDisplayComponent_Bool; +pub const VendorSpecific_Reserved_Start: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_VendorSpecific_Reserved_Start; +pub const VendorSpecific_Reserved_End: TrackedDeviceProperty = sys::ETrackedDeviceProperty_Prop_VendorSpecific_Reserved_End; diff --git a/src/render_models.rs b/src/render_models.rs index 4ea4fd8..8c077ad 100644 --- a/src/render_models.rs +++ b/src/render_models.rs @@ -1,225 +1,261 @@ -use openvr_sys; -use openvr_sys::EVRRenderModelError::*; +use std::{fmt, ptr, slice, mem}; +use std::ffi::{CStr, CString}; -use std::string::String; -use std::ptr::null_mut; -use std::slice; -use subsystems::render_models; -use error::*; +use openvr_sys as sys; -pub struct IVRRenderModels(pub *const ()); +use {RenderModels, ControllerState, get_string}; -pub struct RenderModel(*mut openvr_sys::RenderModel_t); -pub struct RenderModelTexture(*mut openvr_sys::RenderModel_TextureMap_t); - -trait AsyncError { - /// checks if result is currently loading - fn is_loading(&self) -> bool; -} - -impl AsyncError for Error { - fn is_loading(&self) -> bool { - match self.to_raw() { - EVRRenderModelError_VRRenderModelError_Loading => { - true - }, - _ => { - false - } - } - } -} - -impl Drop for RenderModel { - /// will inform openvr that the memory for the render model is no longer required - fn drop (&mut self) { - unsafe { - let models = * { render_models().unwrap().0 as *mut openvr_sys::VR_IVRRenderModels_FnTable}; - models.FreeRenderModel.unwrap()( - self.0 - ); - } - } -} - -impl Drop for RenderModelTexture { - /// will inform openvr that the memory for the render model is no longer required - fn drop (&mut self) { - unsafe { - let models = * { render_models().unwrap().0 as *mut openvr_sys::VR_IVRRenderModels_FnTable}; - models.FreeTexture.unwrap()( - self.0 - ); - } - } -} - -impl RenderModel { - /// Returns an iterator that iterates over vertices - pub fn vertex_iter(&self) -> slice::Iter { - unsafe { - let slice = slice::from_raw_parts((*self.0).rVertexData, (*self.0).unVertexCount as usize); - slice.iter() - } - } - - /// Returns an iterator that iterates over indices - pub fn index_iter(&self) -> slice::Iter { - unsafe { - let slice = slice::from_raw_parts((*self.0).rIndexData, (*self.0).unTriangleCount as usize * 3); - slice.iter() - } - } - - /// asynchronosly loads the texture for the current render model - /// see IVRRenderModels::load_async for info how openvr async work - pub fn load_texture_async(&self) -> Result> { - unsafe { - let models = * { render_models().unwrap().0 as *mut openvr_sys::VR_IVRRenderModels_FnTable}; - let mut resp: *mut openvr_sys::RenderModel_TextureMap_t = null_mut(); - - let err = models.LoadTexture_Async.unwrap()( - (*self.0).diffuseTextureId, - &mut resp - ); - - match err { - EVRRenderModelError_VRRenderModelError_None => { - Ok(RenderModelTexture (resp)) - }, - _ => { - Err(Error::from_raw(err)) - } - } - - } - } - - /// loads the texture for current model - pub fn load_texture(&self) -> Result> { - use std; - - loop { - let result = self.load_texture_async(); - match result { - Ok(texture) => { - return Ok(texture); - }, - Err(err) => { - if !err.is_loading() { - return Err(err); - } - } - } - std::thread::sleep(std::time::Duration::from_millis(10)); - } - } -} - -impl RenderModelTexture { - /// Returns the dimension from the texture (width, height) - pub fn dimension(&self) -> (usize, usize) { - unsafe { - ((*self.0).unWidth as usize, (*self.0).unHeight as usize) - } - } - - /// Creates a 1 dimensional vector of pixels, format: rgba@32 - pub fn to_vec(&self) -> Vec { - unsafe { - let dimension = self.dimension(); - let slice = slice::from_raw_parts((*self.0).rubTextureMapData, dimension.0 * dimension.1 * 4); - let mut vec = Vec::new(); - vec.extend_from_slice(slice); - vec - } - } -} - -impl IVRRenderModels { - pub unsafe fn from_raw(ptr: *const ()) -> Self { - IVRRenderModels(ptr as *mut ()) - } - - /// Returns the amount of render models available - pub fn get_count(&self) -> u32 { - unsafe { - let models = * { self.0 as *mut openvr_sys::VR_IVRRenderModels_FnTable}; - - models.GetRenderModelCount.unwrap()() - } - } - - /// Returns the name of an available render model - pub fn get_name(&self, index: u32) -> String { - unsafe { - let models = * { self.0 as *mut openvr_sys::VR_IVRRenderModels_FnTable}; - let name_out = String::with_capacity(256); - - let size = models.GetRenderModelName.unwrap()( - index, - name_out.as_ptr() as *mut i8, - 256 - ); - - if size > 0 { - return String::from_raw_parts(name_out.as_ptr() as *mut _, (size - 1) as usize, (size - 1) as usize); - } else { - return String::from(""); - } +impl<'a> RenderModels<'a> { + /// Loads and returns a render model for use in the application. `name` should be a render model name from the + /// `RenderModelName_String` property or an absolute path name to a render model on disk. + /// + /// The method returns `Ok(None)` while the render model is still being loaded. Call it at regular intervals until + /// it returns `Ok(Some(model))`. + pub fn load_render_model(&self, name: &CStr) -> Result> { + let mut ptr = ptr::null_mut(); + let r = unsafe { + self.0.LoadRenderModel_Async.unwrap()(name.as_ptr() as *mut _, &mut ptr) }; - } - - /// Loads an render model into local memory - /// blocks the thread and waits until driver responds with model - pub fn load(&self, name: String) -> Result> { - use std; - - loop { - let result = self.load_async(name.clone()); - match result { - Ok(model) => { - return Ok(model); - }, - Err(err) => { - if !err.is_loading() { - return Err(err); - } - } - } - std::thread::sleep(std::time::Duration::from_millis(10)); + match Error(r) { + error::NONE => Ok(Some(Model { ptr: ptr, sys: self.0 })), + error::LOADING => Ok(None), + x => Err(x), } } - /// Loads an render model into local memory - /// When called for the first time openvr will start to load the model into memory - /// In the mean time this call will respond with EVRRenderModelError_VRRenderModelError_Loading - /// It is designed to be used wihtin the render loop as it won't block the user, for sync usage use load() - pub fn load_async(&self, name: String) -> Result> { - use std; + /// Returns the number of components of the specified render model. + /// + /// Components are useful when client application wish to draw, label, or otherwise interact with components of tracked objects. + /// Examples controller components: + /// renderable things such as triggers, buttons + /// non-renderable things which include coordinate systems such as 'tip', 'base', a neutral controller agnostic hand-pose + /// If all controller components are enumerated and rendered, it will be equivalent to drawing the traditional render model + /// Returns 0 if components not supported, >0 otherwise + pub fn component_count(&self, model: &CStr) -> u32 { + unsafe { self.0.GetComponentCount.unwrap()(model.as_ptr() as *mut _) } + } + /// Get the names of available components. + /// + /// `component` does not correlate to a tracked device index, but is only used for iterating over all available + /// components. If it's out of range, this function will return None. + pub fn component_name(&self, model: &CStr, component: u32) -> Option { + unsafe { get_string(|ptr, n| self.0.GetComponentName.unwrap()(model.as_ptr() as *mut _, component, ptr, n)) } + } + + /// Gets all component names of a given model + pub fn component_names(&self, model: &CStr) -> ::std::vec::IntoIter { // FIXME: impl Iterator rather than allocating + let n = self.component_count(model); + (0..n).map(|i| self.component_name(model, i).expect("inconsistent component presence reported by OpenVR")).collect::>().into_iter() + } + + /// Use this to get the render model name for the specified rendermodel/component combination, to be passed to + /// `load_render_model`. + /// + /// If the component name is out of range, this function will return None. + /// Otherwise, it will return the size of the buffer required for the name. + pub fn component_render_model_name(&self, model: &CStr, component: &CStr) -> Option { unsafe { - let models = * { self.0 as *mut openvr_sys::VR_IVRRenderModels_FnTable}; - let mut resp: *mut openvr_sys::RenderModel_t = null_mut(); - let cname = std::ffi::CString::new(name.as_str()).unwrap(); - let rawname = cname.into_raw(); + get_string(|ptr, n| self.0.GetComponentRenderModelName.unwrap()( + model.as_ptr() as *mut _, component.as_ptr() as *mut _, ptr, n)) + } + } - let err = models.LoadRenderModel_Async.unwrap()( - rawname, - &mut resp - ); - - let _ = std::ffi::CString::from_raw(rawname); - - match err { - EVRRenderModelError_VRRenderModelError_None => { - Ok(RenderModel ( resp )) - }, - _ => { - Err(Error::from_raw(err)) - } + /// Use this to query information about the component, as a function of the controller state. + /// + /// Returns None if the component is invalid. + /// + /// Check `ComponentState::is_visible()` to determine whether the returned component should be rendered. + /// + /// For dynamic controller components (ex: trigger) values will reflect component motions. + /// For static components this will return a consistent value independent of the `ControllerState`. + pub fn component_state(&self, model: &CStr, component: &CStr, state: &ControllerState, mode: &ControllerMode) -> Option { + unsafe { + let mut out = mem::uninitialized(); + if self.0.GetComponentState.unwrap()(model.as_ptr() as *mut _, component.as_ptr() as *mut _, + state as *const _ as *mut _, mode as *const _ as *mut _, + &mut out as *mut _ as *mut _) { + Some(out) + } else { + None } + } + } + /// Loads and returns a texture for use in the application. Texture IDs can be obtained from + /// `Model::diffuse_texture_id()`. + /// + /// The method returns `Ok(None)` while the texture is still being loaded. Call it at regular intervals until it + /// returns `Ok(Some(texture))`. + pub fn load_texture(&self, id: TextureId) -> Result> { + let mut ptr = ptr::null_mut(); + let r = unsafe { + self.0.LoadTexture_Async.unwrap()(id, &mut ptr) + }; + match Error(r) { + error::NONE => Ok(Some(Texture { ptr: ptr, sys: self.0 })), + error::LOADING => Ok(None), + x => Err(x), } } } + +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Error(sys::EVRRenderModelError); + +pub mod error { + use super::{sys, Error}; + + pub const NONE: Error = Error(sys::EVRRenderModelError_VRRenderModelError_None); + pub const LOADING: Error = Error(sys::EVRRenderModelError_VRRenderModelError_Loading); + pub const NOT_SUPPORTED: Error = Error(sys::EVRRenderModelError_VRRenderModelError_NotSupported); + pub const INVALID_ARG: Error = Error(sys::EVRRenderModelError_VRRenderModelError_InvalidArg); + pub const INVALID_MODEL: Error = Error(sys::EVRRenderModelError_VRRenderModelError_InvalidModel); + pub const NO_SHAPES: Error = Error(sys::EVRRenderModelError_VRRenderModelError_NoShapes); + pub const MULTIPLE_SHAPES: Error = Error(sys::EVRRenderModelError_VRRenderModelError_MultipleShapes); + pub const TOO_MANY_VERTICES: Error = Error(sys::EVRRenderModelError_VRRenderModelError_TooManyVertices); + pub const MULTIPLE_TEXTURES: Error = Error(sys::EVRRenderModelError_VRRenderModelError_MultipleTextures); + pub const BUFFER_TOO_SMALL: Error = Error(sys::EVRRenderModelError_VRRenderModelError_BufferTooSmall); + pub const NOT_ENOUGH_NORMALS: Error = Error(sys::EVRRenderModelError_VRRenderModelError_NotEnoughNormals); + pub const NOT_ENOUGH_TEX_COORDS: Error = Error(sys::EVRRenderModelError_VRRenderModelError_NotEnoughTexCoords); + pub const INVALID_TEXTURE: Error = Error(sys::EVRRenderModelError_VRRenderModelError_InvalidTexture); +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(::std::error::Error::description(self)) + } +} + +impl ::std::error::Error for Error { + fn description(&self) -> &str { + use self::error::*; + match *self { + NONE => "NONE", + LOADING => "LOADING", + NOT_SUPPORTED => "NOT_SUPPORTED", + INVALID_ARG => "INVALID_ARG", + INVALID_MODEL => "INVALID_MODEL", + NO_SHAPES => "NO_SHAPES", + MULTIPLE_SHAPES => "MULTIPLE_SHAPES", + TOO_MANY_VERTICES => "TOO_MANY_VERTICES", + MULTIPLE_TEXTURES => "MULTIPLE_TEXTURES", + BUFFER_TOO_SMALL => "BUFFER_TOO_SMALL", + NOT_ENOUGH_NORMALS => "NOT_ENOUGH_NORMALS", + NOT_ENOUGH_TEX_COORDS => "NOT_ENOUGH_TEX_COORDS", + INVALID_TEXTURE => "INVALID_TEXTURE", + _ => "UNKNOWN", + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(::std::error::Error::description(self)) + } +} + +pub type Result = ::std::result::Result; + +/// 3D geometry for rendering as an indexed triangle list +pub struct Model<'a> { + ptr: *mut sys::RenderModel_t, + sys: &'a sys::VR_IVRRenderModels_FnTable, +} + +impl<'a> Model<'a> { + pub fn vertices(&self) -> &[Vertex] { + unsafe { + let model = &*self.ptr; + slice::from_raw_parts(model.rVertexData as *mut Vertex, model.unVertexCount as usize) + } + } + + pub fn indices(&self) -> &[u16] { + unsafe { + let model = &*self.ptr; + slice::from_raw_parts(model.rIndexData, 3 * model.unTriangleCount as usize) + } + } + + pub fn diffuse_texture_id(&self) -> Option { + let id = unsafe { (&*self.ptr).diffuseTextureId }; + if id < 0 { None } else { Some(id) } + } +} + +impl<'a> Drop for Model<'a> { + fn drop(&mut self) { unsafe { self.sys.FreeRenderModel.unwrap()(self.ptr) } } +} + +pub struct Texture<'a> { + ptr: *mut sys::RenderModel_TextureMap_t, + sys: &'a sys::VR_IVRRenderModels_FnTable, +} + +impl<'a> Texture<'a> { + pub fn dimensions(&self) -> (u16, u16) { + let tex = unsafe { &*self.ptr }; + (tex.unWidth, tex.unHeight) + } + + /// R8G8B8A8 + pub fn data(&self) -> &[u8] { + unsafe { + let tex = &*self.ptr; + slice::from_raw_parts(tex.rubTextureMapData, tex.unWidth as usize * tex.unHeight as usize * 4) + } + } +} + +impl<'a> Drop for Texture<'a> { + fn drop(&mut self) { unsafe { self.sys.FreeTexture.unwrap()(self.ptr) } } +} + +pub type TextureId = sys::TextureID_t; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Vertex { + pub position: [f32; 3], + pub normal: [f32; 3], + pub texture_coord: [f32; 2], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ControllerMode { + pub scroll_wheel_visible: bool, +} + +impl Default for ControllerMode { + fn default() -> Self { ControllerMode { scroll_wheel_visible: false } } +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ComponentState { + pub tracking_to_component_render_model: [[f32; 4]; 3], + pub tracking_to_component_local: [[f32; 4]; 3], + pub properties: ComponentProperties, +} + +impl ComponentState { + pub fn is_static(&self) -> bool { self.properties & component_properties::IS_STATIC != 0 } + pub fn is_visible(&self) -> bool { self.properties & component_properties::IS_VISIBLE != 0 } + pub fn is_touched(&self) -> bool { self.properties & component_properties::IS_TOUCHED != 0 } + pub fn is_pressed(&self) -> bool { self.properties & component_properties::IS_PRESSED != 0 } + pub fn is_scrolled(&self) -> bool { self.properties & component_properties::IS_SCROLLED != 0 } +} + +type ComponentProperties = sys::VRComponentProperties; + +pub mod component_properties { + use super::{sys, ComponentProperties}; + + pub const IS_STATIC: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsStatic; + pub const IS_VISIBLE: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsVisible; + pub const IS_TOUCHED: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsTouched; + pub const IS_PRESSED: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsPressed; + pub const IS_SCROLLED: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsScrolled; +} diff --git a/src/system/event.rs b/src/system/event.rs index ffaad13..8149cfc 100644 --- a/src/system/event.rs +++ b/src/system/event.rs @@ -271,6 +271,7 @@ pub enum Event { Notification_BeginInteraction, Notification_Destroyed, + /// The application has been asked to quit Quit(Process), ProcessQuit(Process), QuitAborted_UserPrompt(Process), @@ -345,116 +346,116 @@ impl Event { #[allow(deprecated)] match ty { - sys::EVREventType_EVREventType_VREvent_TrackedDeviceActivated => TrackedDeviceActivated, - sys::EVREventType_EVREventType_VREvent_TrackedDeviceDeactivated => TrackedDeviceDeactivated, - sys::EVREventType_EVREventType_VREvent_TrackedDeviceUpdated => TrackedDeviceUpdated, - sys::EVREventType_EVREventType_VREvent_TrackedDeviceUserInteractionStarted => TrackedDeviceUserInteractionStarted, - sys::EVREventType_EVREventType_VREvent_TrackedDeviceUserInteractionEnded => TrackedDeviceUserInteractionEnded, - sys::EVREventType_EVREventType_VREvent_IpdChanged => IpdChanged, - sys::EVREventType_EVREventType_VREvent_EnterStandbyMode => EnterStandbyMode, - sys::EVREventType_EVREventType_VREvent_LeaveStandbyMode => LeaveStandbyMode, - sys::EVREventType_EVREventType_VREvent_TrackedDeviceRoleChanged => TrackedDeviceRoleChanged, - sys::EVREventType_EVREventType_VREvent_WatchdogWakeUpRequested => WatchdogWakeUpRequested, - sys::EVREventType_EVREventType_VREvent_LensDistortionChanged => LensDistortionChanged, - sys::EVREventType_EVREventType_VREvent_PropertyChanged => PropertyChanged(get(data)), - sys::EVREventType_EVREventType_VREvent_ButtonPress => ButtonPress(get(data)), - sys::EVREventType_EVREventType_VREvent_ButtonUnpress => ButtonUnpress(get(data)), - sys::EVREventType_EVREventType_VREvent_ButtonTouch => ButtonTouch(get(data)), - sys::EVREventType_EVREventType_VREvent_ButtonUntouch => ButtonUntouch(get(data)), - sys::EVREventType_EVREventType_VREvent_MouseMove => MouseMove(get(data)), - sys::EVREventType_EVREventType_VREvent_MouseButtonDown => MouseButtonDown(get(data)), - sys::EVREventType_EVREventType_VREvent_MouseButtonUp => MouseButtonUp(get(data)), - sys::EVREventType_EVREventType_VREvent_FocusEnter => FocusEnter(get(data)), - sys::EVREventType_EVREventType_VREvent_FocusLeave => FocusLeave(get(data)), - sys::EVREventType_EVREventType_VREvent_Scroll => Scroll(get(data)), - sys::EVREventType_EVREventType_VREvent_TouchPadMove => TouchPadMove(get(data)), - sys::EVREventType_EVREventType_VREvent_OverlayFocusChanged => OverlayFocusChanged(get(data)), - sys::EVREventType_EVREventType_VREvent_InputFocusCaptured => InputFocusCaptured(get(data)), - sys::EVREventType_EVREventType_VREvent_InputFocusReleased => InputFocusReleased(get(data)), - sys::EVREventType_EVREventType_VREvent_SceneFocusLost => SceneFocusLost(get(data)), - sys::EVREventType_EVREventType_VREvent_SceneFocusGained => SceneFocusGained(get(data)), - sys::EVREventType_EVREventType_VREvent_SceneApplicationChanged => SceneApplicationChanged(get(data)), - sys::EVREventType_EVREventType_VREvent_SceneFocusChanged => SceneFocusChanged(get(data)), - sys::EVREventType_EVREventType_VREvent_InputFocusChanged => InputFocusChanged(get(data)), - sys::EVREventType_EVREventType_VREvent_SceneApplicationSecondaryRenderingStarted => SceneApplicationSecondaryRenderingStarted(get(data)), - sys::EVREventType_EVREventType_VREvent_HideRenderModels => HideRenderModels, - sys::EVREventType_EVREventType_VREvent_ShowRenderModels => ShowRenderModels, - sys::EVREventType_EVREventType_VREvent_OverlayShown => OverlayShown, - sys::EVREventType_EVREventType_VREvent_OverlayHidden => OverlayHidden, - sys::EVREventType_EVREventType_VREvent_DashboardActivated => DashboardActivated, - sys::EVREventType_EVREventType_VREvent_DashboardDeactivated => DashboardDeactivated, - sys::EVREventType_EVREventType_VREvent_DashboardThumbSelected => DashboardThumbSelected, - sys::EVREventType_EVREventType_VREvent_DashboardRequested => DashboardRequested, - sys::EVREventType_EVREventType_VREvent_ResetDashboard => ResetDashboard, - sys::EVREventType_EVREventType_VREvent_RenderToast => RenderToast, - sys::EVREventType_EVREventType_VREvent_ImageLoaded => ImageLoaded, - sys::EVREventType_EVREventType_VREvent_ShowKeyboard => ShowKeyboard, - sys::EVREventType_EVREventType_VREvent_HideKeyboard => HideKeyboard, - sys::EVREventType_EVREventType_VREvent_OverlayGamepadFocusGained => OverlayGamepadFocusGained, - sys::EVREventType_EVREventType_VREvent_OverlayGamepadFocusLost => OverlayGamepadFocusLost, - sys::EVREventType_EVREventType_VREvent_OverlaySharedTextureChanged => OverlaySharedTextureChanged, - sys::EVREventType_EVREventType_VREvent_DashboardGuideButtonDown => DashboardGuideButtonDown, - sys::EVREventType_EVREventType_VREvent_DashboardGuideButtonUp => DashboardGuideButtonUp, - sys::EVREventType_EVREventType_VREvent_ScreenshotTriggered => ScreenshotTriggered, - sys::EVREventType_EVREventType_VREvent_ImageFailed => ImageFailed, - sys::EVREventType_EVREventType_VREvent_DashboardOverlayCreated => DashboardOverlayCreated, - sys::EVREventType_EVREventType_VREvent_RequestScreenshot => RequestScreenshot, - sys::EVREventType_EVREventType_VREvent_ScreenshotTaken => ScreenshotTaken, - sys::EVREventType_EVREventType_VREvent_ScreenshotFailed => ScreenshotFailed, - sys::EVREventType_EVREventType_VREvent_SubmitScreenshotToDashboard => SubmitScreenshotToDashboard, - sys::EVREventType_EVREventType_VREvent_ScreenshotProgressToDashboard => ScreenshotProgressToDashboard, - sys::EVREventType_EVREventType_VREvent_PrimaryDashboardDeviceChanged => PrimaryDashboardDeviceChanged, - sys::EVREventType_EVREventType_VREvent_Notification_Shown => Notification_Shown, - sys::EVREventType_EVREventType_VREvent_Notification_Hidden => Notification_Hidden, - sys::EVREventType_EVREventType_VREvent_Notification_BeginInteraction => Notification_BeginInteraction, - sys::EVREventType_EVREventType_VREvent_Notification_Destroyed => Notification_Destroyed, - sys::EVREventType_EVREventType_VREvent_Quit => Quit(get(data)), - sys::EVREventType_EVREventType_VREvent_ProcessQuit => ProcessQuit(get(data)), - sys::EVREventType_EVREventType_VREvent_QuitAborted_UserPrompt => QuitAborted_UserPrompt(get(data)), - sys::EVREventType_EVREventType_VREvent_QuitAcknowledged => QuitAcknowledged(get(data)), - sys::EVREventType_EVREventType_VREvent_DriverRequestedQuit => DriverRequestedQuit, - sys::EVREventType_EVREventType_VREvent_ChaperoneDataHasChanged => ChaperoneDataHasChanged, - sys::EVREventType_EVREventType_VREvent_ChaperoneUniverseHasChanged => ChaperoneUniverseHasChanged, - sys::EVREventType_EVREventType_VREvent_ChaperoneTempDataHasChanged => ChaperoneTempDataHasChanged, - sys::EVREventType_EVREventType_VREvent_ChaperoneSettingsHaveChanged => ChaperoneSettingsHaveChanged, - sys::EVREventType_EVREventType_VREvent_SeatedZeroPoseReset => SeatedZeroPoseReset, - sys::EVREventType_EVREventType_VREvent_AudioSettingsHaveChanged => AudioSettingsHaveChanged, - sys::EVREventType_EVREventType_VREvent_BackgroundSettingHasChanged => BackgroundSettingHasChanged, - sys::EVREventType_EVREventType_VREvent_CameraSettingsHaveChanged => CameraSettingsHaveChanged, - sys::EVREventType_EVREventType_VREvent_ReprojectionSettingHasChanged => ReprojectionSettingHasChanged, - sys::EVREventType_EVREventType_VREvent_ModelSkinSettingsHaveChanged => ModelSkinSettingsHaveChanged, - sys::EVREventType_EVREventType_VREvent_EnvironmentSettingsHaveChanged => EnvironmentSettingsHaveChanged, - sys::EVREventType_EVREventType_VREvent_PowerSettingsHaveChanged => PowerSettingsHaveChanged, - sys::EVREventType_EVREventType_VREvent_StatusUpdate => StatusUpdate, - sys::EVREventType_EVREventType_VREvent_MCImageUpdated => MCImageUpdated, - sys::EVREventType_EVREventType_VREvent_FirmwareUpdateStarted => FirmwareUpdateStarted, - sys::EVREventType_EVREventType_VREvent_FirmwareUpdateFinished => FirmwareUpdateFinished, - sys::EVREventType_EVREventType_VREvent_KeyboardClosed => KeyboardClosed, - sys::EVREventType_EVREventType_VREvent_KeyboardCharInput => KeyboardCharInput(get(data)), - sys::EVREventType_EVREventType_VREvent_KeyboardDone => KeyboardDone, - sys::EVREventType_EVREventType_VREvent_ApplicationTransitionStarted => ApplicationTransitionStarted, - sys::EVREventType_EVREventType_VREvent_ApplicationTransitionAborted => ApplicationTransitionAborted, - sys::EVREventType_EVREventType_VREvent_ApplicationTransitionNewAppStarted => ApplicationTransitionNewAppStarted, - sys::EVREventType_EVREventType_VREvent_ApplicationListUpdated => ApplicationListUpdated, - sys::EVREventType_EVREventType_VREvent_ApplicationMimeTypeLoad => ApplicationMimeTypeLoad, - sys::EVREventType_EVREventType_VREvent_ApplicationTransitionNewAppLaunchComplete => ApplicationTransitionNewAppLaunchComplete, - sys::EVREventType_EVREventType_VREvent_ProcessConnected => ProcessConnected, - sys::EVREventType_EVREventType_VREvent_ProcessDisconnected => ProcessDisconnected, - sys::EVREventType_EVREventType_VREvent_Compositor_MirrorWindowShown => Compositor_MirrorWindowShown, - sys::EVREventType_EVREventType_VREvent_Compositor_MirrorWindowHidden => Compositor_MirrorWindowHidden, - sys::EVREventType_EVREventType_VREvent_Compositor_ChaperoneBoundsShown => Compositor_ChaperoneBoundsShown, - sys::EVREventType_EVREventType_VREvent_Compositor_ChaperoneBoundsHidden => Compositor_ChaperoneBoundsHidden, - sys::EVREventType_EVREventType_VREvent_TrackedCamera_StartVideoStream => TrackedCamera_StartVideoStream, - sys::EVREventType_EVREventType_VREvent_TrackedCamera_StopVideoStream => TrackedCamera_StopVideoStream, - sys::EVREventType_EVREventType_VREvent_TrackedCamera_PauseVideoStream => TrackedCamera_PauseVideoStream, - sys::EVREventType_EVREventType_VREvent_TrackedCamera_ResumeVideoStream => TrackedCamera_ResumeVideoStream, - sys::EVREventType_EVREventType_VREvent_TrackedCamera_EditingSurface => TrackedCamera_EditingSurface, - sys::EVREventType_EVREventType_VREvent_PerformanceTest_EnableCapture => PerformanceTest_EnableCapture, - sys::EVREventType_EVREventType_VREvent_PerformanceTest_DisableCapture => PerformanceTest_DisableCapture, - sys::EVREventType_EVREventType_VREvent_PerformanceTest_FidelityLevel => PerformanceTest_FidelityLevel, - sys::EVREventType_EVREventType_VREvent_MessageOverlay_Closed => MessageOverlay_Closed, - x if x >= sys::EVREventType_EVREventType_VREvent_VendorSpecific_Reserved_Start - && x <= sys::EVREventType_EVREventType_VREvent_VendorSpecific_Reserved_End => VendorSpecific(x), + sys::EVREventType_VREvent_TrackedDeviceActivated => TrackedDeviceActivated, + sys::EVREventType_VREvent_TrackedDeviceDeactivated => TrackedDeviceDeactivated, + sys::EVREventType_VREvent_TrackedDeviceUpdated => TrackedDeviceUpdated, + sys::EVREventType_VREvent_TrackedDeviceUserInteractionStarted => TrackedDeviceUserInteractionStarted, + sys::EVREventType_VREvent_TrackedDeviceUserInteractionEnded => TrackedDeviceUserInteractionEnded, + sys::EVREventType_VREvent_IpdChanged => IpdChanged, + sys::EVREventType_VREvent_EnterStandbyMode => EnterStandbyMode, + sys::EVREventType_VREvent_LeaveStandbyMode => LeaveStandbyMode, + sys::EVREventType_VREvent_TrackedDeviceRoleChanged => TrackedDeviceRoleChanged, + sys::EVREventType_VREvent_WatchdogWakeUpRequested => WatchdogWakeUpRequested, + sys::EVREventType_VREvent_LensDistortionChanged => LensDistortionChanged, + sys::EVREventType_VREvent_PropertyChanged => PropertyChanged(get(data)), + sys::EVREventType_VREvent_ButtonPress => ButtonPress(get(data)), + sys::EVREventType_VREvent_ButtonUnpress => ButtonUnpress(get(data)), + sys::EVREventType_VREvent_ButtonTouch => ButtonTouch(get(data)), + sys::EVREventType_VREvent_ButtonUntouch => ButtonUntouch(get(data)), + sys::EVREventType_VREvent_MouseMove => MouseMove(get(data)), + sys::EVREventType_VREvent_MouseButtonDown => MouseButtonDown(get(data)), + sys::EVREventType_VREvent_MouseButtonUp => MouseButtonUp(get(data)), + sys::EVREventType_VREvent_FocusEnter => FocusEnter(get(data)), + sys::EVREventType_VREvent_FocusLeave => FocusLeave(get(data)), + sys::EVREventType_VREvent_Scroll => Scroll(get(data)), + sys::EVREventType_VREvent_TouchPadMove => TouchPadMove(get(data)), + sys::EVREventType_VREvent_OverlayFocusChanged => OverlayFocusChanged(get(data)), + sys::EVREventType_VREvent_InputFocusCaptured => InputFocusCaptured(get(data)), + sys::EVREventType_VREvent_InputFocusReleased => InputFocusReleased(get(data)), + sys::EVREventType_VREvent_SceneFocusLost => SceneFocusLost(get(data)), + sys::EVREventType_VREvent_SceneFocusGained => SceneFocusGained(get(data)), + sys::EVREventType_VREvent_SceneApplicationChanged => SceneApplicationChanged(get(data)), + sys::EVREventType_VREvent_SceneFocusChanged => SceneFocusChanged(get(data)), + sys::EVREventType_VREvent_InputFocusChanged => InputFocusChanged(get(data)), + sys::EVREventType_VREvent_SceneApplicationSecondaryRenderingStarted => SceneApplicationSecondaryRenderingStarted(get(data)), + sys::EVREventType_VREvent_HideRenderModels => HideRenderModels, + sys::EVREventType_VREvent_ShowRenderModels => ShowRenderModels, + sys::EVREventType_VREvent_OverlayShown => OverlayShown, + sys::EVREventType_VREvent_OverlayHidden => OverlayHidden, + sys::EVREventType_VREvent_DashboardActivated => DashboardActivated, + sys::EVREventType_VREvent_DashboardDeactivated => DashboardDeactivated, + sys::EVREventType_VREvent_DashboardThumbSelected => DashboardThumbSelected, + sys::EVREventType_VREvent_DashboardRequested => DashboardRequested, + sys::EVREventType_VREvent_ResetDashboard => ResetDashboard, + sys::EVREventType_VREvent_RenderToast => RenderToast, + sys::EVREventType_VREvent_ImageLoaded => ImageLoaded, + sys::EVREventType_VREvent_ShowKeyboard => ShowKeyboard, + sys::EVREventType_VREvent_HideKeyboard => HideKeyboard, + sys::EVREventType_VREvent_OverlayGamepadFocusGained => OverlayGamepadFocusGained, + sys::EVREventType_VREvent_OverlayGamepadFocusLost => OverlayGamepadFocusLost, + sys::EVREventType_VREvent_OverlaySharedTextureChanged => OverlaySharedTextureChanged, + sys::EVREventType_VREvent_DashboardGuideButtonDown => DashboardGuideButtonDown, + sys::EVREventType_VREvent_DashboardGuideButtonUp => DashboardGuideButtonUp, + sys::EVREventType_VREvent_ScreenshotTriggered => ScreenshotTriggered, + sys::EVREventType_VREvent_ImageFailed => ImageFailed, + sys::EVREventType_VREvent_DashboardOverlayCreated => DashboardOverlayCreated, + sys::EVREventType_VREvent_RequestScreenshot => RequestScreenshot, + sys::EVREventType_VREvent_ScreenshotTaken => ScreenshotTaken, + sys::EVREventType_VREvent_ScreenshotFailed => ScreenshotFailed, + sys::EVREventType_VREvent_SubmitScreenshotToDashboard => SubmitScreenshotToDashboard, + sys::EVREventType_VREvent_ScreenshotProgressToDashboard => ScreenshotProgressToDashboard, + sys::EVREventType_VREvent_PrimaryDashboardDeviceChanged => PrimaryDashboardDeviceChanged, + sys::EVREventType_VREvent_Notification_Shown => Notification_Shown, + sys::EVREventType_VREvent_Notification_Hidden => Notification_Hidden, + sys::EVREventType_VREvent_Notification_BeginInteraction => Notification_BeginInteraction, + sys::EVREventType_VREvent_Notification_Destroyed => Notification_Destroyed, + sys::EVREventType_VREvent_Quit => Quit(get(data)), + sys::EVREventType_VREvent_ProcessQuit => ProcessQuit(get(data)), + sys::EVREventType_VREvent_QuitAborted_UserPrompt => QuitAborted_UserPrompt(get(data)), + sys::EVREventType_VREvent_QuitAcknowledged => QuitAcknowledged(get(data)), + sys::EVREventType_VREvent_DriverRequestedQuit => DriverRequestedQuit, + sys::EVREventType_VREvent_ChaperoneDataHasChanged => ChaperoneDataHasChanged, + sys::EVREventType_VREvent_ChaperoneUniverseHasChanged => ChaperoneUniverseHasChanged, + sys::EVREventType_VREvent_ChaperoneTempDataHasChanged => ChaperoneTempDataHasChanged, + sys::EVREventType_VREvent_ChaperoneSettingsHaveChanged => ChaperoneSettingsHaveChanged, + sys::EVREventType_VREvent_SeatedZeroPoseReset => SeatedZeroPoseReset, + sys::EVREventType_VREvent_AudioSettingsHaveChanged => AudioSettingsHaveChanged, + sys::EVREventType_VREvent_BackgroundSettingHasChanged => BackgroundSettingHasChanged, + sys::EVREventType_VREvent_CameraSettingsHaveChanged => CameraSettingsHaveChanged, + sys::EVREventType_VREvent_ReprojectionSettingHasChanged => ReprojectionSettingHasChanged, + sys::EVREventType_VREvent_ModelSkinSettingsHaveChanged => ModelSkinSettingsHaveChanged, + sys::EVREventType_VREvent_EnvironmentSettingsHaveChanged => EnvironmentSettingsHaveChanged, + sys::EVREventType_VREvent_PowerSettingsHaveChanged => PowerSettingsHaveChanged, + sys::EVREventType_VREvent_StatusUpdate => StatusUpdate, + sys::EVREventType_VREvent_MCImageUpdated => MCImageUpdated, + sys::EVREventType_VREvent_FirmwareUpdateStarted => FirmwareUpdateStarted, + sys::EVREventType_VREvent_FirmwareUpdateFinished => FirmwareUpdateFinished, + sys::EVREventType_VREvent_KeyboardClosed => KeyboardClosed, + sys::EVREventType_VREvent_KeyboardCharInput => KeyboardCharInput(get(data)), + sys::EVREventType_VREvent_KeyboardDone => KeyboardDone, + sys::EVREventType_VREvent_ApplicationTransitionStarted => ApplicationTransitionStarted, + sys::EVREventType_VREvent_ApplicationTransitionAborted => ApplicationTransitionAborted, + sys::EVREventType_VREvent_ApplicationTransitionNewAppStarted => ApplicationTransitionNewAppStarted, + sys::EVREventType_VREvent_ApplicationListUpdated => ApplicationListUpdated, + sys::EVREventType_VREvent_ApplicationMimeTypeLoad => ApplicationMimeTypeLoad, + sys::EVREventType_VREvent_ApplicationTransitionNewAppLaunchComplete => ApplicationTransitionNewAppLaunchComplete, + sys::EVREventType_VREvent_ProcessConnected => ProcessConnected, + sys::EVREventType_VREvent_ProcessDisconnected => ProcessDisconnected, + sys::EVREventType_VREvent_Compositor_MirrorWindowShown => Compositor_MirrorWindowShown, + sys::EVREventType_VREvent_Compositor_MirrorWindowHidden => Compositor_MirrorWindowHidden, + sys::EVREventType_VREvent_Compositor_ChaperoneBoundsShown => Compositor_ChaperoneBoundsShown, + sys::EVREventType_VREvent_Compositor_ChaperoneBoundsHidden => Compositor_ChaperoneBoundsHidden, + sys::EVREventType_VREvent_TrackedCamera_StartVideoStream => TrackedCamera_StartVideoStream, + sys::EVREventType_VREvent_TrackedCamera_StopVideoStream => TrackedCamera_StopVideoStream, + sys::EVREventType_VREvent_TrackedCamera_PauseVideoStream => TrackedCamera_PauseVideoStream, + sys::EVREventType_VREvent_TrackedCamera_ResumeVideoStream => TrackedCamera_ResumeVideoStream, + sys::EVREventType_VREvent_TrackedCamera_EditingSurface => TrackedCamera_EditingSurface, + sys::EVREventType_VREvent_PerformanceTest_EnableCapture => PerformanceTest_EnableCapture, + sys::EVREventType_VREvent_PerformanceTest_DisableCapture => PerformanceTest_DisableCapture, + sys::EVREventType_VREvent_PerformanceTest_FidelityLevel => PerformanceTest_FidelityLevel, + sys::EVREventType_VREvent_MessageOverlay_Closed => MessageOverlay_Closed, + x if x >= sys::EVREventType_VREvent_VendorSpecific_Reserved_Start + && x <= sys::EVREventType_VREvent_VendorSpecific_Reserved_End => VendorSpecific(x), x => Unknown(x), } } diff --git a/src/system/mod.rs b/src/system/mod.rs index e505569..c40111a 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -1,7 +1,9 @@ //! The `System` interface provides access to display configuration information, tracking data, controller state, //! events, and device properties. It is the main interface of OpenVR. -use std::mem; +use std::{mem, slice, ptr}; +use std::ffi::CString; +use std::marker::PhantomData; use openvr_sys as sys; @@ -89,12 +91,12 @@ impl<'a> System<'a> { pub fn tracked_device_class(&self, index: TrackedDeviceIndex) -> TrackedDeviceClass { use self::TrackedDeviceClass::*; match unsafe { self.0.GetTrackedDeviceClass.unwrap()(index) } { - sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Invalid => Invalid, - sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_HMD => HMD, - sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Controller => Controller, - sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_GenericTracker => GenericTracker, - sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_TrackingReference => TrackingReference, - sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect => DisplayRedirect, + sys::ETrackedDeviceClass_TrackedDeviceClass_Invalid => Invalid, + sys::ETrackedDeviceClass_TrackedDeviceClass_HMD => HMD, + sys::ETrackedDeviceClass_TrackedDeviceClass_Controller => Controller, + sys::ETrackedDeviceClass_TrackedDeviceClass_GenericTracker => GenericTracker, + sys::ETrackedDeviceClass_TrackedDeviceClass_TrackingReference => TrackingReference, + sys::ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect => DisplayRedirect, _ => Invalid, } } @@ -147,11 +149,143 @@ impl<'a> System<'a> { pub fn get_controller_role_for_tracked_device_index(&self, i: TrackedDeviceIndex) -> Option { let x = unsafe { self.0.GetControllerRoleForTrackedDeviceIndex.unwrap()(i) }; match x { - sys::ETrackedControllerRole_ETrackedControllerRole_TrackedControllerRole_LeftHand => Some(TrackedControllerRole::LeftHand), - sys::ETrackedControllerRole_ETrackedControllerRole_TrackedControllerRole_RightHand => Some(TrackedControllerRole::RightHand), + sys::ETrackedControllerRole_TrackedControllerRole_LeftHand => Some(TrackedControllerRole::LeftHand), + sys::ETrackedControllerRole_TrackedControllerRole_RightHand => Some(TrackedControllerRole::RightHand), _ => None, } } + + pub fn vulkan_output_device(&self) -> Option<*mut VkPhysicalDevice_T> { + unsafe { + let mut device = mem::uninitialized(); + self.0.GetOutputDevice.unwrap()(&mut device, sys::ETextureType_TextureType_Vulkan); + if device == 0 { None } else { Some(device as usize as *mut _) } + } + } + + pub fn bool_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result { + unsafe { + let mut error: TrackedPropertyError = mem::uninitialized(); + let r = self.0.GetBoolTrackedDeviceProperty.unwrap()(device, property, &mut error.0); + if error == tracked_property_error::SUCCESS { Ok(r) } else { Err(error) } + } + } + + pub fn float_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result { + unsafe { + let mut error: TrackedPropertyError = mem::uninitialized(); + let r = self.0.GetFloatTrackedDeviceProperty.unwrap()(device, property, &mut error.0); + if error == tracked_property_error::SUCCESS { Ok(r) } else { Err(error) } + } + } + + pub fn int32_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result { + unsafe { + let mut error: TrackedPropertyError = mem::uninitialized(); + let r = self.0.GetInt32TrackedDeviceProperty.unwrap()(device, property, &mut error.0); + if error == tracked_property_error::SUCCESS { Ok(r) } else { Err(error) } + } + } + + pub fn uint64_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result { + unsafe { + let mut error: TrackedPropertyError = mem::uninitialized(); + let r = self.0.GetUint64TrackedDeviceProperty.unwrap()(device, property, &mut error.0); + if error == tracked_property_error::SUCCESS { Ok(r) } else { Err(error) } + } + } + + pub fn matrix34_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result<[[f32; 4]; 3], TrackedPropertyError> { + unsafe { + let mut error: TrackedPropertyError = mem::uninitialized(); + let r = self.0.GetMatrix34TrackedDeviceProperty.unwrap()(device, property, &mut error.0); + if error == tracked_property_error::SUCCESS { Ok(r.m) } else { Err(error) } + } + } + + pub fn string_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result { + unsafe { + let mut error = mem::uninitialized(); + let res = get_string(|ptr, n| self.0.GetStringTrackedDeviceProperty.unwrap()(device, property, ptr, n, &mut error)); + res.map_or(Err(TrackedPropertyError(error)), Ok) + } + } + + /// Returns the hidden area mesh for the current HMD. + /// + /// The pixels covered by this mesh will never be seen by the user after the lens distortion is applied based on + /// visibility to the panels. If this HMD does not have a hidden area mesh, None is returned. This mesh is meant to + /// be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering each eye's view. + /// This will improve performance by letting the GPU early-reject pixels the user will never see before running the + /// pixel shader. + /// + /// NOTE: Render this mesh with backface culling disabled since the winding order of the vertices can + /// be different per-HMD or per-eye. + /// + /// Passing `HiddenAreaMeshType::Inverse` will produce the visible area mesh that is commonly used in place of + /// full-screen quads. The visible area mesh covers all of the pixels the hidden area mesh does not cover. + // TODO: Handle line loops with a separate method and return type, since HiddenAreaMesh assumes triangles. + pub fn hidden_area_mesh(&self, eye: Eye, ty: HiddenAreaMeshType) -> Option { + let mesh = unsafe { self.0.GetHiddenAreaMesh.unwrap()(eye as sys::EVREye, ty as sys::EHiddenAreaMeshType) }; + if mesh.pVertexData == ptr::null_mut() { None } else { Some(HiddenAreaMesh { mesh, _phantom: PhantomData }) } + } + + /// Looks up the current input state of a controller. + /// + /// Returns None if the device is not a controller, or if the user is currently in the system menu. + /// + /// Needed for rendering controller components (e.g. trigger) accurately wrt. user input using the `render_models` + /// API. + pub fn controller_state(&self, device: TrackedDeviceIndex) -> Option { + unsafe { + let mut state = mem::uninitialized(); + if self.0.GetControllerState.unwrap()(device, &mut state as *mut _ as *mut _, mem::size_of_val(&state) as u32) { + Some(state) + } else { + None + } + } + } + + pub fn controller_state_with_pose(&self, origin: TrackingUniverseOrigin, device: TrackedDeviceIndex) -> Option<(ControllerState, TrackedDevicePose)> { + unsafe { + let mut state = mem::uninitialized(); + let mut pose = mem::uninitialized(); + if self.0.GetControllerStateWithPose.unwrap()( + origin as sys::ETrackingUniverseOrigin, + device, &mut state as *mut _ as *mut _, mem::size_of_val(&state) as u32, + &mut pose) { + Some((state, pose.into())) + } else { + None + } + } + } + + /// Trigger a single haptic pulse on a controller. + /// + /// After this call the application may not trigger another haptic pulse on this controller and axis combination for + /// 5ms. + /// + /// Vive controller haptics respond to axis 0. OpenVR seems to reject durations longer than 3999us. + pub fn trigger_haptic_pulse(&self, device: TrackedDeviceIndex, axis: u32, microseconds: u16) { + unsafe { self.0.TriggerHapticPulse.unwrap()(device, axis, microseconds) } + } + + /// Call this to acknowledge to the system that `Event::Quit` has been received and that the process is exiting. + /// + /// This extends the timeout until the process is killed. + pub fn acknowledge_quit_exiting(&self) { + unsafe { self.0.AcknowledgeQuit_Exiting.unwrap()(); } + } + + /// Call this to tell the system that the user is being prompted to save data. + /// + /// This halts the timeout and dismisses the dashboard (if it was up). Applications should be sure to actually + /// prompt the user to save and then exit afterward, otherwise the user will be left in a confusing state. + pub fn acknowledge_quit_user_prompt(&self) { + unsafe { self.0.AcknowledgeQuit_Exiting.unwrap()(); } + } } /// Values represent the tangents of the half-angles from the center view axis @@ -173,3 +307,83 @@ pub struct DistortionCoordinates { pub green: [f32; 2], pub blue: [f32; 2], } + +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct TrackedPropertyError(sys::TrackedPropertyError); + +pub mod tracked_property_error { + use super::{sys, TrackedPropertyError}; + + pub const SUCCESS: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_Success); + pub const WRONG_DATA_TYPE: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_WrongDataType); + pub const WRONG_DEVICE_CLASS: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_WrongDeviceClass); + pub const BUFFER_TOO_SMALL: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_BufferTooSmall); + pub const UNKNOWN_PROPERTY: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_UnknownProperty); + pub const INVALID_DEVICE: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_InvalidDevice); + pub const COULD_NOT_CONTACT_SERVER: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_CouldNotContactServer); + pub const VALUE_NOT_PROVIDED_BY_DEVICE: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_ValueNotProvidedByDevice); + pub const STRING_EXCEEDS_MAXIMUM_LENGTH: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_StringExceedsMaximumLength); + pub const NOT_YET_AVAILABLE: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_NotYetAvailable); + pub const PERMISSION_DENIED: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_PermissionDenied); + pub const INVALID_OPERATION: TrackedPropertyError = TrackedPropertyError(sys::ETrackedPropertyError_TrackedProp_InvalidOperation); +} + +impl fmt::Debug for TrackedPropertyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(::std::error::Error::description(self)) + } +} + +impl ::std::error::Error for TrackedPropertyError { + fn description(&self) -> &str { + use self::tracked_property_error::*; + match *self { + SUCCESS => "SUCCESS", + WRONG_DATA_TYPE => "WRONG_DATA_TYPE", + WRONG_DEVICE_CLASS => "WRONG_DEVICE_CLASS", + BUFFER_TOO_SMALL => "BUFFER_TOO_SMALL", + UNKNOWN_PROPERTY => "UNKNOWN_PROPERTY", + INVALID_DEVICE => "INVALID_DEVICE", + COULD_NOT_CONTACT_SERVER => "COULD_NOT_CONTACT_SERVER", + VALUE_NOT_PROVIDED_BY_DEVICE => "VALUE_NOT_PROVIDED_BY_DEVICE", + STRING_EXCEEDS_MAXIMUM_LENGTH => "STRING_EXCEEDS_MAXIMUM_LENGTH", + NOT_YET_AVAILABLE => "NOT_YET_AVAILABLE", + PERMISSION_DENIED => "PERMISSION_DENIED", + INVALID_OPERATION => "INVALID_OPERATION", + _ => "UNKNOWN", + } + } +} + +impl fmt::Display for TrackedPropertyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(::std::error::Error::description(self)) + } +} + +pub enum HiddenAreaMeshType { + /// The mesh that covers pixels which cannot be seen by the wearer of the HMD for optical reasons. + Standard = sys::EHiddenAreaMeshType_k_eHiddenAreaMesh_Standard as isize, + /// The inverse of `Standard`, useful for doing full-screen render passes such as postprocessing. + Inverse = sys::EHiddenAreaMeshType_k_eHiddenAreaMesh_Inverse as isize, +} + +impl Default for HiddenAreaMeshType { + fn default() -> Self { HiddenAreaMeshType::Standard } +} + +/// A triangle mesh containing geometry determined by `HiddenAreaMeshType`. +/// +/// Render this mesh with backface culling disabled since the winding order of the vertices can be different per-HMD or +/// per-eye. +pub struct HiddenAreaMesh<'a> { + mesh: sys::HiddenAreaMesh_t, + _phantom: PhantomData<&'a [[f32; 2]]>, +} + +impl<'a> ::std::ops::Deref for HiddenAreaMesh<'a> { + type Target = [[f32; 2]]; + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(&(*self.mesh.pVertexData).v, self.mesh.unTriangleCount as usize * 3) } + } +} diff --git a/src/tracking.rs b/src/tracking.rs index d6904e1..9daa006 100644 --- a/src/tracking.rs +++ b/src/tracking.rs @@ -2,9 +2,9 @@ use openvr_sys as sys; #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum TrackingUniverseOrigin { - Seated = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseSeated as isize, - Standing = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseStanding as isize, - RawAndUncalibrated = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseRawAndUncalibrated as isize, + Seated = sys::ETrackingUniverseOrigin_TrackingUniverseSeated as isize, + Standing = sys::ETrackingUniverseOrigin_TrackingUniverseStanding as isize, + RawAndUncalibrated = sys::ETrackingUniverseOrigin_TrackingUniverseRawAndUncalibrated as isize, } #[repr(C)] @@ -18,11 +18,11 @@ impl TrackedDevicePose { pub fn tracking_result(&self) -> TrackingResult { use self::TrackingResult::*; match self.0.eTrackingResult { - sys::ETrackingResult_ETrackingResult_TrackingResult_Uninitialized => Uninitialized, - sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_InProgress => CalibratingInProgress, - sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_OutOfRange => CalibratingOutOfRange, - sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OK => OK, - sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OutOfRange => RunningOutOfRange, + sys::ETrackingResult_TrackingResult_Uninitialized => Uninitialized, + sys::ETrackingResult_TrackingResult_Calibrating_InProgress => CalibratingInProgress, + sys::ETrackingResult_TrackingResult_Calibrating_OutOfRange => CalibratingOutOfRange, + sys::ETrackingResult_TrackingResult_Running_OK => OK, + sys::ETrackingResult_TrackingResult_Running_OutOfRange => RunningOutOfRange, _ => panic!("unrecognized tracking result") } } @@ -30,23 +30,27 @@ impl TrackedDevicePose { pub fn device_is_connected(&self) -> bool { self.0.bDeviceIsConnected } } -#[derive(Debug, Copy, Clone)] -pub enum TrackingResult { - Uninitialized = sys::ETrackingResult_ETrackingResult_TrackingResult_Uninitialized as isize, - CalibratingInProgress = sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_InProgress as isize, - CalibratingOutOfRange = sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_OutOfRange as isize, - OK = sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OK as isize, - RunningOutOfRange = sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OutOfRange as isize, +impl From for TrackedDevicePose { + fn from(x: sys::TrackedDevicePose_t) -> Self { TrackedDevicePose(x) } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum TrackingResult { + Uninitialized = sys::ETrackingResult_TrackingResult_Uninitialized as isize, + CalibratingInProgress = sys::ETrackingResult_TrackingResult_Calibrating_InProgress as isize, + CalibratingOutOfRange = sys::ETrackingResult_TrackingResult_Calibrating_OutOfRange as isize, + OK = sys::ETrackingResult_TrackingResult_Running_OK as isize, + RunningOutOfRange = sys::ETrackingResult_TrackingResult_Running_OutOfRange as isize, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum TrackedDeviceClass { - Invalid = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Invalid as isize, - HMD = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_HMD as isize, - Controller = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Controller as isize, - GenericTracker = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_GenericTracker as isize, - TrackingReference = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_TrackingReference as isize, - DisplayRedirect = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect as isize, + Invalid = sys::ETrackedDeviceClass_TrackedDeviceClass_Invalid as isize, + HMD = sys::ETrackedDeviceClass_TrackedDeviceClass_HMD as isize, + Controller = sys::ETrackedDeviceClass_TrackedDeviceClass_Controller as isize, + GenericTracker = sys::ETrackedDeviceClass_TrackedDeviceClass_GenericTracker as isize, + TrackingReference = sys::ETrackedDeviceClass_TrackedDeviceClass_TrackingReference as isize, + DisplayRedirect = sys::ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect as isize, } pub type TrackedDeviceIndex = sys::TrackedDeviceIndex_t; @@ -59,10 +63,12 @@ pub mod tracked_device_index { pub type TrackedDeviceProperty = sys::ETrackedDeviceProperty; -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum TrackedControllerRole { - LeftHand = sys::ETrackedControllerRole_ETrackedControllerRole_TrackedControllerRole_LeftHand as isize, - RightHand = sys::ETrackedControllerRole_ETrackedControllerRole_TrackedControllerRole_RightHand as isize, + LeftHand = sys::ETrackedControllerRole_TrackedControllerRole_LeftHand as isize, + RightHand = sys::ETrackedControllerRole_TrackedControllerRole_RightHand as isize, } -pub type TrackedDevicePoses = [TrackedDevicePose; sys::k_unMaxTrackedDeviceCount as usize]; +pub const MAX_TRACKED_DEVICE_COUNT: usize = sys::k_unMaxTrackedDeviceCount as usize; + +pub type TrackedDevicePoses = [TrackedDevicePose; MAX_TRACKED_DEVICE_COUNT];