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,551 @@
1
+ // SPDX-FileCopyrightText: 2023 Erin Catto
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ #include "body.h"
5
+ #include "core.h"
6
+ #include "joint.h"
7
+ #include "solver.h"
8
+ #include "solver_set.h"
9
+ #include "world.h"
10
+
11
+ // needed for dll export
12
+ #include "box2d/box2d.h"
13
+
14
+ #include <stdio.h>
15
+
16
+ void b2WheelJoint_EnableSpring( b2JointId jointId, bool enableSpring )
17
+ {
18
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
19
+
20
+ if ( enableSpring != joint->wheelJoint.enableSpring )
21
+ {
22
+ joint->wheelJoint.enableSpring = enableSpring;
23
+ joint->wheelJoint.springImpulse = 0.0f;
24
+ }
25
+ }
26
+
27
+ bool b2WheelJoint_IsSpringEnabled( b2JointId jointId )
28
+ {
29
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
30
+ return joint->wheelJoint.enableSpring;
31
+ }
32
+
33
+ void b2WheelJoint_SetSpringHertz( b2JointId jointId, float hertz )
34
+ {
35
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
36
+ joint->wheelJoint.hertz = hertz;
37
+ }
38
+
39
+ float b2WheelJoint_GetSpringHertz( b2JointId jointId )
40
+ {
41
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
42
+ return joint->wheelJoint.hertz;
43
+ }
44
+
45
+ void b2WheelJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio )
46
+ {
47
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
48
+ joint->wheelJoint.dampingRatio = dampingRatio;
49
+ }
50
+
51
+ float b2WheelJoint_GetSpringDampingRatio( b2JointId jointId )
52
+ {
53
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
54
+ return joint->wheelJoint.dampingRatio;
55
+ }
56
+
57
+ void b2WheelJoint_EnableLimit( b2JointId jointId, bool enableLimit )
58
+ {
59
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
60
+ if ( joint->wheelJoint.enableLimit != enableLimit )
61
+ {
62
+ joint->wheelJoint.lowerImpulse = 0.0f;
63
+ joint->wheelJoint.upperImpulse = 0.0f;
64
+ joint->wheelJoint.enableLimit = enableLimit;
65
+ }
66
+ }
67
+
68
+ bool b2WheelJoint_IsLimitEnabled( b2JointId jointId )
69
+ {
70
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
71
+ return joint->wheelJoint.enableLimit;
72
+ }
73
+
74
+ float b2WheelJoint_GetLowerLimit( b2JointId jointId )
75
+ {
76
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
77
+ return joint->wheelJoint.lowerTranslation;
78
+ }
79
+
80
+ float b2WheelJoint_GetUpperLimit( b2JointId jointId )
81
+ {
82
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
83
+ return joint->wheelJoint.upperTranslation;
84
+ }
85
+
86
+ void b2WheelJoint_SetLimits( b2JointId jointId, float lower, float upper )
87
+ {
88
+ B2_ASSERT( lower <= upper );
89
+
90
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
91
+ if ( lower != joint->wheelJoint.lowerTranslation || upper != joint->wheelJoint.upperTranslation )
92
+ {
93
+ joint->wheelJoint.lowerTranslation = b2MinFloat( lower, upper );
94
+ joint->wheelJoint.upperTranslation = b2MaxFloat( lower, upper );
95
+ joint->wheelJoint.lowerImpulse = 0.0f;
96
+ joint->wheelJoint.upperImpulse = 0.0f;
97
+ }
98
+ }
99
+
100
+ void b2WheelJoint_EnableMotor( b2JointId jointId, bool enableMotor )
101
+ {
102
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
103
+ if ( joint->wheelJoint.enableMotor != enableMotor )
104
+ {
105
+ joint->wheelJoint.motorImpulse = 0.0f;
106
+ joint->wheelJoint.enableMotor = enableMotor;
107
+ }
108
+ }
109
+
110
+ bool b2WheelJoint_IsMotorEnabled( b2JointId jointId )
111
+ {
112
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
113
+ return joint->wheelJoint.enableMotor;
114
+ }
115
+
116
+ void b2WheelJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed )
117
+ {
118
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
119
+ joint->wheelJoint.motorSpeed = motorSpeed;
120
+ }
121
+
122
+ float b2WheelJoint_GetMotorSpeed( b2JointId jointId )
123
+ {
124
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
125
+ return joint->wheelJoint.motorSpeed;
126
+ }
127
+
128
+ float b2WheelJoint_GetMotorTorque( b2JointId jointId )
129
+ {
130
+ b2World* world = b2GetWorld( jointId.world0 );
131
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
132
+ return world->inv_h * joint->wheelJoint.motorImpulse;
133
+ }
134
+
135
+ void b2WheelJoint_SetMaxMotorTorque( b2JointId jointId, float torque )
136
+ {
137
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
138
+ joint->wheelJoint.maxMotorTorque = torque;
139
+ }
140
+
141
+ float b2WheelJoint_GetMaxMotorTorque( b2JointId jointId )
142
+ {
143
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_wheelJoint );
144
+ return joint->wheelJoint.maxMotorTorque;
145
+ }
146
+
147
+ b2Vec2 b2GetWheelJointForce( b2World* world, b2JointSim* base )
148
+ {
149
+ b2WheelJoint* joint = &base->wheelJoint;
150
+
151
+ // This is a frame behind
152
+ b2Vec2 axisA = joint->axisA;
153
+ b2Vec2 perpA = b2LeftPerp( axisA );
154
+
155
+ float perpForce = world->inv_h * joint->perpImpulse;
156
+ float axialForce = world->inv_h * ( joint->springImpulse + joint->lowerImpulse - joint->upperImpulse );
157
+
158
+ b2Vec2 force = b2Add( b2MulSV( perpForce, perpA ), b2MulSV( axialForce, axisA ) );
159
+ return force;
160
+ }
161
+
162
+ float b2GetWheelJointTorque( b2World* world, b2JointSim* base )
163
+ {
164
+ return world->inv_h * base->wheelJoint.motorImpulse;
165
+ }
166
+
167
+ // Linear constraint (point-to-line)
168
+ // d = pB - pA = xB + rB - xA - rA
169
+ // C = dot(ay, d)
170
+ // Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))
171
+ // = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)
172
+ // J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]
173
+
174
+ // Spring linear constraint
175
+ // C = dot(ax, d)
176
+ // Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)
177
+ // J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]
178
+
179
+ // Motor rotational constraint
180
+ // Cdot = wB - wA
181
+ // J = [0 0 -1 0 0 1]
182
+
183
+ void b2PrepareWheelJoint( b2JointSim* base, b2StepContext* context )
184
+ {
185
+ B2_ASSERT( base->type == b2_wheelJoint );
186
+
187
+ // chase body id to the solver set where the body lives
188
+ int idA = base->bodyIdA;
189
+ int idB = base->bodyIdB;
190
+
191
+ b2World* world = context->world;
192
+
193
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, idA );
194
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, idB );
195
+
196
+ B2_ASSERT( bodyA->setIndex == b2_awakeSet || bodyB->setIndex == b2_awakeSet );
197
+ b2SolverSet* setA = b2SolverSetArray_Get( &world->solverSets, bodyA->setIndex );
198
+ b2SolverSet* setB = b2SolverSetArray_Get( &world->solverSets, bodyB->setIndex );
199
+
200
+ int localIndexA = bodyA->localIndex;
201
+ int localIndexB = bodyB->localIndex;
202
+
203
+ b2BodySim* bodySimA = b2BodySimArray_Get( &setA->bodySims, localIndexA );
204
+ b2BodySim* bodySimB = b2BodySimArray_Get( &setB->bodySims, localIndexB );
205
+
206
+ float mA = bodySimA->invMass;
207
+ float iA = bodySimA->invInertia;
208
+ float mB = bodySimB->invMass;
209
+ float iB = bodySimB->invInertia;
210
+
211
+ base->invMassA = mA;
212
+ base->invMassB = mB;
213
+ base->invIA = iA;
214
+ base->invIB = iB;
215
+
216
+ b2WheelJoint* joint = &base->wheelJoint;
217
+
218
+ joint->indexA = bodyA->setIndex == b2_awakeSet ? localIndexA : B2_NULL_INDEX;
219
+ joint->indexB = bodyB->setIndex == b2_awakeSet ? localIndexB : B2_NULL_INDEX;
220
+
221
+ b2Rot qA = bodySimA->transform.q;
222
+ b2Rot qB = bodySimB->transform.q;
223
+
224
+ joint->anchorA = b2RotateVector( qA, b2Sub( base->localOriginAnchorA, bodySimA->localCenter ) );
225
+ joint->anchorB = b2RotateVector( qB, b2Sub( base->localOriginAnchorB, bodySimB->localCenter ) );
226
+ joint->axisA = b2RotateVector( qA, joint->localAxisA );
227
+ joint->deltaCenter = b2Sub( bodySimB->center, bodySimA->center );
228
+
229
+ b2Vec2 rA = joint->anchorA;
230
+ b2Vec2 rB = joint->anchorB;
231
+
232
+ b2Vec2 d = b2Add( joint->deltaCenter, b2Sub( rB, rA ) );
233
+ b2Vec2 axisA = joint->axisA;
234
+ b2Vec2 perpA = b2LeftPerp( axisA );
235
+
236
+ // perpendicular constraint (keep wheel on line)
237
+ float s1 = b2Cross( b2Add( d, rA ), perpA );
238
+ float s2 = b2Cross( rB, perpA );
239
+
240
+ float kp = mA + mB + iA * s1 * s1 + iB * s2 * s2;
241
+ joint->perpMass = kp > 0.0f ? 1.0f / kp : 0.0f;
242
+
243
+ // spring constraint
244
+ float a1 = b2Cross( b2Add( d, rA ), axisA );
245
+ float a2 = b2Cross( rB, axisA );
246
+
247
+ float ka = mA + mB + iA * a1 * a1 + iB * a2 * a2;
248
+ joint->axialMass = ka > 0.0f ? 1.0f / ka : 0.0f;
249
+
250
+ joint->springSoftness = b2MakeSoft( joint->hertz, joint->dampingRatio, context->h );
251
+
252
+ float km = iA + iB;
253
+ joint->motorMass = km > 0.0f ? 1.0f / km : 0.0f;
254
+
255
+ if ( context->enableWarmStarting == false )
256
+ {
257
+ joint->perpImpulse = 0.0f;
258
+ joint->springImpulse = 0.0f;
259
+ joint->motorImpulse = 0.0f;
260
+ joint->lowerImpulse = 0.0f;
261
+ joint->upperImpulse = 0.0f;
262
+ }
263
+ }
264
+
265
+ void b2WarmStartWheelJoint( b2JointSim* base, b2StepContext* context )
266
+ {
267
+ B2_ASSERT( base->type == b2_wheelJoint );
268
+
269
+ float mA = base->invMassA;
270
+ float mB = base->invMassB;
271
+ float iA = base->invIA;
272
+ float iB = base->invIB;
273
+
274
+ // dummy state for static bodies
275
+ b2BodyState dummyState = b2_identityBodyState;
276
+
277
+ b2WheelJoint* joint = &base->wheelJoint;
278
+
279
+ b2BodyState* stateA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
280
+ b2BodyState* stateB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
281
+
282
+ b2Vec2 rA = b2RotateVector( stateA->deltaRotation, joint->anchorA );
283
+ b2Vec2 rB = b2RotateVector( stateB->deltaRotation, joint->anchorB );
284
+
285
+ b2Vec2 d = b2Add( b2Add( b2Sub( stateB->deltaPosition, stateA->deltaPosition ), joint->deltaCenter ), b2Sub( rB, rA ) );
286
+ b2Vec2 axisA = b2RotateVector( stateA->deltaRotation, joint->axisA );
287
+ b2Vec2 perpA = b2LeftPerp( axisA );
288
+
289
+ float a1 = b2Cross( b2Add( d, rA ), axisA );
290
+ float a2 = b2Cross( rB, axisA );
291
+ float s1 = b2Cross( b2Add( d, rA ), perpA );
292
+ float s2 = b2Cross( rB, perpA );
293
+
294
+ float axialImpulse = joint->springImpulse + joint->lowerImpulse - joint->upperImpulse;
295
+
296
+ b2Vec2 P = b2Add( b2MulSV( axialImpulse, axisA ), b2MulSV( joint->perpImpulse, perpA ) );
297
+ float LA = axialImpulse * a1 + joint->perpImpulse * s1 + joint->motorImpulse;
298
+ float LB = axialImpulse * a2 + joint->perpImpulse * s2 + joint->motorImpulse;
299
+
300
+ stateA->linearVelocity = b2MulSub( stateA->linearVelocity, mA, P );
301
+ stateA->angularVelocity -= iA * LA;
302
+ stateB->linearVelocity = b2MulAdd( stateB->linearVelocity, mB, P );
303
+ stateB->angularVelocity += iB * LB;
304
+ }
305
+
306
+ void b2SolveWheelJoint( b2JointSim* base, b2StepContext* context, bool useBias )
307
+ {
308
+ B2_ASSERT( base->type == b2_wheelJoint );
309
+
310
+ float mA = base->invMassA;
311
+ float mB = base->invMassB;
312
+ float iA = base->invIA;
313
+ float iB = base->invIB;
314
+
315
+ // dummy state for static bodies
316
+ b2BodyState dummyState = b2_identityBodyState;
317
+
318
+ b2WheelJoint* joint = &base->wheelJoint;
319
+
320
+ b2BodyState* stateA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
321
+ b2BodyState* stateB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
322
+
323
+ b2Vec2 vA = stateA->linearVelocity;
324
+ float wA = stateA->angularVelocity;
325
+ b2Vec2 vB = stateB->linearVelocity;
326
+ float wB = stateB->angularVelocity;
327
+
328
+ bool fixedRotation = ( iA + iB == 0.0f );
329
+
330
+ // current anchors
331
+ b2Vec2 rA = b2RotateVector( stateA->deltaRotation, joint->anchorA );
332
+ b2Vec2 rB = b2RotateVector( stateB->deltaRotation, joint->anchorB );
333
+
334
+ b2Vec2 d = b2Add( b2Add( b2Sub( stateB->deltaPosition, stateA->deltaPosition ), joint->deltaCenter ), b2Sub( rB, rA ) );
335
+ b2Vec2 axisA = b2RotateVector( stateA->deltaRotation, joint->axisA );
336
+ float translation = b2Dot( axisA, d );
337
+
338
+ float a1 = b2Cross( b2Add( d, rA ), axisA );
339
+ float a2 = b2Cross( rB, axisA );
340
+
341
+ // motor constraint
342
+ if ( joint->enableMotor && fixedRotation == false )
343
+ {
344
+ float Cdot = wB - wA - joint->motorSpeed;
345
+ float impulse = -joint->motorMass * Cdot;
346
+ float oldImpulse = joint->motorImpulse;
347
+ float maxImpulse = context->h * joint->maxMotorTorque;
348
+ joint->motorImpulse = b2ClampFloat( joint->motorImpulse + impulse, -maxImpulse, maxImpulse );
349
+ impulse = joint->motorImpulse - oldImpulse;
350
+
351
+ wA -= iA * impulse;
352
+ wB += iB * impulse;
353
+ }
354
+
355
+ // spring constraint
356
+ if ( joint->enableSpring )
357
+ {
358
+ // This is a real spring and should be applied even during relax
359
+ float C = translation;
360
+ float bias = joint->springSoftness.biasRate * C;
361
+ float massScale = joint->springSoftness.massScale;
362
+ float impulseScale = joint->springSoftness.impulseScale;
363
+
364
+ float Cdot = b2Dot( axisA, b2Sub( vB, vA ) ) + a2 * wB - a1 * wA;
365
+ float impulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * joint->springImpulse;
366
+ joint->springImpulse += impulse;
367
+
368
+ b2Vec2 P = b2MulSV( impulse, axisA );
369
+ float LA = impulse * a1;
370
+ float LB = impulse * a2;
371
+
372
+ vA = b2MulSub( vA, mA, P );
373
+ wA -= iA * LA;
374
+ vB = b2MulAdd( vB, mB, P );
375
+ wB += iB * LB;
376
+ }
377
+
378
+ if ( joint->enableLimit )
379
+ {
380
+ // Lower limit
381
+ {
382
+ float C = translation - joint->lowerTranslation;
383
+ float bias = 0.0f;
384
+ float massScale = 1.0f;
385
+ float impulseScale = 0.0f;
386
+
387
+ if ( C > 0.0f )
388
+ {
389
+ // speculation
390
+ bias = C * context->inv_h;
391
+ }
392
+ else if ( useBias )
393
+ {
394
+ bias = context->jointSoftness.biasRate * C;
395
+ massScale = context->jointSoftness.massScale;
396
+ impulseScale = context->jointSoftness.impulseScale;
397
+ }
398
+
399
+ float Cdot = b2Dot( axisA, b2Sub( vB, vA ) ) + a2 * wB - a1 * wA;
400
+ float impulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * joint->lowerImpulse;
401
+ float oldImpulse = joint->lowerImpulse;
402
+ joint->lowerImpulse = b2MaxFloat( oldImpulse + impulse, 0.0f );
403
+ impulse = joint->lowerImpulse - oldImpulse;
404
+
405
+ b2Vec2 P = b2MulSV( impulse, axisA );
406
+ float LA = impulse * a1;
407
+ float LB = impulse * a2;
408
+
409
+ vA = b2MulSub( vA, mA, P );
410
+ wA -= iA * LA;
411
+ vB = b2MulAdd( vB, mB, P );
412
+ wB += iB * LB;
413
+ }
414
+
415
+ // Upper limit
416
+ // Note: signs are flipped to keep C positive when the constraint is satisfied.
417
+ // This also keeps the impulse positive when the limit is active.
418
+ {
419
+ // sign flipped
420
+ float C = joint->upperTranslation - translation;
421
+ float bias = 0.0f;
422
+ float massScale = 1.0f;
423
+ float impulseScale = 0.0f;
424
+
425
+ if ( C > 0.0f )
426
+ {
427
+ // speculation
428
+ bias = C * context->inv_h;
429
+ }
430
+ else if ( useBias )
431
+ {
432
+ bias = context->jointSoftness.biasRate * C;
433
+ massScale = context->jointSoftness.massScale;
434
+ impulseScale = context->jointSoftness.impulseScale;
435
+ }
436
+
437
+ // sign flipped on Cdot
438
+ float Cdot = b2Dot( axisA, b2Sub( vA, vB ) ) + a1 * wA - a2 * wB;
439
+ float impulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * joint->upperImpulse;
440
+ float oldImpulse = joint->upperImpulse;
441
+ joint->upperImpulse = b2MaxFloat( oldImpulse + impulse, 0.0f );
442
+ impulse = joint->upperImpulse - oldImpulse;
443
+
444
+ b2Vec2 P = b2MulSV( impulse, axisA );
445
+ float LA = impulse * a1;
446
+ float LB = impulse * a2;
447
+
448
+ // sign flipped on applied impulse
449
+ vA = b2MulAdd( vA, mA, P );
450
+ wA += iA * LA;
451
+ vB = b2MulSub( vB, mB, P );
452
+ wB -= iB * LB;
453
+ }
454
+ }
455
+
456
+ // point to line constraint
457
+ {
458
+ b2Vec2 perpA = b2LeftPerp( axisA );
459
+
460
+ float bias = 0.0f;
461
+ float massScale = 1.0f;
462
+ float impulseScale = 0.0f;
463
+ if ( useBias )
464
+ {
465
+ float C = b2Dot( perpA, d );
466
+ bias = context->jointSoftness.biasRate * C;
467
+ massScale = context->jointSoftness.massScale;
468
+ impulseScale = context->jointSoftness.impulseScale;
469
+ }
470
+
471
+ float s1 = b2Cross( b2Add( d, rA ), perpA );
472
+ float s2 = b2Cross( rB, perpA );
473
+ float Cdot = b2Dot( perpA, b2Sub( vB, vA ) ) + s2 * wB - s1 * wA;
474
+
475
+ float impulse = -massScale * joint->perpMass * ( Cdot + bias ) - impulseScale * joint->perpImpulse;
476
+ joint->perpImpulse += impulse;
477
+
478
+ b2Vec2 P = b2MulSV( impulse, perpA );
479
+ float LA = impulse * s1;
480
+ float LB = impulse * s2;
481
+
482
+ vA = b2MulSub( vA, mA, P );
483
+ wA -= iA * LA;
484
+ vB = b2MulAdd( vB, mB, P );
485
+ wB += iB * LB;
486
+ }
487
+
488
+ stateA->linearVelocity = vA;
489
+ stateA->angularVelocity = wA;
490
+ stateB->linearVelocity = vB;
491
+ stateB->angularVelocity = wB;
492
+ }
493
+
494
+ #if 0
495
+ void b2WheelJoint_Dump()
496
+ {
497
+ int32 indexA = joint->bodyA->joint->islandIndex;
498
+ int32 indexB = joint->bodyB->joint->islandIndex;
499
+
500
+ b2Dump(" b2WheelJointDef jd;\n");
501
+ b2Dump(" jd.bodyA = sims[%d];\n", indexA);
502
+ b2Dump(" jd.bodyB = sims[%d];\n", indexB);
503
+ b2Dump(" jd.collideConnected = bool(%d);\n", joint->collideConnected);
504
+ b2Dump(" jd.localAnchorA.Set(%.9g, %.9g);\n", joint->localAnchorA.x, joint->localAnchorA.y);
505
+ b2Dump(" jd.localAnchorB.Set(%.9g, %.9g);\n", joint->localAnchorB.x, joint->localAnchorB.y);
506
+ b2Dump(" jd.referenceAngle = %.9g;\n", joint->referenceAngle);
507
+ b2Dump(" jd.enableLimit = bool(%d);\n", joint->enableLimit);
508
+ b2Dump(" jd.lowerAngle = %.9g;\n", joint->lowerAngle);
509
+ b2Dump(" jd.upperAngle = %.9g;\n", joint->upperAngle);
510
+ b2Dump(" jd.enableMotor = bool(%d);\n", joint->enableMotor);
511
+ b2Dump(" jd.motorSpeed = %.9g;\n", joint->motorSpeed);
512
+ b2Dump(" jd.maxMotorTorque = %.9g;\n", joint->maxMotorTorque);
513
+ b2Dump(" joints[%d] = joint->world->CreateJoint(&jd);\n", joint->index);
514
+ }
515
+ #endif
516
+
517
+ void b2DrawWheelJoint( b2DebugDraw* draw, b2JointSim* base, b2Transform transformA, b2Transform transformB )
518
+ {
519
+ B2_ASSERT( base->type == b2_wheelJoint );
520
+
521
+ b2WheelJoint* joint = &base->wheelJoint;
522
+
523
+ b2Vec2 pA = b2TransformPoint( transformA, base->localOriginAnchorA );
524
+ b2Vec2 pB = b2TransformPoint( transformB, base->localOriginAnchorB );
525
+ b2Vec2 axis = b2RotateVector( transformA.q, joint->localAxisA );
526
+
527
+ b2HexColor c1 = b2_colorGray;
528
+ b2HexColor c2 = b2_colorGreen;
529
+ b2HexColor c3 = b2_colorRed;
530
+ b2HexColor c4 = b2_colorDimGray;
531
+ b2HexColor c5 = b2_colorBlue;
532
+
533
+ draw->DrawSegmentFcn( pA, pB, c5, draw->context );
534
+
535
+ if ( joint->enableLimit )
536
+ {
537
+ b2Vec2 lower = b2MulAdd( pA, joint->lowerTranslation, axis );
538
+ b2Vec2 upper = b2MulAdd( pA, joint->upperTranslation, axis );
539
+ b2Vec2 perp = b2LeftPerp( axis );
540
+ draw->DrawSegmentFcn( lower, upper, c1, draw->context );
541
+ draw->DrawSegmentFcn( b2MulSub( lower, 0.1f, perp ), b2MulAdd( lower, 0.1f, perp ), c2, draw->context );
542
+ draw->DrawSegmentFcn( b2MulSub( upper, 0.1f, perp ), b2MulAdd( upper, 0.1f, perp ), c3, draw->context );
543
+ }
544
+ else
545
+ {
546
+ draw->DrawSegmentFcn( b2MulSub( pA, 1.0f, axis ), b2MulAdd( pA, 1.0f, axis ), c1, draw->context );
547
+ }
548
+
549
+ draw->DrawPointFcn( pA, 5.0f, c1, draw->context );
550
+ draw->DrawPointFcn( pB, 5.0f, c4, draw->context );
551
+ }