Leap Motion input device support

This commit is contained in:
DavidWyand-GG 2013-01-23 14:38:13 -05:00
parent ecb592b908
commit 6105849df2
12 changed files with 2126 additions and 0 deletions

View file

@ -0,0 +1,34 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _LEAPMOTIONCONSTANTS_H_
#define _LEAPMOTIONCONSTANTS_H_
namespace LeapMotionConstants
{
enum Constants {
MaxHands = 2,
MaxPointablesPerHand = 5,
};
}
#endif // _LEAPMOTIONCONSTANTS_H_

View file

@ -0,0 +1,353 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/leapMotion/leapMotionData.h"
#include "platform/input/leapMotion/leapMotionUtil.h"
LeapMotionDeviceData::LeapMotionDeviceData()
{
reset();
}
void LeapMotionDeviceData::reset()
{
mDataSet = false;
mIsValid = false;
mHasTrackingData = false;
for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
{
mHandValid[i] = false;
for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
{
mPointableValid[i][j] = false;
}
}
}
void LeapMotionDeviceData::setData(const Leap::Frame& frame, LeapMotionDeviceData* prevData, bool keepHandIndexPersistent, bool keepPointableIndexPersistent, const F32& maxHandAxisRadius)
{
mIsValid = frame.isValid();
if(!mIsValid)
return;
// Determine if there is any valid tracking data
mHasTrackingData = frame.hands().count() > 0 || frame.pointables().count() > 0;
const Leap::HandList hands = frame.hands();
// Check if the hand index needs to persist between frames, but only if the
// previous data is valid
if(keepHandIndexPersistent && prevData && prevData->mDataSet && prevData->mIsValid)
{
processPersistentHands(frame.hands(), keepPointableIndexPersistent, prevData);
}
else
{
processHands(frame.hands());
}
// Single hand rotation as axis
if(mHandValid[0])
{
Point2F axis;
LeapMotionUtil::calculateHandAxisRotation(mHandRot[0], maxHandAxisRadius, axis);
mHandRotAxis[0] = axis.x;
mHandRotAxis[1] = axis.y;
}
else
{
// The first hand is not valid so we reset the axis rotation to none
mHandRotAxis[0] = 0.0f;
mHandRotAxis[1] = 0.0f;
}
// Store the current sequence number
mSequenceNum = frame.id();
mDataSet = true;
}
void LeapMotionDeviceData::processPersistentHands(const Leap::HandList& hands, bool keepPointableIndexPersistent, LeapMotionDeviceData* prevData)
{
S32 numHands = hands.count();
static S32 handDataIndex[LeapMotionConstants::MaxHands];
static bool handIndexUsed[LeapMotionConstants::MaxHands];
static Vector<S32> frameHandFound;
// Clear out our lookup arrays
for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
{
handDataIndex[i] = -1;
handIndexUsed[i] = false;
}
frameHandFound.setSize(numHands);
for(U32 i=0; i<numHands; ++i)
{
frameHandFound[i] = -1;
}
// Check if any hands this frame were picked up last frame
for(U32 i=0; i<numHands; ++i)
{
const Leap::Hand& hand = hands[i];
for(U32 j=0; j<LeapMotionConstants::MaxHands; ++j)
{
if(prevData && prevData->mHandValid[j] && hand.id() == prevData->mHandID[j])
{
handDataIndex[j] = i;
frameHandFound[i] = j;
}
}
}
// Process all hands that were present in the last frame
for(U32 i=0; i<numHands; ++i)
{
if(frameHandFound[i] != -1)
{
processHand(hands[i], frameHandFound[i], keepPointableIndexPersistent, prevData);
handIndexUsed[frameHandFound[i]] = true;
}
}
// Process all hands that were not present in the last frame
for(U32 i=0; i<numHands; ++i)
{
if(frameHandFound[i] != -1)
continue;
// Find the first hand data that has not yet been used
for(U32 j=0; j<LeapMotionConstants::MaxHands; ++j)
{
if(!handIndexUsed[j])
{
// Process this hand
processHand(hands[i], j, keepPointableIndexPersistent, prevData);
handIndexUsed[j] = true;
break;
}
}
}
// Finally, mark all hand data that has not been processed this frame as invalid
for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
{
if(!handIndexUsed[i])
{
mHandValid[i] = false;
}
}
}
void LeapMotionDeviceData::processHands(const Leap::HandList& hands)
{
S32 numHands = hands.count();
// Process all valid hands
S32 handsToProcess = getMin(numHands, LeapMotionConstants::MaxHands);
for(U32 i=0; i<handsToProcess; ++i)
{
processHand(hands[i], i, false, NULL);
}
// Take care of any hands that do not exist this frame
for(U32 i=handsToProcess; i<LeapMotionConstants::MaxHands; ++i)
{
mHandValid[i] = false;
}
}
void LeapMotionDeviceData::processHand(const Leap::Hand& hand, U32 handIndex, bool keepPointableIndexPersistent, LeapMotionDeviceData* prevData)
{
mHandValid[handIndex] = true;
mHandID[handIndex] = hand.id();
// Set the hand position
LeapMotionUtil::convertPosition(hand.palmPosition(), mHandRawPos[handIndex][0], mHandRawPos[handIndex][1], mHandRawPos[handIndex][2]);
mHandPos[handIndex][0] = (S32)mFloor(mHandRawPos[handIndex][0]);
mHandPos[handIndex][1] = (S32)mFloor(mHandRawPos[handIndex][1]);
mHandPos[handIndex][2] = (S32)mFloor(mHandRawPos[handIndex][2]);
mHandPosPoint[handIndex].set(mHandPos[handIndex][0], mHandPos[handIndex][1], mHandPos[handIndex][2]);
// Set the hand rotation
LeapMotionUtil::convertHandRotation(hand, mHandRot[handIndex]);
mHandRotQuat[handIndex].set(mHandRot[handIndex]);
// Process the pointables associated with this hand
if(keepPointableIndexPersistent)
{
processPersistentHandPointables(hand.pointables(), handIndex, prevData);
}
else
{
processHandPointables(hand.pointables(), handIndex);
}
}
void LeapMotionDeviceData::processPersistentHandPointables(const Leap::PointableList& pointables, U32 handIndex, LeapMotionDeviceData* prevData)
{
S32 numPointables = pointables.count();
static S32 pointableDataIndex[LeapMotionConstants::MaxPointablesPerHand];
static bool pointableIndexUsed[LeapMotionConstants::MaxPointablesPerHand];
static Vector<S32> framePointableFound;
// Clear out our lookup arrays
for(U32 i=0; i<LeapMotionConstants::MaxPointablesPerHand; ++i)
{
pointableDataIndex[i] = -1;
pointableIndexUsed[i] = false;
}
framePointableFound.setSize(numPointables);
for(U32 i=0; i<numPointables; ++i)
{
framePointableFound[i] = -1;
}
// Check if any pointables for this hand during this frame were picked
// up last frame
for(U32 i=0; i<numPointables; ++i)
{
const Leap::Pointable& pointable = pointables[i];
for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
{
if(prevData && prevData->mPointableValid[handIndex][j] && pointable.id() == prevData->mPointableID[handIndex][j])
{
pointableDataIndex[j] = i;
framePointableFound[i] = j;
}
}
}
// Process all hand pointables that were present in the last frame
for(U32 i=0; i<numPointables; ++i)
{
if(framePointableFound[i] != -1)
{
processHandPointable(pointables[i], handIndex, framePointableFound[i]);
pointableIndexUsed[framePointableFound[i]] = true;
}
}
// Process all hand pointables that were not present in the last frame
for(U32 i=0; i<numPointables; ++i)
{
if(framePointableFound[i] != -1)
continue;
// Find the first hand pointable data that has not yet been used
for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
{
if(!pointableIndexUsed[j])
{
// Process the pointable
processHandPointable(pointables[i], handIndex, j);
pointableIndexUsed[j] = true;
break;
}
}
}
// Finally, mark all hand pointable data that has not been process this frame as invalid
for(U32 i=0; i<LeapMotionConstants::MaxPointablesPerHand; ++i)
{
if(!pointableIndexUsed[i])
{
mPointableValid[handIndex][i] = false;
}
}
}
void LeapMotionDeviceData::processHandPointables(const Leap::PointableList& pointables, U32 handIndex)
{
// Process all pointables attached to the hand
S32 numPointables = pointables.count();
S32 pointablesToProcess = getMin(numPointables, LeapMotionConstants::MaxPointablesPerHand);
for(U32 i=0; i<pointablesToProcess; ++i)
{
processHandPointable(pointables[i], handIndex, i);
}
// Take care of any pointables that do not exist this frame
for(U32 i=pointablesToProcess; i<LeapMotionConstants::MaxPointablesPerHand; ++i)
{
mPointableValid[handIndex][i] = false;
}
}
void LeapMotionDeviceData::processHandPointable(const Leap::Pointable& pointable, U32 handIndex, U32 handPointableIndex)
{
mPointableValid[handIndex][handPointableIndex] = true;
mPointableID[handIndex][handPointableIndex] = pointable.id();
mPointableLength[handIndex][handPointableIndex] = pointable.length();
mPointableWidth[handIndex][handPointableIndex] = pointable.width();
// Set the pointable position
LeapMotionUtil::convertPosition(pointable.tipPosition(), mPointableRawPos[handIndex][handPointableIndex][0], mPointableRawPos[handIndex][handPointableIndex][1], mPointableRawPos[handIndex][handPointableIndex][2]);
mPointablePos[handIndex][handPointableIndex][0] = (S32)mFloor(mPointableRawPos[handIndex][handPointableIndex][0]);
mPointablePos[handIndex][handPointableIndex][1] = (S32)mFloor(mPointableRawPos[handIndex][handPointableIndex][1]);
mPointablePos[handIndex][handPointableIndex][2] = (S32)mFloor(mPointableRawPos[handIndex][handPointableIndex][2]);
mPointablePosPoint[handIndex][handPointableIndex].set(mPointablePos[handIndex][handPointableIndex][0], mPointablePos[handIndex][handPointableIndex][1], mPointablePos[handIndex][handPointableIndex][2]);
// Set the pointable rotation
LeapMotionUtil::convertPointableRotation(pointable, mPointableRot[handIndex][handPointableIndex]);
mPointableRotQuat[handIndex][handPointableIndex].set(mPointableRot[handIndex][handPointableIndex]);
}
U32 LeapMotionDeviceData::compare(LeapMotionDeviceData* other)
{
S32 result = DIFF_NONE;
// Check hand rotation as axis
if(mHandRotAxis[0] != other->mHandRotAxis[0] || !mDataSet)
{
result |= DIFF_HANDROTAXISX;
}
if(mHandRotAxis[1] != other->mHandRotAxis[1] || !mDataSet)
{
result |= DIFF_HANDROTAXISY;
}
return result;
}
U32 LeapMotionDeviceData::compareMeta(LeapMotionDeviceData* other)
{
S32 result = DIFF_NONE;
if(mHasTrackingData != other->mHasTrackingData || !mDataSet)
{
result |= METADIFF_FRAME_VALID_DATA;
}
return result;
}

View file

@ -0,0 +1,113 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _LEAPMOTIONDATA_H_
#define _LEAPMOTIONDATA_H_
#include "console/consoleTypes.h"
#include "math/mMathFn.h"
#include "math/mMatrix.h"
#include "math/mQuat.h"
#include "platform/input/leapMotion/leapMotionConstants.h"
#include "Leap.h"
struct LeapMotionDeviceData
{
enum DataDifferences {
DIFF_NONE = 0,
DIFF_HANDROTAXISX = (1<<1),
DIFF_HANDROTAXISY = (1<<2),
DIFF_HANDROTAXIS = (DIFF_HANDROTAXISX | DIFF_HANDROTAXISY),
};
enum MetaDataDifferences {
METADIFF_NONE = 0,
METADIFF_FRAME_VALID_DATA = (1<<0),
};
protected:
void processPersistentHands(const Leap::HandList& hands, bool keepPointableIndexPersistent, LeapMotionDeviceData* prevData);
void processHands(const Leap::HandList& hands);
void processHand(const Leap::Hand& hand, U32 handIndex, bool keepPointableIndexPersistent, LeapMotionDeviceData* prevData);
void processPersistentHandPointables(const Leap::PointableList& pointables, U32 handIndex, LeapMotionDeviceData* prevData);
void processHandPointables(const Leap::PointableList& pointables, U32 handIndex);
void processHandPointable(const Leap::Pointable& pointable, U32 handIndex, U32 handPointableIndex);
public:
bool mDataSet;
// Frame Data Set
bool mIsValid;
bool mHasTrackingData;
// Hand Data Set
bool mHandValid[LeapMotionConstants::MaxHands];
S32 mHandID[LeapMotionConstants::MaxHands];
// Hand Position
F32 mHandRawPos[LeapMotionConstants::MaxHands][3];
S32 mHandPos[LeapMotionConstants::MaxHands][3];
Point3F mHandPosPoint[LeapMotionConstants::MaxHands];
// Hand Rotation
MatrixF mHandRot[LeapMotionConstants::MaxHands];
QuatF mHandRotQuat[LeapMotionConstants::MaxHands];
// Hand rotation as axis x, y
F32 mHandRotAxis[2];
// Pointable Data Set
bool mPointableValid[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
S32 mPointableID[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
F32 mPointableLength[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
F32 mPointableWidth[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
// Pointable Position
F32 mPointableRawPos[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand][3];
S32 mPointablePos[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand][3];
Point3F mPointablePosPoint[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
// Pointable Rotation
MatrixF mPointableRot[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
QuatF mPointableRotQuat[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand];
// Sequence number from device
U64 mSequenceNum;
LeapMotionDeviceData();
/// Reset device data
void reset();
/// Set data based on Leap Motion device data
void setData(const Leap::Frame& frame, LeapMotionDeviceData* prevData, bool keepHandIndexPersistent, bool keepPointableIndexPersistent, const F32& maxHandAxisRadius);
/// Compare this data and given and return differences
U32 compare(LeapMotionDeviceData* other);
/// Compare meta data between this and given and return differences
U32 compareMeta(LeapMotionDeviceData* other);
};
#endif // _LEAPMOTIONDATA_H_

View file

@ -0,0 +1,364 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/leapMotion/leapMotionDevice.h"
#include "platform/input/leapMotion/leapMotionData.h"
#include "platform/input/leapMotion/leapMotionFrameStore.h"
#include "platform/platformInput.h"
#include "core/module.h"
#include "platform/threads/mutex.h"
#include "console/engineAPI.h"
MODULE_BEGIN( LeapMotionDevice )
MODULE_INIT_AFTER( InputEventManager )
MODULE_SHUTDOWN_BEFORE( InputEventManager )
MODULE_INIT
{
LeapMotionDevice::staticInit();
ManagedSingleton< LeapMotionDevice >::createSingleton();
if(LeapMotionDevice::smEnableDevice)
{
LEAPMOTIONDEV->enable();
}
// Register the device with the Input Event Manager
INPUTMGR->registerDevice(LEAPMOTIONDEV);
}
MODULE_SHUTDOWN
{
INPUTMGR->unregisterDevice(LEAPMOTIONDEV);
ManagedSingleton< LeapMotionDevice >::deleteSingleton();
}
MODULE_END;
//-----------------------------------------------------------------------------
// LeapMotionDevice
//-----------------------------------------------------------------------------
bool LeapMotionDevice::smEnableDevice = true;
bool LeapMotionDevice::smGenerateIndividualEvents = true;
bool LeapMotionDevice::smKeepHandIndexPersistent = false;
bool LeapMotionDevice::smKeepPointableIndexPersistent = false;
bool LeapMotionDevice::smGenerateSingleHandRotationAsAxisEvents = false;
F32 LeapMotionDevice::smMaximumHandAxisAngle = 25.0f;
bool LeapMotionDevice::smGenerateWholeFrameEvents = false;
U32 LeapMotionDevice::LM_FRAMEVALIDDATA = 0;
U32 LeapMotionDevice::LM_HAND[LeapMotionConstants::MaxHands] = {0};
U32 LeapMotionDevice::LM_HANDROT[LeapMotionConstants::MaxHands] = {0};
U32 LeapMotionDevice::LM_HANDAXISX = 0;
U32 LeapMotionDevice::LM_HANDAXISY = 0;
U32 LeapMotionDevice::LM_HANDPOINTABLE[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand] = {0};
U32 LeapMotionDevice::LM_HANDPOINTABLEROT[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand] = {0};
U32 LeapMotionDevice::LM_FRAME = 0;
LeapMotionDevice::LeapMotionDevice()
{
// From IInputDevice
dStrcpy(mName, "leapmotion");
mDeviceType = INPUTMGR->getNextDeviceType();
mController = NULL;
mListener = NULL;
mActiveMutex = Mutex::createMutex();
//
mEnabled = false;
mActive = false;
for(U32 i=0; i<2; ++i)
{
mDataBuffer[i] = new LeapMotionDeviceData();
}
mPrevData = mDataBuffer[0];
buildCodeTable();
}
LeapMotionDevice::~LeapMotionDevice()
{
disable();
Mutex::destroyMutex(mActiveMutex);
}
void LeapMotionDevice::staticInit()
{
Con::addVariable("pref::LeapMotion::EnableDevice", TypeBool, &smEnableDevice,
"@brief If true, the Leap Motion device will be enabled, if present.\n\n"
"@ingroup Game");
Con::addVariable("LeapMotion::GenerateIndividualEvents", TypeBool, &smGenerateIndividualEvents,
"@brief Indicates that events for each hand and pointable will be created.\n\n"
"@ingroup Game");
Con::addVariable("LeapMotion::KeepHandIndexPersistent", TypeBool, &smKeepHandIndexPersistent,
"@brief Indicates that we track hand IDs and will ensure that the same hand will remain at the same index between frames.\n\n"
"@ingroup Game");
Con::addVariable("LeapMotion::KeepPointableIndexPersistent", TypeBool, &smKeepPointableIndexPersistent,
"@brief Indicates that we track pointable IDs and will ensure that the same pointable will remain at the same index between frames.\n\n"
"@ingroup Game");
Con::addVariable("LeapMotion::GenerateSingleHandRotationAsAxisEvents", TypeBool, &smGenerateSingleHandRotationAsAxisEvents,
"@brief If true, broadcast single hand rotation as axis events.\n\n"
"@ingroup Game");
Con::addVariable("LeapMotion::MaximumHandAxisAngle", TypeF32, &smMaximumHandAxisAngle,
"@brief The maximum hand angle when used as an axis event as measured from a vector pointing straight up (in degrees).\n\n"
"Shoud range from 0 to 90 degrees.\n\n"
"@ingroup Game");
Con::addVariable("LeapMotion::GenerateWholeFrameEvents", TypeBool, &smGenerateWholeFrameEvents,
"@brief Indicates that a whole frame event should be generated and frames should be buffered.\n\n"
"@ingroup Game");
}
void LeapMotionDevice::buildCodeTable()
{
// Obtain all of the device codes
LM_FRAMEVALIDDATA = INPUTMGR->getNextDeviceCode();
for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
{
// Hands
LM_HAND[i] = INPUTMGR->getNextDeviceCode();
LM_HANDROT[i] = INPUTMGR->getNextDeviceCode();
// Pointables per hand
for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
{
LM_HANDPOINTABLE[i][j] = INPUTMGR->getNextDeviceCode();
LM_HANDPOINTABLEROT[i][j] = INPUTMGR->getNextDeviceCode();
}
}
LM_HANDAXISX = INPUTMGR->getNextDeviceCode();
LM_HANDAXISY = INPUTMGR->getNextDeviceCode();
LM_FRAME = INPUTMGR->getNextDeviceCode();
// Build out the virtual map
AddInputVirtualMap( lm_framevaliddata, SI_BUTTON, LM_FRAMEVALIDDATA );
char buffer[64];
for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
{
// Hands
dSprintf(buffer, 64, "lm_hand%d", i+1);
INPUTMGR->addVirtualMap( buffer, SI_POS, LM_HAND[i] );
dSprintf(buffer, 64, "lm_hand%drot", i+1);
INPUTMGR->addVirtualMap( buffer, SI_ROT, LM_HANDROT[i] );
// Pointables per hand
for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
{
dSprintf(buffer, 64, "lm_hand%dpoint%d", i+1, j+1);
INPUTMGR->addVirtualMap( buffer, SI_POS, LM_HANDPOINTABLE[i][j] );
dSprintf(buffer, 64, "lm_hand%dpoint%drot", i+1, j+1);
INPUTMGR->addVirtualMap( buffer, SI_POS, LM_HANDPOINTABLEROT[i][j] );
}
}
AddInputVirtualMap( lm_handaxisx, SI_AXIS, LM_HANDAXISX );
AddInputVirtualMap( lm_handaxisy, SI_AXIS, LM_HANDAXISY );
AddInputVirtualMap( lm_frame, SI_INT, LM_FRAME );
}
bool LeapMotionDevice::enable()
{
// Start off with disabling the device if it is already enabled
disable();
// Create the controller to talk with the Leap Motion along with the listener
mListener = new MotionListener();
mController = new Leap::Controller(*mListener);
// The device is now enabled but not yet ready to be used
mEnabled = true;
return false;
}
void LeapMotionDevice::disable()
{
if(mController)
{
delete mController;
mController = NULL;
if(mListener)
{
delete mListener;
mListener = NULL;
}
}
setActive(false);
mEnabled = false;
}
bool LeapMotionDevice::getActive()
{
Mutex::lockMutex(mActiveMutex);
bool active = mActive;
Mutex::unlockMutex(mActiveMutex);
return active;
}
void LeapMotionDevice::setActive(bool state)
{
Mutex::lockMutex(mActiveMutex);
mActive = state;
Mutex::unlockMutex(mActiveMutex);
}
bool LeapMotionDevice::process()
{
if(!mEnabled)
return false;
if(!getActive())
return false;
//Con::printf("LeapMotionDevice::process()");
//Build the maximum hand axis angle to be passed into the LeapMotionDeviceData::setData()
F32 maxHandAxisRadius = mSin(mDegToRad(smMaximumHandAxisAngle));
// Get a frame of data
const Leap::Frame frame = mController->frame();
//const Leap::HandList hands = frame.hands();
//Con::printf("Frame: %lld Hands: %d Fingers: %d Tools: %d", (long long)frame.id(), hands.count(), frame.fingers().count(), frame.tools().count());
// Store the current data
LeapMotionDeviceData* currentBuffer = (mPrevData == mDataBuffer[0]) ? mDataBuffer[1] : mDataBuffer[0];
currentBuffer->setData(frame, mPrevData, smKeepHandIndexPersistent, smKeepPointableIndexPersistent, maxHandAxisRadius);
U32 diff = mPrevData->compare(currentBuffer);
U32 metaDiff = mPrevData->compareMeta(currentBuffer);
// Update the previous data pointers. We do this here in case someone calls our
// console functions during one of the input events below.
mPrevData = currentBuffer;
// Send out any meta data
if(metaDiff & LeapMotionDeviceData::METADIFF_FRAME_VALID_DATA)
{
// Frame valid change event
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_BUTTON, LM_FRAMEVALIDDATA, currentBuffer->mHasTrackingData ? SI_MAKE : SI_BREAK, currentBuffer->mHasTrackingData ? 1.0f : 0.0f);
}
// Send out any valid data
if(currentBuffer->mDataSet && currentBuffer->mIsValid)
{
// Hands and their pointables
if(smGenerateIndividualEvents)
{
for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
{
if(currentBuffer->mHandValid[i])
{
// Send out position
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HAND[i], SI_MOVE, currentBuffer->mHandPosPoint[i]);
// Send out rotation
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDROT[i], SI_MOVE, currentBuffer->mHandRotQuat[i]);
// Pointables for hand
for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
{
if(currentBuffer->mPointableValid[i][j])
{
// Send out position
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HANDPOINTABLE[i][j], SI_MOVE, currentBuffer->mPointablePosPoint[i][j]);
// Send out rotation
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDPOINTABLEROT[i][j], SI_MOVE, currentBuffer->mPointableRotQuat[i][j]);
}
}
}
}
}
// Single Hand as axis rotation
if(smGenerateSingleHandRotationAsAxisEvents && diff & LeapMotionDeviceData::DIFF_HANDROTAXIS)
{
if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISX)
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISX, SI_MOVE, currentBuffer->mHandRotAxis[0]);
if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISY)
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISY, SI_MOVE, currentBuffer->mHandRotAxis[1]);
}
}
// Send out whole frame event, but only if the special frame group is defined
if(smGenerateWholeFrameEvents && LeapMotionFrameStore::isFrameGroupDefined())
{
S32 id = LEAPMOTIONFS->generateNewFrame(frame, maxHandAxisRadius);
if(id != 0)
{
INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_INT, LM_FRAME, SI_VALUE, id);
}
}
return true;
}
//-----------------------------------------------------------------------------
// LeapMotionDevice::MotionListener
//-----------------------------------------------------------------------------
void LeapMotionDevice::MotionListener::onConnect (const Leap::Controller &controller)
{
LEAPMOTIONDEV->setActive(true);
}
void LeapMotionDevice::MotionListener::onDisconnect (const Leap::Controller &controller)
{
LEAPMOTIONDEV->setActive(false);
}
//-----------------------------------------------------------------------------
DefineEngineFunction(isLeapMotionActive, bool, (),,
"@brief Used to determine if the Leap Motion input device is active\n\n"
"The Leap Motion input device is considered active when the support library has been "
"loaded and the device has been found.\n\n"
"@return True if the Leap Motion input device is active.\n"
"@ingroup Game")
{
if(!ManagedSingleton<LeapMotionDevice>::instanceOrNull())
{
return false;
}
return LEAPMOTIONDEV->getActive();
}

View file

@ -0,0 +1,138 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _LEAPMOTIONDEVICE_H_
#define _LEAPMOTIONDEVICE_H_
#include "platform/input/IInputDevice.h"
#include "platform/input/event.h"
#include "platformWin32/platformWin32.h"
#include "core/util/tSingleton.h"
#include "math/mQuat.h"
#include "platform/input/leapMotion/leapMotionConstants.h"
#include "Leap.h"
#define DEFAULT_MOTION_UNIT 0
struct LeapMotionDeviceData;
class LeapMotionDevice : public IInputDevice
{
protected:
class MotionListener : public Leap::Listener
{
public:
MotionListener() {}
virtual ~MotionListener() {}
virtual void onConnect (const Leap::Controller &controller);
virtual void onDisconnect (const Leap::Controller &controller);
};
/// The connection to the Leap Motion
Leap::Controller* mController;
/// Our Leap Motion listener class
MotionListener* mListener;
/// Used with the LM listener object
void* mActiveMutex;
/// Is the Leap Motion active
bool mActive;
/// Buffer to store data Leap Motion data in a Torque friendly way
LeapMotionDeviceData* mDataBuffer[2];
/// Points to the buffers that holds the previously collected data
LeapMotionDeviceData* mPrevData;
protected:
/// Build out the codes used for controller actions with the
/// Input Event Manager
void buildCodeTable();
public:
static bool smEnableDevice;
// Indicates that events for each hand and pointable will be created
static bool smGenerateIndividualEvents;
// Indicates that we track hand IDs and will ensure that the same hand
// will remain at the same index between frames.
static bool smKeepHandIndexPersistent;
// Indicates that we track pointable IDs and will ensure that the same
// pointable will remain at the same index between frames.
static bool smKeepPointableIndexPersistent;
// Broadcast single hand rotation as axis
static bool smGenerateSingleHandRotationAsAxisEvents;
// The maximum hand angle when used as an axis event
// as measured from a vector pointing straight up (in degrees)
static F32 smMaximumHandAxisAngle;
// Indicates that a whole frame event should be generated and frames
// should be buffered.
static bool smGenerateWholeFrameEvents;
// Frame action codes
static U32 LM_FRAMEVALIDDATA; // SI_BUTTON
// Hand action codes
static U32 LM_HAND[LeapMotionConstants::MaxHands]; // SI_POS
static U32 LM_HANDROT[LeapMotionConstants::MaxHands]; // SI_ROT
static U32 LM_HANDAXISX; // SI_AXIS
static U32 LM_HANDAXISY;
// Pointables action codes
static U32 LM_HANDPOINTABLE[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand]; // SI_POS
static U32 LM_HANDPOINTABLEROT[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand]; // SI_ROT
// Whole frame
static U32 LM_FRAME; // SI_INT
public:
LeapMotionDevice();
~LeapMotionDevice();
static void staticInit();
bool enable();
void disable();
bool getActive();
void setActive(bool state);
bool process();
public:
// For ManagedSingleton.
static const char* getSingletonName() { return "LeapMotionDevice"; }
};
/// Returns the LeapMotionDevice singleton.
#define LEAPMOTIONDEV ManagedSingleton<LeapMotionDevice>::instance()
#endif // _LEAPMOTIONDEVICE_H_

View file

@ -0,0 +1,497 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/leapMotion/leapMotionFrame.h"
#include "platform/input/leapMotion/leapMotionUtil.h"
#include "console/engineAPI.h"
#include "math/mAngAxis.h"
#include "math/mTransform.h"
U32 LeapMotionFrame::smNextInternalFrameId = 0;
IMPLEMENT_CONOBJECT(LeapMotionFrame);
ImplementEnumType( LeapMotionFramePointableType,
"Leap Motion pointable type.\n\n")
{ LeapMotionFrame::PT_UNKNOWN, "Unknown", "Unknown pointable type.\n" },
{ LeapMotionFrame::PT_FINGER, "Finger", "Finger pointable type.\n" },
{ LeapMotionFrame::PT_TOOL, "Tool", "Tool pointable type.\n" },
EndImplementEnumType;
LeapMotionFrame::LeapMotionFrame()
{
clear();
}
LeapMotionFrame::~LeapMotionFrame()
{
clear();
}
void LeapMotionFrame::initPersistFields()
{
Parent::initPersistFields();
}
bool LeapMotionFrame::onAdd()
{
if (!Parent::onAdd())
return false;
return true;
}
void LeapMotionFrame::onRemove()
{
Parent::onRemove();
}
void LeapMotionFrame::clear()
{
mFrameValid = false;
mHandCount = 0;
mHandValid.clear();
mHandId.clear();
mHandRawPos.clear();
mHandPos.clear();
mHandRot.clear();
mHandRotQuat.clear();
mHandRotAxis.clear();
mHandPointablesCount.clear();
mPointableCount = 0;
mPointableValid.clear();
mPointableId.clear();
mPointableHandIndex.clear();
mPointableType.clear();
mPointableRawPos.clear();
mPointablePos.clear();
mPointableRot.clear();
mPointableRotQuat.clear();
mPointableLength.clear();
mPointableWidth.clear();
}
void LeapMotionFrame::copyFromFrame(const Leap::Frame& frame, const F32& maxHandAxisRadius)
{
// This also resets all counters
clear();
// Retrieve frame information
mFrameValid = frame.isValid();
mFrameId = frame.id();
mFrameTimeStamp = frame.timestamp();
mFrameInternalId = smNextInternalFrameId;
++smNextInternalFrameId;
mFrameSimTime = Sim::getCurrentTime();
mFrameRealTime = Platform::getRealMilliseconds();
if(!mFrameValid)
{
return;
}
// Retrieve hand information
mHandCount = frame.hands().count();
if(mHandCount > 0)
{
copyFromFrameHands(frame.hands(), maxHandAxisRadius);
}
// Retrieve pointable information
mPointableCount = frame.pointables().count();
if(mPointableCount > 0)
{
copyFromFramePointables(frame.pointables());
}
}
void LeapMotionFrame::copyFromFrameHands(const Leap::HandList& hands, const F32& maxHandAxisRadius)
{
// Set up Vectors
mHandValid.increment(mHandCount);
mHandId.increment(mHandCount);
mHandRawPos.increment(mHandCount);
mHandPos.increment(mHandCount);
mHandRot.increment(mHandCount);
mHandRotQuat.increment(mHandCount);
mHandRotAxis.increment(mHandCount);
mHandPointablesCount.increment(mHandCount);
// Copy data
for(U32 i=0; i<mHandCount; ++i)
{
const Leap::Hand& hand = hands[i];
mHandValid[i] = hand.isValid();
mHandId[i] = hand.id();
// Position
LeapMotionUtil::convertPosition(hand.palmPosition(), mHandRawPos[i]);
mHandPos[i].x = (S32)mFloor(mHandRawPos[i].x);
mHandPos[i].y = (S32)mFloor(mHandRawPos[i].y);
mHandPos[i].z = (S32)mFloor(mHandRawPos[i].z);
// Rotation
LeapMotionUtil::convertHandRotation(hand, mHandRot[i]);
mHandRotQuat[i].set(mHandRot[i]);
// Thumb stick axis rotation
LeapMotionUtil::calculateHandAxisRotation(mHandRot[i], maxHandAxisRadius, mHandRotAxis[i]);
// Pointables
mHandPointablesCount[i] = hand.pointables().count();
}
}
void LeapMotionFrame::copyFromFramePointables(const Leap::PointableList& pointables)
{
// Set up Vectors
mPointableValid.increment(mPointableCount);
mPointableId.increment(mPointableCount);
mPointableHandIndex.increment(mPointableCount);
mPointableType.increment(mPointableCount);
mPointableRawPos.increment(mPointableCount);
mPointablePos.increment(mPointableCount);
mPointableRot.increment(mPointableCount);
mPointableRotQuat.increment(mPointableCount);
mPointableLength.increment(mPointableCount);
mPointableWidth.increment(mPointableCount);
// Copy data
for(U32 i=0; i<mPointableCount; ++i)
{
const Leap::Pointable& pointable = pointables[i];
mPointableValid[i] = pointable.isValid();
mPointableId[i] = pointable.id();
mPointableLength[i] = pointable.length();
mPointableWidth[i] = pointable.width();
mPointableType[i] = PT_UNKNOWN;
if(pointable.isFinger())
{
mPointableType[i] = PT_FINGER;
}
else if(pointable.isTool())
{
mPointableType[i] = PT_TOOL;
}
// Which hand, if any
const Leap::Hand& hand = pointable.hand();
if(hand.isValid())
{
bool found = false;
S32 handId = hand.id();
for(U32 j=0; j<mHandCount; ++j)
{
if(mHandId[j] == handId)
{
mPointableHandIndex[i] = j;
found = true;
break;
}
}
if(!found)
{
mPointableHandIndex[i] = -1;
}
}
else
{
mPointableHandIndex[i] = -1;
}
// Position
LeapMotionUtil::convertPosition(pointable.tipPosition(), mPointableRawPos[i]);
mPointablePos[i].x = (S32)mFloor(mPointableRawPos[i].x);
mPointablePos[i].y = (S32)mFloor(mPointableRawPos[i].y);
mPointablePos[i].z = (S32)mFloor(mPointableRawPos[i].z);
// Rotation
LeapMotionUtil::convertPointableRotation(pointable, mPointableRot[i]);
mPointableRotQuat[i].set(mPointableRot[i]);
}
}
//-----------------------------------------------------------------------------
DefineEngineMethod( LeapMotionFrame, isFrameValid, bool, ( ),,
"@brief Checks if this frame is valid.\n\n"
"@return True if the frame is valid.\n\n")
{
return object->isFrameValid();
}
DefineEngineMethod( LeapMotionFrame, getFrameInternalId, S32, ( ),,
"@brief Provides the internal ID for this frame.\n\n"
"@return Internal ID of this frame.\n\n")
{
return object->getFrameInternalId();
}
DefineEngineMethod( LeapMotionFrame, getFrameSimTime, S32, ( ),,
"@brief Get the sim time that this frame was generated.\n\n"
"@return Sim time of this frame in milliseconds.\n\n")
{
return object->getFrameSimTime();
}
DefineEngineMethod( LeapMotionFrame, getFrameRealTime, S32, ( ),,
"@brief Get the real time that this frame was generated.\n\n"
"@return Real time of this frame in milliseconds.\n\n")
{
return object->getFrameRealTime();
}
DefineEngineMethod( LeapMotionFrame, getHandCount, S32, ( ),,
"@brief Get the number of hands defined in this frame.\n\n"
"@return The number of defined hands.\n\n")
{
return object->getHandCount();
}
DefineEngineMethod( LeapMotionFrame, getHandValid, bool, ( S32 index ),,
"@brief Check if the requested hand is valid.\n\n"
"@param index The hand index to check.\n"
"@return True if the hand is valid.\n\n")
{
return object->getHandValid(index);
}
DefineEngineMethod( LeapMotionFrame, getHandId, S32, ( S32 index ),,
"@brief Get the ID of the requested hand.\n\n"
"@param index The hand index to check.\n"
"@return ID of the requested hand.\n\n")
{
return object->getHandId(index);
}
DefineEngineMethod( LeapMotionFrame, getHandRawPos, Point3F, ( S32 index ),,
"@brief Get the raw position of the requested hand.\n\n"
"The raw position is the hand's floating point position converted to "
"Torque 3D coordinates (in millimeters).\n"
"@param index The hand index to check.\n"
"@return Raw position of the requested hand.\n\n")
{
return object->getHandRawPos(index);
}
DefineEngineMethod( LeapMotionFrame, getHandPos, Point3I, ( S32 index ),,
"@brief Get the position of the requested hand.\n\n"
"The position is the hand's integer position converted to "
"Torque 3D coordinates (in millimeters).\n"
"@param index The hand index to check.\n"
"@return Integer position of the requested hand (in millimeters).\n\n")
{
return object->getHandPos(index);
}
DefineEngineMethod( LeapMotionFrame, getHandRot, AngAxisF, ( S32 index ),,
"@brief Get the rotation of the requested hand.\n\n"
"The Leap Motion hand rotation as converted into the Torque 3D"
"coordinate system.\n"
"@param index The hand index to check.\n"
"@return Rotation of the requested hand.\n\n")
{
AngAxisF aa(object->getHandRot(index));
return aa;
}
DefineEngineMethod( LeapMotionFrame, getHandRawTransform, TransformF, ( S32 index ),,
"@brief Get the raw transform of the requested hand.\n\n"
"@param index The hand index to check.\n"
"@return The raw position and rotation of the requested hand (in Torque 3D coordinates).\n\n")
{
const Point3F& pos = object->getHandRawPos(index);
const QuatF& qa = object->getHandRotQuat(index);
AngAxisF aa(qa);
aa.axis.normalize();
TransformF trans(pos, aa);
return trans;
}
DefineEngineMethod( LeapMotionFrame, getHandTransform, TransformF, ( S32 index ),,
"@brief Get the transform of the requested hand.\n\n"
"@param index The hand index to check.\n"
"@return The position and rotation of the requested hand (in Torque 3D coordinates).\n\n")
{
const Point3I& pos = object->getHandPos(index);
const QuatF& qa = object->getHandRotQuat(index);
AngAxisF aa(qa);
aa.axis.normalize();
TransformF trans;
trans.mPosition = Point3F(pos.x, pos.y, pos.z);
trans.mOrientation = aa;
return trans;
}
DefineEngineMethod( LeapMotionFrame, getHandRotAxis, Point2F, ( S32 index ),,
"@brief Get the axis rotation of the requested hand.\n\n"
"This is the axis rotation of the hand as if the hand were a gamepad thumb stick. "
"Imagine a stick coming out the top of the hand and tilting the hand front, back, "
"left and right controls that stick. The values returned along the x and y stick "
"axis are normalized from -1.0 to 1.0 with the maximum hand tilt angle for these "
"values as defined by $LeapMotion::MaximumHandAxisAngle.\n"
"@param index The hand index to check.\n"
"@return Axis rotation of the requested hand.\n\n"
"@see LeapMotion::MaximumHandAxisAngle\n")
{
return object->getHandRotAxis(index);
}
DefineEngineMethod( LeapMotionFrame, getHandPointablesCount, S32, ( S32 index ),,
"@brief Get the number of pointables associated with this hand.\n\n"
"@param index The hand index to check.\n"
"@return Number of pointables that belong with this hand.\n\n")
{
return object->getHandPointablesCount(index);
}
DefineEngineMethod( LeapMotionFrame, getPointablesCount, S32, ( ),,
"@brief Get the number of pointables defined in this frame.\n\n"
"@return The number of defined pointables.\n\n")
{
return object->getPointablesCount();
}
DefineEngineMethod( LeapMotionFrame, getPointableValid, bool, ( S32 index ),,
"@brief Check if the requested pointable is valid.\n\n"
"@param index The pointable index to check.\n"
"@return True if the pointable is valid.\n\n")
{
return object->getPointableValid(index);
}
DefineEngineMethod( LeapMotionFrame, getPointableId, S32, ( S32 index ),,
"@brief Get the ID of the requested pointable.\n\n"
"@param index The pointable index to check.\n"
"@return ID of the requested pointable.\n\n")
{
return object->getPointableId(index);
}
DefineEngineMethod( LeapMotionFrame, getPointableHandIndex, S32, ( S32 index ),,
"@brief Get the index of the hand that this pointable belongs to, if any.\n\n"
"@param index The pointable index to check.\n"
"@return Index of the hand this pointable belongs to, or -1 if there is no associated hand.\n\n")
{
return object->getPointableHandIndex(index);
}
DefineEngineMethod( LeapMotionFrame, getPointableType, LeapMotionFramePointableType, ( S32 index ),,
"@brief Get the type of the requested pointable.\n\n"
"@param index The pointable index to check.\n"
"@return Type of the requested pointable.\n\n")
{
return object->getPointableType(index);
}
DefineEngineMethod( LeapMotionFrame, getPointableRawPos, Point3F, ( S32 index ),,
"@brief Get the raw position of the requested pointable.\n\n"
"The raw position is the pointable's floating point position converted to "
"Torque 3D coordinates (in millimeters).\n"
"@param index The pointable index to check.\n"
"@return Raw position of the requested pointable.\n\n")
{
return object->getPointableRawPos(index);
}
DefineEngineMethod( LeapMotionFrame, getPointablePos, Point3I, ( S32 index ),,
"@brief Get the position of the requested pointable.\n\n"
"The position is the pointable's integer position converted to "
"Torque 3D coordinates (in millimeters).\n"
"@param index The pointable index to check.\n"
"@return Integer position of the requested pointable (in millimeters).\n\n")
{
return object->getPointablePos(index);
}
DefineEngineMethod( LeapMotionFrame, getPointableRot, AngAxisF, ( S32 index ),,
"@brief Get the rotation of the requested pointable.\n\n"
"The Leap Motion pointable rotation as converted into the Torque 3D"
"coordinate system.\n"
"@param index The pointable index to check.\n"
"@return Rotation of the requested pointable.\n\n")
{
AngAxisF aa(object->getPointableRot(index));
return aa;
}
DefineEngineMethod( LeapMotionFrame, getPointableRawTransform, TransformF, ( S32 index ),,
"@brief Get the raw transform of the requested pointable.\n\n"
"@param index The pointable index to check.\n"
"@return The raw position and rotation of the requested pointable (in Torque 3D coordinates).\n\n")
{
const Point3F& pos = object->getPointableRawPos(index);
const QuatF& qa = object->getPointableRotQuat(index);
AngAxisF aa(qa);
aa.axis.normalize();
TransformF trans(pos, aa);
return trans;
}
DefineEngineMethod( LeapMotionFrame, getPointableTransform, TransformF, ( S32 index ),,
"@brief Get the transform of the requested pointable.\n\n"
"@param index The pointable index to check.\n"
"@return The position and rotation of the requested pointable (in Torque 3D coordinates).\n\n")
{
const Point3I& pos = object->getPointablePos(index);
const QuatF& qa = object->getPointableRotQuat(index);
AngAxisF aa(qa);
aa.axis.normalize();
TransformF trans;
trans.mPosition = Point3F(pos.x, pos.y, pos.z);
trans.mOrientation = aa;
return trans;
}
DefineEngineMethod( LeapMotionFrame, getPointableLength, F32, ( S32 index ),,
"@brief Get the length of the requested pointable.\n\n"
"@param index The pointable index to check.\n"
"@return Length of the requested pointable (in millimeters).\n\n")
{
return object->getPointableLength(index);
}
DefineEngineMethod( LeapMotionFrame, getPointableWidth, F32, ( S32 index ),,
"@brief Get the width of the requested pointable.\n\n"
"@param index The pointable index to check.\n"
"@return Width of the requested pointable (in millimeters).\n\n")
{
return object->getPointableWidth(index);
}

View file

@ -0,0 +1,227 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _LEAPMOTIONFRAME_H_
#define _LEAPMOTIONFRAME_H_
#include "console/simObject.h"
#include "math/mPoint3.h"
#include "math/mMatrix.h"
#include "math/mQuat.h"
#include "Leap.h"
class LeapMotionFrame : public SimObject
{
typedef SimObject Parent;
public:
enum PointableType
{
PT_UNKNOWN = -1,
PT_FINGER = 0,
PT_TOOL,
};
protected:
static U32 smNextInternalFrameId;
// Frame
bool mFrameValid;
U64 mFrameId;
U64 mFrameTimeStamp;
// Torque 3D frame information
U32 mFrameInternalId;
S32 mFrameSimTime;
S32 mFrameRealTime;
// Hands
U32 mHandCount;
Vector<bool> mHandValid;
Vector<S32> mHandId;
Vector<Point3F> mHandRawPos;
Vector<Point3I> mHandPos;
Vector<MatrixF> mHandRot;
Vector<QuatF> mHandRotQuat;
Vector<Point2F> mHandRotAxis;
Vector<U32> mHandPointablesCount;
// Pointables
U32 mPointableCount;
Vector<bool> mPointableValid;
Vector<S32> mPointableId;
Vector<S32> mPointableHandIndex;
Vector<PointableType> mPointableType;
Vector<Point3F> mPointableRawPos;
Vector<Point3I> mPointablePos;
Vector<MatrixF> mPointableRot;
Vector<QuatF> mPointableRotQuat;
Vector<F32> mPointableLength;
Vector<F32> mPointableWidth;
protected:
void copyFromFrameHands(const Leap::HandList& hands, const F32& maxHandAxisRadius);
void copyFromFramePointables(const Leap::PointableList& pointables);
public:
LeapMotionFrame();
virtual ~LeapMotionFrame();
static void initPersistFields();
virtual bool onAdd();
virtual void onRemove();
void clear();
/// Copy a Leap Frame into our data structures
void copyFromFrame(const Leap::Frame& frame, const F32& maxHandAxisRadius);
// Frame
bool isFrameValid() const { return mFrameValid; }
U32 getFrameInternalId() const { return mFrameInternalId; }
S32 getFrameSimTime() const { return mFrameSimTime; }
S32 getFrameRealTime() const { return mFrameRealTime; }
// Hands
U32 getHandCount() const { return mHandCount; }
bool getHandValid(U32 index) const;
S32 getHandId(U32 index) const;
const Point3F& getHandRawPos(U32 index) const;
const Point3I& getHandPos(U32 index) const;
const MatrixF& getHandRot(U32 index) const;
const QuatF& getHandRotQuat(U32 index) const;
const Point2F& getHandRotAxis(U32 index) const;
U32 getHandPointablesCount(U32 index) const;
// Pointables
U32 getPointablesCount() const { return mPointableCount; }
bool getPointableValid(U32 index) const;
S32 getPointableId(U32 index) const;
S32 getPointableHandIndex(U32 index) const;
PointableType getPointableType(U32 index) const;
const Point3F& getPointableRawPos(U32 index) const;
const Point3I& getPointablePos(U32 index) const;
const MatrixF& getPointableRot(U32 index) const;
const QuatF& getPointableRotQuat(U32 index) const;
F32 getPointableLength(U32 index) const;
F32 getPointableWidth(U32 index) const;
DECLARE_CONOBJECT(LeapMotionFrame);
};
typedef LeapMotionFrame::PointableType LeapMotionFramePointableType;
DefineEnumType( LeapMotionFramePointableType );
//-----------------------------------------------------------------------------
inline bool LeapMotionFrame::getHandValid(U32 index) const
{
return (index < mHandCount && mHandValid[index]);
}
inline S32 LeapMotionFrame::getHandId(U32 index) const
{
return (index >= mHandCount) ? -1 : mHandId[index];
}
inline const Point3F& LeapMotionFrame::getHandRawPos(U32 index) const
{
return (index >= mHandCount) ? Point3F::Zero : mHandRawPos[index];
}
inline const Point3I& LeapMotionFrame::getHandPos(U32 index) const
{
return (index >= mHandCount) ? Point3I::Zero : mHandPos[index];
}
inline const MatrixF& LeapMotionFrame::getHandRot(U32 index) const
{
return (index >= mHandCount) ? MatrixF::Identity : mHandRot[index];
}
inline const QuatF& LeapMotionFrame::getHandRotQuat(U32 index) const
{
return (index >= mHandCount) ? QuatF::Identity : mHandRotQuat[index];
}
inline const Point2F& LeapMotionFrame::getHandRotAxis(U32 index) const
{
return (index >= mHandCount) ? Point2F::Zero : mHandRotAxis[index];
}
inline U32 LeapMotionFrame::getHandPointablesCount(U32 index) const
{
return (index >= mHandCount) ? 0 : mHandPointablesCount[index];
}
inline bool LeapMotionFrame::getPointableValid(U32 index) const
{
return (index < mPointableCount && mPointableValid[index]);
}
inline S32 LeapMotionFrame::getPointableId(U32 index) const
{
return (index >= mPointableCount) ? -1 : mPointableId[index];
}
inline S32 LeapMotionFrame::getPointableHandIndex(U32 index) const
{
return (index >= mPointableCount) ? -1 : mPointableHandIndex[index];
}
inline LeapMotionFrame::PointableType LeapMotionFrame::getPointableType(U32 index) const
{
return (index >= mPointableCount) ? PT_UNKNOWN : mPointableType[index];
}
inline const Point3F& LeapMotionFrame::getPointableRawPos(U32 index) const
{
return (index >= mPointableCount) ? Point3F::Zero : mPointableRawPos[index];
}
inline const Point3I& LeapMotionFrame::getPointablePos(U32 index) const
{
return (index >= mPointableCount) ? Point3I::Zero : mPointablePos[index];
}
inline const MatrixF& LeapMotionFrame::getPointableRot(U32 index) const
{
return (index >= mPointableCount) ? MatrixF::Identity : mPointableRot[index];
}
inline const QuatF& LeapMotionFrame::getPointableRotQuat(U32 index) const
{
return (index >= mPointableCount) ? QuatF::Identity : mPointableRotQuat[index];
}
inline F32 LeapMotionFrame::getPointableLength(U32 index) const
{
return (index >= mPointableCount) ? 0.0f : mPointableLength[index];
}
inline F32 LeapMotionFrame::getPointableWidth(U32 index) const
{
return (index >= mPointableCount) ? 0.0f : mPointableWidth[index];
}
#endif // _LEAPMOTIONFRAME_H_

View file

@ -0,0 +1,106 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/leapMotion/leapMotionFrameStore.h"
#include "platform/input/leapMotion/leapMotionFrame.h"
#include "core/module.h"
#include "console/simSet.h"
#include "console/consoleTypes.h"
MODULE_BEGIN( LeapMotionFrameStore )
MODULE_INIT_AFTER( LeapMotionDevice )
MODULE_INIT_AFTER( Sim )
MODULE_SHUTDOWN_BEFORE( Sim )
MODULE_SHUTDOWN_BEFORE( LeapMotionDevice )
MODULE_INIT
{
LeapMotionFrameStore::staticInit();
ManagedSingleton< LeapMotionFrameStore >::createSingleton();
}
MODULE_SHUTDOWN
{
ManagedSingleton< LeapMotionFrameStore >::deleteSingleton();
}
MODULE_END;
S32 LeapMotionFrameStore::smMaximumFramesStored = 30;
SimGroup* LeapMotionFrameStore::smFrameGroup = NULL;
LeapMotionFrameStore::LeapMotionFrameStore()
{
// Set up the SimGroup to store our frames
smFrameGroup = new SimGroup();
smFrameGroup->registerObject("LeapMotionFrameGroup");
smFrameGroup->setNameChangeAllowed(false);
Sim::getRootGroup()->addObject(smFrameGroup);
}
LeapMotionFrameStore::~LeapMotionFrameStore()
{
if(smFrameGroup)
{
smFrameGroup->deleteObject();
smFrameGroup = NULL;
}
}
void LeapMotionFrameStore::staticInit()
{
Con::addVariable("LeapMotion::MaximumFramesStored", TypeS32, &smMaximumFramesStored,
"@brief The maximum number of frames to keep when $LeapMotion::GenerateWholeFrameEvents is true.\n\n"
"@ingroup Game");
}
S32 LeapMotionFrameStore::generateNewFrame(const Leap::Frame& frame, const F32& maxHandAxisRadius)
{
// Make sure our group has been created
if(!smFrameGroup)
return 0;
// Either create a new frame object or pull one off the end
S32 frameID = 0;
if(smFrameGroup->size() >= smMaximumFramesStored)
{
// Make the last frame the first and update
LeapMotionFrame* frameObj = static_cast<LeapMotionFrame*>(smFrameGroup->last());
smFrameGroup->bringObjectToFront(frameObj);
frameObj->copyFromFrame(frame, maxHandAxisRadius);
frameID = frameObj->getId();
}
else
{
// Create a new frame and add it to the front of the list
LeapMotionFrame* frameObj = new LeapMotionFrame();
frameObj->registerObject();
smFrameGroup->addObject(frameObj);
smFrameGroup->bringObjectToFront(frameObj);
frameObj->copyFromFrame(frame, maxHandAxisRadius);
frameID = frameObj->getId();
}
return frameID;
}

View file

@ -0,0 +1,58 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _LEAPMOTIONFRAMESTORE_H_
#define _LEAPMOTIONFRAMESTORE_H_
#include "platformWin32/platformWin32.h"
#include "Leap.h"
class SimGroup;
class LeapMotionFrameStore
{
public:
// The maximum number of frames to keep
static S32 smMaximumFramesStored;
static SimGroup* smFrameGroup;
public:
LeapMotionFrameStore();
virtual ~LeapMotionFrameStore();
static void staticInit();
static bool isFrameGroupDefined() { return smFrameGroup != NULL; }
static SimGroup* getFrameGroup() { return smFrameGroup; }
S32 generateNewFrame(const Leap::Frame& frame, const F32& maxHandAxisRadius);
public:
// For ManagedSingleton.
static const char* getSingletonName() { return "LeapMotionFrameStore"; }
};
/// Returns the LeapMotionFrameStore singleton.
#define LEAPMOTIONFS ManagedSingleton<LeapMotionFrameStore>::instance()
#endif // _LEAPMOTIONFRAMESTORE_H_

View file

@ -0,0 +1,109 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/leapMotion/leapMotionUtil.h"
namespace LeapMotionUtil
{
void convertPosition(const Leap::Vector& inPosition, F32& x, F32& y, F32& z)
{
// Convert to Torque coordinates. The conversion is:
//
// Motion Torque
// x y z --> x -z y
x = inPosition.x; // x = x
y = -inPosition.z; // y = -z
z = inPosition.y; // z = y;
}
void convertPosition(const Leap::Vector& inPosition, Point3F& outPosition)
{
// Convert to Torque coordinates. The conversion is:
//
// Motion Torque
// x y z --> x -z y
outPosition.x = inPosition.x; // x = x
outPosition.y = -inPosition.z; // y = -z
outPosition.z = inPosition.y; // z = y;
}
void convertHandRotation(const Leap::Hand& hand, MatrixF& outRotation)
{
// We need to convert from Motion coordinates to
// Torque coordinates. The conversion is:
//
// Motion Torque
// a b c a b c a -c b
// d e f --> -g -h -i --> -g i -h
// g h i d e f d -f e
const Leap::Vector& handToFingers = hand.direction();
Leap::Vector handFront = -handToFingers;
const Leap::Vector& handDown = hand.palmNormal();
Leap::Vector handUp = -handDown;
Leap::Vector handRight = handUp.cross(handFront);
outRotation.setColumn(0, Point4F( handRight.x, -handRight.z, handRight.y, 0.0f));
outRotation.setColumn(1, Point4F( -handFront.x, handFront.z, -handFront.y, 0.0f));
outRotation.setColumn(2, Point4F( handUp.x, -handUp.z, handUp.y, 0.0f));
outRotation.setPosition(Point3F::Zero);
}
void calculateHandAxisRotation(const MatrixF& handRotation, const F32& maxHandAxisRadius, Point2F& outRotation)
{
const VectorF& controllerUp = handRotation.getUpVector();
outRotation.x = controllerUp.x;
outRotation.y = controllerUp.y;
// Limit the axis angle to that given to us
if(outRotation.len() > maxHandAxisRadius)
{
outRotation.normalize(maxHandAxisRadius);
}
// Renormalize to the range of 0..1
if(maxHandAxisRadius != 0.0f)
{
outRotation /= maxHandAxisRadius;
}
}
void convertPointableRotation(const Leap::Pointable& pointable, MatrixF& outRotation)
{
// We need to convert from Motion coordinates to
// Torque coordinates. The conversion is:
//
// Motion Torque
// a b c a b c a -c b
// d e f --> -g -h -i --> -g i -h
// g h i d e f d -f e
Leap::Vector pointableFront = -pointable.direction();
Leap::Vector pointableRight = Leap::Vector::up().cross(pointableFront);
Leap::Vector pointableUp = pointableFront.cross(pointableRight);
outRotation.setColumn(0, Point4F( pointableRight.x, -pointableRight.z, pointableRight.y, 0.0f));
outRotation.setColumn(1, Point4F( -pointableFront.x, pointableFront.z, -pointableFront.y, 0.0f));
outRotation.setColumn(2, Point4F( pointableUp.x, -pointableUp.z, pointableUp.y, 0.0f));
outRotation.setPosition(Point3F::Zero);
}
}

View file

@ -0,0 +1,48 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _LEAPMOTIONUTIL_H_
#define _LEAPMOTIONUTIL_H_
#include "math/mPoint3.h"
#include "math/mMatrix.h"
#include "Leap.h"
namespace LeapMotionUtil
{
/// Convert from a Leap Motion position to a Torque 3D position
void convertPosition(const Leap::Vector& inPosition, F32& x, F32& y, F32& z);
/// Convert from a Leap Motion position to a Torque 3D Point3F
void convertPosition(const Leap::Vector& inPosition, Point3F& outPosition);
/// Convert a Leap Motion hand's rotation to a Torque 3D matrix
void convertHandRotation(const Leap::Hand& hand, MatrixF& outRotation);
/// Calcualte a hand's rotation as if it were a thumb stick axis
void calculateHandAxisRotation(const MatrixF& handRotation, const F32& maxHandAxisRadius, Point2F& outRotation);
/// Convert a Leap Motion pointable's rotation to a Torque 3D matrix
void convertPointableRotation(const Leap::Pointable& pointable, MatrixF& outRotation);
}
#endif

View file

@ -0,0 +1,79 @@
<?php
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
beginModule( 'leapMotion' );
// Look for the optional global from the project.conf.
global $LEAPMOTION_SDK_PATH;
if (!$LEAPMOTION_SDK_PATH)
{
// First look for an environment var.
$LEAPMOTION_SDK_PATH = getenv( "TORQUE_LEAPMOTION_PATH" );
if (strlen($LEAPMOTION_SDK_PATH) == 0 || !file_exists($LEAPMOTION_SDK_PATH))
{
// Sometimes users get confused and use this var.
$LEAPMOTION_SDK_PATH = getenv( "LEAPMOTION_SDK_PATH" );
}
// We need forward slashes for paths.
$LEAPMOTION_SDK_PATH = str_replace( "\\", "/", $LEAPMOTION_SDK_PATH);
// Remove trailing slashes.
$LEAPMOTION_SDK_PATH = rtrim($LEAPMOTION_SDK_PATH, " /");
}
// If we still don't have the SDK path then let the user know.
if (!file_exists($LEAPMOTION_SDK_PATH))
{
trigger_error(
"\n*******************************************************************".
"\n".
"\n We were not able to find a valid path to the Leap Motion SDK!".
"\n".
"\n You must install the latest Sixense SDK and set the path via a".
"\n \$LEAPMOTION_SDK_PATH variable in your buildFiles/project.conf file".
"\n or by setting the TORQUE_LEAPMOTION_PATH system environment variable".
"\n (may require a reboot).".
"\n".
"\n*******************************************************************".
"\n", E_USER_ERROR );
}
// Only Windows is supported at this time
if ( Generator::$platform == "win32" )
{
// Source
addEngineSrcDir( "platform/input/leapMotion" );
// Includes
addIncludePath( $LEAPMOTION_SDK_PATH . "/include" );
// Libs
addProjectLibDir( $LEAPMOTION_SDK_PATH . "/lib/x86" );
addProjectLibInput( "Leap.lib", "Leapd.lib" );
}
endModule();
?>