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,534 @@
1
+ // SPDX-FileCopyrightText: 2023 Erin Catto
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ #if defined( _MSC_VER ) && !defined( _CRT_SECURE_NO_WARNINGS )
5
+ #define _CRT_SECURE_NO_WARNINGS
6
+ #endif
7
+
8
+ #include "body.h"
9
+ #include "core.h"
10
+ #include "joint.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 <stdio.h>
19
+
20
+ void b2RevoluteJoint_EnableSpring( b2JointId jointId, bool enableSpring )
21
+ {
22
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
23
+ if ( enableSpring != joint->revoluteJoint.enableSpring )
24
+ {
25
+ joint->revoluteJoint.enableSpring = enableSpring;
26
+ joint->revoluteJoint.springImpulse = 0.0f;
27
+ }
28
+ }
29
+
30
+ bool b2RevoluteJoint_IsSpringEnabled( b2JointId jointId )
31
+ {
32
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
33
+ return joint->revoluteJoint.enableSpring;
34
+ }
35
+
36
+ void b2RevoluteJoint_SetSpringHertz( b2JointId jointId, float hertz )
37
+ {
38
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
39
+ joint->revoluteJoint.hertz = hertz;
40
+ }
41
+
42
+ float b2RevoluteJoint_GetSpringHertz( b2JointId jointId )
43
+ {
44
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
45
+ return joint->revoluteJoint.hertz;
46
+ }
47
+
48
+ void b2RevoluteJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio )
49
+ {
50
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
51
+ joint->revoluteJoint.dampingRatio = dampingRatio;
52
+ }
53
+
54
+ float b2RevoluteJoint_GetSpringDampingRatio( b2JointId jointId )
55
+ {
56
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
57
+ return joint->revoluteJoint.dampingRatio;
58
+ }
59
+
60
+ float b2RevoluteJoint_GetAngle( b2JointId jointId )
61
+ {
62
+ b2World* world = b2GetWorld( jointId.world0 );
63
+ b2JointSim* jointSim = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
64
+ b2Transform transformA = b2GetBodyTransform( world, jointSim->bodyIdA );
65
+ b2Transform transformB = b2GetBodyTransform( world, jointSim->bodyIdB );
66
+
67
+ float angle = b2RelativeAngle( transformB.q, transformA.q ) - jointSim->revoluteJoint.referenceAngle;
68
+ angle = b2UnwindAngle( angle );
69
+ return angle;
70
+ }
71
+
72
+ void b2RevoluteJoint_EnableLimit( b2JointId jointId, bool enableLimit )
73
+ {
74
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
75
+ if ( enableLimit != joint->revoluteJoint.enableLimit )
76
+ {
77
+ joint->revoluteJoint.enableLimit = enableLimit;
78
+ joint->revoluteJoint.lowerImpulse = 0.0f;
79
+ joint->revoluteJoint.upperImpulse = 0.0f;
80
+ }
81
+ }
82
+
83
+ bool b2RevoluteJoint_IsLimitEnabled( b2JointId jointId )
84
+ {
85
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
86
+ return joint->revoluteJoint.enableLimit;
87
+ }
88
+
89
+ float b2RevoluteJoint_GetLowerLimit( b2JointId jointId )
90
+ {
91
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
92
+ return joint->revoluteJoint.lowerAngle;
93
+ }
94
+
95
+ float b2RevoluteJoint_GetUpperLimit( b2JointId jointId )
96
+ {
97
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
98
+ return joint->revoluteJoint.upperAngle;
99
+ }
100
+
101
+ void b2RevoluteJoint_SetLimits( b2JointId jointId, float lower, float upper )
102
+ {
103
+ B2_ASSERT( lower <= upper );
104
+ B2_ASSERT( lower >= -0.95f * B2_PI );
105
+ B2_ASSERT( upper <= 0.95f * B2_PI );
106
+
107
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
108
+ if ( lower != joint->revoluteJoint.lowerAngle || upper != joint->revoluteJoint.upperAngle )
109
+ {
110
+ joint->revoluteJoint.lowerAngle = b2MinFloat( lower, upper );
111
+ joint->revoluteJoint.upperAngle = b2MaxFloat( lower, upper );
112
+ joint->revoluteJoint.lowerImpulse = 0.0f;
113
+ joint->revoluteJoint.upperImpulse = 0.0f;
114
+ }
115
+ }
116
+
117
+ void b2RevoluteJoint_EnableMotor( b2JointId jointId, bool enableMotor )
118
+ {
119
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
120
+ if ( enableMotor != joint->revoluteJoint.enableMotor )
121
+ {
122
+ joint->revoluteJoint.enableMotor = enableMotor;
123
+ joint->revoluteJoint.motorImpulse = 0.0f;
124
+ }
125
+ }
126
+
127
+ bool b2RevoluteJoint_IsMotorEnabled( b2JointId jointId )
128
+ {
129
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
130
+ return joint->revoluteJoint.enableMotor;
131
+ }
132
+
133
+ void b2RevoluteJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed )
134
+ {
135
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
136
+ joint->revoluteJoint.motorSpeed = motorSpeed;
137
+ }
138
+
139
+ float b2RevoluteJoint_GetMotorSpeed( b2JointId jointId )
140
+ {
141
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
142
+ return joint->revoluteJoint.motorSpeed;
143
+ }
144
+
145
+ float b2RevoluteJoint_GetMotorTorque( b2JointId jointId )
146
+ {
147
+ b2World* world = b2GetWorld( jointId.world0 );
148
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
149
+ return world->inv_h * joint->revoluteJoint.motorImpulse;
150
+ }
151
+
152
+ void b2RevoluteJoint_SetMaxMotorTorque( b2JointId jointId, float torque )
153
+ {
154
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
155
+ joint->revoluteJoint.maxMotorTorque = torque;
156
+ }
157
+
158
+ float b2RevoluteJoint_GetMaxMotorTorque( b2JointId jointId )
159
+ {
160
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_revoluteJoint );
161
+ return joint->revoluteJoint.maxMotorTorque;
162
+ }
163
+
164
+ b2Vec2 b2GetRevoluteJointForce( b2World* world, b2JointSim* base )
165
+ {
166
+ b2Vec2 force = b2MulSV( world->inv_h, base->revoluteJoint.linearImpulse );
167
+ return force;
168
+ }
169
+
170
+ float b2GetRevoluteJointTorque( b2World* world, b2JointSim* base )
171
+ {
172
+ const b2RevoluteJoint* revolute = &base->revoluteJoint;
173
+ float torque = world->inv_h * ( revolute->motorImpulse + revolute->lowerImpulse - revolute->upperImpulse );
174
+ return torque;
175
+ }
176
+
177
+ // Point-to-point constraint
178
+ // C = p2 - p1
179
+ // Cdot = v2 - v1
180
+ // = v2 + cross(w2, r2) - v1 - cross(w1, r1)
181
+ // J = [-I -r1_skew I r2_skew ]
182
+ // Identity used:
183
+ // w k % (rx i + ry j) = w * (-ry i + rx j)
184
+
185
+ // Motor constraint
186
+ // Cdot = w2 - w1
187
+ // J = [0 0 -1 0 0 1]
188
+ // K = invI1 + invI2
189
+
190
+ void b2PrepareRevoluteJoint( b2JointSim* base, b2StepContext* context )
191
+ {
192
+ B2_ASSERT( base->type == b2_revoluteJoint );
193
+
194
+ // chase body id to the solver set where the body lives
195
+ int idA = base->bodyIdA;
196
+ int idB = base->bodyIdB;
197
+
198
+ b2World* world = context->world;
199
+
200
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, idA );
201
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, idB );
202
+
203
+ B2_ASSERT( bodyA->setIndex == b2_awakeSet || bodyB->setIndex == b2_awakeSet );
204
+ b2SolverSet* setA = b2SolverSetArray_Get( &world->solverSets, bodyA->setIndex );
205
+ b2SolverSet* setB = b2SolverSetArray_Get( &world->solverSets, bodyB->setIndex );
206
+
207
+ int localIndexA = bodyA->localIndex;
208
+ int localIndexB = bodyB->localIndex;
209
+
210
+ b2BodySim* bodySimA = b2BodySimArray_Get( &setA->bodySims, localIndexA );
211
+ b2BodySim* bodySimB = b2BodySimArray_Get( &setB->bodySims, localIndexB );
212
+
213
+ float mA = bodySimA->invMass;
214
+ float iA = bodySimA->invInertia;
215
+ float mB = bodySimB->invMass;
216
+ float iB = bodySimB->invInertia;
217
+
218
+ base->invMassA = mA;
219
+ base->invMassB = mB;
220
+ base->invIA = iA;
221
+ base->invIB = iB;
222
+
223
+ b2RevoluteJoint* joint = &base->revoluteJoint;
224
+
225
+ joint->indexA = bodyA->setIndex == b2_awakeSet ? localIndexA : B2_NULL_INDEX;
226
+ joint->indexB = bodyB->setIndex == b2_awakeSet ? localIndexB : B2_NULL_INDEX;
227
+
228
+ // initial anchors in world space
229
+ joint->anchorA = b2RotateVector( bodySimA->transform.q, b2Sub( base->localOriginAnchorA, bodySimA->localCenter ) );
230
+ joint->anchorB = b2RotateVector( bodySimB->transform.q, b2Sub( base->localOriginAnchorB, bodySimB->localCenter ) );
231
+ joint->deltaCenter = b2Sub( bodySimB->center, bodySimA->center );
232
+ joint->deltaAngle = b2RelativeAngle( bodySimB->transform.q, bodySimA->transform.q ) - joint->referenceAngle;
233
+ joint->deltaAngle = b2UnwindAngle( joint->deltaAngle );
234
+
235
+ float k = iA + iB;
236
+ joint->axialMass = k > 0.0f ? 1.0f / k : 0.0f;
237
+
238
+ joint->springSoftness = b2MakeSoft( joint->hertz, joint->dampingRatio, context->h );
239
+
240
+ if ( context->enableWarmStarting == false )
241
+ {
242
+ joint->linearImpulse = b2Vec2_zero;
243
+ joint->springImpulse = 0.0f;
244
+ joint->motorImpulse = 0.0f;
245
+ joint->lowerImpulse = 0.0f;
246
+ joint->upperImpulse = 0.0f;
247
+ }
248
+ }
249
+
250
+ void b2WarmStartRevoluteJoint( b2JointSim* base, b2StepContext* context )
251
+ {
252
+ B2_ASSERT( base->type == b2_revoluteJoint );
253
+
254
+ float mA = base->invMassA;
255
+ float mB = base->invMassB;
256
+ float iA = base->invIA;
257
+ float iB = base->invIB;
258
+
259
+ // dummy state for static bodies
260
+ b2BodyState dummyState = b2_identityBodyState;
261
+
262
+ b2RevoluteJoint* joint = &base->revoluteJoint;
263
+ b2BodyState* stateA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
264
+ b2BodyState* stateB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
265
+
266
+ b2Vec2 rA = b2RotateVector( stateA->deltaRotation, joint->anchorA );
267
+ b2Vec2 rB = b2RotateVector( stateB->deltaRotation, joint->anchorB );
268
+
269
+ float axialImpulse = joint->springImpulse + joint->motorImpulse + joint->lowerImpulse - joint->upperImpulse;
270
+
271
+ stateA->linearVelocity = b2MulSub( stateA->linearVelocity, mA, joint->linearImpulse );
272
+ stateA->angularVelocity -= iA * ( b2Cross( rA, joint->linearImpulse ) + axialImpulse );
273
+
274
+ stateB->linearVelocity = b2MulAdd( stateB->linearVelocity, mB, joint->linearImpulse );
275
+ stateB->angularVelocity += iB * ( b2Cross( rB, joint->linearImpulse ) + axialImpulse );
276
+ }
277
+
278
+ void b2SolveRevoluteJoint( b2JointSim* base, b2StepContext* context, bool useBias )
279
+ {
280
+ B2_ASSERT( base->type == b2_revoluteJoint );
281
+
282
+ float mA = base->invMassA;
283
+ float mB = base->invMassB;
284
+ float iA = base->invIA;
285
+ float iB = base->invIB;
286
+
287
+ // dummy state for static bodies
288
+ b2BodyState dummyState = b2_identityBodyState;
289
+
290
+ b2RevoluteJoint* joint = &base->revoluteJoint;
291
+
292
+ b2BodyState* stateA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
293
+ b2BodyState* stateB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
294
+
295
+ b2Vec2 vA = stateA->linearVelocity;
296
+ float wA = stateA->angularVelocity;
297
+ b2Vec2 vB = stateB->linearVelocity;
298
+ float wB = stateB->angularVelocity;
299
+
300
+ bool fixedRotation = ( iA + iB == 0.0f );
301
+ // const float maxBias = context->maxBiasVelocity;
302
+
303
+ // Solve spring.
304
+ if ( joint->enableSpring && fixedRotation == false )
305
+ {
306
+ float C = b2RelativeAngle( stateB->deltaRotation, stateA->deltaRotation ) + joint->deltaAngle;
307
+ float bias = joint->springSoftness.biasRate * C;
308
+ float massScale = joint->springSoftness.massScale;
309
+ float impulseScale = joint->springSoftness.impulseScale;
310
+
311
+ float Cdot = wB - wA;
312
+ float impulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * joint->springImpulse;
313
+ joint->springImpulse += impulse;
314
+
315
+ wA -= iA * impulse;
316
+ wB += iB * impulse;
317
+ }
318
+
319
+ // Solve motor constraint.
320
+ if ( joint->enableMotor && fixedRotation == false )
321
+ {
322
+ float Cdot = wB - wA - joint->motorSpeed;
323
+ float impulse = -joint->axialMass * Cdot;
324
+ float oldImpulse = joint->motorImpulse;
325
+ float maxImpulse = context->h * joint->maxMotorTorque;
326
+ joint->motorImpulse = b2ClampFloat( joint->motorImpulse + impulse, -maxImpulse, maxImpulse );
327
+ impulse = joint->motorImpulse - oldImpulse;
328
+
329
+ wA -= iA * impulse;
330
+ wB += iB * impulse;
331
+ }
332
+
333
+ if ( joint->enableLimit && fixedRotation == false )
334
+ {
335
+ float jointAngle = b2RelativeAngle( stateB->deltaRotation, stateA->deltaRotation ) + joint->deltaAngle;
336
+ jointAngle = b2UnwindAngle( jointAngle );
337
+
338
+ // Lower limit
339
+ {
340
+ float C = jointAngle - joint->lowerAngle;
341
+ float bias = 0.0f;
342
+ float massScale = 1.0f;
343
+ float impulseScale = 0.0f;
344
+ if ( C > 0.0f )
345
+ {
346
+ // speculation
347
+ bias = C * context->inv_h;
348
+ }
349
+ else if ( useBias )
350
+ {
351
+ bias = context->jointSoftness.biasRate * C;
352
+ massScale = context->jointSoftness.massScale;
353
+ impulseScale = context->jointSoftness.impulseScale;
354
+ }
355
+
356
+ float Cdot = wB - wA;
357
+ float oldImpulse = joint->lowerImpulse;
358
+ float impulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * oldImpulse;
359
+ joint->lowerImpulse = b2MaxFloat( oldImpulse + impulse, 0.0f );
360
+ impulse = joint->lowerImpulse - oldImpulse;
361
+
362
+ wA -= iA * impulse;
363
+ wB += iB * impulse;
364
+ }
365
+
366
+ // Upper limit
367
+ // Note: signs are flipped to keep C positive when the constraint is satisfied.
368
+ // This also keeps the impulse positive when the limit is active.
369
+ {
370
+ float C = joint->upperAngle - jointAngle;
371
+ float bias = 0.0f;
372
+ float massScale = 1.0f;
373
+ float impulseScale = 0.0f;
374
+ if ( C > 0.0f )
375
+ {
376
+ // speculation
377
+ bias = C * context->inv_h;
378
+ }
379
+ else if ( useBias )
380
+ {
381
+ bias = context->jointSoftness.biasRate * C;
382
+ massScale = context->jointSoftness.massScale;
383
+ impulseScale = context->jointSoftness.impulseScale;
384
+ }
385
+
386
+ // sign flipped on Cdot
387
+ float Cdot = wA - wB;
388
+ float oldImpulse = joint->upperImpulse;
389
+ float impulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * oldImpulse;
390
+ joint->upperImpulse = b2MaxFloat( oldImpulse + impulse, 0.0f );
391
+ impulse = joint->upperImpulse - oldImpulse;
392
+
393
+ // sign flipped on applied impulse
394
+ wA += iA * impulse;
395
+ wB -= iB * impulse;
396
+ }
397
+ }
398
+
399
+ // Solve point-to-point constraint
400
+ {
401
+ // J = [-I -r1_skew I r2_skew]
402
+ // r_skew = [-ry; rx]
403
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x]
404
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB]
405
+
406
+ // current anchors
407
+ b2Vec2 rA = b2RotateVector( stateA->deltaRotation, joint->anchorA );
408
+ b2Vec2 rB = b2RotateVector( stateB->deltaRotation, joint->anchorB );
409
+
410
+ b2Vec2 Cdot = b2Sub( b2Add( vB, b2CrossSV( wB, rB ) ), b2Add( vA, b2CrossSV( wA, rA ) ) );
411
+
412
+ b2Vec2 bias = b2Vec2_zero;
413
+ float massScale = 1.0f;
414
+ float impulseScale = 0.0f;
415
+ if ( useBias )
416
+ {
417
+ b2Vec2 dcA = stateA->deltaPosition;
418
+ b2Vec2 dcB = stateB->deltaPosition;
419
+
420
+ b2Vec2 separation = b2Add( b2Add( b2Sub( dcB, dcA ), b2Sub( rB, rA ) ), joint->deltaCenter );
421
+ bias = b2MulSV( context->jointSoftness.biasRate, separation );
422
+ massScale = context->jointSoftness.massScale;
423
+ impulseScale = context->jointSoftness.impulseScale;
424
+ }
425
+
426
+ b2Mat22 K;
427
+ K.cx.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
428
+ K.cy.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
429
+ K.cx.y = K.cy.x;
430
+ K.cy.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
431
+ b2Vec2 b = b2Solve22( K, b2Add( Cdot, bias ) );
432
+
433
+ b2Vec2 impulse;
434
+ impulse.x = -massScale * b.x - impulseScale * joint->linearImpulse.x;
435
+ impulse.y = -massScale * b.y - impulseScale * joint->linearImpulse.y;
436
+ joint->linearImpulse.x += impulse.x;
437
+ joint->linearImpulse.y += impulse.y;
438
+
439
+ vA = b2MulSub( vA, mA, impulse );
440
+ wA -= iA * b2Cross( rA, impulse );
441
+ vB = b2MulAdd( vB, mB, impulse );
442
+ wB += iB * b2Cross( rB, impulse );
443
+ }
444
+
445
+ stateA->linearVelocity = vA;
446
+ stateA->angularVelocity = wA;
447
+ stateB->linearVelocity = vB;
448
+ stateB->angularVelocity = wB;
449
+ }
450
+
451
+ #if 0
452
+ void b2RevoluteJoint::Dump()
453
+ {
454
+ int32 indexA = joint->bodyA->joint->islandIndex;
455
+ int32 indexB = joint->bodyB->joint->islandIndex;
456
+
457
+ b2Dump(" b2RevoluteJointDef jd;\n");
458
+ b2Dump(" jd.bodyA = bodies[%d];\n", indexA);
459
+ b2Dump(" jd.bodyB = bodies[%d];\n", indexB);
460
+ b2Dump(" jd.collideConnected = bool(%d);\n", joint->collideConnected);
461
+ b2Dump(" jd.localAnchorA.Set(%.9g, %.9g);\n", joint->localAnchorA.x, joint->localAnchorA.y);
462
+ b2Dump(" jd.localAnchorB.Set(%.9g, %.9g);\n", joint->localAnchorB.x, joint->localAnchorB.y);
463
+ b2Dump(" jd.referenceAngle = %.9g;\n", joint->referenceAngle);
464
+ b2Dump(" jd.enableLimit = bool(%d);\n", joint->enableLimit);
465
+ b2Dump(" jd.lowerAngle = %.9g;\n", joint->lowerAngle);
466
+ b2Dump(" jd.upperAngle = %.9g;\n", joint->upperAngle);
467
+ b2Dump(" jd.enableMotor = bool(%d);\n", joint->enableMotor);
468
+ b2Dump(" jd.motorSpeed = %.9g;\n", joint->motorSpeed);
469
+ b2Dump(" jd.maxMotorTorque = %.9g;\n", joint->maxMotorTorque);
470
+ b2Dump(" joints[%d] = joint->world->CreateJoint(&jd);\n", joint->index);
471
+ }
472
+ #endif
473
+
474
+ void b2DrawRevoluteJoint( b2DebugDraw* draw, b2JointSim* base, b2Transform transformA, b2Transform transformB, float drawSize )
475
+ {
476
+ B2_ASSERT( base->type == b2_revoluteJoint );
477
+
478
+ b2RevoluteJoint* joint = &base->revoluteJoint;
479
+
480
+ b2Vec2 pA = b2TransformPoint( transformA, base->localOriginAnchorA );
481
+ b2Vec2 pB = b2TransformPoint( transformB, base->localOriginAnchorB );
482
+
483
+ b2HexColor c1 = b2_colorGray;
484
+ b2HexColor c2 = b2_colorGreen;
485
+ b2HexColor c3 = b2_colorRed;
486
+
487
+ const float L = drawSize;
488
+ // draw->drawPoint(pA, 3.0f, b2_colorGray40, draw->context);
489
+ // draw->drawPoint(pB, 3.0f, b2_colorLightBlue, draw->context);
490
+ draw->DrawCircleFcn( pB, L, c1, draw->context );
491
+
492
+ float angle = b2RelativeAngle( transformB.q, transformA.q );
493
+
494
+ b2Rot rot = b2MakeRot( angle );
495
+ b2Vec2 r = { L * rot.c, L * rot.s };
496
+ b2Vec2 pC = b2Add( pB, r );
497
+ draw->DrawSegmentFcn( pB, pC, c1, draw->context );
498
+
499
+ if ( draw->drawJointExtras )
500
+ {
501
+ float jointAngle = b2UnwindAngle( angle - joint->referenceAngle );
502
+ char buffer[32];
503
+ snprintf( buffer, 32, " %.1f deg", 180.0f * jointAngle / B2_PI );
504
+ draw->DrawStringFcn( pC, buffer, b2_colorWhite, draw->context );
505
+ }
506
+
507
+ float lowerAngle = joint->lowerAngle + joint->referenceAngle;
508
+ float upperAngle = joint->upperAngle + joint->referenceAngle;
509
+
510
+ if ( joint->enableLimit )
511
+ {
512
+ b2Rot rotLo = b2MakeRot( lowerAngle );
513
+ b2Vec2 rlo = { L * rotLo.c, L * rotLo.s };
514
+
515
+ b2Rot rotHi = b2MakeRot( upperAngle );
516
+ b2Vec2 rhi = { L * rotHi.c, L * rotHi.s };
517
+
518
+ draw->DrawSegmentFcn( pB, b2Add( pB, rlo ), c2, draw->context );
519
+ draw->DrawSegmentFcn( pB, b2Add( pB, rhi ), c3, draw->context );
520
+
521
+ b2Rot rotRef = b2MakeRot( joint->referenceAngle );
522
+ b2Vec2 ref = (b2Vec2){ L * rotRef.c, L * rotRef.s };
523
+ draw->DrawSegmentFcn( pB, b2Add( pB, ref ), b2_colorBlue, draw->context );
524
+ }
525
+
526
+ b2HexColor color = b2_colorGold;
527
+ draw->DrawSegmentFcn( transformA.p, pA, color, draw->context );
528
+ draw->DrawSegmentFcn( pA, pB, color, draw->context );
529
+ draw->DrawSegmentFcn( transformB.p, pB, color, draw->context );
530
+
531
+ // char buffer[32];
532
+ // sprintf(buffer, "%.1f", b2Length(joint->impulse));
533
+ // draw->DrawString(pA, buffer, draw->context);
534
+ }