diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 2a2a45b67b..5b7bbc2aba 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -473,18 +473,7 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) { continue; } - int controllerButtons = 0; - - //Check for if we should toggle or drag the magnification window - if (controllerButtons & BUTTON_3) { - if (isPressed[index] == false) { - //We are now dragging the window - isPressed[index] = true; - //set the pressed time in us - pressedTime[index] = usecTimestampNow(); - stateWhenPressed[index] = _magActive[index]; - } - } else if (isPressed[index]) { + if (isPressed[index]) { isPressed[index] = false; //If the button was only pressed for < 250 ms //then disable it. diff --git a/libraries/input-plugins/src/input-plugins/InputPluginsLogging.cpp b/libraries/input-plugins/src/input-plugins/InputPluginsLogging.cpp new file mode 100644 index 0000000000..43a708e5c7 --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/InputPluginsLogging.cpp @@ -0,0 +1,14 @@ +// +// InputPluginsLogging.cpp +// libraries/input-plugins/src/input-plugins +// +// Created by Clement on 11/6/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "InputPluginsLogging.h" + +Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") diff --git a/libraries/input-plugins/src/input-plugins/InputPluginsLogging.h b/libraries/input-plugins/src/input-plugins/InputPluginsLogging.h new file mode 100644 index 0000000000..f82ffdbe2e --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/InputPluginsLogging.h @@ -0,0 +1,18 @@ +// +// InputPluginsLogging.h +// libraries/input-plugins/src/input-plugins +// +// Created by Clement on 11/6/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_InputPluginsLogging_h +#define hifi_InputPluginsLogging_h + +#include +Q_DECLARE_LOGGING_CATEGORY(inputplugins) + +#endif // hifi_InputPluginsLogging_h diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index 33b4332430..3085b377f0 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -9,55 +9,37 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "SixenseManager.h" + +#ifdef HAVE_SIXENSE +#include +#endif #include #include #include +#include #include #include -#include -#include -#include #include -#include +#include +#include +#include #include -#include -#include "SixenseManager.h" - - -#ifdef HAVE_SIXENSE - #include "sixense.h" - -#ifdef __APPLE__ -static QLibrary* _sixenseLibrary { nullptr }; -#endif - -#endif - -// TODO: This should not be here -#include -Q_DECLARE_LOGGING_CATEGORY(inputplugins) -Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") - -#ifdef HAVE_SIXENSE +#include "InputPluginsLogging.h" +static const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 +static const unsigned int BUTTON_1 = 1U << 5; +static const unsigned int BUTTON_2 = 1U << 6; +static const unsigned int BUTTON_3 = 1U << 3; +static const unsigned int BUTTON_4 = 1U << 4; +static const unsigned int BUTTON_FWD = 1U << 7; +static const unsigned int BUTTON_TRIGGER = 1U << 8; const glm::vec3 SixenseManager::DEFAULT_AVATAR_POSITION { -0.25f, -0.35f, -0.3f }; // in hydra frame const float SixenseManager::CONTROLLER_THRESHOLD { 0.35f }; -const float SixenseManager::DEFAULT_REACH_LENGTH { 1.5f }; - -#endif - -#ifdef __APPLE__ -typedef int (*SixenseBaseFunction)(); -typedef int (*SixenseTakeIntFunction)(int); -#ifdef HAVE_SIXENSE -typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData*); -#endif -#endif const QString SixenseManager::NAME = "Sixense"; const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra"; @@ -66,7 +48,6 @@ const QString MENU_PARENT = "Avatar"; const QString MENU_NAME = "Sixense"; const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; const QString TOGGLE_SMOOTH = "Smooth Sixense Movement"; -const float DEFAULT_REACH_LENGTH = 1.5f; bool SixenseManager::isSupported() const { #ifdef HAVE_SIXENSE @@ -84,41 +65,16 @@ bool SixenseManager::isSupported() const { void SixenseManager::activate() { InputPlugin::activate(); + #ifdef HAVE_SIXENSE - _container->addMenu(MENU_PATH); _container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH, - [this] (bool clicked) { this->setSixenseFilter(clicked); }, + [this] (bool clicked) { setSixenseFilter(clicked); }, true, true); auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); -#ifdef __APPLE__ - - if (!_sixenseLibrary) { - -#ifdef SIXENSE_LIB_FILENAME - _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME); -#else - const QString SIXENSE_LIBRARY_NAME = "libsixense_x64"; - QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/" - + SIXENSE_LIBRARY_NAME; - - _sixenseLibrary = new QLibrary(frameworkSixenseLibrary); -#endif - } - - if (_sixenseLibrary->load()){ - qCDebug(inputplugins) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName(); - } else { - qCDebug(inputplugins) << "Sixense library at" << _sixenseLibrary->fileName() << "failed to load." - << "Continuing without hydra support."; - return; - } - - SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); -#endif loadSettings(); sixenseInit(); #endif @@ -139,26 +95,14 @@ void SixenseManager::deactivate() { userInputMapper->removeDevice(_inputDevice->_deviceID); } -#ifdef __APPLE__ - SixenseBaseFunction sixenseExit = (SixenseBaseFunction)_sixenseLibrary->resolve("sixenseExit"); -#endif - sixenseExit(); - -#ifdef __APPLE__ - delete _sixenseLibrary; -#endif - + saveSettings(); #endif } void SixenseManager::setSixenseFilter(bool filter) { #ifdef HAVE_SIXENSE -#ifdef __APPLE__ - SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled"); -#endif - int newFilter = filter ? 1 : 0; - sixenseSetFilterEnabled(newFilter); + sixenseSetFilterEnabled(filter ? 1 : 0); #endif } @@ -180,13 +124,6 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) { #ifdef HAVE_SIXENSE _buttonPressedMap.clear(); -#ifdef __APPLE__ - SixenseBaseFunction sixenseGetNumActiveControllers = - (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); -#endif - - auto userInputMapper = DependencyManager::get(); - static const float MAX_DISCONNECTED_TIME = 2.0f; static bool disconnected { false }; static float disconnectedInterval { 0.0f }; @@ -213,24 +150,11 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) { // FIXME send this message once when we've positively identified hydra hardware //UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); -#ifdef __APPLE__ - SixenseBaseFunction sixenseGetMaxControllers = - (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); -#endif - int maxControllers = sixenseGetMaxControllers(); // we only support two controllers sixenseControllerData controllers[2]; -#ifdef __APPLE__ - SixenseTakeIntFunction sixenseIsControllerEnabled = - (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); - - SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = - (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); -#endif - int numActiveControllers = 0; for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { if (!sixenseIsControllerEnabled(i)) { @@ -293,9 +217,9 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) { // (4) assume that the orb is on a flat surface (yAxis is UP) // (5) compute the forward direction (zAxis = xAxis cross yAxis) -const float MINIMUM_ARM_REACH = 0.3f; // meters -const float MAXIMUM_NOISE_LEVEL = 0.05f; // meters -const quint64 LOCK_DURATION = USECS_PER_SECOND / 4; // time for lock to be acquired +static const float MINIMUM_ARM_REACH = 0.3f; // meters +static const float MAXIMUM_NOISE_LEVEL = 0.05f; // meters +static const quint64 LOCK_DURATION = USECS_PER_SECOND / 4; // time for lock to be acquired void SixenseManager::InputDevice::updateCalibration(void* controllersX) { auto controllers = reinterpret_cast(controllersX); @@ -315,14 +239,12 @@ void SixenseManager::InputDevice::updateCalibration(void* controllersX) { glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft); glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y)); xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis)); - _reachLength = glm::dot(xAxis, _reachRight - _reachLeft); _avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis))); const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f; _avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR; qCDebug(inputplugins, "succeess: sixense calibration"); } break; - default: _calibrationState = CALIBRATION_STATE_IDLE; qCDebug(inputplugins, "failed: sixense calibration"); @@ -479,8 +401,6 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos glm::vec3 velocity(0.0f); glm::quat angularVelocity; - - if (prevPose.isValid() && deltaTime > std::numeric_limits::epsilon()) { velocity = (position - prevPose.getTranslation()) / deltaTime; @@ -518,8 +438,6 @@ static const auto R2 = controller::A; static const auto R3 = controller::B; static const auto R4 = controller::Y; -using namespace controller; - controller::Input::NamedVector SixenseManager::InputDevice::getAvailableInputs() const { using namespace controller; static const Input::NamedVector availableInputs { @@ -563,7 +481,6 @@ void SixenseManager::saveSettings() const { { settings.setVec3Value(QString("avatarPosition"), _inputDevice->_avatarPosition); settings.setQuatValue(QString("avatarRotation"), _inputDevice->_avatarRotation); - settings.setValue(QString("reachLength"), QVariant(_inputDevice->_reachLength)); } settings.endGroup(); } @@ -575,7 +492,6 @@ void SixenseManager::loadSettings() { { settings.getVec3ValueIfValid(QString("avatarPosition"), _inputDevice->_avatarPosition); settings.getQuatValueIfValid(QString("avatarRotation"), _inputDevice->_avatarRotation); - settings.getFloatValueIfValid(QString("reachLength"), _inputDevice->_reachLength); } settings.endGroup(); } diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h index 062a27390c..bdfbd539cb 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.h +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h @@ -12,18 +12,6 @@ #ifndef hifi_SixenseManager_h #define hifi_SixenseManager_h -#ifdef HAVE_SIXENSE - #include - #include - #include "sixense.h" - -#ifdef __APPLE__ - #include - #include -#endif - -#endif - #include #include @@ -31,23 +19,10 @@ #include "InputPlugin.h" -class QLibrary; - -const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 -const unsigned int BUTTON_1 = 1U << 5; -const unsigned int BUTTON_2 = 1U << 6; -const unsigned int BUTTON_3 = 1U << 3; -const unsigned int BUTTON_4 = 1U << 4; -const unsigned int BUTTON_FWD = 1U << 7; -const unsigned int BUTTON_TRIGGER = 1U << 8; - -const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false; - // Handles interaction with the Sixense SDK (e.g., Razer Hydra). class SixenseManager : public InputPlugin { Q_OBJECT public: - // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } @@ -66,18 +41,18 @@ public: public slots: void setSixenseFilter(bool filter); -private: +private: static const int MAX_NUM_AVERAGING_SAMPLES = 50; // At ~100 updates per seconds this means averaging over ~.5s static const int CALIBRATION_STATE_IDLE = 0; static const int CALIBRATION_STATE_IN_PROGRESS = 1; static const int CALIBRATION_STATE_COMPLETE = 2; static const glm::vec3 DEFAULT_AVATAR_POSITION; static const float CONTROLLER_THRESHOLD; - static const float DEFAULT_REACH_LENGTH; - - - using Samples = std::pair< MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES>, MovingAverage< glm::vec4, MAX_NUM_AVERAGING_SAMPLES> >; - using MovingAverageMap = std::map< int, Samples >; + + template + using SampleAverage = MovingAverage; + using Samples = std::pair, SampleAverage>; + using MovingAverageMap = std::map; class InputDevice : public controller::InputDevice { public: @@ -103,7 +78,6 @@ private: glm::vec3 _avatarPosition { DEFAULT_AVATAR_POSITION }; // in hydra-frame glm::quat _avatarRotation; // in hydra-frame - float _reachLength { DEFAULT_REACH_LENGTH }; float _lastDistance; // these are measured values used to compute the calibration results quint64 _lockExpiry; @@ -113,9 +87,6 @@ private: glm::vec3 _reachRight; }; - - - bool _useSixenseFilter = true; std::shared_ptr _inputDevice { std::make_shared() }; static const QString NAME; diff --git a/libraries/input-plugins/src/input-plugins/SixenseSupportOSX.cpp b/libraries/input-plugins/src/input-plugins/SixenseSupportOSX.cpp new file mode 100644 index 0000000000..f6cec5d67f --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/SixenseSupportOSX.cpp @@ -0,0 +1,153 @@ +// +// SixenseSupportOSX.cpp +// libraries/input-plugins/src/input-plugins +// +// Created by Clement on 10/20/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Mock implementation of sixense.h to hide dynamic linking on OS X +#if defined(__APPLE__) && defined(HAVE_SIXENSE) +#include + +#include + +#include +#include + +#include "InputPluginsLogging.h" + +#ifndef SIXENSE_LIB_FILENAME +#define SIXENSE_LIB_FILENAME QCoreApplication::applicationDirPath() + "/../Frameworks/libsixense_x64" +#endif + +using Library = std::unique_ptr; +static Library SIXENSE; + +struct Callable { + template + int operator() (Args&&... args){ + return reinterpret_cast(function)(std::forward(args)...); + } + QFunctionPointer function; +}; + +Callable resolve(const Library& library, const char* name) { + Q_ASSERT_X(library && library->isLoaded(), __FUNCTION__, "Sixense library not loaded"); + auto function = library->resolve(name); + Q_ASSERT_X(function, __FUNCTION__, std::string("Could not resolve ").append(name).c_str()); + return Callable { function }; +} +#define FORWARD resolve(SIXENSE, __FUNCTION__) + + +void loadSixense() { + Q_ASSERT_X(!(SIXENSE && SIXENSE->isLoaded()), __FUNCTION__, "Sixense library already loaded"); + SIXENSE.reset(new QLibrary(SIXENSE_LIB_FILENAME)); + Q_CHECK_PTR(SIXENSE); + + if (SIXENSE->load()){ + qDebug() << "Loaded sixense library for hydra support -" << SIXENSE->fileName(); + } else { + qDebug() << "Sixense library at" << SIXENSE->fileName() << "failed to load:" << SIXENSE->errorString(); + qDebug() << "Continuing without hydra support."; + } +} +void unloadSixense() { + SIXENSE->unload(); +} + + +// sixense.h wrapper for OSX dynamic linking +int sixenseInit() { + loadSixense(); + return FORWARD(); +} +int sixenseExit() { + auto returnCode = FORWARD(); + unloadSixense(); + return returnCode; +} + +int sixenseGetMaxBases() { + return FORWARD(); +} +int sixenseSetActiveBase(int i) { + return FORWARD(i); +} +int sixenseIsBaseConnected(int i) { + return FORWARD(i); +} + +int sixenseGetMaxControllers() { + return FORWARD(); +} +int sixenseIsControllerEnabled(int which) { + return FORWARD(which); +} +int sixenseGetNumActiveControllers() { + return FORWARD(); +} + +int sixenseGetHistorySize() { + return FORWARD(); +} + +int sixenseGetData(int which, int index_back, sixenseControllerData* data) { + return FORWARD(which, index_back, data); +} +int sixenseGetAllData(int index_back, sixenseAllControllerData* data) { + return FORWARD(index_back, data); +} +int sixenseGetNewestData(int which, sixenseControllerData* data) { + return FORWARD(which, data); +} +int sixenseGetAllNewestData(sixenseAllControllerData* data) { + return FORWARD(data); +} + +int sixenseSetHemisphereTrackingMode(int which_controller, int state) { + return FORWARD(which_controller, state); +} +int sixenseGetHemisphereTrackingMode(int which_controller, int* state) { + return FORWARD(which_controller, state); +} +int sixenseAutoEnableHemisphereTracking(int which_controller) { + return FORWARD(which_controller); +} + +int sixenseSetHighPriorityBindingEnabled(int on_or_off) { + return FORWARD(on_or_off); +} +int sixenseGetHighPriorityBindingEnabled(int* on_or_off) { + return FORWARD(on_or_off); +} + +int sixenseTriggerVibration(int controller_id, int duration_100ms, int pattern_id) { + return FORWARD(controller_id, duration_100ms, pattern_id); +} + +int sixenseSetFilterEnabled(int on_or_off) { + return FORWARD(on_or_off); +} +int sixenseGetFilterEnabled(int* on_or_off) { + return FORWARD(on_or_off); +} + +int sixenseSetFilterParams(float near_range, float near_val, float far_range, float far_val) { + return FORWARD(near_range, near_val, far_range, far_val); +} +int sixenseGetFilterParams(float* near_range, float* near_val, float* far_range, float* far_val) { + return FORWARD(near_range, near_val, far_range, far_val); +} + +int sixenseSetBaseColor(unsigned char red, unsigned char green, unsigned char blue) { + return FORWARD(red, green, blue); +} +int sixenseGetBaseColor(unsigned char* red, unsigned char* green, unsigned char* blue) { + return FORWARD(red, green, blue); +} +#endif