require "mspgui";
feature "libovr" "Support Oculus Rift through LibOVR";
+ feature "openvr" "Support HTC Vive and other devices through OpenVR";
if_feature "libovr"
{
};
};
+ if_feature "openvr"
+ {
+ require "openvr";
+ };
+
library "mspvr"
{
source "source";
{
source "source/ovr";
};
+ if_feature "openvr"
+ {
+ source "source/openvr";
+ };
install true;
install_map
{
--- /dev/null
+#include <openvr.h>
+#include "openvrcamera.h"
+#include "openvrdevice.h"
+
+namespace Msp {
+namespace VR {
+
+OpenVRCamera::OpenVRCamera(const OpenVRDevice &d, const GL::Camera &c):
+ HeadTrackingCamera(c),
+ device(d)
+{ }
+
+void OpenVRCamera::reset_tracking()
+{
+ vr::VRSystem()->ResetSeatedZeroPose();
+}
+
+void OpenVRCamera::update()
+{
+ update_from_matrix(device.get_hmd_matrix());
+}
+
+} // namespace VR
+} // namespace Msp
--- /dev/null
+#ifndef MSP_VR_OPENVRCAMERA_H_
+#define MSP_VR_OPENVRCAMERA_H_
+
+#include <msp/vr/headtrackingcamera.h>
+
+namespace Msp {
+namespace VR {
+
+class OpenVRDevice;
+
+class OpenVRCamera: public HeadTrackingCamera
+{
+private:
+ const OpenVRDevice &device;
+
+public:
+ OpenVRCamera(const OpenVRDevice &, const GL::Camera &);
+
+ virtual void reset_tracking();
+ virtual void update();
+};
+
+} // namespace VR
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <openvr.h>
+#include "openvrcombiner.h"
+#include "openvrdevice.h"
+
+namespace Msp {
+namespace VR {
+
+struct OpenVRCombiner::Private
+{
+ static Frustum get_projection(vr::EVREye);
+};
+
+
+OpenVRCombiner::OpenVRCombiner(OpenVRDevice &d):
+ device(d)
+{
+ vr::IVRSystem *vr_sys = vr::VRSystem();
+ uint32_t w, h;
+ vr_sys->GetRecommendedRenderTargetSize(&w, &h);
+ target_width = w;
+ target_height = h;
+
+ Frustum left_frustum = Private::get_projection(vr::Eye_Left);
+ Frustum right_frustum = Private::get_projection(vr::Eye_Right);
+ configure_eye_frustums(left_frustum, right_frustum);
+}
+
+void OpenVRCombiner::prepare() const
+{
+ device.update_pose_matrices();
+}
+
+void OpenVRCombiner::render(const GL::Texture2D &left, const GL::Texture2D &right) const
+{
+ vr::Texture_t tex;
+ tex.eType = vr::API_OpenGL;
+ tex.eColorSpace = vr::ColorSpace_Gamma;
+
+ vr::IVRCompositor *compositor = vr::VRCompositor();
+ tex.handle = reinterpret_cast<void *>(left.get_id());
+ compositor->Submit(vr::Eye_Left, &tex);
+ tex.handle = reinterpret_cast<void *>(right.get_id());
+ compositor->Submit(vr::Eye_Right, &tex);
+}
+
+
+StereoCombiner::Frustum OpenVRCombiner::Private::get_projection(vr::EVREye eye)
+{
+ Frustum frustum;
+ /* The parameter order is documented as left, right, top, bottom; however
+ the third parameter is actually negative and fourth one positive. */
+ vr::VRSystem()->GetProjectionRaw(eye, &frustum.left, &frustum.right, &frustum.bottom, &frustum.top);
+ return frustum;
+}
+
+} // namespace VR
+} // namespace Msp
--- /dev/null
+#ifndef MSP_VR_OPENVRCOMBINER_H_
+#define MSP_VR_OPENVRCOMBINER_H_
+
+#include <msp/vr/stereocombiner.h>
+
+namespace Msp {
+namespace VR {
+
+class OpenVRDevice;
+
+class OpenVRCombiner: public StereoCombiner
+{
+private:
+ struct Private;
+
+ OpenVRDevice &device;
+
+public:
+ OpenVRCombiner(OpenVRDevice &);
+
+ virtual void prepare() const;
+ virtual void render(const GL::Texture2D &, const GL::Texture2D &) const;
+};
+
+} // namespace VR
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <openvr.h>
+#include "openvrdevice.h"
+
+using namespace std;
+
+namespace Msp {
+namespace VR {
+
+unsigned OpenVRDevice::n_instances = 0;
+
+OpenVRDevice::OpenVRDevice()
+{
+ if(!n_instances)
+ {
+ vr::EVRInitError init_err;
+ vr::VR_Init(&init_err, vr::VRApplication_Scene);
+ if(init_err!=vr::VRInitError_None)
+ throw runtime_error("OpenVR initialization failed");
+ }
+ ++n_instances;
+
+ vr::IVRCompositor *compositor = vr::VRCompositor();
+ if(!compositor)
+ throw runtime_error("OpenVR compositor initialization failed");
+
+ vr::VRCompositor()->SetTrackingSpace(vr::TrackingUniverseSeated);
+}
+
+OpenVRDevice::~OpenVRDevice()
+{
+ if(!--n_instances)
+ vr::VR_Shutdown();
+}
+
+OpenVRCamera *OpenVRDevice::create_camera(const GL::Camera &bc)
+{
+ return new OpenVRCamera(*this, bc);
+}
+
+OpenVRCombiner *OpenVRDevice::create_combiner(GL::View &)
+{
+ return new OpenVRCombiner(*this);
+}
+
+void OpenVRDevice::update_pose_matrices()
+{
+ vector<vr::TrackedDevicePose_t> poses;
+ poses.resize(vr::k_unTrackedDeviceIndex_Hmd+1);
+ vr::VRCompositor()->WaitGetPoses(&poses[0], poses.size(), 0, 0);
+
+ vr::TrackedDevicePose_t &hmd_pose = poses[vr::k_unTrackedDeviceIndex_Hmd];
+ if(hmd_pose.bPoseIsValid)
+ {
+ for(unsigned i=0; i<3; ++i)
+ for(unsigned j=0; j<4; ++j)
+ hmd_matrix(i, j) = hmd_pose.mDeviceToAbsoluteTracking.m[i][j];
+ }
+}
+
+} // namespace VR
+} // namespace Msp
--- /dev/null
+#ifndef MSP_VR_OPENVRDEVICE_H_
+#define MSP_VR_OPENVRDEVICE_H_
+
+#include <msp/gl/matrix.h>
+#include <msp/vr/displaydevice.h>
+#include "openvrcamera.h"
+#include "openvrcombiner.h"
+
+namespace Msp {
+namespace VR {
+
+class OpenVRDevice: public DisplayDevice
+{
+private:
+ GL::Matrix hmd_matrix;
+
+ static unsigned n_instances;
+
+public:
+ OpenVRDevice();
+ ~OpenVRDevice();
+
+ virtual void configure_window(Graphics::Window &) const { }
+ virtual void configure_view(StereoView &) const { }
+ virtual OpenVRCamera *create_camera(const GL::Camera &);
+ virtual OpenVRCombiner *create_combiner(GL::View &);
+
+ void update_pose_matrices();
+ const GL::Matrix &get_hmd_matrix() const { return hmd_matrix; }
+};
+
+} // namespace VR
+} // namespace Msp
+
+#endif