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