extern crate gfx_device_gl; extern crate openvr as vr; use std::fmt::Debug; pub use self::vr::{compositor::texture::{ColorSpace, Handle, Texture}, ControllerState, Eye, system::Event as OvrEvent}; use gfx::{self, texture, Factory}; use gfx::memory::Typed; use na; use self::gfx_device_gl::Resources as GLResources; pub struct VR { _context: vr::Context, system: vr::System, compositor: vr::Compositor, origin: vr::TrackingUniverseOrigin, gfx_handles: gfx::handle::Manager, } #[derive(Debug)] pub enum Event { Touch { dev_idx: u32, button: u32 }, Press { dev_idx: u32, button: u32 }, Unpress { dev_idx: u32, button: u32 }, Untouch { dev_idx: u32, button: u32 }, Other { dev_idx: u32, event: OvrEvent }, } pub use self::vr::button_id; #[derive(Debug)] pub enum Error { Init(Box), Poses(Box), Submit(Box) } impl From for Error { fn from(e: vr::InitError) -> Self { Error::Init(Box::new(e)) } } impl VR { pub fn new() -> Result { let context = unsafe { vr::init(vr::ApplicationType::Scene)? }; Ok(VR { system: context.system()?, compositor: context.compositor()?, _context: context, origin: vr::TrackingUniverseOrigin::Standing, gfx_handles: gfx::handle::Manager::new(), }) } pub fn poses(&mut self) -> Result { self.gfx_handles.clear(); self.compositor.wait_get_poses().map(|p| p.render).map_err(|e| Error::Poses(Box::new(e))) } pub fn submit(&mut self, eye: Eye, tex: &gfx::handle::Texture) -> Result<(), Error> { let tex_id = match self.gfx_handles.ref_texture(tex.raw()) { &gfx_device_gl::NewTexture::Surface(id) => id, _ => panic!("Not a surface") }; unsafe { self.compositor.submit(eye, &Texture { handle: Handle::OpenGLRenderBuffer(tex_id as usize), color_space: ColorSpace::Linear }, None, None).map_err(|e| Error::Submit(Box::new(e))) } } pub fn recommended_render_target_size(&self) -> (u32, u32) { 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(); let inv_worked = mat.try_inverse_mut(); assert!(inv_worked, "head_to_eye matrix invert"); mat } pub fn poll_next_event(&mut self) -> Option { let (event, _) = self.system.poll_next_event_with_pose(self.origin)?; let dev_idx = event.tracked_device_index as u32; Some(match event.event { OvrEvent::ButtonTouch(controller) => Event::Touch { dev_idx: dev_idx, button: controller.button }, OvrEvent::ButtonPress(controller) => Event::Press { dev_idx: dev_idx, button: controller.button }, OvrEvent::ButtonUnpress(controller) => Event::Unpress { dev_idx: dev_idx, button: controller.button }, OvrEvent::ButtonUntouch(controller) => Event::Untouch { dev_idx: dev_idx, button: controller.button }, _ => Event::Other { dev_idx: dev_idx, event: event.event }, }) } pub fn get_controller_state(&self, index: u32) -> Option { self.system.controller_state(index) } } 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, width: u32, height: u32) -> Result, gfx::CombinedError> where T: gfx::format::RenderFormat + gfx::format::TextureFormat, D: gfx::format::DepthFormat + gfx::format::TextureFormat { let tex = factory .create_texture(texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single), 1, // levels gfx::memory::Bind::RENDER_TARGET, // bind gfx::memory::Usage::Data, // Usage Some(::get_channel_type()))?; // hint: format::ChannelType? let tgt = factory.view_texture_as_render_target(&tex, 0, None)?; let depth = factory.create_depth_stencil_view_only(width as texture::Size, height as texture::Size)?; Ok(EyeBuffer { tex: tex, target: tgt, depth: depth }) }