BodyLock.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Physics/Body/BodyLockInterface.h>
  5. JPH_NAMESPACE_BEGIN
  6. /// Base class for locking bodies for the duration of the scope of this class (do not use directly)
  7. template <bool Write, class BodyType>
  8. class BodyLockBase : public NonCopyable
  9. {
  10. public:
  11. /// Constructor will lock the body
  12. BodyLockBase(const BodyLockInterface &inBodyLockInterface, const BodyID &inBodyID) :
  13. mBodyLockInterface(inBodyLockInterface)
  14. {
  15. if (inBodyID == BodyID())
  16. {
  17. // Invalid body id
  18. mBodyLockMutex = nullptr;
  19. mBody = nullptr;
  20. }
  21. else
  22. {
  23. // Get mutex
  24. mBodyLockMutex = Write? inBodyLockInterface.LockWrite(inBodyID) : inBodyLockInterface.LockRead(inBodyID);
  25. // Get a reference to the body or nullptr when it is no longer valid
  26. mBody = inBodyLockInterface.TryGetBody(inBodyID);
  27. }
  28. }
  29. /// Explicitly release the lock (normally this is done in the destructor)
  30. inline void ReleaseLock()
  31. {
  32. if (mBodyLockMutex != nullptr)
  33. {
  34. if (Write)
  35. mBodyLockInterface.UnlockWrite(mBodyLockMutex);
  36. else
  37. mBodyLockInterface.UnlockRead(mBodyLockMutex);
  38. mBodyLockMutex = nullptr;
  39. mBody = nullptr;
  40. }
  41. }
  42. /// Destructor will unlock the body
  43. ~BodyLockBase()
  44. {
  45. ReleaseLock();
  46. }
  47. /// Test if the lock was successful (if the body ID was valid)
  48. inline bool Succeeded() const
  49. {
  50. return mBody != nullptr;
  51. }
  52. /// Test if the lock was successful (if the body ID was valid) and the body is still in the broad phase
  53. inline bool SucceededAndIsInBroadPhase() const
  54. {
  55. return mBody != nullptr && mBody->IsInBroadPhase();
  56. }
  57. /// Access the body
  58. inline BodyType & GetBody() const
  59. {
  60. JPH_ASSERT(mBody != nullptr, "Should check Succeeded() first");
  61. return *mBody;
  62. }
  63. private:
  64. const BodyLockInterface & mBodyLockInterface;
  65. SharedMutex * mBodyLockMutex;
  66. BodyType * mBody;
  67. };
  68. /// A body lock takes a body ID and locks the underlying body so that other threads cannot access its members
  69. ///
  70. /// The common usage pattern is:
  71. ///
  72. /// BodyLockInterface lock_interface = physics_system.GetBodyLockInterface(); // Or non-locking interface if the lock is already taken
  73. /// BodyID body_id = ...; // Obtain ID to body
  74. ///
  75. /// // Scoped lock
  76. /// {
  77. /// BodyLockRead lock(lock_interface, body_id);
  78. /// if (lock.Succeeded()) // body_id may no longer be valid
  79. /// {
  80. /// const Body &body = lock.GetBody();
  81. ///
  82. /// // Do something with body
  83. /// ...
  84. /// }
  85. /// }
  86. class BodyLockRead : public BodyLockBase<false, const Body>
  87. {
  88. using BodyLockBase::BodyLockBase;
  89. };
  90. /// Specialization that locks a body for writing to. @see BodyLockRead for usage patterns.
  91. class BodyLockWrite : public BodyLockBase<true, Body>
  92. {
  93. using BodyLockBase::BodyLockBase;
  94. };
  95. JPH_NAMESPACE_END