--- /dev/null
+#include <stdexcept>
+#include "headtrackingcamera.h"
+#include "motioncontroller.h"
+#include "stereoview.h"
+
+using namespace std;
+
+namespace Msp {
+namespace VR {
+
+MotionController::MotionController():
+ view(0)
+{ }
+
+MotionController::~MotionController()
+{
+ detach_from_view();
+}
+
+void MotionController::attach_to_view(StereoView &v)
+{
+ detach_from_view();
+ view = &v;
+ view->add_controller(*this);
+}
+
+void MotionController::detach_from_view()
+{
+ if(view)
+ view->remove_controller(*this);
+ view = 0;
+}
+
+void MotionController::update_from_matrix(const GL::Matrix &m)
+{
+ matrix = m;
+ if(view)
+ if(const HeadTrackingCamera *head_camera = view->get_head_camera())
+ matrix = head_camera->get_base_matrix()*matrix;
+}
+
+} // namespace VR
+} // namespace Msp
--- /dev/null
+#ifndef MSP_VR_MOTIONCONTROLLER_H_
+#define MSP_VR_MOTIONCONTROLLER_H_
+
+#include <msp/gl/matrix.h>
+#include <msp/input/device.h>
+
+namespace Msp {
+namespace VR {
+
+class StereoView;
+
+class MotionController: public Input::Device
+{
+protected:
+ StereoView *view;
+ Msp::GL::Matrix matrix;
+
+ MotionController();
+public:
+ virtual ~MotionController();
+
+ void attach_to_view(StereoView &);
+ void detach_from_view();
+ const GL::Matrix &get_matrix() const { return matrix; }
+ virtual void update() = 0;
+protected:
+ void update_from_matrix(const Msp::GL::Matrix &);
+};
+
+} // namespace VR
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <openvr.h>
+#include "openvrcontroller.h"
+#include "openvrcontroller_private.h"
+#include "openvrsystem.h"
+
+using namespace std;
+
+namespace Msp {
+namespace VR {
+
+OpenVRController::OpenVRController(OpenVRSystem &s):
+ system(s),
+ index(-1)
+{
+ name = "OpenVR Controller";
+
+ system.add_controller(*this);
+}
+
+OpenVRController::~OpenVRController()
+{
+ system.remove_controller(*this);
+}
+
+string OpenVRController::get_button_name(unsigned btn) const
+{
+ switch(btn)
+ {
+ case vr::k_EButton_System: return "System";
+ case vr::k_EButton_ApplicationMenu: return "Menu";
+ case vr::k_EButton_Grip: return "Grip";
+ case vr::k_EButton_Axis0: return "Trackpad";
+ case vr::k_EButton_Axis1: return "Trigger";
+ }
+
+ const char *n = vr::VRSystem()->GetButtonIdNameFromEnum(static_cast<vr::EVRButtonId>(btn));
+ if(n)
+ return n;
+
+ return MotionController::get_button_name(btn);
+}
+
+string OpenVRController::get_axis_name(unsigned axis) const
+{
+ switch(axis)
+ {
+ case 0: return "Trackpad X";
+ case 1: return "Trackpad Y";
+ case 2: return "Trigger";
+ }
+
+ return MotionController::get_axis_name(axis);
+}
+
+void OpenVRController::event(const Event &ev)
+{
+ switch(ev.eventType)
+ {
+ case vr::VREvent_TrackedDeviceActivated:
+ index = ev.trackedDeviceIndex;
+ break;
+ case vr::VREvent_TrackedDeviceDeactivated:
+ index = -1;
+ break;
+ case vr::VREvent_ButtonPress:
+ set_button_state(ev.data.controller.button, true, true);
+ break;
+ case vr::VREvent_ButtonUnpress:
+ set_button_state(ev.data.controller.button, false, true);
+ break;
+ }
+}
+
+void OpenVRController::update()
+{
+ if(index<0)
+ return;
+
+ update_from_matrix(system.get_tracking_matrix(index));
+}
+
+void OpenVRController::update_input_state()
+{
+ if(index<0)
+ return;
+
+ vr::VRControllerState_t state;
+ vr::VRSystem()->GetControllerState(index, &state);
+ if(state.unPacketNum!=last_packet_number)
+ {
+ for(unsigned i=0; i<5; ++i)
+ {
+ set_axis_value(i*2, state.rAxis[i].x, true);
+ set_axis_value(i*2+1, state.rAxis[i].y, true);
+ }
+
+ last_packet_number = state.unPacketNum;
+ }
+}
+
+} // namespace VR
+} // namespace Msp
--- /dev/null
+#ifndef MSP_VR_OPENVRCONTROLLER_H_
+#define MSP_VR_OPENVRCONTROLLER_H_
+
+#include <msp/vr/motioncontroller.h>
+
+namespace Msp {
+namespace VR {
+
+class OpenVRSystem;
+
+class OpenVRController: public MotionController
+{
+public:
+ struct Event;
+
+private:
+ OpenVRSystem &system;
+ int index;
+ unsigned last_packet_number;
+
+public:
+ OpenVRController(OpenVRSystem &);
+ virtual ~OpenVRController();
+
+ virtual std::string get_button_name(unsigned) const;
+ virtual std::string get_axis_name(unsigned) const;
+
+ int get_index() const { return index; }
+
+ void event(const Event &);
+ virtual void update();
+ void update_input_state();
+};
+
+} // namespace VR
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_VR_OPENVRCONTROLLER_PRIVATE_H_
+#define MSP_VR_OPENVRCONTROLLER_PRIVATE_H_
+
+#include <openvr.h>
+#include "openvrcontroller.h"
+
+namespace Msp {
+namespace VR {
+
+struct OpenVRController::Event: vr::VREvent_t
+{
+};
+
+} // namespace VR
+} // namespace Msp
+
+#endif
#include <openvr.h>
#include <msp/vr/stereoview.h>
+#include "openvrcontroller_private.h"
#include "openvrsystem.h"
using namespace std;
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);
}
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();
}
void OpenVRSystem::update_pose_matrices()
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);
+}
+
} // namespace VR
} // namespace Msp
#include <msp/vr/system.h>
#include "openvrcamera.h"
#include "openvrcombiner.h"
+#include "openvrcontroller.h"
namespace Msp {
namespace VR {
private:
unsigned n_tracked_devices;
std::vector<GL::Matrix> tracking_matrices;
+ std::vector<OpenVRController *> controllers;
+ std::vector<unsigned> unclaimed_controllers;
static unsigned n_instances;
virtual bool get_absolute_tracking() const;
virtual OpenVRCamera *create_camera(const GL::Camera &);
virtual OpenVRCombiner *create_combiner(GL::View &);
+ virtual OpenVRController *create_controller();
virtual void tick();
void update_pose_matrices();
const GL::Matrix &get_tracking_matrix(unsigned) const;
const GL::Matrix &get_hmd_matrix() const;
+ void add_controller(OpenVRController &);
+ void remove_controller(OpenVRController &);
};
} // namespace VR
#include <msp/gl/renderer.h>
#include "headtrackingcamera.h"
+#include "motioncontroller.h"
#include "stereocombiner.h"
#include "stereoview.h"
strabismus = s;
}
+void StereoView::add_controller(MotionController &controller)
+{
+ if(find(controllers.begin(), controllers.end(), &controller)==controllers.end())
+ controllers.push_back(&controller);
+}
+
+void StereoView::remove_controller(MotionController &controller)
+{
+ vector<MotionController *>::iterator i = find(controllers.begin(), controllers.end(), &controller);
+ if(i!=controllers.end())
+ controllers.erase(i);
+}
+
void StereoView::setup_frame() const
{
if(head_camera)
head_camera->update();
+ for(vector<MotionController *>::const_iterator i=controllers.begin(); i!=controllers.end(); ++i)
+ (*i)->update();
+
EyeParams params;
params.fov = combiner.get_field_of_view();
if(params.fov==Geometry::Angle<float>::zero())
namespace VR {
class HeadTrackingCamera;
+class MotionController;
class StereoCombiner;
class StereoView
Eye left;
Eye right;
Geometry::Angle<float> strabismus;
+ std::vector<MotionController *> controllers;
public:
StereoView(const StereoCombiner &, const GL::Camera &);
void set_eye_matrices(const GL::Matrix &, const GL::Matrix &);
void set_strabismus(const Geometry::Angle<float> &);
+ void add_controller(MotionController &);
+ void remove_controller(MotionController &);
+
private:
void setup_frame() const;
public:
throw invalid_argument("absolute tracking not supported");
}
+MotionController *System::create_controller()
+{
+ throw runtime_error("controller not supported");
+}
+
} // namespace VR
} // namespace Msp
#include <string>
#include <msp/gl/camera.h>
#include <msp/gl/view.h>
+#include "motioncontroller.h"
namespace Msp {
namespace VR {
virtual bool get_absolute_tracking() const { return false; }
virtual HeadTrackingCamera *create_camera(const GL::Camera &) = 0;
virtual StereoCombiner *create_combiner(GL::View &) = 0;
+ virtual MotionController *create_controller();
virtual void tick() { }
};