LoggingContactListener.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Physics/Collision/ContactListener.h>
  5. // Contact listener that just logs the calls made to it for later validation
  6. class LoggingContactListener : public ContactListener
  7. {
  8. public:
  9. // Contact callback type
  10. enum class EType
  11. {
  12. Validate,
  13. Add,
  14. Persist,
  15. Remove
  16. };
  17. // Entry written when a contact callback happens
  18. struct LogEntry
  19. {
  20. EType mType;
  21. BodyID mBody1;
  22. BodyID mBody2;
  23. ContactManifold mManifold;
  24. };
  25. virtual ValidateResult OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) override
  26. {
  27. // Check contract that body 1 is dynamic
  28. CHECK(inBody1.IsDynamic());
  29. lock_guard lock(mLogMutex);
  30. mLog.push_back({ EType::Validate, inBody1.GetID(), inBody2.GetID(), ContactManifold() });
  31. return ValidateResult::AcceptContact;
  32. }
  33. virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
  34. {
  35. // Check contract that body 1 < body 2
  36. CHECK(inBody1.GetID() < inBody2.GetID());
  37. lock_guard lock(mLogMutex);
  38. SubShapeIDPair key(inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2);
  39. CHECK(mExistingContacts.insert(key).second); // Validate that contact does not exist yet
  40. mLog.push_back({ EType::Add, inBody1.GetID(), inBody2.GetID(), inManifold });
  41. }
  42. virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
  43. {
  44. // Check contract that body 1 < body 2
  45. CHECK(inBody1.GetID() < inBody2.GetID());
  46. lock_guard lock(mLogMutex);
  47. SubShapeIDPair key(inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2);
  48. CHECK(mExistingContacts.find(key) != mExistingContacts.end()); // Validate that OnContactAdded was called
  49. mLog.push_back({ EType::Persist, inBody1.GetID(), inBody2.GetID(), inManifold });
  50. }
  51. virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override
  52. {
  53. // Check contract that body 1 < body 2
  54. CHECK(inSubShapePair.GetBody1ID() < inSubShapePair.GetBody2ID());
  55. lock_guard lock(mLogMutex);
  56. CHECK(mExistingContacts.erase(inSubShapePair) == 1); // Validate that OnContactAdded was called
  57. mLog.push_back({ EType::Remove, inSubShapePair.GetBody1ID(), inSubShapePair.GetBody2ID(), ContactManifold() });
  58. }
  59. void Clear()
  60. {
  61. mLog.clear();
  62. }
  63. size_t GetEntryCount() const
  64. {
  65. return mLog.size();
  66. }
  67. const LogEntry & GetEntry(size_t inIdx) const
  68. {
  69. return mLog[inIdx];
  70. }
  71. // Find first event with a particular type and involving two particular bodies
  72. int Find(EType inType, const BodyID &inBody1, const BodyID &inBody2) const
  73. {
  74. for (size_t i = 0; i < mLog.size(); ++i)
  75. {
  76. const LogEntry &e = mLog[i];
  77. if (e.mType == inType && ((e.mBody1 == inBody1 && e.mBody2 == inBody2) || (e.mBody1 == inBody2 && e.mBody2 == inBody1)))
  78. return int(i);
  79. }
  80. return -1;
  81. }
  82. // Check if event with a particular type and involving two particular bodies exists
  83. bool Contains(EType inType, const BodyID &inBody1, const BodyID &inBody2) const
  84. {
  85. return Find(inType, inBody1, inBody2) >= 0;
  86. }
  87. private:
  88. Mutex mLogMutex; // Callbacks are made from a thread, make sure we don't corrupt the log
  89. vector<LogEntry> mLog;
  90. unordered_set<SubShapeIDPair> mExistingContacts; // For validation purposes: the contacts that are currently active
  91. };