box2d-ruby 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +336 -0
- data/examples/contact_events.rb +22 -0
- data/examples/debug_draw.rb +15 -0
- data/examples/falling_ball.rb +19 -0
- data/examples/rugl_debug_draw.rb +68 -0
- data/examples/stagecraft_debug_draw.rb +64 -0
- data/examples/support/box2d_debug_lines.rb +125 -0
- data/ext/box2d/CMakeLists.txt +35 -0
- data/ext/box2d/extconf.rb +42 -0
- data/ext/box2d/native.c +9 -0
- data/ext/box2d/vendor/box2d/LICENSE +21 -0
- data/ext/box2d/vendor/box2d/VERSION +1 -0
- data/ext/box2d/vendor/box2d/include/box2d/base.h +131 -0
- data/ext/box2d/vendor/box2d/include/box2d/box2d.h +1222 -0
- data/ext/box2d/vendor/box2d/include/box2d/collision.h +830 -0
- data/ext/box2d/vendor/box2d/include/box2d/id.h +144 -0
- data/ext/box2d/vendor/box2d/include/box2d/math_functions.h +761 -0
- data/ext/box2d/vendor/box2d/include/box2d/types.h +1457 -0
- data/ext/box2d/vendor/box2d/src/CMakeLists.txt +223 -0
- data/ext/box2d/vendor/box2d/src/aabb.c +132 -0
- data/ext/box2d/vendor/box2d/src/aabb.h +56 -0
- data/ext/box2d/vendor/box2d/src/arena_allocator.c +112 -0
- data/ext/box2d/vendor/box2d/src/arena_allocator.h +48 -0
- data/ext/box2d/vendor/box2d/src/array.c +8 -0
- data/ext/box2d/vendor/box2d/src/array.h +179 -0
- data/ext/box2d/vendor/box2d/src/atomic.h +79 -0
- data/ext/box2d/vendor/box2d/src/bitset.c +67 -0
- data/ext/box2d/vendor/box2d/src/bitset.h +65 -0
- data/ext/box2d/vendor/box2d/src/body.c +1884 -0
- data/ext/box2d/vendor/box2d/src/body.h +194 -0
- data/ext/box2d/vendor/box2d/src/box2d.natvis +41 -0
- data/ext/box2d/vendor/box2d/src/broad_phase.c +524 -0
- data/ext/box2d/vendor/box2d/src/broad_phase.h +83 -0
- data/ext/box2d/vendor/box2d/src/constants.h +54 -0
- data/ext/box2d/vendor/box2d/src/constraint_graph.c +322 -0
- data/ext/box2d/vendor/box2d/src/constraint_graph.h +58 -0
- data/ext/box2d/vendor/box2d/src/contact.c +650 -0
- data/ext/box2d/vendor/box2d/src/contact.h +148 -0
- data/ext/box2d/vendor/box2d/src/contact_solver.c +2120 -0
- data/ext/box2d/vendor/box2d/src/contact_solver.h +54 -0
- data/ext/box2d/vendor/box2d/src/core.c +178 -0
- data/ext/box2d/vendor/box2d/src/core.h +149 -0
- data/ext/box2d/vendor/box2d/src/ctz.h +112 -0
- data/ext/box2d/vendor/box2d/src/distance.c +1415 -0
- data/ext/box2d/vendor/box2d/src/distance_joint.c +556 -0
- data/ext/box2d/vendor/box2d/src/dynamic_tree.c +1989 -0
- data/ext/box2d/vendor/box2d/src/geometry.c +1028 -0
- data/ext/box2d/vendor/box2d/src/hull.c +328 -0
- data/ext/box2d/vendor/box2d/src/id_pool.c +79 -0
- data/ext/box2d/vendor/box2d/src/id_pool.h +35 -0
- data/ext/box2d/vendor/box2d/src/island.c +977 -0
- data/ext/box2d/vendor/box2d/src/island.h +89 -0
- data/ext/box2d/vendor/box2d/src/joint.c +1272 -0
- data/ext/box2d/vendor/box2d/src/joint.h +335 -0
- data/ext/box2d/vendor/box2d/src/manifold.c +1726 -0
- data/ext/box2d/vendor/box2d/src/math_functions.c +159 -0
- data/ext/box2d/vendor/box2d/src/motor_joint.c +283 -0
- data/ext/box2d/vendor/box2d/src/mouse_joint.c +214 -0
- data/ext/box2d/vendor/box2d/src/mover.c +73 -0
- data/ext/box2d/vendor/box2d/src/prismatic_joint.c +656 -0
- data/ext/box2d/vendor/box2d/src/revolute_joint.c +534 -0
- data/ext/box2d/vendor/box2d/src/sensor.c +389 -0
- data/ext/box2d/vendor/box2d/src/sensor.h +36 -0
- data/ext/box2d/vendor/box2d/src/shape.c +1714 -0
- data/ext/box2d/vendor/box2d/src/shape.h +123 -0
- data/ext/box2d/vendor/box2d/src/solver.c +2038 -0
- data/ext/box2d/vendor/box2d/src/solver.h +155 -0
- data/ext/box2d/vendor/box2d/src/solver_set.c +613 -0
- data/ext/box2d/vendor/box2d/src/solver_set.h +57 -0
- data/ext/box2d/vendor/box2d/src/table.c +238 -0
- data/ext/box2d/vendor/box2d/src/table.h +37 -0
- data/ext/box2d/vendor/box2d/src/timer.c +185 -0
- data/ext/box2d/vendor/box2d/src/types.c +151 -0
- data/ext/box2d/vendor/box2d/src/weld_joint.c +310 -0
- data/ext/box2d/vendor/box2d/src/wheel_joint.c +551 -0
- data/ext/box2d/vendor/box2d/src/world.c +3301 -0
- data/ext/box2d/vendor/box2d/src/world.h +192 -0
- data/generator/generate.rb +316 -0
- data/generator/layout_probe.c +507 -0
- data/generator/verify_layouts.rb +32 -0
- data/lib/box2d/body.rb +172 -0
- data/lib/box2d/body_definition.rb +38 -0
- data/lib/box2d/body_shapes.rb +135 -0
- data/lib/box2d/chain.rb +61 -0
- data/lib/box2d/debug_draw.rb +118 -0
- data/lib/box2d/events.rb +103 -0
- data/lib/box2d/fixed_stepper.rb +39 -0
- data/lib/box2d/handle.rb +46 -0
- data/lib/box2d/hit.rb +5 -0
- data/lib/box2d/joint.rb +197 -0
- data/lib/box2d/native.rb +1462 -0
- data/lib/box2d/native_loader.rb +45 -0
- data/lib/box2d/pixel_scale.rb +29 -0
- data/lib/box2d/shape.rb +109 -0
- data/lib/box2d/shape_definition.rb +44 -0
- data/lib/box2d/value_conversion.rb +80 -0
- data/lib/box2d/version.rb +7 -0
- data/lib/box2d/world.rb +135 -0
- data/lib/box2d/world_joints.rb +156 -0
- data/lib/box2d/world_queries.rb +122 -0
- data/lib/box2d/world_registry.rb +95 -0
- data/lib/box2d.rb +31 -0
- data/script/build_platform_gem.rb +24 -0
- data/script/deterministic_scene.rb +56 -0
- data/script/update_deterministic_snapshot.rb +11 -0
- data/script/verify_platform_gem.rb +24 -0
- metadata +164 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Erin Catto
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
#include "sensor.h"
|
|
5
|
+
|
|
6
|
+
#include "array.h"
|
|
7
|
+
#include "body.h"
|
|
8
|
+
#include "contact.h"
|
|
9
|
+
#include "ctz.h"
|
|
10
|
+
#include "shape.h"
|
|
11
|
+
#include "world.h"
|
|
12
|
+
|
|
13
|
+
#include "box2d/collision.h"
|
|
14
|
+
|
|
15
|
+
#include <stddef.h>
|
|
16
|
+
#include <stdlib.h>
|
|
17
|
+
|
|
18
|
+
B2_ARRAY_SOURCE( b2ShapeRef, b2ShapeRef )
|
|
19
|
+
B2_ARRAY_SOURCE( b2Sensor, b2Sensor )
|
|
20
|
+
B2_ARRAY_SOURCE( b2SensorTaskContext, b2SensorTaskContext )
|
|
21
|
+
|
|
22
|
+
struct b2SensorQueryContext
|
|
23
|
+
{
|
|
24
|
+
b2World* world;
|
|
25
|
+
b2SensorTaskContext* taskContext;
|
|
26
|
+
b2Sensor* sensor;
|
|
27
|
+
b2Shape* sensorShape;
|
|
28
|
+
b2Transform transform;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Sensor shapes need to
|
|
32
|
+
// - detect begin and end overlap events
|
|
33
|
+
// - events must be reported in deterministic order
|
|
34
|
+
// - maintain an active list of overlaps for query
|
|
35
|
+
|
|
36
|
+
// Assumption
|
|
37
|
+
// - sensors don't detect shapes on the same body
|
|
38
|
+
|
|
39
|
+
// Algorithm
|
|
40
|
+
// Query all sensors for overlaps
|
|
41
|
+
// Check against previous overlaps
|
|
42
|
+
|
|
43
|
+
// Data structures
|
|
44
|
+
// Each sensor has an double buffered array of overlaps
|
|
45
|
+
// These overlaps use a shape reference with index and generation
|
|
46
|
+
|
|
47
|
+
static bool b2SensorQueryCallback( int proxyId, uint64_t userData, void* context )
|
|
48
|
+
{
|
|
49
|
+
B2_UNUSED( proxyId );
|
|
50
|
+
|
|
51
|
+
int shapeId = (int)userData;
|
|
52
|
+
|
|
53
|
+
struct b2SensorQueryContext* queryContext = context;
|
|
54
|
+
b2Shape* sensorShape = queryContext->sensorShape;
|
|
55
|
+
int sensorShapeId = sensorShape->id;
|
|
56
|
+
|
|
57
|
+
if ( shapeId == sensorShapeId )
|
|
58
|
+
{
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
b2World* world = queryContext->world;
|
|
63
|
+
b2Shape* otherShape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
64
|
+
|
|
65
|
+
// Are sensor events enabled on the other shape?
|
|
66
|
+
if ( otherShape->enableSensorEvents == false )
|
|
67
|
+
{
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Skip shapes on the same body
|
|
72
|
+
if ( otherShape->bodyId == sensorShape->bodyId )
|
|
73
|
+
{
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check filter
|
|
78
|
+
if ( b2ShouldShapesCollide( sensorShape->filter, otherShape->filter ) == false )
|
|
79
|
+
{
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
b2Transform otherTransform = b2GetBodyTransform( world, otherShape->bodyId );
|
|
84
|
+
|
|
85
|
+
b2DistanceInput input;
|
|
86
|
+
input.proxyA = b2MakeShapeDistanceProxy( sensorShape );
|
|
87
|
+
input.proxyB = b2MakeShapeDistanceProxy( otherShape );
|
|
88
|
+
input.transformA = queryContext->transform;
|
|
89
|
+
input.transformB = otherTransform;
|
|
90
|
+
input.useRadii = true;
|
|
91
|
+
b2SimplexCache cache = { 0 };
|
|
92
|
+
b2DistanceOutput output = b2ShapeDistance(&input, &cache, NULL, 0 );
|
|
93
|
+
|
|
94
|
+
bool overlaps = output.distance < 10.0f * FLT_EPSILON;
|
|
95
|
+
if ( overlaps == false )
|
|
96
|
+
{
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Record the overlap
|
|
101
|
+
b2Sensor* sensor = queryContext->sensor;
|
|
102
|
+
b2ShapeRef* shapeRef = b2ShapeRefArray_Add( &sensor->overlaps2 );
|
|
103
|
+
shapeRef->shapeId = shapeId;
|
|
104
|
+
shapeRef->generation = otherShape->generation;
|
|
105
|
+
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static int b2CompareShapeRefs( const void* a, const void* b )
|
|
110
|
+
{
|
|
111
|
+
const b2ShapeRef* sa = a;
|
|
112
|
+
const b2ShapeRef* sb = b;
|
|
113
|
+
|
|
114
|
+
if ( sa->shapeId < sb->shapeId )
|
|
115
|
+
{
|
|
116
|
+
return -1;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if ( sa->shapeId == sb->shapeId )
|
|
120
|
+
{
|
|
121
|
+
if ( sa->generation < sb->generation )
|
|
122
|
+
{
|
|
123
|
+
return -1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ( sa->generation == sb->generation )
|
|
127
|
+
{
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static void b2SensorTask( int startIndex, int endIndex, uint32_t threadIndex, void* context )
|
|
136
|
+
{
|
|
137
|
+
b2TracyCZoneNC( sensor_task, "Overlap", b2_colorBrown, true );
|
|
138
|
+
|
|
139
|
+
b2World* world = context;
|
|
140
|
+
B2_ASSERT( (int)threadIndex < world->workerCount );
|
|
141
|
+
b2SensorTaskContext* taskContext = world->sensorTaskContexts.data + threadIndex;
|
|
142
|
+
|
|
143
|
+
B2_ASSERT( startIndex < endIndex );
|
|
144
|
+
|
|
145
|
+
b2DynamicTree* trees = world->broadPhase.trees;
|
|
146
|
+
for ( int sensorIndex = startIndex; sensorIndex < endIndex; ++sensorIndex )
|
|
147
|
+
{
|
|
148
|
+
b2Sensor* sensor = b2SensorArray_Get( &world->sensors, sensorIndex );
|
|
149
|
+
b2Shape* sensorShape = b2ShapeArray_Get( &world->shapes, sensor->shapeId );
|
|
150
|
+
|
|
151
|
+
// swap overlap arrays
|
|
152
|
+
b2ShapeRefArray temp = sensor->overlaps1;
|
|
153
|
+
sensor->overlaps1 = sensor->overlaps2;
|
|
154
|
+
sensor->overlaps2 = temp;
|
|
155
|
+
b2ShapeRefArray_Clear( &sensor->overlaps2 );
|
|
156
|
+
|
|
157
|
+
b2Body* body = b2BodyArray_Get( &world->bodies, sensorShape->bodyId );
|
|
158
|
+
if ( body->setIndex == b2_disabledSet || sensorShape->enableSensorEvents == false )
|
|
159
|
+
{
|
|
160
|
+
if ( sensor->overlaps1.count != 0 )
|
|
161
|
+
{
|
|
162
|
+
b2SetBit( &taskContext->eventBits, sensorIndex );
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
168
|
+
|
|
169
|
+
struct b2SensorQueryContext queryContext = {
|
|
170
|
+
.world = world,
|
|
171
|
+
.taskContext = taskContext,
|
|
172
|
+
.sensorShape = sensorShape,
|
|
173
|
+
.sensor = sensor,
|
|
174
|
+
.transform = transform,
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
B2_ASSERT( sensorShape->sensorIndex == sensorIndex );
|
|
178
|
+
b2AABB queryBounds = sensorShape->aabb;
|
|
179
|
+
|
|
180
|
+
// Query all trees
|
|
181
|
+
b2DynamicTree_Query( trees + 0, queryBounds, sensorShape->filter.maskBits, b2SensorQueryCallback, &queryContext );
|
|
182
|
+
b2DynamicTree_Query( trees + 1, queryBounds, sensorShape->filter.maskBits, b2SensorQueryCallback, &queryContext );
|
|
183
|
+
b2DynamicTree_Query( trees + 2, queryBounds, sensorShape->filter.maskBits, b2SensorQueryCallback, &queryContext );
|
|
184
|
+
|
|
185
|
+
// Sort the overlaps to enable finding begin and end events.
|
|
186
|
+
qsort( sensor->overlaps2.data, sensor->overlaps2.count, sizeof( b2ShapeRef ), b2CompareShapeRefs );
|
|
187
|
+
|
|
188
|
+
int count1 = sensor->overlaps1.count;
|
|
189
|
+
int count2 = sensor->overlaps2.count;
|
|
190
|
+
if ( count1 != count2 )
|
|
191
|
+
{
|
|
192
|
+
// something changed
|
|
193
|
+
b2SetBit( &taskContext->eventBits, sensorIndex );
|
|
194
|
+
}
|
|
195
|
+
else
|
|
196
|
+
{
|
|
197
|
+
for ( int i = 0; i < count1; ++i )
|
|
198
|
+
{
|
|
199
|
+
b2ShapeRef* s1 = sensor->overlaps1.data + i;
|
|
200
|
+
b2ShapeRef* s2 = sensor->overlaps2.data + i;
|
|
201
|
+
|
|
202
|
+
if ( s1->shapeId != s2->shapeId || s1->generation != s2->generation )
|
|
203
|
+
{
|
|
204
|
+
// something changed
|
|
205
|
+
b2SetBit( &taskContext->eventBits, sensorIndex );
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
b2TracyCZoneEnd( sensor_task );
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
void b2OverlapSensors( b2World* world )
|
|
216
|
+
{
|
|
217
|
+
int sensorCount = world->sensors.count;
|
|
218
|
+
if ( sensorCount == 0 )
|
|
219
|
+
{
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
B2_ASSERT( world->workerCount > 0 );
|
|
224
|
+
|
|
225
|
+
b2TracyCZoneNC( overlap_sensors, "Sensors", b2_colorMediumPurple, true );
|
|
226
|
+
|
|
227
|
+
for ( int i = 0; i < world->workerCount; ++i )
|
|
228
|
+
{
|
|
229
|
+
b2SetBitCountAndClear( &world->sensorTaskContexts.data[i].eventBits, sensorCount );
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Parallel-for sensors overlaps
|
|
233
|
+
int minRange = 16;
|
|
234
|
+
void* userSensorTask = world->enqueueTaskFcn( &b2SensorTask, sensorCount, minRange, world, world->userTaskContext );
|
|
235
|
+
world->taskCount += 1;
|
|
236
|
+
if ( userSensorTask != NULL )
|
|
237
|
+
{
|
|
238
|
+
world->finishTaskFcn( userSensorTask, world->userTaskContext );
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
b2TracyCZoneNC( sensor_state, "Events", b2_colorLightSlateGray, true );
|
|
242
|
+
|
|
243
|
+
b2BitSet* bitSet = &world->sensorTaskContexts.data[0].eventBits;
|
|
244
|
+
for ( int i = 1; i < world->workerCount; ++i )
|
|
245
|
+
{
|
|
246
|
+
b2InPlaceUnion( bitSet, &world->sensorTaskContexts.data[i].eventBits );
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Iterate sensors bits and publish events
|
|
250
|
+
// Process contact state changes. Iterate over set bits
|
|
251
|
+
uint64_t* bits = bitSet->bits;
|
|
252
|
+
uint32_t blockCount = bitSet->blockCount;
|
|
253
|
+
|
|
254
|
+
for ( uint32_t k = 0; k < blockCount; ++k )
|
|
255
|
+
{
|
|
256
|
+
uint64_t word = bits[k];
|
|
257
|
+
while ( word != 0 )
|
|
258
|
+
{
|
|
259
|
+
uint32_t ctz = b2CTZ64( word );
|
|
260
|
+
int sensorIndex = (int)( 64 * k + ctz );
|
|
261
|
+
|
|
262
|
+
b2Sensor* sensor = b2SensorArray_Get( &world->sensors, sensorIndex );
|
|
263
|
+
b2Shape* sensorShape = b2ShapeArray_Get( &world->shapes, sensor->shapeId );
|
|
264
|
+
b2ShapeId sensorId = { sensor->shapeId + 1, world->worldId, sensorShape->generation };
|
|
265
|
+
|
|
266
|
+
int count1 = sensor->overlaps1.count;
|
|
267
|
+
int count2 = sensor->overlaps2.count;
|
|
268
|
+
const b2ShapeRef* refs1 = sensor->overlaps1.data;
|
|
269
|
+
const b2ShapeRef* refs2 = sensor->overlaps2.data;
|
|
270
|
+
|
|
271
|
+
// overlaps1 can have overlaps that end
|
|
272
|
+
// overlaps2 can have overlaps that begin
|
|
273
|
+
int index1 = 0, index2 = 0;
|
|
274
|
+
while ( index1 < count1 && index2 < count2 )
|
|
275
|
+
{
|
|
276
|
+
const b2ShapeRef* r1 = refs1 + index1;
|
|
277
|
+
const b2ShapeRef* r2 = refs2 + index2;
|
|
278
|
+
if ( r1->shapeId == r2->shapeId )
|
|
279
|
+
{
|
|
280
|
+
if ( r1->generation < r2->generation )
|
|
281
|
+
{
|
|
282
|
+
// end
|
|
283
|
+
b2ShapeId visitorId = { r1->shapeId + 1, world->worldId, r1->generation };
|
|
284
|
+
b2SensorEndTouchEvent event = {
|
|
285
|
+
.sensorShapeId = sensorId,
|
|
286
|
+
.visitorShapeId = visitorId,
|
|
287
|
+
};
|
|
288
|
+
b2SensorEndTouchEventArray_Push( &world->sensorEndEvents[world->endEventArrayIndex], event );
|
|
289
|
+
index1 += 1;
|
|
290
|
+
}
|
|
291
|
+
else if ( r1->generation > r2->generation )
|
|
292
|
+
{
|
|
293
|
+
// begin
|
|
294
|
+
b2ShapeId visitorId = { r2->shapeId + 1, world->worldId, r2->generation };
|
|
295
|
+
b2SensorBeginTouchEvent event = { sensorId, visitorId };
|
|
296
|
+
b2SensorBeginTouchEventArray_Push( &world->sensorBeginEvents, event );
|
|
297
|
+
index2 += 1;
|
|
298
|
+
}
|
|
299
|
+
else
|
|
300
|
+
{
|
|
301
|
+
// persisted
|
|
302
|
+
index1 += 1;
|
|
303
|
+
index2 += 1;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else if ( r1->shapeId < r2->shapeId )
|
|
307
|
+
{
|
|
308
|
+
// end
|
|
309
|
+
b2ShapeId visitorId = { r1->shapeId + 1, world->worldId, r1->generation };
|
|
310
|
+
b2SensorEndTouchEvent event = { sensorId, visitorId };
|
|
311
|
+
b2SensorEndTouchEventArray_Push( &world->sensorEndEvents[world->endEventArrayIndex], event );
|
|
312
|
+
index1 += 1;
|
|
313
|
+
}
|
|
314
|
+
else
|
|
315
|
+
{
|
|
316
|
+
// begin
|
|
317
|
+
b2ShapeId visitorId = { r2->shapeId + 1, world->worldId, r2->generation };
|
|
318
|
+
b2SensorBeginTouchEvent event = { sensorId, visitorId };
|
|
319
|
+
b2SensorBeginTouchEventArray_Push( &world->sensorBeginEvents, event );
|
|
320
|
+
index2 += 1;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
while ( index1 < count1 )
|
|
325
|
+
{
|
|
326
|
+
// end
|
|
327
|
+
const b2ShapeRef* r1 = refs1 + index1;
|
|
328
|
+
b2ShapeId visitorId = { r1->shapeId + 1, world->worldId, r1->generation };
|
|
329
|
+
b2SensorEndTouchEvent event = { sensorId, visitorId };
|
|
330
|
+
b2SensorEndTouchEventArray_Push( &world->sensorEndEvents[world->endEventArrayIndex], event );
|
|
331
|
+
index1 += 1;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
while ( index2 < count2 )
|
|
335
|
+
{
|
|
336
|
+
// begin
|
|
337
|
+
const b2ShapeRef* r2 = refs2 + index2;
|
|
338
|
+
b2ShapeId visitorId = { r2->shapeId + 1, world->worldId, r2->generation };
|
|
339
|
+
b2SensorBeginTouchEvent event = { sensorId, visitorId };
|
|
340
|
+
b2SensorBeginTouchEventArray_Push( &world->sensorBeginEvents, event );
|
|
341
|
+
index2 += 1;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Clear the smallest set bit
|
|
345
|
+
word = word & ( word - 1 );
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
b2TracyCZoneEnd( sensor_state );
|
|
350
|
+
b2TracyCZoneEnd( overlap_sensors );
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
void b2DestroySensor( b2World* world, b2Shape* sensorShape )
|
|
354
|
+
{
|
|
355
|
+
b2Sensor* sensor = b2SensorArray_Get( &world->sensors, sensorShape->sensorIndex );
|
|
356
|
+
for ( int i = 0; i < sensor->overlaps2.count; ++i )
|
|
357
|
+
{
|
|
358
|
+
b2ShapeRef* ref = sensor->overlaps2.data + i;
|
|
359
|
+
b2SensorEndTouchEvent event = {
|
|
360
|
+
.sensorShapeId =
|
|
361
|
+
{
|
|
362
|
+
.index1 = sensorShape->id + 1,
|
|
363
|
+
.generation = sensorShape->generation,
|
|
364
|
+
.world0 = world->worldId,
|
|
365
|
+
},
|
|
366
|
+
.visitorShapeId =
|
|
367
|
+
{
|
|
368
|
+
.index1 = ref->shapeId + 1,
|
|
369
|
+
.generation = ref->generation,
|
|
370
|
+
.world0 = world->worldId,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
b2SensorEndTouchEventArray_Push( world->sensorEndEvents + world->endEventArrayIndex, event );
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Destroy sensor
|
|
378
|
+
b2ShapeRefArray_Destroy( &sensor->overlaps1 );
|
|
379
|
+
b2ShapeRefArray_Destroy( &sensor->overlaps2 );
|
|
380
|
+
|
|
381
|
+
int movedIndex = b2SensorArray_RemoveSwap( &world->sensors, sensorShape->sensorIndex );
|
|
382
|
+
if ( movedIndex != B2_NULL_INDEX )
|
|
383
|
+
{
|
|
384
|
+
// Fixup moved sensor
|
|
385
|
+
b2Sensor* movedSensor = b2SensorArray_Get( &world->sensors, sensorShape->sensorIndex );
|
|
386
|
+
b2Shape* otherSensorShape = b2ShapeArray_Get( &world->shapes, movedSensor->shapeId );
|
|
387
|
+
otherSensorShape->sensorIndex = sensorShape->sensorIndex;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Erin Catto
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "array.h"
|
|
7
|
+
#include "bitset.h"
|
|
8
|
+
|
|
9
|
+
typedef struct b2Shape b2Shape;
|
|
10
|
+
typedef struct b2World b2World;
|
|
11
|
+
|
|
12
|
+
typedef struct b2ShapeRef
|
|
13
|
+
{
|
|
14
|
+
int shapeId;
|
|
15
|
+
uint16_t generation;
|
|
16
|
+
} b2ShapeRef;
|
|
17
|
+
|
|
18
|
+
typedef struct b2Sensor
|
|
19
|
+
{
|
|
20
|
+
b2ShapeRefArray overlaps1;
|
|
21
|
+
b2ShapeRefArray overlaps2;
|
|
22
|
+
int shapeId;
|
|
23
|
+
} b2Sensor;
|
|
24
|
+
|
|
25
|
+
typedef struct b2SensorTaskContext
|
|
26
|
+
{
|
|
27
|
+
b2BitSet eventBits;
|
|
28
|
+
} b2SensorTaskContext;
|
|
29
|
+
|
|
30
|
+
void b2OverlapSensors( b2World* world );
|
|
31
|
+
|
|
32
|
+
void b2DestroySensor( b2World* world, b2Shape* sensorShape );
|
|
33
|
+
|
|
34
|
+
B2_ARRAY_INLINE( b2ShapeRef, b2ShapeRef )
|
|
35
|
+
B2_ARRAY_INLINE( b2Sensor, b2Sensor )
|
|
36
|
+
B2_ARRAY_INLINE( b2SensorTaskContext, b2SensorTaskContext )
|