Torque3D Documentation / _generateds / leapMotionDevice.cpp

leapMotionDevice.cpp

Engine/source/platform/input/leapMotion/leapMotionDevice.cpp

More...

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