Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp
9913 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#include <Jolt/Jolt.h>56#include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>7#include <Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h>8#include <Jolt/Core/Profiler.h>9#include <Jolt/Core/StreamIn.h>10#include <Jolt/Core/StreamOut.h>11#include <Jolt/ObjectStream/TypeDeclarations.h>1213JPH_NAMESPACE_BEGIN1415JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(MutableCompoundShapeSettings)16{17JPH_ADD_BASE_CLASS(MutableCompoundShapeSettings, CompoundShapeSettings)18}1920ShapeSettings::ShapeResult MutableCompoundShapeSettings::Create() const21{22// Build a mutable compound shape23if (mCachedResult.IsEmpty())24Ref<Shape> shape = new MutableCompoundShape(*this, mCachedResult);2526return mCachedResult;27}2829MutableCompoundShape::MutableCompoundShape(const MutableCompoundShapeSettings &inSettings, ShapeResult &outResult) :30CompoundShape(EShapeSubType::MutableCompound, inSettings, outResult)31{32mSubShapes.reserve(inSettings.mSubShapes.size());33for (const CompoundShapeSettings::SubShapeSettings &shape : inSettings.mSubShapes)34{35// Start constructing the runtime sub shape36SubShape out_shape;37if (!out_shape.FromSettings(shape, outResult))38return;3940mSubShapes.push_back(out_shape);41}4243AdjustCenterOfMass();4445CalculateSubShapeBounds(0, (uint)mSubShapes.size());4647// Check if we're not exceeding the amount of sub shape id bits48if (GetSubShapeIDBitsRecursive() > SubShapeID::MaxBits)49{50outResult.SetError("Compound hierarchy is too deep and exceeds the amount of available sub shape ID bits");51return;52}5354outResult.Set(this);55}5657Ref<MutableCompoundShape> MutableCompoundShape::Clone() const58{59Ref<MutableCompoundShape> clone = new MutableCompoundShape();60clone->SetUserData(GetUserData());6162clone->mCenterOfMass = mCenterOfMass;63clone->mLocalBounds = mLocalBounds;64clone->mSubShapes = mSubShapes;65clone->mInnerRadius = mInnerRadius;66clone->mSubShapeBounds = mSubShapeBounds;6768return clone;69}7071void MutableCompoundShape::AdjustCenterOfMass()72{73// First calculate the delta of the center of mass74float mass = 0.0f;75Vec3 center_of_mass = Vec3::sZero();76for (const CompoundShape::SubShape &sub_shape : mSubShapes)77{78MassProperties child = sub_shape.mShape->GetMassProperties();79mass += child.mMass;80center_of_mass += sub_shape.GetPositionCOM() * child.mMass;81}82if (mass > 0.0f)83center_of_mass /= mass;8485// Now adjust all shapes to recenter around center of mass86for (CompoundShape::SubShape &sub_shape : mSubShapes)87sub_shape.SetPositionCOM(sub_shape.GetPositionCOM() - center_of_mass);8889// Update bounding boxes90for (Bounds &bounds : mSubShapeBounds)91{92Vec4 xxxx = center_of_mass.SplatX();93Vec4 yyyy = center_of_mass.SplatY();94Vec4 zzzz = center_of_mass.SplatZ();95bounds.mMinX -= xxxx;96bounds.mMinY -= yyyy;97bounds.mMinZ -= zzzz;98bounds.mMaxX -= xxxx;99bounds.mMaxY -= yyyy;100bounds.mMaxZ -= zzzz;101}102mLocalBounds.Translate(-center_of_mass);103104// And adjust the center of mass for this shape in the opposite direction105mCenterOfMass += center_of_mass;106}107108void MutableCompoundShape::CalculateLocalBounds()109{110uint num_blocks = GetNumBlocks();111if (num_blocks > 0)112{113// Initialize min/max for first block114const Bounds *bounds = mSubShapeBounds.data();115Vec4 min_x = bounds->mMinX;116Vec4 min_y = bounds->mMinY;117Vec4 min_z = bounds->mMinZ;118Vec4 max_x = bounds->mMaxX;119Vec4 max_y = bounds->mMaxY;120Vec4 max_z = bounds->mMaxZ;121122// Accumulate other blocks123const Bounds *bounds_end = bounds + num_blocks;124for (++bounds; bounds < bounds_end; ++bounds)125{126min_x = Vec4::sMin(min_x, bounds->mMinX);127min_y = Vec4::sMin(min_y, bounds->mMinY);128min_z = Vec4::sMin(min_z, bounds->mMinZ);129max_x = Vec4::sMax(max_x, bounds->mMaxX);130max_y = Vec4::sMax(max_y, bounds->mMaxY);131max_z = Vec4::sMax(max_z, bounds->mMaxZ);132}133134// Calculate resulting bounding box135mLocalBounds.mMin.SetX(min_x.ReduceMin());136mLocalBounds.mMin.SetY(min_y.ReduceMin());137mLocalBounds.mMin.SetZ(min_z.ReduceMin());138mLocalBounds.mMax.SetX(max_x.ReduceMax());139mLocalBounds.mMax.SetY(max_y.ReduceMax());140mLocalBounds.mMax.SetZ(max_z.ReduceMax());141}142else143{144// There are no subshapes, make the bounding box empty145mLocalBounds.mMin = mLocalBounds.mMax = Vec3::sZero();146}147148// Cache the inner radius as it can take a while to recursively iterate over all sub shapes149CalculateInnerRadius();150}151152void MutableCompoundShape::EnsureSubShapeBoundsCapacity()153{154// Check if we have enough space155uint new_capacity = ((uint)mSubShapes.size() + 3) >> 2;156if (mSubShapeBounds.size() < new_capacity)157mSubShapeBounds.resize(new_capacity);158}159160void MutableCompoundShape::CalculateSubShapeBounds(uint inStartIdx, uint inNumber)161{162// Ensure that we have allocated the required space for mSubShapeBounds163EnsureSubShapeBoundsCapacity();164165// Loop over blocks of 4 sub shapes166for (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)167{168Mat44 bounds_min;169Mat44 bounds_max;170171AABox sub_shape_bounds;172for (uint col = 0; col < 4; ++col)173{174uint sub_shape_idx = sub_shape_idx_start + col;175if (sub_shape_idx < mSubShapes.size()) // else reuse sub_shape_bounds from previous iteration176{177const SubShape &sub_shape = mSubShapes[sub_shape_idx];178179// Transform the shape's bounds into our local space180Mat44 transform = Mat44::sRotationTranslation(sub_shape.GetRotation(), sub_shape.GetPositionCOM());181182// Get the bounding box183sub_shape_bounds = sub_shape.mShape->GetWorldSpaceBounds(transform, Vec3::sOne());184}185186// Put the bounds as columns in a matrix187bounds_min.SetColumn3(col, sub_shape_bounds.mMin);188bounds_max.SetColumn3(col, sub_shape_bounds.mMax);189}190191// Transpose to go to structure of arrays format192Mat44 bounds_min_t = bounds_min.Transposed();193Mat44 bounds_max_t = bounds_max.Transposed();194195// Store in our bounds array196Bounds &bounds = mSubShapeBounds[sub_shape_idx_start >> 2];197bounds.mMinX = bounds_min_t.GetColumn4(0);198bounds.mMinY = bounds_min_t.GetColumn4(1);199bounds.mMinZ = bounds_min_t.GetColumn4(2);200bounds.mMaxX = bounds_max_t.GetColumn4(0);201bounds.mMaxY = bounds_max_t.GetColumn4(1);202bounds.mMaxZ = bounds_max_t.GetColumn4(2);203}204205CalculateLocalBounds();206}207208uint MutableCompoundShape::AddShape(Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape, uint32 inUserData, uint inIndex)209{210SubShape sub_shape;211sub_shape.mShape = inShape;212sub_shape.mUserData = inUserData;213sub_shape.SetTransform(inPosition, inRotation, mCenterOfMass);214215if (inIndex >= mSubShapes.size())216{217uint shape_idx = uint(mSubShapes.size());218mSubShapes.push_back(sub_shape);219CalculateSubShapeBounds(shape_idx, 1);220return shape_idx;221}222else223{224mSubShapes.insert(mSubShapes.begin() + inIndex, sub_shape);225CalculateSubShapeBounds(inIndex, uint(mSubShapes.size()) - inIndex);226return inIndex;227}228}229230void MutableCompoundShape::RemoveShape(uint inIndex)231{232mSubShapes.erase(mSubShapes.begin() + inIndex);233234// We always need to recalculate the bounds of the sub shapes as we test blocks235// of 4 sub shapes at a time and removed shapes get their bounds updated236// to repeat the bounds of the previous sub shape237uint num_bounds = (uint)mSubShapes.size() - inIndex;238CalculateSubShapeBounds(inIndex, num_bounds);239}240241void MutableCompoundShape::ModifyShape(uint inIndex, Vec3Arg inPosition, QuatArg inRotation)242{243SubShape &sub_shape = mSubShapes[inIndex];244sub_shape.SetTransform(inPosition, inRotation, mCenterOfMass);245246CalculateSubShapeBounds(inIndex, 1);247}248249void MutableCompoundShape::ModifyShape(uint inIndex, Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape)250{251SubShape &sub_shape = mSubShapes[inIndex];252sub_shape.mShape = inShape;253sub_shape.SetTransform(inPosition, inRotation, mCenterOfMass);254255CalculateSubShapeBounds(inIndex, 1);256}257258void MutableCompoundShape::ModifyShapes(uint inStartIndex, uint inNumber, const Vec3 *inPositions, const Quat *inRotations, uint inPositionStride, uint inRotationStride)259{260JPH_ASSERT(inStartIndex + inNumber <= mSubShapes.size());261262const Vec3 *pos = inPositions;263const Quat *rot = inRotations;264for (SubShape *dest = &mSubShapes[inStartIndex], *dest_end = dest + inNumber; dest < dest_end; ++dest)265{266// Update transform267dest->SetTransform(*pos, *rot, mCenterOfMass);268269// Advance pointer in position / rotation buffer270pos = reinterpret_cast<const Vec3 *>(reinterpret_cast<const uint8 *>(pos) + inPositionStride);271rot = reinterpret_cast<const Quat *>(reinterpret_cast<const uint8 *>(rot) + inRotationStride);272}273274CalculateSubShapeBounds(inStartIndex, inNumber);275}276277template <class Visitor>278inline void MutableCompoundShape::WalkSubShapes(Visitor &ioVisitor) const279{280// Loop over all blocks of 4 bounding boxes281for (uint block = 0, num_blocks = GetNumBlocks(); block < num_blocks; ++block)282{283// Test the bounding boxes284const Bounds &bounds = mSubShapeBounds[block];285typename Visitor::Result result = ioVisitor.TestBlock(bounds.mMinX, bounds.mMinY, bounds.mMinZ, bounds.mMaxX, bounds.mMaxY, bounds.mMaxZ);286287// Check if any of the bounding boxes collided288if (ioVisitor.ShouldVisitBlock(result))289{290// Go through the individual boxes291uint sub_shape_start_idx = block << 2;292for (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 array293if (ioVisitor.ShouldVisitSubShape(result, col)) // Because the early out fraction can change, we need to retest every shape294{295// Test sub shape296uint sub_shape_idx = sub_shape_start_idx + col;297const SubShape &sub_shape = mSubShapes[sub_shape_idx];298ioVisitor.VisitShape(sub_shape, sub_shape_idx);299300// If no better collision is available abort301if (ioVisitor.ShouldAbort())302break;303}304}305}306}307308bool MutableCompoundShape::CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const309{310JPH_PROFILE_FUNCTION();311312struct Visitor : public CastRayVisitor313{314using CastRayVisitor::CastRayVisitor;315316using Result = Vec4;317318JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const319{320return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);321}322323JPH_INLINE bool ShouldVisitBlock(Vec4Arg inResult) const324{325UVec4 closer = Vec4::sLess(inResult, Vec4::sReplicate(mHit.mFraction));326return closer.TestAnyTrue();327}328329JPH_INLINE bool ShouldVisitSubShape(Vec4Arg inResult, uint inIndexInBlock) const330{331return inResult[inIndexInBlock] < mHit.mFraction;332}333};334335Visitor visitor(inRay, this, inSubShapeIDCreator, ioHit);336WalkSubShapes(visitor);337return visitor.mReturnValue;338}339340void MutableCompoundShape::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) const341{342JPH_PROFILE_FUNCTION();343344// Test shape filter345if (!inShapeFilter.ShouldCollide(this, inSubShapeIDCreator.GetID()))346return;347348struct Visitor : public CastRayVisitorCollector349{350using CastRayVisitorCollector::CastRayVisitorCollector;351352using Result = Vec4;353354JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const355{356return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);357}358359JPH_INLINE bool ShouldVisitBlock(Vec4Arg inResult) const360{361UVec4 closer = Vec4::sLess(inResult, Vec4::sReplicate(mCollector.GetEarlyOutFraction()));362return closer.TestAnyTrue();363}364365JPH_INLINE bool ShouldVisitSubShape(Vec4Arg inResult, uint inIndexInBlock) const366{367return inResult[inIndexInBlock] < mCollector.GetEarlyOutFraction();368}369};370371Visitor visitor(inRay, inRayCastSettings, this, inSubShapeIDCreator, ioCollector, inShapeFilter);372WalkSubShapes(visitor);373}374375void MutableCompoundShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter) const376{377JPH_PROFILE_FUNCTION();378379// Test shape filter380if (!inShapeFilter.ShouldCollide(this, inSubShapeIDCreator.GetID()))381return;382383struct Visitor : public CollidePointVisitor384{385using CollidePointVisitor::CollidePointVisitor;386387using Result = UVec4;388389JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const390{391return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);392}393394JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const395{396return inResult.TestAnyTrue();397}398399JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const400{401return inResult[inIndexInBlock] != 0;402}403};404405Visitor visitor(inPoint, this, inSubShapeIDCreator, ioCollector, inShapeFilter);406WalkSubShapes(visitor);407}408409void 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)410{411JPH_PROFILE_FUNCTION();412413struct Visitor : public CastShapeVisitor414{415using CastShapeVisitor::CastShapeVisitor;416417using Result = Vec4;418419JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const420{421return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);422}423424JPH_INLINE bool ShouldVisitBlock(Vec4Arg inResult) const425{426UVec4 closer = Vec4::sLess(inResult, Vec4::sReplicate(mCollector.GetPositiveEarlyOutFraction()));427return closer.TestAnyTrue();428}429430JPH_INLINE bool ShouldVisitSubShape(Vec4Arg inResult, uint inIndexInBlock) const431{432return inResult[inIndexInBlock] < mCollector.GetPositiveEarlyOutFraction();433}434};435436JPH_ASSERT(inShape->GetSubType() == EShapeSubType::MutableCompound);437const MutableCompoundShape *shape = static_cast<const MutableCompoundShape *>(inShape);438439Visitor visitor(inShapeCast, inShapeCastSettings, shape, inScale, inShapeFilter, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, ioCollector);440shape->WalkSubShapes(visitor);441}442443void MutableCompoundShape::CollectTransformedShapes(const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) const444{445JPH_PROFILE_FUNCTION();446447// Test shape filter448if (!inShapeFilter.ShouldCollide(this, inSubShapeIDCreator.GetID()))449return;450451struct Visitor : public CollectTransformedShapesVisitor452{453using CollectTransformedShapesVisitor::CollectTransformedShapesVisitor;454455using Result = UVec4;456457JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const458{459return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);460}461462JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const463{464return inResult.TestAnyTrue();465}466467JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const468{469return inResult[inIndexInBlock] != 0;470}471};472473Visitor visitor(inBox, this, inPositionCOM, inRotation, inScale, inSubShapeIDCreator, ioCollector, inShapeFilter);474WalkSubShapes(visitor);475}476477int MutableCompoundShape::GetIntersectingSubShapes(const AABox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const478{479JPH_PROFILE_FUNCTION();480481GetIntersectingSubShapesVisitorMC<AABox> visitor(inBox, outSubShapeIndices, inMaxSubShapeIndices);482WalkSubShapes(visitor);483return visitor.GetNumResults();484}485486int MutableCompoundShape::GetIntersectingSubShapes(const OrientedBox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const487{488JPH_PROFILE_FUNCTION();489490GetIntersectingSubShapesVisitorMC<OrientedBox> visitor(inBox, outSubShapeIndices, inMaxSubShapeIndices);491WalkSubShapes(visitor);492return visitor.GetNumResults();493}494495void 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)496{497JPH_PROFILE_FUNCTION();498499JPH_ASSERT(inShape1->GetSubType() == EShapeSubType::MutableCompound);500const MutableCompoundShape *shape1 = static_cast<const MutableCompoundShape *>(inShape1);501502struct Visitor : public CollideCompoundVsShapeVisitor503{504using CollideCompoundVsShapeVisitor::CollideCompoundVsShapeVisitor;505506using Result = UVec4;507508JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const509{510return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);511}512513JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const514{515return inResult.TestAnyTrue();516}517518JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const519{520return inResult[inIndexInBlock] != 0;521}522};523524Visitor visitor(shape1, inShape2, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, inCollideShapeSettings, ioCollector, inShapeFilter);525shape1->WalkSubShapes(visitor);526}527528void 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)529{530JPH_PROFILE_FUNCTION();531532JPH_ASSERT(inShape2->GetSubType() == EShapeSubType::MutableCompound);533const MutableCompoundShape *shape2 = static_cast<const MutableCompoundShape *>(inShape2);534535struct Visitor : public CollideShapeVsCompoundVisitor536{537using CollideShapeVsCompoundVisitor::CollideShapeVsCompoundVisitor;538539using Result = UVec4;540541JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const542{543return TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);544}545546JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const547{548return inResult.TestAnyTrue();549}550551JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const552{553return inResult[inIndexInBlock] != 0;554}555};556557Visitor visitor(inShape1, shape2, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, inCollideShapeSettings, ioCollector, inShapeFilter);558shape2->WalkSubShapes(visitor);559}560561void MutableCompoundShape::SaveBinaryState(StreamOut &inStream) const562{563CompoundShape::SaveBinaryState(inStream);564565// Write bounds566uint bounds_size = (((uint)mSubShapes.size() + 3) >> 2) * sizeof(Bounds);567inStream.WriteBytes(mSubShapeBounds.data(), bounds_size);568}569570void MutableCompoundShape::RestoreBinaryState(StreamIn &inStream)571{572CompoundShape::RestoreBinaryState(inStream);573574// Ensure that we have allocated the required space for mSubShapeBounds575EnsureSubShapeBoundsCapacity();576577// Read bounds578uint bounds_size = (((uint)mSubShapes.size() + 3) >> 2) * sizeof(Bounds);579inStream.ReadBytes(mSubShapeBounds.data(), bounds_size);580}581582void MutableCompoundShape::sRegister()583{584ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::MutableCompound);585f.mConstruct = []() -> Shape * { return new MutableCompoundShape; };586f.mColor = Color::sDarkOrange;587588for (EShapeSubType s : sAllSubShapeTypes)589{590CollisionDispatch::sRegisterCollideShape(EShapeSubType::MutableCompound, s, sCollideCompoundVsShape);591CollisionDispatch::sRegisterCollideShape(s, EShapeSubType::MutableCompound, sCollideShapeVsCompound);592CollisionDispatch::sRegisterCastShape(s, EShapeSubType::MutableCompound, sCastShapeVsCompound);593}594}595596JPH_NAMESPACE_END597598599