leapMotionDevice.cpp
Engine/source/platform/input/leapMotion/leapMotionDevice.cpp
Public Variables
Public Functions
DefineEngineFunction(isLeapMotionActive , bool , () , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Leap Motion input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active\n\n</a>" "The Leap Motion input device is considered active when the support library has been " "loaded and the device has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">found.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Leap Motion input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active.\n</a>" "@ingroup Game" )
Detailed Description
Public Variables
MODULE_END
MODULE_INIT
MODULE_SHUTDOWN
Public Functions
DefineEngineFunction(isLeapMotionActive , bool , () , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Leap Motion input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active\n\n</a>" "The Leap Motion input device is considered active when the support library has been " "loaded and the device has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">found.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Leap Motion input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active.\n</a>" "@ingroup Game" )
if(LeapMotionDevice::smEnableDevice )
registerDevice(LEAPMOTIONDEV )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/input/leapMotion/leapMotionDevice.h" 25#include "platform/input/leapMotion/leapMotionData.h" 26#include "platform/input/leapMotion/leapMotionFrameStore.h" 27#include "platform/platformInput.h" 28#include "core/module.h" 29#include "platform/threads/mutex.h" 30#include "console/engineAPI.h" 31 32MODULE_BEGIN( LeapMotionDevice ) 33 34 MODULE_INIT_AFTER( InputEventManager ) 35 MODULE_SHUTDOWN_BEFORE( InputEventManager ) 36 37 MODULE_INIT 38 { 39 LeapMotionDevice::staticInit(); 40 ManagedSingleton< LeapMotionDevice >::createSingleton(); 41 if(LeapMotionDevice::smEnableDevice) 42 { 43 LEAPMOTIONDEV->enable(); 44 } 45 46 // Register the device with the Input Event Manager 47 INPUTMGR->registerDevice(LEAPMOTIONDEV); 48 } 49 50 MODULE_SHUTDOWN 51 { 52 INPUTMGR->unregisterDevice(LEAPMOTIONDEV); 53 ManagedSingleton< LeapMotionDevice >::deleteSingleton(); 54 } 55 56MODULE_END; 57 58//----------------------------------------------------------------------------- 59// LeapMotionDevice 60//----------------------------------------------------------------------------- 61 62bool LeapMotionDevice::smEnableDevice = true; 63 64bool LeapMotionDevice::smGenerateIndividualEvents = true; 65bool LeapMotionDevice::smKeepHandIndexPersistent = false; 66bool LeapMotionDevice::smKeepPointableIndexPersistent = false; 67 68bool LeapMotionDevice::smGenerateSingleHandRotationAsAxisEvents = false; 69 70F32 LeapMotionDevice::smMaximumHandAxisAngle = 25.0f; 71 72bool LeapMotionDevice::smGenerateWholeFrameEvents = false; 73 74U32 LeapMotionDevice::LM_FRAMEVALIDDATA = 0; 75U32 LeapMotionDevice::LM_HAND[LeapMotionConstants::MaxHands] = {0}; 76U32 LeapMotionDevice::LM_HANDROT[LeapMotionConstants::MaxHands] = {0}; 77U32 LeapMotionDevice::LM_HANDAXISX = 0; 78U32 LeapMotionDevice::LM_HANDAXISY = 0; 79U32 LeapMotionDevice::LM_HANDPOINTABLE[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand] = {0}; 80U32 LeapMotionDevice::LM_HANDPOINTABLEROT[LeapMotionConstants::MaxHands][LeapMotionConstants::MaxPointablesPerHand] = {0}; 81U32 LeapMotionDevice::LM_FRAME = 0; 82 83LeapMotionDevice::LeapMotionDevice() 84{ 85 // From IInputDevice 86 dStrcpy(mName, "leapmotion", 30); 87 mDeviceType = INPUTMGR->getNextDeviceType(); 88 89 mController = NULL; 90 mListener = NULL; 91 mActiveMutex = Mutex::createMutex(); 92 93 // 94 mEnabled = false; 95 mActive = false; 96 97 for(U32 i=0; i<2; ++i) 98 { 99 mDataBuffer[i] = new LeapMotionDeviceData(); 100 } 101 mPrevData = mDataBuffer[0]; 102 103 buildCodeTable(); 104} 105 106LeapMotionDevice::~LeapMotionDevice() 107{ 108 disable(); 109 110 Mutex::destroyMutex(mActiveMutex); 111} 112 113void LeapMotionDevice::staticInit() 114{ 115 Con::addVariable("pref::LeapMotion::EnableDevice", TypeBool, &smEnableDevice, 116 "@brief If true, the Leap Motion device will be enabled, if present.\n\n" 117 "@ingroup Game"); 118 119 Con::addVariable("LeapMotion::GenerateIndividualEvents", TypeBool, &smGenerateIndividualEvents, 120 "@brief Indicates that events for each hand and pointable will be created.\n\n" 121 "@ingroup Game"); 122 Con::addVariable("LeapMotion::KeepHandIndexPersistent", TypeBool, &smKeepHandIndexPersistent, 123 "@brief Indicates that we track hand IDs and will ensure that the same hand will remain at the same index between frames.\n\n" 124 "@ingroup Game"); 125 Con::addVariable("LeapMotion::KeepPointableIndexPersistent", TypeBool, &smKeepPointableIndexPersistent, 126 "@brief Indicates that we track pointable IDs and will ensure that the same pointable will remain at the same index between frames.\n\n" 127 "@ingroup Game"); 128 129 Con::addVariable("LeapMotion::GenerateSingleHandRotationAsAxisEvents", TypeBool, &smGenerateSingleHandRotationAsAxisEvents, 130 "@brief If true, broadcast single hand rotation as axis events.\n\n" 131 "@ingroup Game"); 132 Con::addVariable("LeapMotion::MaximumHandAxisAngle", TypeF32, &smMaximumHandAxisAngle, 133 "@brief The maximum hand angle when used as an axis event as measured from a vector pointing straight up (in degrees).\n\n" 134 "Shoud range from 0 to 90 degrees.\n\n" 135 "@ingroup Game"); 136 137 Con::addVariable("LeapMotion::GenerateWholeFrameEvents", TypeBool, &smGenerateWholeFrameEvents, 138 "@brief Indicates that a whole frame event should be generated and frames should be buffered.\n\n" 139 "@ingroup Game"); 140} 141 142void LeapMotionDevice::buildCodeTable() 143{ 144 // Obtain all of the device codes 145 LM_FRAMEVALIDDATA = INPUTMGR->getNextDeviceCode(); 146 147 for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) 148 { 149 // Hands 150 LM_HAND[i] = INPUTMGR->getNextDeviceCode(); 151 LM_HANDROT[i] = INPUTMGR->getNextDeviceCode(); 152 153 // Pointables per hand 154 for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) 155 { 156 LM_HANDPOINTABLE[i][j] = INPUTMGR->getNextDeviceCode(); 157 LM_HANDPOINTABLEROT[i][j] = INPUTMGR->getNextDeviceCode(); 158 } 159 } 160 161 LM_HANDAXISX = INPUTMGR->getNextDeviceCode(); 162 LM_HANDAXISY = INPUTMGR->getNextDeviceCode(); 163 164 LM_FRAME = INPUTMGR->getNextDeviceCode(); 165 166 // Build out the virtual map 167 AddInputVirtualMap( lm_framevaliddata, SI_BUTTON, LM_FRAMEVALIDDATA ); 168 169 char buffer[64]; 170 for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) 171 { 172 // Hands 173 dSprintf(buffer, 64, "lm_hand%d", i+1); 174 INPUTMGR->addVirtualMap( buffer, SI_POS, LM_HAND[i] ); 175 dSprintf(buffer, 64, "lm_hand%drot", i+1); 176 INPUTMGR->addVirtualMap( buffer, SI_ROT, LM_HANDROT[i] ); 177 178 // Pointables per hand 179 for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) 180 { 181 dSprintf(buffer, 64, "lm_hand%dpoint%d", i+1, j+1); 182 INPUTMGR->addVirtualMap( buffer, SI_POS, LM_HANDPOINTABLE[i][j] ); 183 dSprintf(buffer, 64, "lm_hand%dpoint%drot", i+1, j+1); 184 INPUTMGR->addVirtualMap( buffer, SI_POS, LM_HANDPOINTABLEROT[i][j] ); 185 } 186 } 187 188 AddInputVirtualMap( lm_handaxisx, SI_AXIS, LM_HANDAXISX ); 189 AddInputVirtualMap( lm_handaxisy, SI_AXIS, LM_HANDAXISY ); 190 191 AddInputVirtualMap( lm_frame, SI_INT, LM_FRAME ); 192} 193 194bool LeapMotionDevice::enable() 195{ 196 // Start off with disabling the device if it is already enabled 197 disable(); 198 199 // Create the controller to talk with the Leap Motion along with the listener 200 mListener = new MotionListener(); 201 mController = new Leap::Controller(*mListener); 202 203 // The device is now enabled but not yet ready to be used 204 mEnabled = true; 205 206 return false; 207} 208 209void LeapMotionDevice::disable() 210{ 211 if(mController) 212 { 213 delete mController; 214 mController = NULL; 215 216 if(mListener) 217 { 218 delete mListener; 219 mListener = NULL; 220 } 221 } 222 223 setActive(false); 224 mEnabled = false; 225} 226 227bool LeapMotionDevice::getActive() 228{ 229 Mutex::lockMutex(mActiveMutex); 230 bool active = mActive; 231 Mutex::unlockMutex(mActiveMutex); 232 233 return active; 234} 235 236void LeapMotionDevice::setActive(bool state) 237{ 238 Mutex::lockMutex(mActiveMutex); 239 mActive = state; 240 Mutex::unlockMutex(mActiveMutex); 241} 242 243bool LeapMotionDevice::process() 244{ 245 if(!mEnabled) 246 return false; 247 248 if(!getActive()) 249 return false; 250 251 //Con::printf("LeapMotionDevice::process()"); 252 253 //Build the maximum hand axis angle to be passed into the LeapMotionDeviceData::setData() 254 F32 maxHandAxisRadius = mSin(mDegToRad(smMaximumHandAxisAngle)); 255 256 // Get a frame of data 257 const Leap::Frame frame = mController->frame(); 258 259 //const Leap::HandList hands = frame.hands(); 260 //Con::printf("Frame: %lld Hands: %d Fingers: %d Tools: %d", (long long)frame.id(), hands.count(), frame.fingers().count(), frame.tools().count()); 261 262 // Store the current data 263 LeapMotionDeviceData* currentBuffer = (mPrevData == mDataBuffer[0]) ? mDataBuffer[1] : mDataBuffer[0]; 264 currentBuffer->setData(frame, mPrevData, smKeepHandIndexPersistent, smKeepPointableIndexPersistent, maxHandAxisRadius); 265 U32 diff = mPrevData->compare(currentBuffer); 266 U32 metaDiff = mPrevData->compareMeta(currentBuffer); 267 268 // Update the previous data pointers. We do this here in case someone calls our 269 // console functions during one of the input events below. 270 mPrevData = currentBuffer; 271 272 // Send out any meta data 273 if(metaDiff & LeapMotionDeviceData::METADIFF_FRAME_VALID_DATA) 274 { 275 // Frame valid change event 276 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_BUTTON, LM_FRAMEVALIDDATA, currentBuffer->mHasTrackingData ? SI_MAKE : SI_BREAK, currentBuffer->mHasTrackingData ? 1.0f : 0.0f); 277 } 278 279 // Send out any valid data 280 if(currentBuffer->mDataSet && currentBuffer->mIsValid) 281 { 282 // Hands and their pointables 283 if(smGenerateIndividualEvents) 284 { 285 for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) 286 { 287 if(currentBuffer->mHandValid[i]) 288 { 289 // Send out position 290 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HAND[i], SI_MOVE, currentBuffer->mHandPosPoint[i]); 291 292 // Send out rotation 293 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDROT[i], SI_MOVE, currentBuffer->mHandRotQuat[i]); 294 295 // Pointables for hand 296 for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) 297 { 298 if(currentBuffer->mPointableValid[i][j]) 299 { 300 // Send out position 301 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HANDPOINTABLE[i][j], SI_MOVE, currentBuffer->mPointablePosPoint[i][j]); 302 303 // Send out rotation 304 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDPOINTABLEROT[i][j], SI_MOVE, currentBuffer->mPointableRotQuat[i][j]); 305 } 306 } 307 } 308 } 309 } 310 311 // Single Hand as axis rotation 312 if(smGenerateSingleHandRotationAsAxisEvents && diff & LeapMotionDeviceData::DIFF_HANDROTAXIS) 313 { 314 if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISX) 315 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISX, SI_MOVE, currentBuffer->mHandRotAxis[0]); 316 if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISY) 317 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISY, SI_MOVE, currentBuffer->mHandRotAxis[1]); 318 } 319 } 320 321 // Send out whole frame event, but only if the special frame group is defined 322 if(smGenerateWholeFrameEvents && LeapMotionFrameStore::isFrameGroupDefined()) 323 { 324 S32 id = LEAPMOTIONFS->generateNewFrame(frame, maxHandAxisRadius); 325 if(id != 0) 326 { 327 INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_INT, LM_FRAME, SI_VALUE, id); 328 } 329 } 330 331 return true; 332} 333 334//----------------------------------------------------------------------------- 335// LeapMotionDevice::MotionListener 336//----------------------------------------------------------------------------- 337 338void LeapMotionDevice::MotionListener::onConnect (const Leap::Controller &controller) 339{ 340 LEAPMOTIONDEV->setActive(true); 341} 342 343void LeapMotionDevice::MotionListener::onDisconnect (const Leap::Controller &controller) 344{ 345 LEAPMOTIONDEV->setActive(false); 346} 347//----------------------------------------------------------------------------- 348 349DefineEngineFunction(isLeapMotionActive, bool, (),, 350 "@brief Used to determine if the Leap Motion input device is active\n\n" 351 352 "The Leap Motion input device is considered active when the support library has been " 353 "loaded and the device has been found.\n\n" 354 355 "@return True if the Leap Motion input device is active.\n" 356 357 "@ingroup Game") 358{ 359 if(!ManagedSingleton<LeapMotionDevice>::instanceOrNull()) 360 { 361 return false; 362 } 363 364 return LEAPMOTIONDEV->getActive(); 365} 366