ContactListenerImpl.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Utils/ContactListenerImpl.h>
  6. #include <Renderer/DebugRendererImp.h>
  7. #include <Jolt/Physics/Body/Body.h>
  8. #include <Jolt/Physics/Collision/CollideShape.h>
  9. #include <Jolt/Core/QuickSort.h>
  10. ValidateResult ContactListenerImpl::OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult)
  11. {
  12. // Check ordering contract between body 1 and body 2
  13. bool contract = inBody1.GetMotionType() >= inBody2.GetMotionType()
  14. || (inBody1.GetMotionType() == inBody2.GetMotionType() && inBody1.GetID() < inBody2.GetID());
  15. if (!contract)
  16. JPH_BREAKPOINT;
  17. ValidateResult result;
  18. if (mNext != nullptr)
  19. result = mNext->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
  20. else
  21. result = ContactListener::OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
  22. RVec3 contact_point = inBaseOffset + inCollisionResult.mContactPointOn1;
  23. DebugRenderer::sInstance->DrawArrow(contact_point, contact_point - inCollisionResult.mPenetrationAxis.NormalizedOr(Vec3::sZero()), Color::sBlue, 0.05f);
  24. Trace("Validate %u and %u result %d", inBody1.GetID().GetIndex(), inBody2.GetID().GetIndex(), (int)result);
  25. return result;
  26. }
  27. void ContactListenerImpl::OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
  28. {
  29. // Expect bodies to be sorted
  30. if (!(inBody1.GetID() < inBody2.GetID()))
  31. JPH_BREAKPOINT;
  32. Trace("Contact added %u (%08x) and %u (%08x)", inBody1.GetID().GetIndex(), inManifold.mSubShapeID1.GetValue(), inBody2.GetID().GetIndex(), inManifold.mSubShapeID2.GetValue());
  33. DebugRenderer::sInstance->DrawWirePolygon(RMat44::sTranslation(inManifold.mBaseOffset), inManifold.mRelativeContactPointsOn1, Color::sGreen, 0.05f);
  34. DebugRenderer::sInstance->DrawWirePolygon(RMat44::sTranslation(inManifold.mBaseOffset), inManifold.mRelativeContactPointsOn2, Color::sGreen, 0.05f);
  35. DebugRenderer::sInstance->DrawArrow(inManifold.GetWorldSpaceContactPointOn1(0), inManifold.GetWorldSpaceContactPointOn1(0) + inManifold.mWorldSpaceNormal, Color::sGreen, 0.05f);
  36. // Insert new manifold into state map
  37. {
  38. lock_guard lock(mStateMutex);
  39. SubShapeIDPair key(inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2);
  40. if (mState.find(key) != mState.end())
  41. JPH_BREAKPOINT; // Added contact that already existed
  42. mState[key] = StatePair(inManifold.mBaseOffset, inManifold.mRelativeContactPointsOn1);
  43. }
  44. if (mNext != nullptr)
  45. mNext->OnContactAdded(inBody1, inBody2, inManifold, ioSettings);
  46. }
  47. void ContactListenerImpl::OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
  48. {
  49. // Expect bodies to be sorted
  50. if (!(inBody1.GetID() < inBody2.GetID()))
  51. JPH_BREAKPOINT;
  52. Trace("Contact persisted %u (%08x) and %u (%08x)", inBody1.GetID().GetIndex(), inManifold.mSubShapeID1.GetValue(), inBody2.GetID().GetIndex(), inManifold.mSubShapeID2.GetValue());
  53. DebugRenderer::sInstance->DrawWirePolygon(RMat44::sTranslation(inManifold.mBaseOffset), inManifold.mRelativeContactPointsOn1, Color::sYellow, 0.05f);
  54. DebugRenderer::sInstance->DrawWirePolygon(RMat44::sTranslation(inManifold.mBaseOffset), inManifold.mRelativeContactPointsOn2, Color::sYellow, 0.05f);
  55. DebugRenderer::sInstance->DrawArrow(inManifold.GetWorldSpaceContactPointOn1(0), inManifold.GetWorldSpaceContactPointOn1(0) + inManifold.mWorldSpaceNormal, Color::sYellow, 0.05f);
  56. // Update existing manifold in state map
  57. {
  58. lock_guard lock(mStateMutex);
  59. SubShapeIDPair key(inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2);
  60. StateMap::iterator i = mState.find(key);
  61. if (i != mState.end())
  62. i->second = StatePair(inManifold.mBaseOffset, inManifold.mRelativeContactPointsOn1);
  63. else
  64. JPH_BREAKPOINT; // Persisted contact that didn't exist
  65. }
  66. if (mNext != nullptr)
  67. mNext->OnContactPersisted(inBody1, inBody2, inManifold, ioSettings);
  68. }
  69. void ContactListenerImpl::OnContactRemoved(const SubShapeIDPair &inSubShapePair)
  70. {
  71. // Expect bodies to be sorted
  72. if (!(inSubShapePair.GetBody1ID() < inSubShapePair.GetBody2ID()))
  73. JPH_BREAKPOINT;
  74. Trace("Contact removed %u (%08x) and %u (%08x)", inSubShapePair.GetBody1ID().GetIndex(), inSubShapePair.GetSubShapeID1().GetValue(), inSubShapePair.GetBody2ID().GetIndex(), inSubShapePair.GetSubShapeID2().GetValue());
  75. // Update existing manifold in state map
  76. {
  77. lock_guard lock(mStateMutex);
  78. StateMap::iterator i = mState.find(inSubShapePair);
  79. if (i != mState.end())
  80. mState.erase(i);
  81. else
  82. JPH_BREAKPOINT; // Removed contact that didn't exist
  83. }
  84. if (mNext != nullptr)
  85. mNext->OnContactRemoved(inSubShapePair);
  86. }
  87. void ContactListenerImpl::SaveState(StateRecorder &inStream) const
  88. {
  89. // Write length
  90. uint32 length = uint32(mState.size());
  91. inStream.Write(length);
  92. // Get and sort keys
  93. Array<SubShapeIDPair> keys;
  94. for (const StateMap::value_type &kv : mState)
  95. keys.push_back(kv.first);
  96. QuickSort(keys.begin(), keys.end());
  97. // Write key value pairs
  98. for (const SubShapeIDPair &k : keys)
  99. {
  100. // Write key
  101. inStream.Write(k);
  102. // Write value
  103. const StatePair &sp = mState.find(k)->second;
  104. inStream.Write(sp.first);
  105. inStream.Write(uint32(sp.second.size()));
  106. inStream.WriteBytes(sp.second.data(), sp.second.size() * sizeof(Vec3));
  107. }
  108. }
  109. void ContactListenerImpl::RestoreState(StateRecorder &inStream)
  110. {
  111. Trace("Restore Contact State");
  112. // Read length
  113. uint32 length;
  114. if (inStream.IsValidating())
  115. length = uint32(mState.size());
  116. inStream.Read(length);
  117. Array<SubShapeIDPair> keys;
  118. // Clear the state and remember the old state for validation
  119. StateMap old_state;
  120. old_state.swap(mState);
  121. // Prepopulate keys and values with current values if we're validating
  122. if (inStream.IsValidating())
  123. {
  124. // Get and sort keys
  125. for (const StateMap::value_type &kv : old_state)
  126. keys.push_back(kv.first);
  127. QuickSort(keys.begin(), keys.end());
  128. }
  129. // Ensure we have the correct size
  130. keys.resize(length);
  131. for (size_t i = 0; i < length; ++i)
  132. {
  133. // Read key
  134. SubShapeIDPair key;
  135. if (inStream.IsValidating())
  136. key = keys[i];
  137. inStream.Read(key);
  138. StatePair sp;
  139. if (inStream.IsValidating())
  140. sp = old_state[key];
  141. // Read offset
  142. inStream.Read(sp.first);
  143. // Read num contact points
  144. uint32 num_contacts;
  145. if (inStream.IsValidating())
  146. num_contacts = uint32(old_state[key].second.size());
  147. inStream.Read(num_contacts);
  148. // Read contact points
  149. sp.second.resize(num_contacts);
  150. inStream.ReadBytes(sp.second.data(), num_contacts * sizeof(Vec3));
  151. // Store the new value
  152. mState[key] = sp;
  153. }
  154. }
  155. void ContactListenerImpl::DrawState()
  156. {
  157. Trace("Draw Contact State");
  158. lock_guard lock(mStateMutex);
  159. for (const StateMap::value_type &kv : mState)
  160. for (Vec3 v : kv.second.second)
  161. DebugRenderer::sInstance->DrawWireSphere(kv.second.first + v, 0.05f, Color::sRed, 1);
  162. }