mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-13 11:43:49 +00:00
Leap Motion input device support
This commit is contained in:
parent
ecb592b908
commit
6105849df2
12 changed files with 2126 additions and 0 deletions
353
Engine/source/platform/input/leapMotion/leapMotionData.cpp
Normal file
353
Engine/source/platform/input/leapMotion/leapMotionData.cpp
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue