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,159 @@
1
+ // SPDX-FileCopyrightText: 2023 Erin Catto
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ #include "box2d/math_functions.h"
5
+
6
+ #include <float.h>
7
+
8
+ _Static_assert( sizeof( int32_t ) == sizeof( int ), "Box2D expects int32_t and int to be the same" );
9
+
10
+ bool b2IsValidFloat( float a )
11
+ {
12
+ if ( isnan( a ) )
13
+ {
14
+ return false;
15
+ }
16
+
17
+ if ( isinf( a ) )
18
+ {
19
+ return false;
20
+ }
21
+
22
+ return true;
23
+ }
24
+
25
+ bool b2IsValidVec2( b2Vec2 v )
26
+ {
27
+ if ( isnan( v.x ) || isnan( v.y ) )
28
+ {
29
+ return false;
30
+ }
31
+
32
+ if ( isinf( v.x ) || isinf( v.y ) )
33
+ {
34
+ return false;
35
+ }
36
+
37
+ return true;
38
+ }
39
+
40
+ bool b2IsValidRotation( b2Rot q )
41
+ {
42
+ if ( isnan( q.s ) || isnan( q.c ) )
43
+ {
44
+ return false;
45
+ }
46
+
47
+ if ( isinf( q.s ) || isinf( q.c ) )
48
+ {
49
+ return false;
50
+ }
51
+
52
+ return b2IsNormalizedRot( q );
53
+ }
54
+
55
+ bool b2IsValidPlane( b2Plane a )
56
+ {
57
+ return b2IsValidVec2( a.normal ) && b2IsNormalized( a.normal ) && b2IsValidFloat( a.offset );
58
+ }
59
+
60
+ // https://stackoverflow.com/questions/46210708/atan2-approximation-with-11bits-in-mantissa-on-x86with-sse2-and-armwith-vfpv4
61
+ float b2Atan2( float y, float x )
62
+ {
63
+ // Added check for (0,0) to match atan2f and avoid NaN
64
+ if (x == 0.0f && y == 0.0f)
65
+ {
66
+ return 0.0f;
67
+ }
68
+
69
+ float ax = b2AbsFloat( x );
70
+ float ay = b2AbsFloat( y );
71
+ float mx = b2MaxFloat( ay, ax );
72
+ float mn = b2MinFloat( ay, ax );
73
+ float a = mn / mx;
74
+
75
+ // Minimax polynomial approximation to atan(a) on [0,1]
76
+ float s = a * a;
77
+ float c = s * a;
78
+ float q = s * s;
79
+ float r = 0.024840285f * q + 0.18681418f;
80
+ float t = -0.094097948f * q - 0.33213072f;
81
+ r = r * s + t;
82
+ r = r * c + a;
83
+
84
+ // Map to full circle
85
+ if ( ay > ax )
86
+ {
87
+ r = 1.57079637f - r;
88
+ }
89
+
90
+ if ( x < 0 )
91
+ {
92
+ r = 3.14159274f - r;
93
+ }
94
+
95
+ if ( y < 0 )
96
+ {
97
+ r = -r;
98
+ }
99
+
100
+ return r;
101
+ }
102
+
103
+ // Approximate cosine and sine for determinism. In my testing cosf and sinf produced
104
+ // the same results on x64 and ARM using MSVC, GCC, and Clang. However, I don't trust
105
+ // this result.
106
+ // https://en.wikipedia.org/wiki/Bh%C4%81skara_I%27s_sine_approximation_formula
107
+ b2CosSin b2ComputeCosSin( float radians )
108
+ {
109
+ float x = b2UnwindLargeAngle( radians );
110
+ float pi2 = B2_PI * B2_PI;
111
+
112
+ // cosine needs angle in [-pi/2, pi/2]
113
+ float c;
114
+ if ( x < -0.5f * B2_PI )
115
+ {
116
+ float y = x + B2_PI;
117
+ float y2 = y * y;
118
+ c = -( pi2 - 4.0f * y2 ) / ( pi2 + y2 );
119
+ }
120
+ else if ( x > 0.5f * B2_PI )
121
+ {
122
+ float y = x - B2_PI;
123
+ float y2 = y * y;
124
+ c = -( pi2 - 4.0f * y2 ) / ( pi2 + y2 );
125
+ }
126
+ else
127
+ {
128
+ float y2 = x * x;
129
+ c = ( pi2 - 4.0f * y2 ) / ( pi2 + y2 );
130
+ }
131
+
132
+ // sine needs angle in [0, pi]
133
+ float s;
134
+ if ( x < 0.0f )
135
+ {
136
+ float y = x + B2_PI;
137
+ s = -16.0f * y * ( B2_PI - y ) / ( 5.0f * pi2 - 4.0f * y * ( B2_PI - y ) );
138
+ }
139
+ else
140
+ {
141
+ s = 16.0f * x * ( B2_PI - x ) / ( 5.0f * pi2 - 4.0f * x * ( B2_PI - x ) );
142
+ }
143
+
144
+ float mag = sqrtf( s * s + c * c );
145
+ float invMag = mag > 0.0 ? 1.0f / mag : 0.0f;
146
+ b2CosSin cs = { c * invMag, s * invMag };
147
+ return cs;
148
+ }
149
+
150
+ b2Rot b2ComputeRotationBetweenUnitVectors(b2Vec2 v1, b2Vec2 v2)
151
+ {
152
+ B2_ASSERT( b2AbsFloat( 1.0f - b2Length( v1 ) ) < 100.0f * FLT_EPSILON );
153
+ B2_ASSERT( b2AbsFloat( 1.0f - b2Length( v2 ) ) < 100.0f * FLT_EPSILON );
154
+
155
+ b2Rot rot;
156
+ rot.c = b2Dot( v1, v2 );
157
+ rot.s = b2Cross( v1, v2 );
158
+ return b2NormalizeRot( rot );
159
+ }
@@ -0,0 +1,283 @@
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
+ void b2MotorJoint_SetLinearOffset( b2JointId jointId, b2Vec2 linearOffset )
15
+ {
16
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
17
+ joint->motorJoint.linearOffset = linearOffset;
18
+ }
19
+
20
+ b2Vec2 b2MotorJoint_GetLinearOffset( b2JointId jointId )
21
+ {
22
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
23
+ return joint->motorJoint.linearOffset;
24
+ }
25
+
26
+ void b2MotorJoint_SetAngularOffset( b2JointId jointId, float angularOffset )
27
+ {
28
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
29
+ joint->motorJoint.angularOffset = b2ClampFloat( angularOffset, -B2_PI, B2_PI );
30
+ }
31
+
32
+ float b2MotorJoint_GetAngularOffset( b2JointId jointId )
33
+ {
34
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
35
+ return joint->motorJoint.angularOffset;
36
+ }
37
+
38
+ void b2MotorJoint_SetMaxForce( b2JointId jointId, float maxForce )
39
+ {
40
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
41
+ joint->motorJoint.maxForce = b2MaxFloat( 0.0f, maxForce );
42
+ }
43
+
44
+ float b2MotorJoint_GetMaxForce( b2JointId jointId )
45
+ {
46
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
47
+ return joint->motorJoint.maxForce;
48
+ }
49
+
50
+ void b2MotorJoint_SetMaxTorque( b2JointId jointId, float maxTorque )
51
+ {
52
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
53
+ joint->motorJoint.maxTorque = b2MaxFloat( 0.0f, maxTorque );
54
+ }
55
+
56
+ float b2MotorJoint_GetMaxTorque( b2JointId jointId )
57
+ {
58
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
59
+ return joint->motorJoint.maxTorque;
60
+ }
61
+
62
+ void b2MotorJoint_SetCorrectionFactor( b2JointId jointId, float correctionFactor )
63
+ {
64
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
65
+ joint->motorJoint.correctionFactor = b2ClampFloat( correctionFactor, 0.0f, 1.0f );
66
+ }
67
+
68
+ float b2MotorJoint_GetCorrectionFactor( b2JointId jointId )
69
+ {
70
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_motorJoint );
71
+ return joint->motorJoint.correctionFactor;
72
+ }
73
+
74
+ b2Vec2 b2GetMotorJointForce( b2World* world, b2JointSim* base )
75
+ {
76
+ b2Vec2 force = b2MulSV( world->inv_h, base->motorJoint.linearImpulse );
77
+ return force;
78
+ }
79
+
80
+ float b2GetMotorJointTorque( b2World* world, b2JointSim* base )
81
+ {
82
+ return world->inv_h * base->motorJoint.angularImpulse;
83
+ }
84
+
85
+ // Point-to-point constraint
86
+ // C = p2 - p1
87
+ // Cdot = v2 - v1
88
+ // = v2 + cross(w2, r2) - v1 - cross(w1, r1)
89
+ // J = [-I -r1_skew I r2_skew ]
90
+ // Identity used:
91
+ // w k % (rx i + ry j) = w * (-ry i + rx j)
92
+
93
+ // Angle constraint
94
+ // C = angle2 - angle1 - referenceAngle
95
+ // Cdot = w2 - w1
96
+ // J = [0 0 -1 0 0 1]
97
+ // K = invI1 + invI2
98
+
99
+ void b2PrepareMotorJoint( b2JointSim* base, b2StepContext* context )
100
+ {
101
+ B2_ASSERT( base->type == b2_motorJoint );
102
+
103
+ // chase body id to the solver set where the body lives
104
+ int idA = base->bodyIdA;
105
+ int idB = base->bodyIdB;
106
+
107
+ b2World* world = context->world;
108
+
109
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, idA );
110
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, idB );
111
+
112
+ B2_ASSERT( bodyA->setIndex == b2_awakeSet || bodyB->setIndex == b2_awakeSet );
113
+
114
+ b2SolverSet* setA = b2SolverSetArray_Get( &world->solverSets, bodyA->setIndex );
115
+ b2SolverSet* setB = b2SolverSetArray_Get( &world->solverSets, bodyB->setIndex );
116
+
117
+ int localIndexA = bodyA->localIndex;
118
+ int localIndexB = bodyB->localIndex;
119
+
120
+ b2BodySim* bodySimA = b2BodySimArray_Get( &setA->bodySims, localIndexA );
121
+ b2BodySim* bodySimB = b2BodySimArray_Get( &setB->bodySims, localIndexB );
122
+
123
+ float mA = bodySimA->invMass;
124
+ float iA = bodySimA->invInertia;
125
+ float mB = bodySimB->invMass;
126
+ float iB = bodySimB->invInertia;
127
+
128
+ base->invMassA = mA;
129
+ base->invMassB = mB;
130
+ base->invIA = iA;
131
+ base->invIB = iB;
132
+
133
+ b2MotorJoint* joint = &base->motorJoint;
134
+ joint->indexA = bodyA->setIndex == b2_awakeSet ? localIndexA : B2_NULL_INDEX;
135
+ joint->indexB = bodyB->setIndex == b2_awakeSet ? localIndexB : B2_NULL_INDEX;
136
+
137
+ joint->anchorA = b2RotateVector( bodySimA->transform.q, b2Sub( base->localOriginAnchorA, bodySimA->localCenter ) );
138
+ joint->anchorB = b2RotateVector( bodySimB->transform.q, b2Sub( base->localOriginAnchorB, bodySimB->localCenter ) );
139
+ joint->deltaCenter = b2Sub( b2Sub( bodySimB->center, bodySimA->center ), joint->linearOffset );
140
+ joint->deltaAngle = b2RelativeAngle( bodySimB->transform.q, bodySimA->transform.q ) - joint->angularOffset;
141
+ joint->deltaAngle = b2UnwindAngle( joint->deltaAngle );
142
+
143
+ b2Vec2 rA = joint->anchorA;
144
+ b2Vec2 rB = joint->anchorB;
145
+
146
+ b2Mat22 K;
147
+ K.cx.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
148
+ K.cx.y = -rA.y * rA.x * iA - rB.y * rB.x * iB;
149
+ K.cy.x = K.cx.y;
150
+ K.cy.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
151
+ joint->linearMass = b2GetInverse22( K );
152
+
153
+ float ka = iA + iB;
154
+ joint->angularMass = ka > 0.0f ? 1.0f / ka : 0.0f;
155
+
156
+ if ( context->enableWarmStarting == false )
157
+ {
158
+ joint->linearImpulse = b2Vec2_zero;
159
+ joint->angularImpulse = 0.0f;
160
+ }
161
+ }
162
+
163
+ void b2WarmStartMotorJoint( b2JointSim* base, b2StepContext* context )
164
+ {
165
+ float mA = base->invMassA;
166
+ float mB = base->invMassB;
167
+ float iA = base->invIA;
168
+ float iB = base->invIB;
169
+
170
+ b2MotorJoint* joint = &base->motorJoint;
171
+
172
+ // dummy state for static bodies
173
+ b2BodyState dummyState = b2_identityBodyState;
174
+
175
+ b2BodyState* bodyA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
176
+ b2BodyState* bodyB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
177
+
178
+ b2Vec2 rA = b2RotateVector( bodyA->deltaRotation, joint->anchorA );
179
+ b2Vec2 rB = b2RotateVector( bodyB->deltaRotation, joint->anchorB );
180
+
181
+ bodyA->linearVelocity = b2MulSub( bodyA->linearVelocity, mA, joint->linearImpulse );
182
+ bodyA->angularVelocity -= iA * ( b2Cross( rA, joint->linearImpulse ) + joint->angularImpulse );
183
+ bodyB->linearVelocity = b2MulAdd( bodyB->linearVelocity, mB, joint->linearImpulse );
184
+ bodyB->angularVelocity += iB * ( b2Cross( rB, joint->linearImpulse ) + joint->angularImpulse );
185
+ }
186
+
187
+ void b2SolveMotorJoint( b2JointSim* base, b2StepContext* context, bool useBias )
188
+ {
189
+ B2_UNUSED( useBias );
190
+ B2_ASSERT( base->type == b2_motorJoint );
191
+
192
+ float mA = base->invMassA;
193
+ float mB = base->invMassB;
194
+ float iA = base->invIA;
195
+ float iB = base->invIB;
196
+
197
+ // dummy state for static bodies
198
+ b2BodyState dummyState = b2_identityBodyState;
199
+
200
+ b2MotorJoint* joint = &base->motorJoint;
201
+ b2BodyState* bodyA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
202
+ b2BodyState* bodyB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
203
+
204
+ b2Vec2 vA = bodyA->linearVelocity;
205
+ float wA = bodyA->angularVelocity;
206
+ b2Vec2 vB = bodyB->linearVelocity;
207
+ float wB = bodyB->angularVelocity;
208
+
209
+ // angular constraint
210
+ {
211
+ float angularSeperation = b2RelativeAngle( bodyB->deltaRotation, bodyA->deltaRotation ) + joint->deltaAngle;
212
+ angularSeperation = b2UnwindAngle( angularSeperation );
213
+
214
+ float angularBias = context->inv_h * joint->correctionFactor * angularSeperation;
215
+
216
+ float Cdot = wB - wA;
217
+ float impulse = -joint->angularMass * ( Cdot + angularBias );
218
+
219
+ float oldImpulse = joint->angularImpulse;
220
+ float maxImpulse = context->h * joint->maxTorque;
221
+ joint->angularImpulse = b2ClampFloat( joint->angularImpulse + impulse, -maxImpulse, maxImpulse );
222
+ impulse = joint->angularImpulse - oldImpulse;
223
+
224
+ wA -= iA * impulse;
225
+ wB += iB * impulse;
226
+ }
227
+
228
+ // linear constraint
229
+ {
230
+ b2Vec2 rA = b2RotateVector( bodyA->deltaRotation, joint->anchorA );
231
+ b2Vec2 rB = b2RotateVector( bodyB->deltaRotation, joint->anchorB );
232
+
233
+ b2Vec2 ds = b2Add( b2Sub( bodyB->deltaPosition, bodyA->deltaPosition ), b2Sub( rB, rA ) );
234
+ b2Vec2 linearSeparation = b2Add( joint->deltaCenter, ds );
235
+ b2Vec2 linearBias = b2MulSV( context->inv_h * joint->correctionFactor, linearSeparation );
236
+
237
+ b2Vec2 Cdot = b2Sub( b2Add( vB, b2CrossSV( wB, rB ) ), b2Add( vA, b2CrossSV( wA, rA ) ) );
238
+ b2Vec2 b = b2MulMV( joint->linearMass, b2Add( Cdot, linearBias ) );
239
+ b2Vec2 impulse = { -b.x, -b.y };
240
+
241
+ b2Vec2 oldImpulse = joint->linearImpulse;
242
+ float maxImpulse = context->h * joint->maxForce;
243
+ joint->linearImpulse = b2Add( joint->linearImpulse, impulse );
244
+
245
+ if ( b2LengthSquared( joint->linearImpulse ) > maxImpulse * maxImpulse )
246
+ {
247
+ joint->linearImpulse = b2Normalize( joint->linearImpulse );
248
+ joint->linearImpulse.x *= maxImpulse;
249
+ joint->linearImpulse.y *= maxImpulse;
250
+ }
251
+
252
+ impulse = b2Sub( joint->linearImpulse, oldImpulse );
253
+
254
+ vA = b2MulSub( vA, mA, impulse );
255
+ wA -= iA * b2Cross( rA, impulse );
256
+ vB = b2MulAdd( vB, mB, impulse );
257
+ wB += iB * b2Cross( rB, impulse );
258
+ }
259
+
260
+ bodyA->linearVelocity = vA;
261
+ bodyA->angularVelocity = wA;
262
+ bodyB->linearVelocity = vB;
263
+ bodyB->angularVelocity = wB;
264
+ }
265
+
266
+ #if 0
267
+ void b2DumpMotorJoint()
268
+ {
269
+ int32 indexA = m_bodyA->m_islandIndex;
270
+ int32 indexB = m_bodyB->m_islandIndex;
271
+
272
+ b2Dump(" b2MotorJointDef jd;\n");
273
+ b2Dump(" jd.bodyA = sims[%d];\n", indexA);
274
+ b2Dump(" jd.bodyB = sims[%d];\n", indexB);
275
+ b2Dump(" jd.collideConnected = bool(%d);\n", m_collideConnected);
276
+ b2Dump(" jd.localAnchorA.Set(%.9g, %.9g);\n", m_localAnchorA.x, m_localAnchorA.y);
277
+ b2Dump(" jd.localAnchorB.Set(%.9g, %.9g);\n", m_localAnchorB.x, m_localAnchorB.y);
278
+ b2Dump(" jd.referenceAngle = %.9g;\n", m_referenceAngle);
279
+ b2Dump(" jd.stiffness = %.9g;\n", m_stiffness);
280
+ b2Dump(" jd.damping = %.9g;\n", m_damping);
281
+ b2Dump(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
282
+ }
283
+ #endif
@@ -0,0 +1,214 @@
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
+ void b2MouseJoint_SetTarget( b2JointId jointId, b2Vec2 target )
15
+ {
16
+ B2_ASSERT( b2IsValidVec2( target ) );
17
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
18
+ base->mouseJoint.targetA = target;
19
+ }
20
+
21
+ b2Vec2 b2MouseJoint_GetTarget( b2JointId jointId )
22
+ {
23
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
24
+ return base->mouseJoint.targetA;
25
+ }
26
+
27
+ void b2MouseJoint_SetSpringHertz( b2JointId jointId, float hertz )
28
+ {
29
+ B2_ASSERT( b2IsValidFloat( hertz ) && hertz >= 0.0f );
30
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
31
+ base->mouseJoint.hertz = hertz;
32
+ }
33
+
34
+ float b2MouseJoint_GetSpringHertz( b2JointId jointId )
35
+ {
36
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
37
+ return base->mouseJoint.hertz;
38
+ }
39
+
40
+ void b2MouseJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio )
41
+ {
42
+ B2_ASSERT( b2IsValidFloat( dampingRatio ) && dampingRatio >= 0.0f );
43
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
44
+ base->mouseJoint.dampingRatio = dampingRatio;
45
+ }
46
+
47
+ float b2MouseJoint_GetSpringDampingRatio( b2JointId jointId )
48
+ {
49
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
50
+ return base->mouseJoint.dampingRatio;
51
+ }
52
+
53
+ void b2MouseJoint_SetMaxForce( b2JointId jointId, float maxForce )
54
+ {
55
+ B2_ASSERT( b2IsValidFloat( maxForce ) && maxForce >= 0.0f );
56
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
57
+ base->mouseJoint.maxForce = maxForce;
58
+ }
59
+
60
+ float b2MouseJoint_GetMaxForce( b2JointId jointId )
61
+ {
62
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_mouseJoint );
63
+ return base->mouseJoint.maxForce;
64
+ }
65
+
66
+ b2Vec2 b2GetMouseJointForce( b2World* world, b2JointSim* base )
67
+ {
68
+ b2Vec2 force = b2MulSV( world->inv_h, base->mouseJoint.linearImpulse );
69
+ return force;
70
+ }
71
+
72
+ float b2GetMouseJointTorque( b2World* world, b2JointSim* base )
73
+ {
74
+ return world->inv_h * base->mouseJoint.angularImpulse;
75
+ }
76
+
77
+ void b2PrepareMouseJoint( b2JointSim* base, b2StepContext* context )
78
+ {
79
+ B2_ASSERT( base->type == b2_mouseJoint );
80
+
81
+ // chase body id to the solver set where the body lives
82
+ int idB = base->bodyIdB;
83
+
84
+ b2World* world = context->world;
85
+
86
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, idB );
87
+
88
+ B2_ASSERT( bodyB->setIndex == b2_awakeSet );
89
+ b2SolverSet* setB = b2SolverSetArray_Get( &world->solverSets, bodyB->setIndex );
90
+
91
+ int localIndexB = bodyB->localIndex;
92
+ b2BodySim* bodySimB = b2BodySimArray_Get( &setB->bodySims, localIndexB );
93
+
94
+ base->invMassB = bodySimB->invMass;
95
+ base->invIB = bodySimB->invInertia;
96
+
97
+ b2MouseJoint* joint = &base->mouseJoint;
98
+ joint->indexB = bodyB->setIndex == b2_awakeSet ? localIndexB : B2_NULL_INDEX;
99
+ joint->anchorB = b2RotateVector( bodySimB->transform.q, b2Sub( base->localOriginAnchorB, bodySimB->localCenter ) );
100
+
101
+ joint->linearSoftness = b2MakeSoft( joint->hertz, joint->dampingRatio, context->h );
102
+
103
+ float angularHertz = 0.5f;
104
+ float angularDampingRatio = 0.1f;
105
+ joint->angularSoftness = b2MakeSoft( angularHertz, angularDampingRatio, context->h );
106
+
107
+ b2Vec2 rB = joint->anchorB;
108
+ float mB = bodySimB->invMass;
109
+ float iB = bodySimB->invInertia;
110
+
111
+ // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
112
+ // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
113
+ // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
114
+ b2Mat22 K;
115
+ K.cx.x = mB + iB * rB.y * rB.y;
116
+ K.cx.y = -iB * rB.x * rB.y;
117
+ K.cy.x = K.cx.y;
118
+ K.cy.y = mB + iB * rB.x * rB.x;
119
+
120
+ joint->linearMass = b2GetInverse22( K );
121
+ joint->deltaCenter = b2Sub( bodySimB->center, joint->targetA );
122
+
123
+ if ( context->enableWarmStarting == false )
124
+ {
125
+ joint->linearImpulse = b2Vec2_zero;
126
+ joint->angularImpulse = 0.0f;
127
+ }
128
+ }
129
+
130
+ void b2WarmStartMouseJoint( b2JointSim* base, b2StepContext* context )
131
+ {
132
+ B2_ASSERT( base->type == b2_mouseJoint );
133
+
134
+ float mB = base->invMassB;
135
+ float iB = base->invIB;
136
+
137
+ b2MouseJoint* joint = &base->mouseJoint;
138
+
139
+ b2BodyState* stateB = context->states + joint->indexB;
140
+ b2Vec2 vB = stateB->linearVelocity;
141
+ float wB = stateB->angularVelocity;
142
+
143
+ b2Rot dqB = stateB->deltaRotation;
144
+ b2Vec2 rB = b2RotateVector( dqB, joint->anchorB );
145
+
146
+ vB = b2MulAdd( vB, mB, joint->linearImpulse );
147
+ wB += iB * ( b2Cross( rB, joint->linearImpulse ) + joint->angularImpulse );
148
+
149
+ stateB->linearVelocity = vB;
150
+ stateB->angularVelocity = wB;
151
+ }
152
+
153
+ void b2SolveMouseJoint( b2JointSim* base, b2StepContext* context )
154
+ {
155
+ float mB = base->invMassB;
156
+ float iB = base->invIB;
157
+
158
+ b2MouseJoint* joint = &base->mouseJoint;
159
+ b2BodyState* stateB = context->states + joint->indexB;
160
+
161
+ b2Vec2 vB = stateB->linearVelocity;
162
+ float wB = stateB->angularVelocity;
163
+
164
+ // Softness with no bias to reduce rotation speed
165
+ {
166
+ float massScale = joint->angularSoftness.massScale;
167
+ float impulseScale = joint->angularSoftness.impulseScale;
168
+
169
+ float impulse = iB > 0.0f ? -wB / iB : 0.0f;
170
+ impulse = massScale * impulse - impulseScale * joint->angularImpulse;
171
+ joint->angularImpulse += impulse;
172
+
173
+ wB += iB * impulse;
174
+ }
175
+
176
+ float maxImpulse = joint->maxForce * context->h;
177
+
178
+ {
179
+ b2Rot dqB = stateB->deltaRotation;
180
+ b2Vec2 rB = b2RotateVector( dqB, joint->anchorB );
181
+ b2Vec2 Cdot = b2Add( vB, b2CrossSV( wB, rB ) );
182
+
183
+ b2Vec2 separation = b2Add( b2Add( stateB->deltaPosition, rB ), joint->deltaCenter );
184
+ b2Vec2 bias = b2MulSV( joint->linearSoftness.biasRate, separation );
185
+
186
+ float massScale = joint->linearSoftness.massScale;
187
+ float impulseScale = joint->linearSoftness.impulseScale;
188
+
189
+ b2Vec2 b = b2MulMV( joint->linearMass, b2Add( Cdot, bias ) );
190
+
191
+ b2Vec2 impulse;
192
+ impulse.x = -massScale * b.x - impulseScale * joint->linearImpulse.x;
193
+ impulse.y = -massScale * b.y - impulseScale * joint->linearImpulse.y;
194
+
195
+ b2Vec2 oldImpulse = joint->linearImpulse;
196
+ joint->linearImpulse.x += impulse.x;
197
+ joint->linearImpulse.y += impulse.y;
198
+
199
+ float mag = b2Length( joint->linearImpulse );
200
+ if ( mag > maxImpulse )
201
+ {
202
+ joint->linearImpulse = b2MulSV( maxImpulse, b2Normalize( joint->linearImpulse ) );
203
+ }
204
+
205
+ impulse.x = joint->linearImpulse.x - oldImpulse.x;
206
+ impulse.y = joint->linearImpulse.y - oldImpulse.y;
207
+
208
+ vB = b2MulAdd( vB, mB, impulse );
209
+ wB += iB * b2Cross( rB, impulse );
210
+ }
211
+
212
+ stateB->linearVelocity = vB;
213
+ stateB->angularVelocity = wB;
214
+ }