mirror of
https://github.com/mii443/rust-openvr.git
synced 2025-08-22 16:25:36 +00:00
Merge pull request #23 from Ralith/update
WIP: Changes for OpenVR 1.0.7
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
dist: trusty
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
|
@ -4,7 +4,8 @@ version = "0.4.0"
|
||||
authors = [
|
||||
"Colin Sherratt",
|
||||
"Erick Tryzelaar",
|
||||
"Rene Eichhorn"
|
||||
"Rene Eichhorn",
|
||||
"Benjamin Saunders"
|
||||
]
|
||||
license-file = "LICENSE.md"
|
||||
|
||||
@ -14,12 +15,8 @@ repository = "https://github.com/rust-openvr/rust-openvr"
|
||||
|
||||
description = "A safe binding for openvr."
|
||||
|
||||
[lib]
|
||||
name = "openvr"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
openvr_sys = "1.0.2"
|
||||
openvr_sys = { git = "https://github.com/Ralith/rust-openvr-sys.git", branch = "update" }
|
||||
|
||||
[dev_dependencies]
|
||||
glium = "0.14.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2016 Colin Sherratt, Erick Tryzelaar, Rene Eichhorn
|
||||
Copyright (c) 2016 Colin Sherratt, Erick Tryzelaar, Rene Eichhorn, Benjamin Saunders
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
@ -1,73 +0,0 @@
|
||||
use openvr_sys;
|
||||
use openvr_sys::EGraphicsAPIConvention::*;
|
||||
use openvr_sys::EVRSubmitFlags::*;
|
||||
use openvr_sys::EColorSpace::*;
|
||||
use common::*;
|
||||
use tracking::*;
|
||||
|
||||
/// A VR compositor
|
||||
pub struct IVRCompositor(*const ());
|
||||
|
||||
impl IVRCompositor {
|
||||
pub unsafe fn from_raw(ptr: *const ()) -> Self {
|
||||
IVRCompositor(ptr as *mut ())
|
||||
}
|
||||
|
||||
/// Check to see if the compositor is fullscreen
|
||||
pub fn is_fullscreen(&self) -> bool {
|
||||
unsafe {
|
||||
let comp = * { self.0 as *mut openvr_sys::VR_IVRCompositor_FnTable };
|
||||
comp.IsFullscreen.unwrap()() > 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if compositor can render a scene
|
||||
pub fn can_render_scene(&self) -> bool {
|
||||
unsafe {
|
||||
let comp = * { self.0 as *mut openvr_sys::VR_IVRCompositor_FnTable };
|
||||
comp.CanRenderScene.unwrap()() > 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Submits an opengl framebuffer as an eye to the render
|
||||
pub fn submit(&self, eye: Eye, texture: usize, bounds: TextureBounds) {
|
||||
let mut b = bounds.to_raw();
|
||||
let e = eye.to_raw();
|
||||
|
||||
unsafe {
|
||||
use std;
|
||||
|
||||
let comp = * { self.0 as *mut openvr_sys::VR_IVRCompositor_FnTable };
|
||||
let mut t = openvr_sys::Texture_t {
|
||||
eType: EGraphicsAPIConvention_API_OpenGL,
|
||||
eColorSpace: EColorSpace_ColorSpace_Auto,
|
||||
handle: texture as *mut std::os::raw::c_void,
|
||||
};
|
||||
|
||||
comp.Submit.unwrap()(
|
||||
e,
|
||||
&mut t,
|
||||
&mut b as *mut openvr_sys::VRTextureBounds_t,
|
||||
EVRSubmitFlags_Submit_GlRenderBuffer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the poses
|
||||
pub fn wait_get_poses(&self) -> TrackedDevicePoses {
|
||||
use std;
|
||||
|
||||
unsafe {
|
||||
let comp = * { self.0 as *mut openvr_sys::VR_IVRCompositor_FnTable };
|
||||
let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
|
||||
|
||||
comp.WaitGetPoses.unwrap()(
|
||||
&mut data[0],
|
||||
16,
|
||||
std::ptr::null_mut(),
|
||||
0
|
||||
);
|
||||
to_tracked(data)
|
||||
}
|
||||
}
|
||||
}
|
168
src/compositor/mod.rs
Normal file
168
src/compositor/mod.rs
Normal file
@ -0,0 +1,168 @@
|
||||
//! The `Compositor` implements distortion, prediction, synchronization and other subtle issues that can be a challenge to
|
||||
//! get operating properly for a solid VR experience.
|
||||
//!
|
||||
//! Applications call WaitGetPoses to get the set of poses used to render the camera and other tracked objects, render
|
||||
//! the left and right eyes as normal (using the info provided by `System`) and finally `submit` those undistorted
|
||||
//! textures for the `Compositor` to display on the output device.
|
||||
//!
|
||||
//! It is recommended that you continue presenting your application's own window, reusing either the left or right eye
|
||||
//! camera render target to draw a single quad (perhaps cropped to a lower fov to hide the hidden area mask).
|
||||
|
||||
use std::{mem, ptr, error, fmt};
|
||||
use std::ffi::CString;
|
||||
|
||||
use openvr_sys as sys;
|
||||
|
||||
pub mod texture;
|
||||
|
||||
pub use self::texture::Texture;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<'a> Compositor<'a> {
|
||||
pub fn vulkan_instance_extensions_required(&self) -> Vec<CString> {
|
||||
let temp = unsafe {
|
||||
let n = (self.0.GetVulkanInstanceExtensionsRequired.unwrap())(ptr::null_mut(), 0);
|
||||
let mut buffer: Vec<u8> = Vec::new();
|
||||
buffer.resize(n as usize, mem::uninitialized());
|
||||
(self.0.GetVulkanInstanceExtensionsRequired.unwrap())(buffer.as_mut_ptr() as *mut i8, n);
|
||||
buffer
|
||||
};
|
||||
temp.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<CString> {
|
||||
let temp = unsafe {
|
||||
let n = (self.0.GetVulkanDeviceExtensionsRequired.unwrap())(physical_device, ptr::null_mut(), 0);
|
||||
let mut buffer: Vec<u8> = 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
|
||||
};
|
||||
temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
|
||||
}
|
||||
|
||||
/// Sets tracking space returned by WaitGetPoses
|
||||
pub fn set_tracking_space(&self, origin: TrackingUniverseOrigin) {
|
||||
unsafe { (self.0.SetTrackingSpace.unwrap())(origin as sys::ETrackingUniverseOrigin) }
|
||||
}
|
||||
|
||||
/// Block until a few milliseconds before the next vsync, then return poses for the next step of rendering and game
|
||||
/// logic.
|
||||
///
|
||||
/// Poses are relative to the origin set by `set_tracking_space`.
|
||||
pub fn wait_get_poses(&self) -> Result<WaitPoses, CompositorError> {
|
||||
unsafe {
|
||||
let mut result: WaitPoses = mem::uninitialized();
|
||||
let e = (self.0.WaitGetPoses.unwrap())(result.render.data.as_mut().as_mut_ptr() as *mut _, result.render.data.len() as u32,
|
||||
result.game.data.as_mut().as_mut_ptr() as *mut _, result.game.data.len() as u32);
|
||||
if e == sys::EVRCompositorError_EVRCompositorError_VRCompositorError_None {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(CompositorError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
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,
|
||||
};
|
||||
let texture = sys::Texture_t {
|
||||
handle: match texture.handle {
|
||||
Vulkan(ref x) => x as *const _ as *mut _,
|
||||
OpenGLTexture(x) => x as *mut _,
|
||||
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,
|
||||
},
|
||||
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 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CompositorError(e))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post_present_handoff(&self) {
|
||||
unsafe { (self.0.PostPresentHandoff.unwrap())() };
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct WaitPoses {
|
||||
/// Predicted to the point they will be at the upcoming frame.
|
||||
pub render: TrackedDevicePoses,
|
||||
/// Predicted to the point they will be at the frame after the upcoming frame, for use in game logic.
|
||||
pub game: TrackedDevicePoses,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
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);
|
||||
}
|
||||
|
||||
impl fmt::Debug for CompositorError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad(error::Error::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CompositorError {
|
||||
fn description(&self) -> &str {
|
||||
use self::compositor_error::*;
|
||||
match *self {
|
||||
REQUEST_FAILED => "REQUEST_FAILED",
|
||||
INCOMPATIBLE_VERSION => "INCOMPATIBLE_VERSION",
|
||||
DO_NOT_HAVE_FOCUS => "DO_NOT_HAVE_FOCUS",
|
||||
INVALID_TEXTURE => "INVALID_TEXTURE",
|
||||
IS_NOT_SCENE_APPLICATION => "IS_NOT_SCENE_APPLICATION",
|
||||
TEXTURE_IS_ON_WRONG_DEVICE => "TEXTURE_IS_ON_WRONG_DEVICE",
|
||||
TEXTURE_USES_UNSUPPORTED_FORMAT => "TEXTURE_USES_UNSUPPORTED_FORMAT",
|
||||
SHARED_TEXTURES_NOT_SUPPORTED => "SHARED_TEXTURES_NOT_SUPPORTED",
|
||||
INDEX_OUT_OF_RANGE => "INDEX_OUT_OF_RANGE",
|
||||
ALREADY_SUBMITTED => "ALREADY_SUBMITTED",
|
||||
_ => "UNKNOWN",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompositorError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
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;
|
45
src/compositor/texture.rs
Normal file
45
src/compositor/texture.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use super::{sys, VkInstance_T, VkDevice_T, VkPhysicalDevice_T, VkQueue_T};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Texture {
|
||||
pub handle: Handle,
|
||||
pub color_space: ColorSpace,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Bounds {
|
||||
pub min: (f32, f32),
|
||||
pub max: (f32, f32),
|
||||
}
|
||||
|
||||
pub mod vulkan {
|
||||
use super::*;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Texture {
|
||||
pub image: u64,
|
||||
pub device: *mut VkDevice_T,
|
||||
pub physical_device: *mut VkPhysicalDevice_T,
|
||||
pub instance: *mut VkInstance_T,
|
||||
pub queue: *mut VkQueue_T,
|
||||
pub queue_family_index: u32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub format: u32,
|
||||
pub sample_count: u32,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Handle {
|
||||
Vulkan(vulkan::Texture),
|
||||
OpenGLTexture(usize),
|
||||
OpenGLRenderBuffer(usize),
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
119
src/error.rs
119
src/error.rs
@ -1,119 +0,0 @@
|
||||
use openvr_sys;
|
||||
use subsystems::*;
|
||||
|
||||
pub trait RawError {
|
||||
fn is_err(&self) -> bool;
|
||||
fn message(&self) -> String;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error<Err: RawError + Copy> {
|
||||
raw: Err
|
||||
}
|
||||
|
||||
impl<Err: RawError + Copy> Error<Err> {
|
||||
/// 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 => {
|
||||
false
|
||||
},
|
||||
_ => {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::ETrackedPropertyError::*;
|
||||
use openvr_sys::EVRInitError::*;
|
||||
use openvr_sys::EVRRenderModelError::*;
|
||||
use openvr_sys::EVRTrackedCameraError::*;
|
||||
|
||||
impl_raw_error!(
|
||||
system,
|
||||
VR_IVRSystem_FnTable,
|
||||
GetPropErrorNameFromEnum,
|
||||
ETrackedPropertyError,
|
||||
ETrackedPropertyError_TrackedProp_Success);
|
||||
|
||||
impl_raw_error!(
|
||||
render_models,
|
||||
VR_IVRRenderModels_FnTable,
|
||||
GetRenderModelErrorNameFromEnum,
|
||||
EVRRenderModelError,
|
||||
EVRRenderModelError_VRRenderModelError_None);
|
||||
|
||||
impl_raw_error!(
|
||||
tracked_camera,
|
||||
VR_IVRTrackedCamera_FnTable,
|
||||
GetCameraErrorNameFromEnum,
|
||||
EVRTrackedCameraError,
|
||||
EVRTrackedCameraError_VRTrackedCameraError_None);
|
||||
|
||||
// The init error has some special function to retrieve string
|
||||
impl RawError for 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)
|
||||
}
|
||||
}
|
171
src/lib.rs
171
src/lib.rs
@ -1,62 +1,135 @@
|
||||
extern crate openvr_sys;
|
||||
|
||||
use openvr_sys::EVRInitError::*;
|
||||
use openvr_sys::EVRApplicationType::*;
|
||||
use std::sync::atomic::{Ordering, AtomicBool, ATOMIC_BOOL_INIT};
|
||||
use std::{fmt, error, slice};
|
||||
use std::ffi::CStr;
|
||||
|
||||
pub mod common;
|
||||
pub mod error;
|
||||
pub mod tracking;
|
||||
pub mod system;
|
||||
pub mod extended_display;
|
||||
pub mod compositor;
|
||||
pub mod render_models;
|
||||
pub mod tracked_camera;
|
||||
pub mod subsystems;
|
||||
use openvr_sys as sys;
|
||||
|
||||
pub use system::IVRSystem;
|
||||
pub use extended_display::IVRExtendedDisplay;
|
||||
pub use compositor::IVRCompositor;
|
||||
pub use render_models::IVRRenderModels;
|
||||
pub use tracked_camera::IVRTrackedCamera;
|
||||
mod tracking;
|
||||
|
||||
pub use subsystems::*;
|
||||
pub use error::*;
|
||||
mod system;
|
||||
mod compositor;
|
||||
|
||||
pub use common::Eye;
|
||||
pub use tracking::*;
|
||||
|
||||
/// Inits the open vr interface and returns the system
|
||||
pub fn init() -> Result<system::IVRSystem, Error<openvr_sys::EVRInitError>> {
|
||||
let mut err = EVRInitError_VRInitError_None;
|
||||
let app_type = EVRApplicationType_VRApplication_Scene;
|
||||
static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
// try to initialize base vr eco
|
||||
unsafe {
|
||||
openvr_sys::VR_InitInternal(&mut err, app_type);
|
||||
};
|
||||
/// Initialize OpenVR
|
||||
///
|
||||
/// # Panics
|
||||
/// When the library has already been initialized
|
||||
pub fn init(ty: ApplicationType) -> Result<Context, InitError> {
|
||||
if INITIALIZED.swap(true, Ordering::AcqRel) {
|
||||
panic!("OpenVR has already been initialized!");
|
||||
}
|
||||
|
||||
// check for errors
|
||||
match err {
|
||||
EVRInitError_VRInitError_None => {
|
||||
// get system
|
||||
let result = system();
|
||||
match result {
|
||||
Ok(sys) => {
|
||||
return Ok(sys);
|
||||
},
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
};
|
||||
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 {
|
||||
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));
|
||||
}
|
||||
Ok(Context {})
|
||||
}
|
||||
|
||||
/// Shutdowns all openvr related systems
|
||||
pub fn shutdown() {
|
||||
unsafe {
|
||||
openvr_sys::VR_ShutdownInternal();
|
||||
pub struct System<'a>(&'a sys::VR_IVRSystem_FnTable);
|
||||
pub struct Compositor<'a>(&'a sys::VR_IVRCompositor_FnTable);
|
||||
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 {}
|
||||
|
||||
fn load<T>(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 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));
|
||||
}
|
||||
Ok(result as *const T)
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn system(&self) -> Result<System, InitError> { load(sys::IVRSystem_Version).map(|x| unsafe { System(&*x) }) }
|
||||
pub fn compositor(&self) -> Result<Compositor, InitError> { load(sys::IVRCompositor_Version).map(|x| unsafe { Compositor(&*x) }) }
|
||||
pub fn render_models(&self) -> Result<RenderModels, InitError> { load(sys::IVRRenderModels_Version).map(|x| unsafe { RenderModels(&*x) }) }
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::VR_ShutdownInternal() }
|
||||
INITIALIZED.store(false, Ordering::AcqRel);
|
||||
}
|
||||
}
|
||||
|
||||
#[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,
|
||||
/// Application will submit 3D frames
|
||||
Scene = sys::EVRApplicationType_EVRApplicationType_VRApplication_Scene as isize,
|
||||
/// Application only interacts with overlays
|
||||
Overlay = sys::EVRApplicationType_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,
|
||||
/// 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,
|
||||
/// Reserved for vrmonitor
|
||||
VRMonitor = sys::EVRApplicationType_EVRApplicationType_VRApplication_VRMonitor as isize,
|
||||
/// Reserved for Steam
|
||||
SteamWatchdog = sys::EVRApplicationType_EVRApplicationType_VRApplication_SteamWatchdog as isize,
|
||||
/// Start up SteamVR
|
||||
Bootstrapper = sys::EVRApplicationType_EVRApplicationType_VRApplication_Bootstrapper as isize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct InitError(sys::EVRInitError);
|
||||
|
||||
impl fmt::Debug for InitError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let msg = unsafe {
|
||||
CStr::from_ptr(sys::VR_GetVRInitErrorAsSymbol(self.0))
|
||||
};
|
||||
f.pad(msg.to_str().expect("OpenVR init error symbol was not valid UTF-8"))
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for InitError {
|
||||
fn description(&self) -> &str {
|
||||
let msg = unsafe {
|
||||
CStr::from_ptr(sys::VR_GetVRInitErrorAsEnglishDescription(self.0))
|
||||
};
|
||||
msg.to_str().expect("OpenVR init error description was not valid UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InitError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad(error::Error::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TrackedDevicePoses {
|
||||
data: [TrackedDevicePose; sys::k_unMaxTrackedDeviceCount as usize]
|
||||
}
|
||||
|
||||
impl TrackedDevicePoses {
|
||||
pub fn iter(&self) -> slice::Iter<TrackedDevicePose> { self.data.iter() }
|
||||
pub fn len(&self) -> usize { self.data.len() }
|
||||
}
|
||||
|
@ -1,111 +0,0 @@
|
||||
extern crate openvr_sys;
|
||||
use openvr_sys::EVRInitError::*;
|
||||
|
||||
use error::*;
|
||||
use system::IVRSystem;
|
||||
use extended_display::IVRExtendedDisplay;
|
||||
use compositor::IVRCompositor;
|
||||
use render_models::IVRRenderModels;
|
||||
use tracked_camera::IVRTrackedCamera;
|
||||
|
||||
use std;
|
||||
|
||||
/// gets the current vr system interface (initialization is required beforehand)
|
||||
pub fn system() -> Result<IVRSystem, Error<openvr_sys::EVRInitError>> {
|
||||
let mut err = EVRInitError_VRInitError_None;
|
||||
let name = std::ffi::CString::new("FnTable:IVRSystem_012").unwrap();
|
||||
let ptr = unsafe {
|
||||
openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err)
|
||||
};
|
||||
|
||||
match err {
|
||||
EVRInitError_VRInitError_None => {
|
||||
unsafe {
|
||||
return Ok(IVRSystem::from_raw(ptr as *const ()));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// gets the current vr extended display interface (initialization is required beforehand)
|
||||
pub fn extended_display() -> Result<IVRExtendedDisplay, Error<openvr_sys::EVRInitError>> {
|
||||
let mut err = EVRInitError_VRInitError_None;
|
||||
let name = std::ffi::CString::new("FnTable:IVRExtendedDisplay_001").unwrap();
|
||||
let ptr = unsafe {
|
||||
openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err)
|
||||
};
|
||||
|
||||
match err {
|
||||
EVRInitError_VRInitError_None => {
|
||||
unsafe {
|
||||
return Ok(IVRExtendedDisplay::from_raw(ptr as *const ()));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// gets the current vr extended display interface (initialization is required beforehand)
|
||||
pub fn compositor() -> Result<IVRCompositor, Error<openvr_sys::EVRInitError>> {
|
||||
let mut err = EVRInitError_VRInitError_None;
|
||||
let name = std::ffi::CString::new("FnTable:IVRCompositor_013").unwrap();
|
||||
let ptr = unsafe {
|
||||
openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err)
|
||||
};
|
||||
|
||||
match err {
|
||||
EVRInitError_VRInitError_None => {
|
||||
unsafe {
|
||||
return Ok(IVRCompositor::from_raw(ptr as *const ()));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// gets the current vr extended display interface (initialization is required beforehand)
|
||||
pub fn render_models() -> Result<IVRRenderModels, Error<openvr_sys::EVRInitError>> {
|
||||
let mut err = EVRInitError_VRInitError_None;
|
||||
let name = std::ffi::CString::new("FnTable:IVRRenderModels_005").unwrap();
|
||||
let ptr = unsafe {
|
||||
openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err)
|
||||
};
|
||||
|
||||
match err {
|
||||
EVRInitError_VRInitError_None => {
|
||||
unsafe {
|
||||
return Ok(IVRRenderModels::from_raw(ptr as *const ()));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// gets the current vr extended display interface (initialization is required beforehand)
|
||||
pub fn tracked_camera() -> Result<IVRTrackedCamera, Error<openvr_sys::EVRInitError>> {
|
||||
let mut err = EVRInitError_VRInitError_None;
|
||||
let name = std::ffi::CString::new("FnTable:IVRTrackedCamera_003").unwrap();
|
||||
let ptr = unsafe {
|
||||
openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err)
|
||||
};
|
||||
|
||||
match err {
|
||||
EVRInitError_VRInitError_None => {
|
||||
unsafe {
|
||||
return Ok(IVRTrackedCamera::from_raw(ptr as *const ()));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
}
|
||||
}
|
112
src/system.rs
112
src/system.rs
@ -1,112 +0,0 @@
|
||||
use openvr_sys;
|
||||
use openvr_sys::EGraphicsAPIConvention::*;
|
||||
use openvr_sys::ETrackingUniverseOrigin::*;
|
||||
|
||||
use common::*;
|
||||
use tracking::*;
|
||||
|
||||
pub struct IVRSystem(pub *const ());
|
||||
|
||||
impl IVRSystem {
|
||||
pub unsafe fn from_raw(ptr: *const ()) -> Self {
|
||||
IVRSystem(ptr as *mut ())
|
||||
}
|
||||
|
||||
/// Get the recommended render target size
|
||||
pub fn recommended_render_target_size(&self) -> Size {
|
||||
unsafe {
|
||||
let system = * { self.0 as *mut openvr_sys::VR_IVRSystem_FnTable };
|
||||
|
||||
let mut size = Size{width: 0, height: 0};
|
||||
system.GetRecommendedRenderTargetSize.unwrap()(
|
||||
&mut size.width,
|
||||
&mut size.height
|
||||
);
|
||||
size
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Get the projection matrix for an eye
|
||||
/// supply the near and the far position
|
||||
/// assumes opengl conventions
|
||||
pub fn projection_matrix(&self, eye: Eye, near: f32, far: f32) -> [[f32; 4]; 4] {
|
||||
unsafe {
|
||||
let system = * { self.0 as *mut openvr_sys::VR_IVRSystem_FnTable };
|
||||
|
||||
let mat = system.GetProjectionMatrix.unwrap()(
|
||||
eye.to_raw(),
|
||||
near,
|
||||
far,
|
||||
EGraphicsAPIConvention_API_OpenGL
|
||||
);
|
||||
mat.m
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the distortion caused by the optics
|
||||
pub fn compute_distortion(&self, eye: Eye, u: f32, v: f32) -> DistortionCoordinates {
|
||||
unsafe {
|
||||
let system = * { self.0 as *mut openvr_sys::VR_IVRSystem_FnTable };
|
||||
let coord = system.ComputeDistortion.unwrap()(
|
||||
eye.to_raw(),
|
||||
u, v
|
||||
);
|
||||
DistortionCoordinates {
|
||||
red: coord.rfRed,
|
||||
blue: coord.rfBlue,
|
||||
green: coord.rfGreen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the distortion caused by the optics
|
||||
pub fn eye_to_head_transform(&self, eye: Eye) -> [[f32; 4]; 3] {
|
||||
unsafe {
|
||||
let system = * { self.0 as *mut openvr_sys::VR_IVRSystem_FnTable };
|
||||
let mat = system.GetEyeToHeadTransform.unwrap()(
|
||||
eye.to_raw(),
|
||||
);
|
||||
mat.m
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the distortion caused by the optics
|
||||
pub fn time_since_last_vsync(&self) -> Option<(f32, u64)> {
|
||||
unsafe {
|
||||
let system = * { self.0 as *mut openvr_sys::VR_IVRSystem_FnTable };
|
||||
let mut frame = 0;
|
||||
let mut sync = 0.;
|
||||
let found = system.GetTimeSinceLastVsync.unwrap()(
|
||||
&mut sync,
|
||||
&mut frame
|
||||
);
|
||||
|
||||
if found > 0 {
|
||||
Some((sync, frame))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the tracked results from the HMD
|
||||
/// when time is bigger than 0, it will give you the predicted poses for that time
|
||||
/// Time is counted in photons, see https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
|
||||
/// for time to photons conversion
|
||||
pub fn tracked_devices(&self, time: f32) -> TrackedDevicePoses {
|
||||
use std;
|
||||
|
||||
unsafe {
|
||||
let system = * { self.0 as *mut openvr_sys::VR_IVRSystem_FnTable };
|
||||
let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
|
||||
system.GetDeviceToAbsoluteTrackingPose.unwrap()(
|
||||
ETrackingUniverseOrigin_TrackingUniverseSeated,
|
||||
time,
|
||||
&mut data[0],
|
||||
16
|
||||
);
|
||||
to_tracked(data)
|
||||
}
|
||||
}
|
||||
}
|
463
src/system/event.rs
Normal file
463
src/system/event.rs
Normal file
@ -0,0 +1,463 @@
|
||||
pub struct EventInfo {
|
||||
/// The tracked device index of the event. For events that aren't connected to a tracked device this is
|
||||
/// k_unTrackedDeviceIndexInvalid
|
||||
pub tracked_device_index: TrackedDeviceIndex,
|
||||
|
||||
/// The age of the event in seconds.
|
||||
pub age: f32,
|
||||
|
||||
/// More information about the event.
|
||||
pub event: Event,
|
||||
}
|
||||
|
||||
impl From<sys::VREvent_t> for EventInfo {
|
||||
fn from(x: sys::VREvent_t) -> Self {
|
||||
EventInfo {
|
||||
tracked_device_index: x.trackedDeviceIndex,
|
||||
age: x.eventAgeSeconds,
|
||||
event: Event::from_sys(x.eventType, &x.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait FromEventData {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self;
|
||||
}
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// Controller button events
|
||||
pub struct Controller {
|
||||
pub button: u32,
|
||||
}
|
||||
|
||||
impl FromEventData for Controller {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = x.controller.as_ref();
|
||||
Controller { button: x.button }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// Simulated mouse events in overlay space
|
||||
pub struct Mouse {
|
||||
/// Absolute position in texcoords, with the origin at the bottom left.
|
||||
pub position: (f32, f32),
|
||||
/// Bitfield
|
||||
pub button: u32,
|
||||
}
|
||||
|
||||
impl FromEventData for Mouse {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = x.mouse.as_ref();
|
||||
Mouse { position: (x.x, x.y), button: x.button }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// Simulated mouse wheel scroll in overlay space
|
||||
///
|
||||
/// Coordinates are fraction of the touchpad traversed since last scroll event.
|
||||
pub struct Scroll {
|
||||
pub delta: (f32, f32),
|
||||
pub repeat_count: u32,
|
||||
}
|
||||
|
||||
impl FromEventData for Scroll {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = x.scroll.as_ref();
|
||||
Scroll { delta: (x.xdelta, x.ydelta), repeat_count: x.repeatCount }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// When in mouse input mode you can receive data from the touchpad, these events are only sent if the user's finger
|
||||
/// is on the touchpad (or just released from it)
|
||||
pub struct TouchPadMove {
|
||||
/// if the user's finger is detected on the touch pad
|
||||
pub finger_down: bool,
|
||||
/// How long the finger has been down in seconds
|
||||
pub seconds_finger_down: f32,
|
||||
/// Starting finger position (so you can do some basic swipe stuff)
|
||||
pub first: (f32, f32),
|
||||
/// This is the raw sampled coordinate without deadzoning
|
||||
pub raw: (f32, f32),
|
||||
}
|
||||
|
||||
impl FromEventData for TouchPadMove {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = x.touchPadMove.as_ref();
|
||||
TouchPadMove { finger_down: x.bFingerDown, seconds_finger_down: x.flSecondsFingerDown,
|
||||
first: (x.fValueXFirst, x.fValueYFirst),
|
||||
raw: (x.fValueXRaw, x.fValueYRaw) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// notification related events. Details will still change at this point
|
||||
pub struct Notification {
|
||||
pub user_value: u64,
|
||||
pub notification_id: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Process {
|
||||
pub pid: u32,
|
||||
pub old_pid: u32,
|
||||
pub forced: bool,
|
||||
}
|
||||
|
||||
impl FromEventData for Process {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = x.process.as_ref();
|
||||
Process { pid: x.pid, old_pid: x.oldPid, forced: x.bForced }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Overlay {
|
||||
pub overlay_handle: u64,
|
||||
}
|
||||
|
||||
impl FromEventData for Overlay {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = x.overlay.as_ref();
|
||||
Overlay { overlay_handle: x.overlayHandle }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Status {
|
||||
pub status_state: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Keyboard {
|
||||
pub new_input: [u8; 8],
|
||||
pub user_value: u64,
|
||||
}
|
||||
|
||||
impl FromEventData for Keyboard {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x = &*(x.keyboard.as_ref() as *const _ as *const sys::VREvent_Keyboard_t_real);
|
||||
Keyboard { new_input: *(x.cNewInput.as_ptr() as *const _), user_value: x.uUserValue }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Ipd {
|
||||
pub ipd_meters: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Chaperone {
|
||||
pub previous_universe: u64,
|
||||
pub current_universe: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Property {
|
||||
pub container: PropertyContainerHandle,
|
||||
pub property: TrackedDeviceProperty,
|
||||
}
|
||||
|
||||
impl FromEventData for Property {
|
||||
unsafe fn from_event_data(x: &sys::VREvent_Data_t) -> Self {
|
||||
let x: &sys::VREvent_Property_t = &*(x as *const _ as *const _); // Field is missing from union
|
||||
Property {
|
||||
container: x.container,
|
||||
property: x.prop,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, deprecated)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Event {
|
||||
TrackedDeviceActivated,
|
||||
TrackedDeviceDeactivated,
|
||||
TrackedDeviceUpdated,
|
||||
TrackedDeviceUserInteractionStarted,
|
||||
TrackedDeviceUserInteractionEnded,
|
||||
IpdChanged,
|
||||
EnterStandbyMode,
|
||||
LeaveStandbyMode,
|
||||
TrackedDeviceRoleChanged,
|
||||
WatchdogWakeUpRequested,
|
||||
LensDistortionChanged,
|
||||
PropertyChanged(Property),
|
||||
|
||||
ButtonPress(Controller),
|
||||
ButtonUnpress(Controller),
|
||||
ButtonTouch(Controller),
|
||||
ButtonUntouch(Controller),
|
||||
|
||||
MouseMove(Mouse),
|
||||
MouseButtonDown(Mouse),
|
||||
MouseButtonUp(Mouse),
|
||||
FocusEnter(Overlay),
|
||||
FocusLeave(Overlay),
|
||||
Scroll(Scroll),
|
||||
TouchPadMove(TouchPadMove),
|
||||
/// global event
|
||||
OverlayFocusChanged(Overlay),
|
||||
|
||||
#[deprecated]
|
||||
InputFocusCaptured(Process),
|
||||
#[deprecated]
|
||||
InputFocusReleased(Process),
|
||||
SceneFocusLost(Process),
|
||||
SceneFocusGained(Process),
|
||||
/// The app actually drawing the scene changed (usually to or from the compositor)
|
||||
SceneApplicationChanged(Process),
|
||||
/// New app got access to draw the scene
|
||||
SceneFocusChanged(Process),
|
||||
InputFocusChanged(Process),
|
||||
SceneApplicationSecondaryRenderingStarted(Process),
|
||||
|
||||
/// Sent to the scene application to request hiding render models temporarily
|
||||
HideRenderModels,
|
||||
/// Sent to the scene application to request restoring render model visibility
|
||||
ShowRenderModels,
|
||||
|
||||
OverlayShown,
|
||||
OverlayHidden,
|
||||
DashboardActivated,
|
||||
DashboardDeactivated,
|
||||
/// Sent to the overlay manager - data is overlay
|
||||
DashboardThumbSelected,
|
||||
/// Sent to the overlay manager - data is overlay
|
||||
DashboardRequested,
|
||||
/// Send to the overlay manager
|
||||
ResetDashboard,
|
||||
/// Send to the dashboard to render a toast - data is the notification ID
|
||||
RenderToast,
|
||||
/// Sent to overlays when a SetOverlayRaw or SetOverlayFromFile call finishes loading
|
||||
ImageLoaded,
|
||||
/// Sent to keyboard renderer in the dashboard to invoke it
|
||||
ShowKeyboard,
|
||||
/// Sent to keyboard renderer in the dashboard to hide it
|
||||
HideKeyboard,
|
||||
/// Sent to an overlay when IVROverlay::SetFocusOverlay is called on it
|
||||
OverlayGamepadFocusGained,
|
||||
/// Send to an overlay when it previously had focus and IVROverlay::SetFocusOverlay is called on something else
|
||||
OverlayGamepadFocusLost,
|
||||
OverlaySharedTextureChanged,
|
||||
DashboardGuideButtonDown,
|
||||
DashboardGuideButtonUp,
|
||||
/// Screenshot button combo was pressed, Dashboard should request a screenshot
|
||||
ScreenshotTriggered,
|
||||
/// Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load
|
||||
ImageFailed,
|
||||
DashboardOverlayCreated,
|
||||
|
||||
/// Sent by vrclient application to compositor to take a screenshot
|
||||
RequestScreenshot,
|
||||
/// Sent by compositor to the application that the screenshot has been taken
|
||||
ScreenshotTaken,
|
||||
/// Sent by compositor to the application that the screenshot failed to be taken
|
||||
ScreenshotFailed,
|
||||
/// Sent by compositor to the dashboard that a completed screenshot was submitted
|
||||
SubmitScreenshotToDashboard,
|
||||
/// Sent by compositor to the dashboard that a completed screenshot was submitted
|
||||
ScreenshotProgressToDashboard,
|
||||
|
||||
PrimaryDashboardDeviceChanged,
|
||||
|
||||
Notification_Shown,
|
||||
Notification_Hidden,
|
||||
Notification_BeginInteraction,
|
||||
Notification_Destroyed,
|
||||
|
||||
Quit(Process),
|
||||
ProcessQuit(Process),
|
||||
QuitAborted_UserPrompt(Process),
|
||||
QuitAcknowledged(Process),
|
||||
/// The driver has requested that SteamVR shut down
|
||||
DriverRequestedQuit,
|
||||
|
||||
ChaperoneDataHasChanged,
|
||||
ChaperoneUniverseHasChanged,
|
||||
ChaperoneTempDataHasChanged,
|
||||
ChaperoneSettingsHaveChanged,
|
||||
SeatedZeroPoseReset,
|
||||
|
||||
AudioSettingsHaveChanged,
|
||||
|
||||
BackgroundSettingHasChanged,
|
||||
CameraSettingsHaveChanged,
|
||||
ReprojectionSettingHasChanged,
|
||||
ModelSkinSettingsHaveChanged,
|
||||
EnvironmentSettingsHaveChanged,
|
||||
PowerSettingsHaveChanged,
|
||||
|
||||
StatusUpdate,
|
||||
|
||||
MCImageUpdated,
|
||||
|
||||
FirmwareUpdateStarted,
|
||||
FirmwareUpdateFinished,
|
||||
|
||||
KeyboardClosed,
|
||||
KeyboardCharInput(Keyboard),
|
||||
/// Sent when DONE button clicked on keyboard
|
||||
KeyboardDone,
|
||||
|
||||
ApplicationTransitionStarted,
|
||||
ApplicationTransitionAborted,
|
||||
ApplicationTransitionNewAppStarted,
|
||||
ApplicationListUpdated,
|
||||
ApplicationMimeTypeLoad,
|
||||
ApplicationTransitionNewAppLaunchComplete,
|
||||
ProcessConnected,
|
||||
ProcessDisconnected,
|
||||
|
||||
Compositor_MirrorWindowShown,
|
||||
Compositor_MirrorWindowHidden,
|
||||
Compositor_ChaperoneBoundsShown,
|
||||
Compositor_ChaperoneBoundsHidden,
|
||||
|
||||
TrackedCamera_StartVideoStream,
|
||||
TrackedCamera_StopVideoStream,
|
||||
TrackedCamera_PauseVideoStream,
|
||||
TrackedCamera_ResumeVideoStream,
|
||||
TrackedCamera_EditingSurface,
|
||||
|
||||
PerformanceTest_EnableCapture,
|
||||
PerformanceTest_DisableCapture,
|
||||
PerformanceTest_FidelityLevel,
|
||||
|
||||
MessageOverlay_Closed,
|
||||
|
||||
VendorSpecific(u32),
|
||||
Unknown(u32),
|
||||
}
|
||||
|
||||
impl Event {
|
||||
fn from_sys(ty: u32, data: &sys::VREvent_Data_t) -> Self {
|
||||
use self::Event::*;
|
||||
|
||||
fn get<T: FromEventData>(x: &sys::VREvent_Data_t) -> T {
|
||||
unsafe { T::from_event_data(x) }
|
||||
}
|
||||
|
||||
#[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),
|
||||
x => Unknown(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use sys::PropertyContainerHandle_t as PropertyContainerHandle;
|
131
src/system/mod.rs
Normal file
131
src/system/mod.rs
Normal file
@ -0,0 +1,131 @@
|
||||
//! 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 openvr_sys as sys;
|
||||
|
||||
pub mod event;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub use self::event::{Event, EventInfo};
|
||||
|
||||
impl<'a> System<'a> {
|
||||
/// Provides the game with the minimum size that it should use for its offscreen render target to minimize pixel
|
||||
/// stretching. This size is matched with the projection matrix and distortion function and will change from display
|
||||
/// to display depending on resolution, distortion, and field of view.
|
||||
pub fn recommended_render_target_size(&self) -> (u32, u32) {
|
||||
unsafe {
|
||||
let mut result: (u32, u32) = mem::uninitialized();
|
||||
(self.0.GetRecommendedRenderTargetSize.unwrap())(&mut result.0, &mut result.1);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the projection matrix to use for the specified eye.
|
||||
///
|
||||
/// Clip plane distances are in meters.
|
||||
pub fn projection_matrix(&self, eye: Eye, near_z: f32, far_z: f32) -> [[f32; 4]; 4] {
|
||||
unsafe { (self.0.GetProjectionMatrix.unwrap())(eye as sys::EVREye, near_z, far_z) }.m
|
||||
}
|
||||
|
||||
/// Returns the raw project values to use for the specified eye. Most games should use GetProjectionMatrix instead
|
||||
/// of this method, but sometimes a game needs to do something fancy with its projection and can use these values to
|
||||
/// compute its own matrix.
|
||||
pub fn projection_raw(&self, eye: Eye) -> RawProjection {
|
||||
unsafe {
|
||||
let mut result: RawProjection = mem::uninitialized();
|
||||
(self.0.GetProjectionRaw.unwrap())(eye as sys::EVREye, &mut result.left, &mut result.right, &mut result.top, &mut result.bottom);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the transform between the view space and eye space. Eye space is the per-eye flavor of view space that
|
||||
/// provides stereo disparity. Instead of Model * View * Projection the model is Model * View * Eye *
|
||||
/// Projection. Normally View and Eye will be multiplied together and treated as View in your application.
|
||||
pub fn eye_to_head_transform(&self, eye: Eye) -> [[f32; 4]; 3] {
|
||||
unsafe { (self.0.GetEyeToHeadTransform.unwrap())(eye as sys::EVREye) }.m
|
||||
}
|
||||
|
||||
/// Returns the number of elapsed seconds since the last recorded vsync event and the global number of frames that
|
||||
/// have been rendered. Timing information will come from a vsync timer event in the timer if possible or from the
|
||||
/// application-reported time if that is not available. If no vsync times are available the function will return
|
||||
/// None.
|
||||
pub fn time_since_last_vsync(&self) -> Option<(f32, u64)> {
|
||||
unsafe {
|
||||
let mut result: (f32, u64) = mem::uninitialized();
|
||||
if (self.0.GetTimeSinceLastVsync.unwrap())(&mut result.0, &mut result.1) {
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates updated poses for all devices.
|
||||
///
|
||||
/// The pose that the tracker thinks that the HMD will be in at the specified number of seconds into the
|
||||
/// future. Pass 0 to get the state at the instant the method is called. Most of the time the application should
|
||||
/// calculate the time until the photons will be emitted from the display and pass that time into the method.
|
||||
///
|
||||
/// This is roughly analogous to the inverse of the view matrix in most applications, though many games will need to
|
||||
/// do some additional rotation or translation on top of the rotation and translation provided by the head pose.
|
||||
///
|
||||
/// Seated experiences should call this method with TrackingUniverseSeated and receive poses relative to the seated
|
||||
/// zero pose. Standing experiences should call this method with TrackingUniverseStanding and receive poses relative
|
||||
/// to the chaperone soft bounds. TrackingUniverseRawAndUncalibrated should probably not be used unless the
|
||||
/// application is the chaperone calibration tool itself, but will provide poses relative to the hardware-specific
|
||||
/// coordinate system in the driver.
|
||||
pub fn device_to_absolute_tracking_pose(&self, origin: TrackingUniverseOrigin, predicted_seconds_to_photons_from_now: f32) -> TrackedDevicePoses {
|
||||
unsafe {
|
||||
let mut result: TrackedDevicePoses = mem::uninitialized();
|
||||
(self.0.GetDeviceToAbsoluteTrackingPose.unwrap())(origin as sys::ETrackingUniverseOrigin, predicted_seconds_to_photons_from_now,
|
||||
result.data.as_mut().as_mut_ptr() as *mut _, result.data.len() as u32);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
_ => Invalid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_tracked_device_connected(&self, index: TrackedDeviceIndex) -> bool {
|
||||
unsafe { (self.0.IsTrackedDeviceConnected.unwrap())(index) }
|
||||
}
|
||||
|
||||
pub fn poll_next_event_with_pose(&self, origin: TrackingUniverseOrigin) -> Option<(EventInfo, TrackedDevicePose)> {
|
||||
let mut event = unsafe { mem::uninitialized() };
|
||||
let mut pose = unsafe { mem::uninitialized() };
|
||||
if unsafe { self.0.PollNextEventWithPose.unwrap()(origin as sys::ETrackingUniverseOrigin,
|
||||
&mut event, mem::size_of_val(&event) as u32,
|
||||
&mut pose as *mut _ as *mut _) }
|
||||
{
|
||||
Some((event.into(), pose))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Values represent the tangents of the half-angles from the center view axis
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RawProjection {
|
||||
/// tangent of the half-angle from center axis to the left clipping plane
|
||||
pub left: f32,
|
||||
/// tangent of the half-angle from center axis to the right clipping plane
|
||||
pub right: f32,
|
||||
/// tangent of the half-angle from center axis to the top clipping plane
|
||||
pub top: f32,
|
||||
/// tangent of the half-angle from center axis to the bottom clipping plane
|
||||
pub bottom: f32,
|
||||
}
|
238
src/tracking.rs
238
src/tracking.rs
@ -1,212 +1,58 @@
|
||||
use openvr_sys;
|
||||
use openvr_sys::ETrackedPropertyError::*;
|
||||
use openvr_sys as sys;
|
||||
|
||||
use subsystems::*;
|
||||
use error::*;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
#[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,
|
||||
}
|
||||
|
||||
/// Describes a string property of a tracked device
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum TrackedDeviceStringProperty {
|
||||
TrackingSystemName,
|
||||
ModelNumber,
|
||||
SerialNumber,
|
||||
RenderModelName,
|
||||
ManufacturerName,
|
||||
TrackingFirmwareVersion,
|
||||
HardwareRevision,
|
||||
AllWirelessDongleDescriptions,
|
||||
ConnectedWirelessDongle,
|
||||
FirmwareManualUpdateURL,
|
||||
FirmwareProgrammingTarget,
|
||||
DisplayMCImageLeft,
|
||||
DisplayMCImageRight,
|
||||
DisplayGCImage,
|
||||
CameraFirmwareDescription,
|
||||
AttachedDeviceId,
|
||||
ModeLabel
|
||||
}
|
||||
|
||||
impl TrackedDeviceStringProperty {
|
||||
pub fn to_raw(&self) -> openvr_sys::ETrackedDeviceProperty {
|
||||
use openvr_sys::ETrackedDeviceProperty::*;
|
||||
use self::TrackedDeviceStringProperty::*;
|
||||
|
||||
match *self {
|
||||
TrackingSystemName => ETrackedDeviceProperty_Prop_TrackingSystemName_String,
|
||||
ModelNumber => ETrackedDeviceProperty_Prop_ModelNumber_String,
|
||||
SerialNumber => ETrackedDeviceProperty_Prop_SerialNumber_String,
|
||||
RenderModelName => ETrackedDeviceProperty_Prop_RenderModelName_String,
|
||||
ManufacturerName => ETrackedDeviceProperty_Prop_ManufacturerName_String,
|
||||
TrackingFirmwareVersion => ETrackedDeviceProperty_Prop_TrackingFirmwareVersion_String,
|
||||
HardwareRevision => ETrackedDeviceProperty_Prop_HardwareRevision_String,
|
||||
AllWirelessDongleDescriptions => ETrackedDeviceProperty_Prop_AllWirelessDongleDescriptions_String,
|
||||
ConnectedWirelessDongle => ETrackedDeviceProperty_Prop_ConnectedWirelessDongle_String,
|
||||
FirmwareManualUpdateURL => ETrackedDeviceProperty_Prop_Firmware_ManualUpdateURL_String,
|
||||
FirmwareProgrammingTarget => ETrackedDeviceProperty_Prop_Firmware_ProgrammingTarget_String,
|
||||
DisplayMCImageLeft => ETrackedDeviceProperty_Prop_DisplayMCImageLeft_String,
|
||||
DisplayMCImageRight => ETrackedDeviceProperty_Prop_DisplayMCImageRight_String,
|
||||
DisplayGCImage => ETrackedDeviceProperty_Prop_DisplayGCImage_String,
|
||||
CameraFirmwareDescription => ETrackedDeviceProperty_Prop_CameraFirmwareDescription_String,
|
||||
AttachedDeviceId => ETrackedDeviceProperty_Prop_AttachedDeviceId_String,
|
||||
ModeLabel => ETrackedDeviceProperty_Prop_ModeLabel_String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the class of a tracked device
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum TrackedDeviceClass {
|
||||
Invalid,
|
||||
HMD,
|
||||
Controller,
|
||||
TrackingReference,
|
||||
Other,
|
||||
}
|
||||
|
||||
impl TrackedDeviceClass {
|
||||
pub fn to_raw(&self) -> openvr_sys::ETrackedDeviceClass {
|
||||
use self::TrackedDeviceClass::*;
|
||||
use openvr_sys::ETrackedDeviceClass::*;
|
||||
|
||||
match *self {
|
||||
Invalid => ETrackedDeviceClass_TrackedDeviceClass_Invalid,
|
||||
HMD => ETrackedDeviceClass_TrackedDeviceClass_HMD,
|
||||
Controller => ETrackedDeviceClass_TrackedDeviceClass_Controller,
|
||||
TrackingReference => ETrackedDeviceClass_TrackedDeviceClass_TrackingReference,
|
||||
Other => ETrackedDeviceClass_TrackedDeviceClass_Other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_raw(raw: openvr_sys::ETrackedDeviceClass) -> Self {
|
||||
use self::TrackedDeviceClass::*;
|
||||
use openvr_sys::ETrackedDeviceClass::*;
|
||||
|
||||
match raw {
|
||||
ETrackedDeviceClass_TrackedDeviceClass_Invalid => Invalid,
|
||||
ETrackedDeviceClass_TrackedDeviceClass_HMD => HMD,
|
||||
ETrackedDeviceClass_TrackedDeviceClass_Controller => Controller,
|
||||
ETrackedDeviceClass_TrackedDeviceClass_TrackingReference => TrackingReference,
|
||||
ETrackedDeviceClass_TrackedDeviceClass_Other => Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TrackedDevicePose {
|
||||
pub index: usize,
|
||||
pub to_device: [[f32; 4]; 3],
|
||||
pub velocity: [f32; 3],
|
||||
pub angular_velocity: [f32; 3],
|
||||
pub is_valid: bool,
|
||||
pub is_connected: bool,
|
||||
}
|
||||
pub struct TrackedDevicePose(sys::TrackedDevicePose_t);
|
||||
|
||||
impl TrackedDevicePose {
|
||||
pub fn from_raw(i: usize, d: openvr_sys::TrackedDevicePose_t) -> Self {
|
||||
TrackedDevicePose {
|
||||
index: i,
|
||||
is_connected: d.bDeviceIsConnected > 0,
|
||||
is_valid: d.bPoseIsValid > 0,
|
||||
to_device: d.mDeviceToAbsoluteTracking.m,
|
||||
velocity: d.vVelocity.v,
|
||||
angular_velocity: d.vAngularVelocity.v,
|
||||
}
|
||||
}
|
||||
|
||||
// returns the device class of the tracked object
|
||||
pub fn device_class(&self) -> TrackedDeviceClass {
|
||||
unsafe {
|
||||
let system = * { system().unwrap().0 as *mut openvr_sys::VR_IVRSystem_FnTable};
|
||||
TrackedDeviceClass::from_raw(system.GetTrackedDeviceClass.unwrap()(self.index as u32))
|
||||
}
|
||||
}
|
||||
|
||||
/// gets a propery as a string
|
||||
pub fn get_property_string(&self, property: TrackedDeviceStringProperty) -> Result<String, Error<openvr_sys::ETrackedPropertyError>> {
|
||||
unsafe {
|
||||
let system = * { system().unwrap().0 as *mut openvr_sys::VR_IVRSystem_FnTable};
|
||||
|
||||
let val_out = String::with_capacity(256);
|
||||
let mut err = ETrackedPropertyError_TrackedProp_Success;
|
||||
|
||||
let size = system.GetStringTrackedDeviceProperty.unwrap()(
|
||||
self.index as u32,
|
||||
property.to_raw(),
|
||||
val_out.as_ptr() as *mut i8,
|
||||
256,
|
||||
&mut err
|
||||
);
|
||||
|
||||
if size > 0 {
|
||||
let ptr = val_out.as_ptr() as *mut u8;
|
||||
let mem = slice::from_raw_parts(ptr, size as usize);
|
||||
let str = str::from_utf8(mem).unwrap();
|
||||
return Ok(String::from(str));
|
||||
} else {
|
||||
return Err(Error::from_raw(err));
|
||||
}
|
||||
pub fn device_to_absolute_tracking(&self) -> &[[f32; 4]; 3] { &self.0.mDeviceToAbsoluteTracking.m }
|
||||
pub fn velocity(&self) -> &[f32; 3] { &self.0.vVelocity.v }
|
||||
pub fn angular_velocity(&self) -> &[f32; 3] { &self.0.vAngularVelocity.v }
|
||||
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,
|
||||
_ => panic!("unrecognized tracking result")
|
||||
}
|
||||
}
|
||||
pub fn pose_is_valid(&self) -> bool { self.0.bPoseIsValid }
|
||||
pub fn device_is_connected(&self) -> bool { self.0.bDeviceIsConnected }
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TrackedDevicePoses {
|
||||
pub count: usize,
|
||||
pub poses: [TrackedDevicePose; 16],
|
||||
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,
|
||||
}
|
||||
|
||||
pub struct TrackedDevicePosesIterator<'a> {
|
||||
pub target: &'a TrackedDevicePoses,
|
||||
pub index: usize
|
||||
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,
|
||||
}
|
||||
|
||||
impl TrackedDevicePoses {
|
||||
pub fn as_slice(&self) -> &[TrackedDevicePose] {
|
||||
&self.poses[0..self.count]
|
||||
}
|
||||
pub type TrackedDeviceIndex = sys::TrackedDeviceIndex_t;
|
||||
|
||||
/// creates an iterator that will iterate over all connected devices
|
||||
pub fn connected_iter(&self) -> TrackedDevicePosesIterator {
|
||||
TrackedDevicePosesIterator { target: self, index: 0 }
|
||||
}
|
||||
pub mod tracked_device_index {
|
||||
use super::*;
|
||||
pub const HMD: TrackedDeviceIndex = sys::k_unTrackedDeviceIndex_Hmd;
|
||||
pub const INVALID: TrackedDeviceIndex = sys::k_unTrackedDeviceIndexInvalid;
|
||||
}
|
||||
|
||||
impl<'a> Iterator for TrackedDevicePosesIterator<'a> {
|
||||
type Item = &'a TrackedDevicePose;
|
||||
|
||||
fn next(&mut self) -> Option<&'a TrackedDevicePose> {
|
||||
// end reached
|
||||
if self.index == self.target.count {
|
||||
return None;
|
||||
}
|
||||
|
||||
let res = &self.target.poses[self.index];
|
||||
if !res.is_valid || !res.is_connected {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.index += 1;
|
||||
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn to_tracked(data: [openvr_sys::TrackedDevicePose_t; 16]) -> TrackedDevicePoses {
|
||||
use std;
|
||||
let mut out: TrackedDevicePoses = std::mem::zeroed();
|
||||
for (i, d) in data.iter().enumerate() {
|
||||
if d.bDeviceIsConnected > 0 {
|
||||
out.count = i + 1;
|
||||
}
|
||||
out.poses[i].index = i;
|
||||
out.poses[i].is_connected = d.bDeviceIsConnected > 0;
|
||||
out.poses[i].is_valid = d.bPoseIsValid > 0;
|
||||
out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
|
||||
out.poses[i].velocity = d.vVelocity.v;
|
||||
out.poses[i].angular_velocity = d.vAngularVelocity.v;
|
||||
}
|
||||
out
|
||||
}
|
||||
pub type TrackedDeviceProperty = sys::ETrackedDeviceProperty;
|
||||
|
Reference in New Issue
Block a user