+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();
+}
+