OPC_PlanesCollider.cpp 25 KB

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