convex.cpp 20 KB

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