diff --git a/Engine/source/platform/input/leapMotion/leapMotionConstants.h b/Engine/source/platform/input/leapMotion/leapMotionConstants.h new file mode 100644 index 000000000..59f6b18e6 --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionConstants.h @@ -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_ diff --git a/Engine/source/platform/input/leapMotion/leapMotionData.cpp b/Engine/source/platform/input/leapMotion/leapMotionData.cpp new file mode 100644 index 000000000..83276aa01 --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionData.cpp @@ -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 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 frameHandFound; + + // Clear out our lookup arrays + for(U32 i=0; imHandValid[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 framePointableFound; + + // Clear out our lookup arrays + for(U32 i=0; imPointableValid[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; imHandRotAxis[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; +} diff --git a/Engine/source/platform/input/leapMotion/leapMotionData.h b/Engine/source/platform/input/leapMotion/leapMotionData.h new file mode 100644 index 000000000..34e9d6ecf --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionData.h @@ -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_ diff --git a/Engine/source/platform/input/leapMotion/leapMotionDevice.cpp b/Engine/source/platform/input/leapMotion/leapMotionDevice.cpp new file mode 100644 index 000000000..5e4aef681 --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionDevice.cpp @@ -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; igetNextDeviceCode(); + LM_HANDROT[i] = INPUTMGR->getNextDeviceCode(); + + // Pointables per hand + for(U32 j=0; jgetNextDeviceCode(); + 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; iaddVirtualMap( 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; jaddVirtualMap( 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; imHandValid[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; jmPointableValid[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::instanceOrNull()) + { + return false; + } + + return LEAPMOTIONDEV->getActive(); +} diff --git a/Engine/source/platform/input/leapMotion/leapMotionDevice.h b/Engine/source/platform/input/leapMotion/leapMotionDevice.h new file mode 100644 index 000000000..2f1542fda --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionDevice.h @@ -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::instance() + +#endif // _LEAPMOTIONDEVICE_H_ diff --git a/Engine/source/platform/input/leapMotion/leapMotionFrame.cpp b/Engine/source/platform/input/leapMotion/leapMotionFrame.cpp new file mode 100644 index 000000000..0f1cf672d --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionFrame.cpp @@ -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; iisFrameValid(); +} + +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); +} diff --git a/Engine/source/platform/input/leapMotion/leapMotionFrame.h b/Engine/source/platform/input/leapMotion/leapMotionFrame.h new file mode 100644 index 000000000..eeefb0843 --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionFrame.h @@ -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 mHandValid; + Vector mHandId; + Vector mHandRawPos; + Vector mHandPos; + Vector mHandRot; + Vector mHandRotQuat; + Vector mHandRotAxis; + Vector mHandPointablesCount; + + // Pointables + U32 mPointableCount; + Vector mPointableValid; + Vector mPointableId; + Vector mPointableHandIndex; + Vector mPointableType; + Vector mPointableRawPos; + Vector mPointablePos; + Vector mPointableRot; + Vector mPointableRotQuat; + Vector mPointableLength; + Vector 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_ diff --git a/Engine/source/platform/input/leapMotion/leapMotionFrameStore.cpp b/Engine/source/platform/input/leapMotion/leapMotionFrameStore.cpp new file mode 100644 index 000000000..77f40485d --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionFrameStore.cpp @@ -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(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; +} diff --git a/Engine/source/platform/input/leapMotion/leapMotionFrameStore.h b/Engine/source/platform/input/leapMotion/leapMotionFrameStore.h new file mode 100644 index 000000000..8576ad52d --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionFrameStore.h @@ -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::instance() + +#endif // _LEAPMOTIONFRAMESTORE_H_ diff --git a/Engine/source/platform/input/leapMotion/leapMotionUtil.cpp b/Engine/source/platform/input/leapMotion/leapMotionUtil.cpp new file mode 100644 index 000000000..12dc42acc --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionUtil.cpp @@ -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); +} + +} diff --git a/Engine/source/platform/input/leapMotion/leapMotionUtil.h b/Engine/source/platform/input/leapMotion/leapMotionUtil.h new file mode 100644 index 000000000..a2eeaed2a --- /dev/null +++ b/Engine/source/platform/input/leapMotion/leapMotionUtil.h @@ -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 diff --git a/Tools/projectGenerator/modules/leapMotion.inc b/Tools/projectGenerator/modules/leapMotion.inc new file mode 100644 index 000000000..06377c681 --- /dev/null +++ b/Tools/projectGenerator/modules/leapMotion.inc @@ -0,0 +1,79 @@ +