Merge pull request #3505 from birarda/hydra-crash

dynamically load sixense lib on OS X to make avoiding hid_init crash easier
This commit is contained in:
Philip Rosedale 2014-09-29 16:09:12 -07:00
commit 3b0214358b
8 changed files with 280 additions and 162 deletions

View file

@ -137,8 +137,9 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY}) set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY})
endif () endif ()
target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES}) if (NOT APPLE OR NOT ${${EXTERNAL}_UPPERCASE} MATCHES "SIXENSE")
target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
endif ()
endif () endif ()
endforeach() endforeach()

View file

@ -182,7 +182,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_lastNackTime(usecTimestampNow()), _lastNackTime(usecTimestampNow()),
_lastSendDownstreamAudioStats(usecTimestampNow()) _lastSendDownstreamAudioStats(usecTimestampNow())
{ {
// read the ApplicationInfo.ini file for Name/Version/Domain information // read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
@ -378,12 +377,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_particleEditSender.setPacketsPerSecond(3000); // super high!! _particleEditSender.setPacketsPerSecond(3000); // super high!!
_entityEditSender.setPacketsPerSecond(3000); // super high!! _entityEditSender.setPacketsPerSecond(3000); // super high!!
// Set the sixense filtering
_sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
// Set hand controller velocity filtering
_sixenseManager.setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter));
checkVersion(); checkVersion();
_overlays.init(_glWidget); // do this before scripts load _overlays.init(_glWidget); // do this before scripts load
@ -1481,7 +1474,7 @@ void Application::setRenderVoxels(bool voxelRender) {
} }
void Application::setLowVelocityFilter(bool lowVelocityFilter) { void Application::setLowVelocityFilter(bool lowVelocityFilter) {
getSixenseManager()->setLowVelocityFilter(lowVelocityFilter); SixenseManager::getInstance().setLowVelocityFilter(lowVelocityFilter);
} }
void Application::doKillLocalVoxels() { void Application::doKillLocalVoxels() {
@ -1802,6 +1795,17 @@ void Application::init() {
if (urlIndex != -1) { if (urlIndex != -1) {
AddressManager::getInstance().handleLookupString(arguments().value(urlIndex + 1)); AddressManager::getInstance().handleLookupString(arguments().value(urlIndex + 1));
} }
#ifdef __APPLE__
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseEnabled)) {
// on OS X we only setup sixense if the user wants it on - this allows running without the hid_init crash
// if hydra support is temporarily not required
Menu::getInstance()->toggleSixense(true);
}
#else
// setup sixense
Menu::getInstance()->toggleSixense(true);
#endif
// initialize our face trackers after loading the menu settings // initialize our face trackers after loading the menu settings
_faceshift.init(); _faceshift.init();
@ -2178,7 +2182,7 @@ void Application::update(float deltaTime) {
DeviceTracker::updateAll(); DeviceTracker::updateAll();
updateFaceshift(); updateFaceshift();
updateVisage(); updateVisage();
_sixenseManager.update(deltaTime); SixenseManager::getInstance().update(deltaTime);
JoystickScriptingInterface::getInstance().update(); JoystickScriptingInterface::getInstance().update();
_prioVR.update(deltaTime); _prioVR.update(deltaTime);

View file

@ -219,7 +219,6 @@ public:
DdeFaceTracker* getDDE() { return &_dde; } DdeFaceTracker* getDDE() { return &_dde; }
CaraFaceTracker* getCara() { return &_cara; } CaraFaceTracker* getCara() { return &_cara; }
FaceTracker* getActiveFaceTracker(); FaceTracker* getActiveFaceTracker();
SixenseManager* getSixenseManager() { return &_sixenseManager; }
PrioVR* getPrioVR() { return &_prioVR; } PrioVR* getPrioVR() { return &_prioVR; }
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; } BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
QUndoStack* getUndoStack() { return &_undoStack; } QUndoStack* getUndoStack() { return &_undoStack; }
@ -510,7 +509,6 @@ private:
CaraFaceTracker _cara; CaraFaceTracker _cara;
DdeFaceTracker _dde; DdeFaceTracker _dde;
SixenseManager _sixenseManager;
PrioVR _prioVR; PrioVR _prioVR;
Camera _myCamera; // My view onto the world Camera _myCamera; // My view onto the world

View file

@ -431,11 +431,18 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
QMenu* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense"); QMenu* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense");
#ifdef __APPLE__
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
MenuOption::SixenseEnabled,
0, true,
this,
SLOT(toggleSixense(bool)));
#endif
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
MenuOption::FilterSixense, MenuOption::FilterSixense,
0, 0,
true, true,
appInstance->getSixenseManager(), &SixenseManager::getInstance(),
SLOT(setFilter(bool))); SLOT(setFilter(bool)));
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
MenuOption::LowVelocityFilter, MenuOption::LowVelocityFilter,
@ -1134,6 +1141,18 @@ void Menu::editAnimations() {
} }
} }
void Menu::toggleSixense(bool shouldEnable) {
SixenseManager& sixenseManager = SixenseManager::getInstance();
if (shouldEnable && !sixenseManager.isInitialized()) {
sixenseManager.initialize();
sixenseManager.setFilter(isOptionChecked(MenuOption::FilterSixense));
sixenseManager.setLowVelocityFilter(isOptionChecked(MenuOption::LowVelocityFilter));
}
sixenseManager.setIsEnabled(shouldEnable);
}
void Menu::changePrivateKey() { void Menu::changePrivateKey() {
// setup the dialog // setup the dialog
QInputDialog privateKeyDialog(Application::getInstance()->getWindow()); QInputDialog privateKeyDialog(Application::getInstance()->getWindow());

View file

@ -186,6 +186,7 @@ public slots:
void pasteToVoxel(); void pasteToVoxel();
void toggleLoginMenuItem(); void toggleLoginMenuItem();
void toggleSixense(bool shouldEnable);
QMenu* addMenu(const QString& menuName); QMenu* addMenu(const QString& menuName);
void removeMenu(const QString& menuName); void removeMenu(const QString& menuName);
@ -448,6 +449,7 @@ namespace MenuOption {
const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
const QString ShowIKConstraints = "Show IK Constraints"; const QString ShowIKConstraints = "Show IK Constraints";
const QString SimpleShadows = "Simple"; const QString SimpleShadows = "Simple";
const QString SixenseEnabled = "Enable Hydra Support";
const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString SixenseMouseInput = "Enable Sixense Mouse Input";
const QString SixenseLasers = "Enable Sixense UI Lasers"; const QString SixenseLasers = "Enable Sixense UI Lasers";
const QString StandOnNearbyFloors = "Stand on nearby floors"; const QString StandOnNearbyFloors = "Stand on nearby floors";

View file

@ -30,23 +30,28 @@ const int CALIBRATION_STATE_COMPLETE = 4;
const float NECK_X = 0.25f; // meters const float NECK_X = 0.25f; // meters
const float NECK_Y = 0.3f; // meters const float NECK_Y = 0.3f; // meters
const float NECK_Z = 0.3f; // meters const float NECK_Z = 0.3f; // meters
#ifdef __APPLE__
typedef int (*SixenseBaseFunction)();
typedef int (*SixenseTakeIntFunction)(int);
typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData*);
#endif #endif
SixenseManager::SixenseManager() {
#ifdef HAVE_SIXENSE
_lastMovement = 0;
_amountMoved = glm::vec3(0.0f);
_lowVelocityFilter = false;
_calibrationState = CALIBRATION_STATE_IDLE;
// By default we assume the _neckBase (in orb frame) is as high above the orb
// as the "torso" is below it.
_neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
sixenseInit();
#endif #endif
_hydrasConnected = false;
SixenseManager& SixenseManager::getInstance() {
static SixenseManager sharedInstance;
return sharedInstance;
}
SixenseManager::SixenseManager() :
#ifdef __APPLE__
_sixenseLibrary(NULL),
#endif
_isInitialized(false),
_isEnabled(true),
_hydrasConnected(false)
{
_triggerPressed[0] = false; _triggerPressed[0] = false;
_bumperPressed[0] = false; _bumperPressed[0] = false;
_oldX[0] = -1; _oldX[0] = -1;
@ -58,155 +63,227 @@ SixenseManager::SixenseManager() {
} }
SixenseManager::~SixenseManager() { SixenseManager::~SixenseManager() {
#ifdef HAVE_SIXENSE_
if (_isInitialized) {
#ifdef __APPLE__
SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit");
#endif
sixenseExit();
}
#ifdef __APPLE__
delete _sixenseLibrary;
#endif
#endif
}
void SixenseManager::initialize() {
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
sixenseExit();
if (!_isInitialized) {
_lastMovement = 0;
_amountMoved = glm::vec3(0.0f);
_lowVelocityFilter = false;
_calibrationState = CALIBRATION_STATE_IDLE;
// By default we assume the _neckBase (in orb frame) is as high above the orb
// as the "torso" is below it.
_neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
#ifdef __APPLE__
if (!_sixenseLibrary) {
const QString SIXENSE_LIBRARY_NAME = "libsixense_x64.dylib";
_sixenseLibrary = new QLibrary(SIXENSE_LIBRARY_NAME);
}
SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
#endif
sixenseInit();
_isInitialized = true;
}
#endif #endif
} }
void SixenseManager::setFilter(bool filter) { void SixenseManager::setFilter(bool filter) {
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
if (filter) {
sixenseSetFilterEnabled(1); if (_isInitialized) {
} else { #ifdef __APPLE__
sixenseSetFilterEnabled(0); SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
#endif
if (filter) {
sixenseSetFilterEnabled(1);
} else {
sixenseSetFilterEnabled(0);
}
} }
#endif #endif
} }
void SixenseManager::update(float deltaTime) { void SixenseManager::update(float deltaTime) {
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
// if the controllers haven't been moved in a while, disable if (_isInitialized && _isEnabled) {
const unsigned int MOVEMENT_DISABLE_SECONDS = 3; // if the controllers haven't been moved in a while, disable
if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * USECS_PER_SECOND)) { const unsigned int MOVEMENT_DISABLE_SECONDS = 3;
Hand* hand = Application::getInstance()->getAvatar()->getHand(); if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * USECS_PER_SECOND)) {
for (std::vector<PalmData>::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { Hand* hand = Application::getInstance()->getAvatar()->getHand();
it->setActive(false); for (std::vector<PalmData>::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) {
} it->setActive(false);
_lastMovement = usecTimestampNow();
}
if (sixenseGetNumActiveControllers() == 0) {
_hydrasConnected = false;
return;
}
PerformanceTimer perfTimer("sixense");
if (!_hydrasConnected) {
_hydrasConnected = true;
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
}
MyAvatar* avatar = Application::getInstance()->getAvatar();
Hand* hand = avatar->getHand();
int maxControllers = sixenseGetMaxControllers();
// we only support two controllers
sixenseControllerData controllers[2];
int numActiveControllers = 0;
for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) {
if (!sixenseIsControllerEnabled(i)) {
continue;
}
sixenseControllerData* data = controllers + numActiveControllers;
++numActiveControllers;
sixenseGetNewestData(i, data);
// Set palm position and normal based on Hydra position/orientation
// Either find a palm matching the sixense controller, or make a new one
PalmData* palm;
bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == data->controller_index) {
palm = &(hand->getPalms()[j]);
foundHand = true;
} }
}
if (!foundHand) {
PalmData newPalm(hand);
hand->getPalms().push_back(newPalm);
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
palm->setSixenseID(data->controller_index);
qDebug("Found new Sixense controller, ID %i", data->controller_index);
}
palm->setActive(true);
// Read controller buttons and joystick into the hand
palm->setControllerButtons(data->buttons);
palm->setTrigger(data->trigger);
palm->setJoystick(data->joystick_x, data->joystick_y);
// Emulate the mouse so we can use scripts
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
emulateMouse(palm, numActiveControllers - 1);
}
// NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.
glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);
position *= METERS_PER_MILLIMETER;
// Transform the measured position into body frame.
glm::vec3 neck = _neckBase;
// Zeroing y component of the "neck" effectively raises the measured position a little bit.
neck.y = 0.f;
position = _orbRotation * (position - neck);
// Rotation of Palm
glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _orbRotation * rotation;
// Compute current velocity from position change
glm::vec3 rawVelocity;
if (deltaTime > 0.f) {
rawVelocity = (position - palm->getRawPosition()) / deltaTime;
} else {
rawVelocity = glm::vec3(0.0f);
}
palm->setRawVelocity(rawVelocity); // meters/sec
// adjustment for hydra controllers fit into hands
float sign = (i == 0) ? -1.0f : 1.0f;
rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f));
if (_lowVelocityFilter) {
// Use a velocity sensitive filter to damp small motions and preserve large ones with
// no latency.
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
palm->setRawPosition(position);
palm->setRawRotation(rotation);
} else {
palm->setRawPosition(position);
palm->setRawRotation(rotation);
}
// use the velocity to determine whether there's any movement (if the hand isn't new)
const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f;
_amountMoved += rawVelocity * deltaTime;
if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) {
_lastMovement = usecTimestampNow(); _lastMovement = usecTimestampNow();
_amountMoved = glm::vec3(0.0f);
} }
// Store the one fingertip in the palm structure so we can track velocity #ifdef __APPLE__
const float FINGER_LENGTH = 0.3f; // meters SixenseBaseFunction sixenseGetNumActiveControllers =
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; #endif
glm::vec3 oldTipPosition = palm->getTipRawPosition();
if (deltaTime > 0.f) { if (sixenseGetNumActiveControllers() == 0) {
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime); _hydrasConnected = false;
} else { return;
palm->setTipVelocity(glm::vec3(0.f)); }
PerformanceTimer perfTimer("sixense");
if (!_hydrasConnected) {
_hydrasConnected = true;
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
}
MyAvatar* avatar = Application::getInstance()->getAvatar();
Hand* hand = avatar->getHand();
#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)) {
continue;
}
sixenseControllerData* data = controllers + numActiveControllers;
++numActiveControllers;
sixenseGetNewestData(i, data);
// Set palm position and normal based on Hydra position/orientation
// Either find a palm matching the sixense controller, or make a new one
PalmData* palm;
bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == data->controller_index) {
palm = &(hand->getPalms()[j]);
foundHand = true;
}
}
if (!foundHand) {
PalmData newPalm(hand);
hand->getPalms().push_back(newPalm);
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
palm->setSixenseID(data->controller_index);
qDebug("Found new Sixense controller, ID %i", data->controller_index);
}
palm->setActive(true);
// Read controller buttons and joystick into the hand
palm->setControllerButtons(data->buttons);
palm->setTrigger(data->trigger);
palm->setJoystick(data->joystick_x, data->joystick_y);
// Emulate the mouse so we can use scripts
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
emulateMouse(palm, numActiveControllers - 1);
}
// NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.
glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);
position *= METERS_PER_MILLIMETER;
// Transform the measured position into body frame.
glm::vec3 neck = _neckBase;
// Zeroing y component of the "neck" effectively raises the measured position a little bit.
neck.y = 0.f;
position = _orbRotation * (position - neck);
// Rotation of Palm
glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _orbRotation * rotation;
// Compute current velocity from position change
glm::vec3 rawVelocity;
if (deltaTime > 0.f) {
rawVelocity = (position - palm->getRawPosition()) / deltaTime;
} else {
rawVelocity = glm::vec3(0.0f);
}
palm->setRawVelocity(rawVelocity); // meters/sec
// adjustment for hydra controllers fit into hands
float sign = (i == 0) ? -1.0f : 1.0f;
rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f));
if (_lowVelocityFilter) {
// Use a velocity sensitive filter to damp small motions and preserve large ones with
// no latency.
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
palm->setRawPosition(position);
palm->setRawRotation(rotation);
} else {
palm->setRawPosition(position);
palm->setRawRotation(rotation);
}
// use the velocity to determine whether there's any movement (if the hand isn't new)
const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f;
_amountMoved += rawVelocity * deltaTime;
if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) {
_lastMovement = usecTimestampNow();
_amountMoved = glm::vec3(0.0f);
}
// Store the one fingertip in the palm structure so we can track velocity
const float FINGER_LENGTH = 0.3f; // meters
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
glm::vec3 oldTipPosition = palm->getTipRawPosition();
if (deltaTime > 0.f) {
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
} else {
palm->setTipVelocity(glm::vec3(0.f));
}
palm->setTipPosition(newTipPosition);
}
if (numActiveControllers == 2) {
updateCalibration(controllers);
} }
palm->setTipPosition(newTipPosition);
}
if (numActiveControllers == 2) {
updateCalibration(controllers);
} }
#endif // HAVE_SIXENSE #endif // HAVE_SIXENSE
} }

View file

@ -18,6 +18,11 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include "sixense.h" #include "sixense.h"
#ifdef __APPLE__
#include <qlibrary.h>
#endif
#endif #endif
const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2
@ -38,9 +43,12 @@ const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
class SixenseManager : public QObject { class SixenseManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static SixenseManager& getInstance();
SixenseManager(); void initialize();
~SixenseManager(); bool isInitialized() const { return _isInitialized; }
void setIsEnabled(bool isEnabled) { _isEnabled = isEnabled; }
void update(float deltaTime); void update(float deltaTime);
float getCursorPixelRangeMult() const; float getCursorPixelRangeMult() const;
@ -51,6 +59,9 @@ public slots:
void setLowVelocityFilter(bool lowVelocityFilter) { _lowVelocityFilter = lowVelocityFilter; }; void setLowVelocityFilter(bool lowVelocityFilter) { _lowVelocityFilter = lowVelocityFilter; };
private: private:
SixenseManager();
~SixenseManager();
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
void updateCalibration(const sixenseControllerData* controllers); void updateCalibration(const sixenseControllerData* controllers);
void emulateMouse(PalmData* palm, int index); void emulateMouse(PalmData* palm, int index);
@ -72,7 +83,13 @@ private:
glm::vec3 _reachForward; glm::vec3 _reachForward;
float _lastDistance; float _lastDistance;
#ifdef __APPLE__
QLibrary* _sixenseLibrary;
#endif #endif
#endif
bool _isInitialized;
bool _isEnabled;
bool _hydrasConnected; bool _hydrasConnected;
quint64 _lastMovement; quint64 _lastMovement;
glm::vec3 _amountMoved; glm::vec3 _amountMoved;

View file

@ -671,7 +671,7 @@ void ApplicationOverlay::renderControllerPointers() {
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
// Get the pixel range over which the xAngle and yAngle are scaled // Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMult(); float cursorRange = glWidget->width() * SixenseManager::getInstance().getCursorPixelRangeMult();
mouseX = (glWidget->width() / 2.0f + cursorRange * xAngle); mouseX = (glWidget->width() / 2.0f + cursorRange * xAngle);
mouseY = (glWidget->height() / 2.0f + cursorRange * yAngle); mouseY = (glWidget->height() / 2.0f + cursorRange * yAngle);