Provide objects for visualizing controllers
authorMikko Rasa <tdb@tdb.fi>
Thu, 6 Oct 2016 17:15:19 +0000 (20:15 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 6 Oct 2016 17:15:19 +0000 (20:15 +0300)
source/motioncontroller.h
source/openvr/openvrcontroller.cpp
source/openvr/openvrcontroller.h
source/openvr/openvrsystem.cpp
source/openvr/openvrsystem.h

index 959e056cd8c6c1b537951bb8161d7f0d6c1dfd83..0dbee9c2b1aea0ce9e365a04fb3e0762121f6335 100644 (file)
@@ -2,6 +2,7 @@
 #define MSP_VR_MOTIONCONTROLLER_H_
 
 #include <msp/gl/matrix.h>
+#include <msp/gl/object.h>
 #include <msp/input/device.h>
 
 namespace Msp {
@@ -29,6 +30,9 @@ public:
        virtual void update() = 0;
 protected:
        void update_from_matrix(const Msp::GL::Matrix &);
+
+public:
+       virtual const GL::Object *get_object() const { return 0; }
 };
 
 } // namespace VR
index 016405bab6b90b652a192f7ab7b7a70472238da4..e757221d2911a76b144977989a35f10bce512661 100644 (file)
@@ -101,5 +101,15 @@ void OpenVRController::update_input_state()
        }
 }
 
+const GL::Object *OpenVRController::get_object() const
+{
+       char buf[1024];
+       unsigned len = vr::VRSystem()->GetStringTrackedDeviceProperty(index, vr::Prop_RenderModelName_String, buf, sizeof(buf));
+       if(len>1)
+               return system.get_render_model(string(buf, len-1));
+
+       return 0;
+}
+
 } // namespace VR
 } // namespace Msp
index 00ae1c09d5c83ba1018665d2479ddf04abb818ec..79924f3b47948ce38409fd05224cba218637e9b3 100644 (file)
@@ -31,6 +31,8 @@ public:
        void event(const Event &);
        virtual void update();
        void update_input_state();
+
+       virtual const GL::Object *get_object() const;
 };
 
 } // namespace VR
index e847b201385f4a8c685367dcee8f3799c337ed11..5b08ba7cbed38b9c3c91dbae431d51bc81b8b60e 100644 (file)
@@ -1,4 +1,7 @@
 #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"
@@ -16,12 +19,30 @@ Msp::GL::Matrix convert_matrix(const vr::HmdMatrix34_t &m)
        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():
@@ -52,6 +73,19 @@ 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()
@@ -159,6 +193,22 @@ void OpenVRSystem::tick()
 
        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()
@@ -216,5 +266,121 @@ void OpenVRSystem::remove_controller(OpenVRController &controller)
        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
index 7799ad298405914f198d41c7ddd676eae902b59b..0e787eb8d465c947d8d6f53283be5c5a6bfb5f1d 100644 (file)
@@ -1,7 +1,10 @@
 #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"
@@ -13,11 +16,21 @@ namespace VR {
 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:
@@ -42,6 +55,12 @@ 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