diff options
Diffstat (limited to 'tracker-steamvr')
| -rw-r--r-- | tracker-steamvr/CMakeLists.txt | 28 | ||||
| -rw-r--r-- | tracker-steamvr/dialog.ui | 6 | ||||
| -rw-r--r-- | tracker-steamvr/lang/nl_NL.ts | 17 | ||||
| -rw-r--r-- | tracker-steamvr/lang/ru_RU.ts | 17 | ||||
| -rw-r--r-- | tracker-steamvr/lang/stub.ts | 17 | ||||
| -rw-r--r-- | tracker-steamvr/lang/zh_CN.ts | 33 | ||||
| -rw-r--r-- | tracker-steamvr/steamvr.cpp | 268 | ||||
| -rw-r--r-- | tracker-steamvr/steamvr.hpp | 53 |
8 files changed, 244 insertions, 195 deletions
diff --git a/tracker-steamvr/CMakeLists.txt b/tracker-steamvr/CMakeLists.txt index 512a49ff..eb8b20b9 100644 --- a/tracker-steamvr/CMakeLists.txt +++ b/tracker-steamvr/CMakeLists.txt @@ -2,10 +2,13 @@ set(steamvr-dir "") set(steamvr-dll "") set(steamvr-lib "") -if(LINUX AND opentrack-64bit) - set(steamvr-dir "linux64") +if(LINUX) + if (opentrack-64bit) + set(steamvr-dir "linux64") + else() + set(steamvr-dir "linux32") + endif() set(steamvr-dll "libopenvr_api.so") - set(steamvr-lib "${steamvr-dll}") endif() if(WIN32) @@ -18,19 +21,26 @@ if(WIN32) set(steamvr-lib "openvr_api.lib") endif() -if(APPLE AND NOT opentrack-64bit) - set(steamvr-dir "osx32") +if(APPLE) + # expect user compiled it as a non-framework version + if(opentrack-64bit) + set(steamvr-dir "osx64") + else() + set(steamvr-dir "osx32") + endif() set(steamvr-dll "libopenvr_api.dylib") - set(steamvr-lib "${steamvr-dll}") endif() -if(steamvr-dll) +if(steamvr-dll AND opentrack-intel) + if(steamvr-lib STREQUAL "") + set(steamvr-lib "${steamvr-dll}") + endif() SET(SDK_VALVE_STEAMVR "" CACHE PATH "Valve's SteamVR") if(SDK_VALVE_STEAMVR) otr_module(tracker-steamvr) - install(FILES "${SDK_VALVE_STEAMVR}/bin/${steamvr-dir}/${steamvr-dll}" DESTINATION "${opentrack-hier-pfx}") + install(FILES "${SDK_VALVE_STEAMVR}/bin/${steamvr-dir}/${steamvr-dll}" DESTINATION "${opentrack-libexec}") - target_include_directories(opentrack-tracker-steamvr SYSTEM PUBLIC "${SDK_VALVE_STEAMVR}/headers") + target_include_directories(opentrack-tracker-steamvr SYSTEM PRIVATE "${SDK_VALVE_STEAMVR}/headers") target_link_libraries(opentrack-tracker-steamvr "${SDK_VALVE_STEAMVR}/lib/${steamvr-dir}/${steamvr-lib}") endif() endif() diff --git a/tracker-steamvr/dialog.ui b/tracker-steamvr/dialog.ui index 12a01816..0f981160 100644 --- a/tracker-steamvr/dialog.ui +++ b/tracker-steamvr/dialog.ui @@ -9,7 +9,7 @@ <rect> <x>0</x> <y>0</y> - <width>394</width> + <width>452</width> <height>85</height> </rect> </property> @@ -24,7 +24,7 @@ </property> <property name="windowIcon"> <iconset> - <normaloff>images/FaceTrackNoIR.png</normaloff>images/FaceTrackNoIR.png</iconset> + <normaloff>images/opentrack.png</normaloff>images/opentrack.png</iconset> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> @@ -43,7 +43,7 @@ <widget class="QLabel" name="label"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>3</horstretch> + <horstretch>1</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> diff --git a/tracker-steamvr/lang/nl_NL.ts b/tracker-steamvr/lang/nl_NL.ts index f57bcc35..37c3130d 100644 --- a/tracker-steamvr/lang/nl_NL.ts +++ b/tracker-steamvr/lang/nl_NL.ts @@ -4,33 +4,28 @@ <context> <name>dialog</name> <message> - <location filename="../dialog.ui" line="+23"/> <source>Valve SteamVR</source> <translation type="unfinished"></translation> </message> -</context> -<context> - <name>steamvr</name> <message> - <location filename="../steamvr.cpp" line="+57"/> - <source>Valve SteamVR init error</source> + <source>Device</source> <translation type="unfinished"></translation> </message> +</context> +<context> + <name>steamvr</name> <message> - <location line="+17"/> - <source>Valve SteamVR init warning</source> + <source>No HMD connected</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>No HMD connected</source> + <source>Can't find device with that serial</source> <translation type="unfinished"></translation> </message> </context> <context> <name>steamvr_metadata</name> <message> - <location filename="../steamvr.hpp" line="+74"/> <source>Valve SteamVR</source> <translation type="unfinished"></translation> </message> diff --git a/tracker-steamvr/lang/ru_RU.ts b/tracker-steamvr/lang/ru_RU.ts index 85eb4faf..380518d0 100644 --- a/tracker-steamvr/lang/ru_RU.ts +++ b/tracker-steamvr/lang/ru_RU.ts @@ -4,33 +4,28 @@ <context> <name>dialog</name> <message> - <location filename="../dialog.ui" line="+23"/> <source>Valve SteamVR</source> <translation type="unfinished"></translation> </message> -</context> -<context> - <name>steamvr</name> <message> - <location filename="../steamvr.cpp" line="+57"/> - <source>Valve SteamVR init error</source> + <source>Device</source> <translation type="unfinished"></translation> </message> +</context> +<context> + <name>steamvr</name> <message> - <location line="+17"/> - <source>Valve SteamVR init warning</source> + <source>No HMD connected</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>No HMD connected</source> + <source>Can't find device with that serial</source> <translation type="unfinished"></translation> </message> </context> <context> <name>steamvr_metadata</name> <message> - <location filename="../steamvr.hpp" line="+74"/> <source>Valve SteamVR</source> <translation type="unfinished"></translation> </message> diff --git a/tracker-steamvr/lang/stub.ts b/tracker-steamvr/lang/stub.ts index 757a56c1..7b68034b 100644 --- a/tracker-steamvr/lang/stub.ts +++ b/tracker-steamvr/lang/stub.ts @@ -4,33 +4,28 @@ <context> <name>dialog</name> <message> - <location filename="../dialog.ui" line="+23"/> <source>Valve SteamVR</source> <translation type="unfinished"></translation> </message> -</context> -<context> - <name>steamvr</name> <message> - <location filename="../steamvr.cpp" line="+57"/> - <source>Valve SteamVR init error</source> + <source>Device</source> <translation type="unfinished"></translation> </message> +</context> +<context> + <name>steamvr</name> <message> - <location line="+17"/> - <source>Valve SteamVR init warning</source> + <source>No HMD connected</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>No HMD connected</source> + <source>Can't find device with that serial</source> <translation type="unfinished"></translation> </message> </context> <context> <name>steamvr_metadata</name> <message> - <location filename="../steamvr.hpp" line="+74"/> <source>Valve SteamVR</source> <translation type="unfinished"></translation> </message> diff --git a/tracker-steamvr/lang/zh_CN.ts b/tracker-steamvr/lang/zh_CN.ts new file mode 100644 index 00000000..2c6f7230 --- /dev/null +++ b/tracker-steamvr/lang/zh_CN.ts @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="zh_CN"> +<context> + <name>dialog</name> + <message> + <source>Valve SteamVR</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Device</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>steamvr</name> + <message> + <source>No HMD connected</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Can't find device with that serial</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>steamvr_metadata</name> + <message> + <source>Valve SteamVR</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tracker-steamvr/steamvr.cpp b/tracker-steamvr/steamvr.cpp index fac0346a..05b5ed35 100644 --- a/tracker-steamvr/steamvr.cpp +++ b/tracker-steamvr/steamvr.cpp @@ -19,12 +19,9 @@ #include "steamvr.hpp" #include "api/plugin-api.hpp" -#include "compat/util.hpp" -#include <cstdlib> #include <cmath> -#include <type_traits> -#include <algorithm> +#include <cstdlib> #include <QMessageBox> #include <QDebug> @@ -32,76 +29,87 @@ QMutex device_list::mtx(QMutex::Recursive); template<typename F> -static auto with_vr_lock(F&& fun) -> decltype(fun(vr_t(), error_t())) +auto with_vr_lock(F&& fun) -> decltype(fun(vr_t(), vr_error_t())) { QMutexLocker l(&device_list::mtx); - error_t e; vr_t v; - std::tie(v, e) = device_list::vr_init(); + auto [v, e] = device_list::vr_init(); return fun(v, e); } void device_list::fill_device_specs(QList<device_spec>& list) { - with_vr_lock([&](vr_t v, error_t) + with_vr_lock([&](vr_t v, vr_error_t) { list.clear(); - list.reserve(max_devices); pose_t device_states[max_devices]; - if (v) + if (!v) + return; + + v->GetDeviceToAbsoluteTrackingPose(origin::TrackingUniverseSeated, 0, + device_states, vr::k_unMaxTrackedDeviceCount); + + constexpr unsigned bufsiz = vr::k_unMaxPropertyStringSize; + static char str[bufsiz+1] {}; // vr_lock prevents reentrancy + + for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++) { - v->GetDeviceToAbsoluteTrackingPose(origin::TrackingUniverseSeated, 0, - device_states, vr::k_unMaxTrackedDeviceCount); + if (v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_Invalid) + { + qDebug() << "steamvr: no device with index"; + continue; + } + + if (!device_states[k].bDeviceIsConnected) + { + qDebug() << "steamvr: device not connected but proceeding"; + 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; + } - static constexpr unsigned bufsiz = vr::k_unTrackingStringSize; - static char str[bufsiz] {}; // vr_lock prevents reentrancy + device_spec dev; - for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++) + 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; + } + + switch (v->GetTrackedDeviceClass(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; - } - - switch (v->GetTrackedDeviceClass(k)) - { - case vr::ETrackedDeviceClass::TrackedDeviceClass_HMD: - dev.type = "HMD"; break; - case vr::ETrackedDeviceClass::TrackedDeviceClass_Controller: - dev.type = "Controller"; break; - default: - dev.type = "Unknown"; break; - } - - dev.model = str; - dev.pose = device_states[k]; - dev.k = k; - - list.push_back(dev); + using enum vr::ETrackedDeviceClass; + case TrackedDeviceClass_HMD: + dev.type = "HMD"; break; + case TrackedDeviceClass_Controller: + dev.type = "Controller"; break; + case TrackedDeviceClass_TrackingReference: + dev.type = "Tracking reference"; break; + case TrackedDeviceClass_DisplayRedirect: + dev.type = "Display redirect"; break; + case TrackedDeviceClass_GenericTracker: + dev.type = "Generic"; break; + default: + dev.type = "Unknown"; break; } + + dev.model = str; + dev.pose = device_states[k]; + dev.k = k; + dev.is_connected = device_states[k].bDeviceIsConnected; + + list.push_back(dev); } }); } @@ -113,15 +121,17 @@ device_list::device_list() void device_list::refresh_device_list() { + device_specs.clear(); + device_specs.reserve(max_devices); fill_device_specs(device_specs); } device_list::maybe_pose device_list::get_pose(int k) { - if (k < 0 || !(k < max_devices)) + if (!(unsigned(k) < max_devices)) return maybe_pose(false, pose_t{}); - return with_vr_lock([k](vr_t v, error_t) + return with_vr_lock([k](vr_t v, vr_error_t) { static pose_t poses[max_devices] {}; // vr_lock removes reentrancy @@ -131,14 +141,14 @@ device_list::maybe_pose device_list::get_pose(int k) const pose_t& pose = poses[k]; if (pose.bPoseIsValid && pose.bDeviceIsConnected) - return maybe_pose(true, poses[k]); + return maybe_pose{ true, poses[k] }; else - once_only(qDebug() << "steamvr:" + eval_once(qDebug() << "steamvr:" << "no valid pose from device" << k << "valid" << pose.bPoseIsValid << "connected" << pose.bDeviceIsConnected); - return maybe_pose(false, pose_t{}); + return maybe_pose{ false, {} }; }); } @@ -150,41 +160,44 @@ tt device_list::vr_init() tt device_list::vr_init_() { - error_t error = error_t::VRInitError_Unknown; + vr_error_t error = vr_error_t::VRInitError_Unknown; vr_t v = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Other); if (v) std::atexit(vr::VR_Shutdown); else - qDebug() << "steamvr: init failure" << error << device_list::strerror(error); + qDebug() << "steamvr: init failure" << error << device_list::error_string(error); - return tt(v, error); + return { v, error }; } -QString device_list::strerror(error_t err) +QString device_list::error_string(vr_error_t err) { - const char* str(vr::VR_GetVRInitErrorAsSymbol(err)); - return QString(str ? str : "No description"); -} + const char* str = vr::VR_GetVRInitErrorAsSymbol(err); + const char* desc = vr::VR_GetVRInitErrorAsEnglishDescription(err); -steamvr::steamvr() : device_index(-1) -{ -} + if (!desc) + desc = "No description"; -steamvr::~steamvr() -{ + if (str) + return QStringLiteral("%1: %2").arg(str, desc); + else + return { "Unknown error" }; } -void steamvr::start_tracker(QFrame*) +steamvr::steamvr() = default; +steamvr::~steamvr() = default; + +module_status steamvr::start_tracker(QFrame*) { - with_vr_lock([this](vr_t v, error_t e) + return with_vr_lock([this](vr_t v, vr_error_t e) { + QString err; + if (!v) { - QMessageBox::warning(nullptr, - tr("SteamVR init error"), device_list::strerror(e), - QMessageBox::Close, QMessageBox::NoButton); - return; + err = device_list::error_string(e); + return error(err); } const QString serial = s.device_serial().toString(); @@ -193,54 +206,53 @@ void steamvr::start_tracker(QFrame*) const int sz = specs.count(); if (sz == 0) - { - QMessageBox::warning(nullptr, - tr("SteamVR init error"), - tr("No HMD connected"), - QMessageBox::Close, QMessageBox::NoButton); - return; - } - - device_index = -1; + err = tr("No HMD connected"); for (const device_spec& spec : specs) { if (serial == "" || serial == spec.to_string()) { - device_index = int(spec.k); + device_index = spec.k; break; } } - if (device_index == -1) + if (device_index == UINT_MAX && err.isEmpty()) + err = tr("Can't find device with that serial"); + + if (err.isEmpty()) { - QMessageBox::warning(nullptr, - tr("SteamVR init error"), - tr("Can't find device with that serial"), - QMessageBox::Close, QMessageBox::NoButton); + if (auto* c = vr::VRCompositor(); c != nullptr) + { + c->SetTrackingSpace(origin::TrackingUniverseSeated); + return status_ok(); + } + else + return error("vr::VRCompositor == NULL"); } + + return error(err); }); } void steamvr::data(double* data) { - if (device_index != -1) + if (device_index != UINT_MAX) { - pose_t pose; bool ok; - std::tie(ok, pose) = device_list::get_pose(device_index); + auto [ok, pose] = device_list::get_pose(device_index); if (ok) { - static constexpr int c = 10; + constexpr 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; + data[TX] = (double)(-result.m[0][3] * c); + data[TY] = (double)(result.m[1][3] * c); + data[TZ] = (double)(result.m[2][3] * c); matrix_to_euler(data[Yaw], data[Pitch], data[Roll], result); - static constexpr double r2d = 180 / M_PI; + constexpr double r2d = 180 / M_PI; data[Yaw] *= r2d; data[Pitch] *= r2d; data[Roll] *= r2d; } } @@ -248,28 +260,41 @@ void steamvr::data(double* data) bool steamvr::center() { - with_vr_lock([&](vr_t v, error_t) + return with_vr_lock([&](vr_t v, vr_error_t) { if (v) - // Reset yaw and position - v->ResetSeatedZeroPose(); + { + if (v->GetTrackedDeviceClass(device_index) == vr::ETrackedDeviceClass::TrackedDeviceClass_HMD) + { + auto* c = vr::VRChaperone(); + if (!c) + { + eval_once(qDebug() << "steamvr: vr::VRChaperone == NULL"); + return false; + } + else + { + c->ResetZeroPose(origin::TrackingUniverseSeated); + // Use chaperone universe real world up instead of opentrack's initial pose centering + // Note: Controllers will be centered based on initial headset position. + return true; + } + } + else + // with controllers, resetting the seated pose does nothing + return false; + } + return false; }); - // Use chaperone universe real world up instead of OpenTrack's initial pose centering - // Note: Controllers will be centered based on initial headset position. - // TODO: may want to center controller/tracker yaw and position (only) when used alone - return true; } void steamvr::matrix_to_euler(double& yaw, double& pitch, double& roll, const vr::HmdMatrix34_t& result) { - using std::atan2; - using std::sqrt; + using d = double; - yaw = atan2((double)-result.m[2][0], sqrt(double(result.m[2][1]) * result.m[2][1] + result.m[2][2] * result.m[2][2])); - pitch = atan2((double)result.m[2][1], (double)result.m[2][2]); - roll = atan2((double)result.m[1][0], (double)result.m[0][0]); - - // TODO: gimbal lock avoidance? + yaw = std::atan2(d(result.m[2][0]), d(result.m[0][0])); + pitch = std::atan2(-d(result.m[1][2]), d(result.m[1][1])); + roll = std::asin(d(result.m[1][0])); } steamvr_dialog::steamvr_dialog() @@ -284,7 +309,12 @@ steamvr_dialog::steamvr_dialog() device_list list; for (const device_spec& spec : list.devices()) - ui.device->addItem(spec.to_string(), spec.to_string()); + { + QString text = spec.to_string(); + if (!spec.is_connected) + text = QStringLiteral("%1 [disconnected]").arg(text); + ui.device->addItem(text, spec.to_string()); + } tie_setting(s.device_serial, ui.device); } @@ -304,7 +334,7 @@ void steamvr_dialog::doCancel() QString device_spec::to_string() const { - return QStringLiteral("<%1> %2 [%3]").arg(type).arg(model).arg(serial); + return QStringLiteral("<%1> %2 [%3]").arg(type, model, serial); } OPENTRACK_DECLARE_TRACKER(steamvr, steamvr_dialog, steamvr_metadata) diff --git a/tracker-steamvr/steamvr.hpp b/tracker-steamvr/steamvr.hpp index e979b9e3..61da2e05 100644 --- a/tracker-steamvr/steamvr.hpp +++ b/tracker-steamvr/steamvr.hpp @@ -1,27 +1,24 @@ #pragma once -#include "api/plugin-api.hpp" + #include "ui_dialog.h" -#include "compat/util.hpp" +#include "api/plugin-api.hpp" #include "options/options.hpp" -#include "compat/euler.hpp" - -#include <openvr.h> - -#include <cmath> -#include <memory> #include <tuple> +#include <climits> #include <QString> #include <QMutex> -#include <QMutexLocker> #include <QList> +#include <openvr.h> + using namespace options; -using error_t = vr::EVRInitError; + +using vr_error_t = vr::EVRInitError; using vr_t = vr::IVRSystem*; -using tt = std::tuple<vr_t, error_t>; +using tt = std::tuple<vr_t, vr_error_t>; using pose_t = vr::TrackedDevicePose_t; using origin = vr::ETrackingUniverseOrigin; @@ -40,6 +37,7 @@ struct device_spec QString model, serial, type; unsigned k; QString to_string() const; + bool is_connected; }; struct device_list final @@ -48,20 +46,19 @@ struct device_list final device_list(); void refresh_device_list(); - const QList<device_spec>& devices() const & { return device_specs; } + const QList<device_spec>& devices() const { return device_specs; } - static OTR_NEVER_INLINE maybe_pose get_pose(int k); - static QString strerror(error_t error); - static constexpr int max_devices = int(vr::k_unMaxTrackedDeviceCount); + static never_inline maybe_pose get_pose(int k); + static QString error_string(vr_error_t error); + static constexpr unsigned max_devices = vr::k_unMaxTrackedDeviceCount; template<typename F> - friend auto with_vr_lock(F&& fun) -> decltype(fun(vr_t(), error_t())); + friend auto with_vr_lock(F&& fun) -> decltype(fun(vr_t(), vr_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(); }; @@ -70,24 +67,17 @@ class steamvr : public QObject, public ITracker { Q_OBJECT - using error_t = vr::EVRInitError; - using vr_t = vr::IVRSystem*; + static void matrix_to_euler(double& yaw, double& pitch, double& roll, const vr::HmdMatrix34_t& result); + + settings s; + unsigned device_index{UINT_MAX}; public: steamvr(); ~steamvr() override; - void start_tracker(QFrame *) override; + module_status start_tracker(QFrame *) override; void data(double *data) override; bool center() override; - -private: - static 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; }; class steamvr_dialog : public ITrackerDialog @@ -107,7 +97,8 @@ private slots: class steamvr_metadata : public Metadata { -public: - QString name() override { return QString(QCoreApplication::translate("steamvr_metadata", "Valve SteamVR")); } + Q_OBJECT + + QString name() override { return tr("Valve SteamVR"); } QIcon icon() override { return QIcon(":/images/rift_tiny.png"); } }; |
