ContactListenerImpl.cpp 6.8 KB

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