#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"
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():
}
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()
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;
+ }
}
void OpenVRSystem::update_pose_matrices()
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
#ifndef MSP_VR_OPENVRSYSTEM_H_
#define MSP_VR_OPENVRSYSTEM_H_
+#include <msp/gl/material.h>
#include <msp/gl/matrix.h>
+#include <msp/gl/object.h>
+#include <msp/gl/technique.h>
#include <msp/vr/system.h>
#include "openvrcamera.h"
#include "openvrcombiner.h"
class OpenVRSystem: public System
{
private:
+ struct RenderModel;
+
unsigned n_tracked_devices;
std::vector<GL::Matrix> tracking_matrices;
std::vector<OpenVRController *> controllers;
std::vector<unsigned> unclaimed_controllers;
+ GL::Program render_shprog;
+ GL::Program render_shprog_textured;
+ GL::Material render_material;
+ std::map<std::string, RenderModel *> render_models;
+ std::map<unsigned, GL::Texture2D *> render_textures;
+ std::list<std::string> loading_render_models;
+ std::list<unsigned> loading_textures;
+
static unsigned n_instances;
public:
const GL::Matrix &get_hmd_matrix() const;
void add_controller(OpenVRController &);
void remove_controller(OpenVRController &);
+
+ const GL::Object *get_render_model(const std::string &);
+private:
+ bool check_loading_render_model(const std::string &);
+ const GL::Texture2D *get_texture(unsigned);
+ bool check_loading_texture(unsigned);
};
} // namespace VR