diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 15f68bf4b3..6d4b5b4225 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1678,6 +1678,8 @@ void Application::initMenu() { (_renderCoverageMapV2 = debugMenu->addAction("Render Coverage Map V2"))->setCheckable(true); _renderCoverageMapV2->setShortcut(Qt::SHIFT | Qt::CTRL | Qt::Key_P); + (_simulateLeapHand = debugMenu->addAction("Simulate Leap Hand"))->setCheckable(true); + (_testRaveGlove = debugMenu->addAction("Test RaveGlove"))->setCheckable(true); QMenu* settingsMenu = menuBar->addMenu("Settings"); (_settingsAutosave = settingsMenu->addAction("Autosave"))->setCheckable(true); @@ -1936,6 +1938,7 @@ void Application::update(float deltaTime) { } // Leap finger-sensing device + LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked()); LeapManager::nextFrame(); _myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); _myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); diff --git a/interface/src/Application.h b/interface/src/Application.h index cb69271b4b..7d56e4d673 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -262,6 +262,9 @@ private: QAction* _renderCoverageMapV2; QAction* _renderCoverageMap; + + QAction* _simulateLeapHand; // When there's no Leap, use this to pretend there is one and feed fake hand data + QAction* _testRaveGlove; // Test fancy sparkle-rave-glove mode BandwidthMeter _bandwidthMeter; BandwidthDialog* _bandwidthDialog; diff --git a/interface/src/LeapManager.cpp b/interface/src/LeapManager.cpp index b3d7737969..fe47e527fa 100755 --- a/interface/src/LeapManager.cpp +++ b/interface/src/LeapManager.cpp @@ -12,9 +12,14 @@ #include bool LeapManager::_libraryExists = false; +bool LeapManager::_doFakeFingers = false; Leap::Controller* LeapManager::_controller = NULL; HifiLeapListener* LeapManager::_listener = NULL; +namespace { +glm::vec3 fakeHandOffset(0.0f, 50.0f, 50.0f); +} // end anonymous namespace + class HifiLeapListener : public Leap::Listener { public: HifiLeapListener() {} @@ -76,47 +81,91 @@ void LeapManager::terminate() { } void LeapManager::nextFrame() { - if (_listener && _controller) + if (controllersExist()) { _listener->onFrame(*_controller); + } +} + +void LeapManager::enableFakeFingers(bool enable) { + _doFakeFingers = enable; +} + +bool LeapManager::controllersExist() { +#ifdef LEAP_STUBS + return false; +#else + return _listener && _controller && _controller->devices().count() > 0; +#endif } const std::vector& LeapManager::getFingerTips() { - if (_listener) { + if (controllersExist()) { return _listener->fingerTips; } else { - static std::vector empty; - return empty; + static std::vector stubData; + stubData.clear(); + if (_doFakeFingers) { + // Simulated data + float scale = 1.5f; + stubData.push_back(glm::vec3( -60.0f, 0.0f, -40.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( -20.0f, 0.0f, -60.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( 20.0f, 0.0f, -60.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( 60.0f, 0.0f, -40.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( -50.0f, 0.0f, 30.0f) * scale + fakeHandOffset); + } + return stubData; } } const std::vector& LeapManager::getFingerRoots() { - if (_listener) { + if (controllersExist()) { return _listener->fingerRoots; } else { - static std::vector empty; - return empty; + static std::vector stubData; + stubData.clear(); + if (_doFakeFingers) { + // Simulated data + float scale = 0.75f; + stubData.push_back(glm::vec3( -60.0f, 0.0f, -40.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( -20.0f, 0.0f, -60.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( 20.0f, 0.0f, -60.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( 60.0f, 0.0f, -40.0f) * scale + fakeHandOffset); + stubData.push_back(glm::vec3( -50.0f, 0.0f, 30.0f) * scale + fakeHandOffset); + } + return stubData; } } const std::vector& LeapManager::getHandPositions() { - if (_listener) { + if (controllersExist()) { return _listener->handPositions; } else { - static std::vector empty; - return empty; + static std::vector stubData; + stubData.clear(); + if (_doFakeFingers) { + // Simulated data + glm::vec3 handOffset(0.0f, 50.0f, 50.0f); + stubData.push_back(glm::vec3( 0.0f, 0.0f, 0.0f) + fakeHandOffset); + } + return stubData; } } const std::vector& LeapManager::getHandNormals() { - if (_listener) { + if (controllersExist()) { return _listener->handNormals; } else { - static std::vector empty; - return empty; + static std::vector stubData; + stubData.clear(); + if (_doFakeFingers) { + // Simulated data + stubData.push_back(glm::vec3(0.0f, 1.0f, 0.0f)); + } + return stubData; } } diff --git a/interface/src/LeapManager.h b/interface/src/LeapManager.h index f6ed925c6b..e6ac304677 100755 --- a/interface/src/LeapManager.h +++ b/interface/src/LeapManager.h @@ -20,7 +20,9 @@ namespace Leap { class LeapManager { public: - static void nextFrame(); // called once per frame to get new Leap data + static void nextFrame(); // called once per frame to get new Leap data + static bool controllersExist(); // Returns true if there's at least one active Leap plugged in + static void enableFakeFingers(bool enable); // put fake data in if there's no Leap plugged in static const std::vector& getFingerTips(); static const std::vector& getFingerRoots(); static const std::vector& getHandPositions(); @@ -31,6 +33,7 @@ public: private: static bool _libraryExists; // The library is present, so we won't crash if we call it. + static bool _doFakeFingers; static Leap::Controller* _controller; static HifiLeapListener* _listener; }; diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 244ff0dafd..1c25c85fbc 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -50,6 +50,9 @@ public: // getters const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;} + // position conversion + glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition); + private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); @@ -66,7 +69,6 @@ private: // private methods void renderHandSpheres(); void calculateGeometry(); - glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition); }; #endif diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index b0d71b4dee..50a4843153 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -20,6 +20,8 @@ class HandData { public: HandData(AvatarData* owningAvatar); + // These methods return the positions in Leap-relative space. + // To convert to world coordinates, use Hand::leapPositionToWorldPosition. const std::vector& getFingerTips() const { return _fingerTips; } const std::vector& getFingerRoots() const { return _fingerRoots; } const std::vector& getHandPositions() const { return _handPositions; }