2 #include <msp/vr/stereoview.h>
3 #include "openvrcontroller_private.h"
4 #include "openvrsystem.h"
10 Msp::GL::Matrix convert_matrix(const vr::HmdMatrix34_t &m)
12 Msp::GL::Matrix result;
13 for(unsigned i=0; i<3; ++i)
14 for(unsigned j=0; j<4; ++j)
15 result(i, j) = m.m[i][j];
25 unsigned OpenVRSystem::n_instances = 0;
27 OpenVRSystem::OpenVRSystem():
30 vr::IVRSystem *vr_sys = 0;
33 vr::EVRInitError init_err;
34 vr_sys = vr::VR_Init(&init_err, vr::VRApplication_Scene);
35 if(init_err!=vr::VRInitError_None)
36 throw runtime_error("OpenVR initialization failed");
40 vr::IVRCompositor *compositor = vr::VRCompositor();
42 throw runtime_error("OpenVR compositor initialization failed");
44 vr::VRCompositor()->SetTrackingSpace(vr::TrackingUniverseSeated);
46 for(unsigned i=0; i<vr::k_unMaxTrackedDeviceCount; ++i)
47 if(vr_sys->IsTrackedDeviceConnected(i))
49 n_tracked_devices = i+1;
50 if(vr_sys->GetTrackedDeviceClass(i)==vr::TrackedDeviceClass_Controller)
51 unclaimed_controllers.push_back(i);
54 tracking_matrices.resize(n_tracked_devices);
57 OpenVRSystem::~OpenVRSystem()
63 bool OpenVRSystem::is_maybe_available()
65 return vr::VR_IsHmdPresent();
68 void OpenVRSystem::configure_view(StereoView &view) const
70 vr::IVRSystem *vr_sys = vr::VRSystem();
72 #if defined(__GNUC__) && defined(_WIN32)
73 /* Visual C++ passes the return value address as first stack parameter and
74 the this pointer in ecx. MinGW does the other way around. This trick
75 forces the function signature to match at machine code level. */
76 typedef void (vr::IVRSystem::*FuncPtr)(vr::HmdMatrix34_t *, vr::EVREye);
77 FuncPtr get_eye_to_head_transform = reinterpret_cast<FuncPtr>(&vr::IVRSystem::GetEyeToHeadTransform);
79 vr::HmdMatrix34_t left, right;
80 (vr_sys->*get_eye_to_head_transform)(&left, vr::Eye_Left);
81 (vr_sys->*get_eye_to_head_transform)(&right, vr::Eye_Right);
83 vr::HmdMatrix34_t left = vr_sys->GetEyeToHeadTransform(vr::Eye_Left);
84 vr::HmdMatrix34_t right = vr_sys->GetEyeToHeadTransform(vr::Eye_Right);
87 view.set_eye_matrices(convert_matrix(left), convert_matrix(right));
90 void OpenVRSystem::set_absolute_tracking(bool a)
92 vr::VRCompositor()->SetTrackingSpace(a ? vr::TrackingUniverseStanding : vr::TrackingUniverseSeated);
95 bool OpenVRSystem::get_absolute_tracking() const
97 return vr::VRCompositor()->GetTrackingSpace()==vr::TrackingUniverseStanding;
100 OpenVRCamera *OpenVRSystem::create_camera(const GL::Camera &bc)
102 return new OpenVRCamera(*this, bc);
105 OpenVRCombiner *OpenVRSystem::create_combiner(GL::View &v)
107 return new OpenVRCombiner(*this, v);
110 OpenVRController *OpenVRSystem::create_controller()
112 return new OpenVRController(*this);
115 void OpenVRSystem::tick()
117 vr::IVRSystem *vr_sys = vr::VRSystem();
119 OpenVRController::Event event;
120 while(vr_sys->PollNextEvent(&event, sizeof(event)))
122 bool controller_matched = false;
123 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
125 int cindex = (*i)->get_index();
126 if(cindex>=0 && event.trackedDeviceIndex==static_cast<unsigned>(cindex))
129 controller_matched = true;
133 if(!controller_matched && event.eventType==vr::VREvent_TrackedDeviceActivated)
135 if(event.trackedDeviceIndex>=n_tracked_devices)
137 n_tracked_devices = event.trackedDeviceIndex+1;
138 tracking_matrices.resize(n_tracked_devices);
141 vr::ETrackedDeviceClass dev_class = vr_sys->GetTrackedDeviceClass(event.trackedDeviceIndex);
143 if(dev_class==vr::TrackedDeviceClass_Controller)
145 bool assigned_to_controller = false;
146 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
147 if((*i)->get_index()<0)
150 assigned_to_controller = true;
154 if(!assigned_to_controller)
155 unclaimed_controllers.push_back(event.trackedDeviceIndex);
160 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
161 (*i)->update_input_state();
164 void OpenVRSystem::update_pose_matrices()
166 vector<vr::TrackedDevicePose_t> poses;
167 poses.resize(n_tracked_devices);
168 vr::VRCompositor()->WaitGetPoses(&poses[0], poses.size(), 0, 0);
170 for(unsigned i=0; i<n_tracked_devices; ++i)
171 if(poses[i].bPoseIsValid)
172 tracking_matrices[i] = convert_matrix(poses[i].mDeviceToAbsoluteTracking);
175 const GL::Matrix &OpenVRSystem::get_tracking_matrix(unsigned index) const
177 if(index>=tracking_matrices.size())
178 throw out_of_range("OpenVRSystem::get_tracking_matrix");
180 return tracking_matrices[index];
183 const GL::Matrix &OpenVRSystem::get_hmd_matrix() const
185 return get_tracking_matrix(vr::k_unTrackedDeviceIndex_Hmd);
188 void OpenVRSystem::add_controller(OpenVRController &controller)
190 vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
191 if(i!=controllers.end())
192 throw invalid_argument("already added");
194 controllers.push_back(&controller);
196 if(!unclaimed_controllers.empty())
198 OpenVRController::Event event;
199 event.eventType = vr::VREvent_TrackedDeviceActivated;
200 event.trackedDeviceIndex = unclaimed_controllers.back();
201 event.eventAgeSeconds = 0;
202 controller.event(event);
203 unclaimed_controllers.pop_back();
207 void OpenVRSystem::remove_controller(OpenVRController &controller)
209 vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
210 if(i==controllers.end())
211 throw invalid_argument("not added");
213 int index = controller.get_index();
215 unclaimed_controllers.push_back(index);
216 controllers.erase(i);