Merge pull request #387 from ctrlaltdavid/feature/openvr-linux

Build OpenVR plugin on Linux
This commit is contained in:
kasenvr 2020-07-09 17:10:29 -04:00 committed by GitHub
commit cf2beb6c96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 218 additions and 78 deletions

View file

@ -21,8 +21,8 @@
These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required. These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required.
- [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83 - [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83
- [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8 - [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8
- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac) - [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Windows) / 0.5 (Mac)
- [OpenVR](https://github.com/ValveSoftware/openvr): 1.11.11 (Win32 only) - [OpenVR](https://github.com/ValveSoftware/openvr): 1.11.11 (Windows, Linux)
- [Polyvox](http://www.volumesoffun.com/): 0.2.1 - [Polyvox](http://www.volumesoffun.com/): 0.2.1
- [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3 - [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3
- [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3 - [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3

View file

@ -1,4 +1,4 @@
Source: hifi-client-deps Source: hifi-client-deps
Version: 0.1 Version: 0.1
Description: Collected dependencies for High Fidelity applications Description: Collected dependencies for High Fidelity applications
Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr (windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr (linux|windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator

View file

@ -11,15 +11,23 @@ vcpkg_from_github(
set(VCPKG_LIBRARY_LINKAGE dynamic) set(VCPKG_LIBRARY_LINKAGE dynamic)
if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64")
set(ARCH_PATH "win64") if(WIN32)
set(ARCH_PATH "win64")
else()
set(ARCH_PATH "linux64")
endif()
elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86")
set(ARCH_PATH "win32") if(WIN32)
set(ARCH_PATH "win32")
else()
set(ARCH_PATH "linux32")
endif()
else() else()
message(FATAL_ERROR "Package only supports x64 and x86 windows.") message(FATAL_ERROR "Package only supports x64 and x86 Windows and Linux.")
endif() endif()
if(VCPKG_CMAKE_SYSTEM_NAME) if(VCPKG_CMAKE_SYSTEM_NAME AND NOT (VCPKG_CMAKE_SYSTEM_NAME STREQUAL "Linux"))
message(FATAL_ERROR "Package only supports windows desktop.") message(FATAL_ERROR "Package only supports Windows or Linux desktop.")
endif() endif()
file(MAKE_DIRECTORY file(MAKE_DIRECTORY
@ -28,18 +36,35 @@ file(MAKE_DIRECTORY
${CURRENT_PACKAGES_DIR}/debug/lib ${CURRENT_PACKAGES_DIR}/debug/lib
${CURRENT_PACKAGES_DIR}/debug/bin ${CURRENT_PACKAGES_DIR}/debug/bin
) )
file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/lib)
file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) if(WIN32)
file(COPY file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/lib)
${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib)
${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb file(COPY
DESTINATION ${CURRENT_PACKAGES_DIR}/bin ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll
) ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb
file(COPY DESTINATION ${CURRENT_PACKAGES_DIR}/bin
${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll )
${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb file(COPY
DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll
) ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb
DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin
)
else()
file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/libopenvr_api.so DESTINATION ${CURRENT_PACKAGES_DIR}/lib)
file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/libopenvr_api.so DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib)
file(COPY
${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so
${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so.dbg
DESTINATION ${CURRENT_PACKAGES_DIR}/bin
)
file(COPY
${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so
${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so.dbg
DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin
)
endif()
file(COPY ${SOURCE_PATH}/headers DESTINATION ${CURRENT_PACKAGES_DIR}) file(COPY ${SOURCE_PATH}/headers DESTINATION ${CURRENT_PACKAGES_DIR})
file(RENAME ${CURRENT_PACKAGES_DIR}/headers ${CURRENT_PACKAGES_DIR}/include) file(RENAME ${CURRENT_PACKAGES_DIR}/headers ${CURRENT_PACKAGES_DIR}/include)

View file

@ -1,12 +1,13 @@
# #
# Created by Bradley Austin Davis on 2015/11/18 # Created by Bradley Austin Davis on 2015/11/18
# Copyright 2015 High Fidelity, Inc. # Copyright 2015 High Fidelity, Inc.
# Copyright 2020 Vircadia contributors.
# #
# Distributed under the Apache License, Version 2.0. # Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
# #
if (WIN32 AND (NOT USE_GLES)) if ((WIN32 OR UNIX AND NOT APPLE) AND NOT USE_GLES)
set(TARGET_NAME openvr) set(TARGET_NAME openvr)
setup_hifi_plugin(Gui Qml Multimedia) setup_hifi_plugin(Gui Qml Multimedia)
link_hifi_libraries(shared task gl qml networking controllers ui link_hifi_libraries(shared task gl qml networking controllers ui
@ -15,7 +16,9 @@ if (WIN32 AND (NOT USE_GLES))
include_hifi_library_headers(octree) include_hifi_library_headers(octree)
target_openvr() target_openvr()
target_sranipal() if (WIN32)
target_aristo() target_sranipal()
target_link_libraries(${TARGET_NAME} Winmm.lib) target_aristo()
target_link_libraries(${TARGET_NAME} Winmm.lib)
endif()
endif() endif()

View file

@ -1,6 +1,7 @@
// //
// Created by Bradley Austin Davis on 2015/05/12 // Created by Bradley Austin Davis on 2015/05/12
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -739,6 +740,8 @@ int OpenVrDisplayPlugin::getRequiredThreadCount() const {
QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const { QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const {
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_RecordingDeviceOverride_String); QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_RecordingDeviceOverride_String);
// FIXME: Address Linux.
#ifdef Q_OS_WIN
if (!device.isEmpty()) { if (!device.isEmpty()) {
static const WCHAR INIT = 0; static const WCHAR INIT = 0;
size_t size = device.size() + 1; size_t size = device.size() + 1;
@ -748,11 +751,14 @@ QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const {
// FIXME: This may not be necessary if vr::k_pch_audio_RecordingDeviceOverride_StringName is used above. // FIXME: This may not be necessary if vr::k_pch_audio_RecordingDeviceOverride_StringName is used above.
device = AudioClient::getWinDeviceName(deviceW.data()); device = AudioClient::getWinDeviceName(deviceW.data());
} }
#endif
return device; return device;
} }
QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const { QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const {
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_PlaybackDeviceOverride_String); QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_PlaybackDeviceOverride_String);
// FIXME: Address Linux.
#ifdef Q_OS_WIN
if (!device.isEmpty()) { if (!device.isEmpty()) {
static const WCHAR INIT = 0; static const WCHAR INIT = 0;
size_t size = device.size() + 1; size_t size = device.size() + 1;
@ -762,6 +768,7 @@ QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const {
// FIXME: This may not be necessary if vr::k_pch_audio_PlaybackDeviceOverride_StringName is used above. // FIXME: This may not be necessary if vr::k_pch_audio_PlaybackDeviceOverride_StringName is used above.
device = AudioClient::getWinDeviceName(deviceW.data()); device = AudioClient::getWinDeviceName(deviceW.data());
} }
#endif
return device; return device;
} }

View file

@ -1,6 +1,7 @@
// //
// Created by Bradley Austin Davis on 2015/11/01 // Created by Bradley Austin Davis on 2015/11/01
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -18,8 +19,6 @@
#include <QtGui/QInputMethodEvent> #include <QtGui/QInputMethodEvent>
#include <QtQuick/QQuickWindow> #include <QtQuick/QQuickWindow>
#include <PathUtils.h>
#include <Windows.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
#include <controllers/Pose.h> #include <controllers/Pose.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
@ -51,7 +50,7 @@ static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000;
bool isOculusPresent() { bool isOculusPresent() {
bool result = false; bool result = false;
#if defined(Q_OS_WIN32) #ifdef Q_OS_WIN
HANDLE oculusServiceEvent = ::OpenEventW(SYNCHRONIZE, FALSE, L"OculusHMDConnected"); HANDLE oculusServiceEvent = ::OpenEventW(SYNCHRONIZE, FALSE, L"OculusHMDConnected");
// The existence of the service indicates a running Oculus runtime // The existence of the service indicates a running Oculus runtime
if (oculusServiceEvent) { if (oculusServiceEvent) {
@ -208,8 +207,10 @@ void finishOpenVrKeyboardInput() {
updateFromOpenVrKeyboardInput(); updateFromOpenVrKeyboardInput();
// Simulate an enter press on the top level window to trigger the action // Simulate an enter press on the top level window to trigger the action
if (0 == (_currentHints & Qt::ImhMultiLine)) { if (0 == (_currentHints & Qt::ImhMultiLine)) {
qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"))); auto keyPress = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"));
qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers())); auto keyRelease = QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers());
qApp->sendEvent(offscreenUi->getWindow(), &keyPress);
qApp->sendEvent(offscreenUi->getWindow(), &keyRelease);
} }
} }
@ -293,11 +294,20 @@ void handleOpenVrEvents() {
ulong promitySensorFlag = (1UL << ((int)vr::k_EButton_ProximitySensor)); ulong promitySensorFlag = (1UL << ((int)vr::k_EButton_ProximitySensor));
_headInHeadset = (controllerState.ulButtonPressed & promitySensorFlag) == promitySensorFlag; _headInHeadset = (controllerState.ulButtonPressed & promitySensorFlag) == promitySensorFlag;
} }
} }
#if DEV_BUILD #if DEV_BUILD
qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; //qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")";
// FIXME: Reinstate the line above and remove the following lines once the problem with excessive occurrences of
// VREvent_ActionBindingReloaded events is fixed in SteamVR for Linux.
// https://github.com/ValveSoftware/SteamVR-for-Linux/issues/307
#ifdef Q_OS_LINUX
if (event.eventType != vr::VREvent_ActionBindingReloaded) {
qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")";
};
#else
qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")";
#endif
#endif #endif
} }
@ -407,9 +417,32 @@ void showMinSpecWarning() {
qFatal("Unable to create overlay"); qFatal("Unable to create overlay");
} }
// Needed here for PathUtils #ifdef Q_OS_LINUX
QFile cmdlineFile("/proc/self/cmdline");
if (!cmdlineFile.open(QIODevice::ReadOnly)) {
qFatal("Unable to open /proc/self/cmdline");
}
auto contents = cmdlineFile.readAll();
auto arguments = contents.split('\0');
arguments.pop_back(); // Last element is empty.
cmdlineFile.close();
int __argc = arguments.count();
char** __argv = new char* [__argc];
for (int i = 0; i < __argc; i++) {
__argv[i] = arguments[i].data();
}
#endif
QCoreApplication miniApp(__argc, __argv); QCoreApplication miniApp(__argc, __argv);
#ifdef Q_OS_LINUX
QObject::connect(&miniApp, &QCoreApplication::destroyed, [=] {
delete[] __argv;
});
#endif
vrSystem->ResetSeatedZeroPose(); vrSystem->ResetSeatedZeroPose();
QString imagePath = PathUtils::resourcesPath() + "/images/steam-min-spec-failed.png"; QString imagePath = PathUtils::resourcesPath() + "/images/steam-min-spec-failed.png";
vrOverlay->SetOverlayFromFile(minSpecFailedOverlay, imagePath.toLocal8Bit().toStdString().c_str()); vrOverlay->SetOverlayFromFile(minSpecFailedOverlay, imagePath.toLocal8Bit().toStdString().c_str());
@ -487,7 +520,12 @@ bool checkMinSpecImpl() {
} }
extern "C" { extern "C" {
#if defined(Q_OS_WIN32)
__declspec(dllexport) int __stdcall CheckMinSpec() { __declspec(dllexport) int __stdcall CheckMinSpec() {
#else
__attribute__((visibility("default"))) int CheckMinSpec() {
#endif
return checkMinSpecImpl() ? 1 : 0; return checkMinSpecImpl() ? 1 : 0;
} }
} }

View file

@ -1,6 +1,7 @@
// //
// Created by Bradley Austin Davis on 2015/06/12 // Created by Bradley Austin Davis on 2015/06/12
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -76,7 +77,7 @@ struct PoseData {
} }
void update(const glm::mat4& resetMat) { void update(const glm::mat4& resetMat) {
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
if (!vrPoses[i].bPoseIsValid) { if (!vrPoses[i].bPoseIsValid) {
continue; continue;
} }
@ -87,7 +88,7 @@ struct PoseData {
} }
void resetToInvalid() { void resetToInvalid() {
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
vrPoses[i].bPoseIsValid = false; vrPoses[i].bPoseIsValid = false;
} }
} }

View file

@ -1,9 +1,9 @@
// //
// ViveControllerManager.cpp // ViveControllerManager.cpp
// input-plugins/src/input-plugins
// //
// Created by Sam Gondelman on 6/29/15. // Created by Sam Gondelman on 6/29/15.
// Copyright 2013 High Fidelity, Inc. // Copyright 2013 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -19,10 +19,12 @@
#pragma warning( disable : 4334 ) #pragma warning( disable : 4334 )
#endif #endif
#ifdef VIVE_PRO_EYE
#include <SRanipal.h> #include <SRanipal.h>
#include <SRanipal_Eye.h> #include <SRanipal_Eye.h>
#include <SRanipal_Enums.h> #include <SRanipal_Enums.h>
#include <interface_gesture.hpp> #include <interface_gesture.hpp>
#endif
#ifdef _WIN32 #ifdef _WIN32
#pragma warning( pop ) #pragma warning( pop )
@ -49,7 +51,7 @@
#include <plugins/DisplayPlugin.h> #include <plugins/DisplayPlugin.h>
#include <controllers/UserInputMapper.h> #include <controllers/UserInputMapper.h>
#include <Plugins/InputConfiguration.h> #include <plugins/InputConfiguration.h>
#include <controllers/StandardControls.h> #include <controllers/StandardControls.h>
#include "OpenVrDisplayPlugin.h" #include "OpenVrDisplayPlugin.h"
@ -60,13 +62,8 @@ vr::IVRSystem* acquireOpenVrSystem();
void releaseOpenVrSystem(); void releaseOpenVrSystem();
static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml"); static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml");
static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND; const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND;
static const char* MENU_PARENT = "Avatar";
static const char* MENU_NAME = "Vive Controllers";
static const char* MENU_PATH = "Avatar" ">" "Vive Controllers";
static const int MIN_HEAD = 1; static const int MIN_HEAD = 1;
static const int MIN_PUCK_COUNT = 2; static const int MIN_PUCK_COUNT = 2;
static const int MIN_FEET_AND_HIPS = 3; static const int MIN_FEET_AND_HIPS = 3;
@ -79,6 +76,7 @@ static const int SECOND_FOOT = 1;
static const int HIP = 2; static const int HIP = 2;
static const int CHEST = 3; static const int CHEST = 3;
#ifdef VIVE_PRO_EYE
enum ViveHandJointIndex { enum ViveHandJointIndex {
HAND = 0, HAND = 0,
THUMB_1, THUMB_1,
@ -104,6 +102,7 @@ enum ViveHandJointIndex {
Size Size
}; };
#endif
const char* ViveControllerManager::NAME { "OpenVR" }; const char* ViveControllerManager::NAME { "OpenVR" };
@ -157,22 +156,7 @@ static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult)
return result; return result;
} }
static glm::mat4 calculateResetMat() { #ifdef VIVE_PRO_EYE
auto chaperone = vr::VRChaperone();
if (chaperone) {
float const UI_RADIUS = 1.0f;
float const UI_HEIGHT = 1.6f;
float const UI_Z_OFFSET = 0.5;
float xSize, zSize;
chaperone->GetPlayAreaSize(&xSize, &zSize);
glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET);
return glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos));
}
return glm::mat4();
}
class ViveProEyeReadThread : public QThread { class ViveProEyeReadThread : public QThread {
public: public:
ViveProEyeReadThread() { ViveProEyeReadThread() {
@ -216,6 +200,7 @@ public:
QMutex eyeDataMutex; QMutex eyeDataMutex;
EyeDataBuffer eyeDataBuffer; EyeDataBuffer eyeDataBuffer;
}; };
#endif
static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) { static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) {
@ -328,7 +313,7 @@ bool areBothHandControllersActive(vr::IVRSystem*& system) {
isHandControllerActive(system, vr::TrackedControllerRole_RightHand); isHandControllerActive(system, vr::TrackedControllerRole_RightHand);
} }
#ifdef VIVE_PRO_EYE
void ViveControllerManager::enableGestureDetection() { void ViveControllerManager::enableGestureDetection() {
if (_viveCameraHandTracker) { if (_viveCameraHandTracker) {
return; return;
@ -373,6 +358,7 @@ void ViveControllerManager::disableGestureDetection() {
StopGestureDetection(); StopGestureDetection();
_viveCameraHandTracker = false; _viveCameraHandTracker = false;
} }
#endif
bool ViveControllerManager::activate() { bool ViveControllerManager::activate() {
InputPlugin::activate(); InputPlugin::activate();
@ -394,6 +380,7 @@ bool ViveControllerManager::activate() {
userInputMapper->registerDevice(_inputDevice); userInputMapper->registerDevice(_inputDevice);
_registeredWithInputMapper = true; _registeredWithInputMapper = true;
#ifdef VIVE_PRO_EYE
if (ViveSR::anipal::Eye::IsViveProEye()) { if (ViveSR::anipal::Eye::IsViveProEye()) {
qDebug() << "Vive Pro eye-tracking detected"; qDebug() << "Vive Pro eye-tracking detected";
@ -414,6 +401,7 @@ bool ViveControllerManager::activate() {
_viveProEyeReadThread->start(QThread::HighPriority); _viveProEyeReadThread->start(QThread::HighPriority);
} }
} }
#endif
return true; return true;
} }
@ -436,12 +424,14 @@ void ViveControllerManager::deactivate() {
userInputMapper->removeDevice(_inputDevice->_deviceID); userInputMapper->removeDevice(_inputDevice->_deviceID);
_registeredWithInputMapper = false; _registeredWithInputMapper = false;
#ifdef VIVE_PRO_EYE
if (_viveProEyeReadThread) { if (_viveProEyeReadThread) {
_viveProEyeReadThread->quit = true; _viveProEyeReadThread->quit = true;
_viveProEyeReadThread->wait(); _viveProEyeReadThread->wait();
_viveProEyeReadThread = nullptr; _viveProEyeReadThread = nullptr;
ViveSR::anipal::Release(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE); ViveSR::anipal::Release(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE);
} }
#endif
saveSettings(); saveSettings();
} }
@ -454,6 +444,7 @@ bool ViveControllerManager::isHeadControllerMounted() const {
return activityLevel == vr::k_EDeviceActivityLevel_UserInteraction; return activityLevel == vr::k_EDeviceActivityLevel_UserInteraction;
} }
#ifdef VIVE_PRO_EYE
void ViveControllerManager::invalidateEyeInputs() { void ViveControllerManager::invalidateEyeInputs() {
_inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false; _inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false;
_inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false; _inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false;
@ -461,7 +452,6 @@ void ViveControllerManager::invalidateEyeInputs() {
_inputDevice->_axisStateMap[controller::EYEBLINK_R].valid = false; _inputDevice->_axisStateMap[controller::EYEBLINK_R].valid = false;
} }
void ViveControllerManager::updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { void ViveControllerManager::updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
if (!isHeadControllerMounted()) { if (!isHeadControllerMounted()) {
invalidateEyeInputs(); invalidateEyeInputs();
@ -763,6 +753,7 @@ void ViveControllerManager::updateCameraHandTracker(float deltaTime,
} }
_lastHandTrackerFrameIndex = handTrackerFrameIndex; _lastHandTrackerFrameIndex = handTrackerFrameIndex;
} }
#endif
void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
@ -801,11 +792,14 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
_registeredWithInputMapper = true; _registeredWithInputMapper = true;
} }
#ifdef VIVE_PRO_EYE
if (_viveProEye) { if (_viveProEye) {
updateEyeTracker(deltaTime, inputCalibrationData); updateEyeTracker(deltaTime, inputCalibrationData);
} }
updateCameraHandTracker(deltaTime, inputCalibrationData); updateCameraHandTracker(deltaTime, inputCalibrationData);
#endif
} }
void ViveControllerManager::loadSettings() { void ViveControllerManager::loadSettings() {
@ -879,7 +873,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false);
// collect poses for all generic trackers // collect poses for all generic trackers
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
handleTrackedObject(i, inputCalibrationData); handleTrackedObject(i, inputCalibrationData);
handleHmd(i, inputCalibrationData); handleHmd(i, inputCalibrationData);
} }
@ -954,8 +948,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
bool overrideHead = headObject["override"].toBool(); bool overrideHead = headObject["override"].toBool();
if (overrideHead) { if (overrideHead) {
_headConfig = HeadConfig::Puck; _headConfig = HeadConfig::Puck;
_headPuckYOffset = headObject["Y"].toDouble() * CM_TO_M; _headPuckYOffset = (float)headObject["Y"].toDouble() * CM_TO_M;
_headPuckZOffset = headObject["Z"].toDouble() * CM_TO_M; _headPuckZOffset = (float)headObject["Z"].toDouble() * CM_TO_M;
} else { } else {
_headConfig = HeadConfig::HMD; _headConfig = HeadConfig::HMD;
} }
@ -964,8 +958,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
bool overrideHands = handsObject["override"].toBool(); bool overrideHands = handsObject["override"].toBool();
if (overrideHands) { if (overrideHands) {
_handConfig = HandConfig::Pucks; _handConfig = HandConfig::Pucks;
_handPuckYOffset = handsObject["Y"].toDouble() * CM_TO_M; _handPuckYOffset = (float)handsObject["Y"].toDouble() * CM_TO_M;
_handPuckZOffset = handsObject["Z"].toDouble() * CM_TO_M; _handPuckZOffset = (float)handsObject["Z"].toDouble() * CM_TO_M;
} else { } else {
_handConfig = HandConfig::HandController; _handConfig = HandConfig::HandController;
} }
@ -999,8 +993,8 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() {
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD); configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD);
configurationSettings["handController"] = (_handConfig == HandConfig::HandController); configurationSettings["handController"] = (_handConfig == HandConfig::HandController);
configurationSettings["puckCount"] = (int)_validTrackedObjects.size(); configurationSettings["puckCount"] = (int)_validTrackedObjects.size();
configurationSettings["armCircumference"] = (double)_armCircumference * M_TO_CM; configurationSettings["armCircumference"] = (double)(_armCircumference * M_TO_CM);
configurationSettings["shoulderWidth"] = (double)_shoulderWidth * M_TO_CM; configurationSettings["shoulderWidth"] = (double)(_shoulderWidth * M_TO_CM);
configurationSettings["outOfRangeDataStrategy"] = outOfRangeDataStrategyToString(_outOfRangeDataStrategy); configurationSettings["outOfRangeDataStrategy"] = outOfRangeDataStrategyToString(_outOfRangeDataStrategy);
return configurationSettings; return configurationSettings;
} }
@ -1217,8 +1211,6 @@ bool ViveControllerManager::InputDevice::configureHead(const glm::mat4& defaultT
bool ViveControllerManager::InputDevice::configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { bool ViveControllerManager::InputDevice::configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
int puckCount = (int)_validTrackedObjects.size(); int puckCount = (int)_validTrackedObjects.size();
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat);
if (_config == Config::None) { if (_config == Config::None) {
return true; return true;
} else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) { } else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) {
@ -1316,8 +1308,6 @@ controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(const c
} }
void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) {
uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex;
if (_system->IsTrackedDeviceConnected(deviceIndex) && if (_system->IsTrackedDeviceConnected(deviceIndex) &&
_system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_HMD && _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_HMD &&
_nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) { _nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) {
@ -1491,11 +1481,11 @@ void ViveControllerManager::InputDevice::printDeviceTrackingResultChange(uint32_
} }
bool ViveControllerManager::InputDevice::checkForCalibrationEvent() { bool ViveControllerManager::InputDevice::checkForCalibrationEvent() {
auto& endOfMap = _buttonPressedMap.end(); auto endOfMap = _buttonPressedMap.end();
auto& leftTrigger = _buttonPressedMap.find(controller::LT); auto leftTrigger = _buttonPressedMap.find(controller::LT);
auto& rightTrigger = _buttonPressedMap.find(controller::RT); auto rightTrigger = _buttonPressedMap.find(controller::RT);
auto& leftAppButton = _buttonPressedMap.find(LEFT_APP_MENU); auto leftAppButton = _buttonPressedMap.find(LEFT_APP_MENU);
auto& rightAppButton = _buttonPressedMap.find(RIGHT_APP_MENU); auto rightAppButton = _buttonPressedMap.find(RIGHT_APP_MENU);
return ((leftTrigger != endOfMap && leftAppButton != endOfMap) && (rightTrigger != endOfMap && rightAppButton != endOfMap)); return ((leftTrigger != endOfMap && leftAppButton != endOfMap) && (rightTrigger != endOfMap && rightAppButton != endOfMap));
} }
@ -1846,10 +1836,74 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu
* <tr><td><code>Hips</code></td><td>number</td><td>{@link Pose}</td><td>Hips pose.</td></tr> * <tr><td><code>Hips</code></td><td>number</td><td>{@link Pose}</td><td>Hips pose.</td></tr>
* <tr><td><code>Spine2</code></td><td>number</td><td>{@link Pose}</td><td>Spine2 pose.</td></tr> * <tr><td><code>Spine2</code></td><td>number</td><td>{@link Pose}</td><td>Spine2 pose.</td></tr>
* <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Head pose.</td></tr> * <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Head pose.</td></tr>
* <tr><td><code>LeftEye</code></td><td>number</td><td>{@link Pose}</td><td>Left eye pose.</td></tr>
* <tr><td><code>RightEye</code></td><td>number</td><td>{@link Pose}</td><td>Right eye pose.</td></tr>
* <tr><td><code>EyeBlink_L</code></td><td>number</td><td>number</td><td>Left eyelid blink.</td></tr>
* <tr><td><code>EyeBlink_R</code></td><td>number</td><td>number</td><td>Right eyelid blink.</td></tr>
* <tr><td><code>LeftArm</code></td><td>number</td><td>{@link Pose}</td><td>Left arm pose.</td></tr> * <tr><td><code>LeftArm</code></td><td>number</td><td>{@link Pose}</td><td>Left arm pose.</td></tr>
* <tr><td><code>RightArm</code></td><td>number</td><td>{@link Pose}</td><td>Right arm pose</td></tr> * <tr><td><code>RightArm</code></td><td>number</td><td>{@link Pose}</td><td>Right arm pose</td></tr>
* <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Left hand pose.</td></tr> * <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Left hand pose.</td></tr>
* <tr><td><code>LeftHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 4 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Left index 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Left index 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Left index 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Left index 4 finger joint pose.</td></tr>
* <tr><td><code>LeftHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 1 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 2 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 3 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 4 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 4 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 4 finger joint pose.</td></tr>
* <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>Right hand pose.</td></tr> * <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>Right hand pose.</td></tr>
* <tr><td><code>RightHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 4 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Right index 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Right index 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Right index 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Right index 4 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 4 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 1 finger joint pose.</td></tr>
* <tr><td><code>RightHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 2 finger joint pose.</td></tr>
* <tr><td><code>RightHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 3 finger joint pose.</td></tr>
* <tr><td><code>RightHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 4 finger joint pose.</td></tr>
* <tr><td><code>RightHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 4 finger joint pose.
* </td></tr>
* <tr><td colspan="4"><strong>Trackers</strong></td></tr> * <tr><td colspan="4"><strong>Trackers</strong></td></tr>
* <tr><td><code>TrackedObject00</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 0 pose.</td></tr> * <tr><td><code>TrackedObject00</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 0 pose.</td></tr>
* <tr><td><code>TrackedObject01</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 1 pose.</td></tr> * <tr><td><code>TrackedObject01</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 1 pose.</td></tr>

View file

@ -1,9 +1,9 @@
// //
// ViveControllerManager.h // ViveControllerManager.h
// input-plugins/src/input-plugins
// //
// Created by Sam Gondelman on 6/29/15. // Created by Sam Gondelman on 6/29/15.
// Copyright 2013 High Fidelity, Inc. // Copyright 2013 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -25,12 +25,18 @@
#include <plugins/InputPlugin.h> #include <plugins/InputPlugin.h>
#include "OpenVrHelpers.h" #include "OpenVrHelpers.h"
#ifdef Q_OS_WIN
#define VIVE_PRO_EYE
#endif
using PuckPosePair = std::pair<uint32_t, controller::Pose>; using PuckPosePair = std::pair<uint32_t, controller::Pose>;
namespace vr { namespace vr {
class IVRSystem; class IVRSystem;
} }
#ifdef VIVE_PRO_EYE
class ViveProEyeReadThread; class ViveProEyeReadThread;
class EyeDataBuffer { class EyeDataBuffer {
@ -45,7 +51,7 @@ public:
float leftEyeOpenness { 0.0f }; float leftEyeOpenness { 0.0f };
float rightEyeOpenness { 0.0f }; float rightEyeOpenness { 0.0f };
}; };
#endif
class ViveControllerManager : public InputPlugin { class ViveControllerManager : public InputPlugin {
@ -66,18 +72,22 @@ public:
bool isHeadController() const override { return true; } bool isHeadController() const override { return true; }
bool isHeadControllerMounted() const; bool isHeadControllerMounted() const;
#ifdef VIVE_PRO_EYE
void enableGestureDetection(); void enableGestureDetection();
void disableGestureDetection(); void disableGestureDetection();
#endif
bool activate() override; bool activate() override;
void deactivate() override; void deactivate() override;
QString getDeviceName() { return QString::fromStdString(_inputDevice->_headsetName); } QString getDeviceName() override { return QString::fromStdString(_inputDevice->_headsetName); }
void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
#ifdef VIVE_PRO_EYE
void invalidateEyeInputs(); void invalidateEyeInputs();
void updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData); void updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData);
void updateCameraHandTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData); void updateCameraHandTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData);
#endif
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
virtual void saveSettings() const override; virtual void saveSettings() const override;
@ -252,6 +262,7 @@ private:
vr::IVRSystem* _system { nullptr }; vr::IVRSystem* _system { nullptr };
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) }; std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
#ifdef VIVE_PRO_EYE
bool _viveProEye { false }; bool _viveProEye { false };
std::shared_ptr<ViveProEyeReadThread> _viveProEyeReadThread; std::shared_ptr<ViveProEyeReadThread> _viveProEyeReadThread;
EyeDataBuffer _prevEyeData; EyeDataBuffer _prevEyeData;
@ -268,6 +279,7 @@ private:
void trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4, void trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4,
controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2, controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2,
controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4); controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4);
#endif
static const char* NAME; static const char* NAME;
}; };