mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 04:34:48 +00:00
365 lines
13 KiB
C++
365 lines
13 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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();
|
|
}
|