summaryrefslogtreecommitdiffhomepage
path: root/tracker-steamvr/steamvr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-steamvr/steamvr.cpp')
-rw-r--r--tracker-steamvr/steamvr.cpp281
1 files changed, 203 insertions, 78 deletions
diff --git a/tracker-steamvr/steamvr.cpp b/tracker-steamvr/steamvr.cpp
index 2d92c5a4..b60d4896 100644
--- a/tracker-steamvr/steamvr.cpp
+++ b/tracker-steamvr/steamvr.cpp
@@ -16,45 +16,161 @@
*/
#include "steamvr.hpp"
+
#include "api/plugin-api.hpp"
#include "compat/util.hpp"
#include <cstdlib>
#include <cmath>
+#include <type_traits>
+#include <algorithm>
#include <QMessageBox>
#include <QDebug>
-void steamvr::vr_deleter()
+QMutex device_list::mtx(QMutex::Recursive);
+
+template<typename F>
+static auto with_vr_lock(F&& fun) -> decltype(fun(vr_t(), error_t()))
{
- static std::atomic_flag atexit_done = ATOMIC_FLAG_INIT;
+ QMutexLocker l(&device_list::mtx);
+ error_t e; vr_t v;
+ std::tie(v, e) = device_list::vr_init();
+ return fun(v, e);
+}
- if (atexit_done.test_and_set(std::memory_order_seq_cst))
+void device_list::fill_device_specs(QList<device_spec>& list)
+{
+ with_vr_lock([&](vr_t v, error_t)
{
- std::atexit(vr::VR_Shutdown);
- }
+ list.clear();
+ list.reserve(max_devices);
+
+ pose_t device_states[max_devices];
+
+ if (v)
+ {
+ v->GetDeviceToAbsoluteTrackingPose(origin::TrackingUniverseSeated, 0,
+ device_states, vr::k_unMaxTrackedDeviceCount);
+
+ static constexpr unsigned bufsiz = vr::k_unTrackingStringSize;
+ char str[bufsiz] {};
+
+ for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++)
+ {
+ if (v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_Invalid ||
+ v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_TrackingReference)
+ continue;
+
+ if (!device_states[k].bDeviceIsConnected)
+ continue;
+
+ unsigned len;
+
+ len = v->GetStringTrackedDeviceProperty(k, vr::ETrackedDeviceProperty::Prop_SerialNumber_String, str, bufsiz);
+ if (!len)
+ {
+ qDebug() << "steamvr: getting serial number failed for" << k;
+ continue;
+ }
+
+ device_spec dev;
+
+ dev.serial = str;
+
+ len = v->GetStringTrackedDeviceProperty(k, vr::ETrackedDeviceProperty::Prop_ModelNumber_String, str, bufsiz);
+ if (!len)
+ {
+ qDebug() << "steamvr: getting model number failed for" << k;
+ continue;
+ }
+
+ dev.model = str;
+ dev.pose = device_states[k];
+ dev.k = k;
+
+ list.push_back(dev);
+ }
+ }
+ });
+}
+
+device_list::device_list()
+{
+ refresh_device_list();
+}
+
+void device_list::refresh_device_list()
+{
+ fill_device_specs(device_specs);
+}
+
+device_list::maybe_pose device_list::get_pose(int k)
+{
+ if (k < 0 || !(k < max_devices))
+ return maybe_pose(false, pose_t{});
+
+ return with_vr_lock([k](vr_t v, error_t)
+ {
+ static pose_t poses[max_devices] {}; // vr_lock removes reentrancy
+
+ v->GetDeviceToAbsoluteTrackingPose(origin::TrackingUniverseSeated, 0,
+ poses, max_devices);
+
+ const pose_t& pose = poses[k];
+
+ if (pose.bPoseIsValid && pose.bDeviceIsConnected)
+ return maybe_pose(true, poses[k]);
+ else
+ once_only(qDebug() << "steamvr:"
+ << "no valid pose from device" << k
+ << "valid" << pose.bPoseIsValid
+ << "connected" << pose.bDeviceIsConnected);
+
+ return maybe_pose(false, pose_t{});
+ });
+}
+
+bool device_list::get_all_poses(pose_t* poses)
+{
+ with_vr_lock([poses](vr_t v, error_t)
+ {
+ if (v)
+ {
+ v->GetDeviceToAbsoluteTrackingPose(origin::TrackingUniverseSeated, 0,
+ poses, max_devices);
+ }
+ return v != nullptr;
+ });
+
}
-steamvr::vr_t steamvr::vr_init(error_t& error)
+tt device_list::vr_init()
{
- error = error_t::VRInitError_Unknown;
+ static tt t = vr_init_();
+ return t;
+}
- // the background type would surely confuse users
- vr_t vr = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Other);
+tt device_list::vr_init_()
+{
+ error_t error = error_t::VRInitError_Unknown;
+ vr_t v = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Other);
- if (vr)
- vr_deleter();
+ if (v)
+ std::atexit(vr::VR_Shutdown);
+ else
+ once_only(qDebug() << "steamvr: init failure" << error << strerror(error));
- return vr;
+ return tt(v, error);
}
-QString steamvr::strerror(error_t error)
+QString device_list::strerror(error_t err)
{
- const char* str(vr::VR_GetVRInitErrorAsSymbol(error));
+ const char* str(vr::VR_GetVRInitErrorAsSymbol(err));
return QString(str ? str : "No description");
}
-steamvr::steamvr() : vr(nullptr)
+steamvr::steamvr() : device_index(-1)
{
}
@@ -64,97 +180,106 @@ steamvr::~steamvr()
void steamvr::start_tracker(QFrame*)
{
- error_t e(error_t::VRInitError_Unknown);
- vr = vr_init(e);
-
- if (!vr)
+ with_vr_lock([this](vr_t v, error_t e)
{
- QMessageBox::warning(nullptr,
- tr("Valve SteamVR init error"), strerror(e),
- QMessageBox::Close, QMessageBox::NoButton);
- return;
- }
+ if (!v)
+ {
+ QMessageBox::warning(nullptr,
+ tr("Valve SteamVR init error"), strerror(e),
+ QMessageBox::Close, QMessageBox::NoButton);
+ }
- bool ok = false;
+ const QString serial = s.device_serial;
+ device_list d;
+ const QList<device_spec>& specs = d.devices();
+ const int sz = specs.count();
- for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++)
- if (vr->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_HMD)
+ if (sz == 0)
{
- ok = true;
- break;
+ QMessageBox::warning(nullptr,
+ tr("Valve SteamVR init error"),
+ tr("No HMD connected"),
+ QMessageBox::Close, QMessageBox::NoButton);
}
- if (!ok)
- {
- QMessageBox::warning(nullptr,
- tr("Valve SteamVR init warning"),
- tr("No HMD connected"),
- QMessageBox::Close, QMessageBox::NoButton);
- return;
- }
+ for (const device_spec& spec : specs)
+ {
+ if (serial == "" || serial == spec.serial)
+ {
+ device_index = int(spec.k);
+ break;
+ }
+ }
+ });
}
void steamvr::data(double* data)
{
- if (vr)
+ if (device_index != -1)
{
- vr::TrackedDevicePose_t devices[vr::k_unMaxTrackedDeviceCount] = {};
-
- vr->GetDeviceToAbsoluteTrackingPose(vr::ETrackingUniverseOrigin::TrackingUniverseSeated, 0,
- devices, vr::k_unMaxTrackedDeviceCount);
-
- for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++)
+ pose_t pose; bool ok;
+ std::tie(ok, pose) = device_list::get_pose(device_index);
+ if (ok)
{
- if (!devices[k].bPoseIsValid)
- continue;
-
- if (vr->GetTrackedDeviceClass(k) != vr::ETrackedDeviceClass::TrackedDeviceClass_HMD)
- continue;
-
- const vr::HmdMatrix34_t& result = devices[k].mDeviceToAbsoluteTracking;
+ static constexpr int c = 10;
- int c = 10;
+ const auto& result = pose.mDeviceToAbsoluteTracking;
data[TX] = -result.m[0][3] * c;
data[TY] = result.m[1][3] * c;
data[TZ] = result.m[2][3] * c;
- using std::atan2;
- using std::asin;
-
- // transformation matrix to euler angles
- if (result.m[0][0] == 1.0f || result.m[0][0] == -1.0f)
- {
- data[Yaw] = -atan2(result.m[0][2], result.m[2][3]);
- data[Pitch] = 0;
- data[Roll] = 0;
- }
- else
- {
- data[Yaw] = -atan2(-result.m[2][0], result.m[0][0]);
- data[Pitch] = atan2(-result.m[1][2], result.m[1][1]);
- data[Roll] = atan2(result.m[1][1], result.m[0][1]);
- }
+ matrix_to_euler(data[Yaw], data[Pitch], data[Roll], result);
static constexpr double r2d = 180 / M_PI;
-
- data[Yaw] *= r2d;
- data[Pitch] *= r2d;
- data[Roll] *= r2d;
-
- break;
+ data[Yaw] *= r2d; data[Pitch] *= r2d; data[Roll] *= r2d;
}
}
}
bool steamvr::center()
{
- if (vr)
- vr->ResetSeatedZeroPose();
+ with_vr_lock([&](vr_t v, error_t)
+ {
+ if (v)
+ v->ResetSeatedZeroPose();
+ });
return false;
}
-void steamvr_dialog::register_tracker(ITracker*) {}
-void steamvr_dialog::unregister_tracker() {}
+void steamvr::matrix_to_euler(double& yaw, double& pitch, double& roll, const vr::HmdMatrix34_t& result)
+{
+ yaw = atan2(result.m[2][0], result.m[0][0]);
+ pitch = atan2(result.m[1][1], result.m[1][2]);
+ roll = atan2(result.m[1][1], result.m[0][1]);
+}
+
+steamvr_dialog::steamvr_dialog()
+{
+ ui.setupUi(this);
+
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
+
+ ui.device->clear();
+ ui.device->addItem("");
+
+ device_list list;
+ for (const device_spec& spec : list.devices())
+ ui.device->addItem(spec.serial);
+
+ tie_setting(s.device_serial, ui.device);
+}
+
+void steamvr_dialog::doOK()
+{
+ s.b->save();
+ close();
+}
+
+void steamvr_dialog::doCancel()
+{
+ close();
+}
OPENTRACK_DECLARE_TRACKER(steamvr, steamvr_dialog, steamvr_metadata)