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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +336 -0
  4. data/examples/contact_events.rb +22 -0
  5. data/examples/debug_draw.rb +15 -0
  6. data/examples/falling_ball.rb +19 -0
  7. data/examples/rugl_debug_draw.rb +68 -0
  8. data/examples/stagecraft_debug_draw.rb +64 -0
  9. data/examples/support/box2d_debug_lines.rb +125 -0
  10. data/ext/box2d/CMakeLists.txt +35 -0
  11. data/ext/box2d/extconf.rb +42 -0
  12. data/ext/box2d/native.c +9 -0
  13. data/ext/box2d/vendor/box2d/LICENSE +21 -0
  14. data/ext/box2d/vendor/box2d/VERSION +1 -0
  15. data/ext/box2d/vendor/box2d/include/box2d/base.h +131 -0
  16. data/ext/box2d/vendor/box2d/include/box2d/box2d.h +1222 -0
  17. data/ext/box2d/vendor/box2d/include/box2d/collision.h +830 -0
  18. data/ext/box2d/vendor/box2d/include/box2d/id.h +144 -0
  19. data/ext/box2d/vendor/box2d/include/box2d/math_functions.h +761 -0
  20. data/ext/box2d/vendor/box2d/include/box2d/types.h +1457 -0
  21. data/ext/box2d/vendor/box2d/src/CMakeLists.txt +223 -0
  22. data/ext/box2d/vendor/box2d/src/aabb.c +132 -0
  23. data/ext/box2d/vendor/box2d/src/aabb.h +56 -0
  24. data/ext/box2d/vendor/box2d/src/arena_allocator.c +112 -0
  25. data/ext/box2d/vendor/box2d/src/arena_allocator.h +48 -0
  26. data/ext/box2d/vendor/box2d/src/array.c +8 -0
  27. data/ext/box2d/vendor/box2d/src/array.h +179 -0
  28. data/ext/box2d/vendor/box2d/src/atomic.h +79 -0
  29. data/ext/box2d/vendor/box2d/src/bitset.c +67 -0
  30. data/ext/box2d/vendor/box2d/src/bitset.h +65 -0
  31. data/ext/box2d/vendor/box2d/src/body.c +1884 -0
  32. data/ext/box2d/vendor/box2d/src/body.h +194 -0
  33. data/ext/box2d/vendor/box2d/src/box2d.natvis +41 -0
  34. data/ext/box2d/vendor/box2d/src/broad_phase.c +524 -0
  35. data/ext/box2d/vendor/box2d/src/broad_phase.h +83 -0
  36. data/ext/box2d/vendor/box2d/src/constants.h +54 -0
  37. data/ext/box2d/vendor/box2d/src/constraint_graph.c +322 -0
  38. data/ext/box2d/vendor/box2d/src/constraint_graph.h +58 -0
  39. data/ext/box2d/vendor/box2d/src/contact.c +650 -0
  40. data/ext/box2d/vendor/box2d/src/contact.h +148 -0
  41. data/ext/box2d/vendor/box2d/src/contact_solver.c +2120 -0
  42. data/ext/box2d/vendor/box2d/src/contact_solver.h +54 -0
  43. data/ext/box2d/vendor/box2d/src/core.c +178 -0
  44. data/ext/box2d/vendor/box2d/src/core.h +149 -0
  45. data/ext/box2d/vendor/box2d/src/ctz.h +112 -0
  46. data/ext/box2d/vendor/box2d/src/distance.c +1415 -0
  47. data/ext/box2d/vendor/box2d/src/distance_joint.c +556 -0
  48. data/ext/box2d/vendor/box2d/src/dynamic_tree.c +1989 -0
  49. data/ext/box2d/vendor/box2d/src/geometry.c +1028 -0
  50. data/ext/box2d/vendor/box2d/src/hull.c +328 -0
  51. data/ext/box2d/vendor/box2d/src/id_pool.c +79 -0
  52. data/ext/box2d/vendor/box2d/src/id_pool.h +35 -0
  53. data/ext/box2d/vendor/box2d/src/island.c +977 -0
  54. data/ext/box2d/vendor/box2d/src/island.h +89 -0
  55. data/ext/box2d/vendor/box2d/src/joint.c +1272 -0
  56. data/ext/box2d/vendor/box2d/src/joint.h +335 -0
  57. data/ext/box2d/vendor/box2d/src/manifold.c +1726 -0
  58. data/ext/box2d/vendor/box2d/src/math_functions.c +159 -0
  59. data/ext/box2d/vendor/box2d/src/motor_joint.c +283 -0
  60. data/ext/box2d/vendor/box2d/src/mouse_joint.c +214 -0
  61. data/ext/box2d/vendor/box2d/src/mover.c +73 -0
  62. data/ext/box2d/vendor/box2d/src/prismatic_joint.c +656 -0
  63. data/ext/box2d/vendor/box2d/src/revolute_joint.c +534 -0
  64. data/ext/box2d/vendor/box2d/src/sensor.c +389 -0
  65. data/ext/box2d/vendor/box2d/src/sensor.h +36 -0
  66. data/ext/box2d/vendor/box2d/src/shape.c +1714 -0
  67. data/ext/box2d/vendor/box2d/src/shape.h +123 -0
  68. data/ext/box2d/vendor/box2d/src/solver.c +2038 -0
  69. data/ext/box2d/vendor/box2d/src/solver.h +155 -0
  70. data/ext/box2d/vendor/box2d/src/solver_set.c +613 -0
  71. data/ext/box2d/vendor/box2d/src/solver_set.h +57 -0
  72. data/ext/box2d/vendor/box2d/src/table.c +238 -0
  73. data/ext/box2d/vendor/box2d/src/table.h +37 -0
  74. data/ext/box2d/vendor/box2d/src/timer.c +185 -0
  75. data/ext/box2d/vendor/box2d/src/types.c +151 -0
  76. data/ext/box2d/vendor/box2d/src/weld_joint.c +310 -0
  77. data/ext/box2d/vendor/box2d/src/wheel_joint.c +551 -0
  78. data/ext/box2d/vendor/box2d/src/world.c +3301 -0
  79. data/ext/box2d/vendor/box2d/src/world.h +192 -0
  80. data/generator/generate.rb +316 -0
  81. data/generator/layout_probe.c +507 -0
  82. data/generator/verify_layouts.rb +32 -0
  83. data/lib/box2d/body.rb +172 -0
  84. data/lib/box2d/body_definition.rb +38 -0
  85. data/lib/box2d/body_shapes.rb +135 -0
  86. data/lib/box2d/chain.rb +61 -0
  87. data/lib/box2d/debug_draw.rb +118 -0
  88. data/lib/box2d/events.rb +103 -0
  89. data/lib/box2d/fixed_stepper.rb +39 -0
  90. data/lib/box2d/handle.rb +46 -0
  91. data/lib/box2d/hit.rb +5 -0
  92. data/lib/box2d/joint.rb +197 -0
  93. data/lib/box2d/native.rb +1462 -0
  94. data/lib/box2d/native_loader.rb +45 -0
  95. data/lib/box2d/pixel_scale.rb +29 -0
  96. data/lib/box2d/shape.rb +109 -0
  97. data/lib/box2d/shape_definition.rb +44 -0
  98. data/lib/box2d/value_conversion.rb +80 -0
  99. data/lib/box2d/version.rb +7 -0
  100. data/lib/box2d/world.rb +135 -0
  101. data/lib/box2d/world_joints.rb +156 -0
  102. data/lib/box2d/world_queries.rb +122 -0
  103. data/lib/box2d/world_registry.rb +95 -0
  104. data/lib/box2d.rb +31 -0
  105. data/script/build_platform_gem.rb +24 -0
  106. data/script/deterministic_scene.rb +56 -0
  107. data/script/update_deterministic_snapshot.rb +11 -0
  108. data/script/verify_platform_gem.rb +24 -0
  109. metadata +164 -0
@@ -0,0 +1,1272 @@
1
+ // SPDX-FileCopyrightText: 2023 Erin Catto
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ #include "joint.h"
5
+
6
+ #include "body.h"
7
+ #include "contact.h"
8
+ #include "core.h"
9
+ #include "island.h"
10
+ #include "shape.h"
11
+ #include "solver.h"
12
+ #include "solver_set.h"
13
+ #include "world.h"
14
+
15
+ // needed for dll export
16
+ #include "box2d/box2d.h"
17
+
18
+ #include <stddef.h>
19
+ #include <string.h>
20
+
21
+ B2_ARRAY_SOURCE( b2Joint, b2Joint )
22
+ B2_ARRAY_SOURCE( b2JointSim, b2JointSim )
23
+
24
+ b2DistanceJointDef b2DefaultDistanceJointDef( void )
25
+ {
26
+ b2DistanceJointDef def = { 0 };
27
+ def.length = 1.0f;
28
+ def.maxLength = B2_HUGE;
29
+ def.internalValue = B2_SECRET_COOKIE;
30
+ return def;
31
+ }
32
+
33
+ b2MotorJointDef b2DefaultMotorJointDef( void )
34
+ {
35
+ b2MotorJointDef def = { 0 };
36
+ def.maxForce = 1.0f;
37
+ def.maxTorque = 1.0f;
38
+ def.correctionFactor = 0.3f;
39
+ def.internalValue = B2_SECRET_COOKIE;
40
+ return def;
41
+ }
42
+
43
+ b2MouseJointDef b2DefaultMouseJointDef( void )
44
+ {
45
+ b2MouseJointDef def = { 0 };
46
+ def.hertz = 4.0f;
47
+ def.dampingRatio = 1.0f;
48
+ def.maxForce = 1.0f;
49
+ def.internalValue = B2_SECRET_COOKIE;
50
+ return def;
51
+ }
52
+
53
+ b2FilterJointDef b2DefaultFilterJointDef( void )
54
+ {
55
+ b2FilterJointDef def = { 0 };
56
+ def.internalValue = B2_SECRET_COOKIE;
57
+ return def;
58
+ }
59
+
60
+ b2PrismaticJointDef b2DefaultPrismaticJointDef( void )
61
+ {
62
+ b2PrismaticJointDef def = { 0 };
63
+ def.localAxisA = (b2Vec2){ 1.0f, 0.0f };
64
+ def.internalValue = B2_SECRET_COOKIE;
65
+ return def;
66
+ }
67
+
68
+ b2RevoluteJointDef b2DefaultRevoluteJointDef( void )
69
+ {
70
+ b2RevoluteJointDef def = { 0 };
71
+ def.drawSize = 0.25f;
72
+ def.internalValue = B2_SECRET_COOKIE;
73
+ return def;
74
+ }
75
+
76
+ b2WeldJointDef b2DefaultWeldJointDef( void )
77
+ {
78
+ b2WeldJointDef def = { 0 };
79
+ def.internalValue = B2_SECRET_COOKIE;
80
+ return def;
81
+ }
82
+
83
+ b2WheelJointDef b2DefaultWheelJointDef( void )
84
+ {
85
+ b2WheelJointDef def = { 0 };
86
+ def.localAxisA.y = 1.0f;
87
+ def.enableSpring = true;
88
+ def.hertz = 1.0f;
89
+ def.dampingRatio = 0.7f;
90
+ def.internalValue = B2_SECRET_COOKIE;
91
+ return def;
92
+ }
93
+
94
+ b2ExplosionDef b2DefaultExplosionDef( void )
95
+ {
96
+ b2ExplosionDef def = { 0 };
97
+ def.maskBits = B2_DEFAULT_MASK_BITS;
98
+ return def;
99
+ }
100
+
101
+ b2Joint* b2GetJointFullId( b2World* world, b2JointId jointId )
102
+ {
103
+ int id = jointId.index1 - 1;
104
+ b2Joint* joint = b2JointArray_Get( &world->joints, id );
105
+ B2_ASSERT( joint->jointId == id && joint->generation == jointId.generation );
106
+ return joint;
107
+ }
108
+
109
+ b2JointSim* b2GetJointSim( b2World* world, b2Joint* joint )
110
+ {
111
+ if ( joint->setIndex == b2_awakeSet )
112
+ {
113
+ B2_ASSERT( 0 <= joint->colorIndex && joint->colorIndex < B2_GRAPH_COLOR_COUNT );
114
+ b2GraphColor* color = world->constraintGraph.colors + joint->colorIndex;
115
+ return b2JointSimArray_Get( &color->jointSims, joint->localIndex );
116
+ }
117
+
118
+ b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, joint->setIndex );
119
+ return b2JointSimArray_Get( &set->jointSims, joint->localIndex );
120
+ }
121
+
122
+ b2JointSim* b2GetJointSimCheckType( b2JointId jointId, b2JointType type )
123
+ {
124
+ B2_UNUSED( type );
125
+
126
+ b2World* world = b2GetWorld( jointId.world0 );
127
+ B2_ASSERT( world->locked == false );
128
+ if ( world->locked )
129
+ {
130
+ return NULL;
131
+ }
132
+
133
+ b2Joint* joint = b2GetJointFullId( world, jointId );
134
+ B2_ASSERT( joint->type == type );
135
+ b2JointSim* jointSim = b2GetJointSim( world, joint );
136
+ B2_ASSERT( jointSim->type == type );
137
+ return jointSim;
138
+ }
139
+
140
+ typedef struct b2JointPair
141
+ {
142
+ b2Joint* joint;
143
+ b2JointSim* jointSim;
144
+ } b2JointPair;
145
+
146
+ static b2JointPair b2CreateJoint( b2World* world, b2Body* bodyA, b2Body* bodyB, void* userData, float drawSize, b2JointType type,
147
+ bool collideConnected )
148
+ {
149
+ int bodyIdA = bodyA->id;
150
+ int bodyIdB = bodyB->id;
151
+ int maxSetIndex = b2MaxInt( bodyA->setIndex, bodyB->setIndex );
152
+
153
+ // Create joint id and joint
154
+ int jointId = b2AllocId( &world->jointIdPool );
155
+ if ( jointId == world->joints.count )
156
+ {
157
+ b2JointArray_Push( &world->joints, (b2Joint){ 0 } );
158
+ }
159
+
160
+ b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
161
+ joint->jointId = jointId;
162
+ joint->userData = userData;
163
+ joint->generation += 1;
164
+ joint->setIndex = B2_NULL_INDEX;
165
+ joint->colorIndex = B2_NULL_INDEX;
166
+ joint->localIndex = B2_NULL_INDEX;
167
+ joint->islandId = B2_NULL_INDEX;
168
+ joint->islandPrev = B2_NULL_INDEX;
169
+ joint->islandNext = B2_NULL_INDEX;
170
+ joint->drawSize = drawSize;
171
+ joint->type = type;
172
+ joint->collideConnected = collideConnected;
173
+ joint->isMarked = false;
174
+
175
+ // Doubly linked list on bodyA
176
+ joint->edges[0].bodyId = bodyIdA;
177
+ joint->edges[0].prevKey = B2_NULL_INDEX;
178
+ joint->edges[0].nextKey = bodyA->headJointKey;
179
+
180
+ int keyA = ( jointId << 1 ) | 0;
181
+ if ( bodyA->headJointKey != B2_NULL_INDEX )
182
+ {
183
+ b2Joint* jointA = b2JointArray_Get( &world->joints, bodyA->headJointKey >> 1 );
184
+ b2JointEdge* edgeA = jointA->edges + ( bodyA->headJointKey & 1 );
185
+ edgeA->prevKey = keyA;
186
+ }
187
+ bodyA->headJointKey = keyA;
188
+ bodyA->jointCount += 1;
189
+
190
+ // Doubly linked list on bodyB
191
+ joint->edges[1].bodyId = bodyIdB;
192
+ joint->edges[1].prevKey = B2_NULL_INDEX;
193
+ joint->edges[1].nextKey = bodyB->headJointKey;
194
+
195
+ int keyB = ( jointId << 1 ) | 1;
196
+ if ( bodyB->headJointKey != B2_NULL_INDEX )
197
+ {
198
+ b2Joint* jointB = b2JointArray_Get( &world->joints, bodyB->headJointKey >> 1 );
199
+ b2JointEdge* edgeB = jointB->edges + ( bodyB->headJointKey & 1 );
200
+ edgeB->prevKey = keyB;
201
+ }
202
+ bodyB->headJointKey = keyB;
203
+ bodyB->jointCount += 1;
204
+
205
+ b2JointSim* jointSim;
206
+
207
+ if ( bodyA->setIndex == b2_disabledSet || bodyB->setIndex == b2_disabledSet )
208
+ {
209
+ // if either body is disabled, create in disabled set
210
+ b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, b2_disabledSet );
211
+ joint->setIndex = b2_disabledSet;
212
+ joint->localIndex = set->jointSims.count;
213
+
214
+ jointSim = b2JointSimArray_Add( &set->jointSims );
215
+ memset( jointSim, 0, sizeof( b2JointSim ) );
216
+
217
+ jointSim->jointId = jointId;
218
+ jointSim->bodyIdA = bodyIdA;
219
+ jointSim->bodyIdB = bodyIdB;
220
+ }
221
+ else if ( bodyA->setIndex == b2_staticSet && bodyB->setIndex == b2_staticSet )
222
+ {
223
+ // joint is connecting static bodies
224
+ b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, b2_staticSet );
225
+ joint->setIndex = b2_staticSet;
226
+ joint->localIndex = set->jointSims.count;
227
+
228
+ jointSim = b2JointSimArray_Add( &set->jointSims );
229
+ memset( jointSim, 0, sizeof( b2JointSim ) );
230
+
231
+ jointSim->jointId = jointId;
232
+ jointSim->bodyIdA = bodyIdA;
233
+ jointSim->bodyIdB = bodyIdB;
234
+ }
235
+ else if ( bodyA->setIndex == b2_awakeSet || bodyB->setIndex == b2_awakeSet )
236
+ {
237
+ // if either body is sleeping, wake it
238
+ if ( maxSetIndex >= b2_firstSleepingSet )
239
+ {
240
+ b2WakeSolverSet( world, maxSetIndex );
241
+ }
242
+
243
+ joint->setIndex = b2_awakeSet;
244
+
245
+ jointSim = b2CreateJointInGraph( world, joint );
246
+ jointSim->jointId = jointId;
247
+ jointSim->bodyIdA = bodyIdA;
248
+ jointSim->bodyIdB = bodyIdB;
249
+ }
250
+ else
251
+ {
252
+ // joint connected between sleeping and/or static bodies
253
+ B2_ASSERT( bodyA->setIndex >= b2_firstSleepingSet || bodyB->setIndex >= b2_firstSleepingSet );
254
+ B2_ASSERT( bodyA->setIndex != b2_staticSet || bodyB->setIndex != b2_staticSet );
255
+
256
+ // joint should go into the sleeping set (not static set)
257
+ int setIndex = maxSetIndex;
258
+
259
+ b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, setIndex );
260
+ joint->setIndex = setIndex;
261
+ joint->localIndex = set->jointSims.count;
262
+
263
+ jointSim = b2JointSimArray_Add( &set->jointSims );
264
+ memset( jointSim, 0, sizeof( b2JointSim ) );
265
+
266
+ jointSim->jointId = jointId;
267
+ jointSim->bodyIdA = bodyIdA;
268
+ jointSim->bodyIdB = bodyIdB;
269
+
270
+ if ( bodyA->setIndex != bodyB->setIndex && bodyA->setIndex >= b2_firstSleepingSet &&
271
+ bodyB->setIndex >= b2_firstSleepingSet )
272
+ {
273
+ // merge sleeping sets
274
+ b2MergeSolverSets( world, bodyA->setIndex, bodyB->setIndex );
275
+ B2_ASSERT( bodyA->setIndex == bodyB->setIndex );
276
+
277
+ // fix potentially invalid set index
278
+ setIndex = bodyA->setIndex;
279
+
280
+ b2SolverSet* mergedSet = b2SolverSetArray_Get( &world->solverSets, setIndex );
281
+
282
+ // Careful! The joint sim pointer was orphaned by the set merge.
283
+ jointSim = b2JointSimArray_Get( &mergedSet->jointSims, joint->localIndex );
284
+ }
285
+
286
+ B2_ASSERT( joint->setIndex == setIndex );
287
+ }
288
+
289
+ B2_ASSERT( jointSim->jointId == jointId );
290
+ B2_ASSERT( jointSim->bodyIdA == bodyIdA );
291
+ B2_ASSERT( jointSim->bodyIdB == bodyIdB );
292
+
293
+ if ( joint->setIndex > b2_disabledSet )
294
+ {
295
+ // Add edge to island graph
296
+ bool mergeIslands = true;
297
+ b2LinkJoint( world, joint, mergeIslands );
298
+ }
299
+
300
+ b2ValidateSolverSets( world );
301
+
302
+ return (b2JointPair){ joint, jointSim };
303
+ }
304
+
305
+ static void b2DestroyContactsBetweenBodies( b2World* world, b2Body* bodyA, b2Body* bodyB )
306
+ {
307
+ int contactKey;
308
+ int otherBodyId;
309
+
310
+ // use the smaller of the two contact lists
311
+ if ( bodyA->contactCount < bodyB->contactCount )
312
+ {
313
+ contactKey = bodyA->headContactKey;
314
+ otherBodyId = bodyB->id;
315
+ }
316
+ else
317
+ {
318
+ contactKey = bodyB->headContactKey;
319
+ otherBodyId = bodyA->id;
320
+ }
321
+
322
+ // no need to wake bodies when a joint removes collision between them
323
+ bool wakeBodies = false;
324
+
325
+ // destroy the contacts
326
+ while ( contactKey != B2_NULL_INDEX )
327
+ {
328
+ int contactId = contactKey >> 1;
329
+ int edgeIndex = contactKey & 1;
330
+
331
+ b2Contact* contact = b2ContactArray_Get( &world->contacts, contactId );
332
+ contactKey = contact->edges[edgeIndex].nextKey;
333
+
334
+ int otherEdgeIndex = edgeIndex ^ 1;
335
+ if ( contact->edges[otherEdgeIndex].bodyId == otherBodyId )
336
+ {
337
+ // Careful, this removes the contact from the current doubly linked list
338
+ b2DestroyContact( world, contact, wakeBodies );
339
+ }
340
+ }
341
+
342
+ b2ValidateSolverSets( world );
343
+ }
344
+
345
+ b2JointId b2CreateDistanceJoint( b2WorldId worldId, const b2DistanceJointDef* def )
346
+ {
347
+ B2_CHECK_DEF( def );
348
+ b2World* world = b2GetWorldFromId( worldId );
349
+
350
+ B2_ASSERT( world->locked == false );
351
+
352
+ if ( world->locked )
353
+ {
354
+ return (b2JointId){ 0 };
355
+ }
356
+
357
+ B2_ASSERT( b2Body_IsValid( def->bodyIdA ) );
358
+ B2_ASSERT( b2Body_IsValid( def->bodyIdB ) );
359
+ B2_ASSERT( b2IsValidFloat( def->length ) && def->length > 0.0f );
360
+
361
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
362
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
363
+
364
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_distanceJoint, def->collideConnected );
365
+
366
+ b2JointSim* joint = pair.jointSim;
367
+ joint->type = b2_distanceJoint;
368
+ joint->localOriginAnchorA = def->localAnchorA;
369
+ joint->localOriginAnchorB = def->localAnchorB;
370
+
371
+ b2DistanceJoint empty = { 0 };
372
+ joint->distanceJoint = empty;
373
+ joint->distanceJoint.length = b2MaxFloat( def->length, B2_LINEAR_SLOP );
374
+ joint->distanceJoint.hertz = def->hertz;
375
+ joint->distanceJoint.dampingRatio = def->dampingRatio;
376
+ joint->distanceJoint.minLength = b2MaxFloat( def->minLength, B2_LINEAR_SLOP );
377
+ joint->distanceJoint.maxLength = b2MaxFloat( def->minLength, def->maxLength );
378
+ joint->distanceJoint.maxMotorForce = def->maxMotorForce;
379
+ joint->distanceJoint.motorSpeed = def->motorSpeed;
380
+ joint->distanceJoint.enableSpring = def->enableSpring;
381
+ joint->distanceJoint.enableLimit = def->enableLimit;
382
+ joint->distanceJoint.enableMotor = def->enableMotor;
383
+ joint->distanceJoint.impulse = 0.0f;
384
+ joint->distanceJoint.lowerImpulse = 0.0f;
385
+ joint->distanceJoint.upperImpulse = 0.0f;
386
+ joint->distanceJoint.motorImpulse = 0.0f;
387
+
388
+ // If the joint prevents collisions, then destroy all contacts between attached bodies
389
+ if ( def->collideConnected == false )
390
+ {
391
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
392
+ }
393
+
394
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
395
+ return jointId;
396
+ }
397
+
398
+ b2JointId b2CreateMotorJoint( b2WorldId worldId, const b2MotorJointDef* def )
399
+ {
400
+ B2_CHECK_DEF( def );
401
+ b2World* world = b2GetWorldFromId( worldId );
402
+
403
+ B2_ASSERT( world->locked == false );
404
+
405
+ if ( world->locked )
406
+ {
407
+ return (b2JointId){ 0 };
408
+ }
409
+
410
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
411
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
412
+
413
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_motorJoint, def->collideConnected );
414
+ b2JointSim* joint = pair.jointSim;
415
+
416
+ joint->type = b2_motorJoint;
417
+ joint->localOriginAnchorA = (b2Vec2){ 0.0f, 0.0f };
418
+ joint->localOriginAnchorB = (b2Vec2){ 0.0f, 0.0f };
419
+ joint->motorJoint = (b2MotorJoint){ 0 };
420
+ joint->motorJoint.linearOffset = def->linearOffset;
421
+ joint->motorJoint.angularOffset = def->angularOffset;
422
+ joint->motorJoint.maxForce = def->maxForce;
423
+ joint->motorJoint.maxTorque = def->maxTorque;
424
+ joint->motorJoint.correctionFactor = b2ClampFloat( def->correctionFactor, 0.0f, 1.0f );
425
+
426
+ // If the joint prevents collisions, then destroy all contacts between attached bodies
427
+ if ( def->collideConnected == false )
428
+ {
429
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
430
+ }
431
+
432
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
433
+ return jointId;
434
+ }
435
+
436
+ b2JointId b2CreateMouseJoint( b2WorldId worldId, const b2MouseJointDef* def )
437
+ {
438
+ B2_CHECK_DEF( def );
439
+ b2World* world = b2GetWorldFromId( worldId );
440
+
441
+ B2_ASSERT( world->locked == false );
442
+
443
+ if ( world->locked )
444
+ {
445
+ return (b2JointId){ 0 };
446
+ }
447
+
448
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
449
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
450
+
451
+ b2Transform transformA = b2GetBodyTransformQuick( world, bodyA );
452
+ b2Transform transformB = b2GetBodyTransformQuick( world, bodyB );
453
+
454
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_mouseJoint, def->collideConnected );
455
+
456
+ b2JointSim* joint = pair.jointSim;
457
+ joint->type = b2_mouseJoint;
458
+ joint->localOriginAnchorA = b2InvTransformPoint( transformA, def->target );
459
+ joint->localOriginAnchorB = b2InvTransformPoint( transformB, def->target );
460
+
461
+ b2MouseJoint empty = { 0 };
462
+ joint->mouseJoint = empty;
463
+ joint->mouseJoint.targetA = def->target;
464
+ joint->mouseJoint.hertz = def->hertz;
465
+ joint->mouseJoint.dampingRatio = def->dampingRatio;
466
+ joint->mouseJoint.maxForce = def->maxForce;
467
+
468
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
469
+ return jointId;
470
+ }
471
+
472
+ b2JointId b2CreateFilterJoint( b2WorldId worldId, const b2FilterJointDef* def )
473
+ {
474
+ B2_CHECK_DEF( def );
475
+ b2World* world = b2GetWorldFromId( worldId );
476
+
477
+ B2_ASSERT( world->locked == false );
478
+
479
+ if ( world->locked )
480
+ {
481
+ return (b2JointId){ 0 };
482
+ }
483
+
484
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
485
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
486
+
487
+ bool collideConnected = false;
488
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_filterJoint, collideConnected );
489
+
490
+ b2JointSim* joint = pair.jointSim;
491
+ joint->type = b2_filterJoint;
492
+ joint->localOriginAnchorA = b2Vec2_zero;
493
+ joint->localOriginAnchorB = b2Vec2_zero;
494
+
495
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
496
+ return jointId;
497
+ }
498
+
499
+ b2JointId b2CreateRevoluteJoint( b2WorldId worldId, const b2RevoluteJointDef* def )
500
+ {
501
+ B2_CHECK_DEF( def );
502
+ B2_ASSERT( def->lowerAngle <= def->upperAngle );
503
+ B2_ASSERT( def->lowerAngle >= -0.95f * B2_PI );
504
+ B2_ASSERT( def->upperAngle <= 0.95f * B2_PI );
505
+
506
+ b2World* world = b2GetWorldFromId( worldId );
507
+
508
+ B2_ASSERT( world->locked == false );
509
+
510
+ if ( world->locked )
511
+ {
512
+ return (b2JointId){ 0 };
513
+ }
514
+
515
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
516
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
517
+
518
+ b2JointPair pair =
519
+ b2CreateJoint( world, bodyA, bodyB, def->userData, def->drawSize, b2_revoluteJoint, def->collideConnected );
520
+
521
+ b2JointSim* joint = pair.jointSim;
522
+ joint->type = b2_revoluteJoint;
523
+ joint->localOriginAnchorA = def->localAnchorA;
524
+ joint->localOriginAnchorB = def->localAnchorB;
525
+
526
+ b2RevoluteJoint empty = { 0 };
527
+ joint->revoluteJoint = empty;
528
+
529
+ joint->revoluteJoint.referenceAngle = b2ClampFloat( def->referenceAngle, -B2_PI, B2_PI );
530
+ joint->revoluteJoint.linearImpulse = b2Vec2_zero;
531
+ joint->revoluteJoint.axialMass = 0.0f;
532
+ joint->revoluteJoint.springImpulse = 0.0f;
533
+ joint->revoluteJoint.motorImpulse = 0.0f;
534
+ joint->revoluteJoint.lowerImpulse = 0.0f;
535
+ joint->revoluteJoint.upperImpulse = 0.0f;
536
+ joint->revoluteJoint.hertz = def->hertz;
537
+ joint->revoluteJoint.dampingRatio = def->dampingRatio;
538
+ joint->revoluteJoint.lowerAngle = def->lowerAngle;
539
+ joint->revoluteJoint.upperAngle = def->upperAngle;
540
+ joint->revoluteJoint.maxMotorTorque = def->maxMotorTorque;
541
+ joint->revoluteJoint.motorSpeed = def->motorSpeed;
542
+ joint->revoluteJoint.enableSpring = def->enableSpring;
543
+ joint->revoluteJoint.enableLimit = def->enableLimit;
544
+ joint->revoluteJoint.enableMotor = def->enableMotor;
545
+
546
+ // If the joint prevents collisions, then destroy all contacts between attached bodies
547
+ if ( def->collideConnected == false )
548
+ {
549
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
550
+ }
551
+
552
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
553
+ return jointId;
554
+ }
555
+
556
+ b2JointId b2CreatePrismaticJoint( b2WorldId worldId, const b2PrismaticJointDef* def )
557
+ {
558
+ B2_CHECK_DEF( def );
559
+ B2_ASSERT( def->lowerTranslation <= def->upperTranslation );
560
+
561
+ b2World* world = b2GetWorldFromId( worldId );
562
+
563
+ B2_ASSERT( world->locked == false );
564
+
565
+ if ( world->locked )
566
+ {
567
+ return (b2JointId){ 0 };
568
+ }
569
+
570
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
571
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
572
+
573
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_prismaticJoint, def->collideConnected );
574
+
575
+ b2JointSim* joint = pair.jointSim;
576
+ joint->type = b2_prismaticJoint;
577
+ joint->localOriginAnchorA = def->localAnchorA;
578
+ joint->localOriginAnchorB = def->localAnchorB;
579
+
580
+ b2PrismaticJoint empty = { 0 };
581
+ joint->prismaticJoint = empty;
582
+
583
+ joint->prismaticJoint.localAxisA = b2Normalize( def->localAxisA );
584
+ joint->prismaticJoint.referenceAngle = def->referenceAngle;
585
+ joint->prismaticJoint.impulse = b2Vec2_zero;
586
+ joint->prismaticJoint.axialMass = 0.0f;
587
+ joint->prismaticJoint.springImpulse = 0.0f;
588
+ joint->prismaticJoint.motorImpulse = 0.0f;
589
+ joint->prismaticJoint.lowerImpulse = 0.0f;
590
+ joint->prismaticJoint.upperImpulse = 0.0f;
591
+ joint->prismaticJoint.hertz = def->hertz;
592
+ joint->prismaticJoint.dampingRatio = def->dampingRatio;
593
+ joint->prismaticJoint.lowerTranslation = def->lowerTranslation;
594
+ joint->prismaticJoint.upperTranslation = def->upperTranslation;
595
+ joint->prismaticJoint.maxMotorForce = def->maxMotorForce;
596
+ joint->prismaticJoint.motorSpeed = def->motorSpeed;
597
+ joint->prismaticJoint.enableSpring = def->enableSpring;
598
+ joint->prismaticJoint.enableLimit = def->enableLimit;
599
+ joint->prismaticJoint.enableMotor = def->enableMotor;
600
+
601
+ // If the joint prevents collisions, then destroy all contacts between attached bodies
602
+ if ( def->collideConnected == false )
603
+ {
604
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
605
+ }
606
+
607
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
608
+ return jointId;
609
+ }
610
+
611
+ b2JointId b2CreateWeldJoint( b2WorldId worldId, const b2WeldJointDef* def )
612
+ {
613
+ B2_CHECK_DEF( def );
614
+ b2World* world = b2GetWorldFromId( worldId );
615
+
616
+ B2_ASSERT( world->locked == false );
617
+
618
+ if ( world->locked )
619
+ {
620
+ return (b2JointId){ 0 };
621
+ }
622
+
623
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
624
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
625
+
626
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_weldJoint, def->collideConnected );
627
+
628
+ b2JointSim* joint = pair.jointSim;
629
+ joint->type = b2_weldJoint;
630
+ joint->localOriginAnchorA = def->localAnchorA;
631
+ joint->localOriginAnchorB = def->localAnchorB;
632
+
633
+ b2WeldJoint empty = { 0 };
634
+ joint->weldJoint = empty;
635
+ joint->weldJoint.referenceAngle = def->referenceAngle;
636
+ joint->weldJoint.linearHertz = def->linearHertz;
637
+ joint->weldJoint.linearDampingRatio = def->linearDampingRatio;
638
+ joint->weldJoint.angularHertz = def->angularHertz;
639
+ joint->weldJoint.angularDampingRatio = def->angularDampingRatio;
640
+ joint->weldJoint.linearImpulse = b2Vec2_zero;
641
+ joint->weldJoint.angularImpulse = 0.0f;
642
+
643
+ // If the joint prevents collisions, then destroy all contacts between attached bodies
644
+ if ( def->collideConnected == false )
645
+ {
646
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
647
+ }
648
+
649
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
650
+ return jointId;
651
+ }
652
+
653
+ b2JointId b2CreateWheelJoint( b2WorldId worldId, const b2WheelJointDef* def )
654
+ {
655
+ B2_CHECK_DEF( def );
656
+ B2_ASSERT( def->lowerTranslation <= def->upperTranslation );
657
+
658
+ b2World* world = b2GetWorldFromId( worldId );
659
+
660
+ B2_ASSERT( world->locked == false );
661
+
662
+ if ( world->locked )
663
+ {
664
+ return (b2JointId){ 0 };
665
+ }
666
+
667
+ b2Body* bodyA = b2GetBodyFullId( world, def->bodyIdA );
668
+ b2Body* bodyB = b2GetBodyFullId( world, def->bodyIdB );
669
+
670
+ b2JointPair pair = b2CreateJoint( world, bodyA, bodyB, def->userData, 1.0f, b2_wheelJoint, def->collideConnected );
671
+
672
+ b2JointSim* joint = pair.jointSim;
673
+ joint->type = b2_wheelJoint;
674
+ joint->localOriginAnchorA = def->localAnchorA;
675
+ joint->localOriginAnchorB = def->localAnchorB;
676
+
677
+ joint->wheelJoint = (b2WheelJoint){ 0 };
678
+ joint->wheelJoint.localAxisA = b2Normalize( def->localAxisA );
679
+ joint->wheelJoint.perpMass = 0.0f;
680
+ joint->wheelJoint.axialMass = 0.0f;
681
+ joint->wheelJoint.motorImpulse = 0.0f;
682
+ joint->wheelJoint.lowerImpulse = 0.0f;
683
+ joint->wheelJoint.upperImpulse = 0.0f;
684
+ joint->wheelJoint.lowerTranslation = def->lowerTranslation;
685
+ joint->wheelJoint.upperTranslation = def->upperTranslation;
686
+ joint->wheelJoint.maxMotorTorque = def->maxMotorTorque;
687
+ joint->wheelJoint.motorSpeed = def->motorSpeed;
688
+ joint->wheelJoint.hertz = def->hertz;
689
+ joint->wheelJoint.dampingRatio = def->dampingRatio;
690
+ joint->wheelJoint.enableSpring = def->enableSpring;
691
+ joint->wheelJoint.enableLimit = def->enableLimit;
692
+ joint->wheelJoint.enableMotor = def->enableMotor;
693
+
694
+ // If the joint prevents collisions, then destroy all contacts between attached bodies
695
+ if ( def->collideConnected == false )
696
+ {
697
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
698
+ }
699
+
700
+ b2JointId jointId = { joint->jointId + 1, world->worldId, pair.joint->generation };
701
+ return jointId;
702
+ }
703
+
704
+ void b2DestroyJointInternal( b2World* world, b2Joint* joint, bool wakeBodies )
705
+ {
706
+ int jointId = joint->jointId;
707
+
708
+ b2JointEdge* edgeA = joint->edges + 0;
709
+ b2JointEdge* edgeB = joint->edges + 1;
710
+
711
+ int idA = edgeA->bodyId;
712
+ int idB = edgeB->bodyId;
713
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, idA );
714
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, idB );
715
+
716
+ // Remove from body A
717
+ if ( edgeA->prevKey != B2_NULL_INDEX )
718
+ {
719
+ b2Joint* prevJoint = b2JointArray_Get( &world->joints, edgeA->prevKey >> 1 );
720
+ b2JointEdge* prevEdge = prevJoint->edges + ( edgeA->prevKey & 1 );
721
+ prevEdge->nextKey = edgeA->nextKey;
722
+ }
723
+
724
+ if ( edgeA->nextKey != B2_NULL_INDEX )
725
+ {
726
+ b2Joint* nextJoint = b2JointArray_Get( &world->joints, edgeA->nextKey >> 1 );
727
+ b2JointEdge* nextEdge = nextJoint->edges + ( edgeA->nextKey & 1 );
728
+ nextEdge->prevKey = edgeA->prevKey;
729
+ }
730
+
731
+ int edgeKeyA = ( jointId << 1 ) | 0;
732
+ if ( bodyA->headJointKey == edgeKeyA )
733
+ {
734
+ bodyA->headJointKey = edgeA->nextKey;
735
+ }
736
+
737
+ bodyA->jointCount -= 1;
738
+
739
+ // Remove from body B
740
+ if ( edgeB->prevKey != B2_NULL_INDEX )
741
+ {
742
+ b2Joint* prevJoint = b2JointArray_Get( &world->joints, edgeB->prevKey >> 1 );
743
+ b2JointEdge* prevEdge = prevJoint->edges + ( edgeB->prevKey & 1 );
744
+ prevEdge->nextKey = edgeB->nextKey;
745
+ }
746
+
747
+ if ( edgeB->nextKey != B2_NULL_INDEX )
748
+ {
749
+ b2Joint* nextJoint = b2JointArray_Get( &world->joints, edgeB->nextKey >> 1 );
750
+ b2JointEdge* nextEdge = nextJoint->edges + ( edgeB->nextKey & 1 );
751
+ nextEdge->prevKey = edgeB->prevKey;
752
+ }
753
+
754
+ int edgeKeyB = ( jointId << 1 ) | 1;
755
+ if ( bodyB->headJointKey == edgeKeyB )
756
+ {
757
+ bodyB->headJointKey = edgeB->nextKey;
758
+ }
759
+
760
+ bodyB->jointCount -= 1;
761
+
762
+ if ( joint->islandId != B2_NULL_INDEX )
763
+ {
764
+ B2_ASSERT( joint->setIndex > b2_disabledSet );
765
+ b2UnlinkJoint( world, joint );
766
+ }
767
+ else
768
+ {
769
+ B2_ASSERT( joint->setIndex <= b2_disabledSet );
770
+ }
771
+
772
+ // Remove joint from solver set that owns it
773
+ int setIndex = joint->setIndex;
774
+ int localIndex = joint->localIndex;
775
+
776
+ if ( setIndex == b2_awakeSet )
777
+ {
778
+ b2RemoveJointFromGraph( world, joint->edges[0].bodyId, joint->edges[1].bodyId, joint->colorIndex, localIndex );
779
+ }
780
+ else
781
+ {
782
+ b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, setIndex );
783
+ int movedIndex = b2JointSimArray_RemoveSwap( &set->jointSims, localIndex );
784
+ if ( movedIndex != B2_NULL_INDEX )
785
+ {
786
+ // Fix moved joint
787
+ b2JointSim* movedJointSim = set->jointSims.data + localIndex;
788
+ int movedId = movedJointSim->jointId;
789
+ b2Joint* movedJoint = b2JointArray_Get( &world->joints, movedId );
790
+ B2_ASSERT( movedJoint->localIndex == movedIndex );
791
+ movedJoint->localIndex = localIndex;
792
+ }
793
+ }
794
+
795
+ // Free joint and id (preserve joint generation)
796
+ joint->setIndex = B2_NULL_INDEX;
797
+ joint->localIndex = B2_NULL_INDEX;
798
+ joint->colorIndex = B2_NULL_INDEX;
799
+ joint->jointId = B2_NULL_INDEX;
800
+ b2FreeId( &world->jointIdPool, jointId );
801
+
802
+ if ( wakeBodies )
803
+ {
804
+ b2WakeBody( world, bodyA );
805
+ b2WakeBody( world, bodyB );
806
+ }
807
+
808
+ b2ValidateSolverSets( world );
809
+ }
810
+
811
+ void b2DestroyJoint( b2JointId jointId )
812
+ {
813
+ b2World* world = b2GetWorld( jointId.world0 );
814
+ B2_ASSERT( world->locked == false );
815
+
816
+ if ( world->locked )
817
+ {
818
+ return;
819
+ }
820
+
821
+ b2Joint* joint = b2GetJointFullId( world, jointId );
822
+
823
+ b2DestroyJointInternal( world, joint, true );
824
+ }
825
+
826
+ b2JointType b2Joint_GetType( b2JointId jointId )
827
+ {
828
+ b2World* world = b2GetWorld( jointId.world0 );
829
+ b2Joint* joint = b2GetJointFullId( world, jointId );
830
+ return joint->type;
831
+ }
832
+
833
+ b2BodyId b2Joint_GetBodyA( b2JointId jointId )
834
+ {
835
+ b2World* world = b2GetWorld( jointId.world0 );
836
+ b2Joint* joint = b2GetJointFullId( world, jointId );
837
+ return b2MakeBodyId( world, joint->edges[0].bodyId );
838
+ }
839
+
840
+ b2BodyId b2Joint_GetBodyB( b2JointId jointId )
841
+ {
842
+ b2World* world = b2GetWorld( jointId.world0 );
843
+ b2Joint* joint = b2GetJointFullId( world, jointId );
844
+ return b2MakeBodyId( world, joint->edges[1].bodyId );
845
+ }
846
+
847
+ b2WorldId b2Joint_GetWorld( b2JointId jointId )
848
+ {
849
+ b2World* world = b2GetWorld( jointId.world0 );
850
+ return (b2WorldId){ jointId.world0 + 1, world->generation };
851
+ }
852
+
853
+ b2Vec2 b2Joint_GetLocalAnchorA( b2JointId jointId )
854
+ {
855
+ b2World* world = b2GetWorld( jointId.world0 );
856
+ b2Joint* joint = b2GetJointFullId( world, jointId );
857
+ b2JointSim* jointSim = b2GetJointSim( world, joint );
858
+ return jointSim->localOriginAnchorA;
859
+ }
860
+
861
+ b2Vec2 b2Joint_GetLocalAnchorB( b2JointId jointId )
862
+ {
863
+ b2World* world = b2GetWorld( jointId.world0 );
864
+ b2Joint* joint = b2GetJointFullId( world, jointId );
865
+ b2JointSim* jointSim = b2GetJointSim( world, joint );
866
+ return jointSim->localOriginAnchorB;
867
+ }
868
+
869
+ void b2Joint_SetCollideConnected( b2JointId jointId, bool shouldCollide )
870
+ {
871
+ b2World* world = b2GetWorldLocked( jointId.world0 );
872
+ if ( world == NULL )
873
+ {
874
+ return;
875
+ }
876
+
877
+ b2Joint* joint = b2GetJointFullId( world, jointId );
878
+ if ( joint->collideConnected == shouldCollide )
879
+ {
880
+ return;
881
+ }
882
+
883
+ joint->collideConnected = shouldCollide;
884
+
885
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, joint->edges[0].bodyId );
886
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, joint->edges[1].bodyId );
887
+
888
+ if ( shouldCollide )
889
+ {
890
+ // need to tell the broad-phase to look for new pairs for one of the
891
+ // two bodies. Pick the one with the fewest shapes.
892
+ int shapeCountA = bodyA->shapeCount;
893
+ int shapeCountB = bodyB->shapeCount;
894
+
895
+ int shapeId = shapeCountA < shapeCountB ? bodyA->headShapeId : bodyB->headShapeId;
896
+ while ( shapeId != B2_NULL_INDEX )
897
+ {
898
+ b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
899
+
900
+ if ( shape->proxyKey != B2_NULL_INDEX )
901
+ {
902
+ b2BufferMove( &world->broadPhase, shape->proxyKey );
903
+ }
904
+
905
+ shapeId = shape->nextShapeId;
906
+ }
907
+ }
908
+ else
909
+ {
910
+ b2DestroyContactsBetweenBodies( world, bodyA, bodyB );
911
+ }
912
+ }
913
+
914
+ bool b2Joint_GetCollideConnected( b2JointId jointId )
915
+ {
916
+ b2World* world = b2GetWorld( jointId.world0 );
917
+ b2Joint* joint = b2GetJointFullId( world, jointId );
918
+ return joint->collideConnected;
919
+ }
920
+
921
+ void b2Joint_SetUserData( b2JointId jointId, void* userData )
922
+ {
923
+ b2World* world = b2GetWorld( jointId.world0 );
924
+ b2Joint* joint = b2GetJointFullId( world, jointId );
925
+ joint->userData = userData;
926
+ }
927
+
928
+ void* b2Joint_GetUserData( b2JointId jointId )
929
+ {
930
+ b2World* world = b2GetWorld( jointId.world0 );
931
+ b2Joint* joint = b2GetJointFullId( world, jointId );
932
+ return joint->userData;
933
+ }
934
+
935
+ void b2Joint_WakeBodies( b2JointId jointId )
936
+ {
937
+ b2World* world = b2GetWorldLocked( jointId.world0 );
938
+ if ( world == NULL )
939
+ {
940
+ return;
941
+ }
942
+
943
+ b2Joint* joint = b2GetJointFullId( world, jointId );
944
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, joint->edges[0].bodyId );
945
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, joint->edges[1].bodyId );
946
+
947
+ b2WakeBody( world, bodyA );
948
+ b2WakeBody( world, bodyB );
949
+ }
950
+
951
+ b2Vec2 b2Joint_GetConstraintForce( b2JointId jointId )
952
+ {
953
+ b2World* world = b2GetWorld( jointId.world0 );
954
+ b2Joint* joint = b2GetJointFullId( world, jointId );
955
+ b2JointSim* base = b2GetJointSim( world, joint );
956
+
957
+ switch ( joint->type )
958
+ {
959
+ case b2_distanceJoint:
960
+ return b2GetDistanceJointForce( world, base );
961
+
962
+ case b2_motorJoint:
963
+ return b2GetMotorJointForce( world, base );
964
+
965
+ case b2_mouseJoint:
966
+ return b2GetMouseJointForce( world, base );
967
+
968
+ case b2_filterJoint:
969
+ return b2Vec2_zero;
970
+
971
+ case b2_prismaticJoint:
972
+ return b2GetPrismaticJointForce( world, base );
973
+
974
+ case b2_revoluteJoint:
975
+ return b2GetRevoluteJointForce( world, base );
976
+
977
+ case b2_weldJoint:
978
+ return b2GetWeldJointForce( world, base );
979
+
980
+ case b2_wheelJoint:
981
+ return b2GetWheelJointForce( world, base );
982
+
983
+ default:
984
+ B2_ASSERT( false );
985
+ return b2Vec2_zero;
986
+ }
987
+ }
988
+
989
+ float b2Joint_GetConstraintTorque( b2JointId jointId )
990
+ {
991
+ b2World* world = b2GetWorld( jointId.world0 );
992
+ b2Joint* joint = b2GetJointFullId( world, jointId );
993
+ b2JointSim* base = b2GetJointSim( world, joint );
994
+
995
+ switch ( joint->type )
996
+ {
997
+ case b2_distanceJoint:
998
+ return 0.0f;
999
+
1000
+ case b2_motorJoint:
1001
+ return b2GetMotorJointTorque( world, base );
1002
+
1003
+ case b2_mouseJoint:
1004
+ return b2GetMouseJointTorque( world, base );
1005
+
1006
+ case b2_filterJoint:
1007
+ return 0.0f;
1008
+
1009
+ case b2_prismaticJoint:
1010
+ return b2GetPrismaticJointTorque( world, base );
1011
+
1012
+ case b2_revoluteJoint:
1013
+ return b2GetRevoluteJointTorque( world, base );
1014
+
1015
+ case b2_weldJoint:
1016
+ return b2GetWeldJointTorque( world, base );
1017
+
1018
+ case b2_wheelJoint:
1019
+ return b2GetWheelJointTorque( world, base );
1020
+
1021
+ default:
1022
+ B2_ASSERT( false );
1023
+ return 0.0f;
1024
+ }
1025
+ }
1026
+
1027
+ void b2PrepareJoint( b2JointSim* joint, b2StepContext* context )
1028
+ {
1029
+ switch ( joint->type )
1030
+ {
1031
+ case b2_distanceJoint:
1032
+ b2PrepareDistanceJoint( joint, context );
1033
+ break;
1034
+
1035
+ case b2_motorJoint:
1036
+ b2PrepareMotorJoint( joint, context );
1037
+ break;
1038
+
1039
+ case b2_mouseJoint:
1040
+ b2PrepareMouseJoint( joint, context );
1041
+ break;
1042
+
1043
+ case b2_filterJoint:
1044
+ break;
1045
+
1046
+ case b2_prismaticJoint:
1047
+ b2PreparePrismaticJoint( joint, context );
1048
+ break;
1049
+
1050
+ case b2_revoluteJoint:
1051
+ b2PrepareRevoluteJoint( joint, context );
1052
+ break;
1053
+
1054
+ case b2_weldJoint:
1055
+ b2PrepareWeldJoint( joint, context );
1056
+ break;
1057
+
1058
+ case b2_wheelJoint:
1059
+ b2PrepareWheelJoint( joint, context );
1060
+ break;
1061
+
1062
+ default:
1063
+ B2_ASSERT( false );
1064
+ }
1065
+ }
1066
+
1067
+ void b2WarmStartJoint( b2JointSim* joint, b2StepContext* context )
1068
+ {
1069
+ switch ( joint->type )
1070
+ {
1071
+ case b2_distanceJoint:
1072
+ b2WarmStartDistanceJoint( joint, context );
1073
+ break;
1074
+
1075
+ case b2_motorJoint:
1076
+ b2WarmStartMotorJoint( joint, context );
1077
+ break;
1078
+
1079
+ case b2_mouseJoint:
1080
+ b2WarmStartMouseJoint( joint, context );
1081
+ break;
1082
+
1083
+ case b2_filterJoint:
1084
+ break;
1085
+
1086
+ case b2_prismaticJoint:
1087
+ b2WarmStartPrismaticJoint( joint, context );
1088
+ break;
1089
+
1090
+ case b2_revoluteJoint:
1091
+ b2WarmStartRevoluteJoint( joint, context );
1092
+ break;
1093
+
1094
+ case b2_weldJoint:
1095
+ b2WarmStartWeldJoint( joint, context );
1096
+ break;
1097
+
1098
+ case b2_wheelJoint:
1099
+ b2WarmStartWheelJoint( joint, context );
1100
+ break;
1101
+
1102
+ default:
1103
+ B2_ASSERT( false );
1104
+ }
1105
+ }
1106
+
1107
+ void b2SolveJoint( b2JointSim* joint, b2StepContext* context, bool useBias )
1108
+ {
1109
+ switch ( joint->type )
1110
+ {
1111
+ case b2_distanceJoint:
1112
+ b2SolveDistanceJoint( joint, context, useBias );
1113
+ break;
1114
+
1115
+ case b2_motorJoint:
1116
+ b2SolveMotorJoint( joint, context, useBias );
1117
+ break;
1118
+
1119
+ case b2_mouseJoint:
1120
+ b2SolveMouseJoint( joint, context );
1121
+ break;
1122
+
1123
+ case b2_filterJoint:
1124
+ break;
1125
+
1126
+ case b2_prismaticJoint:
1127
+ b2SolvePrismaticJoint( joint, context, useBias );
1128
+ break;
1129
+
1130
+ case b2_revoluteJoint:
1131
+ b2SolveRevoluteJoint( joint, context, useBias );
1132
+ break;
1133
+
1134
+ case b2_weldJoint:
1135
+ b2SolveWeldJoint( joint, context, useBias );
1136
+ break;
1137
+
1138
+ case b2_wheelJoint:
1139
+ b2SolveWheelJoint( joint, context, useBias );
1140
+ break;
1141
+
1142
+ default:
1143
+ B2_ASSERT( false );
1144
+ }
1145
+ }
1146
+
1147
+ void b2PrepareOverflowJoints( b2StepContext* context )
1148
+ {
1149
+ b2TracyCZoneNC( prepare_joints, "PrepJoints", b2_colorOldLace, true );
1150
+
1151
+ b2ConstraintGraph* graph = context->graph;
1152
+ b2JointSim* joints = graph->colors[B2_OVERFLOW_INDEX].jointSims.data;
1153
+ int jointCount = graph->colors[B2_OVERFLOW_INDEX].jointSims.count;
1154
+
1155
+ for ( int i = 0; i < jointCount; ++i )
1156
+ {
1157
+ b2JointSim* joint = joints + i;
1158
+ b2PrepareJoint( joint, context );
1159
+ }
1160
+
1161
+ b2TracyCZoneEnd( prepare_joints );
1162
+ }
1163
+
1164
+ void b2WarmStartOverflowJoints( b2StepContext* context )
1165
+ {
1166
+ b2TracyCZoneNC( prepare_joints, "PrepJoints", b2_colorOldLace, true );
1167
+
1168
+ b2ConstraintGraph* graph = context->graph;
1169
+ b2JointSim* joints = graph->colors[B2_OVERFLOW_INDEX].jointSims.data;
1170
+ int jointCount = graph->colors[B2_OVERFLOW_INDEX].jointSims.count;
1171
+
1172
+ for ( int i = 0; i < jointCount; ++i )
1173
+ {
1174
+ b2JointSim* joint = joints + i;
1175
+ b2WarmStartJoint( joint, context );
1176
+ }
1177
+
1178
+ b2TracyCZoneEnd( prepare_joints );
1179
+ }
1180
+
1181
+ void b2SolveOverflowJoints( b2StepContext* context, bool useBias )
1182
+ {
1183
+ b2TracyCZoneNC( solve_joints, "SolveJoints", b2_colorLemonChiffon, true );
1184
+
1185
+ b2ConstraintGraph* graph = context->graph;
1186
+ b2JointSim* joints = graph->colors[B2_OVERFLOW_INDEX].jointSims.data;
1187
+ int jointCount = graph->colors[B2_OVERFLOW_INDEX].jointSims.count;
1188
+
1189
+ for ( int i = 0; i < jointCount; ++i )
1190
+ {
1191
+ b2JointSim* joint = joints + i;
1192
+ b2SolveJoint( joint, context, useBias );
1193
+ }
1194
+
1195
+ b2TracyCZoneEnd( solve_joints );
1196
+ }
1197
+
1198
+ void b2DrawJoint( b2DebugDraw* draw, b2World* world, b2Joint* joint )
1199
+ {
1200
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, joint->edges[0].bodyId );
1201
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, joint->edges[1].bodyId );
1202
+ if ( bodyA->setIndex == b2_disabledSet || bodyB->setIndex == b2_disabledSet )
1203
+ {
1204
+ return;
1205
+ }
1206
+
1207
+ b2JointSim* jointSim = b2GetJointSim( world, joint );
1208
+
1209
+ b2Transform transformA = b2GetBodyTransformQuick( world, bodyA );
1210
+ b2Transform transformB = b2GetBodyTransformQuick( world, bodyB );
1211
+ b2Vec2 pA = b2TransformPoint( transformA, jointSim->localOriginAnchorA );
1212
+ b2Vec2 pB = b2TransformPoint( transformB, jointSim->localOriginAnchorB );
1213
+
1214
+ b2HexColor color = b2_colorDarkSeaGreen;
1215
+
1216
+ switch ( joint->type )
1217
+ {
1218
+ case b2_distanceJoint:
1219
+ b2DrawDistanceJoint( draw, jointSim, transformA, transformB );
1220
+ break;
1221
+
1222
+ case b2_mouseJoint:
1223
+ {
1224
+ b2Vec2 target = jointSim->mouseJoint.targetA;
1225
+
1226
+ b2HexColor c1 = b2_colorGreen;
1227
+ draw->DrawPointFcn( target, 4.0f, c1, draw->context );
1228
+ draw->DrawPointFcn( pB, 4.0f, c1, draw->context );
1229
+
1230
+ b2HexColor c2 = b2_colorLightGray;
1231
+ draw->DrawSegmentFcn( target, pB, c2, draw->context );
1232
+ }
1233
+ break;
1234
+
1235
+ case b2_filterJoint:
1236
+ {
1237
+ draw->DrawSegmentFcn( pA, pB, b2_colorGold, draw->context );
1238
+ }
1239
+ break;
1240
+
1241
+ case b2_prismaticJoint:
1242
+ b2DrawPrismaticJoint( draw, jointSim, transformA, transformB );
1243
+ break;
1244
+
1245
+ case b2_revoluteJoint:
1246
+ b2DrawRevoluteJoint( draw, jointSim, transformA, transformB, joint->drawSize );
1247
+ break;
1248
+
1249
+ case b2_wheelJoint:
1250
+ b2DrawWheelJoint( draw, jointSim, transformA, transformB );
1251
+ break;
1252
+
1253
+ default:
1254
+ draw->DrawSegmentFcn( transformA.p, pA, color, draw->context );
1255
+ draw->DrawSegmentFcn( pA, pB, color, draw->context );
1256
+ draw->DrawSegmentFcn( transformB.p, pB, color, draw->context );
1257
+ }
1258
+
1259
+ if ( draw->drawGraphColors )
1260
+ {
1261
+ b2HexColor colors[B2_GRAPH_COLOR_COUNT] = { b2_colorRed, b2_colorOrange, b2_colorYellow, b2_colorGreen,
1262
+ b2_colorCyan, b2_colorBlue, b2_colorViolet, b2_colorPink,
1263
+ b2_colorChocolate, b2_colorGoldenRod, b2_colorCoral, b2_colorBlack };
1264
+
1265
+ int colorIndex = joint->colorIndex;
1266
+ if ( colorIndex != B2_NULL_INDEX )
1267
+ {
1268
+ b2Vec2 p = b2Lerp( pA, pB, 0.5f );
1269
+ draw->DrawPointFcn( p, 5.0f, colors[colorIndex], draw->context );
1270
+ }
1271
+ }
1272
+ }