ContactListenerImpl.cpp 6.1 KB

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