mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Remove old Leap Motion code
This commit is contained in:
parent
9c928f16b2
commit
a8501a7ac6
12 changed files with 0 additions and 1464 deletions
|
@ -143,7 +143,6 @@
|
|||
#include "avatar/MyHead.h"
|
||||
#include "CrashHandler.h"
|
||||
#include "devices/DdeFaceTracker.h"
|
||||
#include "devices/Leapmotion.h"
|
||||
#include "DiscoverabilityManager.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "InterfaceDynamicFactory.h"
|
||||
|
@ -1809,8 +1808,6 @@ Application::~Application() {
|
|||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
|
||||
Leapmotion::destroy();
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
steamClient->shutdown();
|
||||
}
|
||||
|
@ -3977,8 +3974,6 @@ void Application::init() {
|
|||
|
||||
qCDebug(interfaceapp) << "Loaded settings";
|
||||
|
||||
Leapmotion::init();
|
||||
|
||||
// fire off an immediate domain-server check in now that settings are loaded
|
||||
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
|
||||
|
||||
|
@ -4451,7 +4446,6 @@ void Application::update(float deltaTime) {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("devices");
|
||||
DeviceTracker::updateAll();
|
||||
|
||||
FaceTracker* tracker = getSelectedFaceTracker();
|
||||
if (tracker && Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking) != tracker->isMuted()) {
|
||||
|
@ -4519,8 +4513,6 @@ void Application::update(float deltaTime) {
|
|||
keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface->updateInputControllers();
|
||||
|
||||
// Transfer the user inputs to the driveKeys
|
||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||
myAvatar->clearDriveKeys();
|
||||
|
|
|
@ -547,9 +547,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false,
|
||||
avatar.get(), SLOT(setEnableDebugDrawHandControllers(bool)));
|
||||
|
||||
MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
|
||||
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
|
||||
|
||||
// Developer > Entities >>>
|
||||
MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities");
|
||||
|
||||
|
|
|
@ -115,7 +115,6 @@ namespace MenuOption {
|
|||
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
||||
const QString IndependentMode = "Independent Mode";
|
||||
const QString ActionMotorControl = "Enable Default Motor Control";
|
||||
const QString LeapMotionOnHMD = "Leap Motion on HMD";
|
||||
const QString LoadScript = "Open and Run Script File...";
|
||||
const QString LoadScriptURL = "Open and Run Script from URL...";
|
||||
const QString LodTools = "LOD Tools";
|
||||
|
|
|
@ -1,246 +0,0 @@
|
|||
//
|
||||
// Created by Sam Cake on 6/2/2014
|
||||
// Copyright 2014 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 "Leapmotion.h"
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "Menu.h"
|
||||
|
||||
const int PALMROOT_NUM_JOINTS = 3;
|
||||
const int FINGER_NUM_JOINTS = 4;
|
||||
const int HAND_NUM_JOINTS = FINGER_NUM_JOINTS*5+PALMROOT_NUM_JOINTS;
|
||||
|
||||
const DeviceTracker::Name Leapmotion::NAME = "Leapmotion";
|
||||
|
||||
// find the index of a joint from
|
||||
// the side: true = right
|
||||
// the finger & the bone:
|
||||
// finger in [0..4] : bone in [0..3] a finger phalange
|
||||
// [-1] up the hand branch : bone in [0..2] <=> [ hand, forearm, arm]
|
||||
MotionTracker::Index evalJointIndex(bool isRightSide, int finger, int bone) {
|
||||
|
||||
MotionTracker::Index offset = 1 // start after root
|
||||
+ (int(isRightSide) * HAND_NUM_JOINTS) // then offset for side
|
||||
+ PALMROOT_NUM_JOINTS; // then add the arm/forearm/hand chain
|
||||
if (finger >= 0) {
|
||||
// from there go down in the correct finger and bone
|
||||
return offset + (finger * FINGER_NUM_JOINTS) + bone;
|
||||
} else {
|
||||
// or go back up for the correct root bone
|
||||
return offset - 1 - bone;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void Leapmotion::init() {
|
||||
DeviceTracker* device = DeviceTracker::getDevice(NAME);
|
||||
|
||||
if (!device) {
|
||||
// create a new Leapmotion and register it
|
||||
Leapmotion* leap = new Leapmotion();
|
||||
DeviceTracker::registerDevice(NAME, leap);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void Leapmotion::destroy() {
|
||||
DeviceTracker::destroyDevice(NAME);
|
||||
}
|
||||
|
||||
// static
|
||||
Leapmotion* Leapmotion::getInstance() {
|
||||
DeviceTracker* device = DeviceTracker::getDevice(NAME);
|
||||
if (!device) {
|
||||
// create a new Leapmotion and register it
|
||||
device = new Leapmotion();
|
||||
DeviceTracker::registerDevice(NAME, device);
|
||||
}
|
||||
return dynamic_cast< Leapmotion* > (device);
|
||||
}
|
||||
|
||||
Leapmotion::Leapmotion() :
|
||||
MotionTracker(),
|
||||
_active(false)
|
||||
{
|
||||
// Create the Leapmotion joint hierarchy
|
||||
std::vector< Semantic > sides;
|
||||
sides.push_back("joint_L_");
|
||||
sides.push_back("joint_R_");
|
||||
|
||||
std::vector< Semantic > rootBones;
|
||||
rootBones.push_back("elbow");
|
||||
rootBones.push_back("wrist");
|
||||
rootBones.push_back("hand");
|
||||
|
||||
std::vector< Semantic > fingers;
|
||||
fingers.push_back("thumb");
|
||||
fingers.push_back("index");
|
||||
fingers.push_back("middle");
|
||||
fingers.push_back("ring");
|
||||
fingers.push_back("pinky");
|
||||
|
||||
std::vector< Semantic > fingerBones;
|
||||
fingerBones.push_back("1");
|
||||
fingerBones.push_back("2");
|
||||
fingerBones.push_back("3");
|
||||
fingerBones.push_back("4");
|
||||
|
||||
std::vector< Index > palms;
|
||||
for (unsigned int s = 0; s < sides.size(); s++) {
|
||||
Index rootJoint = 0;
|
||||
for (unsigned int rb = 0; rb < rootBones.size(); rb++) {
|
||||
rootJoint = addJoint(sides[s] + rootBones[rb], rootJoint);
|
||||
}
|
||||
|
||||
// capture the hand index for debug
|
||||
palms.push_back(rootJoint);
|
||||
|
||||
for (unsigned int f = 0; f < fingers.size(); f++) {
|
||||
for (unsigned int b = 0; b < fingerBones.size(); b++) {
|
||||
rootJoint = addJoint(sides[s] + fingers[f] + fingerBones[b], rootJoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LEAPMOTION
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::LeapMotionOnHMD)) {
|
||||
_controller.setPolicyFlags(Leap::Controller::POLICY_OPTIMIZE_HMD);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Leapmotion::~Leapmotion() {
|
||||
}
|
||||
|
||||
#ifdef HAVE_LEAPMOTION
|
||||
glm::quat quatFromLeapBase(float sideSign, const Leap::Matrix& basis) {
|
||||
|
||||
// fix the handness to right and always...
|
||||
glm::vec3 xAxis = glm::normalize(sideSign * glm::vec3(basis.xBasis.x, basis.xBasis.y, basis.xBasis.z));
|
||||
glm::vec3 yAxis = glm::normalize(glm::vec3(basis.yBasis.x, basis.yBasis.y, basis.yBasis.z));
|
||||
glm::vec3 zAxis = glm::normalize(glm::vec3(basis.zBasis.x, basis.zBasis.y, basis.zBasis.z));
|
||||
|
||||
xAxis = glm::normalize(glm::cross(yAxis, zAxis));
|
||||
|
||||
glm::quat orientation = (glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
|
||||
return orientation;
|
||||
}
|
||||
|
||||
glm::vec3 vec3FromLeapVector(const Leap::Vector& vec) {
|
||||
return glm::vec3(vec.x * METERS_PER_MILLIMETER, vec.y * METERS_PER_MILLIMETER, vec.z * METERS_PER_MILLIMETER);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Leapmotion::update() {
|
||||
#ifdef HAVE_LEAPMOTION
|
||||
bool wasActive = _active;
|
||||
_active = _controller.isConnected();
|
||||
|
||||
if (_active || wasActive) {
|
||||
// Go through all the joints and increment their counter since last update.
|
||||
// Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive.
|
||||
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
|
||||
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
|
||||
(*jointIt).tickNewFrame();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the most recent frame and report some basic information
|
||||
const Leap::Frame frame = _controller.frame();
|
||||
static int64_t lastFrameID = -1;
|
||||
int64_t newFrameID = frame.id();
|
||||
|
||||
// If too soon then exit
|
||||
if (lastFrameID >= newFrameID)
|
||||
return;
|
||||
|
||||
glm::vec3 delta(0.0f);
|
||||
glm::quat handOri;
|
||||
if (!frame.hands().isEmpty()) {
|
||||
for (int handNum = 0; handNum < frame.hands().count(); handNum++) {
|
||||
|
||||
const Leap::Hand hand = frame.hands()[handNum];
|
||||
int side = (hand.isRight() ? 1 : -1);
|
||||
|
||||
JointTracker* parentJointTracker = _jointsArray.data();
|
||||
|
||||
|
||||
int rootBranchIndex = -1;
|
||||
|
||||
Leap::Arm arm = hand.arm();
|
||||
if (arm.isValid()) {
|
||||
glm::quat ori = quatFromLeapBase(float(side), arm.basis());
|
||||
glm::vec3 pos = vec3FromLeapVector(arm.elbowPosition());
|
||||
JointTracker* elbow = editJointTracker(evalJointIndex((side > 0), rootBranchIndex, 2)); // 2 is the index of the elbow joint
|
||||
elbow->editAbsFrame().setTranslation(pos);
|
||||
elbow->editAbsFrame().setRotation(ori);
|
||||
elbow->updateLocFromAbsTransform(parentJointTracker);
|
||||
elbow->activeFrame();
|
||||
parentJointTracker = elbow;
|
||||
|
||||
pos = vec3FromLeapVector(arm.wristPosition());
|
||||
JointTracker* wrist = editJointTracker(evalJointIndex((side > 0), rootBranchIndex, 1)); // 1 is the index of the wrist joint
|
||||
wrist->editAbsFrame().setTranslation(pos);
|
||||
wrist->editAbsFrame().setRotation(ori);
|
||||
wrist->updateLocFromAbsTransform(parentJointTracker);
|
||||
wrist->activeFrame();
|
||||
parentJointTracker = wrist;
|
||||
}
|
||||
|
||||
JointTracker* palmJoint = NULL;
|
||||
{
|
||||
glm::vec3 pos = vec3FromLeapVector(hand.palmPosition());
|
||||
glm::quat ori = quatFromLeapBase(float(side), hand.basis());
|
||||
|
||||
palmJoint = editJointTracker(evalJointIndex((side > 0), rootBranchIndex, 0)); // 0 is the index of the palm joint
|
||||
palmJoint->editAbsFrame().setTranslation(pos);
|
||||
palmJoint->editAbsFrame().setRotation(ori);
|
||||
palmJoint->updateLocFromAbsTransform(parentJointTracker);
|
||||
palmJoint->activeFrame();
|
||||
}
|
||||
|
||||
// Check if the hand has any fingers
|
||||
const Leap::FingerList fingers = hand.fingers();
|
||||
if (!fingers.isEmpty()) {
|
||||
// For every fingers in the list
|
||||
for (int i = 0; i < fingers.count(); ++i) {
|
||||
// Reset the parent joint to the palmJoint for every finger traversal
|
||||
parentJointTracker = palmJoint;
|
||||
|
||||
// surprisingly, Leap::Finger::Type start at 0 for thumb a until 4 for the pinky
|
||||
Index fingerIndex = evalJointIndex((side > 0), int(fingers[i].type()), 0);
|
||||
|
||||
// let's update the finger's joints
|
||||
for (int b = 0; b < FINGER_NUM_JOINTS; b++) {
|
||||
Leap::Bone::Type type = Leap::Bone::Type(b + Leap::Bone::TYPE_METACARPAL);
|
||||
Leap::Bone bone = fingers[i].bone(type);
|
||||
JointTracker* ljointTracker = editJointTracker(fingerIndex + b);
|
||||
if (bone.isValid()) {
|
||||
Leap::Vector bp = bone.nextJoint();
|
||||
|
||||
ljointTracker->editAbsFrame().setTranslation(vec3FromLeapVector(bp));
|
||||
ljointTracker->editAbsFrame().setRotation(quatFromLeapBase(float(side), bone.basis()));
|
||||
ljointTracker->updateLocFromAbsTransform(parentJointTracker);
|
||||
ljointTracker->activeFrame();
|
||||
}
|
||||
parentJointTracker = ljointTracker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastFrameID = newFrameID;
|
||||
#endif
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
//
|
||||
// Created by Sam Cake on 6/2/2014
|
||||
// Copyright 2014 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_Leapmotion_h
|
||||
#define hifi_Leapmotion_h
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#include <trackers/MotionTracker.h>
|
||||
|
||||
#ifdef HAVE_LEAPMOTION
|
||||
#include <Leap.h>
|
||||
#endif
|
||||
|
||||
/// Handles interaction with the Leapmotion skeleton tracking suit.
|
||||
class Leapmotion : public MotionTracker {
|
||||
public:
|
||||
static const Name NAME;
|
||||
|
||||
static void init();
|
||||
static void destroy();
|
||||
|
||||
/// Leapmotion MotionTracker factory
|
||||
static Leapmotion* getInstance();
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
virtual void update() override;
|
||||
|
||||
protected:
|
||||
Leapmotion();
|
||||
virtual ~Leapmotion();
|
||||
|
||||
private:
|
||||
#ifdef HAVE_LEAPMOTION
|
||||
Leap::Listener _listener;
|
||||
Leap::Controller _controller;
|
||||
#endif
|
||||
|
||||
bool _active;
|
||||
};
|
||||
|
||||
#endif // hifi_Leapmotion_h
|
|
@ -17,7 +17,6 @@
|
|||
#include <plugins/PluginManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include <trackers/MotionTracker.h>
|
||||
|
||||
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
|
||||
if (event->type() == HFActionEvent::startType()) {
|
||||
|
@ -97,86 +96,6 @@ QVariant ControllerScriptingInterface::getRecommendedOverlayRect() const {
|
|||
return qRectToVariant(rect);
|
||||
}
|
||||
|
||||
controller::InputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
|
||||
// This is where we retrieve the Device Tracker category and then the sub tracker within it
|
||||
auto icIt = _inputControllers.find(0);
|
||||
if (icIt != _inputControllers.end()) {
|
||||
return (*icIt).second.get();
|
||||
}
|
||||
|
||||
// Look for device
|
||||
DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
|
||||
if (deviceID < 0) {
|
||||
deviceID = 0;
|
||||
}
|
||||
// TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
|
||||
// in the near future we need to change that to a real mapping between the devices and the deviceName
|
||||
// ALso we need to expand the spec so we can fall back on the "default" controller per categories
|
||||
|
||||
if (deviceID >= 0) {
|
||||
// TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
|
||||
MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
|
||||
if (motionTracker) {
|
||||
MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
|
||||
if (trackerID >= 0) {
|
||||
controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
|
||||
controller::InputController::Key key = inputController->getKey();
|
||||
_inputControllers.insert(InputControllerMap::value_type(key, inputController));
|
||||
return inputController.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::releaseInputController(controller::InputController* input) {
|
||||
_inputControllers.erase(input->getKey());
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::updateInputControllers() {
|
||||
for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
|
||||
(*it).second->update();
|
||||
}
|
||||
}
|
||||
|
||||
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
|
||||
_deviceTrackerId(deviceTrackerId),
|
||||
_subTrackerId(subTrackerId),
|
||||
_isActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
void InputController::update() {
|
||||
_isActive = false;
|
||||
|
||||
// TODO for now the InputController is only supporting a JointTracker from a MotionTracker
|
||||
MotionTracker* motionTracker = dynamic_cast< MotionTracker*> (DeviceTracker::getDevice(_deviceTrackerId));
|
||||
if (motionTracker) {
|
||||
if ((int)_subTrackerId < motionTracker->numJointTrackers()) {
|
||||
const MotionTracker::JointTracker* joint = motionTracker->getJointTracker(_subTrackerId);
|
||||
|
||||
if (joint->isActive()) {
|
||||
joint->getAbsFrame().getTranslation(_eventCache.absTranslation);
|
||||
joint->getAbsFrame().getRotation(_eventCache.absRotation);
|
||||
joint->getLocFrame().getTranslation(_eventCache.locTranslation);
|
||||
joint->getLocFrame().getRotation(_eventCache.locRotation);
|
||||
|
||||
_isActive = true;
|
||||
//emit spatialEvent(_eventCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int INPUTCONTROLLER_KEY_DEVICE_OFFSET = 16;
|
||||
const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16;
|
||||
|
||||
InputController::Key InputController::getKey() const {
|
||||
return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId);
|
||||
}
|
||||
|
||||
|
||||
void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
|
||||
void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
|
||||
|
||||
|
|
|
@ -25,38 +25,6 @@
|
|||
#include <WheelEvent.h>
|
||||
class ScriptEngine;
|
||||
|
||||
class PalmData;
|
||||
|
||||
class InputController : public controller::InputController {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InputController(int deviceTrackerId, int subTrackerId, QObject* parent = NULL);
|
||||
|
||||
virtual void update() override;
|
||||
virtual Key getKey() const override;
|
||||
|
||||
public slots:
|
||||
|
||||
virtual bool isActive() const override { return _isActive; }
|
||||
virtual glm::vec3 getAbsTranslation() const override { return _eventCache.absTranslation; }
|
||||
virtual glm::quat getAbsRotation() const override { return _eventCache.absRotation; }
|
||||
virtual glm::vec3 getLocTranslation() const override { return _eventCache.locTranslation; }
|
||||
virtual glm::quat getLocRotation() const override { return _eventCache.locRotation; }
|
||||
|
||||
private:
|
||||
|
||||
int _deviceTrackerId;
|
||||
uint _subTrackerId;
|
||||
|
||||
// cache for the spatial
|
||||
SpatialEvent _eventCache;
|
||||
bool _isActive;
|
||||
|
||||
signals:
|
||||
};
|
||||
|
||||
|
||||
/// handles scripting of input controller commands from JS
|
||||
class ControllerScriptingInterface : public controller::ScriptingInterface {
|
||||
Q_OBJECT
|
||||
|
@ -86,8 +54,6 @@ public:
|
|||
bool isJoystickCaptured(int joystickIndex) const;
|
||||
bool areEntityClicksCaptured() const;
|
||||
|
||||
void updateInputControllers();
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void captureKeyEvents(const KeyEvent& event);
|
||||
|
@ -102,10 +68,6 @@ public slots:
|
|||
virtual glm::vec2 getViewportDimensions() const;
|
||||
virtual QVariant getRecommendedOverlayRect() const;
|
||||
|
||||
/// Factory to create an InputController
|
||||
virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker);
|
||||
virtual void releaseInputController(controller::InputController* input);
|
||||
|
||||
signals:
|
||||
void keyPressEvent(const KeyEvent& event);
|
||||
void keyReleaseEvent(const KeyEvent& event);
|
||||
|
@ -135,8 +97,6 @@ private:
|
|||
bool _captureEntityClicks;
|
||||
|
||||
using InputKey = controller::InputController::Key;
|
||||
using InputControllerMap = std::map<InputKey, controller::InputController::Pointer>;
|
||||
InputControllerMap _inputControllers;
|
||||
};
|
||||
|
||||
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
//
|
||||
// Created by Sam Cake on 6/20/14.
|
||||
// Copyright 2014 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 "DeviceTracker.h"
|
||||
|
||||
DeviceTracker::SingletonData::~SingletonData() {
|
||||
// Destroy all the device registered
|
||||
//TODO C++11 for (auto device = _devicesVector.begin(); device != _devicesVector.end(); device++) {
|
||||
for (Vector::iterator device = _devicesVector.begin(); device != _devicesVector.end(); device++) {
|
||||
delete (*device);
|
||||
}
|
||||
}
|
||||
|
||||
int DeviceTracker::getNumDevices() {
|
||||
return (int)Singleton::get()->_devicesMap.size();
|
||||
}
|
||||
|
||||
DeviceTracker::ID DeviceTracker::getDeviceID(const Name& name) {
|
||||
//TODO C++11 auto deviceIt = Singleton::get()->_devicesMap.find(name);
|
||||
Map::iterator deviceIt = Singleton::get()->_devicesMap.find(name);
|
||||
if (deviceIt != Singleton::get()->_devicesMap.end()) {
|
||||
return (*deviceIt).second;
|
||||
} else {
|
||||
return INVALID_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceTracker* DeviceTracker::getDevice(const Name& name) {
|
||||
return getDevice(getDeviceID(name));
|
||||
}
|
||||
|
||||
DeviceTracker* DeviceTracker::getDevice(DeviceTracker::ID deviceID) {
|
||||
if ((deviceID >= 0) && (deviceID < (int)(Singleton::get()->_devicesVector.size()))) {
|
||||
return Singleton::get()->_devicesVector[ deviceID ];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceTracker::ID DeviceTracker::registerDevice(const Name& name, DeviceTracker* device) {
|
||||
// Check that the device exists, if not exit
|
||||
if (!device) {
|
||||
return INVALID_DEVICE;
|
||||
}
|
||||
|
||||
// Look if the name is not already used
|
||||
ID deviceID = getDeviceID(name);
|
||||
if (deviceID >= 0) {
|
||||
return INVALID_DEVICE_NAME;
|
||||
}
|
||||
|
||||
// Good to register the device
|
||||
deviceID = (ID)Singleton::get()->_devicesVector.size();
|
||||
Singleton::get()->_devicesMap.insert(Map::value_type(name, deviceID));
|
||||
Singleton::get()->_devicesVector.push_back(device);
|
||||
device->assignIDAndName(deviceID, name);
|
||||
|
||||
return deviceID;
|
||||
}
|
||||
|
||||
void DeviceTracker::destroyDevice(const Name& name) {
|
||||
DeviceTracker::ID deviceID = getDeviceID(name);
|
||||
if (deviceID != INVALID_DEVICE) {
|
||||
delete Singleton::get()->_devicesVector[getDeviceID(name)];
|
||||
Singleton::get()->_devicesVector[getDeviceID(name)] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceTracker::updateAll() {
|
||||
//TODO C++11 for (auto deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++) {
|
||||
for (Vector::iterator deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++) {
|
||||
if ((*deviceIt))
|
||||
(*deviceIt)->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Core features of the Device Tracker
|
||||
DeviceTracker::DeviceTracker() :
|
||||
_ID(INVALID_DEVICE),
|
||||
_name("Unkown")
|
||||
{
|
||||
}
|
||||
|
||||
DeviceTracker::~DeviceTracker() {
|
||||
}
|
||||
|
||||
void DeviceTracker::update() {
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
//
|
||||
// Created by Sam Cake on 6/20/14.
|
||||
// Copyright 2014 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_DeviceTracker_h
|
||||
#define hifi_DeviceTracker_h
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// Singleton template class
|
||||
template < typename T >
|
||||
class TemplateSingleton {
|
||||
public:
|
||||
|
||||
static T* get() {
|
||||
if ( !_singleton._one ) {
|
||||
_singleton._one = new T();
|
||||
}
|
||||
return _singleton._one;
|
||||
}
|
||||
|
||||
TemplateSingleton() :
|
||||
_one(0)
|
||||
{
|
||||
}
|
||||
~TemplateSingleton() {
|
||||
if ( _one ) {
|
||||
delete _one;
|
||||
_one = 0;
|
||||
}
|
||||
}
|
||||
private:
|
||||
static TemplateSingleton< T > _singleton;
|
||||
T* _one;
|
||||
};
|
||||
template <typename T>
|
||||
TemplateSingleton<T> TemplateSingleton<T>::_singleton;
|
||||
|
||||
/// Base class for device trackers.
|
||||
class DeviceTracker {
|
||||
public:
|
||||
|
||||
// THe ID and Name types used to manage the pool of devices
|
||||
typedef std::string Name;
|
||||
typedef int ID;
|
||||
static const ID INVALID_DEVICE = -1;
|
||||
static const ID INVALID_DEVICE_NAME = -2;
|
||||
|
||||
// Singleton interface to register and query the devices currently connected
|
||||
static int getNumDevices();
|
||||
static ID getDeviceID(const Name& name);
|
||||
static DeviceTracker* getDevice(ID deviceID);
|
||||
static DeviceTracker* getDevice(const Name& name);
|
||||
|
||||
/// Update all the devices calling for their update() function
|
||||
/// This should be called every frame by the main loop to update all the devices that pull their state
|
||||
static void updateAll();
|
||||
|
||||
/// Register a device tracker to the factory
|
||||
/// Right after creating a new DeviceTracker, it should be registered
|
||||
/// This is why, it's recommended to use a factory static call in the specialized class
|
||||
/// to create a new input device
|
||||
///
|
||||
/// \param name The Name under wich registering the device
|
||||
/// \param parent The DeviceTracker
|
||||
///
|
||||
/// \return The Index of the newly registered device.
|
||||
/// Valid if everything went well.
|
||||
/// INVALID_DEVICE if the device is not valid (NULL)
|
||||
/// INVALID_DEVICE_NAME if the name is already taken
|
||||
static ID registerDevice(const Name& name, DeviceTracker* tracker);
|
||||
|
||||
static void destroyDevice(const Name& name);
|
||||
|
||||
// DeviceTracker interface
|
||||
|
||||
virtual void update();
|
||||
|
||||
/// Get the ID assigned to the Device when registered after creation, or INVALID_DEVICE if it hasn't been registered which should not happen.
|
||||
ID getID() const { return _ID; }
|
||||
|
||||
/// Get the name assigned to the Device when registered after creation, or "Unknown" if it hasn't been registered which should not happen.
|
||||
const Name& getName() const { return _name; }
|
||||
|
||||
typedef std::map< Name, ID > Map;
|
||||
static const Map& getDevices() { return Singleton::get()->_devicesMap; }
|
||||
|
||||
protected:
|
||||
DeviceTracker();
|
||||
virtual ~DeviceTracker();
|
||||
|
||||
private:
|
||||
ID _ID;
|
||||
Name _name;
|
||||
|
||||
// this call is used by the singleton when the device tracker is currently beeing registered and beeing assigned an ID
|
||||
void assignIDAndName( const ID id, const Name& name ) { _ID = id; _name = name; }
|
||||
|
||||
typedef std::vector< DeviceTracker* > Vector;
|
||||
struct SingletonData {
|
||||
Map _devicesMap;
|
||||
Vector _devicesVector;
|
||||
|
||||
~SingletonData();
|
||||
};
|
||||
typedef TemplateSingleton< SingletonData > Singleton;
|
||||
};
|
||||
|
||||
#endif // hifi_DeviceTracker_h
|
|
@ -1,186 +0,0 @@
|
|||
//
|
||||
// Created by Sam Cake on 6/20/14.
|
||||
// Copyright 2014 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 "MotionTracker.h"
|
||||
|
||||
// glm::mult(mat43, mat43) just the composition of the 2 matrices assuming they are in fact mat44 with the last raw = { 0, 0, 0, 1 }
|
||||
namespace glm {
|
||||
mat4x3 mult(const mat4& lhs, const mat4x3& rhs) {
|
||||
vec3 lrx(lhs[0].x, lhs[1].x, lhs[2].x);
|
||||
vec3 lry(lhs[0].y, lhs[1].y, lhs[2].y);
|
||||
vec3 lrz(lhs[0].z, lhs[1].z, lhs[2].z);
|
||||
return mat4x3(
|
||||
dot(lrx, rhs[0]),
|
||||
dot(lry, rhs[0]),
|
||||
dot(lrz, rhs[0]),
|
||||
|
||||
dot(lrx, rhs[1]),
|
||||
dot(lry, rhs[1]),
|
||||
dot(lrz, rhs[1]),
|
||||
|
||||
dot(lrx, rhs[2]),
|
||||
dot(lry, rhs[2]),
|
||||
dot(lrz, rhs[2]),
|
||||
|
||||
dot(lrx, rhs[3]) + lhs[3].x,
|
||||
dot(lry, rhs[3]) + lhs[3].y,
|
||||
dot(lrz, rhs[3]) + lhs[3].z
|
||||
);
|
||||
}
|
||||
mat4x3 mult(const mat4x3& lhs, const mat4x3& rhs) {
|
||||
vec3 lrx(lhs[0].x, lhs[1].x, lhs[2].x);
|
||||
vec3 lry(lhs[0].y, lhs[1].y, lhs[2].y);
|
||||
vec3 lrz(lhs[0].z, lhs[1].z, lhs[2].z);
|
||||
return mat4x3(
|
||||
dot(lrx, rhs[0]),
|
||||
dot(lry, rhs[0]),
|
||||
dot(lrz, rhs[0]),
|
||||
|
||||
dot(lrx, rhs[1]),
|
||||
dot(lry, rhs[1]),
|
||||
dot(lrz, rhs[1]),
|
||||
|
||||
dot(lrx, rhs[2]),
|
||||
dot(lry, rhs[2]),
|
||||
dot(lrz, rhs[2]),
|
||||
|
||||
dot(lrx, rhs[3]) + lhs[3].x,
|
||||
dot(lry, rhs[3]) + lhs[3].y,
|
||||
dot(lrz, rhs[3]) + lhs[3].z
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// MotionTracker
|
||||
MotionTracker::MotionTracker() :
|
||||
DeviceTracker()
|
||||
{
|
||||
_jointsArray.resize(1);
|
||||
_jointsMap.insert(JointTracker::Map::value_type(Semantic("Root"), 0));
|
||||
}
|
||||
|
||||
MotionTracker::~MotionTracker()
|
||||
{
|
||||
}
|
||||
|
||||
bool MotionTracker::isConnected() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
MotionTracker::Index MotionTracker::addJoint(const Semantic& semantic, Index parent) {
|
||||
// Check the parent
|
||||
if (int(parent) < 0)
|
||||
return INVALID_PARENT;
|
||||
|
||||
// Check that the semantic is not already in use
|
||||
Index foundIndex = findJointIndex(semantic);
|
||||
if (foundIndex >= 0) {
|
||||
return INVALID_SEMANTIC;
|
||||
}
|
||||
|
||||
|
||||
// All good then allocate the joint
|
||||
Index newIndex = (Index)_jointsArray.size();
|
||||
_jointsArray.push_back(JointTracker(semantic, parent));
|
||||
_jointsMap.insert(JointTracker::Map::value_type(semantic, newIndex));
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
MotionTracker::Index MotionTracker::findJointIndex(const Semantic& semantic) const {
|
||||
// TODO C++11 auto jointIt = _jointsMap.find(semantic);
|
||||
JointTracker::Map::const_iterator jointIt = _jointsMap.find(semantic);
|
||||
if (jointIt != _jointsMap.end()) {
|
||||
return (*jointIt).second;
|
||||
}
|
||||
|
||||
return INVALID_SEMANTIC;
|
||||
}
|
||||
|
||||
void MotionTracker::updateAllAbsTransform() {
|
||||
_jointsArray[0].updateAbsFromLocTransform(0);
|
||||
|
||||
// Because we know the hierarchy is stored from root down the branches let's just traverse and update
|
||||
for (Index i = 1; i < (Index)(_jointsArray.size()); i++) {
|
||||
JointTracker* joint = _jointsArray.data() + i;
|
||||
joint->updateAbsFromLocTransform(_jointsArray.data() + joint->getParent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MotionTracker::JointTracker
|
||||
MotionTracker::JointTracker::JointTracker() :
|
||||
_locFrame(),
|
||||
_absFrame(),
|
||||
_semantic(""),
|
||||
_parent(INVALID_PARENT),
|
||||
_lastUpdate(1) // Joint inactive
|
||||
{
|
||||
}
|
||||
|
||||
MotionTracker::JointTracker::JointTracker(const Semantic& semantic, Index parent) :
|
||||
_semantic(semantic),
|
||||
_parent(parent),
|
||||
_lastUpdate(1) // Joint inactive
|
||||
{
|
||||
}
|
||||
|
||||
MotionTracker::JointTracker::JointTracker(const JointTracker& tracker) :
|
||||
_locFrame(tracker._locFrame),
|
||||
_absFrame(tracker._absFrame),
|
||||
_semantic(tracker._semantic),
|
||||
_parent(tracker._parent),
|
||||
_lastUpdate(tracker._lastUpdate)
|
||||
{
|
||||
}
|
||||
|
||||
void MotionTracker::JointTracker::updateAbsFromLocTransform(const JointTracker* parentJoint) {
|
||||
if (parentJoint) {
|
||||
editAbsFrame()._transform = (parentJoint->getAbsFrame()._transform * getLocFrame()._transform);
|
||||
} else {
|
||||
editAbsFrame()._transform = getLocFrame()._transform;
|
||||
}
|
||||
}
|
||||
|
||||
void MotionTracker::JointTracker::updateLocFromAbsTransform(const JointTracker* parentJoint) {
|
||||
if (parentJoint) {
|
||||
glm::mat4 ip = glm::inverse(parentJoint->getAbsFrame()._transform);
|
||||
editLocFrame()._transform = (ip * getAbsFrame()._transform);
|
||||
} else {
|
||||
editLocFrame()._transform = getAbsFrame()._transform;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// MotionTracker::Frame
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
MotionTracker::Frame::Frame() :
|
||||
_transform()
|
||||
{
|
||||
}
|
||||
|
||||
void MotionTracker::Frame::setRotation(const glm::quat& rotation) {
|
||||
glm::mat3x3 rot = glm::mat3_cast(rotation);
|
||||
_transform[0] = glm::vec4(rot[0], 0.0f);
|
||||
_transform[1] = glm::vec4(rot[1], 0.0f);
|
||||
_transform[2] = glm::vec4(rot[2], 0.0f);
|
||||
}
|
||||
|
||||
void MotionTracker::Frame::getRotation(glm::quat& rotation) const {
|
||||
rotation = glm::quat_cast(_transform);
|
||||
}
|
||||
|
||||
void MotionTracker::Frame::setTranslation(const glm::vec3& translation) {
|
||||
_transform[3] = glm::vec4(translation, 1.0f);
|
||||
}
|
||||
|
||||
void MotionTracker::Frame::getTranslation(glm::vec3& translation) const {
|
||||
translation = extractTranslation(_transform);
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
//
|
||||
// Created by Sam Cake on 6/20/14.
|
||||
// Copyright 2014 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_MotionTracker_h
|
||||
#define hifi_MotionTracker_h
|
||||
|
||||
#include "DeviceTracker.h"
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
/// Base class for device trackers.
|
||||
class MotionTracker : public DeviceTracker {
|
||||
public:
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
Frame();
|
||||
|
||||
glm::mat4 _transform;
|
||||
|
||||
void setRotation(const glm::quat& rotation);
|
||||
void getRotation(glm::quat& rotatio) const;
|
||||
|
||||
void setTranslation(const glm::vec3& translation);
|
||||
void getTranslation(glm::vec3& translation) const;
|
||||
};
|
||||
|
||||
// Semantic and Index types to retreive the JointTrackers of this MotionTracker
|
||||
typedef std::string Semantic;
|
||||
typedef int32_t Index;
|
||||
static const Index INVALID_SEMANTIC = -1;
|
||||
static const Index INVALID_PARENT = -2;
|
||||
|
||||
class JointTracker {
|
||||
public:
|
||||
typedef std::vector< JointTracker > Vector;
|
||||
typedef std::map< Semantic, Index > Map;
|
||||
|
||||
JointTracker();
|
||||
JointTracker(const JointTracker& tracker);
|
||||
JointTracker(const Semantic& semantic, Index parent);
|
||||
|
||||
const Frame& getLocFrame() const { return _locFrame; }
|
||||
Frame& editLocFrame() { return _locFrame; }
|
||||
void setLocFrame(const Frame& frame) { editLocFrame() = frame; }
|
||||
|
||||
const Frame& getAbsFrame() const { return _absFrame; }
|
||||
Frame& editAbsFrame() { return _absFrame; }
|
||||
void setAbsFrame(const Frame& frame) { editAbsFrame() = frame; }
|
||||
|
||||
const Semantic& getSemantic() const { return _semantic; }
|
||||
const Index& getParent() const { return _parent; }
|
||||
|
||||
bool isActive() const { return (_lastUpdate <= 0); }
|
||||
void tickNewFrame() { _lastUpdate++; }
|
||||
void activeFrame() { _lastUpdate = 0; }
|
||||
|
||||
/// Update the loc/abs transform for this joint from the current abs/loc value and the specified parent joint abs frame
|
||||
void updateLocFromAbsTransform(const JointTracker* parentJoint);
|
||||
void updateAbsFromLocTransform(const JointTracker* parentJoint);
|
||||
|
||||
protected:
|
||||
Frame _locFrame;
|
||||
Frame _absFrame;
|
||||
Semantic _semantic;
|
||||
Index _parent;
|
||||
int _lastUpdate;
|
||||
};
|
||||
|
||||
virtual bool isConnected() const;
|
||||
|
||||
Index numJointTrackers() const { return (Index)_jointsArray.size(); }
|
||||
|
||||
/// Access a Joint from it's index.
|
||||
/// Index 0 is always the "Root".
|
||||
/// if the index is Invalid then returns NULL.
|
||||
const JointTracker* getJointTracker(Index index) const { return ((index > 0) && (index < (Index)(_jointsArray.size())) ? _jointsArray.data() + index : NULL); }
|
||||
JointTracker* editJointTracker(Index index) { return ((index > 0) && (index < (Index)(_jointsArray.size())) ? _jointsArray.data() + index : NULL); }
|
||||
|
||||
/// From a semantic, find the Index of the Joint.
|
||||
/// \return the index of the mapped Joint or INVALID_SEMANTIC if the semantic is not knowned.
|
||||
Index findJointIndex(const Semantic& semantic) const;
|
||||
|
||||
protected:
|
||||
MotionTracker();
|
||||
virtual ~MotionTracker();
|
||||
|
||||
JointTracker::Vector _jointsArray;
|
||||
JointTracker::Map _jointsMap;
|
||||
|
||||
/// Adding joint is only done from the specialized Motion Tracker, hence this function is protected.
|
||||
/// The hierarchy of joints must be created from the top down to the branches.
|
||||
/// The "Root" node is at index 0 and exists at creation of the Motion Tracker.
|
||||
///
|
||||
/// \param semantic A joint is defined by it's semantic, the unique name mapping to it
|
||||
/// \param parent The parent's index, the parent must be valid and correspond to a Joint that has been previously created
|
||||
///
|
||||
/// \return The Index of the newly created Joint.
|
||||
/// Valid if everything went well.
|
||||
/// INVALID_SEMANTIC if the semantic is already in use
|
||||
/// INVALID_PARENT if the parent is not valid
|
||||
Index addJoint(const Semantic& semantic, Index parent);
|
||||
|
||||
/// Update the absolute transform stack traversing the hierarchy from the root down the branches
|
||||
/// This is a generic way to update all the Joint's absFrame by combining the locFrame going down the hierarchy branch.
|
||||
void updateAllAbsTransform();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // hifi_MotionTracker_h
|
|
@ -1,527 +0,0 @@
|
|||
//
|
||||
// leapHands.js
|
||||
// examples
|
||||
//
|
||||
// Created by David Rowe on 8 Sep 2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that uses the Leap Motion to make the avatar's hands replicate the user's hand actions.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var leftTriggerValue = 0;
|
||||
var rightTriggerValue = 0;
|
||||
|
||||
var LEAP_TRIGGER_START_ANGLE = 15.0;
|
||||
var LEAP_TRIGGER_END_ANGLE = 40.0;
|
||||
|
||||
function getLeapMotionLeftTrigger() {
|
||||
//print("left trigger = " + leftTriggerValue);
|
||||
return leftTriggerValue;
|
||||
}
|
||||
function getLeapMotionRightTrigger() {
|
||||
//print("right trigger = " + rightTriggerValue);
|
||||
return rightTriggerValue;
|
||||
}
|
||||
|
||||
var leapHands = (function () {
|
||||
|
||||
var isOnHMD,
|
||||
LEAP_ON_HMD_MENU_ITEM = "Leap Motion on HMD",
|
||||
LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip
|
||||
HMD_OFFSET = 0.070, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief
|
||||
hasHandAndWristJoints,
|
||||
handToWristOffset = [], // For avatars without a wrist joint we control an estimate of a proper hand joint position
|
||||
HAND_OFFSET = 0.4, // Relative distance of wrist to hand versus wrist to index finger knuckle
|
||||
handAnimationStateHandlers,
|
||||
handAnimationStateFunctions,
|
||||
handAnimationStateProperties,
|
||||
hands,
|
||||
wrists,
|
||||
NUM_HANDS = 2, // 0 = left; 1 = right
|
||||
fingers,
|
||||
NUM_FINGERS = 5, // 0 = thumb; ...; 4 = pinky
|
||||
THUMB = 0,
|
||||
MIDDLE_FINGER = 2,
|
||||
NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal joint
|
||||
MAX_HAND_INACTIVE_COUNT = 20,
|
||||
calibrationStatus,
|
||||
UNCALIBRATED = 0,
|
||||
CALIBRATING = 1,
|
||||
CALIBRATED = 2,
|
||||
CALIBRATION_TIME = 1000, // milliseconds
|
||||
avatarScale,
|
||||
avatarFaceModelURL,
|
||||
avatarSkeletonModelURL,
|
||||
settingsTimer,
|
||||
HMD_CAMERA_TO_AVATAR_ROTATION = [
|
||||
Quat.angleAxis(180.0, { x: 0, y: 0, z: 1 }),
|
||||
Quat.angleAxis(-180.0, { x: 0, y: 0, z: 1 })
|
||||
],
|
||||
DESKTOP_CAMERA_TO_AVATAR_ROTATION =
|
||||
Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 })),
|
||||
LEAP_THUMB_ROOT_ADJUST = [Quat.fromPitchYawRollDegrees(0, 0, 20), Quat.fromPitchYawRollDegrees(0, 0, -20)];
|
||||
|
||||
function printSkeletonJointNames() {
|
||||
var jointNames,
|
||||
i;
|
||||
|
||||
print(MyAvatar.skeletonModelURL);
|
||||
|
||||
print("Skeleton joint names ...");
|
||||
jointNames = MyAvatar.getJointNames();
|
||||
for (i = 0; i < jointNames.length; i += 1) {
|
||||
print(i + ": " + jointNames[i]);
|
||||
}
|
||||
print("... skeleton joint names");
|
||||
}
|
||||
|
||||
function animateLeftHand() {
|
||||
var ROTATION_AND_POSITION = 0;
|
||||
|
||||
return {
|
||||
leftHandType: ROTATION_AND_POSITION,
|
||||
leftHandPosition: hands[0].position,
|
||||
leftHandRotation: hands[0].rotation
|
||||
};
|
||||
}
|
||||
|
||||
function animateRightHand() {
|
||||
var ROTATION_AND_POSITION = 0;
|
||||
|
||||
return {
|
||||
rightHandType: ROTATION_AND_POSITION,
|
||||
rightHandPosition: hands[1].position,
|
||||
rightHandRotation: hands[1].rotation
|
||||
};
|
||||
}
|
||||
|
||||
function finishCalibration() {
|
||||
var avatarPosition,
|
||||
handPosition,
|
||||
middleFingerPosition,
|
||||
leapHandHeight,
|
||||
h;
|
||||
|
||||
if (!isOnHMD) {
|
||||
if (hands[0].controller.isActive() && hands[1].controller.isActive()) {
|
||||
leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0;
|
||||
} else {
|
||||
calibrationStatus = UNCALIBRATED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
avatarPosition = MyAvatar.position;
|
||||
|
||||
for (h = 0; h < NUM_HANDS; h += 1) {
|
||||
handPosition = MyAvatar.getJointPosition(hands[h].jointName);
|
||||
if (!hasHandAndWristJoints) {
|
||||
middleFingerPosition = MyAvatar.getJointPosition(fingers[h][MIDDLE_FINGER][0].jointName);
|
||||
handToWristOffset[h] = Vec3.multiply(Vec3.subtract(handPosition, middleFingerPosition), 1.0 - HAND_OFFSET);
|
||||
}
|
||||
|
||||
if (isOnHMD) {
|
||||
// Offset of Leap Motion origin from physical eye position
|
||||
hands[h].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET };
|
||||
} else {
|
||||
hands[h].zeroPosition = {
|
||||
x: handPosition.x - avatarPosition.x,
|
||||
y: handPosition.y - avatarPosition.y,
|
||||
z: avatarPosition.z - handPosition.z
|
||||
};
|
||||
hands[h].zeroPosition = Vec3.multiplyQbyV(MyAvatar.orientation, hands[h].zeroPosition);
|
||||
hands[h].zeroPosition.y = hands[h].zeroPosition.y - leapHandHeight;
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("RightHand");
|
||||
MyAvatar.clearJointData("RightForeArm");
|
||||
|
||||
calibrationStatus = CALIBRATED;
|
||||
print("Leap Motion: Calibrated");
|
||||
}
|
||||
|
||||
function calibrate() {
|
||||
var jointNames,
|
||||
i;
|
||||
|
||||
calibrationStatus = CALIBRATING;
|
||||
|
||||
avatarScale = MyAvatar.scale;
|
||||
avatarFaceModelURL = MyAvatar.faceModelURL;
|
||||
avatarSkeletonModelURL = MyAvatar.skeletonModelURL;
|
||||
|
||||
// Does this skeleton have both wrist and hand joints?
|
||||
hasHandAndWristJoints = false;
|
||||
jointNames = MyAvatar.getJointNames();
|
||||
for (i = 0; i < jointNames.length; i += 1) {
|
||||
hasHandAndWristJoints = hasHandAndWristJoints || jointNames[i].toLowerCase() === "leftwrist";
|
||||
}
|
||||
|
||||
// Set avatar arms vertical, forearms horizontal, as "zero" position for calibration
|
||||
MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 0.0, 90.0));
|
||||
MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollDegrees(0.0, 90.0, 0.0));
|
||||
MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0));
|
||||
MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollDegrees(0.0, -90.0, 0.0));
|
||||
|
||||
// Wait for arms to assume their positions before calculating
|
||||
Script.setTimeout(finishCalibration, CALIBRATION_TIME);
|
||||
}
|
||||
|
||||
function checkCalibration() {
|
||||
|
||||
if (calibrationStatus === CALIBRATED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (calibrationStatus !== CALIBRATING) {
|
||||
calibrate();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function setIsOnHMD() {
|
||||
isOnHMD = Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM);
|
||||
print("Leap Motion: " + (isOnHMD ? "Is on HMD" : "Is on desk"));
|
||||
}
|
||||
|
||||
function checkSettings() {
|
||||
if (calibrationStatus > UNCALIBRATED && (MyAvatar.scale !== avatarScale
|
||||
|| MyAvatar.faceModelURL !== avatarFaceModelURL
|
||||
|| MyAvatar.skeletonModelURL !== avatarSkeletonModelURL
|
||||
|| Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM) !== isOnHMD)) {
|
||||
print("Leap Motion: Recalibrate...");
|
||||
calibrationStatus = UNCALIBRATED;
|
||||
|
||||
setIsOnHMD();
|
||||
}
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
|
||||
wrists = [
|
||||
{
|
||||
jointName: "LeftWrist",
|
||||
controller: Controller.createInputController("Spatial", "joint_L_wrist")
|
||||
},
|
||||
{
|
||||
jointName: "RightWrist",
|
||||
controller: Controller.createInputController("Spatial", "joint_R_wrist")
|
||||
}
|
||||
];
|
||||
|
||||
hands = [
|
||||
{
|
||||
jointName: "LeftHand",
|
||||
controller: Controller.createInputController("Spatial", "joint_L_hand"),
|
||||
inactiveCount: 0
|
||||
},
|
||||
{
|
||||
jointName: "RightHand",
|
||||
controller: Controller.createInputController("Spatial", "joint_R_hand"),
|
||||
inactiveCount: 0
|
||||
}
|
||||
];
|
||||
|
||||
// The Leap controller's first joint is the hand-metacarpal joint but this joint's data is not used because it's too
|
||||
// dependent on the model skeleton exactly matching the Leap skeleton; using just the second and subsequent joints
|
||||
// seems to work better over all.
|
||||
fingers = [{}, {}];
|
||||
fingers[0] = [
|
||||
[
|
||||
{ jointName: "LeftHandThumb1", controller: Controller.createInputController("Spatial", "joint_L_thumb2") },
|
||||
{ jointName: "LeftHandThumb2", controller: Controller.createInputController("Spatial", "joint_L_thumb3") },
|
||||
{ jointName: "LeftHandThumb3", controller: Controller.createInputController("Spatial", "joint_L_thumb4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "LeftHandIndex1", controller: Controller.createInputController("Spatial", "joint_L_index2") },
|
||||
{ jointName: "LeftHandIndex2", controller: Controller.createInputController("Spatial", "joint_L_index3") },
|
||||
{ jointName: "LeftHandIndex3", controller: Controller.createInputController("Spatial", "joint_L_index4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "LeftHandMiddle1", controller: Controller.createInputController("Spatial", "joint_L_middle2") },
|
||||
{ jointName: "LeftHandMiddle2", controller: Controller.createInputController("Spatial", "joint_L_middle3") },
|
||||
{ jointName: "LeftHandMiddle3", controller: Controller.createInputController("Spatial", "joint_L_middle4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "LeftHandRing1", controller: Controller.createInputController("Spatial", "joint_L_ring2") },
|
||||
{ jointName: "LeftHandRing2", controller: Controller.createInputController("Spatial", "joint_L_ring3") },
|
||||
{ jointName: "LeftHandRing3", controller: Controller.createInputController("Spatial", "joint_L_ring4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "LeftHandPinky1", controller: Controller.createInputController("Spatial", "joint_L_pinky2") },
|
||||
{ jointName: "LeftHandPinky2", controller: Controller.createInputController("Spatial", "joint_L_pinky3") },
|
||||
{ jointName: "LeftHandPinky3", controller: Controller.createInputController("Spatial", "joint_L_pinky4") }
|
||||
]
|
||||
];
|
||||
fingers[1] = [
|
||||
[
|
||||
{ jointName: "RightHandThumb1", controller: Controller.createInputController("Spatial", "joint_R_thumb2") },
|
||||
{ jointName: "RightHandThumb2", controller: Controller.createInputController("Spatial", "joint_R_thumb3") },
|
||||
{ jointName: "RightHandThumb3", controller: Controller.createInputController("Spatial", "joint_R_thumb4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "RightHandIndex1", controller: Controller.createInputController("Spatial", "joint_R_index2") },
|
||||
{ jointName: "RightHandIndex2", controller: Controller.createInputController("Spatial", "joint_R_index3") },
|
||||
{ jointName: "RightHandIndex3", controller: Controller.createInputController("Spatial", "joint_R_index4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "RightHandMiddle1", controller: Controller.createInputController("Spatial", "joint_R_middle2") },
|
||||
{ jointName: "RightHandMiddle2", controller: Controller.createInputController("Spatial", "joint_R_middle3") },
|
||||
{ jointName: "RightHandMiddle3", controller: Controller.createInputController("Spatial", "joint_R_middle4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "RightHandRing1", controller: Controller.createInputController("Spatial", "joint_R_ring2") },
|
||||
{ jointName: "RightHandRing2", controller: Controller.createInputController("Spatial", "joint_R_ring3") },
|
||||
{ jointName: "RightHandRing3", controller: Controller.createInputController("Spatial", "joint_R_ring4") }
|
||||
],
|
||||
[
|
||||
{ jointName: "RightHandPinky1", controller: Controller.createInputController("Spatial", "joint_R_pinky2") },
|
||||
{ jointName: "RightHandPinky2", controller: Controller.createInputController("Spatial", "joint_R_pinky3") },
|
||||
{ jointName: "RightHandPinky3", controller: Controller.createInputController("Spatial", "joint_R_pinky4") }
|
||||
]
|
||||
];
|
||||
|
||||
handAnimationStateHandlers = [null, null];
|
||||
handAnimationStateFunctions = [animateLeftHand, animateRightHand];
|
||||
handAnimationStateProperties = [
|
||||
["leftHandType", "leftHandPosition", "leftHandRotation"],
|
||||
["rightHandType", "rightHandPosition", "rightHandPosition"]
|
||||
];
|
||||
|
||||
setIsOnHMD();
|
||||
|
||||
settingsTimer = Script.setInterval(checkSettings, 2000);
|
||||
|
||||
calibrationStatus = UNCALIBRATED;
|
||||
|
||||
{
|
||||
var mapping = Controller.newMapping("LeapmotionTrigger");
|
||||
mapping.from(getLeapMotionLeftTrigger).to(Controller.Standard.LT);
|
||||
mapping.from(getLeapMotionRightTrigger).to(Controller.Standard.RT);
|
||||
mapping.enable();
|
||||
}
|
||||
}
|
||||
|
||||
function moveHands() {
|
||||
var h,
|
||||
i,
|
||||
j,
|
||||
side,
|
||||
handOffset,
|
||||
wristOffset,
|
||||
handRotation,
|
||||
locRotation,
|
||||
cameraOrientation,
|
||||
inverseAvatarOrientation;
|
||||
|
||||
for (h = 0; h < NUM_HANDS; h += 1) {
|
||||
side = h === 0 ? -1.0 : 1.0;
|
||||
|
||||
if (hands[h].controller.isActive()) {
|
||||
|
||||
// Calibrate if necessary.
|
||||
if (!checkCalibration()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hand animation handlers ...
|
||||
if (handAnimationStateHandlers[h] === null) {
|
||||
handAnimationStateHandlers[h] = MyAvatar.addAnimationStateHandler(handAnimationStateFunctions[h],
|
||||
handAnimationStateProperties[h]);
|
||||
}
|
||||
|
||||
// Hand position ...
|
||||
handOffset = hands[h].controller.getAbsTranslation();
|
||||
handRotation = hands[h].controller.getAbsRotation();
|
||||
|
||||
if (isOnHMD) {
|
||||
|
||||
// Adjust to control wrist position if "hand" joint is at wrist ...
|
||||
if (!hasHandAndWristJoints) {
|
||||
wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]);
|
||||
handOffset = Vec3.sum(handOffset, wristOffset);
|
||||
}
|
||||
|
||||
// Hand offset in camera coordinates ...
|
||||
handOffset = {
|
||||
x: -handOffset.x,
|
||||
y: -handOffset.z,
|
||||
z: -handOffset.y - hands[h].zeroPosition.z
|
||||
};
|
||||
|
||||
// Hand offset in world coordinates ...
|
||||
cameraOrientation = Camera.getOrientation();
|
||||
handOffset = Vec3.sum(Camera.getPosition(), Vec3.multiplyQbyV(cameraOrientation, handOffset));
|
||||
|
||||
// Hand offset in avatar coordinates ...
|
||||
inverseAvatarOrientation = Quat.inverse(MyAvatar.orientation);
|
||||
handOffset = Vec3.subtract(handOffset, MyAvatar.position);
|
||||
handOffset = Vec3.multiplyQbyV(inverseAvatarOrientation, handOffset);
|
||||
handOffset.z = -handOffset.z;
|
||||
handOffset.x = -handOffset.x;
|
||||
|
||||
|
||||
// Hand rotation in camera coordinates ...
|
||||
handRotation = {
|
||||
x: -handRotation.y,
|
||||
y: -handRotation.z,
|
||||
z: -handRotation.x,
|
||||
w: handRotation.w
|
||||
};
|
||||
|
||||
// Hand rotation in avatar coordinates ...
|
||||
handRotation = Quat.multiply(HMD_CAMERA_TO_AVATAR_ROTATION[h], handRotation);
|
||||
cameraOrientation = {
|
||||
x: cameraOrientation.z,
|
||||
y: cameraOrientation.y,
|
||||
z: cameraOrientation.x,
|
||||
w: cameraOrientation.w
|
||||
};
|
||||
cameraOrientation = Quat.multiply(cameraOrientation, Quat.inverse(MyAvatar.orientation));
|
||||
handRotation = Quat.multiply(handRotation, cameraOrientation); // Works!!!
|
||||
|
||||
} else {
|
||||
|
||||
// Adjust to control wrist position if "hand" joint is at wrist ...
|
||||
if (!hasHandAndWristJoints) {
|
||||
wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]);
|
||||
handOffset = Vec3.sum(handOffset, wristOffset);
|
||||
}
|
||||
|
||||
// Hand offset in camera coordinates ...
|
||||
handOffset = {
|
||||
x: -handOffset.x,
|
||||
y: hands[h].zeroPosition.y + handOffset.y,
|
||||
z: hands[h].zeroPosition.z - handOffset.z
|
||||
};
|
||||
|
||||
// Hand rotation in camera coordinates ...
|
||||
handRotation = {
|
||||
x: handRotation.z,
|
||||
y: handRotation.y,
|
||||
z: handRotation.x,
|
||||
w: handRotation.w
|
||||
};
|
||||
|
||||
// Hand rotation in avatar coordinates ...
|
||||
handRotation = Quat.multiply(DESKTOP_CAMERA_TO_AVATAR_ROTATION, handRotation);
|
||||
}
|
||||
|
||||
// Set hand position and orientation for animation state handler ...
|
||||
hands[h].position = handOffset;
|
||||
hands[h].rotation = handRotation;
|
||||
|
||||
// Set finger joints ...
|
||||
var summed = 0;
|
||||
var closeAngle = 0;
|
||||
for (i = 0; i < NUM_FINGERS; i += 1) {
|
||||
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
|
||||
if (fingers[h][i][j].controller !== null) {
|
||||
locRotation = fingers[h][i][j].controller.getLocRotation();
|
||||
var eulers = Quat.safeEulerAngles(locRotation);
|
||||
closeAngle += eulers.x;
|
||||
|
||||
summed++;
|
||||
|
||||
if (i === THUMB) {
|
||||
locRotation = {
|
||||
x: side * locRotation.y,
|
||||
y: side * -locRotation.z,
|
||||
z: side * -locRotation.x,
|
||||
w: locRotation.w
|
||||
};
|
||||
if (j === 0) {
|
||||
// Adjust avatar thumb root joint rotation to make avatar hands look better
|
||||
locRotation = Quat.multiply(LEAP_THUMB_ROOT_ADJUST[h], locRotation);
|
||||
}
|
||||
} else {
|
||||
locRotation = {
|
||||
x: -locRotation.x,
|
||||
y: -locRotation.z,
|
||||
z: -locRotation.y,
|
||||
w: locRotation.w
|
||||
};
|
||||
}
|
||||
MyAvatar.setJointRotation(fingers[h][i][j].jointName, locRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hands[h].inactiveCount = 0;
|
||||
if (summed > 0) {
|
||||
closeAngle /= summed;
|
||||
}
|
||||
|
||||
var triggerValue = (-closeAngle - LEAP_TRIGGER_START_ANGLE) / (LEAP_TRIGGER_END_ANGLE - LEAP_TRIGGER_START_ANGLE);
|
||||
triggerValue = Math.max(0.0, Math.min(triggerValue, 1.0));
|
||||
|
||||
if (h == 0) {
|
||||
leftTriggerValue = triggerValue;
|
||||
} else {
|
||||
rightTriggerValue = triggerValue;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (hands[h].inactiveCount < MAX_HAND_INACTIVE_COUNT) {
|
||||
|
||||
hands[h].inactiveCount += 1;
|
||||
|
||||
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
|
||||
if (handAnimationStateHandlers[h] !== null) {
|
||||
MyAvatar.removeAnimationStateHandler(handAnimationStateHandlers[h]);
|
||||
handAnimationStateHandlers[h] = null;
|
||||
leftTriggerValue = 0.0;
|
||||
rightTriggerValue = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
var h,
|
||||
i,
|
||||
j;
|
||||
|
||||
Script.clearInterval(settingsTimer);
|
||||
|
||||
for (h = 0; h < NUM_HANDS; h += 1) {
|
||||
Controller.releaseInputController(hands[h].controller);
|
||||
Controller.releaseInputController(wrists[h].controller);
|
||||
if (handAnimationStateHandlers[h] !== null) {
|
||||
MyAvatar.removeAnimationStateHandler(handAnimationStateHandlers[h]);
|
||||
}
|
||||
for (i = 0; i < NUM_FINGERS; i += 1) {
|
||||
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
|
||||
if (fingers[h][i][j].controller !== null) {
|
||||
Controller.releaseInputController(fingers[h][i][j].controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
printSkeletonJointNames: printSkeletonJointNames,
|
||||
setUp : setUp,
|
||||
moveHands : moveHands,
|
||||
tearDown : tearDown
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
//leapHands.printSkeletonJointNames();
|
||||
|
||||
leapHands.setUp();
|
||||
Script.update.connect(leapHands.moveHands);
|
||||
Script.scriptEnding.connect(leapHands.tearDown);
|
Loading…
Reference in a new issue