MutableCompoundShape.cpp 21 KB

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