]> git.tdb.fi Git - libs/vr.git/blob - source/openvr/openvrsystem.cpp
e847b201385f4a8c685367dcee8f3799c337ed11
[libs/vr.git] / source / openvr / openvrsystem.cpp
1 #include <openvr.h>
2 #include <msp/vr/stereoview.h>
3 #include "openvrcontroller_private.h"
4 #include "openvrsystem.h"
5
6 using namespace std;
7
8 namespace {
9
10 Msp::GL::Matrix convert_matrix(const vr::HmdMatrix34_t &m)
11 {
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];
16         return result;
17 }
18
19 }
20
21
22 namespace Msp {
23 namespace VR {
24
25 unsigned OpenVRSystem::n_instances = 0;
26
27 OpenVRSystem::OpenVRSystem():
28         n_tracked_devices(0)
29 {
30         vr::IVRSystem *vr_sys = 0;
31         if(!n_instances)
32         {
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");
37         }
38         ++n_instances;
39
40         vr::IVRCompositor *compositor = vr::VRCompositor();
41         if(!compositor)
42                 throw runtime_error("OpenVR compositor initialization failed");
43
44         vr::VRCompositor()->SetTrackingSpace(vr::TrackingUniverseSeated);
45
46         for(unsigned i=0; i<vr::k_unMaxTrackedDeviceCount; ++i)
47                 if(vr_sys->IsTrackedDeviceConnected(i))
48                 {
49                         n_tracked_devices = i+1;
50                         if(vr_sys->GetTrackedDeviceClass(i)==vr::TrackedDeviceClass_Controller)
51                                 unclaimed_controllers.push_back(i);
52                 }
53
54         tracking_matrices.resize(n_tracked_devices);
55 }
56
57 OpenVRSystem::~OpenVRSystem()
58 {
59         if(!--n_instances)
60                 vr::VR_Shutdown();
61 }
62
63 bool OpenVRSystem::is_maybe_available()
64 {
65         return vr::VR_IsHmdPresent();
66 }
67
68 void OpenVRSystem::configure_view(StereoView &view) const
69 {
70         vr::IVRSystem *vr_sys = vr::VRSystem();
71
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);
78
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);
82 #else
83         vr::HmdMatrix34_t left = vr_sys->GetEyeToHeadTransform(vr::Eye_Left);
84         vr::HmdMatrix34_t right = vr_sys->GetEyeToHeadTransform(vr::Eye_Right);
85 #endif
86         
87         view.set_eye_matrices(convert_matrix(left), convert_matrix(right));
88 }
89
90 void OpenVRSystem::set_absolute_tracking(bool a)
91 {
92         vr::VRCompositor()->SetTrackingSpace(a ? vr::TrackingUniverseStanding : vr::TrackingUniverseSeated);
93 }
94
95 bool OpenVRSystem::get_absolute_tracking() const
96 {
97         return vr::VRCompositor()->GetTrackingSpace()==vr::TrackingUniverseStanding;
98 }
99
100 OpenVRCamera *OpenVRSystem::create_camera(const GL::Camera &bc)
101 {
102         return new OpenVRCamera(*this, bc);
103 }
104
105 OpenVRCombiner *OpenVRSystem::create_combiner(GL::View &v)
106 {
107         return new OpenVRCombiner(*this, v);
108 }
109
110 OpenVRController *OpenVRSystem::create_controller()
111 {
112         return new OpenVRController(*this);
113 }
114
115 void OpenVRSystem::tick()
116 {
117         vr::IVRSystem *vr_sys = vr::VRSystem();
118
119         OpenVRController::Event event;
120         while(vr_sys->PollNextEvent(&event, sizeof(event)))
121         {
122                 bool controller_matched = false;
123                 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
124                 {
125                         int cindex = (*i)->get_index();
126                         if(cindex>=0 && event.trackedDeviceIndex==static_cast<unsigned>(cindex))
127                         {
128                                 (*i)->event(event);
129                                 controller_matched = true;
130                         }
131                 }
132
133                 if(!controller_matched && event.eventType==vr::VREvent_TrackedDeviceActivated)
134                 {
135                         if(event.trackedDeviceIndex>=n_tracked_devices)
136                         {
137                                 n_tracked_devices = event.trackedDeviceIndex+1;
138                                 tracking_matrices.resize(n_tracked_devices);
139                         }
140
141                         vr::ETrackedDeviceClass dev_class = vr_sys->GetTrackedDeviceClass(event.trackedDeviceIndex);
142
143                         if(dev_class==vr::TrackedDeviceClass_Controller)
144                         {
145                                 bool assigned_to_controller = false;
146                                 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
147                                         if((*i)->get_index()<0)
148                                         {
149                                                 (*i)->event(event);
150                                                 assigned_to_controller = true;
151                                                 break;
152                                         }
153
154                                 if(!assigned_to_controller)
155                                         unclaimed_controllers.push_back(event.trackedDeviceIndex);
156                         }
157                 }
158         }
159
160         for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
161                 (*i)->update_input_state();
162 }
163
164 void OpenVRSystem::update_pose_matrices()
165 {
166         vector<vr::TrackedDevicePose_t> poses;
167         poses.resize(n_tracked_devices);
168         vr::VRCompositor()->WaitGetPoses(&poses[0], poses.size(), 0, 0);
169
170         for(unsigned i=0; i<n_tracked_devices; ++i)
171                 if(poses[i].bPoseIsValid)
172                         tracking_matrices[i] = convert_matrix(poses[i].mDeviceToAbsoluteTracking);
173 }
174
175 const GL::Matrix &OpenVRSystem::get_tracking_matrix(unsigned index) const
176 {
177         if(index>=tracking_matrices.size())
178                 throw out_of_range("OpenVRSystem::get_tracking_matrix");
179
180         return tracking_matrices[index];
181 }
182
183 const GL::Matrix &OpenVRSystem::get_hmd_matrix() const
184 {
185         return get_tracking_matrix(vr::k_unTrackedDeviceIndex_Hmd);
186 }
187
188 void OpenVRSystem::add_controller(OpenVRController &controller)
189 {
190         vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
191         if(i!=controllers.end())
192                 throw invalid_argument("already added");
193
194         controllers.push_back(&controller);
195
196         if(!unclaimed_controllers.empty())
197         {
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();
204         }
205 }
206
207 void OpenVRSystem::remove_controller(OpenVRController &controller)
208 {
209         vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
210         if(i==controllers.end())
211                 throw invalid_argument("not added");
212
213         int index = controller.get_index();
214         if(index>=0)
215                 unclaimed_controllers.push_back(index);
216         controllers.erase(i);
217 }
218
219 } // namespace VR
220 } // namespace Msp