MutableCompoundShape.cpp 19 KB

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