leapMotionData.cpp
Engine/source/platform/input/leapMotion/leapMotionData.cpp
Detailed Description
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/leapMotionData.h" 25#include "platform/input/leapMotion/leapMotionUtil.h" 26 27LeapMotionDeviceData::LeapMotionDeviceData() 28{ 29 reset(); 30} 31 32void LeapMotionDeviceData::reset() 33{ 34 mDataSet = false; 35 36 mIsValid = false; 37 38 mHasTrackingData = false; 39 40 for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) 41 { 42 mHandValid[i] = false; 43 44 for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) 45 { 46 mPointableValid[i][j] = false; 47 } 48 } 49} 50 51void LeapMotionDeviceData::setData(const Leap::Frame& frame, LeapMotionDeviceData* prevData, bool keepHandIndexPersistent, bool keepPointableIndexPersistent, const F32& maxHandAxisRadius) 52{ 53 mIsValid = frame.isValid(); 54 if(!mIsValid) 55 return; 56 57 // Determine if there is any valid tracking data 58 mHasTrackingData = frame.hands().count() > 0 || frame.pointables().count() > 0; 59 60 const Leap::HandList hands = frame.hands(); 61 62 // Check if the hand index needs to persist between frames, but only if the 63 // previous data is valid 64 if(keepHandIndexPersistent && prevData && prevData->mDataSet && prevData->mIsValid) 65 { 66 processPersistentHands(frame.hands(), keepPointableIndexPersistent, prevData); 67 } 68 else 69 { 70 processHands(frame.hands()); 71 } 72 73 // Single hand rotation as axis 74 if(mHandValid[0]) 75 { 76 Point2F axis; 77 LeapMotionUtil::calculateHandAxisRotation(mHandRot[0], maxHandAxisRadius, axis); 78 79 mHandRotAxis[0] = axis.x; 80 mHandRotAxis[1] = axis.y; 81 } 82 else 83 { 84 // The first hand is not valid so we reset the axis rotation to none 85 mHandRotAxis[0] = 0.0f; 86 mHandRotAxis[1] = 0.0f; 87 } 88 89 // Store the current sequence number 90 mSequenceNum = frame.id(); 91 92 mDataSet = true; 93} 94 95void LeapMotionDeviceData::processPersistentHands(const Leap::HandList& hands, bool keepPointableIndexPersistent, LeapMotionDeviceData* prevData) 96{ 97 S32 numHands = hands.count(); 98 99 static S32 handDataIndex[LeapMotionConstants::MaxHands]; 100 static bool handIndexUsed[LeapMotionConstants::MaxHands]; 101 static Vector<S32> frameHandFound; 102 103 // Clear out our lookup arrays 104 for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) 105 { 106 handDataIndex[i] = -1; 107 handIndexUsed[i] = false; 108 } 109 frameHandFound.setSize(numHands); 110 for(U32 i=0; i<numHands; ++i) 111 { 112 frameHandFound[i] = -1; 113 } 114 115 // Check if any hands this frame were picked up last frame 116 for(U32 i=0; i<numHands; ++i) 117 { 118 const Leap::Hand& hand = hands[i]; 119 for(U32 j=0; j<LeapMotionConstants::MaxHands; ++j) 120 { 121 if(prevData && prevData->mHandValid[j] && hand.id() == prevData->mHandID[j]) 122 { 123 handDataIndex[j] = i; 124 frameHandFound[i] = j; 125 } 126 } 127 } 128 129 // Process all hands that were present in the last frame 130 for(U32 i=0; i<numHands; ++i) 131 { 132 if(frameHandFound[i] != -1) 133 { 134 processHand(hands[i], frameHandFound[i], keepPointableIndexPersistent, prevData); 135 handIndexUsed[frameHandFound[i]] = true; 136 } 137 } 138 139 // Process all hands that were not present in the last frame 140 for(U32 i=0; i<numHands; ++i) 141 { 142 if(frameHandFound[i] != -1) 143 continue; 144 145 // Find the first hand data that has not yet been used 146 for(U32 j=0; j<LeapMotionConstants::MaxHands; ++j) 147 { 148 if(!handIndexUsed[j]) 149 { 150 // Process this hand 151 processHand(hands[i], j, keepPointableIndexPersistent, prevData); 152 handIndexUsed[j] = true; 153 break; 154 } 155 } 156 } 157 158 // Finally, mark all hand data that has not been processed this frame as invalid 159 for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) 160 { 161 if(!handIndexUsed[i]) 162 { 163 mHandValid[i] = false; 164 } 165 } 166} 167 168void LeapMotionDeviceData::processHands(const Leap::HandList& hands) 169{ 170 S32 numHands = hands.count(); 171 172 // Process all valid hands 173 S32 handsToProcess = getMin(numHands, LeapMotionConstants::MaxHands); 174 for(U32 i=0; i<handsToProcess; ++i) 175 { 176 processHand(hands[i], i, false, NULL); 177 } 178 179 // Take care of any hands that do not exist this frame 180 for(U32 i=handsToProcess; i<LeapMotionConstants::MaxHands; ++i) 181 { 182 mHandValid[i] = false; 183 } 184} 185 186void LeapMotionDeviceData::processHand(const Leap::Hand& hand, U32 handIndex, bool keepPointableIndexPersistent, LeapMotionDeviceData* prevData) 187{ 188 mHandValid[handIndex] = true; 189 190 mHandID[handIndex] = hand.id(); 191 192 // Set the hand position 193 LeapMotionUtil::convertPosition(hand.palmPosition(), mHandRawPos[handIndex][0], mHandRawPos[handIndex][1], mHandRawPos[handIndex][2]); 194 mHandPos[handIndex][0] = (S32)mFloor(mHandRawPos[handIndex][0]); 195 mHandPos[handIndex][1] = (S32)mFloor(mHandRawPos[handIndex][1]); 196 mHandPos[handIndex][2] = (S32)mFloor(mHandRawPos[handIndex][2]); 197 198 mHandPosPoint[handIndex].set(mHandPos[handIndex][0], mHandPos[handIndex][1], mHandPos[handIndex][2]); 199 200 // Set the hand rotation 201 LeapMotionUtil::convertHandRotation(hand, mHandRot[handIndex]); 202 mHandRotQuat[handIndex].set(mHandRot[handIndex]); 203 204 // Process the pointables associated with this hand 205 if(keepPointableIndexPersistent) 206 { 207 processPersistentHandPointables(hand.pointables(), handIndex, prevData); 208 } 209 else 210 { 211 processHandPointables(hand.pointables(), handIndex); 212 } 213} 214 215void LeapMotionDeviceData::processPersistentHandPointables(const Leap::PointableList& pointables, U32 handIndex, LeapMotionDeviceData* prevData) 216{ 217 S32 numPointables = pointables.count(); 218 219 static S32 pointableDataIndex[LeapMotionConstants::MaxPointablesPerHand]; 220 static bool pointableIndexUsed[LeapMotionConstants::MaxPointablesPerHand]; 221 static Vector<S32> framePointableFound; 222 223 // Clear out our lookup arrays 224 for(U32 i=0; i<LeapMotionConstants::MaxPointablesPerHand; ++i) 225 { 226 pointableDataIndex[i] = -1; 227 pointableIndexUsed[i] = false; 228 } 229 framePointableFound.setSize(numPointables); 230 for(U32 i=0; i<numPointables; ++i) 231 { 232 framePointableFound[i] = -1; 233 } 234 235 // Check if any pointables for this hand during this frame were picked 236 // up last frame 237 for(U32 i=0; i<numPointables; ++i) 238 { 239 const Leap::Pointable& pointable = pointables[i]; 240 for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) 241 { 242 if(prevData && prevData->mPointableValid[handIndex][j] && pointable.id() == prevData->mPointableID[handIndex][j]) 243 { 244 pointableDataIndex[j] = i; 245 framePointableFound[i] = j; 246 } 247 } 248 } 249 250 // Process all hand pointables that were present in the last frame 251 for(U32 i=0; i<numPointables; ++i) 252 { 253 if(framePointableFound[i] != -1) 254 { 255 processHandPointable(pointables[i], handIndex, framePointableFound[i]); 256 pointableIndexUsed[framePointableFound[i]] = true; 257 } 258 } 259 260 // Process all hand pointables that were not present in the last frame 261 for(U32 i=0; i<numPointables; ++i) 262 { 263 if(framePointableFound[i] != -1) 264 continue; 265 266 // Find the first hand pointable data that has not yet been used 267 for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) 268 { 269 if(!pointableIndexUsed[j]) 270 { 271 // Process the pointable 272 processHandPointable(pointables[i], handIndex, j); 273 pointableIndexUsed[j] = true; 274 break; 275 } 276 } 277 } 278 279 // Finally, mark all hand pointable data that has not been process this frame as invalid 280 for(U32 i=0; i<LeapMotionConstants::MaxPointablesPerHand; ++i) 281 { 282 if(!pointableIndexUsed[i]) 283 { 284 mPointableValid[handIndex][i] = false; 285 } 286 } 287} 288 289void LeapMotionDeviceData::processHandPointables(const Leap::PointableList& pointables, U32 handIndex) 290{ 291 // Process all pointables attached to the hand 292 S32 numPointables = pointables.count(); 293 S32 pointablesToProcess = getMin(numPointables, LeapMotionConstants::MaxPointablesPerHand); 294 for(U32 i=0; i<pointablesToProcess; ++i) 295 { 296 processHandPointable(pointables[i], handIndex, i); 297 } 298 299 // Take care of any pointables that do not exist this frame 300 for(U32 i=pointablesToProcess; i<LeapMotionConstants::MaxPointablesPerHand; ++i) 301 { 302 mPointableValid[handIndex][i] = false; 303 } 304} 305 306void LeapMotionDeviceData::processHandPointable(const Leap::Pointable& pointable, U32 handIndex, U32 handPointableIndex) 307{ 308 mPointableValid[handIndex][handPointableIndex] = true; 309 310 mPointableID[handIndex][handPointableIndex] = pointable.id(); 311 mPointableLength[handIndex][handPointableIndex] = pointable.length(); 312 mPointableWidth[handIndex][handPointableIndex] = pointable.width(); 313 314 // Set the pointable position 315 LeapMotionUtil::convertPosition(pointable.tipPosition(), mPointableRawPos[handIndex][handPointableIndex][0], mPointableRawPos[handIndex][handPointableIndex][1], mPointableRawPos[handIndex][handPointableIndex][2]); 316 mPointablePos[handIndex][handPointableIndex][0] = (S32)mFloor(mPointableRawPos[handIndex][handPointableIndex][0]); 317 mPointablePos[handIndex][handPointableIndex][1] = (S32)mFloor(mPointableRawPos[handIndex][handPointableIndex][1]); 318 mPointablePos[handIndex][handPointableIndex][2] = (S32)mFloor(mPointableRawPos[handIndex][handPointableIndex][2]); 319 320 mPointablePosPoint[handIndex][handPointableIndex].set(mPointablePos[handIndex][handPointableIndex][0], mPointablePos[handIndex][handPointableIndex][1], mPointablePos[handIndex][handPointableIndex][2]); 321 322 // Set the pointable rotation 323 LeapMotionUtil::convertPointableRotation(pointable, mPointableRot[handIndex][handPointableIndex]); 324 mPointableRotQuat[handIndex][handPointableIndex].set(mPointableRot[handIndex][handPointableIndex]); 325} 326 327U32 LeapMotionDeviceData::compare(LeapMotionDeviceData* other) 328{ 329 S32 result = DIFF_NONE; 330 331 // Check hand rotation as axis 332 if(mHandRotAxis[0] != other->mHandRotAxis[0] || !mDataSet) 333 { 334 result |= DIFF_HANDROTAXISX; 335 } 336 if(mHandRotAxis[1] != other->mHandRotAxis[1] || !mDataSet) 337 { 338 result |= DIFF_HANDROTAXISY; 339 } 340 341 return result; 342} 343 344U32 LeapMotionDeviceData::compareMeta(LeapMotionDeviceData* other) 345{ 346 S32 result = DIFF_NONE; 347 348 if(mHasTrackingData != other->mHasTrackingData || !mDataSet) 349 { 350 result |= METADIFF_FRAME_VALID_DATA; 351 } 352 353 return result; 354} 355