X-Git-Url: http://git.tdb.fi/?p=libs%2Fvr.git;a=blobdiff_plain;f=source%2Fopenvr%2Fopenvrsystem.cpp;h=5b08ba7cbed38b9c3c91dbae431d51bc81b8b60e;hp=e71ba33b45346935d22eb48fc54b22724f4f4888;hb=8b0577558582dd34362219e498f688d9416f0ca1;hpb=0b9fa4d7eb2acb22f5f4f31bbd508d0216421108 diff --git a/source/openvr/openvrsystem.cpp b/source/openvr/openvrsystem.cpp index e71ba33..5b08ba7 100644 --- a/source/openvr/openvrsystem.cpp +++ b/source/openvr/openvrsystem.cpp @@ -1,5 +1,9 @@ #include +#include +#include +#include #include +#include "openvrcontroller_private.h" #include "openvrsystem.h" using namespace std; @@ -15,20 +19,40 @@ 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() +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"); } @@ -39,6 +63,29 @@ OpenVRSystem::OpenVRSystem() throw runtime_error("OpenVR compositor initialization failed"); vr::VRCompositor()->SetTrackingSpace(vr::TrackingUniverseSeated); + + for(unsigned i=0; iIsTrackedDeviceConnected(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() @@ -47,6 +94,11 @@ OpenVRSystem::~OpenVRSystem() vr::VR_Shutdown(); } +bool OpenVRSystem::is_maybe_available() +{ + return vr::VR_IsHmdPresent(); +} + void OpenVRSystem::configure_view(StereoView &view) const { vr::IVRSystem *vr_sys = vr::VRSystem(); @@ -74,6 +126,11 @@ void OpenVRSystem::set_absolute_tracking(bool a) vr::VRCompositor()->SetTrackingSpace(a ? vr::TrackingUniverseStanding : vr::TrackingUniverseSeated); } +bool OpenVRSystem::get_absolute_tracking() const +{ + return vr::VRCompositor()->GetTrackingSpace()==vr::TrackingUniverseStanding; +} + OpenVRCamera *OpenVRSystem::create_camera(const GL::Camera &bc) { return new OpenVRCamera(*this, bc); @@ -84,15 +141,245 @@ OpenVRCombiner *OpenVRSystem::create_combiner(GL::View &v) return new OpenVRCombiner(*this, v); } +OpenVRController *OpenVRSystem::create_controller() +{ + return new OpenVRController(*this); +} + +void OpenVRSystem::tick() +{ + vr::IVRSystem *vr_sys = vr::VRSystem(); + + OpenVRController::Event event; + while(vr_sys->PollNextEvent(&event, sizeof(event))) + { + bool controller_matched = false; + for(vector::iterator i=controllers.begin(); i!=controllers.end(); ++i) + { + int cindex = (*i)->get_index(); + if(cindex>=0 && event.trackedDeviceIndex==static_cast(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::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::iterator i=controllers.begin(); i!=controllers.end(); ++i) + (*i)->update_input_state(); + + for(list::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::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() { vector poses; - poses.resize(vr::k_unTrackedDeviceIndex_Hmd+1); + poses.resize(n_tracked_devices); vr::VRCompositor()->WaitGetPoses(&poses[0], poses.size(), 0, 0); - vr::TrackedDevicePose_t &hmd_pose = poses[vr::k_unTrackedDeviceIndex_Hmd]; - if(hmd_pose.bPoseIsValid) - hmd_matrix = convert_matrix(hmd_pose.mDeviceToAbsoluteTracking); + for(unsigned i=0; i=tracking_matrices.size()) + throw out_of_range("OpenVRSystem::get_tracking_matrix"); + + return tracking_matrices[index]; +} + +const GL::Matrix &OpenVRSystem::get_hmd_matrix() const +{ + return get_tracking_matrix(vr::k_unTrackedDeviceIndex_Hmd); +} + +void OpenVRSystem::add_controller(OpenVRController &controller) +{ + vector::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::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::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::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