extern crate gfx; extern crate gfx_device_gl; extern crate nalgebra as na; extern crate num_traits; extern crate openvr as vr; extern crate openvr_sys; pub use self::vr::Eye; pub use self::vr::common::Size; pub use self::vr::tracking::{TrackedDeviceClass, TrackedDevicePoses}; use self::gfx::{tex, Factory, Typed}; use self::gfx_device_gl::Resources as GLResources; use self::na::Inverse; use self::num_traits::identities::Zero; use self::num_traits::identities::One; use self::openvr_sys::{VREvent_Controller_t, VREvent_t}; pub struct VR { system: vr::IVRSystem, compositor: vr::IVRCompositor, gfx_handles: gfx::handle::Manager, } #[derive(Debug)] pub enum Event { Touch { dev_idx: u32, controller: VREvent_Controller_t }, Press { dev_idx: u32, controller: VREvent_Controller_t }, Unpress { dev_idx: u32, controller: VREvent_Controller_t }, Untouch { dev_idx: u32, controller: VREvent_Controller_t }, Other(VREvent_t), } impl VR { pub fn new() -> Result> { Ok(VR { system: try!(vr::init()), compositor: try!(vr::compositor()), gfx_handles: gfx::handle::Manager::new(), }) } pub fn poses(&mut self) -> vr::tracking::TrackedDevicePoses { self.gfx_handles.clear(); self.compositor.wait_get_poses() } pub fn submit(&mut self, eye: Eye, tex: &gfx::handle::Texture) { let tex_id = match self.gfx_handles.ref_texture(tex.raw()) { &gfx_device_gl::NewTexture::Surface(id) => id, _ => panic!("Not a surface") }; self.compositor.submit(eye, tex_id as usize, vr::common::TextureBounds::new((0.0, 1.0), (0.0, 1.0))); } pub fn recommended_render_target_size(&self) -> Size { self.system.recommended_render_target_size() } pub fn projection_matrix(self: &Self, eye: Eye, near: f32, far: f32) -> na::Matrix4 { self.system.projection_matrix(eye, near, far).as_matrix4() } pub fn head_to_eye_transform(self: &Self, eye: Eye) -> na::Matrix4 { let mut mat = self.system.eye_to_head_transform(eye).as_matrix4(); assert!(mat.inverse_mut(), "inverse eye matrix"); mat } pub fn poll_next_event(&mut self) -> Option { use self::openvr_sys::EVREventType as EvType; unsafe { let system = * { self.system.0 as *mut openvr_sys::VR_IVRSystem_FnTable }; let mut event: openvr_sys::VREvent_t = ::std::mem::zeroed(); if system.PollNextEvent.unwrap()(&mut event, ::std::mem::size_of::() as u32 ) == 0 { return None; } let dev_idx = event.trackedDeviceIndex; Some(match ::std::mem::transmute(event.eventType) { EvType::EVREventType_VREvent_ButtonTouch => Event::Touch { dev_idx: dev_idx as u32, controller: *event.data.controller() }, EvType::EVREventType_VREvent_ButtonPress => Event::Press { dev_idx: dev_idx as u32, controller: *event.data.controller() }, EvType::EVREventType_VREvent_ButtonUnpress => Event::Unpress { dev_idx: dev_idx as u32, controller: *event.data.controller() }, EvType::EVREventType_VREvent_ButtonUntouch => Event::Untouch { dev_idx: dev_idx as u32, controller: *event.data.controller() }, _ => Event::Other(event), }) } } pub fn get_controller_state(&self, index: u32) -> Option { unsafe { let system = * { self.system.0 as *const openvr_sys::VR_IVRSystem_FnTable }; let mut state: openvr_sys::VRControllerState_t = ::std::mem::zeroed(); match system.GetControllerState.unwrap()( index, &mut state, ) { 0 => None, _ => Some(state) } } } } impl Drop for VR { fn drop(&mut self) { vr::shutdown() } } pub trait AsMatrix4 { fn as_matrix4(self) -> na::Matrix4; } impl AsMatrix4 for [[N; 4]; 3] { #[inline] fn as_matrix4(self) -> na::Matrix4 { na::Matrix4::new(self[0][0], self[0][1], self[0][2], self[0][3], self[1][0], self[1][1], self[1][2], self[1][3], self[2][0], self[2][1], self[2][2], self[2][3], N::zero(), N::zero(), N::zero(), N::one()) } } impl AsMatrix4 for [[N; 4]; 4] { #[inline] fn as_matrix4(self) -> na::Matrix4 { na::Matrix4::new(self[0][0], self[0][1], self[0][2], self[0][3], self[1][0], self[1][1], self[1][2], self[1][3], self[2][0], self[2][1], self[2][2], self[2][3], self[3][0], self[3][1], self[3][2], self[3][3]) } } pub struct EyeBuffer where T: gfx::format::RenderFormat + gfx::format::TextureFormat, D: gfx::format::DepthFormat + gfx::format::TextureFormat { pub tex: gfx::handle::Texture, pub target: gfx::handle::RenderTargetView, pub depth: gfx::handle::DepthStencilView, } pub fn create_eyebuffer(factory: &mut gfx_device_gl::Factory, size: Size) -> Result, gfx::CombinedError> where T: gfx::format::RenderFormat + gfx::format::TextureFormat, D: gfx::format::DepthFormat + gfx::format::TextureFormat { let tex = try!(factory.create_texture( tex::Kind::D2(size.width as tex::Size, size.height as tex::Size, tex::AaMode::Single), 1, // levels gfx::RENDER_TARGET, // bind gfx::Usage::GpuOnly, // Usage Some(::get_channel_type()))); // hint: format::ChannelType? let tgt = try!(factory.view_texture_as_render_target(&tex, 0, None)); let depth = try!(factory.create_depth_stencil_view_only(size.width as tex::Size, size.height as tex::Size)); Ok(EyeBuffer { tex: tex, target: tgt, depth: depth }) }