diff --git a/Cargo.lock b/Cargo.lock index 7b04c11..b40e32c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "openvr" -version = "0.2.0" +version = "0.3.0" dependencies = [ "glium 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "nalgebra 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 25c95cc..0eabb51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openvr" -version = "0.2.0" +version = "0.3.0" authors = [ "Colin Sherratt", "Erick Tryzelaar", diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..a9c8c29 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,123 @@ +use openvr_sys; +use subsystems::*; + +pub trait RawError { + fn is_err(&self) -> bool; + fn message(&self) -> String; +} + +#[derive(Debug)] +pub struct Error { + raw: Err +} + +impl Error { + /// Creates a new error object using the raw openvr_sys error + pub fn from_raw(raw: Err) -> Self { + Error { + raw: raw + } + } + + /// Turns managed error into raw enum from binding + pub fn to_raw(&self) -> Err { + self.raw + } + + /// Gets an human-readable error message (if available) + pub fn message(&self) -> String { + self.raw.message() + } + + /// Returns true when current object is not an error + pub fn is_ok(&self) -> bool { + !self.raw.is_err() + } + + /// Return true when current object is an error + pub fn is_err(&self) -> bool { + self.raw.is_err() + } +} + +// OpenVR implement per error type a new function to get a error string +// for easier use, this macro will generate easily the RawError trait +macro_rules! impl_raw_error { + ($subsystem:ident, $fntable: ident, $get:ident, $raw_name:ident, $none_name:ident) => { + impl RawError for $raw_name { + fn is_err(&self) -> bool { + match *self { + $none_name => { + true + }, + _ => { + false + } + } + } + + fn message(&self) -> String { + let sstr = unsafe { + let sub = * { $subsystem().unwrap().0 as *mut openvr_sys::$fntable}; + CStr::from_ptr(sub.$get.unwrap()(*self)).to_str().unwrap() + }; + + String::from(sstr) + } + } + } +} + +use std::ffi::CStr; +use openvr_sys::*; +use openvr_sys::Enum_ETrackedPropertyError::*; +use openvr_sys::Enum_EVRInitError::*; +use openvr_sys::Enum_EVRRenderModelError::*; + +impl_raw_error!( + system, + Struct_VR_IVRSystem_FnTable, + GetPropErrorNameFromEnum, + ETrackedPropertyError, + ETrackedPropertyError_TrackedProp_Success); + + +// The init error has some special function to retrieve string +impl RawError for Enum_EVRInitError { + fn is_err(&self) -> bool { + match *self { + EVRInitError_VRInitError_None => { + true + }, + _ => { + false + } + } + } + + fn message(&self) -> String { + let sstr = unsafe { + CStr::from_ptr(openvr_sys::VR_GetVRInitErrorAsEnglishDescription(*self)).to_str().unwrap() + }; + + String::from(sstr) + } +} + +// RenderModelError has no implementation in 0.1.19 unfortunately +impl RawError for Enum_EVRRenderModelError { + fn is_err(&self) -> bool { + match *self { + EVRRenderModelError_VRRenderModelError_None => { + true + }, + _ => { + false + } + } + } + + fn message(&self) -> String { + String::from(format!("{:?}", *self)) + } +} diff --git a/src/lib.rs b/src/lib.rs index 49a07b7..8d8a0e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub use openvr_sys::Enum_ETrackedDeviceProperty::*; pub use openvr_sys::Enum_ETrackedDeviceClass::*; pub mod common; +pub mod error; pub mod tracking; pub mod system; pub mod extended_display; @@ -18,11 +19,12 @@ pub use compositor::IVRCompositor; pub use render_models::IVRRenderModels; pub use subsystems::*; +pub use error::*; pub use common::Eye; /// Inits the open vr interface and returns the system -pub fn init() -> Result { +pub fn init() -> Result> { let mut err = EVRInitError_VRInitError_None; let app_type = EVRApplicationType_VRApplication_Scene; @@ -46,7 +48,7 @@ pub fn init() -> Result { } }, _ => { - return Err(err); + return Err(Error::from_raw(err)); } }; } diff --git a/src/render_models.rs b/src/render_models.rs index 8f4eaff..b3dcb54 100644 --- a/src/render_models.rs +++ b/src/render_models.rs @@ -5,12 +5,31 @@ use std::string::String; use std::ptr::null_mut; use std::slice; use subsystems::render_models; +use error::*; pub struct IVRRenderModels(*const ()); 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) { @@ -54,7 +73,7 @@ impl RenderModel { /// 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 { + pub fn load_texture_async(&self) -> Result> { unsafe { let models = * { render_models().unwrap().0 as *mut openvr_sys::Struct_VR_IVRRenderModels_FnTable}; let mut resp: *mut openvr_sys::RenderModel_TextureMap_t = null_mut(); @@ -69,7 +88,7 @@ impl RenderModel { Ok(RenderModelTexture (resp)) }, _ => { - Err(err) + Err(Error::from_raw(err)) } } @@ -77,7 +96,7 @@ impl RenderModel { } /// loads the texture for current model - pub fn load_texture(&self) -> Result { + pub fn load_texture(&self) -> Result> { use std; loop { @@ -87,13 +106,8 @@ impl RenderModel { return Ok(texture); }, Err(err) => { - match err { - EVRRenderModelError_VRRenderModelError_Loading => { - // ask again later - }, - _ => { - return Err(err); - } + if !err.is_loading() { + return Err(err); } } } @@ -158,7 +172,7 @@ impl IVRRenderModels { /// Loads an render model into local memory /// blocks the thread and waits until driver responds with model - pub fn load(&self, name: String) -> Result { + pub fn load(&self, name: String) -> Result> { use std; loop { @@ -168,13 +182,8 @@ impl IVRRenderModels { return Ok(model); }, Err(err) => { - match err { - EVRRenderModelError_VRRenderModelError_Loading => { - // ask again later - }, - _ => { - return Err(err); - } + if !err.is_loading() { + return Err(err); } } } @@ -186,7 +195,7 @@ impl IVRRenderModels { /// 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 { + pub fn load_async(&self, name: String) -> Result> { use std; unsafe { @@ -207,7 +216,7 @@ impl IVRRenderModels { Ok(RenderModel ( resp )) }, _ => { - Err(err) + Err(Error::from_raw(err)) } } diff --git a/src/subsystems.rs b/src/subsystems.rs index 2d35312..8d59a27 100644 --- a/src/subsystems.rs +++ b/src/subsystems.rs @@ -1,6 +1,7 @@ extern crate openvr_sys; use openvr_sys::Enum_EVRInitError::*; +use error::*; use system::IVRSystem; use extended_display::IVRExtendedDisplay; use compositor::IVRCompositor; @@ -9,7 +10,7 @@ use render_models::IVRRenderModels; use std; /// gets the current vr system interface (initialization is required beforehand) -pub fn system() -> Result { +pub fn system() -> Result> { let mut err = EVRInitError_VRInitError_None; let name = std::ffi::CString::new("FnTable:IVRSystem_012").unwrap(); let ptr = unsafe { @@ -23,13 +24,13 @@ pub fn system() -> Result { } }, _ => { - return Err(err); + return Err(Error::from_raw(err)); } } } /// gets the current vr extended display interface (initialization is required beforehand) -pub fn extended_display() -> Result { +pub fn extended_display() -> Result> { let mut err = EVRInitError_VRInitError_None; let name = std::ffi::CString::new("FnTable:IVRExtendedDisplay_001").unwrap(); let ptr = unsafe { @@ -43,13 +44,13 @@ pub fn extended_display() -> Result { } }, _ => { - return Err(err); + return Err(Error::from_raw(err)); } } } /// gets the current vr extended display interface (initialization is required beforehand) -pub fn compositor() -> Result { +pub fn compositor() -> Result> { let mut err = EVRInitError_VRInitError_None; let name = std::ffi::CString::new("FnTable:IVRCompositor_013").unwrap(); let ptr = unsafe { @@ -63,13 +64,13 @@ pub fn compositor() -> Result { } }, _ => { - return Err(err); + return Err(Error::from_raw(err)); } } } /// gets the current vr extended display interface (initialization is required beforehand) -pub fn render_models() -> Result { +pub fn render_models() -> Result> { let mut err = EVRInitError_VRInitError_None; let name = std::ffi::CString::new("FnTable:IVRRenderModels_005").unwrap(); let ptr = unsafe { @@ -83,7 +84,7 @@ pub fn render_models() -> Result { } }, _ => { - return Err(err); + return Err(Error::from_raw(err)); } } } diff --git a/src/tracking.rs b/src/tracking.rs index 9002d12..c427f93 100644 --- a/src/tracking.rs +++ b/src/tracking.rs @@ -1,6 +1,8 @@ use openvr_sys; use openvr_sys::Enum_ETrackedPropertyError::*; + use subsystems::*; +use error::*; #[derive(Debug, Copy, Clone)] pub struct TrackedDevicePose { @@ -22,7 +24,7 @@ impl TrackedDevicePose { } /// gets a propery as a string - pub fn get_property_string(&self, property: openvr_sys::Enum_ETrackedDeviceProperty) -> Result { + pub fn get_property_string(&self, property: openvr_sys::Enum_ETrackedDeviceProperty) -> Result> { unsafe { let system = * { system().unwrap().0 as *mut openvr_sys::Struct_VR_IVRSystem_FnTable}; @@ -40,7 +42,7 @@ impl TrackedDevicePose { if size > 0 { return Ok(String::from_raw_parts(val_out.as_ptr() as *mut _, (size - 1) as usize, (size - 1) as usize)); } else { - return Err(err); + return Err(Error::from_raw(err)); } } }