StateRecorder.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Core/StreamIn.h>
  6. #include <Jolt/Core/StreamOut.h>
  7. JPH_NAMESPACE_BEGIN
  8. class Body;
  9. class Constraint;
  10. class BodyID;
  11. JPH_SUPPRESS_WARNING_PUSH
  12. JPH_GCC_SUPPRESS_WARNING("-Wshadow") // GCC complains about the 'Constraints' value conflicting with the 'Constraints' typedef
  13. /// A bit field that determines which aspects of the simulation to save
  14. enum class EStateRecorderState : uint8
  15. {
  16. None = 0, ///< Save nothing
  17. Global = 1, ///< Save global physics system state (delta time, gravity, etc.)
  18. Bodies = 2, ///< Save the state of bodies
  19. Contacts = 4, ///< Save the state of contacts
  20. Constraints = 8, ///< Save the state of constraints
  21. All = Global | Bodies | Contacts | Constraints ///< Save all state
  22. };
  23. JPH_SUPPRESS_WARNING_POP
  24. /// Bitwise OR operator for EStateRecorderState
  25. constexpr EStateRecorderState operator | (EStateRecorderState inLHS, EStateRecorderState inRHS)
  26. {
  27. return EStateRecorderState(uint8(inLHS) | uint8(inRHS));
  28. }
  29. /// Bitwise AND operator for EStateRecorderState
  30. constexpr EStateRecorderState operator & (EStateRecorderState inLHS, EStateRecorderState inRHS)
  31. {
  32. return EStateRecorderState(uint8(inLHS) & uint8(inRHS));
  33. }
  34. /// Bitwise XOR operator for EStateRecorderState
  35. constexpr EStateRecorderState operator ^ (EStateRecorderState inLHS, EStateRecorderState inRHS)
  36. {
  37. return EStateRecorderState(uint8(inLHS) ^ uint8(inRHS));
  38. }
  39. /// Bitwise NOT operator for EStateRecorderState
  40. constexpr EStateRecorderState operator ~ (EStateRecorderState inAllowedDOFs)
  41. {
  42. return EStateRecorderState(~uint8(inAllowedDOFs));
  43. }
  44. /// Bitwise OR assignment operator for EStateRecorderState
  45. constexpr EStateRecorderState & operator |= (EStateRecorderState &ioLHS, EStateRecorderState inRHS)
  46. {
  47. ioLHS = ioLHS | inRHS;
  48. return ioLHS;
  49. }
  50. /// Bitwise AND assignment operator for EStateRecorderState
  51. constexpr EStateRecorderState & operator &= (EStateRecorderState &ioLHS, EStateRecorderState inRHS)
  52. {
  53. ioLHS = ioLHS & inRHS;
  54. return ioLHS;
  55. }
  56. /// Bitwise XOR assignment operator for EStateRecorderState
  57. constexpr EStateRecorderState & operator ^= (EStateRecorderState &ioLHS, EStateRecorderState inRHS)
  58. {
  59. ioLHS = ioLHS ^ inRHS;
  60. return ioLHS;
  61. }
  62. /// User callbacks that allow determining which parts of the simulation should be saved by a StateRecorder
  63. class JPH_EXPORT StateRecorderFilter
  64. {
  65. public:
  66. /// Destructor
  67. virtual ~StateRecorderFilter() = default;
  68. ///@name Functions called during SaveState
  69. ///@{
  70. /// If the state of a specific body should be saved
  71. virtual bool ShouldSaveBody([[maybe_unused]] const Body &inBody) const { return true; }
  72. /// If the state of a specific constraint should be saved
  73. virtual bool ShouldSaveConstraint([[maybe_unused]] const Constraint &inConstraint) const { return true; }
  74. /// If the state of a specific contact should be saved
  75. virtual bool ShouldSaveContact([[maybe_unused]] const BodyID &inBody1, [[maybe_unused]] const BodyID &inBody2) const { return true; }
  76. ///@}
  77. ///@name Functions called during RestoreState
  78. ///@{
  79. /// If the state of a specific contact should be restored
  80. virtual bool ShouldRestoreContact([[maybe_unused]] const BodyID &inBody1, [[maybe_unused]] const BodyID &inBody2) const { return true; }
  81. ///@}
  82. };
  83. /// Class that records the state of a physics system. Can be used to check if the simulation is deterministic by putting the recorder in validation mode.
  84. /// Can be used to restore the state to an earlier point in time. Note that only the state that is modified by the simulation is saved, configuration settings
  85. /// like body friction or restitution, motion quality etc. are not saved and need to be saved by the user if desired.
  86. class JPH_EXPORT StateRecorder : public StreamIn, public StreamOut
  87. {
  88. public:
  89. /// Constructor
  90. StateRecorder() = default;
  91. StateRecorder(const StateRecorder &inRHS) : mIsValidating(inRHS.mIsValidating) { }
  92. /// Sets the stream in validation mode. In this case the physics system ensures that before it calls ReadBytes that it will
  93. /// ensure that those bytes contain the current state. This makes it possible to step and save the state, restore to the previous
  94. /// step and step again and when the recorded state is not the same it can restore the expected state and any byte that changes
  95. /// due to a ReadBytes function can be caught to find out which part of the simulation is not deterministic.
  96. /// Note that validation only works when saving the full state of the simulation (EStateRecorderState::All, StateRecorderFilter == nullptr).
  97. void SetValidating(bool inValidating) { mIsValidating = inValidating; }
  98. bool IsValidating() const { return mIsValidating; }
  99. /// This allows splitting the state in multiple parts. While restoring, only the last part should have this flag set to true.
  100. /// Note that you should ensure that the different parts contain information for disjoint sets of bodies, constraints and contacts.
  101. /// E.g. if you restore the same contact twice, you get undefined behavior. In order to create disjoint sets you can use the StateRecorderFilter.
  102. /// Note that validation is not compatible with restoring a simulation state in multiple parts.
  103. void SetIsLastPart(bool inIsLastPart) { mIsLastPart = inIsLastPart; }
  104. bool IsLastPart() const { return mIsLastPart; }
  105. private:
  106. bool mIsValidating = false;
  107. bool mIsLastPart = true;
  108. };
  109. JPH_NAMESPACE_END