SubShapeID.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. JPH_NAMESPACE_BEGIN
  6. /// @brief A sub shape id contains a path to an element (usually a triangle or other primitive type) of a compound shape
  7. ///
  8. /// Each sub shape knows how many bits it needs to encode its ID, so knows how many bits to take from the sub shape ID.
  9. ///
  10. /// For example:
  11. /// * We have a CompoundShape A with 5 child shapes (identify sub shape using 3 bits AAA)
  12. /// * One of its child shapes is CompoundShape B which has 3 child shapes (identify sub shape using 2 bits BB)
  13. /// * One of its child shapes is MeshShape C which contains enough triangles to need 7 bits to identify a triangle (identify sub shape using 7 bits CCCCCCC, note that MeshShape is block based and sorts triangles spatially, you can't assume that the first triangle will have bit pattern 0000000).
  14. ///
  15. /// The bit pattern of the sub shape ID to identify a triangle in MeshShape C will then be CCCCCCCBBAAA.
  16. ///
  17. /// A sub shape ID will become invalid when the structure of the shape changes. For example, if a child shape is removed from a compound shape, the sub shape ID will no longer be valid.
  18. /// This can be a problem when caching sub shape IDs from one frame to the next. See comments at ContactListener::OnContactPersisted / OnContactRemoved.
  19. class SubShapeID
  20. {
  21. public:
  22. JPH_OVERRIDE_NEW_DELETE
  23. /// Underlying storage type
  24. using Type = uint32;
  25. /// Type that is bigger than the underlying storage type for operations that would otherwise overflow
  26. using BiggerType = uint64;
  27. static_assert(sizeof(BiggerType) > sizeof(Type), "The calculation below assumes BiggerType is a bigger type than Type");
  28. /// How many bits we can store in this ID
  29. static constexpr uint MaxBits = 8 * sizeof(Type);
  30. /// Constructor
  31. SubShapeID() = default;
  32. /// Get the next id in the chain of ids (pops parents before children)
  33. Type PopID(uint inBits, SubShapeID &outRemainder) const
  34. {
  35. Type mask_bits = Type((BiggerType(1) << inBits) - 1);
  36. Type fill_bits = Type(BiggerType(cEmpty) << (MaxBits - inBits)); // Fill left side bits with 1 so that if there's no remainder all bits will be set, note that we do this using a BiggerType since on intel 0xffffffff << 32 == 0xffffffff
  37. Type v = mValue & mask_bits;
  38. outRemainder = SubShapeID(Type(BiggerType(mValue) >> inBits) | fill_bits);
  39. return v;
  40. }
  41. /// Get the value of the path to the sub shape ID
  42. inline Type GetValue() const
  43. {
  44. return mValue;
  45. }
  46. /// Set the value of the sub shape ID (use with care!)
  47. inline void SetValue(Type inValue)
  48. {
  49. mValue = inValue;
  50. }
  51. /// Check if there is any bits of subshape ID left.
  52. /// Note that this is not a 100% guarantee as the subshape ID could consist of all 1 bits. Use for asserts only.
  53. inline bool IsEmpty() const
  54. {
  55. return mValue == cEmpty;
  56. }
  57. /// Check equal
  58. inline bool operator == (const SubShapeID &inRHS) const
  59. {
  60. return mValue == inRHS.mValue;
  61. }
  62. /// Check not-equal
  63. inline bool operator != (const SubShapeID &inRHS) const
  64. {
  65. return mValue != inRHS.mValue;
  66. }
  67. private:
  68. friend class SubShapeIDCreator;
  69. /// An empty SubShapeID has all bits set
  70. static constexpr Type cEmpty = ~Type(0);
  71. /// Constructor
  72. explicit SubShapeID(const Type &inValue) : mValue(inValue) { }
  73. /// Adds an id at a particular position in the chain
  74. /// (this should really only be called by the SubShapeIDCreator)
  75. void PushID(Type inValue, uint inFirstBit, uint inBits)
  76. {
  77. // First clear the bits
  78. mValue &= ~(Type((BiggerType(1) << inBits) - 1) << inFirstBit);
  79. // Then set them to the new value
  80. mValue |= inValue << inFirstBit;
  81. }
  82. Type mValue = cEmpty;
  83. };
  84. /// A sub shape id creator can be used to create a new sub shape id by recursing through the shape
  85. /// hierarchy and pushing new ID's onto the chain
  86. class SubShapeIDCreator
  87. {
  88. public:
  89. /// Add a new id to the chain of id's and return it
  90. SubShapeIDCreator PushID(uint inValue, uint inBits) const
  91. {
  92. JPH_ASSERT(inValue < (SubShapeID::BiggerType(1) << inBits));
  93. SubShapeIDCreator copy = *this;
  94. copy.mID.PushID(inValue, mCurrentBit, inBits);
  95. copy.mCurrentBit += inBits;
  96. JPH_ASSERT(copy.mCurrentBit <= SubShapeID::MaxBits);
  97. return copy;
  98. }
  99. // Get the resulting sub shape ID
  100. const SubShapeID & GetID() const
  101. {
  102. return mID;
  103. }
  104. /// Get the number of bits that have been written to the sub shape ID so far
  105. inline uint GetNumBitsWritten() const
  106. {
  107. return mCurrentBit;
  108. }
  109. private:
  110. SubShapeID mID;
  111. uint mCurrentBit = 0;
  112. };
  113. JPH_NAMESPACE_END