BodyManager.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/PhysicsSettings.h>
  5. #include <Physics/Body/BodyManager.h>
  6. #include <Physics/Body/BodyCreationSettings.h>
  7. #include <Physics/Body/BodyLock.h>
  8. #include <Physics/Body/BodyActivationListener.h>
  9. #include <Physics/StateRecorder.h>
  10. #include <Core/StringTools.h>
  11. #ifdef JPH_DEBUG_RENDERER
  12. #include <Renderer/DebugRenderer.h>
  13. #endif // JPH_DEBUG_RENDERER
  14. namespace JPH {
  15. #ifdef JPH_ENABLE_ASSERTS
  16. thread_local bool BodyManager::sOverrideAllowActivation = false;
  17. thread_local bool BodyManager::sOverrideAllowDeactivation = false;
  18. #endif
  19. BodyManager::~BodyManager()
  20. {
  21. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  22. // Destroy any bodies that are still alive
  23. for (Body *b : mBodies)
  24. if (sIsValidBodyPointer(b))
  25. delete b;
  26. delete [] mActiveBodies;
  27. }
  28. void BodyManager::Init(uint inMaxBodies, uint inNumBodyMutexes)
  29. {
  30. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  31. // Num body mutexes must be a power of two and not bigger than our MutexMask
  32. uint num_body_mutexes = Clamp<uint>(GetNextPowerOf2(inNumBodyMutexes == 0? 2 * thread::hardware_concurrency() : inNumBodyMutexes), 1, sizeof(MutexMask) * 8);
  33. // Allocate the body mutexes
  34. mBodyMutexes.Init(num_body_mutexes);
  35. // Allocate space for bodies
  36. mBodies.reserve(inMaxBodies);
  37. // Allocate space for active bodies
  38. JPH_ASSERT(mActiveBodies == nullptr);
  39. mActiveBodies = new BodyID [inMaxBodies];
  40. // Allocate space for sequence numbers
  41. mBodySequenceNumbers.resize(inMaxBodies);
  42. }
  43. uint BodyManager::GetNumBodies() const
  44. {
  45. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  46. return mNumBodies;
  47. }
  48. BodyManager::BodyStats BodyManager::GetBodyStats() const
  49. {
  50. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  51. BodyStats stats;
  52. stats.mNumBodies = mNumBodies;
  53. stats.mMaxBodies = uint(mBodies.capacity());
  54. for (const Body *body : mBodies)
  55. if (sIsValidBodyPointer(body))
  56. {
  57. switch (body->GetMotionType())
  58. {
  59. case EMotionType::Static:
  60. stats.mNumBodiesStatic++;
  61. break;
  62. case EMotionType::Dynamic:
  63. stats.mNumBodiesDynamic++;
  64. if (body->IsActive())
  65. stats.mNumActiveBodiesDynamic++;
  66. break;
  67. case EMotionType::Kinematic:
  68. stats.mNumBodiesKinematic++;
  69. if (body->IsActive())
  70. stats.mNumActiveBodiesKinematic++;
  71. break;
  72. }
  73. }
  74. return stats;
  75. }
  76. Body *BodyManager::CreateBody(const BodyCreationSettings &inBodyCreationSettings)
  77. {
  78. // Determine next free index
  79. uint32 idx;
  80. {
  81. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  82. if (mBodyIDFreeListStart != cBodyIDFreeListEnd)
  83. {
  84. // Pop an item from the freelist
  85. JPH_ASSERT(mBodyIDFreeListStart & cIsFreedBody);
  86. idx = uint32(mBodyIDFreeListStart >> cFreedBodyIndexShift);
  87. JPH_ASSERT(!sIsValidBodyPointer(mBodies[idx]));
  88. mBodyIDFreeListStart = uintptr_t(mBodies[idx]);
  89. }
  90. else
  91. {
  92. if (mBodies.size() < mBodies.capacity())
  93. {
  94. // Allocate a new entry, note that the array should not actually resize since we've reserved it at init time
  95. idx = uint32(mBodies.size());
  96. mBodies.push_back((Body *)cBodyIDFreeListEnd);
  97. }
  98. else
  99. {
  100. // Out of bodies
  101. return nullptr;
  102. }
  103. }
  104. // Update cached number of bodies
  105. mNumBodies++;
  106. }
  107. // Get next sequence number
  108. uint8 seq_no = GetNextSequenceNumber(idx);
  109. // Fill in basic properties
  110. Body *body = new Body();
  111. body->mID = BodyID(idx, seq_no);
  112. body->mShape = inBodyCreationSettings.GetShape();
  113. body->SetFriction(inBodyCreationSettings.mFriction);
  114. body->SetRestitution(inBodyCreationSettings.mRestitution);
  115. body->mMotionType = inBodyCreationSettings.mMotionType;
  116. if (inBodyCreationSettings.mIsSensor)
  117. body->mFlags |= uint8(Body::EFlags::IsSensor);
  118. body->mObjectLayer = inBodyCreationSettings.mObjectLayer;
  119. body->mCollisionGroup = inBodyCreationSettings.mCollisionGroup;
  120. if (inBodyCreationSettings.HasMassProperties())
  121. {
  122. JPH_ASSERT(!inBodyCreationSettings.mIsSensor, "Sensors should be static and moved through BodyInterface::SetPosition/SetPositionAndRotation");
  123. MotionProperties *mp = new MotionProperties();
  124. mp->SetLinearDamping(inBodyCreationSettings.mLinearDamping);
  125. mp->SetAngularDamping(inBodyCreationSettings.mAngularDamping);
  126. mp->SetMaxLinearVelocity(inBodyCreationSettings.mMaxLinearVelocity);
  127. mp->SetMaxAngularVelocity(inBodyCreationSettings.mMaxAngularVelocity);
  128. mp->SetGravityFactor(inBodyCreationSettings.mGravityFactor);
  129. mp->SetMotionQuality(inBodyCreationSettings.mMotionQuality);
  130. mp->mAllowSleeping = inBodyCreationSettings.mAllowSleeping;
  131. mp->mIndexInActiveBodies = Body::cInactiveIndex;
  132. mp->mIslandIndex = Body::cInactiveIndex;
  133. JPH_IF_ENABLE_ASSERTS(mp->mCachedMotionType = body->mMotionType;)
  134. mp->SetMassProperties(inBodyCreationSettings.GetMassProperties());
  135. body->mMotionProperties = mp;
  136. }
  137. // Position body
  138. body->SetPositionAndRotationInternal(inBodyCreationSettings.mPosition, inBodyCreationSettings.mRotation);
  139. // Add body
  140. mBodies[idx] = body;
  141. return body;
  142. }
  143. void BodyManager::DestroyBodies(const BodyID *inBodyIDs, int inNumber)
  144. {
  145. // Don't take lock if no bodies are to be destroyed
  146. if (inNumber <= 0)
  147. return;
  148. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  149. // Update cached number of bodies
  150. JPH_ASSERT(mNumBodies >= (uint)inNumber);
  151. mNumBodies -= inNumber;
  152. for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
  153. {
  154. // Get body
  155. BodyID body_id = *b;
  156. uint32 idx = body_id.GetIndex();
  157. Body *body = mBodies[idx];
  158. // Validate that it can be removed
  159. JPH_ASSERT(body->GetID() == body_id);
  160. JPH_ASSERT(!body->IsActive());
  161. JPH_ASSERT(!body->IsInBroadPhase());
  162. // Push the id onto the freelist
  163. mBodies[idx] = (Body *)mBodyIDFreeListStart;
  164. mBodyIDFreeListStart = (uintptr_t(idx) << cFreedBodyIndexShift) | cIsFreedBody;
  165. // Free the body
  166. delete body;
  167. }
  168. #if defined(_DEBUG) && defined(JPH_ENABLE_ASSERTS)
  169. // Check that the freelist is correct
  170. size_t num_freed = 0;
  171. for (uintptr_t start = mBodyIDFreeListStart; start != cBodyIDFreeListEnd; start = uintptr_t(mBodies[start >> cFreedBodyIndexShift]))
  172. {
  173. JPH_ASSERT(start & cIsFreedBody);
  174. num_freed++;
  175. }
  176. JPH_ASSERT(mNumBodies == mBodies.size() - num_freed);
  177. #endif // defined(_DEBUG) && _defined(JPH_ENABLE_ASSERTS)
  178. }
  179. void BodyManager::ActivateBodies(const BodyID *inBodyIDs, int inNumber)
  180. {
  181. // Don't take lock if no bodies are to be activated
  182. if (inNumber <= 0)
  183. return;
  184. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  185. JPH_ASSERT(!mActiveBodiesLocked || sOverrideAllowActivation);
  186. for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
  187. {
  188. BodyID body_id = *b;
  189. Body &body = *mBodies[body_id.GetIndex()];
  190. JPH_ASSERT(GetMutexForBody(body_id).is_locked(), "Assuming that body has been locked!");
  191. JPH_ASSERT(body.GetID() == body_id);
  192. JPH_ASSERT(body.IsInBroadPhase());
  193. if (!body.IsStatic()
  194. && body.mMotionProperties->mIndexInActiveBodies == Body::cInactiveIndex)
  195. {
  196. body.mMotionProperties->mIndexInActiveBodies = mNumActiveBodies;
  197. body.ResetSleepTestSpheres();
  198. JPH_ASSERT(mNumActiveBodies < GetMaxBodies());
  199. mActiveBodies[mNumActiveBodies] = body_id;
  200. mNumActiveBodies++; // Increment atomic after setting the body ID so that PhysicsSystem::JobFindCollisions (which doesn't lock the mActiveBodiesMutex) will only read valid IDs
  201. // Count CCD bodies
  202. if (body.mMotionProperties->GetMotionQuality() == EMotionQuality::LinearCast)
  203. mNumActiveCCDBodies++;
  204. // Call activation listener
  205. if (mActivationListener != nullptr)
  206. mActivationListener->OnBodyActivated(body_id, body.GetUserData());
  207. }
  208. }
  209. }
  210. void BodyManager::DeactivateBodies(const BodyID *inBodyIDs, int inNumber)
  211. {
  212. // Don't take lock if no bodies are to be deactivated
  213. if (inNumber <= 0)
  214. return;
  215. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  216. JPH_ASSERT(!mActiveBodiesLocked || sOverrideAllowDeactivation);
  217. for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
  218. {
  219. BodyID body_id = *b;
  220. Body &body = *mBodies[body_id.GetIndex()];
  221. JPH_ASSERT(GetMutexForBody(body_id).is_locked(), "Assuming that body has been locked!");
  222. JPH_ASSERT(body.GetID() == body_id);
  223. JPH_ASSERT(body.IsInBroadPhase());
  224. if (body.mMotionProperties != nullptr
  225. && body.mMotionProperties->mIndexInActiveBodies != Body::cInactiveIndex)
  226. {
  227. uint32 last_body_index = mNumActiveBodies - 1;
  228. if (body.mMotionProperties->mIndexInActiveBodies != last_body_index)
  229. {
  230. // This is not the last body, use the last body to fill the hole
  231. BodyID last_body_id = mActiveBodies[last_body_index];
  232. mActiveBodies[body.mMotionProperties->mIndexInActiveBodies] = last_body_id;
  233. // Update that body's index in the active list
  234. Body &last_body = *mBodies[last_body_id.GetIndex()];
  235. JPH_ASSERT(last_body.mMotionProperties->mIndexInActiveBodies == last_body_index);
  236. last_body.mMotionProperties->mIndexInActiveBodies = body.mMotionProperties->mIndexInActiveBodies;
  237. }
  238. // Mark this body as no longer active
  239. body.mMotionProperties->mIndexInActiveBodies = Body::cInactiveIndex;
  240. body.mMotionProperties->mIslandIndex = Body::cInactiveIndex;
  241. // Reset velocity
  242. body.mMotionProperties->mLinearVelocity = Vec3::sZero();
  243. body.mMotionProperties->mAngularVelocity = Vec3::sZero();
  244. // Remove unused element from active bodies list
  245. --mNumActiveBodies;
  246. // Count CCD bodies
  247. if (body.mMotionProperties->GetMotionQuality() == EMotionQuality::LinearCast)
  248. mNumActiveCCDBodies--;
  249. // Call activation listener
  250. if (mActivationListener != nullptr)
  251. mActivationListener->OnBodyDeactivated(body_id, body.GetUserData());
  252. }
  253. }
  254. }
  255. void BodyManager::GetActiveBodies(BodyIDVector &outBodyIDs) const
  256. {
  257. JPH_PROFILE_FUNCTION();
  258. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  259. outBodyIDs.assign(mActiveBodies, mActiveBodies + mNumActiveBodies);
  260. }
  261. void BodyManager::GetBodyIDs(BodyIDVector &outBodies) const
  262. {
  263. JPH_PROFILE_FUNCTION();
  264. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  265. // Reserve space for all bodies
  266. outBodies.clear();
  267. outBodies.reserve(mNumBodies);
  268. // Iterate the list and find the bodies that are not null
  269. for (const Body *b : mBodies)
  270. if (sIsValidBodyPointer(b))
  271. outBodies.push_back(b->GetID());
  272. // Validate that our reservation was correct
  273. JPH_ASSERT(outBodies.size() == mNumBodies);
  274. }
  275. void BodyManager::SetBodyActivationListener(BodyActivationListener *inListener)
  276. {
  277. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  278. mActivationListener = inListener;
  279. }
  280. BodyManager::MutexMask BodyManager::GetMutexMask(const BodyID *inBodies, int inNumber) const
  281. {
  282. JPH_ASSERT(sizeof(MutexMask) * 8 >= mBodyMutexes.GetNumMutexes(), "MutexMask must have enough bits");
  283. if (inNumber >= (int)mBodyMutexes.GetNumMutexes())
  284. {
  285. // Just lock everything if there are too many bodies
  286. return GetAllBodiesMutexMask();
  287. }
  288. else
  289. {
  290. MutexMask mask = 0;
  291. for (const BodyID *b = inBodies, *b_end = inBodies + inNumber; b < b_end; ++b)
  292. if (!b->IsInvalid())
  293. {
  294. uint32 index = mBodyMutexes.GetMutexIndex(b->GetIndex());
  295. mask |= (MutexMask(1) << index);
  296. }
  297. return mask;
  298. }
  299. }
  300. void BodyManager::LockRead(MutexMask inMutexMask) const
  301. {
  302. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
  303. int index = 0;
  304. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  305. if (mask & 1)
  306. mBodyMutexes.GetMutexByIndex(index).lock_shared();
  307. }
  308. void BodyManager::UnlockRead(MutexMask inMutexMask) const
  309. {
  310. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
  311. int index = 0;
  312. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  313. if (mask & 1)
  314. mBodyMutexes.GetMutexByIndex(index).unlock_shared();
  315. }
  316. void BodyManager::LockWrite(MutexMask inMutexMask) const
  317. {
  318. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
  319. int index = 0;
  320. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  321. if (mask & 1)
  322. mBodyMutexes.GetMutexByIndex(index).lock();
  323. }
  324. void BodyManager::UnlockWrite(MutexMask inMutexMask) const
  325. {
  326. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
  327. int index = 0;
  328. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  329. if (mask & 1)
  330. mBodyMutexes.GetMutexByIndex(index).unlock();
  331. }
  332. void BodyManager::LockAllBodies() const
  333. {
  334. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
  335. mBodyMutexes.LockAll();
  336. PhysicsLock::sLock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  337. }
  338. void BodyManager::UnlockAllBodies() const
  339. {
  340. PhysicsLock::sUnlock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  341. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
  342. mBodyMutexes.UnlockAll();
  343. }
  344. void BodyManager::SaveState(StateRecorder &inStream) const
  345. {
  346. {
  347. LockAllBodies();
  348. // Count number of bodies
  349. size_t num_bodies = 0;
  350. for (const Body *b : mBodies)
  351. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  352. ++num_bodies;
  353. inStream.Write(num_bodies);
  354. // Write state of bodies
  355. for (const Body *b : mBodies)
  356. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  357. {
  358. inStream.Write(b->GetID());
  359. b->SaveState(inStream);
  360. }
  361. UnlockAllBodies();
  362. }
  363. {
  364. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  365. // Write active bodies, sort because activation can come from multiple threads, so order is not deterministic
  366. inStream.Write(mNumActiveBodies);
  367. BodyIDVector sorted_active_bodies(mActiveBodies, mActiveBodies + mNumActiveBodies);
  368. sort(sorted_active_bodies.begin(), sorted_active_bodies.end());
  369. for (const BodyID &id : sorted_active_bodies)
  370. inStream.Write(id);
  371. inStream.Write(mNumActiveCCDBodies);
  372. }
  373. }
  374. bool BodyManager::RestoreState(StateRecorder &inStream)
  375. {
  376. {
  377. LockAllBodies();
  378. // Read state of bodies, note this reads it in a way to be consistent with validation
  379. size_t old_num_bodies = 0;
  380. for (const Body *b : mBodies)
  381. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  382. ++old_num_bodies;
  383. size_t num_bodies = old_num_bodies; // Initialize to current value for validation
  384. inStream.Read(num_bodies);
  385. if (num_bodies != old_num_bodies)
  386. {
  387. JPH_ASSERT(false, "Cannot handle adding/removing bodies");
  388. UnlockAllBodies();
  389. return false;
  390. }
  391. for (Body *b : mBodies)
  392. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  393. {
  394. BodyID body_id = b->GetID(); // Initialize to current value for validation
  395. inStream.Read(body_id);
  396. if (body_id != b->GetID())
  397. {
  398. JPH_ASSERT(false, "Cannot handle adding/removing bodies");
  399. UnlockAllBodies();
  400. return false;
  401. }
  402. b->RestoreState(inStream);
  403. }
  404. UnlockAllBodies();
  405. }
  406. {
  407. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  408. // Mark current active bodies as deactivated
  409. for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
  410. mBodies[id->GetIndex()]->mMotionProperties->mIndexInActiveBodies = Body::cInactiveIndex;
  411. sort(mActiveBodies, mActiveBodies + mNumActiveBodies); // Sort for validation
  412. // Read active bodies
  413. inStream.Read(mNumActiveBodies);
  414. for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
  415. {
  416. inStream.Read(*id);
  417. mBodies[id->GetIndex()]->mMotionProperties->mIndexInActiveBodies = uint32(id - mActiveBodies);
  418. }
  419. inStream.Read(mNumActiveCCDBodies);
  420. }
  421. return true;
  422. }
  423. #ifdef JPH_DEBUG_RENDERER
  424. void BodyManager::Draw(const DrawSettings &inDrawSettings, const PhysicsSettings &inPhysicsSettings, DebugRenderer *inRenderer)
  425. {
  426. JPH_PROFILE_FUNCTION();
  427. LockAllBodies();
  428. for (const Body *body : mBodies)
  429. if (sIsValidBodyPointer(body) && body->IsInBroadPhase())
  430. {
  431. JPH_ASSERT(mBodies[body->GetID().GetIndex()] == body);
  432. bool is_sensor = body->IsSensor();
  433. // Determine drawing mode
  434. Color color;
  435. if (is_sensor)
  436. color = Color::sYellow;
  437. else
  438. switch (inDrawSettings.mDrawShapeColor)
  439. {
  440. case EShapeColor::InstanceColor:
  441. // Each instance has own color
  442. color = Color::sGetDistinctColor(body->mID.GetIndex());
  443. break;
  444. case EShapeColor::ShapeTypeColor:
  445. color = ShapeFunctions::sGet(body->GetShape()->GetSubType()).mColor;
  446. break;
  447. case EShapeColor::MotionTypeColor:
  448. // Determine color based on motion type
  449. switch (body->mMotionType)
  450. {
  451. case EMotionType::Static:
  452. color = Color::sGrey;
  453. break;
  454. case EMotionType::Kinematic:
  455. color = Color::sGreen;
  456. break;
  457. case EMotionType::Dynamic:
  458. color = Color::sGetDistinctColor(body->mID.GetIndex());
  459. break;
  460. default:
  461. JPH_ASSERT(false);
  462. color = Color::sBlack;
  463. break;
  464. }
  465. break;
  466. case EShapeColor::SleepColor:
  467. // Determine color based on motion type
  468. switch (body->mMotionType)
  469. {
  470. case EMotionType::Static:
  471. color = Color::sGrey;
  472. break;
  473. case EMotionType::Kinematic:
  474. color = body->IsActive()? Color::sGreen : Color::sRed;
  475. break;
  476. case EMotionType::Dynamic:
  477. color = body->IsActive()? Color::sYellow : Color::sRed;
  478. break;
  479. default:
  480. JPH_ASSERT(false);
  481. color = Color::sBlack;
  482. break;
  483. }
  484. break;
  485. case EShapeColor::IslandColor:
  486. // Determine color based on motion type
  487. switch (body->mMotionType)
  488. {
  489. case EMotionType::Static:
  490. color = Color::sGrey;
  491. break;
  492. case EMotionType::Kinematic:
  493. case EMotionType::Dynamic:
  494. {
  495. uint32 idx = body->GetMotionProperties()->GetIslandIndexInternal();
  496. color = idx != Body::cInactiveIndex? Color::sGetDistinctColor(idx) : Color::sLightGrey;
  497. }
  498. break;
  499. default:
  500. JPH_ASSERT(false);
  501. color = Color::sBlack;
  502. break;
  503. }
  504. break;
  505. case EShapeColor::MaterialColor:
  506. color = Color::sWhite;
  507. break;
  508. default:
  509. JPH_ASSERT(false);
  510. color = Color::sBlack;
  511. break;
  512. }
  513. // Draw the results of GetSupportFunction
  514. if (inDrawSettings.mDrawGetSupportFunction)
  515. body->mShape->DrawGetSupportFunction(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), color, inDrawSettings.mDrawSupportDirection);
  516. // Draw the results of GetSupportingFace
  517. if (inDrawSettings.mDrawGetSupportingFace)
  518. body->mShape->DrawGetSupportingFace(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
  519. // Draw the shape
  520. if (inDrawSettings.mDrawShape)
  521. body->mShape->Draw(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), color, inDrawSettings.mDrawShapeColor == EShapeColor::MaterialColor, inDrawSettings.mDrawShapeWireframe || is_sensor);
  522. // Draw bounding box
  523. if (inDrawSettings.mDrawBoundingBox)
  524. inRenderer->DrawWireBox(body->mBounds, color);
  525. // Draw center of mass transform
  526. if (inDrawSettings.mDrawCenterOfMassTransform)
  527. inRenderer->DrawCoordinateSystem(body->GetCenterOfMassTransform(), 0.2f);
  528. // Draw world transform
  529. if (inDrawSettings.mDrawWorldTransform)
  530. inRenderer->DrawCoordinateSystem(body->GetWorldTransform(), 0.2f);
  531. // Draw world space linear and angular velocity
  532. if (inDrawSettings.mDrawVelocity)
  533. {
  534. Vec3 pos = body->GetCenterOfMassPosition();
  535. inRenderer->DrawArrow(pos, pos + body->GetLinearVelocity(), Color::sGreen, 0.1f);
  536. inRenderer->DrawArrow(pos, pos + body->GetAngularVelocity(), Color::sRed, 0.1f);
  537. }
  538. if (inDrawSettings.mDrawMassAndInertia && body->IsDynamic())
  539. {
  540. const MotionProperties *mp = body->GetMotionProperties();
  541. // Invert mass again
  542. float mass = 1.0f / mp->GetInverseMass();
  543. // Invert diagonal again
  544. Vec3 diagonal = mp->GetInverseInertiaDiagonal().Reciprocal();
  545. // Determine how big of a box has the equivalent inertia
  546. Vec3 box_size = MassProperties::sGetEquivalentSolidBoxSize(mass, diagonal);
  547. // Draw box with equivalent inertia
  548. inRenderer->DrawWireBox(body->GetCenterOfMassTransform() * Mat44::sRotation(mp->GetInertiaRotation()), AABox(-0.5f * box_size, 0.5f * box_size), Color::sOrange);
  549. // Draw mass
  550. inRenderer->DrawText3D(body->GetCenterOfMassPosition(), StringFormat("%.2f", (double)mass), Color::sOrange, 0.2f);
  551. }
  552. if (inDrawSettings.mDrawSleepStats && body->IsDynamic() && body->IsActive())
  553. {
  554. // Draw stats to know which bodies could go to sleep
  555. string text = StringFormat("t: %.1f", (double)body->mMotionProperties->mSleepTestTimer);
  556. uint8 g = uint8(Clamp(255.0f * body->mMotionProperties->mSleepTestTimer / inPhysicsSettings.mTimeBeforeSleep, 0.0f, 255.0f));
  557. Color sleep_color = Color(0, 255 - g, g);
  558. inRenderer->DrawText3D(body->GetCenterOfMassPosition(), text, sleep_color, 0.2f);
  559. for (int i = 0; i < 3; ++i)
  560. inRenderer->DrawWireSphere(body->mMotionProperties->mSleepTestSpheres[i].GetCenter(), body->mMotionProperties->mSleepTestSpheres[i].GetRadius(), sleep_color);
  561. }
  562. if (inDrawSettings.mDrawNames)
  563. inRenderer->DrawText3D(body->GetCenterOfMassPosition(), body->GetDebugName(), Color::sCyan, 0.2f);
  564. }
  565. UnlockAllBodies();
  566. }
  567. #endif // JPH_DEBUG_RENDERER
  568. void BodyManager::InvalidateContactCacheForBody(Body &ioBody)
  569. {
  570. lock_guard lock(mBodiesCacheInvalidMutex);
  571. if (!ioBody.IsCollisionCacheInvalid())
  572. {
  573. mBodiesCacheInvalid.push_back(ioBody.GetID());
  574. ioBody.InvalidateCollisionCacheInternal(true);
  575. }
  576. }
  577. void BodyManager::ValidateContactCacheForAllBodies()
  578. {
  579. lock_guard lock(mBodiesCacheInvalidMutex);
  580. for (const BodyID &b : mBodiesCacheInvalid)
  581. {
  582. // The body may have been removed between the call to InvalidateContactCacheForBody and this call, so check if it still exists
  583. Body *body = TryGetBody(b);
  584. if (body != nullptr)
  585. body->InvalidateCollisionCacheInternal(false);
  586. }
  587. mBodiesCacheInvalid.clear();
  588. }
  589. #ifdef _DEBUG
  590. void BodyManager::ValidateActiveBodyBounds()
  591. {
  592. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  593. for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
  594. {
  595. const Body *body = mBodies[id->GetIndex()];
  596. AABox cached = body->GetWorldSpaceBounds();
  597. AABox calculated = body->GetShape()->GetWorldSpaceBounds(body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
  598. JPH_ASSERT(cached == calculated);
  599. }
  600. }
  601. #endif // _DEBUG
  602. } // JPH