summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--tracker-steamvr/dialog.cpp22
-rw-r--r--tracker-steamvr/dialog.ui57
-rw-r--r--tracker-steamvr/steamvr.cpp281
-rw-r--r--tracker-steamvr/steamvr.hpp66
4 files changed, 296 insertions, 130 deletions
diff --git a/tracker-steamvr/dialog.cpp b/tracker-steamvr/dialog.cpp
deleted file mode 100644
index bbb8866d..00000000
--- a/tracker-steamvr/dialog.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "steamvr.hpp"
-#include "api/plugin-api.hpp"
-
-steamvr_dialog::steamvr_dialog()
-{
- ui.setupUi(this);
-
- connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
- connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
-}
-
-void steamvr_dialog::doOK()
-{
- s.b->save();
- close();
-}
-
-void steamvr_dialog::doCancel()
-{
- close();
-}
-
diff --git a/tracker-steamvr/dialog.ui b/tracker-steamvr/dialog.ui
index 9d3b1e85..12a01816 100644
--- a/tracker-steamvr/dialog.ui
+++ b/tracker-steamvr/dialog.ui
@@ -9,15 +9,15 @@
<rect>
<x>0</x>
<y>0</y>
- <width>281</width>
- <height>66</height>
+ <width>394</width>
+ <height>85</height>
</rect>
</property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <property name="minimumSize">
+ <size>
+ <width>394</width>
+ <height>0</height>
+ </size>
</property>
<property name="windowTitle">
<string>Valve SteamVR</string>
@@ -32,8 +32,40 @@
<property name="autoFillBackground">
<bool>false</bool>
</property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>3</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Device</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="device">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>8</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -46,13 +78,6 @@
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>No settings necessary</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
<resources/>
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)
diff --git a/tracker-steamvr/steamvr.hpp b/tracker-steamvr/steamvr.hpp
index 2842fda3..0c6af65a 100644
--- a/tracker-steamvr/steamvr.hpp
+++ b/tracker-steamvr/steamvr.hpp
@@ -8,47 +8,86 @@
#include <openvr.h>
-#include <atomic>
#include <cmath>
#include <memory>
+#include <tuple>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
+#include <QList>
using namespace options;
+using error_t = vr::EVRInitError;
+using vr_t = vr::IVRSystem*;
+
+using tt = std::tuple<vr_t, error_t>;
+using pose_t = vr::TrackedDevicePose_t;
+using origin = vr::ETrackingUniverseOrigin;
struct settings : opts
{
+ value<QString> device_serial;
settings() :
- opts("valve-steamvr")
+ opts("valve-steamvr"),
+ device_serial(b, "serial", "")
{}
};
+struct device_spec
+{
+ vr::TrackedDevicePose_t pose;
+ QString model, serial;
+ unsigned k;
+};
+
+struct device_list final
+{
+ using maybe_pose = std::tuple<bool, pose_t>;
+
+ device_list();
+ void refresh_device_list();
+ const QList<device_spec>& devices() const & { return device_specs; }
+
+ static OTR_NEVER_INLINE maybe_pose get_pose(int k);
+ static bool get_all_poses(pose_t*poses);
+ static QString strerror(error_t error);
+ static constexpr int max_devices = int(vr::k_unMaxTrackedDeviceCount);
+
+ template<typename F>
+ friend static auto with_vr_lock(F&& fun) -> decltype(fun(vr_t(), error_t()));
+
+private:
+ QList<device_spec> device_specs;
+ static QMutex mtx;
+ static tt vr_init_();
+ static void vr_deleter();
+ static void fill_device_specs(QList<device_spec>& list);
+ static tt vr_init();
+};
+
class steamvr : public QObject, public ITracker
{
Q_OBJECT
+
+ using error_t = vr::EVRInitError;
+ using vr_t = vr::IVRSystem*;
+
public:
steamvr();
~steamvr() override;
void start_tracker(QFrame *) override;
void data(double *data) override;
bool center() override;
-private:
- using error_t = vr::EVRInitError;
- using vr_t = vr::IVRSystem*;
-
- vr_t vr;
+private:
+ void matrix_to_euler(double &yaw, double &pitch, double &roll, const vr::HmdMatrix34_t& result);
settings s;
+ int device_index;
using rmat = euler::rmat;
using euler_t = euler::euler_t;
-
- static void vr_deleter();
- static vr_t vr_init(error_t& error);
- static QString strerror(error_t error);
};
class steamvr_dialog : public ITrackerDialog
@@ -57,12 +96,11 @@ class steamvr_dialog : public ITrackerDialog
public:
steamvr_dialog();
- void register_tracker(ITracker *) override;
- void unregister_tracker() override;
private:
Ui::dialog ui;
settings s;
- vr::IVRSystem* vr;
+ device_list devices;
+
private slots:
void doOK();
void doCancel();