BroadPhaseQuadTree.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/Collision/BroadPhase/BroadPhaseQuadTree.h>
  5. #include <Physics/Collision/RayCast.h>
  6. #include <Physics/Collision/AABoxCast.h>
  7. #include <Physics/Collision/CastResult.h>
  8. #include <Physics/PhysicsLock.h>
  9. namespace JPH {
  10. BroadPhaseQuadTree::~BroadPhaseQuadTree()
  11. {
  12. delete [] mLayers;
  13. }
  14. void BroadPhaseQuadTree::Init(BodyManager* inBodyManager, const ObjectToBroadPhaseLayer &inObjectToBroadPhaseLayer, BroadPhaseLayerToString inBroadPhaseLayerToString)
  15. {
  16. BroadPhase::Init(inBodyManager, inObjectToBroadPhaseLayer, inBroadPhaseLayerToString);
  17. // Store input parameters
  18. mObjectToBroadPhaseLayer = inObjectToBroadPhaseLayer;
  19. mBroadPhaseLayerToString = inBroadPhaseLayerToString;
  20. // Store max bodies
  21. mMaxBodies = inBodyManager->GetMaxBodies();
  22. // Initialize tracking data
  23. mTracking.resize(mMaxBodies);
  24. // Init allocator
  25. // Estimate the amount of nodes we're going to need
  26. uint32 num_leaves = (uint32)(mMaxBodies + 1) / 2; // Assume 50% fill
  27. uint32 num_leaves_plus_internal_nodes = num_leaves + (num_leaves + 2) / 3; // = Sum(num_leaves * 4^-i) with i = [0, Inf].
  28. mAllocator.Init(2 * num_leaves_plus_internal_nodes, 256); // We use double the amount of nodes while rebuilding the tree during Update()
  29. // Determine min and max layers
  30. BroadPhaseLayer::Type min_layer = (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid, max_layer = 0;
  31. for (BroadPhaseLayer layer : inObjectToBroadPhaseLayer)
  32. {
  33. min_layer = min(min_layer, (BroadPhaseLayer::Type)layer);
  34. max_layer = max(max_layer, (BroadPhaseLayer::Type)layer);
  35. }
  36. JPH_ASSERT(min_layer == 0); // Assume layers start at 0
  37. JPH_ASSERT(max_layer != (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid); // Assume the invalid layer is unused
  38. mNumLayers = max_layer + 1;
  39. // Init sub trees
  40. mLayers = new QuadTree [mNumLayers];
  41. for (uint l = 0; l < mNumLayers; ++l)
  42. mLayers[l].Init(mAllocator);
  43. }
  44. void BroadPhaseQuadTree::FrameSync()
  45. {
  46. JPH_PROFILE_FUNCTION();
  47. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  48. mLayers[l].DiscardOldTree();
  49. }
  50. void BroadPhaseQuadTree::Optimize()
  51. {
  52. JPH_PROFILE_FUNCTION();
  53. FrameSync();
  54. LockModifications();
  55. for (uint l = 0; l < mNumLayers; ++l)
  56. {
  57. QuadTree &t = mLayers[l];
  58. if (t.HasBodies() && t.IsDirty())
  59. {
  60. QuadTree::UpdateState update_state;
  61. t.UpdatePrepare(mBodyManager->GetBodies(), mTracking, update_state);
  62. t.UpdateFinalize(mBodyManager->GetBodies(), mTracking, update_state);
  63. }
  64. }
  65. UnlockModifications();
  66. mNextLayerToUpdate = 0;
  67. }
  68. void BroadPhaseQuadTree::LockModifications()
  69. {
  70. // From this point on we prevent modifications to the tree
  71. PhysicsLock::sLock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  72. }
  73. BroadPhase::UpdateState BroadPhaseQuadTree::UpdatePrepare()
  74. {
  75. // LockModifications should have been called
  76. JPH_ASSERT(mUpdateMutex.is_locked());
  77. // Create update state
  78. UpdateState update_state;
  79. UpdateStateImpl *update_state_impl = reinterpret_cast<UpdateStateImpl *>(&update_state);
  80. // Loop until we've seen all layers
  81. for (uint iteration = 0; iteration < mNumLayers; ++iteration)
  82. {
  83. // Get the layer
  84. QuadTree &t = mLayers[mNextLayerToUpdate];
  85. mNextLayerToUpdate = (mNextLayerToUpdate + 1) % mNumLayers;
  86. // If it is dirty we update this one
  87. if (t.HasBodies() && t.IsDirty() && t.CanBeUpdated())
  88. {
  89. update_state_impl->mTree = &t;
  90. t.UpdatePrepare(mBodyManager->GetBodies(), mTracking, update_state_impl->mUpdateState);
  91. return update_state;
  92. }
  93. }
  94. // Nothing to update
  95. update_state_impl->mTree = nullptr;
  96. return update_state;
  97. }
  98. void BroadPhaseQuadTree::UpdateFinalize(UpdateState &inUpdateState)
  99. {
  100. // LockModifications should have been called
  101. JPH_ASSERT(mUpdateMutex.is_locked());
  102. // Test if a tree was updated
  103. UpdateStateImpl *update_state_impl = reinterpret_cast<UpdateStateImpl *>(&inUpdateState);
  104. if (update_state_impl->mTree == nullptr)
  105. return;
  106. update_state_impl->mTree->UpdateFinalize(mBodyManager->GetBodies(), mTracking, update_state_impl->mUpdateState);
  107. }
  108. void BroadPhaseQuadTree::UnlockModifications()
  109. {
  110. // From this point on we allow modifications to the tree again
  111. PhysicsLock::sUnlock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  112. }
  113. BroadPhase::AddState BroadPhaseQuadTree::AddBodiesPrepare(BodyID *ioBodies, int inNumber)
  114. {
  115. JPH_PROFILE_FUNCTION();
  116. JPH_ASSERT(inNumber > 0);
  117. const BodyVector &bodies = mBodyManager->GetBodies();
  118. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  119. LayerState *state = new LayerState [mNumLayers];
  120. // Sort bodies on layer
  121. const BroadPhaseLayer *object_to_broadphase = mObjectToBroadPhaseLayer.data();
  122. Body * const * const bodies_ptr = bodies.data(); // C pointer or else sort is incredibly slow in debug mode
  123. sort(ioBodies, ioBodies + inNumber, [bodies_ptr, object_to_broadphase](BodyID inLHS, BodyID inRHS) -> bool { return object_to_broadphase[bodies_ptr[inLHS.GetIndex()]->GetObjectLayer()] < object_to_broadphase[bodies_ptr[inRHS.GetIndex()]->GetObjectLayer()]; });
  124. BodyID *b_start = ioBodies, *b_end = ioBodies + inNumber;
  125. while (b_start < b_end)
  126. {
  127. // Get broadphase layer
  128. ObjectLayer first_body_object_layer = bodies[b_start->GetIndex()]->GetObjectLayer();
  129. JPH_ASSERT(first_body_object_layer < mObjectToBroadPhaseLayer.size());
  130. BroadPhaseLayer::Type broadphase_layer = (BroadPhaseLayer::Type)object_to_broadphase[first_body_object_layer];
  131. JPH_ASSERT(broadphase_layer < mNumLayers);
  132. // Find first body with different layer
  133. BodyID *b_mid = upper_bound(b_start, b_end, broadphase_layer, [bodies_ptr, object_to_broadphase](BroadPhaseLayer::Type inLayer, BodyID inBodyID) -> bool { return inLayer < (BroadPhaseLayer::Type)object_to_broadphase[bodies_ptr[inBodyID.GetIndex()]->GetObjectLayer()]; });
  134. // Keep track of state for this layer
  135. LayerState &layer_state = state[broadphase_layer];
  136. layer_state.mBodyStart = b_start;
  137. layer_state.mBodyEnd = b_mid;
  138. // Insert all bodies of the same layer
  139. mLayers[broadphase_layer].AddBodiesPrepare(bodies, mTracking, b_start, int(b_mid - b_start), layer_state.mAddState);
  140. // Keep track in which tree we placed the object
  141. for (BodyID *b = b_start; b < b_mid; ++b)
  142. {
  143. uint32 index = b->GetIndex();
  144. JPH_ASSERT(bodies[index]->GetID() == *b, "Provided BodyID doesn't match BodyID in body manager");
  145. JPH_ASSERT(!bodies[index]->IsInBroadPhase());
  146. Tracking &t = mTracking[index];
  147. JPH_ASSERT(t.mBroadPhaseLayer == (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid);
  148. t.mBroadPhaseLayer = broadphase_layer;
  149. JPH_ASSERT(t.mObjectLayer == cObjectLayerInvalid);
  150. t.mObjectLayer = bodies[index]->GetObjectLayer();
  151. }
  152. // Repeat
  153. b_start = b_mid;
  154. }
  155. return state;
  156. }
  157. void BroadPhaseQuadTree::AddBodiesFinalize(BodyID *ioBodies, int inNumber, AddState inAddState)
  158. {
  159. JPH_PROFILE_FUNCTION();
  160. // This cannot run concurrently with UpdatePrepare()/UpdateFinalize()
  161. SharedLock<SharedMutex> lock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  162. BodyVector &bodies = mBodyManager->GetBodies();
  163. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  164. LayerState *state = (LayerState *)inAddState;
  165. for (BroadPhaseLayer::Type broadphase_layer = 0; broadphase_layer < mNumLayers; broadphase_layer++)
  166. {
  167. const LayerState &l = state[broadphase_layer];
  168. if (l.mBodyStart != nullptr)
  169. {
  170. // Insert all bodies of the same layer
  171. mLayers[broadphase_layer].AddBodiesFinalize(mTracking, int(l.mBodyEnd - l.mBodyStart), l.mAddState);
  172. // Mark added to broadphase
  173. for (BodyID *b = l.mBodyStart; b < l.mBodyEnd; ++b)
  174. {
  175. uint32 index = b->GetIndex();
  176. JPH_ASSERT(bodies[index]->GetID() == *b, "Provided BodyID doesn't match BodyID in body manager");
  177. JPH_ASSERT(mTracking[index].mBroadPhaseLayer == broadphase_layer);
  178. JPH_ASSERT(mTracking[index].mObjectLayer == bodies[index]->GetObjectLayer());
  179. JPH_ASSERT(!bodies[index]->IsInBroadPhase());
  180. bodies[index]->SetInBroadPhaseInternal(true);
  181. }
  182. }
  183. }
  184. delete [] state;
  185. }
  186. void BroadPhaseQuadTree::AddBodiesAbort(BodyID *ioBodies, int inNumber, AddState inAddState)
  187. {
  188. JPH_PROFILE_FUNCTION();
  189. JPH_IF_ENABLE_ASSERTS(const BodyVector &bodies = mBodyManager->GetBodies();)
  190. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  191. LayerState *state = (LayerState *)inAddState;
  192. for (BroadPhaseLayer::Type broadphase_layer = 0; broadphase_layer < mNumLayers; broadphase_layer++)
  193. {
  194. const LayerState &l = state[broadphase_layer];
  195. if (l.mBodyStart != nullptr)
  196. {
  197. // Insert all bodies of the same layer
  198. mLayers[broadphase_layer].AddBodiesAbort(mTracking, l.mAddState);
  199. // Reset bookkeeping
  200. for (BodyID *b = l.mBodyStart; b < l.mBodyEnd; ++b)
  201. {
  202. uint32 index = b->GetIndex();
  203. JPH_ASSERT(bodies[index]->GetID() == *b, "Provided BodyID doesn't match BodyID in body manager");
  204. JPH_ASSERT(!bodies[index]->IsInBroadPhase());
  205. Tracking &t = mTracking[index];
  206. JPH_ASSERT(t.mBroadPhaseLayer == broadphase_layer);
  207. t.mBroadPhaseLayer = (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid;
  208. t.mObjectLayer = cObjectLayerInvalid;
  209. }
  210. }
  211. }
  212. delete [] state;
  213. }
  214. void BroadPhaseQuadTree::RemoveBodies(BodyID *ioBodies, int inNumber)
  215. {
  216. JPH_PROFILE_FUNCTION();
  217. // This cannot run concurrently with UpdatePrepare()/UpdateFinalize()
  218. SharedLock<SharedMutex> lock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  219. JPH_ASSERT(inNumber > 0);
  220. BodyVector &bodies = mBodyManager->GetBodies();
  221. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  222. // Sort bodies on layer
  223. Tracking *tracking = mTracking.data(); // C pointer or else sort is incredibly slow in debug mode
  224. sort(ioBodies, ioBodies + inNumber, [tracking](BodyID inLHS, BodyID inRHS) -> bool { return tracking[inLHS.GetIndex()].mBroadPhaseLayer < tracking[inRHS.GetIndex()].mBroadPhaseLayer; });
  225. BodyID *b_start = ioBodies, *b_end = ioBodies + inNumber;
  226. while (b_start < b_end)
  227. {
  228. // Get broad phase layer
  229. BroadPhaseLayer::Type broadphase_layer = mTracking[b_start->GetIndex()].mBroadPhaseLayer;
  230. JPH_ASSERT(broadphase_layer != (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid);
  231. // Find first body with different layer
  232. BodyID *b_mid = upper_bound(b_start, b_end, broadphase_layer, [tracking](BroadPhaseLayer::Type inLayer, BodyID inBodyID) -> bool { return inLayer < tracking[inBodyID.GetIndex()].mBroadPhaseLayer; });
  233. // Remove all bodies of the same layer
  234. mLayers[broadphase_layer].RemoveBodies(bodies, mTracking, b_start, int(b_mid - b_start));
  235. for (BodyID *b = b_start; b < b_mid; ++b)
  236. {
  237. // Reset bookkeeping
  238. uint32 index = b->GetIndex();
  239. Tracking &t = tracking[index];
  240. t.mBroadPhaseLayer = (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid;
  241. t.mObjectLayer = cObjectLayerInvalid;
  242. // Mark removed from broadphase
  243. JPH_ASSERT(bodies[index]->IsInBroadPhase());
  244. bodies[index]->SetInBroadPhaseInternal(false);
  245. }
  246. // Repeat
  247. b_start = b_mid;
  248. }
  249. }
  250. void BroadPhaseQuadTree::NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber, bool inTakeLock)
  251. {
  252. JPH_PROFILE_FUNCTION();
  253. JPH_ASSERT(inNumber > 0);
  254. // This cannot run concurrently with UpdatePrepare()/UpdateFinalize()
  255. if (inTakeLock)
  256. PhysicsLock::sLockShared(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  257. else
  258. JPH_ASSERT(mUpdateMutex.is_locked());
  259. const BodyVector &bodies = mBodyManager->GetBodies();
  260. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  261. // Sort bodies on layer
  262. Tracking *tracking = mTracking.data(); // C pointer or else sort is incredibly slow in debug mode
  263. sort(ioBodies, ioBodies + inNumber, [tracking](BodyID inLHS, BodyID inRHS) -> bool { return tracking[inLHS.GetIndex()].mBroadPhaseLayer < tracking[inRHS.GetIndex()].mBroadPhaseLayer; });
  264. BodyID *b_start = ioBodies, *b_end = ioBodies + inNumber;
  265. while (b_start < b_end)
  266. {
  267. // Get broadphase layer
  268. BroadPhaseLayer::Type broadphase_layer = tracking[b_start->GetIndex()].mBroadPhaseLayer;
  269. JPH_ASSERT(broadphase_layer != (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid);
  270. // Find first body with different layer
  271. BodyID *b_mid = upper_bound(b_start, b_end, broadphase_layer, [tracking](BroadPhaseLayer::Type inLayer, BodyID inBodyID) -> bool { return inLayer < tracking[inBodyID.GetIndex()].mBroadPhaseLayer; });
  272. // Nodify all bodies of the same layer changed
  273. mLayers[broadphase_layer].NotifyBodiesAABBChanged(bodies, mTracking, b_start, int(b_mid - b_start));
  274. // Repeat
  275. b_start = b_mid;
  276. }
  277. if (inTakeLock)
  278. PhysicsLock::sUnlockShared(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  279. }
  280. void BroadPhaseQuadTree::NotifyBodiesLayerChanged(BodyID *ioBodies, int inNumber)
  281. {
  282. JPH_PROFILE_FUNCTION();
  283. JPH_ASSERT(inNumber > 0);
  284. // First sort the bodies that actually changed layer to beginning of the array
  285. const BodyVector &bodies = mBodyManager->GetBodies();
  286. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  287. for (BodyID *body_id = ioBodies + inNumber - 1; body_id >= ioBodies; --body_id)
  288. {
  289. uint32 index = body_id->GetIndex();
  290. JPH_ASSERT(bodies[index]->GetID() == *body_id, "Provided BodyID doesn't match BodyID in body manager");
  291. ObjectLayer object_layer = bodies[index]->GetObjectLayer();
  292. JPH_ASSERT(object_layer < mObjectToBroadPhaseLayer.size());
  293. BroadPhaseLayer::Type broadphase_layer = (BroadPhaseLayer::Type)mObjectToBroadPhaseLayer[object_layer];
  294. JPH_ASSERT(broadphase_layer < mNumLayers);
  295. if (mTracking[index].mBroadPhaseLayer == broadphase_layer)
  296. {
  297. // Update tracking information
  298. mTracking[index].mObjectLayer = object_layer;
  299. // If move the body to the end, layer didn't change
  300. swap(*body_id, ioBodies[inNumber - 1]);
  301. --inNumber;
  302. }
  303. }
  304. if (inNumber > 0)
  305. {
  306. // Changing layer requires us to remove from one tree and add to another, so this is equivalent to removing all bodies first and then adding them again
  307. RemoveBodies(ioBodies, inNumber);
  308. AddState add_state = AddBodiesPrepare(ioBodies, inNumber);
  309. AddBodiesFinalize(ioBodies, inNumber, add_state);
  310. }
  311. }
  312. void BroadPhaseQuadTree::CastRay(const RayCast &inRay, RayCastBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  313. {
  314. JPH_PROFILE_FUNCTION();
  315. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  316. // Loop over all layers and test the ones that could hit
  317. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  318. if (inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  319. {
  320. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  321. mLayers[l].CastRay(inRay, ioCollector, inObjectLayerFilter, mTracking);
  322. if (ioCollector.ShouldEarlyOut())
  323. break;
  324. }
  325. }
  326. void BroadPhaseQuadTree::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  327. {
  328. JPH_PROFILE_FUNCTION();
  329. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  330. // Loop over all layers and test the ones that could hit
  331. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  332. if (inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  333. {
  334. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  335. mLayers[l].CollideAABox(inBox, ioCollector, inObjectLayerFilter, mTracking);
  336. if (ioCollector.ShouldEarlyOut())
  337. break;
  338. }
  339. }
  340. void BroadPhaseQuadTree::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  341. {
  342. JPH_PROFILE_FUNCTION();
  343. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  344. // Loop over all layers and test the ones that could hit
  345. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  346. if (inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  347. {
  348. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  349. mLayers[l].CollideSphere(inCenter, inRadius, ioCollector, inObjectLayerFilter, mTracking);
  350. if (ioCollector.ShouldEarlyOut())
  351. break;
  352. }
  353. }
  354. void BroadPhaseQuadTree::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  355. {
  356. JPH_PROFILE_FUNCTION();
  357. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  358. // Loop over all layers and test the ones that could hit
  359. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  360. if (inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  361. {
  362. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  363. mLayers[l].CollidePoint(inPoint, ioCollector, inObjectLayerFilter, mTracking);
  364. if (ioCollector.ShouldEarlyOut())
  365. break;
  366. }
  367. }
  368. void BroadPhaseQuadTree::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  369. {
  370. JPH_PROFILE_FUNCTION();
  371. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  372. // Loop over all layers and test the ones that could hit
  373. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  374. if (inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  375. {
  376. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  377. mLayers[l].CollideOrientedBox(inBox, ioCollector, inObjectLayerFilter, mTracking);
  378. if (ioCollector.ShouldEarlyOut())
  379. break;
  380. }
  381. }
  382. void BroadPhaseQuadTree::CastAABox(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  383. {
  384. JPH_PROFILE_FUNCTION();
  385. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  386. // Loop over all layers and test the ones that could hit
  387. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  388. if (inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  389. {
  390. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  391. mLayers[l].CastAABox(inBox, ioCollector, inObjectLayerFilter, mTracking);
  392. if (ioCollector.ShouldEarlyOut())
  393. break;
  394. }
  395. }
  396. void BroadPhaseQuadTree::FindCollidingPairs(BodyID *ioActiveBodies, int inNumActiveBodies, float inSpeculativeContactDistance, ObjectVsBroadPhaseLayerFilter inObjectVsBroadPhaseLayerFilter, ObjectLayerPairFilter inObjectLayerPairFilter, BodyPairCollector &ioPairCollector) const
  397. {
  398. JPH_PROFILE_FUNCTION();
  399. const BodyVector &bodies = mBodyManager->GetBodies();
  400. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  401. // Sort bodies on layer
  402. const Tracking *tracking = mTracking.data(); // C pointer or else sort is incredibly slow in debug mode
  403. sort(ioActiveBodies, ioActiveBodies + inNumActiveBodies, [tracking](BodyID inLHS, BodyID inRHS) -> bool { return tracking[inLHS.GetIndex()].mObjectLayer < tracking[inRHS.GetIndex()].mObjectLayer; });
  404. BodyID *b_start = ioActiveBodies, *b_end = ioActiveBodies + inNumActiveBodies;
  405. while (b_start < b_end)
  406. {
  407. // Get broadphase layer
  408. ObjectLayer object_layer = tracking[b_start->GetIndex()].mObjectLayer;
  409. JPH_ASSERT(object_layer != cObjectLayerInvalid);
  410. // Find first body with different layer
  411. BodyID *b_mid = upper_bound(b_start, b_end, object_layer, [tracking](ObjectLayer inLayer, BodyID inBodyID) -> bool { return inLayer < tracking[inBodyID.GetIndex()].mObjectLayer; });
  412. // Loop over all layers and test the ones that could hit
  413. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  414. if (inObjectVsBroadPhaseLayerFilter(object_layer, BroadPhaseLayer(l)))
  415. {
  416. JPH_PROFILE(mBroadPhaseLayerToString != nullptr? mBroadPhaseLayerToString(BroadPhaseLayer(l)) : "QuadTree");
  417. mLayers[l].FindCollidingPairs(bodies, b_start, int(b_mid - b_start), inSpeculativeContactDistance, ioPairCollector, inObjectLayerPairFilter);
  418. }
  419. // Repeat
  420. b_start = b_mid;
  421. }
  422. }
  423. } // JPH