#include <openvr.h>
+#include <msp/core/maputils.h>
+#include <msp/gl/meshbuilder.h>
+#include <msp/gl/programbuilder.h>
#include <msp/vr/stereoview.h>
+#include "openvrcontroller_private.h"
#include "openvrsystem.h"
using namespace std;
return result;
}
+void set_texture_image(Msp::GL::Texture2D &texture, const vr::RenderModel_TextureMap_t &openvr_tex)
+{
+ texture.storage(Msp::GL::SRGB8_ALPHA8, openvr_tex.unWidth, openvr_tex.unHeight);
+ texture.image(0, Msp::GL::RGBA, Msp::GL::UNSIGNED_BYTE, openvr_tex.rubTextureMapData);
+}
+
}
namespace Msp {
namespace VR {
+struct OpenVRSystem::RenderModel
+{
+ GL::Mesh mesh;
+ GL::Technique tech;
+ GL::Object object;
+
+ RenderModel();
+
+ void convert(const vr::RenderModel_t &, OpenVRSystem &);
+};
+
+
unsigned OpenVRSystem::n_instances = 0;
OpenVRSystem::OpenVRSystem():
n_tracked_devices(0)
{
+ vr::IVRSystem *vr_sys = 0;
if(!n_instances)
{
vr::EVRInitError init_err;
- vr::VR_Init(&init_err, vr::VRApplication_Scene);
+ vr_sys = vr::VR_Init(&init_err, vr::VRApplication_Scene);
if(init_err!=vr::VRInitError_None)
throw runtime_error("OpenVR initialization failed");
}
for(unsigned i=0; i<vr::k_unMaxTrackedDeviceCount; ++i)
if(vr_sys->IsTrackedDeviceConnected(i))
+ {
n_tracked_devices = i+1;
+ if(vr_sys->GetTrackedDeviceClass(i)==vr::TrackedDeviceClass_Controller)
+ unclaimed_controllers.push_back(i);
+ }
tracking_matrices.resize(n_tracked_devices);
+
+ GL::ProgramBuilder::StandardFeatures features;
+ features.lighting = true;
+ features.material = true;
+ GL::ProgramBuilder(features).add_shaders(render_shprog);
+ render_shprog.link();
+
+ features.texture = true;
+ GL::ProgramBuilder(features).add_shaders(render_shprog_textured);
+ render_shprog_textured.link();
+
+ render_material.set_diffuse(GL::Color(1.0f));
+ render_material.set_ambient(GL::Color(1.0f));
}
OpenVRSystem::~OpenVRSystem()
return new OpenVRCombiner(*this, v);
}
+OpenVRController *OpenVRSystem::create_controller()
+{
+ return new OpenVRController(*this);
+}
+
void OpenVRSystem::tick()
{
vr::IVRSystem *vr_sys = vr::VRSystem();
- vr::VREvent_t event;
+ OpenVRController::Event event;
while(vr_sys->PollNextEvent(&event, sizeof(event)))
{
- if(event.eventType==vr::VREvent_TrackedDeviceActivated)
+ bool controller_matched = false;
+ for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
+ {
+ int cindex = (*i)->get_index();
+ if(cindex>=0 && event.trackedDeviceIndex==static_cast<unsigned>(cindex))
+ {
+ (*i)->event(event);
+ controller_matched = true;
+ }
+ }
+
+ if(!controller_matched && event.eventType==vr::VREvent_TrackedDeviceActivated)
+ {
if(event.trackedDeviceIndex>=n_tracked_devices)
{
n_tracked_devices = event.trackedDeviceIndex+1;
tracking_matrices.resize(n_tracked_devices);
}
+
+ vr::ETrackedDeviceClass dev_class = vr_sys->GetTrackedDeviceClass(event.trackedDeviceIndex);
+
+ if(dev_class==vr::TrackedDeviceClass_Controller)
+ {
+ bool assigned_to_controller = false;
+ for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
+ if((*i)->get_index()<0)
+ {
+ (*i)->event(event);
+ assigned_to_controller = true;
+ break;
+ }
+
+ if(!assigned_to_controller)
+ unclaimed_controllers.push_back(event.trackedDeviceIndex);
+ }
+ }
+ }
+
+ for(vector<OpenVRController *>::iterator i=controllers.begin(); i!=controllers.end(); ++i)
+ (*i)->update_input_state();
+
+ for(list<string>::iterator i=loading_render_models.begin(); i!=loading_render_models.end(); )
+ {
+ if(check_loading_render_model(*i))
+ loading_render_models.erase(i++);
+ else
+ ++i;
+ }
+
+ for(list<unsigned>::iterator i=loading_textures.begin(); i!=loading_textures.end(); )
+ {
+ if(check_loading_texture(*i))
+ loading_textures.erase(i++);
+ else
+ ++i;
}
}
return get_tracking_matrix(vr::k_unTrackedDeviceIndex_Hmd);
}
+void OpenVRSystem::add_controller(OpenVRController &controller)
+{
+ vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
+ if(i!=controllers.end())
+ throw invalid_argument("already added");
+
+ controllers.push_back(&controller);
+
+ if(!unclaimed_controllers.empty())
+ {
+ OpenVRController::Event event;
+ event.eventType = vr::VREvent_TrackedDeviceActivated;
+ event.trackedDeviceIndex = unclaimed_controllers.back();
+ event.eventAgeSeconds = 0;
+ controller.event(event);
+ unclaimed_controllers.pop_back();
+ }
+}
+
+void OpenVRSystem::remove_controller(OpenVRController &controller)
+{
+ vector<OpenVRController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
+ if(i==controllers.end())
+ throw invalid_argument("not added");
+
+ int index = controller.get_index();
+ if(index>=0)
+ unclaimed_controllers.push_back(index);
+ controllers.erase(i);
+}
+
+const GL::Object *OpenVRSystem::get_render_model(const string &name)
+{
+ map<string, RenderModel *>::const_iterator i = render_models.find(name);
+ if(i!=render_models.end())
+ return &i->second->object;
+
+ vr::IVRRenderModels *service = vr::VRRenderModels();
+ vr::RenderModel_t *openvr_model = 0;
+ vr::EVRRenderModelError err = service->LoadRenderModel_Async(name.c_str(), &openvr_model);
+ if(err!=vr::VRRenderModelError_None && err!=vr::VRRenderModelError_Loading)
+ throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
+
+ if(err==vr::VRRenderModelError_None && !openvr_model)
+ return 0;
+
+ RenderModel *model = new RenderModel;
+ render_models[name] = model;
+ if(err==vr::VRRenderModelError_Loading)
+ loading_render_models.push_back(name);
+ else
+ model->convert(*openvr_model, *this);
+
+ return &model->object;
+}
+
+bool OpenVRSystem::check_loading_render_model(const string &name)
+{
+ RenderModel &model = *get_item(render_models, name);
+
+ vr::IVRRenderModels *service = vr::VRRenderModels();
+ vr::RenderModel_t *openvr_model = 0;
+ vr::EVRRenderModelError err = service->LoadRenderModel_Async(name.c_str(), &openvr_model);
+ if(err==vr::VRRenderModelError_Loading)
+ return false;
+ else if(err!=vr::VRRenderModelError_None)
+ throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
+
+ model.convert(*openvr_model, *this);
+ return true;
+}
+
+const GL::Texture2D *OpenVRSystem::get_texture(unsigned id)
+{
+ map<unsigned, GL::Texture2D *>::const_iterator i = render_textures.find(id);
+ if(i!=render_textures.end())
+ return i->second;
+
+ vr::IVRRenderModels *service = vr::VRRenderModels();
+ vr::RenderModel_TextureMap_t *openvr_texture = 0;
+ vr::EVRRenderModelError err = service->LoadTexture_Async(id, &openvr_texture);
+ if(err!=vr::VRRenderModelError_None && err!=vr::VRRenderModelError_Loading)
+ throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
+
+ GL::Texture2D *texture = new GL::Texture2D;
+ render_textures[id] = texture;
+ texture->set_min_filter(GL::LINEAR_MIPMAP_LINEAR);
+ texture->set_generate_mipmap(true);
+ if(err==vr::VRRenderModelError_Loading)
+ loading_textures.push_back(id);
+ else
+ set_texture_image(*texture, *openvr_texture);
+
+ return texture;
+}
+
+bool OpenVRSystem::check_loading_texture(unsigned id)
+{
+ GL::Texture2D &texture = *get_item(render_textures, id);
+
+ vr::IVRRenderModels *service = vr::VRRenderModels();
+ vr::RenderModel_TextureMap_t *openvr_texture = 0;
+ vr::EVRRenderModelError err = service->LoadTexture_Async(id, &openvr_texture);
+ if(err==vr::VRRenderModelError_Loading)
+ return false;
+ else if(err!=vr::VRRenderModelError_None)
+ throw runtime_error(service->GetRenderModelErrorNameFromEnum(err));
+
+ set_texture_image(texture, *openvr_texture);
+ return true;
+}
+
+
+OpenVRSystem::RenderModel::RenderModel():
+ mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3)),
+ object(&mesh, &tech)
+{ }
+
+void OpenVRSystem::RenderModel::convert(const vr::RenderModel_t &model, OpenVRSystem &system)
+{
+ GL::RenderPass &pass = tech.add_pass(0);
+ pass.set_material(&system.render_material);
+ if(model.diffuseTextureId>=0)
+ {
+ pass.set_shader_program(&system.render_shprog_textured, 0);
+ pass.set_texture(0, system.get_texture(model.diffuseTextureId));
+ }
+ else
+ pass.set_shader_program(&system.render_shprog, 0);
+
+ mesh.clear();
+ Msp::GL::MeshBuilder bld(mesh);
+ for(unsigned i=0; i<model.unVertexCount; ++i)
+ {
+ const vr::RenderModel_Vertex_t &v = model.rVertexData[i];
+ bld.normal(Msp::GL::Vector3(v.vNormal.v));
+ bld.texcoord(v.rfTextureCoord[0], v.rfTextureCoord[1]);
+ bld.vertex(Msp::GL::Vector3(v.vPosition.v));
+ }
+
+ bld.begin(Msp::GL::TRIANGLES);
+ for(unsigned i=0; i<model.unTriangleCount; ++i)
+ for(unsigned j=0; j<3; ++j)
+ bld.element(model.rIndexData[i*3+j]);
+ bld.end();
+}
+
} // namespace VR
} // namespace Msp