2 #include <msp/core/maputils.h>
3 #include <msp/gl/meshbuilder.h>
4 #include <msp/gl/programbuilder.h>
5 #include <msp/vr/stereoview.h>
6 #include "openvrcontroller_private.h"
7 #include "openvrsystem.h"
13 Msp::GL::Matrix convert_matrix(const vr::HmdMatrix34_t &m)
15 Msp::GL::Matrix result;
16 for(unsigned i=0; i<3; ++i)
17 for(unsigned j=0; j<4; ++j)
18 result(i, j) = m.m[i][j];
22 void set_texture_image(Msp::GL::Texture2D &texture, const vr::RenderModel_TextureMap_t &openvr_tex)
24 texture.storage(Msp::GL::SRGB8_ALPHA8, openvr_tex.unWidth, openvr_tex.unHeight);
25 texture.image(0, Msp::GL::RGBA, Msp::GL::UNSIGNED_BYTE, openvr_tex.rubTextureMapData);
34 struct OpenVRSystem::RenderModel
42 void convert(const vr::RenderModel_t &, OpenVRSystem &);
46 unsigned OpenVRSystem::n_instances = 0;
48 OpenVRSystem::OpenVRSystem():
51 vr::IVRSystem *vr_sys = 0;
54 vr::EVRInitError init_err;
55 vr_sys = vr::VR_Init(&init_err, vr::VRApplication_Scene);
56 if(init_err!=vr::VRInitError_None)
57 throw runtime_error("OpenVR initialization failed");
61 vr::IVRCompositor *compositor = vr::VRCompositor();
63 throw runtime_error("OpenVR compositor initialization failed");
65 vr::VRCompositor()->SetTrackingSpace(vr::TrackingUniverseSeated);
67 for(unsigned i=0; i<vr::k_unMaxTrackedDeviceCount; ++i)
68 if(vr_sys->IsTrackedDeviceConnected(i))
70 n_tracked_devices = i+1;
71 if(vr_sys->GetTrackedDeviceClass(i)==vr::TrackedDeviceClass_Controller)
72 unclaimed_controllers.push_back(i);
75 tracking_matrices.resize(n_tracked_devices);
77 GL::ProgramBuilder::StandardFeatures features;
78 features.lighting = true;
79 features.material = true;
80 GL::ProgramBuilder(features).add_shaders(render_shprog);
83 features.texture = true;
84 GL::ProgramBuilder(features).add_shaders(render_shprog_textured);
85 render_shprog_textured.link();
87 render_material.set_diffuse(GL::Color(1.0f));
88 render_material.set_ambient(GL::Color(1.0f));
91 OpenVRSystem::~OpenVRSystem()
97 bool OpenVRSystem::is_maybe_available()
99 return vr::VR_IsHmdPresent();
102 void OpenVRSystem::configure_view(StereoView &view) const
104 vr::IVRSystem *vr_sys = vr::VRSystem();
106 #if defined(__GNUC__) && defined(_WIN32)
107 /* Visual C++ passes the return value address as first stack parameter and
108 the this pointer in ecx. MinGW does the other way around. This trick
109 forces the function signature to match at machine code level. */
110 typedef void (vr::IVRSystem::*FuncPtr)(vr::HmdMatrix34_t *, vr::EVREye);
111 FuncPtr get_eye_to_head_transform = reinterpret_cast<FuncPtr>(&vr::IVRSystem::GetEyeToHeadTransform);
113 vr::HmdMatrix34_t left, right;
114 (vr_sys->*get_eye_to_head_transform)(&left, vr::Eye_Left);
115 (vr_sys->*get_eye_to_head_transform)(&right, vr::Eye_Right);
117 vr::HmdMatrix34_t left = vr_sys->GetEyeToHeadTransform(vr::Eye_Left);
118 vr::HmdMatrix34_t right = vr_sys->GetEyeToHeadTransform(vr::Eye_Right);
121 view.set_eye_matrices(convert_matrix(left), convert_matrix(right));
124 void OpenVRSystem::set_absolute_tracking(bool a)
126 vr::VRCompositor()->SetTrackingSpace(a ? vr::TrackingUniverseStanding : vr::TrackingUniverseSeated);
129 bool OpenVRSystem::get_absolute_tracking() const
131 return vr::VRCompositor()->GetTrackingSpace()==vr::TrackingUniverseStanding;
134 OpenVRCamera *OpenVRSystem::create_camera(const GL::Camera &bc)
136 return new OpenVRCamera(*this, bc);
139 OpenVRCombiner *OpenVRSystem::create_combiner(GL::View &v)
141 return new OpenVRCombiner(*this, v);
144 OpenVRController *OpenVRSystem::create_controller()
146 return new OpenVRController(*this);
149 void OpenVRSystem::tick()
151 vr::IVRSystem *vr_sys = vr::VRSystem();
153 OpenVRController::Event event;
154 while(vr_sys->PollNextEvent(&event, sizeof(event)))
156 bool controller_matched = false;
157 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
159 int cindex = (*i)->get_index();
160 if(cindex>=0 && event.trackedDeviceIndex==static_cast<unsigned>(cindex))
163 controller_matched = true;
167 if(!controller_matched && event.eventType==vr::VREvent_TrackedDeviceActivated)
169 if(event.trackedDeviceIndex>=n_tracked_devices)
171 n_tracked_devices = event.trackedDeviceIndex+1;
172 tracking_matrices.resize(n_tracked_devices);
175 vr::ETrackedDeviceClass dev_class = vr_sys->GetTrackedDeviceClass(event.trackedDeviceIndex);
177 if(dev_class==vr::TrackedDeviceClass_Controller)
179 bool assigned_to_controller = false;
180 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
181 if((*i)->get_index()<0)
184 assigned_to_controller = true;
188 if(!assigned_to_controller)
189 unclaimed_controllers.push_back(event.trackedDeviceIndex);
194 for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
195 (*i)->update_input_state();
197 for(list<string>::iterator i=loading_render_models.begin(); i!=loading_render_models.end(); )
199 if(check_loading_render_model(*i))
200 loading_render_models.erase(i++);
205 for(list<unsigned>::iterator i=loading_textures.begin(); i!=loading_textures.end(); )
207 if(check_loading_texture(*i))
208 loading_textures.erase(i++);
214 void OpenVRSystem::update_pose_matrices()
216 vector<vr::TrackedDevicePose_t> poses;
217 poses.resize(n_tracked_devices);
218 vr::VRCompositor()->WaitGetPoses(&poses[0], poses.size(), 0, 0);
220 for(unsigned i=0; i<n_tracked_devices; ++i)
221 if(poses[i].bPoseIsValid)
222 tracking_matrices[i] = convert_matrix(poses[i].mDeviceToAbsoluteTracking);
225 const GL::Matrix &OpenVRSystem::get_tracking_matrix(unsigned index) const
227 if(index>=tracking_matrices.size())
228 throw out_of_range("OpenVRSystem::get_tracking_matrix");
230 return tracking_matrices[index];
233 const GL::Matrix &OpenVRSystem::get_hmd_matrix() const
235 return get_tracking_matrix(vr::k_unTrackedDeviceIndex_Hmd);
238 void OpenVRSystem::add_controller(OpenVRController &controller)
240 vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
241 if(i!=controllers.end())
242 throw invalid_argument("already added");
244 controllers.push_back(&controller);
246 if(!unclaimed_controllers.empty())
248 OpenVRController::Event event;
249 event.eventType = vr::VREvent_TrackedDeviceActivated;
250 event.trackedDeviceIndex = unclaimed_controllers.back();
251 event.eventAgeSeconds = 0;
252 controller.event(event);
253 unclaimed_controllers.pop_back();
257 void OpenVRSystem::remove_controller(OpenVRController &controller)
259 vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
260 if(i==controllers.end())
261 throw invalid_argument("not added");
263 int index = controller.get_index();
265 unclaimed_controllers.push_back(index);
266 controllers.erase(i);
269 const GL::Object *OpenVRSystem::get_render_model(const string &name)
271 map<string, RenderModel *>::const_iterator i = render_models.find(name);
272 if(i!=render_models.end())
273 return &i->second->object;
275 vr::IVRRenderModels *service = vr::VRRenderModels();
276 vr::RenderModel_t *openvr_model = 0;
277 vr::EVRRenderModelError err = service->LoadRenderModel_Async(name.c_str(), &openvr_model);
278 if(err!=vr::VRRenderModelError_None && err!=vr::VRRenderModelError_Loading)
279 throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
281 if(err==vr::VRRenderModelError_None && !openvr_model)
284 RenderModel *model = new RenderModel;
285 render_models[name] = model;
286 if(err==vr::VRRenderModelError_Loading)
287 loading_render_models.push_back(name);
289 model->convert(*openvr_model, *this);
291 return &model->object;
294 bool OpenVRSystem::check_loading_render_model(const string &name)
296 RenderModel &model = *get_item(render_models, name);
298 vr::IVRRenderModels *service = vr::VRRenderModels();
299 vr::RenderModel_t *openvr_model = 0;
300 vr::EVRRenderModelError err = service->LoadRenderModel_Async(name.c_str(), &openvr_model);
301 if(err==vr::VRRenderModelError_Loading)
303 else if(err!=vr::VRRenderModelError_None)
304 throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
306 model.convert(*openvr_model, *this);
310 const GL::Texture2D *OpenVRSystem::get_texture(unsigned id)
312 map<unsigned, GL::Texture2D *>::const_iterator i = render_textures.find(id);
313 if(i!=render_textures.end())
316 vr::IVRRenderModels *service = vr::VRRenderModels();
317 vr::RenderModel_TextureMap_t *openvr_texture = 0;
318 vr::EVRRenderModelError err = service->LoadTexture_Async(id, &openvr_texture);
319 if(err!=vr::VRRenderModelError_None && err!=vr::VRRenderModelError_Loading)
320 throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
322 GL::Texture2D *texture = new GL::Texture2D;
323 render_textures[id] = texture;
324 texture->set_min_filter(GL::LINEAR_MIPMAP_LINEAR);
325 texture->set_generate_mipmap(true);
326 if(err==vr::VRRenderModelError_Loading)
327 loading_textures.push_back(id);
329 set_texture_image(*texture, *openvr_texture);
334 bool OpenVRSystem::check_loading_texture(unsigned id)
336 GL::Texture2D &texture = *get_item(render_textures, id);
338 vr::IVRRenderModels *service = vr::VRRenderModels();
339 vr::RenderModel_TextureMap_t *openvr_texture = 0;
340 vr::EVRRenderModelError err = service->LoadTexture_Async(id, &openvr_texture);
341 if(err==vr::VRRenderModelError_Loading)
343 else if(err!=vr::VRRenderModelError_None)
344 throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
346 set_texture_image(texture, *openvr_texture);
351 OpenVRSystem::RenderModel::RenderModel():
352 mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3)),
356 void OpenVRSystem::RenderModel::convert(const vr::RenderModel_t &model, OpenVRSystem &system)
358 GL::RenderPass &pass = tech.add_pass(0);
359 pass.set_material(&system.render_material);
360 if(model.diffuseTextureId>=0)
362 pass.set_shader_program(&system.render_shprog_textured, 0);
363 pass.set_texture(0, system.get_texture(model.diffuseTextureId));
366 pass.set_shader_program(&system.render_shprog, 0);
369 Msp::GL::MeshBuilder bld(mesh);
370 for(unsigned i=0; i<model.unVertexCount; ++i)
372 const vr::RenderModel_Vertex_t &v = model.rVertexData[i];
373 bld.normal(Msp::GL::Vector3(v.vNormal.v));
374 bld.texcoord(v.rfTextureCoord[0], v.rfTextureCoord[1]);
375 bld.vertex(Msp::GL::Vector3(v.vPosition.v));
378 bld.begin(Msp::GL::TRIANGLES);
379 for(unsigned i=0; i<model.unTriangleCount; ++i)
380 for(unsigned j=0; j<3; ++j)
381 bld.element(model.rIndexData[i*3+j]);