Merge pull request #6343 from Atlante45/sixense

Sixense cleanup
This commit is contained in:
Brad Davis 2015-11-06 17:50:12 -08:00
commit e84f3af483
6 changed files with 216 additions and 155 deletions

View file

@ -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.

View file

@ -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")

View file

@ -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 <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(inputplugins)
#endif // hifi_InputPluginsLogging_h

View file

@ -9,55 +9,37 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <vector>
#include "SixenseManager.h"
#ifdef HAVE_SIXENSE
#include <sixense.h>
#endif
#include <QCoreApplication>
#include <QtCore/QSysInfo>
#include <QtGlobal>
#include <controllers/UserInputMapper.h>
#include <GLMHelpers.h>
#include <NumericalConstants.h>
#include <PerfStat.h>
#include <SettingHandle.h>
#include <plugins/PluginContainer.h>
#include <PathUtils.h>
#include <NumericalConstants.h>
#include <PerfStat.h>
#include <plugins/PluginContainer.h>
#include <SettingHandle.h>
#include <UserActivityLogger.h>
#include <controllers/UserInputMapper.h>
#include "SixenseManager.h"
#ifdef HAVE_SIXENSE
#include "sixense.h"
#ifdef __APPLE__
static QLibrary* _sixenseLibrary { nullptr };
#endif
#endif
// TODO: This should not be here
#include <QLoggingCategory>
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<controller::UserInputMapper>();
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<controller::UserInputMapper>();
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<sixenseControllerData*>(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<float>::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();
}

View file

@ -12,18 +12,6 @@
#ifndef hifi_SixenseManager_h
#define hifi_SixenseManager_h
#ifdef HAVE_SIXENSE
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "sixense.h"
#ifdef __APPLE__
#include <QCoreApplication>
#include <qlibrary.h>
#endif
#endif
#include <SimpleMovingAverage.h>
#include <controllers/InputDevice.h>
@ -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<typename T>
using SampleAverage = MovingAverage<T, MAX_NUM_AVERAGING_SAMPLES>;
using Samples = std::pair<SampleAverage<glm::vec3>, SampleAverage<glm::vec4>>;
using MovingAverageMap = std::map<int, Samples>;
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> _inputDevice { std::make_shared<InputDevice>() };
static const QString NAME;

View file

@ -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 <type_traits>
#include <sixense.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QLibrary>
#include "InputPluginsLogging.h"
#ifndef SIXENSE_LIB_FILENAME
#define SIXENSE_LIB_FILENAME QCoreApplication::applicationDirPath() + "/../Frameworks/libsixense_x64"
#endif
using Library = std::unique_ptr<QLibrary>;
static Library SIXENSE;
struct Callable {
template<typename... Args>
int operator() (Args&&... args){
return reinterpret_cast<int(*)(Args...)>(function)(std::forward<Args>(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