MutableCompoundShape.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>
  5. #include <Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h>
  6. #include <Jolt/Core/Profiler.h>
  7. #include <Jolt/Core/StreamIn.h>
  8. #include <Jolt/Core/StreamOut.h>
  9. #include <Jolt/ObjectStream/TypeDeclarations.h>
  10. JPH_NAMESPACE_BEGIN
  11. JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(MutableCompoundShapeSettings)
  12. {
  13. JPH_ADD_BASE_CLASS(MutableCompoundShapeSettings, CompoundShapeSettings)
  14. }
  15. ShapeSettings::ShapeResult MutableCompoundShapeSettings::Create() const
  16. {
  17. // Build a mutable compound shape
  18. if (mCachedResult.IsEmpty())
  19. Ref<Shape> shape = new MutableCompoundShape(*this, mCachedResult);
  20. return mCachedResult;
  21. }
  22. MutableCompoundShape::MutableCompoundShape(const MutableCompoundShapeSettings &inSettings, ShapeResult &outResult) :
  23. CompoundShape(EShapeSubType::MutableCompound, inSettings, outResult)
  24. {
  25. mSubShapes.reserve(inSettings.mSubShapes.size());
  26. for (const CompoundShapeSettings::SubShapeSettings &shape : inSettings.mSubShapes)
  27. {
  28. // Start constructing the runtime sub shape
  29. SubShape out_shape;
  30. if (!out_shape.FromSettings(shape, outResult))
  31. return;
  32. mSubShapes.push_back(out_shape);
  33. }
  34. AdjustCenterOfMass();
  35. CalculateSubShapeBounds(0, (uint)mSubShapes.size());
  36. // Check if we're not exceeding the amount of sub shape id bits
  37. if (GetSubShapeIDBitsRecursive() > SubShapeID::MaxBits)
  38. {
  39. outResult.SetError("Compound hierarchy is too deep and exceeds the amount of available sub shape ID bits");
  40. return;
  41. }
  42. outResult.Set(this);
  43. }
  44. void MutableCompoundShape::AdjustCenterOfMass()
  45. {
  46. // First calculate the delta of the center of mass
  47. float mass = 0.0f;
  48. Vec3 center_of_mass = Vec3::sZero();
  49. for (const CompoundShape::SubShape &sub_shape : mSubShapes)
  50. {
  51. MassProperties child = sub_shape.mShape->GetMassProperties();
  52. mass += child.mMass;
  53. center_of_mass += sub_shape.GetPositionCOM() * child.mMass;
  54. }
  55. if (mass > 0.0f)
  56. center_of_mass /= mass;
  57. // Now adjust all shapes to recenter around center of mass
  58. for (CompoundShape::SubShape &sub_shape : mSubShapes)
  59. sub_shape.SetPositionCOM(sub_shape.GetPositionCOM() - center_of_mass);
  60. // And adjust the center of mass for this shape in the opposite direction
  61. mCenterOfMass += center_of_mass;
  62. }
  63. void MutableCompoundShape::CalculateLocalBounds()
  64. {
  65. uint num_blocks = GetNumBlocks();
  66. if (num_blocks > 0)
  67. {
  68. // Initialize min/max for first block
  69. const Bounds *bounds = mSubShapeBounds.data();
  70. Vec4 min_x = bounds->mMinX;
  71. Vec4 min_y = bounds->mMinY;
  72. Vec4 min_z = bounds->mMinZ;
  73. Vec4 max_x = bounds->mMaxX;
  74. Vec4 max_y = bounds->mMaxY;
  75. Vec4 max_z = bounds->mMaxZ;
  76. // Accumulate other blocks
  77. const Bounds *bounds_end = bounds + num_blocks;
  78. for (++bounds; bounds < bounds_end; ++bounds)
  79. {
  80. min_x = Vec4::sMin(min_x, bounds->mMinX);
  81. min_y = Vec4::sMin(min_y, bounds->mMinY);
  82. min_z = Vec4::sMin(min_z, bounds->mMinZ);
  83. max_x = Vec4::sMax(max_x, bounds->mMaxX);
  84. max_y = Vec4::sMax(max_y, bounds->mMaxY);
  85. max_z = Vec4::sMax(max_z, bounds->mMaxZ);
  86. }
  87. // Calculate resulting bounding box
  88. mLocalBounds.mMin.SetX(min_x.ReduceMin());
  89. mLocalBounds.mMin.SetY(min_y.ReduceMin());
  90. mLocalBounds.mMin.SetZ(min_z.ReduceMin());
  91. mLocalBounds.mMax.SetX(max_x.ReduceMax());
  92. mLocalBounds.mMax.SetY(max_y.ReduceMax());
  93. mLocalBounds.mMax.SetZ(max_z.ReduceMax());
  94. }
  95. else
  96. {
  97. // There are no subshapes, set the bounding box to invalid
  98. mLocalBounds.SetEmpty();
  99. }
  100. // Cache the inner radius as it can take a while to recursively iterate over all sub shapes
  101. CalculateInnerRadius();
  102. }
  103. void MutableCompoundShape::EnsureSubShapeBoundsCapacity()
  104. {
  105. // Check if we have enough space
  106. uint new_capacity = ((uint)mSubShapes.size() + 3) >> 2;
  107. if (mSubShapeBounds.size() < new_capacity)
  108. mSubShapeBounds.resize(new_capacity);
  109. }
  110. void MutableCompoundShape::CalculateSubShapeBounds(uint inStartIdx, uint inNumber)
  111. {
  112. // Ensure that we have allocated the required space for mSubShapeBounds
  113. EnsureSubShapeBoundsCapacity();
  114. // Loop over blocks of 4 sub shapes
  115. for (uint sub_shape_idx_start = inStartIdx & ~uint(3), sub_shape_idx_end = inStartIdx + inNumber; sub_shape_idx_start < sub_shape_idx_end; sub_shape_idx_start += 4)
  116. {
  117. Mat44 bounds_min;
  118. Mat44 bounds_max;
  119. AABox sub_shape_bounds;
  120. for (uint col = 0; col < 4; ++col)
  121. {
  122. uint sub_shape_idx = sub_shape_idx_start + col;
  123. if (sub_shape_idx < mSubShapes.size()) // else reuse sub_shape_bounds from previous iteration
  124. {
  125. const SubShape &sub_shape = mSubShapes[sub_shape_idx];
  126. // Tranform the shape's bounds into our local space
  127. Mat44 transform = Mat44::sRotationTranslation(sub_shape.GetRotation(), sub_shape.GetPositionCOM());
  128. // Get the bounding box
  129. sub_shape_bounds = sub_shape.mShape->GetWorldSpaceBounds(transform, Vec3::sReplicate(1.0f));
  130. }
  131. // Put the bounds as columns in a matrix
  132. bounds_min.SetColumn3(col, sub_shape_bounds.mMin);
  133. bounds_max.SetColumn3(col, sub_shape_bounds.mMax);
  134. }
  135. // Transpose to go to strucucture of arrays format
  136. Mat44 bounds_min_t = bounds_min.Transposed();
  137. Mat44 bounds_max_t = bounds_max.Transposed();
  138. // Store in our bounds array
  139. Bounds &bounds = mSubShapeBounds[sub_shape_idx_start >> 2];
  140. bounds.mMinX = bounds_min_t.GetColumn4(0);
  141. bounds.mMinY = bounds_min_t.GetColumn4(1);
  142. bounds.mMinZ = bounds_min_t.GetColumn4(2);
  143. bounds.mMaxX = bounds_max_t.GetColumn4(0);
  144. bounds.mMaxY = bounds_max_t.GetColumn4(1);
  145. bounds.mMaxZ = bounds_max_t.GetColumn4(2);
  146. }
  147. CalculateLocalBounds();
  148. }
  149. uint MutableCompoundShape::AddShape(Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape, uint32 inUserData)
  150. {
  151. SubShape sub_shape;
  152. sub_shape.mShape = inShape;
  153. sub_shape.mUserData = inUserData;
  154. sub_shape.SetTransform(inPosition, inRotation, mCenterOfMass);
  155. mSubShapes.push_back(sub_shape);
  156. uint shape_idx = (uint)mSubShapes.size() - 1;
  157. CalculateSubShapeBounds(shape_idx, 1);
  158. return shape_idx;
  159. }
  160. void MutableCompoundShape::RemoveShape(uint inIndex)
  161. {
  162. mSubShapes.erase(mSubShapes.begin() + inIndex);
  163. uint num_bounds = (uint)mSubShapes.size() - inIndex;
  164. if (num_bounds > 0)
  165. CalculateSubShapeBounds(inIndex, num_bounds);
  166. else
  167. CalculateLocalBounds();
  168. }
  169. void MutableCompoundShape::ModifyShape(uint inIndex, Vec3Arg inPosition, QuatArg inRotation)
  170. {
  171. SubShape &sub_shape = mSubShapes[inIndex];
  172. sub_shape.SetTransform(inPosition, inRotation, mCenterOfMass);
  173. CalculateSubShapeBounds(inIndex, 1);
  174. }
  175. void MutableCompoundShape::ModifyShape(uint inIndex, Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape)
  176. {
  177. SubShape &sub_shape = mSubShapes[inIndex];
  178. sub_shape.mShape = inShape;
  179. sub_shape.SetTransform(inPosition, inRotation, mCenterOfMass);
  180. CalculateSubShapeBounds(inIndex, 1);
  181. }
  182. void MutableCompoundShape::ModifyShapes(uint inStartIndex, uint inNumber, const Vec3 *inPositions, const Quat *inRotations, uint inPositionStride, uint inRotationStride)
  183. {
  184. JPH_ASSERT(inStartIndex + inNumber <= mSubShapes.size());
  185. const Vec3 *pos = inPositions;
  186. const Quat *rot = inRotations;
  187. for (SubShape *dest = &mSubShapes[inStartIndex], *dest_end = dest + inNumber; dest < dest_end; ++dest)
  188. {
  189. // Update transform
  190. dest->SetTransform(*pos, *rot, mCenterOfMass);
  191. // Advance pointer in position / rotation buffer
  192. pos = reinterpret_cast<const Vec3 *>(reinterpret_cast<const uint8 *>(pos) + inPositionStride);
  193. rot = reinterpret_cast<const Quat *>(reinterpret_cast<const uint8 *>(rot) + inRotationStride);
  194. }
  195. CalculateSubShapeBounds(inStartIndex, inNumber);
  196. }
  197. template <class Visitor>
  198. inline void MutableCompoundShape::WalkSubShapes(Visitor &ioVisitor) const
  199. {
  200. // Loop over all blocks of 4 bounding boxes
  201. for (uint block = 0, num_blocks = GetNumBlocks(); block < num_blocks; ++block)
  202. {
  203. // Test the bounding boxes
  204. const Bounds &bounds = mSubShapeBounds[block];
  205. typename Visitor::Result result = ioVisitor.TestBlock(bounds.mMinX, bounds.mMinY, bounds.mMinZ, bounds.mMaxX, bounds.mMaxY, bounds.mMaxZ);
  206. // Check if any of the bounding boxes collided
  207. if (ioVisitor.ShouldVisitBlock(result))
  208. {
  209. // Go through the individual boxes
  210. uint sub_shape_start_idx = block << 2;
  211. for (uint col = 0, max_col = min<uint>(4, (uint)mSubShapes.size() - sub_shape_start_idx); col < max_col; ++col) // Don't read beyond the end of the subshapes array
  212. if (ioVisitor.ShouldVisitSubShape(result, col)) // Because the early out fraction can change, we need to retest every shape
  213. {
  214. // Test sub shape
  215. uint sub_shape_idx = sub_shape_start_idx + col;
  216. const SubShape &sub_shape = mSubShapes[sub_shape_idx];
  217. ioVisitor.VisitShape(sub_shape, sub_shape_idx);
  218. // If no better collision is available abort
  219. if (ioVisitor.ShouldAbort())
  220. break;
  221. }
  222. }
  223. }
  224. }
  225. bool MutableCompoundShape::CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const
  226. {
  227. JPH_PROFILE_FUNCTION();
  228. struct Visitor : public CastRayVisitor
  229. {
  230. using CastRayVisitor::CastRayVisitor;
  231. using Result = Vec4;
  232. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  233. {
  234. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  235. }
  236. JPH_INLINE bool ShouldVisitBlock(Vec4Arg inResult) const
  237. {
  238. UVec4 closer = Vec4::sLess(inResult, Vec4::sReplicate(mHit.mFraction));
  239. return closer.TestAnyTrue();
  240. }
  241. JPH_INLINE bool ShouldVisitSubShape(Vec4Arg inResult, uint inIndexInBlock) const
  242. {
  243. return inResult[inIndexInBlock] < mHit.mFraction;
  244. }
  245. };
  246. Visitor visitor(inRay, this, inSubShapeIDCreator, ioHit);
  247. WalkSubShapes(visitor);
  248. return visitor.mReturnValue;
  249. }
  250. void MutableCompoundShape::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  251. {
  252. JPH_PROFILE_FUNCTION();
  253. // Test shape filter
  254. if (!inShapeFilter.ShouldCollide(inSubShapeIDCreator.GetID()))
  255. return;
  256. struct Visitor : public CastRayVisitorCollector
  257. {
  258. using CastRayVisitorCollector::CastRayVisitorCollector;
  259. using Result = Vec4;
  260. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  261. {
  262. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  263. }
  264. JPH_INLINE bool ShouldVisitBlock(Vec4Arg inResult) const
  265. {
  266. UVec4 closer = Vec4::sLess(inResult, Vec4::sReplicate(mCollector.GetEarlyOutFraction()));
  267. return closer.TestAnyTrue();
  268. }
  269. JPH_INLINE bool ShouldVisitSubShape(Vec4Arg inResult, uint inIndexInBlock) const
  270. {
  271. return inResult[inIndexInBlock] < mCollector.GetEarlyOutFraction();
  272. }
  273. };
  274. Visitor visitor(inRay, inRayCastSettings, this, inSubShapeIDCreator, ioCollector, inShapeFilter);
  275. WalkSubShapes(visitor);
  276. }
  277. void MutableCompoundShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  278. {
  279. JPH_PROFILE_FUNCTION();
  280. // Test shape filter
  281. if (!inShapeFilter.ShouldCollide(inSubShapeIDCreator.GetID()))
  282. return;
  283. struct Visitor : public CollidePointVisitor
  284. {
  285. using CollidePointVisitor::CollidePointVisitor;
  286. using Result = UVec4;
  287. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  288. {
  289. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  290. }
  291. JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const
  292. {
  293. return inResult.TestAnyTrue();
  294. }
  295. JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const
  296. {
  297. return inResult[inIndexInBlock] != 0;
  298. }
  299. };
  300. Visitor visitor(inPoint, this, inSubShapeIDCreator, ioCollector, inShapeFilter);
  301. WalkSubShapes(visitor);
  302. }
  303. void MutableCompoundShape::sCastShapeVsCompound(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
  304. {
  305. JPH_PROFILE_FUNCTION();
  306. struct Visitor : public CastShapeVisitor
  307. {
  308. using CastShapeVisitor::CastShapeVisitor;
  309. using Result = Vec4;
  310. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  311. {
  312. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  313. }
  314. JPH_INLINE bool ShouldVisitBlock(Vec4Arg inResult) const
  315. {
  316. UVec4 closer = Vec4::sLess(inResult, Vec4::sReplicate(mCollector.GetEarlyOutFraction()));
  317. return closer.TestAnyTrue();
  318. }
  319. JPH_INLINE bool ShouldVisitSubShape(Vec4Arg inResult, uint inIndexInBlock) const
  320. {
  321. return inResult[inIndexInBlock] < mCollector.GetEarlyOutFraction();
  322. }
  323. };
  324. JPH_ASSERT(inShape->GetSubType() == EShapeSubType::MutableCompound);
  325. const MutableCompoundShape *shape = static_cast<const MutableCompoundShape *>(inShape);
  326. Visitor visitor(inShapeCast, inShapeCastSettings, shape, inScale, inShapeFilter, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, ioCollector);
  327. shape->WalkSubShapes(visitor);
  328. }
  329. void MutableCompoundShape::CollectTransformedShapes(const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  330. {
  331. JPH_PROFILE_FUNCTION();
  332. // Test shape filter
  333. if (!inShapeFilter.ShouldCollide(inSubShapeIDCreator.GetID()))
  334. return;
  335. struct Visitor : public CollectTransformedShapesVisitor
  336. {
  337. using CollectTransformedShapesVisitor::CollectTransformedShapesVisitor;
  338. using Result = UVec4;
  339. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  340. {
  341. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  342. }
  343. JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const
  344. {
  345. return inResult.TestAnyTrue();
  346. }
  347. JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const
  348. {
  349. return inResult[inIndexInBlock] != 0;
  350. }
  351. };
  352. Visitor visitor(inBox, this, inPositionCOM, inRotation, inScale, inSubShapeIDCreator, ioCollector, inShapeFilter);
  353. WalkSubShapes(visitor);
  354. }
  355. int MutableCompoundShape::GetIntersectingSubShapes(const AABox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const
  356. {
  357. JPH_PROFILE_FUNCTION();
  358. GetIntersectingSubShapesVisitorMC<AABox> visitor(inBox, outSubShapeIndices, inMaxSubShapeIndices);
  359. WalkSubShapes(visitor);
  360. return visitor.GetNumResults();
  361. }
  362. int MutableCompoundShape::GetIntersectingSubShapes(const OrientedBox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const
  363. {
  364. JPH_PROFILE_FUNCTION();
  365. GetIntersectingSubShapesVisitorMC<OrientedBox> visitor(inBox, outSubShapeIndices, inMaxSubShapeIndices);
  366. WalkSubShapes(visitor);
  367. return visitor.GetNumResults();
  368. }
  369. void MutableCompoundShape::sCollideCompoundVsShape(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const ShapeFilter &inShapeFilter)
  370. {
  371. JPH_PROFILE_FUNCTION();
  372. JPH_ASSERT(inShape1->GetSubType() == EShapeSubType::MutableCompound);
  373. const MutableCompoundShape *shape1 = static_cast<const MutableCompoundShape *>(inShape1);
  374. struct Visitor : public CollideCompoundVsShapeVisitor
  375. {
  376. using CollideCompoundVsShapeVisitor::CollideCompoundVsShapeVisitor;
  377. using Result = UVec4;
  378. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  379. {
  380. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  381. }
  382. JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const
  383. {
  384. return inResult.TestAnyTrue();
  385. }
  386. JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const
  387. {
  388. return inResult[inIndexInBlock] != 0;
  389. }
  390. };
  391. Visitor visitor(shape1, inShape2, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, inCollideShapeSettings, ioCollector, inShapeFilter);
  392. shape1->WalkSubShapes(visitor);
  393. }
  394. void MutableCompoundShape::sCollideShapeVsCompound(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const ShapeFilter &inShapeFilter)
  395. {
  396. JPH_PROFILE_FUNCTION();
  397. JPH_ASSERT(inShape2->GetSubType() == EShapeSubType::MutableCompound);
  398. const MutableCompoundShape *shape2 = static_cast<const MutableCompoundShape *>(inShape2);
  399. struct Visitor : public CollideShapeVsCompoundVisitor
  400. {
  401. using CollideShapeVsCompoundVisitor::CollideShapeVsCompoundVisitor;
  402. using Result = UVec4;
  403. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  404. {
  405. return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  406. }
  407. JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const
  408. {
  409. return inResult.TestAnyTrue();
  410. }
  411. JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const
  412. {
  413. return inResult[inIndexInBlock] != 0;
  414. }
  415. };
  416. Visitor visitor(inShape1, shape2, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, inCollideShapeSettings, ioCollector, inShapeFilter);
  417. shape2->WalkSubShapes(visitor);
  418. }
  419. void MutableCompoundShape::SaveBinaryState(StreamOut &inStream) const
  420. {
  421. CompoundShape::SaveBinaryState(inStream);
  422. // Write bounds
  423. uint bounds_size = (((uint)mSubShapes.size() + 3) >> 2) * sizeof(Bounds);
  424. inStream.WriteBytes(mSubShapeBounds.data(), bounds_size);
  425. }
  426. void MutableCompoundShape::RestoreBinaryState(StreamIn &inStream)
  427. {
  428. CompoundShape::RestoreBinaryState(inStream);
  429. // Ensure that we have allocated the required space for mSubShapeBounds
  430. EnsureSubShapeBoundsCapacity();
  431. // Read bounds
  432. uint bounds_size = (((uint)mSubShapes.size() + 3) >> 2) * sizeof(Bounds);
  433. inStream.ReadBytes(mSubShapeBounds.data(), bounds_size);
  434. }
  435. void MutableCompoundShape::sRegister()
  436. {
  437. ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::MutableCompound);
  438. f.mConstruct = []() -> Shape * { return new MutableCompoundShape; };
  439. f.mColor = Color::sDarkOrange;
  440. for (EShapeSubType s : sAllSubShapeTypes)
  441. {
  442. CollisionDispatch::sRegisterCollideShape(EShapeSubType::MutableCompound, s, sCollideCompoundVsShape);
  443. CollisionDispatch::sRegisterCollideShape(s, EShapeSubType::MutableCompound, sCollideShapeVsCompound);
  444. CollisionDispatch::sRegisterCastShape(s, EShapeSubType::MutableCompound, sCastShapeVsCompound);
  445. }
  446. }
  447. JPH_NAMESPACE_END