Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/objects/jolt_area_3d.cpp
10278 views
1
/**************************************************************************/
2
/* jolt_area_3d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "jolt_area_3d.h"
32
33
#include "../jolt_project_settings.h"
34
#include "../misc/jolt_math_funcs.h"
35
#include "../misc/jolt_type_conversions.h"
36
#include "../shapes/jolt_shape_3d.h"
37
#include "../spaces/jolt_broad_phase_layer.h"
38
#include "../spaces/jolt_space_3d.h"
39
#include "jolt_body_3d.h"
40
#include "jolt_group_filter.h"
41
#include "jolt_soft_body_3d.h"
42
43
namespace {
44
45
constexpr double AREA_DEFAULT_WIND_MAGNITUDE = 0.0;
46
constexpr double AREA_DEFAULT_WIND_ATTENUATION = 0.0;
47
48
const Vector3 AREA_DEFAULT_WIND_SOURCE = Vector3();
49
const Vector3 AREA_DEFAULT_WIND_DIRECTION = Vector3();
50
51
} // namespace
52
53
JPH::BroadPhaseLayer JoltArea3D::_get_broad_phase_layer() const {
54
return monitorable ? JoltBroadPhaseLayer::AREA_DETECTABLE : JoltBroadPhaseLayer::AREA_UNDETECTABLE;
55
}
56
57
JPH::ObjectLayer JoltArea3D::_get_object_layer() const {
58
ERR_FAIL_NULL_V(space, 0);
59
60
if (jolt_shape == nullptr || jolt_shape->GetType() == JPH::EShapeType::Empty) {
61
// No point doing collision checks against a shapeless object.
62
return space->map_to_object_layer(_get_broad_phase_layer(), 0, 0);
63
}
64
65
return space->map_to_object_layer(_get_broad_phase_layer(), collision_layer, collision_mask);
66
}
67
68
void JoltArea3D::_add_to_space() {
69
jolt_shape = build_shapes(true);
70
71
JPH::CollisionGroup::GroupID group_id = 0;
72
JPH::CollisionGroup::SubGroupID sub_group_id = 0;
73
JoltGroupFilter::encode_object(this, group_id, sub_group_id);
74
75
jolt_settings->mUserData = reinterpret_cast<JPH::uint64>(this);
76
jolt_settings->mObjectLayer = _get_object_layer();
77
jolt_settings->mCollisionGroup = JPH::CollisionGroup(nullptr, group_id, sub_group_id);
78
jolt_settings->mMotionType = _get_motion_type();
79
jolt_settings->mIsSensor = true;
80
jolt_settings->mCollideKinematicVsNonDynamic = true;
81
jolt_settings->mUseManifoldReduction = false;
82
jolt_settings->mOverrideMassProperties = JPH::EOverrideMassProperties::MassAndInertiaProvided;
83
jolt_settings->mMassPropertiesOverride.mMass = 1.0f;
84
jolt_settings->mMassPropertiesOverride.mInertia = JPH::Mat44::sIdentity();
85
86
jolt_settings->SetShape(jolt_shape);
87
88
JPH::Body *new_jolt_body = space->add_object(*this, *jolt_settings, _should_sleep());
89
if (new_jolt_body == nullptr) {
90
return;
91
}
92
93
jolt_body = new_jolt_body;
94
95
delete jolt_settings;
96
jolt_settings = nullptr;
97
}
98
99
void JoltArea3D::_enqueue_call_queries() {
100
if (space != nullptr) {
101
space->enqueue_call_queries(&call_queries_element);
102
}
103
}
104
105
void JoltArea3D::_dequeue_call_queries() {
106
if (space != nullptr) {
107
space->dequeue_call_queries(&call_queries_element);
108
}
109
}
110
111
void JoltArea3D::_add_shape_pair(Overlap &p_overlap, const JPH::BodyID &p_body_id, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
112
const JoltShapedObject3D *other_object = space->try_get_shaped(p_body_id);
113
ERR_FAIL_NULL(other_object);
114
115
p_overlap.rid = other_object->get_rid();
116
p_overlap.instance_id = other_object->get_instance_id();
117
118
HashMap<ShapeIDPair, ShapeIndexPair, ShapeIDPair>::Iterator shape_pair = p_overlap.shape_pairs.find(ShapeIDPair(p_other_shape_id, p_self_shape_id));
119
if (shape_pair == p_overlap.shape_pairs.end()) {
120
const int other_shape_index = other_object->find_shape_index(p_other_shape_id);
121
const int self_shape_index = find_shape_index(p_self_shape_id);
122
shape_pair = p_overlap.shape_pairs.insert(ShapeIDPair(p_other_shape_id, p_self_shape_id), ShapeIndexPair(other_shape_index, self_shape_index));
123
}
124
125
p_overlap.pending_added.push_back(shape_pair->value);
126
127
_events_changed();
128
}
129
130
bool JoltArea3D::_remove_shape_pair(Overlap &p_overlap, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
131
HashMap<ShapeIDPair, ShapeIndexPair, ShapeIDPair>::Iterator shape_pair = p_overlap.shape_pairs.find(ShapeIDPair(p_other_shape_id, p_self_shape_id));
132
133
if (shape_pair == p_overlap.shape_pairs.end()) {
134
return false;
135
}
136
137
p_overlap.pending_removed.push_back(shape_pair->value);
138
p_overlap.shape_pairs.remove(shape_pair);
139
140
_events_changed();
141
142
return true;
143
}
144
145
void JoltArea3D::_flush_events(OverlapsById &p_objects, const Callable &p_callback) {
146
for (OverlapsById::Iterator E = p_objects.begin(); E;) {
147
Overlap &overlap = E->value;
148
149
if (p_callback.is_valid()) {
150
for (const ShapeIndexPair &shape_indices : overlap.pending_added) {
151
int &ref_count = overlap.ref_counts[shape_indices];
152
if (ref_count++ == 0) {
153
_report_event(p_callback, PhysicsServer3D::AREA_BODY_ADDED, overlap.rid, overlap.instance_id, shape_indices.other, shape_indices.self);
154
}
155
}
156
157
for (const ShapeIndexPair &shape_indices : overlap.pending_removed) {
158
int &ref_count = overlap.ref_counts[shape_indices];
159
ERR_CONTINUE(ref_count <= 0);
160
if (--ref_count == 0) {
161
_report_event(p_callback, PhysicsServer3D::AREA_BODY_REMOVED, overlap.rid, overlap.instance_id, shape_indices.other, shape_indices.self);
162
overlap.ref_counts.erase(shape_indices);
163
}
164
}
165
}
166
167
overlap.pending_removed.clear();
168
overlap.pending_added.clear();
169
170
OverlapsById::Iterator next = E;
171
++next;
172
173
if (overlap.shape_pairs.is_empty()) {
174
p_objects.remove(E);
175
}
176
177
E = next;
178
}
179
}
180
181
void JoltArea3D::_report_event(const Callable &p_callback, PhysicsServer3D::AreaBodyStatus p_status, const RID &p_other_rid, ObjectID p_other_instance_id, int p_other_shape_index, int p_self_shape_index) const {
182
ERR_FAIL_COND(!p_callback.is_valid());
183
184
const Variant arg1 = p_status;
185
const Variant arg2 = p_other_rid;
186
const Variant arg3 = p_other_instance_id;
187
const Variant arg4 = p_other_shape_index;
188
const Variant arg5 = p_self_shape_index;
189
const Variant *args[5] = { &arg1, &arg2, &arg3, &arg4, &arg5 };
190
191
Callable::CallError ce;
192
Variant ret;
193
p_callback.callp(args, 5, ret, ce);
194
195
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
196
ERR_PRINT_ONCE(vformat("Failed to call area monitor callback for '%s'. It returned the following error: '%s'.", to_string(), Variant::get_callable_error_text(p_callback, args, 5, ce)));
197
}
198
}
199
200
void JoltArea3D::_notify_body_entered(const JPH::BodyID &p_body_id) {
201
if (JoltBody3D *other_body = space->try_get_body(p_body_id)) {
202
other_body->add_area(this);
203
}
204
}
205
206
void JoltArea3D::_notify_body_exited(const JPH::BodyID &p_body_id) {
207
if (JoltBody3D *other_body = space->try_get_body(p_body_id)) {
208
other_body->remove_area(this);
209
}
210
}
211
212
void JoltArea3D::_remove_all_overlaps() {
213
for (KeyValue<JPH::BodyID, Overlap> &E : bodies_by_id) {
214
_notify_body_exited(E.key);
215
}
216
217
bodies_by_id.clear();
218
areas_by_id.clear();
219
}
220
221
void JoltArea3D::_update_sleeping() {
222
if (!in_space()) {
223
return;
224
}
225
226
space->set_is_object_sleeping(jolt_body->GetID(), _should_sleep());
227
}
228
229
void JoltArea3D::_update_group_filter() {
230
if (!in_space()) {
231
return;
232
}
233
234
jolt_body->GetCollisionGroup().SetGroupFilter(JoltGroupFilter::instance);
235
}
236
237
void JoltArea3D::_update_default_gravity() {
238
if (is_default_area()) {
239
space->get_physics_system().SetGravity(to_jolt(gravity_vector) * gravity);
240
}
241
}
242
243
void JoltArea3D::_space_changing() {
244
JoltShapedObject3D::_space_changing();
245
246
_remove_all_overlaps();
247
_dequeue_call_queries();
248
}
249
250
void JoltArea3D::_space_changed() {
251
JoltShapedObject3D::_space_changed();
252
253
_update_group_filter();
254
_update_default_gravity();
255
}
256
257
void JoltArea3D::_events_changed() {
258
_enqueue_call_queries();
259
}
260
261
void JoltArea3D::_body_monitoring_changed() {
262
_update_sleeping();
263
}
264
265
void JoltArea3D::_area_monitoring_changed() {
266
_update_sleeping();
267
}
268
269
void JoltArea3D::_monitorable_changed() {
270
_update_object_layer();
271
}
272
273
void JoltArea3D::_gravity_changed() {
274
_update_default_gravity();
275
}
276
277
JoltArea3D::JoltArea3D() :
278
JoltShapedObject3D(OBJECT_TYPE_AREA),
279
call_queries_element(this) {
280
}
281
282
bool JoltArea3D::is_default_area() const {
283
return space != nullptr && space->get_default_area() == this;
284
}
285
286
void JoltArea3D::set_default_area(bool p_value) {
287
if (p_value) {
288
_update_default_gravity();
289
}
290
}
291
292
void JoltArea3D::set_transform(Transform3D p_transform) {
293
JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed to area '%s'.", to_string()));
294
295
Vector3 new_scale;
296
JoltMath::decompose(p_transform, new_scale);
297
298
// Ideally we would do an exact comparison here, but due to floating-point precision this would be invalidated very often.
299
if (!scale.is_equal_approx(new_scale)) {
300
scale = new_scale;
301
_shapes_changed();
302
}
303
304
if (!in_space()) {
305
jolt_settings->mPosition = to_jolt_r(p_transform.origin);
306
jolt_settings->mRotation = to_jolt(p_transform.basis);
307
} else {
308
space->get_body_iface().SetPositionAndRotation(jolt_body->GetID(), to_jolt_r(p_transform.origin), to_jolt(p_transform.basis), JPH::EActivation::DontActivate);
309
}
310
}
311
312
Variant JoltArea3D::get_param(PhysicsServer3D::AreaParameter p_param) const {
313
switch (p_param) {
314
case PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE: {
315
return get_gravity_mode();
316
}
317
case PhysicsServer3D::AREA_PARAM_GRAVITY: {
318
return get_gravity();
319
}
320
case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: {
321
return get_gravity_vector();
322
}
323
case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: {
324
return is_point_gravity();
325
}
326
case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE: {
327
return get_point_gravity_distance();
328
}
329
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: {
330
return get_linear_damp_mode();
331
}
332
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: {
333
return get_linear_damp();
334
}
335
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE: {
336
return get_angular_damp_mode();
337
}
338
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: {
339
return get_angular_damp();
340
}
341
case PhysicsServer3D::AREA_PARAM_PRIORITY: {
342
return get_priority();
343
}
344
case PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE: {
345
return AREA_DEFAULT_WIND_MAGNITUDE;
346
}
347
case PhysicsServer3D::AREA_PARAM_WIND_SOURCE: {
348
return AREA_DEFAULT_WIND_SOURCE;
349
}
350
case PhysicsServer3D::AREA_PARAM_WIND_DIRECTION: {
351
return AREA_DEFAULT_WIND_DIRECTION;
352
}
353
case PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR: {
354
return AREA_DEFAULT_WIND_ATTENUATION;
355
}
356
default: {
357
ERR_FAIL_V_MSG(Variant(), vformat("Unhandled area parameter: '%d'. This should not happen. Please report this.", p_param));
358
}
359
}
360
}
361
362
void JoltArea3D::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
363
switch (p_param) {
364
case PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE: {
365
set_gravity_mode((OverrideMode)(int)p_value);
366
} break;
367
case PhysicsServer3D::AREA_PARAM_GRAVITY: {
368
set_gravity(p_value);
369
} break;
370
case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: {
371
set_gravity_vector(p_value);
372
} break;
373
case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: {
374
set_point_gravity(p_value);
375
} break;
376
case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE: {
377
set_point_gravity_distance(p_value);
378
} break;
379
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: {
380
set_linear_damp_mode((OverrideMode)(int)p_value);
381
} break;
382
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: {
383
set_area_linear_damp(p_value);
384
} break;
385
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE: {
386
set_angular_damp_mode((OverrideMode)(int)p_value);
387
} break;
388
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: {
389
set_area_angular_damp(p_value);
390
} break;
391
case PhysicsServer3D::AREA_PARAM_PRIORITY: {
392
set_priority(p_value);
393
} break;
394
case PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE: {
395
if (!Math::is_equal_approx((double)p_value, AREA_DEFAULT_WIND_MAGNITUDE)) {
396
WARN_PRINT(vformat("Invalid wind force magnitude for '%s'. Area wind force magnitude is not supported when using Jolt Physics. Any such value will be ignored.", to_string()));
397
}
398
} break;
399
case PhysicsServer3D::AREA_PARAM_WIND_SOURCE: {
400
if (!((Vector3)p_value).is_equal_approx(AREA_DEFAULT_WIND_SOURCE)) {
401
WARN_PRINT(vformat("Invalid wind source for '%s'. Area wind source is not supported when using Jolt Physics. Any such value will be ignored.", to_string()));
402
}
403
} break;
404
case PhysicsServer3D::AREA_PARAM_WIND_DIRECTION: {
405
if (!((Vector3)p_value).is_equal_approx(AREA_DEFAULT_WIND_DIRECTION)) {
406
WARN_PRINT(vformat("Invalid wind direction for '%s'. Area wind direction is not supported when using Jolt Physics. Any such value will be ignored.", to_string()));
407
}
408
} break;
409
case PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR: {
410
if (!Math::is_equal_approx((double)p_value, AREA_DEFAULT_WIND_ATTENUATION)) {
411
WARN_PRINT(vformat("Invalid wind attenuation for '%s'. Area wind attenuation is not supported when using Jolt Physics. Any such value will be ignored.", to_string()));
412
}
413
} break;
414
default: {
415
ERR_FAIL_MSG(vformat("Unhandled area parameter: '%d'. This should not happen. Please report this.", p_param));
416
} break;
417
}
418
}
419
420
void JoltArea3D::set_body_monitor_callback(const Callable &p_callback) {
421
if (p_callback == body_monitor_callback) {
422
return;
423
}
424
425
body_monitor_callback = p_callback;
426
427
_body_monitoring_changed();
428
}
429
430
void JoltArea3D::set_area_monitor_callback(const Callable &p_callback) {
431
if (p_callback == area_monitor_callback) {
432
return;
433
}
434
435
area_monitor_callback = p_callback;
436
437
_area_monitoring_changed();
438
}
439
440
void JoltArea3D::set_monitorable(bool p_monitorable) {
441
if (p_monitorable == monitorable) {
442
return;
443
}
444
445
monitorable = p_monitorable;
446
447
_monitorable_changed();
448
}
449
450
bool JoltArea3D::can_monitor(const JoltBody3D &p_other) const {
451
return is_monitoring_bodies() && (collision_mask & p_other.get_collision_layer()) != 0;
452
}
453
454
bool JoltArea3D::can_monitor(const JoltSoftBody3D &p_other) const {
455
return false;
456
}
457
458
bool JoltArea3D::can_monitor(const JoltArea3D &p_other) const {
459
return is_monitoring_areas() && p_other.is_monitorable() && (collision_mask & p_other.get_collision_layer()) != 0;
460
}
461
462
bool JoltArea3D::can_interact_with(const JoltBody3D &p_other) const {
463
return can_monitor(p_other);
464
}
465
466
bool JoltArea3D::can_interact_with(const JoltSoftBody3D &p_other) const {
467
return false;
468
}
469
470
bool JoltArea3D::can_interact_with(const JoltArea3D &p_other) const {
471
return can_monitor(p_other) || p_other.can_monitor(*this);
472
}
473
474
Vector3 JoltArea3D::get_velocity_at_position(const Vector3 &p_position) const {
475
return Vector3();
476
}
477
478
void JoltArea3D::set_point_gravity(bool p_enabled) {
479
if (point_gravity == p_enabled) {
480
return;
481
}
482
483
point_gravity = p_enabled;
484
485
_gravity_changed();
486
}
487
488
void JoltArea3D::set_gravity(float p_gravity) {
489
if (gravity == p_gravity) {
490
return;
491
}
492
493
gravity = p_gravity;
494
495
_gravity_changed();
496
}
497
498
void JoltArea3D::set_point_gravity_distance(float p_distance) {
499
if (point_gravity_distance == p_distance) {
500
return;
501
}
502
503
point_gravity_distance = p_distance;
504
505
_gravity_changed();
506
}
507
508
void JoltArea3D::set_gravity_mode(OverrideMode p_mode) {
509
if (gravity_mode == p_mode) {
510
return;
511
}
512
513
gravity_mode = p_mode;
514
515
_gravity_changed();
516
}
517
518
void JoltArea3D::set_gravity_vector(const Vector3 &p_vector) {
519
if (gravity_vector == p_vector) {
520
return;
521
}
522
523
gravity_vector = p_vector;
524
525
_gravity_changed();
526
}
527
528
Vector3 JoltArea3D::compute_gravity(const Vector3 &p_position) const {
529
if (!point_gravity) {
530
return gravity_vector * gravity;
531
}
532
533
const Vector3 point = get_transform_scaled().xform(gravity_vector);
534
const Vector3 to_point = point - p_position;
535
const real_t to_point_dist_sq = MAX(to_point.length_squared(), (real_t)CMP_EPSILON);
536
const Vector3 to_point_dir = to_point / Math::sqrt(to_point_dist_sq);
537
538
if (point_gravity_distance == 0.0f) {
539
return to_point_dir * gravity;
540
}
541
542
const float gravity_dist_sq = point_gravity_distance * point_gravity_distance;
543
544
return to_point_dir * (gravity * gravity_dist_sq / to_point_dist_sq);
545
}
546
547
void JoltArea3D::body_shape_entered(const JPH::BodyID &p_body_id, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
548
Overlap &overlap = bodies_by_id[p_body_id];
549
550
if (overlap.shape_pairs.is_empty()) {
551
_notify_body_entered(p_body_id);
552
}
553
554
_add_shape_pair(overlap, p_body_id, p_other_shape_id, p_self_shape_id);
555
}
556
557
bool JoltArea3D::body_shape_exited(const JPH::BodyID &p_body_id, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
558
Overlap *overlap = bodies_by_id.getptr(p_body_id);
559
if (overlap == nullptr) {
560
return false;
561
}
562
563
if (!_remove_shape_pair(*overlap, p_other_shape_id, p_self_shape_id)) {
564
return false;
565
}
566
567
if (overlap->shape_pairs.is_empty()) {
568
_notify_body_exited(p_body_id);
569
}
570
571
return true;
572
}
573
574
void JoltArea3D::area_shape_entered(const JPH::BodyID &p_body_id, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
575
_add_shape_pair(areas_by_id[p_body_id], p_body_id, p_other_shape_id, p_self_shape_id);
576
}
577
578
bool JoltArea3D::area_shape_exited(const JPH::BodyID &p_body_id, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
579
Overlap *overlap = areas_by_id.getptr(p_body_id);
580
if (overlap == nullptr) {
581
return false;
582
}
583
584
return _remove_shape_pair(*overlap, p_other_shape_id, p_self_shape_id);
585
}
586
587
bool JoltArea3D::shape_exited(const JPH::BodyID &p_body_id, const JPH::SubShapeID &p_other_shape_id, const JPH::SubShapeID &p_self_shape_id) {
588
return body_shape_exited(p_body_id, p_other_shape_id, p_self_shape_id) || area_shape_exited(p_body_id, p_other_shape_id, p_self_shape_id);
589
}
590
591
void JoltArea3D::body_exited(const JPH::BodyID &p_body_id, bool p_notify) {
592
Overlap *overlap = bodies_by_id.getptr(p_body_id);
593
if (unlikely(overlap == nullptr)) {
594
return;
595
}
596
597
if (unlikely(overlap->shape_pairs.is_empty())) {
598
return;
599
}
600
601
for (const KeyValue<ShapeIDPair, ShapeIndexPair> &E : overlap->shape_pairs) {
602
overlap->pending_added.erase(E.value);
603
overlap->pending_removed.push_back(E.value);
604
}
605
606
_events_changed();
607
608
overlap->shape_pairs.clear();
609
610
if (p_notify) {
611
_notify_body_exited(p_body_id);
612
}
613
}
614
615
void JoltArea3D::area_exited(const JPH::BodyID &p_body_id) {
616
Overlap *overlap = areas_by_id.getptr(p_body_id);
617
if (unlikely(overlap == nullptr)) {
618
return;
619
}
620
621
if (unlikely(overlap->shape_pairs.is_empty())) {
622
return;
623
}
624
625
for (const KeyValue<ShapeIDPair, ShapeIndexPair> &E : overlap->shape_pairs) {
626
overlap->pending_added.erase(E.value);
627
overlap->pending_removed.push_back(E.value);
628
}
629
630
_events_changed();
631
632
overlap->shape_pairs.clear();
633
}
634
635
void JoltArea3D::call_queries() {
636
_flush_events(bodies_by_id, body_monitor_callback);
637
_flush_events(areas_by_id, area_monitor_callback);
638
}
639
640