/lib/ode/ode_source/OPCODE/OPC_PlanesCollider.cpp

http://narutortsproject.googlecode.com/ · C++ · 653 lines · 339 code · 110 blank · 204 comment · 66 complexity · 89ee7f185f1bee92a8165058ae067d82 MD5 · raw file

  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /*
  3. * OPCODE - Optimized Collision Detection
  4. * Copyright (C) 2001 Pierre Terdiman
  5. * Homepage: http://www.codercorner.com/Opcode.htm
  6. */
  7. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. /**
  10. * Contains code for a planes collider.
  11. * \file OPC_PlanesCollider.cpp
  12. * \author Pierre Terdiman
  13. * \date January, 1st, 2002
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. /**
  18. * Contains a Planes-vs-tree collider.
  19. *
  20. * \class PlanesCollider
  21. * \author Pierre Terdiman
  22. * \version 1.3
  23. * \date January, 1st, 2002
  24. */
  25. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. // Precompiled Header
  28. #include "Stdafx.h"
  29. using namespace Opcode;
  30. #include "OPC_PlanesAABBOverlap.h"
  31. #include "OPC_PlanesTriOverlap.h"
  32. #define SET_CONTACT(prim_index, flag) \
  33. /* Set contact status */ \
  34. mFlags |= flag; \
  35. mTouchedPrimitives->Add(udword(prim_index));
  36. //! Planes-triangle test
  37. #define PLANES_PRIM(prim_index, flag) \
  38. /* Request vertices from the app */ \
  39. mIMesh->GetTriangle(mVP, prim_index, mVC); \
  40. /* Perform triangle-box overlap test */ \
  41. if(PlanesTriOverlap(clip_mask)) \
  42. { \
  43. SET_CONTACT(prim_index, flag) \
  44. }
  45. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  46. /**
  47. * Constructor.
  48. */
  49. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  50. PlanesCollider::PlanesCollider() :
  51. mNbPlanes (0),
  52. mPlanes (null)
  53. {
  54. }
  55. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. /**
  57. * Destructor.
  58. */
  59. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  60. PlanesCollider::~PlanesCollider()
  61. {
  62. DELETEARRAY(mPlanes);
  63. }
  64. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. /**
  66. * Validates current settings. You should call this method after all the settings and callbacks have been defined.
  67. * \return null if everything is ok, else a string describing the problem
  68. */
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. const char* PlanesCollider::ValidateSettings()
  71. {
  72. if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
  73. return VolumeCollider::ValidateSettings();
  74. }
  75. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  76. /**
  77. * Generic collision query for generic OPCODE models. After the call, access the results:
  78. * - with GetContactStatus()
  79. * - with GetNbTouchedPrimitives()
  80. * - with GetTouchedPrimitives()
  81. *
  82. * \param cache [in/out] a planes cache
  83. * \param planes [in] list of planes in world space
  84. * \param nb_planes [in] number of planes
  85. * \param model [in] Opcode model to collide with
  86. * \param worldm [in] model's world matrix, or null
  87. * \return true if success
  88. * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
  89. */
  90. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  91. bool PlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm)
  92. {
  93. // Checkings
  94. if(!Setup(&model)) return false;
  95. // Init collision query
  96. if(InitQuery(cache, planes, nb_planes, worldm)) return true;
  97. udword PlaneMask = (1<<nb_planes)-1;
  98. if(!model.HasLeafNodes())
  99. {
  100. if(model.IsQuantized())
  101. {
  102. const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
  103. // Setup dequantization coeffs
  104. mCenterCoeff = Tree->mCenterCoeff;
  105. mExtentsCoeff = Tree->mExtentsCoeff;
  106. // Perform collision query
  107. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  108. else _Collide(Tree->GetNodes(), PlaneMask);
  109. }
  110. else
  111. {
  112. const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
  113. // Perform collision query
  114. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  115. else _Collide(Tree->GetNodes(), PlaneMask);
  116. }
  117. }
  118. else
  119. {
  120. if(model.IsQuantized())
  121. {
  122. const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
  123. // Setup dequantization coeffs
  124. mCenterCoeff = Tree->mCenterCoeff;
  125. mExtentsCoeff = Tree->mExtentsCoeff;
  126. // Perform collision query
  127. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  128. else _Collide(Tree->GetNodes(), PlaneMask);
  129. }
  130. else
  131. {
  132. const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
  133. // Perform collision query
  134. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  135. else _Collide(Tree->GetNodes(), PlaneMask);
  136. }
  137. }
  138. return true;
  139. }
  140. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  141. /**
  142. * Initializes a collision query :
  143. * - reset stats & contact status
  144. * - compute planes in model space
  145. * - check temporal coherence
  146. *
  147. * \param cache [in/out] a planes cache
  148. * \param planes [in] list of planes
  149. * \param nb_planes [in] number of planes
  150. * \param worldm [in] model's world matrix, or null
  151. * \return TRUE if we can return immediately
  152. * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only.
  153. */
  154. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. BOOL PlanesCollider::InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm)
  156. {
  157. // 1) Call the base method
  158. VolumeCollider::InitQuery();
  159. // 2) Compute planes in model space
  160. if(nb_planes>mNbPlanes)
  161. {
  162. DELETEARRAY(mPlanes);
  163. mPlanes = new Plane[nb_planes];
  164. }
  165. mNbPlanes = nb_planes;
  166. if(worldm)
  167. {
  168. Matrix4x4 InvWorldM;
  169. InvertPRMatrix(InvWorldM, *worldm);
  170. // for(udword i=0;i<nb_planes;i++) mPlanes[i] = planes[i] * InvWorldM;
  171. for(udword i=0;i<nb_planes;i++) TransformPlane(mPlanes[i], planes[i], InvWorldM);
  172. }
  173. else CopyMemory(mPlanes, planes, nb_planes*sizeof(Plane));
  174. // 3) Setup destination pointer
  175. mTouchedPrimitives = &cache.TouchedPrimitives;
  176. // 4) Special case: 1-triangle meshes [Opcode 1.3]
  177. if(mCurrentModel && mCurrentModel->HasSingleNode())
  178. {
  179. if(!SkipPrimitiveTests())
  180. {
  181. // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
  182. mTouchedPrimitives->Reset();
  183. // Perform overlap test between the unique triangle and the planes (and set contact status if needed)
  184. udword clip_mask = (1<<mNbPlanes)-1;
  185. PLANES_PRIM(udword(0), OPC_CONTACT)
  186. // Return immediately regardless of status
  187. return TRUE;
  188. }
  189. }
  190. // 4) Check temporal coherence:
  191. if(TemporalCoherenceEnabled())
  192. {
  193. // Here we use temporal coherence
  194. // => check results from previous frame before performing the collision query
  195. if(FirstContactEnabled())
  196. {
  197. // We're only interested in the first contact found => test the unique previously touched face
  198. if(mTouchedPrimitives->GetNbEntries())
  199. {
  200. // Get index of previously touched face = the first entry in the array
  201. udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
  202. // Then reset the array:
  203. // - if the overlap test below is successful, the index we'll get added back anyway
  204. // - if it isn't, then the array should be reset anyway for the normal query
  205. mTouchedPrimitives->Reset();
  206. // Perform overlap test between the cached triangle and the planes (and set contact status if needed)
  207. udword clip_mask = (1<<mNbPlanes)-1;
  208. PLANES_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT)
  209. // Return immediately if possible
  210. if(GetContactStatus()) return TRUE;
  211. }
  212. // else no face has been touched during previous query
  213. // => we'll have to perform a normal query
  214. }
  215. else mTouchedPrimitives->Reset();
  216. }
  217. else
  218. {
  219. // Here we don't use temporal coherence => do a normal query
  220. mTouchedPrimitives->Reset();
  221. }
  222. return FALSE;
  223. }
  224. #define TEST_CLIP_MASK \
  225. /* If the box is completely included, so are its children. We don't need to do extra tests, we */ \
  226. /* can immediately output a list of visible children. Those ones won't need to be clipped. */ \
  227. if(!OutClipMask) \
  228. { \
  229. /* Set contact status */ \
  230. mFlags |= OPC_CONTACT; \
  231. _Dump(node); \
  232. return; \
  233. }
  234. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  235. /**
  236. * Recursive collision query for normal AABB trees.
  237. * \param node [in] current collision node
  238. */
  239. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  240. void PlanesCollider::_Collide(const AABBCollisionNode* node, udword clip_mask)
  241. {
  242. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  243. udword OutClipMask;
  244. if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return;
  245. TEST_CLIP_MASK
  246. // Else the box straddles one or several planes, so we need to recurse down the tree.
  247. if(node->IsLeaf())
  248. {
  249. PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT)
  250. }
  251. else
  252. {
  253. _Collide(node->GetPos(), OutClipMask);
  254. if(ContactFound()) return;
  255. _Collide(node->GetNeg(), OutClipMask);
  256. }
  257. }
  258. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. /**
  260. * Recursive collision query for normal AABB trees.
  261. * \param node [in] current collision node
  262. */
  263. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  264. void PlanesCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask)
  265. {
  266. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  267. udword OutClipMask;
  268. if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return;
  269. TEST_CLIP_MASK
  270. // Else the box straddles one or several planes, so we need to recurse down the tree.
  271. if(node->IsLeaf())
  272. {
  273. SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
  274. }
  275. else
  276. {
  277. _CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
  278. if(ContactFound()) return;
  279. _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
  280. }
  281. }
  282. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. /**
  284. * Recursive collision query for quantized AABB trees.
  285. * \param node [in] current collision node
  286. */
  287. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  288. void PlanesCollider::_Collide(const AABBQuantizedNode* node, udword clip_mask)
  289. {
  290. // Dequantize box
  291. const QuantizedAABB& Box = node->mAABB;
  292. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  293. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  294. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  295. udword OutClipMask;
  296. if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
  297. TEST_CLIP_MASK
  298. // Else the box straddles one or several planes, so we need to recurse down the tree.
  299. if(node->IsLeaf())
  300. {
  301. PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT)
  302. }
  303. else
  304. {
  305. _Collide(node->GetPos(), OutClipMask);
  306. if(ContactFound()) return;
  307. _Collide(node->GetNeg(), OutClipMask);
  308. }
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. /**
  312. * Recursive collision query for quantized AABB trees.
  313. * \param node [in] current collision node
  314. */
  315. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  316. void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask)
  317. {
  318. // Dequantize box
  319. const QuantizedAABB& Box = node->mAABB;
  320. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  321. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  322. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  323. udword OutClipMask;
  324. if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
  325. TEST_CLIP_MASK
  326. // Else the box straddles one or several planes, so we need to recurse down the tree.
  327. if(node->IsLeaf())
  328. {
  329. SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
  330. }
  331. else
  332. {
  333. _CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
  334. if(ContactFound()) return;
  335. _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
  336. }
  337. }
  338. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  339. /**
  340. * Recursive collision query for no-leaf AABB trees.
  341. * \param node [in] current collision node
  342. */
  343. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. void PlanesCollider::_Collide(const AABBNoLeafNode* node, udword clip_mask)
  345. {
  346. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  347. udword OutClipMask;
  348. if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return;
  349. TEST_CLIP_MASK
  350. // Else the box straddles one or several planes, so we need to recurse down the tree.
  351. if(node->HasPosLeaf()) { PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
  352. else _Collide(node->GetPos(), OutClipMask);
  353. if(ContactFound()) return;
  354. if(node->HasNegLeaf()) { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
  355. else _Collide(node->GetNeg(), OutClipMask);
  356. }
  357. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  358. /**
  359. * Recursive collision query for no-leaf AABB trees.
  360. * \param node [in] current collision node
  361. */
  362. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  363. void PlanesCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask)
  364. {
  365. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  366. udword OutClipMask;
  367. if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return;
  368. TEST_CLIP_MASK
  369. // Else the box straddles one or several planes, so we need to recurse down the tree.
  370. if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
  371. else _CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
  372. if(ContactFound()) return;
  373. if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
  374. else _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
  375. }
  376. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. /**
  378. * Recursive collision query for quantized no-leaf AABB trees.
  379. * \param node [in] current collision node
  380. */
  381. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  382. void PlanesCollider::_Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask)
  383. {
  384. // Dequantize box
  385. const QuantizedAABB& Box = node->mAABB;
  386. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  387. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  388. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  389. udword OutClipMask;
  390. if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
  391. TEST_CLIP_MASK
  392. // Else the box straddles one or several planes, so we need to recurse down the tree.
  393. if(node->HasPosLeaf()) { PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
  394. else _Collide(node->GetPos(), OutClipMask);
  395. if(ContactFound()) return;
  396. if(node->HasNegLeaf()) { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
  397. else _Collide(node->GetNeg(), OutClipMask);
  398. }
  399. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  400. /**
  401. * Recursive collision query for quantized no-leaf AABB trees.
  402. * \param node [in] current collision node
  403. */
  404. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  405. void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask)
  406. {
  407. // Dequantize box
  408. const QuantizedAABB& Box = node->mAABB;
  409. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  410. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  411. // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
  412. udword OutClipMask;
  413. if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
  414. TEST_CLIP_MASK
  415. // Else the box straddles one or several planes, so we need to recurse down the tree.
  416. if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
  417. else _CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
  418. if(ContactFound()) return;
  419. if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
  420. else _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
  421. }
  422. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  423. /**
  424. * Constructor.
  425. */
  426. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  427. HybridPlanesCollider::HybridPlanesCollider()
  428. {
  429. }
  430. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  431. /**
  432. * Destructor.
  433. */
  434. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  435. HybridPlanesCollider::~HybridPlanesCollider()
  436. {
  437. }
  438. bool HybridPlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm)
  439. {
  440. // We don't want primitive tests here!
  441. mFlags |= OPC_NO_PRIMITIVE_TESTS;
  442. // Checkings
  443. if(!Setup(&model)) return false;
  444. // Init collision query
  445. if(InitQuery(cache, planes, nb_planes, worldm)) return true;
  446. // Special case for 1-leaf trees
  447. if(mCurrentModel && mCurrentModel->HasSingleNode())
  448. {
  449. // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
  450. udword Nb = mIMesh->GetNbTriangles();
  451. // Loop through all triangles
  452. udword clip_mask = (1<<mNbPlanes)-1;
  453. for(udword i=0;i<Nb;i++)
  454. {
  455. PLANES_PRIM(i, OPC_CONTACT)
  456. }
  457. return true;
  458. }
  459. // Override destination array since we're only going to get leaf boxes here
  460. mTouchedBoxes.Reset();
  461. mTouchedPrimitives = &mTouchedBoxes;
  462. udword PlaneMask = (1<<nb_planes)-1;
  463. // Now, do the actual query against leaf boxes
  464. if(!model.HasLeafNodes())
  465. {
  466. if(model.IsQuantized())
  467. {
  468. const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
  469. // Setup dequantization coeffs
  470. mCenterCoeff = Tree->mCenterCoeff;
  471. mExtentsCoeff = Tree->mExtentsCoeff;
  472. // Perform collision query - we don't want primitive tests here!
  473. _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  474. }
  475. else
  476. {
  477. const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
  478. // Perform collision query - we don't want primitive tests here!
  479. _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  480. }
  481. }
  482. else
  483. {
  484. if(model.IsQuantized())
  485. {
  486. const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
  487. // Setup dequantization coeffs
  488. mCenterCoeff = Tree->mCenterCoeff;
  489. mExtentsCoeff = Tree->mExtentsCoeff;
  490. // Perform collision query - we don't want primitive tests here!
  491. _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  492. }
  493. else
  494. {
  495. const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
  496. // Perform collision query - we don't want primitive tests here!
  497. _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
  498. }
  499. }
  500. // We only have a list of boxes so far
  501. if(GetContactStatus())
  502. {
  503. // Reset contact status, since it currently only reflects collisions with leaf boxes
  504. Collider::InitQuery();
  505. // Change dest container so that we can use built-in overlap tests and get collided primitives
  506. cache.TouchedPrimitives.Reset();
  507. mTouchedPrimitives = &cache.TouchedPrimitives;
  508. // Read touched leaf boxes
  509. udword Nb = mTouchedBoxes.GetNbEntries();
  510. const udword* Touched = mTouchedBoxes.GetEntries();
  511. const LeafTriangles* LT = model.GetLeafTriangles();
  512. const udword* Indices = model.GetIndices();
  513. // Loop through touched leaves
  514. udword clip_mask = (1<<mNbPlanes)-1;
  515. while(Nb--)
  516. {
  517. const LeafTriangles& CurrentLeaf = LT[*Touched++];
  518. // Each leaf box has a set of triangles
  519. udword NbTris = CurrentLeaf.GetNbTriangles();
  520. if(Indices)
  521. {
  522. const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
  523. // Loop through triangles and test each of them
  524. while(NbTris--)
  525. {
  526. udword TriangleIndex = *T++;
  527. PLANES_PRIM(TriangleIndex, OPC_CONTACT)
  528. }
  529. }
  530. else
  531. {
  532. udword BaseIndex = CurrentLeaf.GetTriangleIndex();
  533. // Loop through triangles and test each of them
  534. while(NbTris--)
  535. {
  536. udword TriangleIndex = BaseIndex++;
  537. PLANES_PRIM(TriangleIndex, OPC_CONTACT)
  538. }
  539. }
  540. }
  541. }
  542. return true;
  543. }