convex.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "collision/convex.h"
  24. #include "platform/types.h"
  25. #include "core/dataChunker.h"
  26. #include "collision/collision.h"
  27. #include "scene/sceneObject.h"
  28. #include "collision/gjk.h"
  29. #include "collision/concretePolyList.h"
  30. #include "platform/profiler.h"
  31. //----------------------------------------------------------------------------
  32. //----------------------------------------------------------------------------
  33. static DataChunker sChunker;
  34. CollisionStateList CollisionStateList::sFreeList;
  35. CollisionWorkingList CollisionWorkingList::sFreeList;
  36. F32 sqrDistanceEdges(const Point3F& start0,
  37. const Point3F& end0,
  38. const Point3F& start1,
  39. const Point3F& end1,
  40. Point3F* is,
  41. Point3F* it);
  42. //----------------------------------------------------------------------------
  43. // Collision State
  44. //----------------------------------------------------------------------------
  45. CollisionState::CollisionState()
  46. {
  47. mB = mA = NULL;
  48. mDist = 0.0f;
  49. mListb = mLista = 0;
  50. }
  51. CollisionState::~CollisionState()
  52. {
  53. if (mLista)
  54. mLista->free();
  55. if (mListb)
  56. mListb->free();
  57. }
  58. void CollisionState::swap()
  59. {
  60. }
  61. void CollisionState::set(Convex* a,Convex* b,const MatrixF& a2w, const MatrixF& b2w)
  62. {
  63. }
  64. F32 CollisionState::distance(const MatrixF& a2w, const MatrixF& b2w, const F32 dontCareDist,
  65. const MatrixF* w2a, const MatrixF* _w2b)
  66. {
  67. return 0;
  68. }
  69. //----------------------------------------------------------------------------
  70. // Feature Collision
  71. //----------------------------------------------------------------------------
  72. void ConvexFeature::reset()
  73. {
  74. material = NULL;
  75. mObject = NULL;
  76. mVertexList.clear();
  77. mEdgeList.clear();
  78. mFaceList.clear();
  79. }
  80. bool ConvexFeature::collide(ConvexFeature& cf,CollisionList* cList, F32 tol)
  81. {
  82. // Our vertices vs. other faces
  83. const Point3F* vert = mVertexList.begin();
  84. const Point3F* vend = mVertexList.end();
  85. while (vert != vend) {
  86. cf.testVertex(*vert,cList,false, tol);
  87. vert++;
  88. }
  89. // Other vertices vs. our faces
  90. vert = cf.mVertexList.begin();
  91. vend = cf.mVertexList.end();
  92. while (vert != vend) {
  93. U32 storeCount = cList->getCount();
  94. testVertex(*vert,cList,true, tol);
  95. // Fix up last reference. material and object are copied from this rather
  96. // than the object we're colliding against.
  97. if (storeCount != cList->getCount())
  98. {
  99. Collision &col = (*cList)[cList->getCount() - 1];
  100. col.material = cf.material;
  101. col.object = cf.mObject;
  102. }
  103. vert++;
  104. }
  105. // Edge vs. Edge
  106. const Edge* edge = mEdgeList.begin();
  107. const Edge* eend = mEdgeList.end();
  108. while (edge != eend) {
  109. cf.testEdge(this,mVertexList[edge->vertex[0]],
  110. mVertexList[edge->vertex[1]],cList, tol);
  111. edge++;
  112. }
  113. return true;
  114. }
  115. inline bool isInside(const Point3F& p, const Point3F& a, const Point3F& b, const VectorF& n)
  116. {
  117. VectorF v;
  118. mCross(n,b - a,&v);
  119. return mDot(v,p - a) < 0.0f;
  120. }
  121. void ConvexFeature::testVertex(const Point3F& v,CollisionList* cList,bool flip, F32 tol)
  122. {
  123. // Test vertex against all faces
  124. const Face* face = mFaceList.begin();
  125. const Face* end = mFaceList.end();
  126. for (; face != end; face++) {
  127. if (cList->getCount() >= CollisionList::MaxCollisions)
  128. return;
  129. const Point3F& p0 = mVertexList[face->vertex[0]];
  130. const Point3F& p1 = mVertexList[face->vertex[1]];
  131. const Point3F& p2 = mVertexList[face->vertex[2]];
  132. // Point near the plane?
  133. F32 distance = mDot(face->normal,v - p0);
  134. if (distance > tol || distance < -tol)
  135. continue;
  136. // Make sure it's within the bounding edges
  137. if (isInside(v,p0,p1,face->normal) && isInside(v,p1,p2,face->normal) &&
  138. isInside(v,p2,p0,face->normal)) {
  139. // Add collision to this face
  140. Collision& info = cList->increment();
  141. info.point = v;
  142. info.normal = face->normal;
  143. if (flip)
  144. info.normal.neg();
  145. info.material = material;
  146. info.object = mObject;
  147. info.distance = distance;
  148. }
  149. }
  150. }
  151. void ConvexFeature::testEdge(ConvexFeature* cf,const Point3F& s1, const Point3F& e1, CollisionList* cList, F32 tol)
  152. {
  153. F32 tolSquared = tol*tol;
  154. // Test edges against edges
  155. const Edge* edge = mEdgeList.begin();
  156. const Edge* end = mEdgeList.end();
  157. for (; edge != end; edge++) {
  158. if (cList->getCount() >= CollisionList::MaxCollisions)
  159. return;
  160. const Point3F& s2 = mVertexList[edge->vertex[0]];
  161. const Point3F& e2 = mVertexList[edge->vertex[1]];
  162. // Get the distance and closest points
  163. Point3F i1,i2;
  164. F32 distance = sqrDistanceEdges(s1, e1, s2, e2, &i1, &i2);
  165. if (distance > tolSquared)
  166. continue;
  167. distance = mSqrt(distance);
  168. // Need to figure out how to orient the collision normal.
  169. // The current test involves checking to see whether the collision
  170. // points are contained within the convex volumes, which is slow.
  171. if (inVolume(i1) || cf->inVolume(i2))
  172. distance = -distance;
  173. // Contact normal
  174. VectorF normal = i1 - i2;
  175. if ( mIsZero( distance ) )
  176. normal.zero();
  177. else
  178. normal *= 1 / distance;
  179. // Return a collision
  180. Collision& info = cList->increment();
  181. info.point = i1;
  182. info.normal = normal;
  183. info.distance = distance;
  184. info.material = material;
  185. info.object = mObject;
  186. }
  187. }
  188. bool ConvexFeature::inVolume(const Point3F& v)
  189. {
  190. // Test the point to see if it's inside the volume
  191. const Face* face = mFaceList.begin();
  192. const Face* end = mFaceList.end();
  193. for (; face != end; face++) {
  194. const Point3F& p0 = mVertexList[face->vertex[0]];
  195. if (mDot(face->normal,v - p0) > 0)
  196. return false;
  197. }
  198. return true;
  199. }
  200. //----------------------------------------------------------------------------
  201. // Collision State management
  202. //----------------------------------------------------------------------------
  203. //----------------------------------------------------------------------------
  204. CollisionStateList::CollisionStateList()
  205. {
  206. mPrev = mNext = this;
  207. mState = NULL;
  208. }
  209. void CollisionStateList::linkAfter(CollisionStateList* ptr)
  210. {
  211. mPrev = ptr;
  212. mNext = ptr->mNext;
  213. ptr->mNext = this;
  214. mNext->mPrev = this;
  215. }
  216. void CollisionStateList::unlink()
  217. {
  218. mPrev->mNext = mNext;
  219. mNext->mPrev = mPrev;
  220. mPrev = mNext = this;
  221. }
  222. CollisionStateList* CollisionStateList::alloc()
  223. {
  224. if (!sFreeList.isEmpty()) {
  225. CollisionStateList* nxt = sFreeList.mNext;
  226. nxt->unlink();
  227. nxt->mState = NULL;
  228. return nxt;
  229. }
  230. return constructInPlace((CollisionStateList*)sChunker.alloc(sizeof(CollisionStateList)));
  231. }
  232. void CollisionStateList::free()
  233. {
  234. unlink();
  235. linkAfter(&sFreeList);
  236. }
  237. //----------------------------------------------------------------------------
  238. CollisionWorkingList::CollisionWorkingList()
  239. {
  240. wLink.mPrev = wLink.mNext = this;
  241. rLink.mPrev = rLink.mNext = this;
  242. mConvex = NULL;
  243. }
  244. void CollisionWorkingList::wLinkAfter(CollisionWorkingList* ptr)
  245. {
  246. wLink.mPrev = ptr;
  247. wLink.mNext = ptr->wLink.mNext;
  248. ptr->wLink.mNext = this;
  249. wLink.mNext->wLink.mPrev = this;
  250. }
  251. void CollisionWorkingList::rLinkAfter(CollisionWorkingList* ptr)
  252. {
  253. rLink.mPrev = ptr;
  254. rLink.mNext = ptr->rLink.mNext;
  255. ptr->rLink.mNext = this;
  256. rLink.mNext->rLink.mPrev = this;
  257. }
  258. void CollisionWorkingList::unlink()
  259. {
  260. wLink.mPrev->wLink.mNext = wLink.mNext;
  261. wLink.mNext->wLink.mPrev = wLink.mPrev;
  262. wLink.mPrev = wLink.mNext = this;
  263. rLink.mPrev->rLink.mNext = rLink.mNext;
  264. rLink.mNext->rLink.mPrev = rLink.mPrev;
  265. rLink.mPrev = rLink.mNext = this;
  266. }
  267. CollisionWorkingList* CollisionWorkingList::alloc()
  268. {
  269. if (sFreeList.wLink.mNext != &sFreeList) {
  270. CollisionWorkingList* nxt = sFreeList.wLink.mNext;
  271. nxt->unlink();
  272. return nxt;
  273. }
  274. return constructInPlace((CollisionWorkingList*)sChunker.alloc(sizeof(CollisionWorkingList)));
  275. }
  276. void CollisionWorkingList::free()
  277. {
  278. unlink();
  279. wLinkAfter(&sFreeList);
  280. }
  281. //----------------------------------------------------------------------------
  282. // Convex Base Class
  283. //----------------------------------------------------------------------------
  284. U32 Convex::sTag = (U32)-1;
  285. //----------------------------------------------------------------------------
  286. Convex::Convex()
  287. {
  288. mNext = mPrev = this;
  289. mTag = 0;
  290. mObject = NULL;
  291. mType = ConvexType::BoxConvexType;
  292. }
  293. Convex::~Convex()
  294. {
  295. // Unlink from Convex Database
  296. unlink();
  297. // Delete collision states
  298. while (mList.mNext != &mList)
  299. delete mList.mNext->mState;
  300. // Free up working list
  301. while (mWorking.wLink.mNext != &mWorking)
  302. mWorking.wLink.mNext->free();
  303. // Free up references
  304. while (mReference.rLink.mNext != &mReference)
  305. mReference.rLink.mNext->free();
  306. }
  307. //----------------------------------------------------------------------------
  308. void Convex::collectGarbage()
  309. {
  310. // Delete unreferenced Convex Objects
  311. for (Convex* itr = mNext; itr != this; itr = itr->mNext) {
  312. if (itr->mReference.rLink.mNext == &itr->mReference) {
  313. Convex* ptr = itr;
  314. itr = itr->mPrev;
  315. delete ptr;
  316. }
  317. }
  318. }
  319. void Convex::nukeList()
  320. {
  321. // Delete all Convex Objects
  322. for (Convex* itr = mNext; itr != this; itr = itr->mNext) {
  323. Convex* ptr = itr;
  324. itr = itr->mPrev;
  325. delete ptr;
  326. }
  327. }
  328. void Convex::registerObject(Convex *convex)
  329. {
  330. convex->linkAfter(this);
  331. }
  332. //----------------------------------------------------------------------------
  333. void Convex::linkAfter(Convex* ptr)
  334. {
  335. mPrev = ptr;
  336. mNext = ptr->mNext;
  337. ptr->mNext = this;
  338. mNext->mPrev = this;
  339. }
  340. void Convex::unlink()
  341. {
  342. mPrev->mNext = mNext;
  343. mNext->mPrev = mPrev;
  344. mPrev = mNext = this;
  345. }
  346. //----------------------------------------------------------------------------
  347. Point3F Convex::support(const VectorF&) const
  348. {
  349. return Point3F(0,0,0);
  350. }
  351. void Convex::getFeatures(const MatrixF&,const VectorF&,ConvexFeature* f)
  352. {
  353. f->mObject = NULL;
  354. }
  355. const MatrixF& Convex::getTransform() const
  356. {
  357. return mObject->getTransform();
  358. }
  359. const Point3F& Convex::getScale() const
  360. {
  361. return mObject->getScale();
  362. }
  363. Box3F Convex::getBoundingBox() const
  364. {
  365. return mObject->getWorldBox();
  366. }
  367. Box3F Convex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const
  368. {
  369. Box3F wBox = mObject->getObjBox();
  370. wBox.minExtents.convolve(scale);
  371. wBox.maxExtents.convolve(scale);
  372. mat.mul(wBox);
  373. return wBox;
  374. }
  375. //----------------------------------------------------------------------------
  376. void Convex::addToWorkingList(Convex* ptr)
  377. {
  378. CollisionWorkingList* cl = CollisionWorkingList::alloc();
  379. cl->wLinkAfter(&mWorking);
  380. cl->rLinkAfter(&ptr->mReference);
  381. cl->mConvex = ptr;
  382. };
  383. //----------------------------------------------------------------------------
  384. void Convex::updateWorkingList(const Box3F& box, const U32 colMask)
  385. {
  386. PROFILE_SCOPE( Convex_UpdateWorkingList );
  387. sTag++;
  388. // Clear objects off the working list that are no longer intersecting
  389. for (CollisionWorkingList* itr = mWorking.wLink.mNext; itr != &mWorking; itr = itr->wLink.mNext) {
  390. itr->mConvex->mTag = sTag;
  391. if ((!box.isOverlapped(itr->mConvex->getBoundingBox())) || (!itr->mConvex->getObject()->isCollisionEnabled())) {
  392. CollisionWorkingList* cl = itr;
  393. itr = itr->wLink.mPrev;
  394. cl->free();
  395. }
  396. }
  397. // Special processing for the terrain and interiors...
  398. AssertFatal(mObject->getContainer(), "Must be in a container!");
  399. SimpleQueryList sql;
  400. mObject->getContainer()->findObjects(box, colMask,SimpleQueryList::insertionCallback, &sql);
  401. for (U32 i = 0; i < sql.mList.size(); i++)
  402. sql.mList[i]->buildConvex(box, this);
  403. }
  404. void Convex::clearWorkingList()
  405. {
  406. PROFILE_SCOPE( Convex_ClearWorkingList );
  407. sTag++;
  408. for (CollisionWorkingList* itr = mWorking.wLink.mNext; itr != &mWorking; itr = itr->wLink.mNext)
  409. {
  410. itr->mConvex->mTag = sTag;
  411. CollisionWorkingList* cl = itr;
  412. itr = itr->wLink.mPrev;
  413. cl->free();
  414. }
  415. }
  416. // ---------------------------------------------------------------------------
  417. void Convex::updateStateList(const MatrixF& mat, const Point3F& scale, const Point3F* displacement)
  418. {
  419. PROFILE_SCOPE( Convex_UpdateStateList );
  420. Box3F box1 = getBoundingBox(mat, scale);
  421. box1.minExtents -= Point3F(1, 1, 1);
  422. box1.maxExtents += Point3F(1, 1, 1);
  423. if (displacement) {
  424. Point3F oldMin = box1.minExtents;
  425. Point3F oldMax = box1.maxExtents;
  426. box1.minExtents.setMin(oldMin + *displacement);
  427. box1.minExtents.setMin(oldMax + *displacement);
  428. box1.maxExtents.setMax(oldMin + *displacement);
  429. box1.maxExtents.setMax(oldMax + *displacement);
  430. }
  431. sTag++;
  432. // Destroy states which are no longer intersecting
  433. for (CollisionStateList* itr = mList.mNext; itr != &mList; itr = itr->mNext) {
  434. Convex* cv = (itr->mState->mA == this)? itr->mState->mB: itr->mState->mA;
  435. cv->mTag = sTag;
  436. if (!box1.isOverlapped(cv->getBoundingBox())) {
  437. CollisionState* cs = itr->mState;
  438. itr = itr->mPrev;
  439. delete cs;
  440. }
  441. }
  442. // Add collision states for new overlapping objects
  443. for (CollisionWorkingList* itr0 = mWorking.wLink.mNext; itr0 != &mWorking; itr0 = itr0->wLink.mNext) {
  444. Convex* cv = itr0->mConvex;
  445. if (cv->mTag != sTag && box1.isOverlapped(cv->getBoundingBox())) {
  446. CollisionState* state = new GjkCollisionState;
  447. state->set(this,cv,mat,cv->getTransform());
  448. state->mLista->linkAfter(&mList);
  449. state->mListb->linkAfter(&cv->mList);
  450. }
  451. }
  452. }
  453. //----------------------------------------------------------------------------
  454. CollisionState* Convex::findClosestState(const MatrixF& mat, const Point3F& scale, const F32 dontCareDist)
  455. {
  456. PROFILE_SCOPE( Convex_FindClosestState );
  457. updateStateList(mat, scale);
  458. F32 dist = +1E30f;
  459. CollisionState *st = 0;
  460. // Prepare scaled version of transform
  461. MatrixF axform = mat;
  462. axform.scale(scale);
  463. MatrixF axforminv(true);
  464. MatrixF temp(mat);
  465. axforminv.scale(Point3F(1.0f/scale.x, 1.0f/scale.y, 1.0f/scale.z));
  466. temp.affineInverse();
  467. axforminv.mul(temp);
  468. for (CollisionStateList* itr = mList.mNext; itr != &mList; itr = itr->mNext)
  469. {
  470. CollisionState* state = itr->mState;
  471. if (state->mLista != itr)
  472. state->swap();
  473. // Prepare scaled version of transform
  474. MatrixF bxform = state->mB->getTransform();
  475. temp = bxform;
  476. Point3F bscale = state->mB->getScale();
  477. bxform.scale(bscale);
  478. MatrixF bxforminv(true);
  479. bxforminv.scale(Point3F(1.0f/bscale.x, 1.0f/bscale.y, 1.0f/bscale.z));
  480. temp.affineInverse();
  481. bxforminv.mul(temp);
  482. //
  483. F32 dd = state->distance(axform, bxform, dontCareDist, &axforminv, &bxforminv);
  484. if (dd < dist)
  485. {
  486. dist = dd;
  487. st = state;
  488. }
  489. }
  490. if (dist < dontCareDist)
  491. return st;
  492. else
  493. return NULL;
  494. }
  495. //----------------------------------------------------------------------------
  496. bool Convex::getCollisionInfo(const MatrixF& mat, const Point3F& scale, CollisionList* cList,F32 tol)
  497. {
  498. PROFILE_SCOPE( Convex_GetCollisionInfo );
  499. // Making these static prevents needless Vector resizing that occurs
  500. // in the ConvexFeature constructor.
  501. static ConvexFeature fa;
  502. static ConvexFeature fb;
  503. for ( CollisionStateList* itr = mList.mNext;
  504. itr != &mList;
  505. itr = itr->mNext)
  506. {
  507. CollisionState* state = itr->mState;
  508. if (state->mLista != itr)
  509. state->swap();
  510. if (state->mDist <= tol)
  511. {
  512. fa.reset();
  513. fb.reset();
  514. VectorF v;
  515. // The idea is that we need to scale the matrix, so we need to
  516. // make a copy of it, before we can pass it in to getFeatures.
  517. // This is used to scale us for comparison against the other
  518. // convex, which is correctly scaled.
  519. MatrixF omat = mat;
  520. omat.scale(scale);
  521. MatrixF imat = omat;
  522. imat.inverse();
  523. imat.mulV(-state->mDistvec,&v);
  524. getFeatures(omat,v,&fa);
  525. imat = state->mB->getTransform();
  526. imat.scale(state->mB->getScale());
  527. MatrixF bxform = imat;
  528. imat.inverse();
  529. imat.mulV(state->mDistvec,&v);
  530. state->mB->getFeatures(bxform,v,&fb);
  531. fa.collide(fb,cList,tol);
  532. }
  533. }
  534. return (cList->getCount() != 0);
  535. }
  536. void Convex::getPolyList(AbstractPolyList*)
  537. {
  538. }
  539. void Convex::renderWorkingList()
  540. {
  541. //bool rendered = false;
  542. CollisionWorkingList& rList = getWorkingList();
  543. CollisionWorkingList* pList = rList.wLink.mNext;
  544. while (pList != &rList) {
  545. Convex* pConvex = pList->mConvex;
  546. pConvex->render();
  547. //rendered = true;
  548. pList = pList->wLink.mNext;
  549. }
  550. //Con::warnf( "convex rendered - %s", rendered ? "YES" : "NO" );
  551. }
  552. void Convex::render()
  553. {
  554. ConcretePolyList polyList;
  555. getPolyList( &polyList );
  556. polyList.render();
  557. }
  558. //-----------------------------------------------------------------------------
  559. // This function based on code originally written for the book:
  560. // 3D Game Engine Design, by David H. Eberly
  561. //
  562. F32 sqrDistanceEdges(const Point3F& start0, const Point3F& end0,
  563. const Point3F& start1, const Point3F& end1,
  564. Point3F* is, Point3F* it)
  565. {
  566. Point3F direction0 = end0 - start0;
  567. F32 fA00 = direction0.lenSquared();
  568. Point3F direction1 = end1 - start1;
  569. F32 fA11 = direction1.lenSquared();
  570. F32 fA01 = -mDot(direction0, direction1);
  571. Point3F kDiff = start0 - start1;
  572. F32 fC = kDiff.lenSquared();
  573. F32 fB0 = mDot(kDiff, direction0);
  574. F32 fDet = mFabs(fA00*fA11 - fA01*fA01);
  575. // Since the endpoints are tested as vertices, we're not interested
  576. // in parallel lines, and intersections that don't involve end-points.
  577. if (fDet >= 0.00001) {
  578. // Calculate time of intersection for each line
  579. F32 fB1 = -mDot(kDiff, direction1);
  580. F32 fS = fA01*fB1-fA11*fB0;
  581. F32 fT = fA01*fB0-fA00*fB1;
  582. // Only interested in collisions that don't involve the end points
  583. if (fS >= 0.0 && fS <= fDet && fT >= 0.0 && fT <= fDet) {
  584. F32 fInvDet = 1.0 / fDet;
  585. fS *= fInvDet;
  586. fT *= fInvDet;
  587. F32 fSqrDist = (fS*(fA00*fS + fA01*fT + 2.0*fB0) +
  588. fT*(fA01*fS + fA11*fT + 2.0*fB1) + fC);
  589. // Intersection points.
  590. *is = start0 + direction0 * fS;
  591. *it = start1 + direction1 * fT;
  592. return mFabs(fSqrDist);
  593. }
  594. }
  595. // Return a large number in the cases where endpoints are involved.
  596. return 1e10f;
  597. }