00001
00002
00003
00004
00005
00006
00007
00008 #include "LeapScene.h"
00009 #include <cfloat>
00010 #include <cstring>
00011
00012 namespace Leap {
00013
00014 using namespace LeapUtil;
00015
00016 #if defined(LEAP_SCENE_USE_UTIL_GL)
00017 using namespace LeapUtilGL;
00018 #endif
00019
00020
00021
00022
00023
00024
00025
00026 Scene::Scene()
00027 : m_pUserData( NULL ),
00028 m_fDeltaTimeSeconds( 0.0f ),
00029 m_fPointableRadius( 1.0f ),
00030 m_fSelectHitTime( 1.0f ),
00031 m_uiNumObjects( 0 ),
00032 m_uiNumRayHits( 0 ),
00033 m_uiNumQueuedInteractions( 0 ),
00034 m_uiNumPendingRemovals( 0 ),
00035 m_uiNextSerial( 0 ),
00036 m_uiFlags( kF_UpdateRayCast | kF_UpdateContact )
00037 {
00038 memset( m_apObjects, 0, sizeof(m_apObjects) );
00039 }
00040
00041 void Scene::RemoveObject( SceneObject* pObject )
00042 {
00043 if ( pObject && (pObject->m_pScene == this) && !pObject->m_bPendingRemoval )
00044 {
00045 pObject->m_bPendingRemoval = true;
00046 m_uiNumPendingRemovals++;
00047 }
00048 }
00049
00050 void Scene::Reset()
00051 {
00052 for ( uint32_t i = 0; i < m_uiNumObjects; i++ )
00053 {
00054 if ( SceneObject* pObj = m_apObjects[i] )
00055 {
00056 pObj->m_pScene = NULL;
00057 pObj->m_index = kMaxObjects;
00058 }
00059
00060 m_apObjects[i].Release();
00061 }
00062
00063 m_uiNumObjects = 0;
00064 m_uiNumPendingRemovals = 0;
00065
00066 clearInteractionQueue();
00067 clearRayHits();
00068 }
00069
00070 void Scene::Update(const Frame& frame, float fDeltaTimeSeconds)
00071 {
00072 m_fDeltaTimeSeconds = fDeltaTimeSeconds;
00073
00074 clearRayHits();
00075
00076 clearInteractionQueue();
00077
00078 processPendingRemovals();
00079
00080 updateSelectionAndContact( frame );
00081
00082 updateInteraction( frame );
00083 }
00084
00085 void Scene::DeselectAll()
00086 {
00087 SceneInteraction deselection;
00088 deselection.m_uiFlags = kIT_SelectionChange;
00089
00090 for (size_t i=0; i < m_uiNumObjects; i++)
00091 {
00092 m_apObjects[i]->SetSelected( false );
00093 }
00094 }
00095
00096 const SceneObjectPtr& Scene::TestRayHit( const SceneRay& ray ) const
00097 {
00098 float fClosestHitDist = FLT_MAX;
00099 int closestHitIndex = -1;
00100
00101 for (uint32_t i = 0; i < m_uiNumObjects; i++)
00102 {
00103 float fHitDist = FLT_MAX;
00104 if (m_apObjects[i]->TestRayHit(ray, fHitDist) && (fHitDist < fClosestHitDist) )
00105 {
00106 closestHitIndex = static_cast<int>(i);
00107 fClosestHitDist = fHitDist;
00108 }
00109 }
00110
00111 if (closestHitIndex >= 0)
00112 {
00113 return m_apObjects[closestHitIndex];
00114 }
00115
00116 return SceneObjectPtr::Null();
00117 }
00118
00119 #if defined(LEAP_SCENE_USE_UTIL_GL)
00120 void Scene::RayHitsDebugDrawGL() const
00121 {
00122 GLAttribScope attribScope( GL_CURRENT_BIT | GL_LIGHTING_BIT );
00123
00124 glDisable( GL_LIGHTING );
00125 glColor3f(1, 1, 1);
00126
00127 const float fHitSphereSize = m_fPointableRadius * 0.3f;
00128
00129 for ( uint32_t i = 0, e = GetNumRayHits(); i < e; i++ )
00130 {
00131 const SceneRayHit& rayHit = m_aRayHits[i];
00132 rayHit.DebugDrawGL( fHitSphereSize );
00133 }
00134 }
00135 #endif // LEAP_SCENE_USE_UTIL_GL
00136
00137
00138
00139
00140
00141
00142
00143 void Scene::deallocateObject( uint32_t idxToRemove )
00144 {
00145 if ( SceneObject* pObjToRemove = (idxToRemove < m_uiNumObjects) ? m_apObjects[idxToRemove].GetPointer() : NULL )
00146 {
00147 m_uiNumObjects--;
00148
00149
00150 pObjToRemove->m_pScene = NULL;
00151
00152
00153 pObjToRemove->m_index = static_cast<uint32_t>(kMaxObjects);
00154
00155
00156 if ( idxToRemove != m_uiNumObjects )
00157 {
00158
00159
00160 m_apObjects[idxToRemove] = m_apObjects[m_uiNumObjects];
00161
00162
00163 m_apObjects[idxToRemove]->m_index = static_cast<uint16_t>(idxToRemove);
00164
00165
00166 m_apObjects[m_uiNumObjects].Release();
00167 }
00168 else
00169 {
00170
00171 m_apObjects[idxToRemove].Release();
00172 }
00173
00174 }
00175 }
00176
00177 bool Scene::testRayHitClosest( SceneRayHit& hitResult )
00178 {
00179 float fClosestHitDist = FLT_MAX;
00180 int closestHitIndex = -1;
00181
00182 for (uint32_t i = 0; i < m_uiNumObjects; i++)
00183 {
00184 float fHitDist = FLT_MAX;
00185 if (m_apObjects[i]->TestRayHit(hitResult.m_ray, fHitDist) && (fHitDist < fClosestHitDist) )
00186 {
00187 closestHitIndex = static_cast<int>(i);
00188 fClosestHitDist = fHitDist;
00189 }
00190 }
00191
00192 if (closestHitIndex >= 0)
00193 {
00194 hitResult.m_fHitDistance = fClosestHitDist;
00195 hitResult.m_pHitObject = m_apObjects[closestHitIndex];
00196 hitResult.m_hitPoint = hitResult.m_ray.CalcPointOn( hitResult.m_fHitDistance );
00197
00198 m_apObjects[closestHitIndex]->IncNumPointing();
00199
00200 m_apObjects[closestHitIndex]->m_fTotalHitTime += m_fDeltaTimeSeconds;
00201
00202 return true;
00203 }
00204
00205 return false;
00206 }
00207
00208 void Scene::updateContact( const SceneContactPoint& testPoint )
00209 {
00210 for (size_t i=0; i < m_uiNumObjects; i++)
00211 {
00212 if ( m_apObjects[i]->TestSphereHit( testPoint.m_vPoint, m_fPointableRadius ) )
00213 {
00214 m_apObjects[i]->IncNumContacts( testPoint );
00215 m_apObjects[i]->m_fTotalHitTime += m_fDeltaTimeSeconds;
00216 }
00217 }
00218 }
00219
00220 void Scene::updateSelectionAndContact( const Frame& frame )
00221 {
00222 const PointableList& pointables = frame.pointables();
00223
00224 if ( pointables.isEmpty() && frame.hands().isEmpty() )
00225 {
00226 queueDeselectAll();
00227 }
00228
00229 for ( uint32_t j = 0, numPointables = pointables.count(); j < numPointables; j++ )
00230 {
00231 const Pointable& pointable = pointables[j];
00232 const Vector vPos = TransformFramePoint( pointable.tipPosition() );
00233 const int iPointableID = pointable.id();
00234
00235 if ( GetUpdateRayCast() && (m_uiNumRayHits < static_cast<uint32_t>(kMaxRayHits)) )
00236 {
00237 SceneRayHit& rayHit = m_aRayHits[m_uiNumRayHits];
00238
00239 rayHit.m_ray = SceneRay( vPos, TransformFrameDirection( pointable.direction() ) );
00240 rayHit.m_iPointableID = iPointableID;
00241
00242 if ( testRayHitClosest( rayHit ) )
00243 {
00244 m_uiNumRayHits++;
00245 }
00246 }
00247
00248 if ( GetUpdateContact() )
00249 {
00250 updateContact( SceneContactPoint( vPos, iPointableID ) );
00251 }
00252 }
00253 }
00254
00255 void Scene::updateInteraction( const Frame& frame )
00256 {
00257 static const uint8_t kMaxContactMissedFrames = 64;
00258
00259 (void)frame;
00260
00261 for (size_t i=0; i < m_uiNumObjects; i++)
00262 {
00263 const SceneObjectPtr& pObj = m_apObjects[i];
00264
00265 if (!pObj->HasInitialContact() && pObj->GetNumContacts() == 0 && pObj->GetNumPointing() == 0)
00266 {
00267 pObj->m_fTotalHitTime = 0.0f;
00268 }
00270 else if ( !pObj->IsSelected() && pObj->m_fTotalHitTime >= m_fSelectHitTime )
00271 {
00272 SceneInteraction selection;
00273 selection.m_uiFlags = kIT_SelectionChange | kIT_IsSelected;
00274 selection.m_pObject = pObj;
00275 queueInteraction( selection );
00276 }
00278 else if ( pObj->IsSelected() )
00279 {
00280
00281 if ( pObj->HasInitialContact() )
00282 {
00283 const SceneContactPoint& initContact = pObj->m_initialContactPoint;
00284 Leap::Pointable contactPointable = frame.pointable(initContact.m_iPointableID);
00285
00286 if ( contactPointable.isValid() )
00287 {
00288 const Vector vPointablePos = TransformFramePoint(contactPointable.tipPosition());
00289 const Vector vTrans = (vPointablePos - pObj->GetCenter());
00290 SceneInteraction translation;
00291
00292 translation.m_mtxTransform.origin = vTrans;
00293 translation.m_uiFlags |= kIT_Translation;
00294 translation.m_pObject = pObj;
00295
00296 queueInteraction( translation );
00297
00298 pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
00299 }
00300 else
00301 {
00302 pObj->m_uiHasInitialContact--;
00303
00304 if ( !pObj->m_uiLastNumContacts )
00305 {
00306 pObj->ClearHits();
00307 }
00308 }
00309 }
00310 else
00311 {
00312 if ( pObj->GetNumContacts() )
00313 {
00314 pObj->m_initialContactPoint = *(pObj->GetContactPoint(0));
00315 pObj->m_initialContactPoint.m_vPoint -= pObj->GetCenter();
00316 pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
00317 }
00318 else if ( pObj->GetLastNumContacts() )
00319 {
00320 pObj->m_initialContactPoint = *(pObj->GetLastContactPoint(0));
00321 pObj->m_initialContactPoint.m_vPoint -= pObj->GetCenter();
00322 pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
00323 }
00324 }
00325
00327 if (pObj->GetLastNumContacts() >= 2 && pObj->GetNumContacts() >= 2)
00328 {
00329 const SceneContactPoint& lastContact0 = *(pObj->GetLastContactPoint(0));
00330 const SceneContactPoint& lastContact1 = *(pObj->GetLastContactPoint(1));
00331 const SceneContactPoint* pCurContact0 = pObj->GetContactPointByPointableID( lastContact0.m_iPointableID );
00332 const SceneContactPoint* pCurContact1 = pObj->GetContactPointByPointableID( lastContact1.m_iPointableID );
00333
00334 if ( pCurContact0 && pCurContact1 )
00335 {
00336 const Vector lastVec = (lastContact1.m_vPoint - lastContact0.m_vPoint);
00337 const Vector newVec = (pCurContact1->m_vPoint - pCurContact0->m_vPoint);
00338
00339 if ( !IsNearEqual(lastVec, newVec) && !IsNearZero(lastVec) )
00340 {
00341 const float fLastDist = lastVec.magnitude();
00342 const float fNewDist = newVec.magnitude();
00344 const float fScale = fNewDist/fLastDist;
00345
00347 const Vector vLastDir = lastVec * 1.0f/fLastDist;
00348 const Vector vNewDir = newVec * 1.0f/fNewDist;
00349
00350 const Vector vAxis = vNewDir.cross(vLastDir);
00351 const float fAngle = acosf( vNewDir.dot(vLastDir) );
00352
00354 const Vector vTrans = ( (pCurContact0->m_vPoint - lastContact0.m_vPoint) +
00355 (pCurContact1->m_vPoint - lastContact1.m_vPoint) ) * 0.5f;
00356
00357 SceneInteraction interaction;
00358
00359 if ( !IsNearZero(fAngle) )
00360 {
00361 interaction.m_mtxTransform.setRotation( vAxis, fAngle );
00362 interaction.m_uiFlags |= kIT_Rotation;
00363 }
00364
00365 if ( !IsNearEqual(fScale, 1.0f) )
00366 {
00367 interaction.m_fScale = fScale;
00368 interaction.m_uiFlags |= kIT_Scale;
00369 }
00370
00371 if ( !IsNearZero( vTrans ) )
00372 {
00373 interaction.m_mtxTransform.origin = vTrans;
00374 interaction.m_uiFlags |= kIT_Translation;
00375 }
00376
00377 if ( interaction.m_uiFlags )
00378 {
00379 interaction.m_pObject = pObj;
00380 queueInteraction( interaction );
00381 }
00382 }
00383 }
00384 }
00385 }
00386
00387 pObj->rotateContactPoints();
00388 pObj->m_uiNumPointing = 0;
00389 }
00390 }
00391
00392 void Scene::processPendingRemovals()
00393 {
00394 for ( uint32_t i = 0; (i < m_uiNumObjects) && m_uiNumPendingRemovals; m_uiNumPendingRemovals-- )
00395 {
00396 if ( m_apObjects[i]->m_bPendingRemoval )
00397 {
00398 deallocateObject( i );
00399 }
00400 else
00401 {
00402 i++;
00403 }
00404 }
00405 }
00406
00407 void Scene::queueDeselectAll()
00408 {
00409 SceneInteraction deselection;
00410 deselection.m_uiFlags = kIT_SelectionChange;
00411
00412 for (size_t i=0; i < m_uiNumObjects; i++)
00413 {
00414 if ( m_apObjects[i]->IsSelected() )
00415 {
00416 deselection.m_pObject = m_apObjects[i];
00417 queueInteraction( deselection );
00418 }
00419 }
00420 }
00421
00422
00423
00424
00425
00426
00427
00428 #if defined(LEAP_SCENE_USE_UTIL_GL)
00429 void SceneRayHit::DebugDrawGL( float fHitSphereSize ) const
00430 {
00431 const Vector& pos = m_ray.m_vOrigin;
00432 const Vector& pt = m_hitPoint;
00433
00434 glBegin(GL_LINES);
00435 glVertex3fv( &(pos.x) );
00436 glVertex3fv( &(pt.x) );
00437 glEnd();
00438
00439 {
00440 GLMatrixScope matrixScope;
00441
00442 glTranslatef(pt.x, pt.y, pt.z);
00443 glScalef( fHitSphereSize, fHitSphereSize, fHitSphereSize );
00444
00445 drawSphere( kStyle_Solid );
00446 }
00447 }
00448 #endif // LEAP_SCENE_USE_UTIL_GL
00449
00450
00451
00452
00453
00454
00455
00456 bool SceneBox::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00457 {
00458
00459
00460
00461 SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
00462 Vector vMax = GetSize() * m_fScale * 0.5f;
00463 Vector vMin = -vMax;
00464 Vector vDirScale = ComponentWiseReciprocal(testRayObj.m_vDirection);
00465 Vector vLower = ComponentWiseScale(vMin - testRayObj.m_vOrigin, vDirScale);
00466 Vector vUpper = ComponentWiseScale(vMax - testRayObj.m_vOrigin, vDirScale);
00467
00468 float fTMin = MaxComponent(ComponentWiseMin(vLower, vUpper));
00469 float fTMax = MinComponent(ComponentWiseMax(vLower, vUpper));
00470
00471 if (fTMin < fTMax)
00472 {
00473 if (fTMin > 0)
00474 {
00475 fHitDistOut = fTMin;
00476 return true;
00477 }
00478
00479 if (fTMax > 0)
00480 {
00481 fHitDistOut = fTMax;
00482 return true;
00483 }
00484 }
00485
00486 return false;
00487 }
00488
00489 bool SceneBox::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00490 {
00491
00492
00493 Vector vPos = WorldToObjectPoint(vTestPoint);
00494 Vector vMax = GetSize() * m_fScale * 0.5f;
00495 Vector vMin = -vMax;
00496
00497 return ( ComponentWiseMin(vPos - vMin, Vector::zero()).magnitudeSquared() +
00498 ComponentWiseMax(vPos - vMax, Vector::zero()).magnitudeSquared() ) <= fTestRadius*fTestRadius;
00499 }
00500
00501 #if defined(LEAP_SCENE_USE_UTIL_GL)
00502 void SceneBox::DebugDrawGL( eStyle drawStyle ) const
00503 {
00504 GLMatrixScope matrixScope;
00505 const Vector vSize = GetSize() * GetScale();
00506
00507 glMultMatrixf( GetTransform().toArray4x4() );
00508
00509 glScalef( vSize.x, vSize.y, vSize.z );
00510
00511 drawBox( drawStyle );
00512
00513 if ( IsSelected() )
00514 {
00515 GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00516
00517 if ( drawStyle != kStyle_Outline )
00518 {
00519 glColor3f(1.0f, 1.0f, 1.0f);
00520 drawBox( kStyle_Outline );
00521 }
00522
00523 glDisable(GL_DEPTH_TEST);
00524 const Vector vScale = LeapUtil::ComponentWiseReciprocal(vSize) * 0.125f;
00525 glScalef( vScale.x, vScale.y, vScale.z );
00526
00527 drawAxes();
00528 }
00529 }
00530 #endif // LEAP_SCENE_USE_UTIL_GL
00531
00532 bool SceneCylinder::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00533 {
00534 SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
00535
00536 const Vector& vAxis = Vector::yAxis();
00537 float radius = m_fScale * m_fRadius;
00538 float height = m_fScale * m_fHeight;
00539 Vector RxA = testRayObj.m_vDirection.cross(vAxis);
00540 float norm = RxA.magnitude();
00541
00542 if (norm > 0)
00543 {
00544 Vector D = RxA/norm;
00545 float d = fabs(testRayObj.m_vOrigin.dot(D));
00546 if (d >= radius) {
00547 return false;
00548 }
00549 Vector O = D.cross(vAxis).normalized();
00550 float s = fabs(sqrt(radius*radius - d*d)/(testRayObj.m_vDirection.dot(O)));
00551 float temp = -((testRayObj.m_vOrigin).cross(vAxis)).dot(D)/norm;
00552 float tin = temp - s;
00553 float tout = temp + s;
00554
00555 if (tin > 0 && fabs(testRayObj.CalcPointOn(tin).y) <= height/2.0)
00556 {
00557 fHitDistOut = tin;
00558 return true;
00559 }
00560
00561 if (tout > 0 && fabs(testRayObj.CalcPointOn(tout).y) <= height/2.0)
00562 {
00563 fHitDistOut = tout;
00564 return true;
00565 }
00566 }
00567 return false;
00568 }
00569
00570
00571 bool SceneCylinder::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00572 {
00573
00574
00575
00576 const Vector vTestPosObj = WorldToObjectPoint(vTestPoint);
00577
00578 const float fCylRadius = m_fRadius * m_fScale;
00579 const float fHalfCylHeight = m_fHeight * m_fScale * 0.5f;
00580
00581 const Vector vAxisToPoint = Vector(vTestPosObj.x, 0, vTestPosObj.z);
00582
00583 const float fAxisToPointDistSq = vAxisToPoint.magnitudeSquared();
00584
00585
00586
00587 if (fAxisToPointDistSq < (fTestRadius + fCylRadius)*(fTestRadius + fCylRadius))
00588 {
00589
00590 const float fAbsDistAlongAxis = fabs(vTestPosObj.y);
00591
00592
00593
00594
00595 if (fAbsDistAlongAxis < fHalfCylHeight)
00596 {
00597 return true;
00598 }
00599
00600
00601
00602
00603
00604 if (fAxisToPointDistSq < (fCylRadius*fCylRadius) && fAbsDistAlongAxis < (fHalfCylHeight + fTestRadius) )
00605 {
00606 return true;
00607 }
00608
00609
00610
00611
00612 const Vector vClosest = fCylRadius*vAxisToPoint.normalized() +
00613 Vector( 0, fHalfCylHeight * ((vTestPosObj.y < 0.0f) ? -1.0f : 1.0f), 0 );
00614
00615
00616
00617 if ((vTestPosObj-vClosest).magnitudeSquared() < fTestRadius*fTestRadius)
00618 {
00619 return true;
00620 }
00621 }
00622
00623 return false;
00624 }
00625
00626 #if defined(LEAP_SCENE_USE_UTIL_GL)
00627 void SceneCylinder::DebugDrawGL( eStyle drawStyle ) const
00628 {
00629 GLMatrixScope matrixScope;
00630 const float fHeight = GetHeight() * GetScale();
00631 const float fRadius = GetRadius() * GetScale();
00632
00633 glMultMatrixf( GetTransform().toArray4x4() );
00634
00635 glScalef( fRadius * 2, fHeight, fRadius * 2 );
00636
00637 drawCylinder( drawStyle, kAxis_Y );
00638
00639 if ( IsSelected() )
00640 {
00641 GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00642
00643 if ( drawStyle != kStyle_Outline )
00644 {
00645 glColor3f(1.0f, 1.0f, 1.0f);
00646 drawCylinder( kStyle_Outline, kAxis_Y );
00647 }
00648
00649 glDisable(GL_DEPTH_TEST);
00650 const float fScaleXZ = 1.0f/(fRadius + fRadius) * 0.125f;
00651 glScalef( fScaleXZ, 1.0f/fHeight * 0.125f, fScaleXZ );
00652 drawAxes();
00653 }
00654 }
00655 #endif // LEAP_SCENE_USE_UTIL_GL
00656
00657 bool SceneDisk::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00658 {
00659
00660
00661
00662 SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
00663 float fRadius = m_fScale * m_fRadius;
00664
00665
00666
00667
00668
00669 if (fabs(testRayObj.m_vDirection.z) < kfEpsilon)
00670 {
00671 return false;
00672 }
00673
00674
00675 float fPlaneHitDist = -testRayObj.m_vOrigin.z/testRayObj.m_vDirection.z;
00676
00677
00678
00679 if ( fPlaneHitDist > 0 )
00680 {
00681
00682 const Vector vPointOnPlane = testRayObj.CalcPointOn( fPlaneHitDist );
00683
00684
00685 if ( vPointOnPlane.magnitudeSquared() < fRadius * fRadius )
00686 {
00687 fHitDistOut = fPlaneHitDist;
00688 return true;
00689 }
00690 }
00691
00692 return false;
00693 }
00694
00695 bool SceneDisk::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00696 {
00697
00698
00699
00700 const Vector vPos = WorldToObjectPoint(vTestPoint);
00701 const float fDiskRadius = (m_fScale*m_fRadius);
00702
00703
00704 if (fabs(vPos.z) < fTestRadius)
00705 {
00706
00707 const Vector vOnPlane( vPos.x, vPos.y, 0 );
00708 const float fSin = vPos.z/fTestRadius;
00709 const float fCos = sqrtf(1 - fSin*fSin);
00710
00711
00712
00713
00714 fTestRadius = fCos * fTestRadius + fDiskRadius;
00715
00716 if (vOnPlane.magnitudeSquared() < fTestRadius * fTestRadius)
00717 {
00718 return true;
00719 }
00720 }
00721
00722 return false;
00723 }
00724
00725 #if defined(LEAP_SCENE_USE_UTIL_GL)
00726 void SceneDisk::DebugDrawGL( eStyle drawStyle ) const
00727 {
00728 GLMatrixScope matrixScope;
00729 const float fRadius = GetRadius() * GetScale();
00730
00731 glMultMatrixf( GetTransform().toArray4x4() );
00732
00733 glScalef( fRadius + fRadius, fRadius + fRadius, fRadius + fRadius );
00734
00735 drawDisk( drawStyle, kPlane_XY );
00736
00737 if ( IsSelected() )
00738 {
00739 GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00740
00741 if ( drawStyle != kStyle_Outline )
00742 {
00743 glColor3f(1.0f, 1.0f, 1.0f);
00744 drawDisk( kStyle_Outline, kPlane_XY );
00745 }
00746
00747 glDisable(GL_DEPTH_TEST);
00748 const float fScale = 1.0f/(fRadius + fRadius) * 0.125f;
00749 glScalef( fScale, fScale, fScale );
00750 drawAxes();
00751 }
00752 }
00753 #endif // LEAP_SCENE_USE_UTIL_GL
00754
00755 bool ScenePlane::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00756 {
00757 const float fRayAngleCos = GetNormal().dot( testRay.m_vDirection );
00758
00759 if (fabs(fRayAngleCos) < kfEpsilon)
00760 {
00761 return false;
00762 }
00763
00764
00765 const float fRayOriginPlaneDist = GetNormal().dot(GetCenter() - testRay.m_vOrigin);
00766
00767
00768 const float fPlaneHitDist = fRayOriginPlaneDist/fRayAngleCos;
00769
00770 if (fPlaneHitDist > 0)
00771 {
00772 fHitDistOut = fPlaneHitDist;
00773 return true;
00774 }
00775
00776 return false;
00777 }
00778
00779 bool ScenePlane::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00780 {
00781 return fabs((vTestPoint - GetCenter()).dot(GetNormal())) < fTestRadius;
00782 }
00783
00784 #if defined(LEAP_SCENE_USE_UTIL_GL)
00785 void ScenePlane::DebugDrawGL( eStyle drawStyle ) const
00786 {
00787 (void)drawStyle;
00788 }
00789 #endif // LEAP_SCENE_USE_UTIL_GL
00790
00791 bool SceneSphere::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00792 {
00793 const float fRadius = m_fScale * m_fRadius;
00794 const Vector O = testRay.m_vOrigin - GetCenter();
00795 const float b = O.dot(testRay.m_vDirection);
00796 const float c = O.dot(O) - fRadius*fRadius;
00797 const float disc = b*b - c;
00798
00799 if (disc > 0)
00800 {
00801 float sdisc = sqrtf(disc);
00802 float root = (-b - sdisc);
00803
00804 if (root > 0)
00805 {
00806 fHitDistOut = root;
00807 return true;
00808 }
00809
00810 root = (-b + sdisc);
00811
00812 if (root > 0)
00813 {
00814 fHitDistOut = root;
00815 return true;
00816 }
00817 }
00818
00819 return false;
00820 }
00821
00822 bool SceneSphere::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00823 {
00824 const float fMaxDist = (m_fScale*m_fRadius + fTestRadius);
00825 return (GetCenter() - vTestPoint).magnitudeSquared() < (fMaxDist * fMaxDist);
00826 }
00827
00828 #if defined(LEAP_SCENE_USE_UTIL_GL)
00829 void SceneSphere::DebugDrawGL( eStyle drawStyle ) const
00830 {
00831 GLMatrixScope matrixScope;
00832
00833 const float fRadius = GetRadius() * GetScale();
00834
00835 glMultMatrixf( GetTransform().toArray4x4() );
00836
00837 glScalef( fRadius+fRadius, fRadius+fRadius, fRadius+fRadius );
00838
00839 drawSphere( drawStyle );
00840
00841 if ( IsSelected() )
00842 {
00843 GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00844
00845 if ( drawStyle != kStyle_Outline )
00846 {
00847 glColor3f(1.0f, 1.0f, 1.0f);
00848 drawSphere( kStyle_Outline );
00849 }
00850
00851 glDisable(GL_DEPTH_TEST);
00852
00853 const float fScale = 1.0f/(fRadius + fRadius) * 0.125f;
00854 glScalef( fScale, fScale, fScale );
00855
00856 drawAxes();
00857 }
00858 }
00859 #endif // LEAP_SCENE_USE_UTIL_GL
00860
00861 }