box2d-ruby 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +336 -0
- data/examples/contact_events.rb +22 -0
- data/examples/debug_draw.rb +15 -0
- data/examples/falling_ball.rb +19 -0
- data/examples/rugl_debug_draw.rb +68 -0
- data/examples/stagecraft_debug_draw.rb +64 -0
- data/examples/support/box2d_debug_lines.rb +125 -0
- data/ext/box2d/CMakeLists.txt +35 -0
- data/ext/box2d/extconf.rb +42 -0
- data/ext/box2d/native.c +9 -0
- data/ext/box2d/vendor/box2d/LICENSE +21 -0
- data/ext/box2d/vendor/box2d/VERSION +1 -0
- data/ext/box2d/vendor/box2d/include/box2d/base.h +131 -0
- data/ext/box2d/vendor/box2d/include/box2d/box2d.h +1222 -0
- data/ext/box2d/vendor/box2d/include/box2d/collision.h +830 -0
- data/ext/box2d/vendor/box2d/include/box2d/id.h +144 -0
- data/ext/box2d/vendor/box2d/include/box2d/math_functions.h +761 -0
- data/ext/box2d/vendor/box2d/include/box2d/types.h +1457 -0
- data/ext/box2d/vendor/box2d/src/CMakeLists.txt +223 -0
- data/ext/box2d/vendor/box2d/src/aabb.c +132 -0
- data/ext/box2d/vendor/box2d/src/aabb.h +56 -0
- data/ext/box2d/vendor/box2d/src/arena_allocator.c +112 -0
- data/ext/box2d/vendor/box2d/src/arena_allocator.h +48 -0
- data/ext/box2d/vendor/box2d/src/array.c +8 -0
- data/ext/box2d/vendor/box2d/src/array.h +179 -0
- data/ext/box2d/vendor/box2d/src/atomic.h +79 -0
- data/ext/box2d/vendor/box2d/src/bitset.c +67 -0
- data/ext/box2d/vendor/box2d/src/bitset.h +65 -0
- data/ext/box2d/vendor/box2d/src/body.c +1884 -0
- data/ext/box2d/vendor/box2d/src/body.h +194 -0
- data/ext/box2d/vendor/box2d/src/box2d.natvis +41 -0
- data/ext/box2d/vendor/box2d/src/broad_phase.c +524 -0
- data/ext/box2d/vendor/box2d/src/broad_phase.h +83 -0
- data/ext/box2d/vendor/box2d/src/constants.h +54 -0
- data/ext/box2d/vendor/box2d/src/constraint_graph.c +322 -0
- data/ext/box2d/vendor/box2d/src/constraint_graph.h +58 -0
- data/ext/box2d/vendor/box2d/src/contact.c +650 -0
- data/ext/box2d/vendor/box2d/src/contact.h +148 -0
- data/ext/box2d/vendor/box2d/src/contact_solver.c +2120 -0
- data/ext/box2d/vendor/box2d/src/contact_solver.h +54 -0
- data/ext/box2d/vendor/box2d/src/core.c +178 -0
- data/ext/box2d/vendor/box2d/src/core.h +149 -0
- data/ext/box2d/vendor/box2d/src/ctz.h +112 -0
- data/ext/box2d/vendor/box2d/src/distance.c +1415 -0
- data/ext/box2d/vendor/box2d/src/distance_joint.c +556 -0
- data/ext/box2d/vendor/box2d/src/dynamic_tree.c +1989 -0
- data/ext/box2d/vendor/box2d/src/geometry.c +1028 -0
- data/ext/box2d/vendor/box2d/src/hull.c +328 -0
- data/ext/box2d/vendor/box2d/src/id_pool.c +79 -0
- data/ext/box2d/vendor/box2d/src/id_pool.h +35 -0
- data/ext/box2d/vendor/box2d/src/island.c +977 -0
- data/ext/box2d/vendor/box2d/src/island.h +89 -0
- data/ext/box2d/vendor/box2d/src/joint.c +1272 -0
- data/ext/box2d/vendor/box2d/src/joint.h +335 -0
- data/ext/box2d/vendor/box2d/src/manifold.c +1726 -0
- data/ext/box2d/vendor/box2d/src/math_functions.c +159 -0
- data/ext/box2d/vendor/box2d/src/motor_joint.c +283 -0
- data/ext/box2d/vendor/box2d/src/mouse_joint.c +214 -0
- data/ext/box2d/vendor/box2d/src/mover.c +73 -0
- data/ext/box2d/vendor/box2d/src/prismatic_joint.c +656 -0
- data/ext/box2d/vendor/box2d/src/revolute_joint.c +534 -0
- data/ext/box2d/vendor/box2d/src/sensor.c +389 -0
- data/ext/box2d/vendor/box2d/src/sensor.h +36 -0
- data/ext/box2d/vendor/box2d/src/shape.c +1714 -0
- data/ext/box2d/vendor/box2d/src/shape.h +123 -0
- data/ext/box2d/vendor/box2d/src/solver.c +2038 -0
- data/ext/box2d/vendor/box2d/src/solver.h +155 -0
- data/ext/box2d/vendor/box2d/src/solver_set.c +613 -0
- data/ext/box2d/vendor/box2d/src/solver_set.h +57 -0
- data/ext/box2d/vendor/box2d/src/table.c +238 -0
- data/ext/box2d/vendor/box2d/src/table.h +37 -0
- data/ext/box2d/vendor/box2d/src/timer.c +185 -0
- data/ext/box2d/vendor/box2d/src/types.c +151 -0
- data/ext/box2d/vendor/box2d/src/weld_joint.c +310 -0
- data/ext/box2d/vendor/box2d/src/wheel_joint.c +551 -0
- data/ext/box2d/vendor/box2d/src/world.c +3301 -0
- data/ext/box2d/vendor/box2d/src/world.h +192 -0
- data/generator/generate.rb +316 -0
- data/generator/layout_probe.c +507 -0
- data/generator/verify_layouts.rb +32 -0
- data/lib/box2d/body.rb +172 -0
- data/lib/box2d/body_definition.rb +38 -0
- data/lib/box2d/body_shapes.rb +135 -0
- data/lib/box2d/chain.rb +61 -0
- data/lib/box2d/debug_draw.rb +118 -0
- data/lib/box2d/events.rb +103 -0
- data/lib/box2d/fixed_stepper.rb +39 -0
- data/lib/box2d/handle.rb +46 -0
- data/lib/box2d/hit.rb +5 -0
- data/lib/box2d/joint.rb +197 -0
- data/lib/box2d/native.rb +1462 -0
- data/lib/box2d/native_loader.rb +45 -0
- data/lib/box2d/pixel_scale.rb +29 -0
- data/lib/box2d/shape.rb +109 -0
- data/lib/box2d/shape_definition.rb +44 -0
- data/lib/box2d/value_conversion.rb +80 -0
- data/lib/box2d/version.rb +7 -0
- data/lib/box2d/world.rb +135 -0
- data/lib/box2d/world_joints.rb +156 -0
- data/lib/box2d/world_queries.rb +122 -0
- data/lib/box2d/world_registry.rb +95 -0
- data/lib/box2d.rb +31 -0
- data/script/build_platform_gem.rb +24 -0
- data/script/deterministic_scene.rb +56 -0
- data/script/update_deterministic_snapshot.rb +11 -0
- data/script/verify_platform_gem.rb +24 -0
- metadata +164 -0
|
@@ -0,0 +1,2120 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Erin Catto
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
#include "contact_solver.h"
|
|
5
|
+
|
|
6
|
+
#include "body.h"
|
|
7
|
+
#include "constraint_graph.h"
|
|
8
|
+
#include "contact.h"
|
|
9
|
+
#include "core.h"
|
|
10
|
+
#include "solver_set.h"
|
|
11
|
+
#include "world.h"
|
|
12
|
+
|
|
13
|
+
#include <stddef.h>
|
|
14
|
+
|
|
15
|
+
// contact separation for sub-stepping
|
|
16
|
+
// s = s0 + dot(cB + rB - cA - rA, normal)
|
|
17
|
+
// normal is held constant
|
|
18
|
+
// body positions c can translation and anchors r can rotate
|
|
19
|
+
// s(t) = s0 + dot(cB(t) + rB(t) - cA(t) - rA(t), normal)
|
|
20
|
+
// s(t) = s0 + dot(cB0 + dpB + rot(dqB, rB0) - cA0 - dpA - rot(dqA, rA0), normal)
|
|
21
|
+
// s(t) = s0 + dot(cB0 - cA0, normal) + dot(dpB - dpA + rot(dqB, rB0) - rot(dqA, rA0), normal)
|
|
22
|
+
// s_base = s0 + dot(cB0 - cA0, normal)
|
|
23
|
+
|
|
24
|
+
void b2PrepareOverflowContacts( b2StepContext* context )
|
|
25
|
+
{
|
|
26
|
+
b2TracyCZoneNC( prepare_overflow_contact, "Prepare Overflow Contact", b2_colorYellow, true );
|
|
27
|
+
|
|
28
|
+
b2World* world = context->world;
|
|
29
|
+
b2ConstraintGraph* graph = context->graph;
|
|
30
|
+
b2GraphColor* color = graph->colors + B2_OVERFLOW_INDEX;
|
|
31
|
+
b2ContactConstraint* constraints = color->overflowConstraints;
|
|
32
|
+
int contactCount = color->contactSims.count;
|
|
33
|
+
b2ContactSim* contacts = color->contactSims.data;
|
|
34
|
+
b2BodyState* awakeStates = context->states;
|
|
35
|
+
|
|
36
|
+
#if B2_VALIDATE
|
|
37
|
+
b2Body* bodies = world->bodies.data;
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
// Stiffer for static contacts to avoid bodies getting pushed through the ground
|
|
41
|
+
b2Softness contactSoftness = context->contactSoftness;
|
|
42
|
+
b2Softness staticSoftness = context->staticSoftness;
|
|
43
|
+
|
|
44
|
+
float warmStartScale = world->enableWarmStarting ? 1.0f : 0.0f;
|
|
45
|
+
|
|
46
|
+
for ( int i = 0; i < contactCount; ++i )
|
|
47
|
+
{
|
|
48
|
+
b2ContactSim* contactSim = contacts + i;
|
|
49
|
+
|
|
50
|
+
const b2Manifold* manifold = &contactSim->manifold;
|
|
51
|
+
int pointCount = manifold->pointCount;
|
|
52
|
+
|
|
53
|
+
B2_ASSERT( 0 < pointCount && pointCount <= 2 );
|
|
54
|
+
|
|
55
|
+
int indexA = contactSim->bodySimIndexA;
|
|
56
|
+
int indexB = contactSim->bodySimIndexB;
|
|
57
|
+
|
|
58
|
+
#if B2_VALIDATE
|
|
59
|
+
b2Body* bodyA = bodies + contactSim->bodyIdA;
|
|
60
|
+
int validIndexA = bodyA->setIndex == b2_awakeSet ? bodyA->localIndex : B2_NULL_INDEX;
|
|
61
|
+
B2_ASSERT( indexA == validIndexA );
|
|
62
|
+
|
|
63
|
+
b2Body* bodyB = bodies + contactSim->bodyIdB;
|
|
64
|
+
int validIndexB = bodyB->setIndex == b2_awakeSet ? bodyB->localIndex : B2_NULL_INDEX;
|
|
65
|
+
B2_ASSERT( indexB == validIndexB );
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
b2ContactConstraint* constraint = constraints + i;
|
|
69
|
+
constraint->indexA = indexA;
|
|
70
|
+
constraint->indexB = indexB;
|
|
71
|
+
constraint->normal = manifold->normal;
|
|
72
|
+
constraint->friction = contactSim->friction;
|
|
73
|
+
constraint->restitution = contactSim->restitution;
|
|
74
|
+
constraint->rollingResistance = contactSim->rollingResistance;
|
|
75
|
+
constraint->rollingImpulse = warmStartScale * manifold->rollingImpulse;
|
|
76
|
+
constraint->tangentSpeed = contactSim->tangentSpeed;
|
|
77
|
+
constraint->pointCount = pointCount;
|
|
78
|
+
|
|
79
|
+
b2Vec2 vA = b2Vec2_zero;
|
|
80
|
+
float wA = 0.0f;
|
|
81
|
+
float mA = contactSim->invMassA;
|
|
82
|
+
float iA = contactSim->invIA;
|
|
83
|
+
if ( indexA != B2_NULL_INDEX )
|
|
84
|
+
{
|
|
85
|
+
b2BodyState* stateA = awakeStates + indexA;
|
|
86
|
+
vA = stateA->linearVelocity;
|
|
87
|
+
wA = stateA->angularVelocity;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
b2Vec2 vB = b2Vec2_zero;
|
|
91
|
+
float wB = 0.0f;
|
|
92
|
+
float mB = contactSim->invMassB;
|
|
93
|
+
float iB = contactSim->invIB;
|
|
94
|
+
if ( indexB != B2_NULL_INDEX )
|
|
95
|
+
{
|
|
96
|
+
b2BodyState* stateB = awakeStates + indexB;
|
|
97
|
+
vB = stateB->linearVelocity;
|
|
98
|
+
wB = stateB->angularVelocity;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if ( indexA == B2_NULL_INDEX || indexB == B2_NULL_INDEX )
|
|
102
|
+
{
|
|
103
|
+
constraint->softness = staticSoftness;
|
|
104
|
+
}
|
|
105
|
+
else
|
|
106
|
+
{
|
|
107
|
+
constraint->softness = contactSoftness;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// copy mass into constraint to avoid cache misses during sub-stepping
|
|
111
|
+
constraint->invMassA = mA;
|
|
112
|
+
constraint->invIA = iA;
|
|
113
|
+
constraint->invMassB = mB;
|
|
114
|
+
constraint->invIB = iB;
|
|
115
|
+
|
|
116
|
+
{
|
|
117
|
+
float k = iA + iB;
|
|
118
|
+
constraint->rollingMass = k > 0.0f ? 1.0f / k : 0.0f;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
b2Vec2 normal = constraint->normal;
|
|
122
|
+
b2Vec2 tangent = b2RightPerp( constraint->normal );
|
|
123
|
+
|
|
124
|
+
for ( int j = 0; j < pointCount; ++j )
|
|
125
|
+
{
|
|
126
|
+
const b2ManifoldPoint* mp = manifold->points + j;
|
|
127
|
+
b2ContactConstraintPoint* cp = constraint->points + j;
|
|
128
|
+
|
|
129
|
+
cp->normalImpulse = warmStartScale * mp->normalImpulse;
|
|
130
|
+
cp->tangentImpulse = warmStartScale * mp->tangentImpulse;
|
|
131
|
+
cp->totalNormalImpulse = 0.0f;
|
|
132
|
+
|
|
133
|
+
b2Vec2 rA = mp->anchorA;
|
|
134
|
+
b2Vec2 rB = mp->anchorB;
|
|
135
|
+
|
|
136
|
+
cp->anchorA = rA;
|
|
137
|
+
cp->anchorB = rB;
|
|
138
|
+
cp->baseSeparation = mp->separation - b2Dot( b2Sub( rB, rA ), normal );
|
|
139
|
+
|
|
140
|
+
float rnA = b2Cross( rA, normal );
|
|
141
|
+
float rnB = b2Cross( rB, normal );
|
|
142
|
+
float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
|
143
|
+
cp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
|
|
144
|
+
|
|
145
|
+
float rtA = b2Cross( rA, tangent );
|
|
146
|
+
float rtB = b2Cross( rB, tangent );
|
|
147
|
+
float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
|
|
148
|
+
cp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;
|
|
149
|
+
|
|
150
|
+
// Save relative velocity for restitution
|
|
151
|
+
b2Vec2 vrA = b2Add( vA, b2CrossSV( wA, rA ) );
|
|
152
|
+
b2Vec2 vrB = b2Add( vB, b2CrossSV( wB, rB ) );
|
|
153
|
+
cp->relativeVelocity = b2Dot( normal, b2Sub( vrB, vrA ) );
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
b2TracyCZoneEnd( prepare_overflow_contact );
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
void b2WarmStartOverflowContacts( b2StepContext* context )
|
|
161
|
+
{
|
|
162
|
+
b2TracyCZoneNC( warmstart_overflow_contact, "WarmStart Overflow Contact", b2_colorDarkOrange, true );
|
|
163
|
+
|
|
164
|
+
b2ConstraintGraph* graph = context->graph;
|
|
165
|
+
b2GraphColor* color = graph->colors + B2_OVERFLOW_INDEX;
|
|
166
|
+
b2ContactConstraint* constraints = color->overflowConstraints;
|
|
167
|
+
int contactCount = color->contactSims.count;
|
|
168
|
+
b2World* world = context->world;
|
|
169
|
+
b2SolverSet* awakeSet = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
170
|
+
b2BodyState* states = awakeSet->bodyStates.data;
|
|
171
|
+
|
|
172
|
+
// This is a dummy state to represent a static body because static bodies don't have a solver body.
|
|
173
|
+
b2BodyState dummyState = b2_identityBodyState;
|
|
174
|
+
|
|
175
|
+
for ( int i = 0; i < contactCount; ++i )
|
|
176
|
+
{
|
|
177
|
+
const b2ContactConstraint* constraint = constraints + i;
|
|
178
|
+
|
|
179
|
+
int indexA = constraint->indexA;
|
|
180
|
+
int indexB = constraint->indexB;
|
|
181
|
+
|
|
182
|
+
b2BodyState* stateA = indexA == B2_NULL_INDEX ? &dummyState : states + indexA;
|
|
183
|
+
b2BodyState* stateB = indexB == B2_NULL_INDEX ? &dummyState : states + indexB;
|
|
184
|
+
|
|
185
|
+
b2Vec2 vA = stateA->linearVelocity;
|
|
186
|
+
float wA = stateA->angularVelocity;
|
|
187
|
+
b2Vec2 vB = stateB->linearVelocity;
|
|
188
|
+
float wB = stateB->angularVelocity;
|
|
189
|
+
|
|
190
|
+
float mA = constraint->invMassA;
|
|
191
|
+
float iA = constraint->invIA;
|
|
192
|
+
float mB = constraint->invMassB;
|
|
193
|
+
float iB = constraint->invIB;
|
|
194
|
+
|
|
195
|
+
// Stiffer for static contacts to avoid bodies getting pushed through the ground
|
|
196
|
+
b2Vec2 normal = constraint->normal;
|
|
197
|
+
b2Vec2 tangent = b2RightPerp( constraint->normal );
|
|
198
|
+
int pointCount = constraint->pointCount;
|
|
199
|
+
|
|
200
|
+
for ( int j = 0; j < pointCount; ++j )
|
|
201
|
+
{
|
|
202
|
+
const b2ContactConstraintPoint* cp = constraint->points + j;
|
|
203
|
+
|
|
204
|
+
// fixed anchors
|
|
205
|
+
b2Vec2 rA = cp->anchorA;
|
|
206
|
+
b2Vec2 rB = cp->anchorB;
|
|
207
|
+
|
|
208
|
+
b2Vec2 P = b2Add( b2MulSV( cp->normalImpulse, normal ), b2MulSV( cp->tangentImpulse, tangent ) );
|
|
209
|
+
wA -= iA * b2Cross( rA, P );
|
|
210
|
+
vA = b2MulAdd( vA, -mA, P );
|
|
211
|
+
wB += iB * b2Cross( rB, P );
|
|
212
|
+
vB = b2MulAdd( vB, mB, P );
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
wA -= iA * constraint->rollingImpulse;
|
|
216
|
+
wB += iB * constraint->rollingImpulse;
|
|
217
|
+
|
|
218
|
+
stateA->linearVelocity = vA;
|
|
219
|
+
stateA->angularVelocity = wA;
|
|
220
|
+
stateB->linearVelocity = vB;
|
|
221
|
+
stateB->angularVelocity = wB;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
b2TracyCZoneEnd( warmstart_overflow_contact );
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
void b2SolveOverflowContacts( b2StepContext* context, bool useBias )
|
|
228
|
+
{
|
|
229
|
+
b2TracyCZoneNC( solve_contact, "Solve Contact", b2_colorAliceBlue, true );
|
|
230
|
+
|
|
231
|
+
b2ConstraintGraph* graph = context->graph;
|
|
232
|
+
b2GraphColor* color = graph->colors + B2_OVERFLOW_INDEX;
|
|
233
|
+
b2ContactConstraint* constraints = color->overflowConstraints;
|
|
234
|
+
int contactCount = color->contactSims.count;
|
|
235
|
+
b2World* world = context->world;
|
|
236
|
+
b2SolverSet* awakeSet = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
237
|
+
b2BodyState* states = awakeSet->bodyStates.data;
|
|
238
|
+
|
|
239
|
+
float inv_h = context->inv_h;
|
|
240
|
+
const float pushout = context->world->maxContactPushSpeed;
|
|
241
|
+
|
|
242
|
+
// This is a dummy body to represent a static body since static bodies don't have a solver body.
|
|
243
|
+
b2BodyState dummyState = b2_identityBodyState;
|
|
244
|
+
|
|
245
|
+
for ( int i = 0; i < contactCount; ++i )
|
|
246
|
+
{
|
|
247
|
+
b2ContactConstraint* constraint = constraints + i;
|
|
248
|
+
float mA = constraint->invMassA;
|
|
249
|
+
float iA = constraint->invIA;
|
|
250
|
+
float mB = constraint->invMassB;
|
|
251
|
+
float iB = constraint->invIB;
|
|
252
|
+
|
|
253
|
+
b2BodyState* stateA = constraint->indexA == B2_NULL_INDEX ? &dummyState : states + constraint->indexA;
|
|
254
|
+
b2Vec2 vA = stateA->linearVelocity;
|
|
255
|
+
float wA = stateA->angularVelocity;
|
|
256
|
+
b2Rot dqA = stateA->deltaRotation;
|
|
257
|
+
|
|
258
|
+
b2BodyState* stateB = constraint->indexB == B2_NULL_INDEX ? &dummyState : states + constraint->indexB;
|
|
259
|
+
b2Vec2 vB = stateB->linearVelocity;
|
|
260
|
+
float wB = stateB->angularVelocity;
|
|
261
|
+
b2Rot dqB = stateB->deltaRotation;
|
|
262
|
+
|
|
263
|
+
b2Vec2 dp = b2Sub( stateB->deltaPosition, stateA->deltaPosition );
|
|
264
|
+
|
|
265
|
+
b2Vec2 normal = constraint->normal;
|
|
266
|
+
b2Vec2 tangent = b2RightPerp( normal );
|
|
267
|
+
float friction = constraint->friction;
|
|
268
|
+
b2Softness softness = constraint->softness;
|
|
269
|
+
|
|
270
|
+
int pointCount = constraint->pointCount;
|
|
271
|
+
float totalNormalImpulse = 0.0f;
|
|
272
|
+
|
|
273
|
+
// Non-penetration
|
|
274
|
+
for ( int j = 0; j < pointCount; ++j )
|
|
275
|
+
{
|
|
276
|
+
b2ContactConstraintPoint* cp = constraint->points + j;
|
|
277
|
+
|
|
278
|
+
// fixed anchor points
|
|
279
|
+
b2Vec2 rA = cp->anchorA;
|
|
280
|
+
b2Vec2 rB = cp->anchorB;
|
|
281
|
+
|
|
282
|
+
// compute current separation
|
|
283
|
+
// this is subject to round-off error if the anchor is far from the body center of mass
|
|
284
|
+
b2Vec2 ds = b2Add( dp, b2Sub( b2RotateVector( dqB, rB ), b2RotateVector( dqA, rA ) ) );
|
|
285
|
+
float s = cp->baseSeparation + b2Dot( ds, normal );
|
|
286
|
+
|
|
287
|
+
float velocityBias = 0.0f;
|
|
288
|
+
float massScale = 1.0f;
|
|
289
|
+
float impulseScale = 0.0f;
|
|
290
|
+
if ( s > 0.0f )
|
|
291
|
+
{
|
|
292
|
+
// speculative bias
|
|
293
|
+
velocityBias = s * inv_h;
|
|
294
|
+
}
|
|
295
|
+
else if ( useBias )
|
|
296
|
+
{
|
|
297
|
+
velocityBias = b2MaxFloat( softness.biasRate * s, -pushout );
|
|
298
|
+
massScale = softness.massScale;
|
|
299
|
+
impulseScale = softness.impulseScale;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// relative normal velocity at contact
|
|
303
|
+
b2Vec2 vrA = b2Add( vA, b2CrossSV( wA, rA ) );
|
|
304
|
+
b2Vec2 vrB = b2Add( vB, b2CrossSV( wB, rB ) );
|
|
305
|
+
float vn = b2Dot( b2Sub( vrB, vrA ), normal );
|
|
306
|
+
|
|
307
|
+
// incremental normal impulse
|
|
308
|
+
float impulse = -cp->normalMass * massScale * ( vn + velocityBias ) - impulseScale * cp->normalImpulse;
|
|
309
|
+
|
|
310
|
+
// clamp the accumulated impulse
|
|
311
|
+
float newImpulse = b2MaxFloat( cp->normalImpulse + impulse, 0.0f );
|
|
312
|
+
impulse = newImpulse - cp->normalImpulse;
|
|
313
|
+
cp->normalImpulse = newImpulse;
|
|
314
|
+
cp->totalNormalImpulse += newImpulse;
|
|
315
|
+
totalNormalImpulse += newImpulse;
|
|
316
|
+
|
|
317
|
+
// apply normal impulse
|
|
318
|
+
b2Vec2 P = b2MulSV( impulse, normal );
|
|
319
|
+
vA = b2MulSub( vA, mA, P );
|
|
320
|
+
wA -= iA * b2Cross( rA, P );
|
|
321
|
+
|
|
322
|
+
vB = b2MulAdd( vB, mB, P );
|
|
323
|
+
wB += iB * b2Cross( rB, P );
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Friction
|
|
327
|
+
for ( int j = 0; j < pointCount; ++j )
|
|
328
|
+
{
|
|
329
|
+
b2ContactConstraintPoint* cp = constraint->points + j;
|
|
330
|
+
|
|
331
|
+
// fixed anchor points
|
|
332
|
+
b2Vec2 rA = cp->anchorA;
|
|
333
|
+
b2Vec2 rB = cp->anchorB;
|
|
334
|
+
|
|
335
|
+
// relative tangent velocity at contact
|
|
336
|
+
b2Vec2 vrB = b2Add( vB, b2CrossSV( wB, rB ) );
|
|
337
|
+
b2Vec2 vrA = b2Add( vA, b2CrossSV( wA, rA ) );
|
|
338
|
+
|
|
339
|
+
// vt = dot(vrB - sB * tangent - (vrA + sA * tangent), tangent)
|
|
340
|
+
// = dot(vrB - vrA, tangent) - (sA + sB)
|
|
341
|
+
|
|
342
|
+
float vt = b2Dot( b2Sub( vrB, vrA ), tangent ) - constraint->tangentSpeed;
|
|
343
|
+
|
|
344
|
+
// incremental tangent impulse
|
|
345
|
+
float impulse = cp->tangentMass * ( -vt );
|
|
346
|
+
|
|
347
|
+
// clamp the accumulated force
|
|
348
|
+
float maxFriction = friction * cp->normalImpulse;
|
|
349
|
+
float newImpulse = b2ClampFloat( cp->tangentImpulse + impulse, -maxFriction, maxFriction );
|
|
350
|
+
impulse = newImpulse - cp->tangentImpulse;
|
|
351
|
+
cp->tangentImpulse = newImpulse;
|
|
352
|
+
|
|
353
|
+
// apply tangent impulse
|
|
354
|
+
b2Vec2 P = b2MulSV( impulse, tangent );
|
|
355
|
+
vA = b2MulSub( vA, mA, P );
|
|
356
|
+
wA -= iA * b2Cross( rA, P );
|
|
357
|
+
vB = b2MulAdd( vB, mB, P );
|
|
358
|
+
wB += iB * b2Cross( rB, P );
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Rolling resistance
|
|
362
|
+
{
|
|
363
|
+
float deltaLambda = -constraint->rollingMass * ( wB - wA );
|
|
364
|
+
float lambda = constraint->rollingImpulse;
|
|
365
|
+
float maxLambda = constraint->rollingResistance * totalNormalImpulse;
|
|
366
|
+
constraint->rollingImpulse = b2ClampFloat( lambda + deltaLambda, -maxLambda, maxLambda );
|
|
367
|
+
deltaLambda = constraint->rollingImpulse - lambda;
|
|
368
|
+
|
|
369
|
+
wA -= iA * deltaLambda;
|
|
370
|
+
wB += iB * deltaLambda;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
stateA->linearVelocity = vA;
|
|
374
|
+
stateA->angularVelocity = wA;
|
|
375
|
+
stateB->linearVelocity = vB;
|
|
376
|
+
stateB->angularVelocity = wB;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
b2TracyCZoneEnd( solve_contact );
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
void b2ApplyOverflowRestitution( b2StepContext* context )
|
|
383
|
+
{
|
|
384
|
+
b2TracyCZoneNC( overflow_resitution, "Overflow Restitution", b2_colorViolet, true );
|
|
385
|
+
|
|
386
|
+
b2ConstraintGraph* graph = context->graph;
|
|
387
|
+
b2GraphColor* color = graph->colors + B2_OVERFLOW_INDEX;
|
|
388
|
+
b2ContactConstraint* constraints = color->overflowConstraints;
|
|
389
|
+
int contactCount = color->contactSims.count;
|
|
390
|
+
b2World* world = context->world;
|
|
391
|
+
b2SolverSet* awakeSet = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
392
|
+
b2BodyState* states = awakeSet->bodyStates.data;
|
|
393
|
+
|
|
394
|
+
float threshold = context->world->restitutionThreshold;
|
|
395
|
+
|
|
396
|
+
// dummy state to represent a static body
|
|
397
|
+
b2BodyState dummyState = b2_identityBodyState;
|
|
398
|
+
|
|
399
|
+
for ( int i = 0; i < contactCount; ++i )
|
|
400
|
+
{
|
|
401
|
+
b2ContactConstraint* constraint = constraints + i;
|
|
402
|
+
|
|
403
|
+
float restitution = constraint->restitution;
|
|
404
|
+
if ( restitution == 0.0f )
|
|
405
|
+
{
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
float mA = constraint->invMassA;
|
|
410
|
+
float iA = constraint->invIA;
|
|
411
|
+
float mB = constraint->invMassB;
|
|
412
|
+
float iB = constraint->invIB;
|
|
413
|
+
|
|
414
|
+
b2BodyState* stateA = constraint->indexA == B2_NULL_INDEX ? &dummyState : states + constraint->indexA;
|
|
415
|
+
b2Vec2 vA = stateA->linearVelocity;
|
|
416
|
+
float wA = stateA->angularVelocity;
|
|
417
|
+
|
|
418
|
+
b2BodyState* stateB = constraint->indexB == B2_NULL_INDEX ? &dummyState : states + constraint->indexB;
|
|
419
|
+
b2Vec2 vB = stateB->linearVelocity;
|
|
420
|
+
float wB = stateB->angularVelocity;
|
|
421
|
+
|
|
422
|
+
b2Vec2 normal = constraint->normal;
|
|
423
|
+
int pointCount = constraint->pointCount;
|
|
424
|
+
|
|
425
|
+
// it is possible to get more accurate restitution by iterating
|
|
426
|
+
// this only makes a difference if there are two contact points
|
|
427
|
+
// for (int iter = 0; iter < 10; ++iter)
|
|
428
|
+
{
|
|
429
|
+
for ( int j = 0; j < pointCount; ++j )
|
|
430
|
+
{
|
|
431
|
+
b2ContactConstraintPoint* cp = constraint->points + j;
|
|
432
|
+
|
|
433
|
+
// if the normal impulse is zero then there was no collision
|
|
434
|
+
// this skips speculative contact points that didn't generate an impulse
|
|
435
|
+
// The max normal impulse is used in case there was a collision that moved away within the sub-step process
|
|
436
|
+
if ( cp->relativeVelocity > -threshold || cp->totalNormalImpulse == 0.0f )
|
|
437
|
+
{
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// fixed anchor points
|
|
442
|
+
b2Vec2 rA = cp->anchorA;
|
|
443
|
+
b2Vec2 rB = cp->anchorB;
|
|
444
|
+
|
|
445
|
+
// relative normal velocity at contact
|
|
446
|
+
b2Vec2 vrB = b2Add( vB, b2CrossSV( wB, rB ) );
|
|
447
|
+
b2Vec2 vrA = b2Add( vA, b2CrossSV( wA, rA ) );
|
|
448
|
+
float vn = b2Dot( b2Sub( vrB, vrA ), normal );
|
|
449
|
+
|
|
450
|
+
// compute normal impulse
|
|
451
|
+
float impulse = -cp->normalMass * ( vn + restitution * cp->relativeVelocity );
|
|
452
|
+
|
|
453
|
+
// clamp the accumulated impulse
|
|
454
|
+
// todo should this be stored?
|
|
455
|
+
float newImpulse = b2MaxFloat( cp->normalImpulse + impulse, 0.0f );
|
|
456
|
+
impulse = newImpulse - cp->normalImpulse;
|
|
457
|
+
cp->normalImpulse = newImpulse;
|
|
458
|
+
|
|
459
|
+
// Add the incremental impulse rather than the full impulse because this is not a sub-step
|
|
460
|
+
cp->totalNormalImpulse += impulse;
|
|
461
|
+
|
|
462
|
+
// apply contact impulse
|
|
463
|
+
b2Vec2 P = b2MulSV( impulse, normal );
|
|
464
|
+
vA = b2MulSub( vA, mA, P );
|
|
465
|
+
wA -= iA * b2Cross( rA, P );
|
|
466
|
+
vB = b2MulAdd( vB, mB, P );
|
|
467
|
+
wB += iB * b2Cross( rB, P );
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
stateA->linearVelocity = vA;
|
|
472
|
+
stateA->angularVelocity = wA;
|
|
473
|
+
stateB->linearVelocity = vB;
|
|
474
|
+
stateB->angularVelocity = wB;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
b2TracyCZoneEnd( overflow_resitution );
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
void b2StoreOverflowImpulses( b2StepContext* context )
|
|
481
|
+
{
|
|
482
|
+
b2TracyCZoneNC( store_impulses, "Store", b2_colorFireBrick, true );
|
|
483
|
+
|
|
484
|
+
b2ConstraintGraph* graph = context->graph;
|
|
485
|
+
b2GraphColor* color = graph->colors + B2_OVERFLOW_INDEX;
|
|
486
|
+
b2ContactConstraint* constraints = color->overflowConstraints;
|
|
487
|
+
b2ContactSim* contacts = color->contactSims.data;
|
|
488
|
+
int contactCount = color->contactSims.count;
|
|
489
|
+
|
|
490
|
+
for ( int i = 0; i < contactCount; ++i )
|
|
491
|
+
{
|
|
492
|
+
const b2ContactConstraint* constraint = constraints + i;
|
|
493
|
+
b2ContactSim* contact = contacts + i;
|
|
494
|
+
b2Manifold* manifold = &contact->manifold;
|
|
495
|
+
int pointCount = manifold->pointCount;
|
|
496
|
+
|
|
497
|
+
for ( int j = 0; j < pointCount; ++j )
|
|
498
|
+
{
|
|
499
|
+
manifold->points[j].normalImpulse = constraint->points[j].normalImpulse;
|
|
500
|
+
manifold->points[j].tangentImpulse = constraint->points[j].tangentImpulse;
|
|
501
|
+
manifold->points[j].totalNormalImpulse = constraint->points[j].totalNormalImpulse;
|
|
502
|
+
manifold->points[j].normalVelocity = constraint->points[j].relativeVelocity;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
manifold->rollingImpulse = constraint->rollingImpulse;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
b2TracyCZoneEnd( store_impulses );
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
#if defined( B2_SIMD_AVX2 )
|
|
512
|
+
|
|
513
|
+
#include <immintrin.h>
|
|
514
|
+
|
|
515
|
+
// wide float holds 8 numbers
|
|
516
|
+
typedef __m256 b2FloatW;
|
|
517
|
+
|
|
518
|
+
#elif defined( B2_SIMD_NEON )
|
|
519
|
+
|
|
520
|
+
#include <arm_neon.h>
|
|
521
|
+
|
|
522
|
+
// wide float holds 4 numbers
|
|
523
|
+
typedef float32x4_t b2FloatW;
|
|
524
|
+
|
|
525
|
+
#elif defined( B2_SIMD_SSE2 )
|
|
526
|
+
|
|
527
|
+
#include <emmintrin.h>
|
|
528
|
+
|
|
529
|
+
// wide float holds 4 numbers
|
|
530
|
+
typedef __m128 b2FloatW;
|
|
531
|
+
|
|
532
|
+
#else
|
|
533
|
+
|
|
534
|
+
// scalar math
|
|
535
|
+
typedef struct b2FloatW
|
|
536
|
+
{
|
|
537
|
+
float x, y, z, w;
|
|
538
|
+
} b2FloatW;
|
|
539
|
+
|
|
540
|
+
#endif
|
|
541
|
+
|
|
542
|
+
// Wide vec2
|
|
543
|
+
typedef struct b2Vec2W
|
|
544
|
+
{
|
|
545
|
+
b2FloatW X, Y;
|
|
546
|
+
} b2Vec2W;
|
|
547
|
+
|
|
548
|
+
// Wide rotation
|
|
549
|
+
typedef struct b2RotW
|
|
550
|
+
{
|
|
551
|
+
b2FloatW C, S;
|
|
552
|
+
} b2RotW;
|
|
553
|
+
|
|
554
|
+
#if defined( B2_SIMD_AVX2 )
|
|
555
|
+
|
|
556
|
+
static inline b2FloatW b2ZeroW( void )
|
|
557
|
+
{
|
|
558
|
+
return _mm256_setzero_ps();
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
static inline b2FloatW b2SplatW( float scalar )
|
|
562
|
+
{
|
|
563
|
+
return _mm256_set1_ps( scalar );
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static inline b2FloatW b2AddW( b2FloatW a, b2FloatW b )
|
|
567
|
+
{
|
|
568
|
+
return _mm256_add_ps( a, b );
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
static inline b2FloatW b2SubW( b2FloatW a, b2FloatW b )
|
|
572
|
+
{
|
|
573
|
+
return _mm256_sub_ps( a, b );
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
static inline b2FloatW b2MulW( b2FloatW a, b2FloatW b )
|
|
577
|
+
{
|
|
578
|
+
return _mm256_mul_ps( a, b );
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
static inline b2FloatW b2MulAddW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
582
|
+
{
|
|
583
|
+
// FMA can be emulated: https://github.com/lattera/glibc/blob/master/sysdeps/ieee754/dbl-64/s_fmaf.c#L34
|
|
584
|
+
// return _mm256_fmadd_ps( b, c, a );
|
|
585
|
+
return _mm256_add_ps( _mm256_mul_ps( b, c ), a );
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
static inline b2FloatW b2MulSubW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
589
|
+
{
|
|
590
|
+
// return _mm256_fnmadd_ps(b, c, a);
|
|
591
|
+
return _mm256_sub_ps( a, _mm256_mul_ps( b, c ) );
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
static inline b2FloatW b2MinW( b2FloatW a, b2FloatW b )
|
|
595
|
+
{
|
|
596
|
+
return _mm256_min_ps( a, b );
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
static inline b2FloatW b2MaxW( b2FloatW a, b2FloatW b )
|
|
600
|
+
{
|
|
601
|
+
return _mm256_max_ps( a, b );
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// a = clamp(a, -b, b)
|
|
605
|
+
static inline b2FloatW b2SymClampW( b2FloatW a, b2FloatW b )
|
|
606
|
+
{
|
|
607
|
+
b2FloatW nb = _mm256_sub_ps( _mm256_setzero_ps(), b );
|
|
608
|
+
return _mm256_max_ps( nb, _mm256_min_ps( a, b ) );
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
static inline b2FloatW b2OrW( b2FloatW a, b2FloatW b )
|
|
612
|
+
{
|
|
613
|
+
return _mm256_or_ps( a, b );
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
static inline b2FloatW b2GreaterThanW( b2FloatW a, b2FloatW b )
|
|
617
|
+
{
|
|
618
|
+
return _mm256_cmp_ps( a, b, _CMP_GT_OQ );
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
static inline b2FloatW b2EqualsW( b2FloatW a, b2FloatW b )
|
|
622
|
+
{
|
|
623
|
+
return _mm256_cmp_ps( a, b, _CMP_EQ_OQ );
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
static inline bool b2AllZeroW( b2FloatW a )
|
|
627
|
+
{
|
|
628
|
+
// Compare each element with zero
|
|
629
|
+
b2FloatW zero = _mm256_setzero_ps();
|
|
630
|
+
b2FloatW cmp = _mm256_cmp_ps( a, zero, _CMP_EQ_OQ );
|
|
631
|
+
|
|
632
|
+
// Create a mask from the comparison results
|
|
633
|
+
int mask = _mm256_movemask_ps( cmp );
|
|
634
|
+
|
|
635
|
+
// If all elements are zero, the mask will be 0xFF (11111111 in binary)
|
|
636
|
+
return mask == 0xFF;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// component-wise returns mask ? b : a
|
|
640
|
+
static inline b2FloatW b2BlendW( b2FloatW a, b2FloatW b, b2FloatW mask )
|
|
641
|
+
{
|
|
642
|
+
return _mm256_blendv_ps( a, b, mask );
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
#elif defined( B2_SIMD_NEON )
|
|
646
|
+
|
|
647
|
+
static inline b2FloatW b2ZeroW( void )
|
|
648
|
+
{
|
|
649
|
+
return vdupq_n_f32( 0.0f );
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
static inline b2FloatW b2SplatW( float scalar )
|
|
653
|
+
{
|
|
654
|
+
return vdupq_n_f32( scalar );
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
static inline b2FloatW b2SetW( float a, float b, float c, float d )
|
|
658
|
+
{
|
|
659
|
+
float32_t array[4] = { a, b, c, d };
|
|
660
|
+
return vld1q_f32( array );
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
static inline b2FloatW b2AddW( b2FloatW a, b2FloatW b )
|
|
664
|
+
{
|
|
665
|
+
return vaddq_f32( a, b );
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
static inline b2FloatW b2SubW( b2FloatW a, b2FloatW b )
|
|
669
|
+
{
|
|
670
|
+
return vsubq_f32( a, b );
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
static inline b2FloatW b2MulW( b2FloatW a, b2FloatW b )
|
|
674
|
+
{
|
|
675
|
+
return vmulq_f32( a, b );
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
static inline b2FloatW b2MulAddW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
679
|
+
{
|
|
680
|
+
return vmlaq_f32( a, b, c );
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
static inline b2FloatW b2MulSubW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
684
|
+
{
|
|
685
|
+
return vmlsq_f32( a, b, c );
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
static inline b2FloatW b2MinW( b2FloatW a, b2FloatW b )
|
|
689
|
+
{
|
|
690
|
+
return vminq_f32( a, b );
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
static inline b2FloatW b2MaxW( b2FloatW a, b2FloatW b )
|
|
694
|
+
{
|
|
695
|
+
return vmaxq_f32( a, b );
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// a = clamp(a, -b, b)
|
|
699
|
+
static inline b2FloatW b2SymClampW( b2FloatW a, b2FloatW b )
|
|
700
|
+
{
|
|
701
|
+
b2FloatW nb = vnegq_f32( b );
|
|
702
|
+
return vmaxq_f32( nb, vminq_f32( a, b ) );
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
static inline b2FloatW b2OrW( b2FloatW a, b2FloatW b )
|
|
706
|
+
{
|
|
707
|
+
return vreinterpretq_f32_u32( vorrq_u32( vreinterpretq_u32_f32( a ), vreinterpretq_u32_f32( b ) ) );
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
static inline b2FloatW b2GreaterThanW( b2FloatW a, b2FloatW b )
|
|
711
|
+
{
|
|
712
|
+
return vreinterpretq_f32_u32( vcgtq_f32( a, b ) );
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
static inline b2FloatW b2EqualsW( b2FloatW a, b2FloatW b )
|
|
716
|
+
{
|
|
717
|
+
return vreinterpretq_f32_u32( vceqq_f32( a, b ) );
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
static inline bool b2AllZeroW( b2FloatW a )
|
|
721
|
+
{
|
|
722
|
+
// Create a zero vector for comparison
|
|
723
|
+
b2FloatW zero = vdupq_n_f32( 0.0f );
|
|
724
|
+
|
|
725
|
+
// Compare the input vector with zero
|
|
726
|
+
uint32x4_t cmp_result = vceqq_f32( a, zero );
|
|
727
|
+
|
|
728
|
+
// Check if all comparison results are non-zero using vminvq
|
|
729
|
+
#ifdef __ARM_FEATURE_SVE
|
|
730
|
+
// ARM v8.2+ has horizontal minimum instruction
|
|
731
|
+
return vminvq_u32( cmp_result ) != 0;
|
|
732
|
+
#else
|
|
733
|
+
// For older ARM architectures, we need to manually check all lanes
|
|
734
|
+
return vgetq_lane_u32( cmp_result, 0 ) != 0 && vgetq_lane_u32( cmp_result, 1 ) != 0 && vgetq_lane_u32( cmp_result, 2 ) != 0 &&
|
|
735
|
+
vgetq_lane_u32( cmp_result, 3 ) != 0;
|
|
736
|
+
#endif
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// component-wise returns mask ? b : a
|
|
740
|
+
static inline b2FloatW b2BlendW( b2FloatW a, b2FloatW b, b2FloatW mask )
|
|
741
|
+
{
|
|
742
|
+
uint32x4_t mask32 = vreinterpretq_u32_f32( mask );
|
|
743
|
+
return vbslq_f32( mask32, b, a );
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
static inline b2FloatW b2LoadW( const float32_t* data )
|
|
747
|
+
{
|
|
748
|
+
return vld1q_f32( data );
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
static inline void b2StoreW( float32_t* data, b2FloatW a )
|
|
752
|
+
{
|
|
753
|
+
vst1q_f32( data, a );
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
static inline b2FloatW b2UnpackLoW( b2FloatW a, b2FloatW b )
|
|
757
|
+
{
|
|
758
|
+
#if defined( __aarch64__ )
|
|
759
|
+
return vzip1q_f32( a, b );
|
|
760
|
+
#else
|
|
761
|
+
float32x2_t a1 = vget_low_f32( a );
|
|
762
|
+
float32x2_t b1 = vget_low_f32( b );
|
|
763
|
+
float32x2x2_t result = vzip_f32( a1, b1 );
|
|
764
|
+
return vcombine_f32( result.val[0], result.val[1] );
|
|
765
|
+
#endif
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
static inline b2FloatW b2UnpackHiW( b2FloatW a, b2FloatW b )
|
|
769
|
+
{
|
|
770
|
+
#if defined( __aarch64__ )
|
|
771
|
+
return vzip2q_f32( a, b );
|
|
772
|
+
#else
|
|
773
|
+
float32x2_t a1 = vget_high_f32( a );
|
|
774
|
+
float32x2_t b1 = vget_high_f32( b );
|
|
775
|
+
float32x2x2_t result = vzip_f32( a1, b1 );
|
|
776
|
+
return vcombine_f32( result.val[0], result.val[1] );
|
|
777
|
+
#endif
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
#elif defined( B2_SIMD_SSE2 )
|
|
781
|
+
|
|
782
|
+
static inline b2FloatW b2ZeroW( void )
|
|
783
|
+
{
|
|
784
|
+
return _mm_setzero_ps();
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
static inline b2FloatW b2SplatW( float scalar )
|
|
788
|
+
{
|
|
789
|
+
return _mm_set1_ps( scalar );
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
static inline b2FloatW b2SetW( float a, float b, float c, float d )
|
|
793
|
+
{
|
|
794
|
+
return _mm_setr_ps( a, b, c, d );
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
static inline b2FloatW b2AddW( b2FloatW a, b2FloatW b )
|
|
798
|
+
{
|
|
799
|
+
return _mm_add_ps( a, b );
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
static inline b2FloatW b2SubW( b2FloatW a, b2FloatW b )
|
|
803
|
+
{
|
|
804
|
+
return _mm_sub_ps( a, b );
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
static inline b2FloatW b2MulW( b2FloatW a, b2FloatW b )
|
|
808
|
+
{
|
|
809
|
+
return _mm_mul_ps( a, b );
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
static inline b2FloatW b2MulAddW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
813
|
+
{
|
|
814
|
+
return _mm_add_ps( a, _mm_mul_ps( b, c ) );
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
static inline b2FloatW b2MulSubW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
818
|
+
{
|
|
819
|
+
return _mm_sub_ps( a, _mm_mul_ps( b, c ) );
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
static inline b2FloatW b2MinW( b2FloatW a, b2FloatW b )
|
|
823
|
+
{
|
|
824
|
+
return _mm_min_ps( a, b );
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
static inline b2FloatW b2MaxW( b2FloatW a, b2FloatW b )
|
|
828
|
+
{
|
|
829
|
+
return _mm_max_ps( a, b );
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// a = clamp(a, -b, b)
|
|
833
|
+
static inline b2FloatW b2SymClampW( b2FloatW a, b2FloatW b )
|
|
834
|
+
{
|
|
835
|
+
// Create a mask with the sign bit set for each element
|
|
836
|
+
__m128 mask = _mm_set1_ps( -0.0f );
|
|
837
|
+
|
|
838
|
+
// XOR the input with the mask to negate each element
|
|
839
|
+
__m128 nb = _mm_xor_ps( b, mask );
|
|
840
|
+
|
|
841
|
+
return _mm_max_ps( nb, _mm_min_ps( a, b ) );
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
static inline b2FloatW b2OrW( b2FloatW a, b2FloatW b )
|
|
845
|
+
{
|
|
846
|
+
return _mm_or_ps( a, b );
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
static inline b2FloatW b2GreaterThanW( b2FloatW a, b2FloatW b )
|
|
850
|
+
{
|
|
851
|
+
return _mm_cmpgt_ps( a, b );
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
static inline b2FloatW b2EqualsW( b2FloatW a, b2FloatW b )
|
|
855
|
+
{
|
|
856
|
+
return _mm_cmpeq_ps( a, b );
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
static inline bool b2AllZeroW( b2FloatW a )
|
|
860
|
+
{
|
|
861
|
+
// Compare each element with zero
|
|
862
|
+
b2FloatW zero = _mm_setzero_ps();
|
|
863
|
+
b2FloatW cmp = _mm_cmpeq_ps( a, zero );
|
|
864
|
+
|
|
865
|
+
// Create a mask from the comparison results
|
|
866
|
+
int mask = _mm_movemask_ps( cmp );
|
|
867
|
+
|
|
868
|
+
// If all elements are zero, the mask will be 0xF (1111 in binary)
|
|
869
|
+
return mask == 0xF;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// component-wise returns mask ? b : a
|
|
873
|
+
static inline b2FloatW b2BlendW( b2FloatW a, b2FloatW b, b2FloatW mask )
|
|
874
|
+
{
|
|
875
|
+
return _mm_or_ps( _mm_and_ps( mask, b ), _mm_andnot_ps( mask, a ) );
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
static inline b2FloatW b2LoadW( const float* data )
|
|
879
|
+
{
|
|
880
|
+
return _mm_load_ps( data );
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
static inline void b2StoreW( float* data, b2FloatW a )
|
|
884
|
+
{
|
|
885
|
+
_mm_store_ps( data, a );
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
static inline b2FloatW b2UnpackLoW( b2FloatW a, b2FloatW b )
|
|
889
|
+
{
|
|
890
|
+
return _mm_unpacklo_ps( a, b );
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
static inline b2FloatW b2UnpackHiW( b2FloatW a, b2FloatW b )
|
|
894
|
+
{
|
|
895
|
+
return _mm_unpackhi_ps( a, b );
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
#else
|
|
899
|
+
|
|
900
|
+
static inline b2FloatW b2ZeroW( void )
|
|
901
|
+
{
|
|
902
|
+
return (b2FloatW){ 0.0f, 0.0f, 0.0f, 0.0f };
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
static inline b2FloatW b2SplatW( float scalar )
|
|
906
|
+
{
|
|
907
|
+
return (b2FloatW){ scalar, scalar, scalar, scalar };
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
static inline b2FloatW b2AddW( b2FloatW a, b2FloatW b )
|
|
911
|
+
{
|
|
912
|
+
return (b2FloatW){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w };
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
static inline b2FloatW b2SubW( b2FloatW a, b2FloatW b )
|
|
916
|
+
{
|
|
917
|
+
return (b2FloatW){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w };
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
static inline b2FloatW b2MulW( b2FloatW a, b2FloatW b )
|
|
921
|
+
{
|
|
922
|
+
return (b2FloatW){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w };
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
static inline b2FloatW b2MulAddW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
926
|
+
{
|
|
927
|
+
return (b2FloatW){ a.x + b.x * c.x, a.y + b.y * c.y, a.z + b.z * c.z, a.w + b.w * c.w };
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
static inline b2FloatW b2MulSubW( b2FloatW a, b2FloatW b, b2FloatW c )
|
|
931
|
+
{
|
|
932
|
+
return (b2FloatW){ a.x - b.x * c.x, a.y - b.y * c.y, a.z - b.z * c.z, a.w - b.w * c.w };
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
static inline b2FloatW b2MinW( b2FloatW a, b2FloatW b )
|
|
936
|
+
{
|
|
937
|
+
b2FloatW r;
|
|
938
|
+
r.x = a.x <= b.x ? a.x : b.x;
|
|
939
|
+
r.y = a.y <= b.y ? a.y : b.y;
|
|
940
|
+
r.z = a.z <= b.z ? a.z : b.z;
|
|
941
|
+
r.w = a.w <= b.w ? a.w : b.w;
|
|
942
|
+
return r;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
static inline b2FloatW b2MaxW( b2FloatW a, b2FloatW b )
|
|
946
|
+
{
|
|
947
|
+
b2FloatW r;
|
|
948
|
+
r.x = a.x >= b.x ? a.x : b.x;
|
|
949
|
+
r.y = a.y >= b.y ? a.y : b.y;
|
|
950
|
+
r.z = a.z >= b.z ? a.z : b.z;
|
|
951
|
+
r.w = a.w >= b.w ? a.w : b.w;
|
|
952
|
+
return r;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// a = clamp(a, -b, b)
|
|
956
|
+
static inline b2FloatW b2SymClampW( b2FloatW a, b2FloatW b )
|
|
957
|
+
{
|
|
958
|
+
b2FloatW r;
|
|
959
|
+
r.x = b2ClampFloat( a.x, -b.x, b.x );
|
|
960
|
+
r.y = b2ClampFloat( a.y, -b.y, b.y );
|
|
961
|
+
r.z = b2ClampFloat( a.z, -b.z, b.z );
|
|
962
|
+
r.w = b2ClampFloat( a.w, -b.w, b.w );
|
|
963
|
+
return r;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
static inline b2FloatW b2OrW( b2FloatW a, b2FloatW b )
|
|
967
|
+
{
|
|
968
|
+
b2FloatW r;
|
|
969
|
+
r.x = a.x != 0.0f || b.x != 0.0f ? 1.0f : 0.0f;
|
|
970
|
+
r.y = a.y != 0.0f || b.y != 0.0f ? 1.0f : 0.0f;
|
|
971
|
+
r.z = a.z != 0.0f || b.z != 0.0f ? 1.0f : 0.0f;
|
|
972
|
+
r.w = a.w != 0.0f || b.w != 0.0f ? 1.0f : 0.0f;
|
|
973
|
+
return r;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
static inline b2FloatW b2GreaterThanW( b2FloatW a, b2FloatW b )
|
|
977
|
+
{
|
|
978
|
+
b2FloatW r;
|
|
979
|
+
r.x = a.x > b.x ? 1.0f : 0.0f;
|
|
980
|
+
r.y = a.y > b.y ? 1.0f : 0.0f;
|
|
981
|
+
r.z = a.z > b.z ? 1.0f : 0.0f;
|
|
982
|
+
r.w = a.w > b.w ? 1.0f : 0.0f;
|
|
983
|
+
return r;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
static inline b2FloatW b2EqualsW( b2FloatW a, b2FloatW b )
|
|
987
|
+
{
|
|
988
|
+
b2FloatW r;
|
|
989
|
+
r.x = a.x == b.x ? 1.0f : 0.0f;
|
|
990
|
+
r.y = a.y == b.y ? 1.0f : 0.0f;
|
|
991
|
+
r.z = a.z == b.z ? 1.0f : 0.0f;
|
|
992
|
+
r.w = a.w == b.w ? 1.0f : 0.0f;
|
|
993
|
+
return r;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
static inline bool b2AllZeroW( b2FloatW a )
|
|
997
|
+
{
|
|
998
|
+
return a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// component-wise returns mask ? b : a
|
|
1002
|
+
static inline b2FloatW b2BlendW( b2FloatW a, b2FloatW b, b2FloatW mask )
|
|
1003
|
+
{
|
|
1004
|
+
b2FloatW r;
|
|
1005
|
+
r.x = mask.x != 0.0f ? b.x : a.x;
|
|
1006
|
+
r.y = mask.y != 0.0f ? b.y : a.y;
|
|
1007
|
+
r.z = mask.z != 0.0f ? b.z : a.z;
|
|
1008
|
+
r.w = mask.w != 0.0f ? b.w : a.w;
|
|
1009
|
+
return r;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
#endif
|
|
1013
|
+
|
|
1014
|
+
static inline b2FloatW b2DotW( b2Vec2W a, b2Vec2W b )
|
|
1015
|
+
{
|
|
1016
|
+
return b2AddW( b2MulW( a.X, b.X ), b2MulW( a.Y, b.Y ) );
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
static inline b2FloatW b2CrossW( b2Vec2W a, b2Vec2W b )
|
|
1020
|
+
{
|
|
1021
|
+
return b2SubW( b2MulW( a.X, b.Y ), b2MulW( a.Y, b.X ) );
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
static inline b2Vec2W b2RotateVectorW( b2RotW q, b2Vec2W v )
|
|
1025
|
+
{
|
|
1026
|
+
return (b2Vec2W){ b2SubW( b2MulW( q.C, v.X ), b2MulW( q.S, v.Y ) ), b2AddW( b2MulW( q.S, v.X ), b2MulW( q.C, v.Y ) ) };
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Soft contact constraints with sub-stepping support
|
|
1030
|
+
// Uses fixed anchors for Jacobians for better behavior on rolling shapes (circles & capsules)
|
|
1031
|
+
// http://mmacklin.com/smallsteps.pdf
|
|
1032
|
+
// https://box2d.org/files/ErinCatto_SoftConstraints_GDC2011.pdf
|
|
1033
|
+
|
|
1034
|
+
typedef struct b2ContactConstraintSIMD
|
|
1035
|
+
{
|
|
1036
|
+
int indexA[B2_SIMD_WIDTH];
|
|
1037
|
+
int indexB[B2_SIMD_WIDTH];
|
|
1038
|
+
|
|
1039
|
+
b2FloatW invMassA, invMassB;
|
|
1040
|
+
b2FloatW invIA, invIB;
|
|
1041
|
+
b2Vec2W normal;
|
|
1042
|
+
b2FloatW friction;
|
|
1043
|
+
b2FloatW tangentSpeed;
|
|
1044
|
+
b2FloatW rollingResistance;
|
|
1045
|
+
b2FloatW rollingMass;
|
|
1046
|
+
b2FloatW rollingImpulse;
|
|
1047
|
+
b2FloatW biasRate;
|
|
1048
|
+
b2FloatW massScale;
|
|
1049
|
+
b2FloatW impulseScale;
|
|
1050
|
+
b2Vec2W anchorA1, anchorB1;
|
|
1051
|
+
b2FloatW normalMass1, tangentMass1;
|
|
1052
|
+
b2FloatW baseSeparation1;
|
|
1053
|
+
b2FloatW normalImpulse1;
|
|
1054
|
+
b2FloatW totalNormalImpulse1;
|
|
1055
|
+
b2FloatW tangentImpulse1;
|
|
1056
|
+
b2Vec2W anchorA2, anchorB2;
|
|
1057
|
+
b2FloatW baseSeparation2;
|
|
1058
|
+
b2FloatW normalImpulse2;
|
|
1059
|
+
b2FloatW totalNormalImpulse2;
|
|
1060
|
+
b2FloatW tangentImpulse2;
|
|
1061
|
+
b2FloatW normalMass2, tangentMass2;
|
|
1062
|
+
b2FloatW restitution;
|
|
1063
|
+
b2FloatW relativeVelocity1, relativeVelocity2;
|
|
1064
|
+
} b2ContactConstraintSIMD;
|
|
1065
|
+
|
|
1066
|
+
int b2GetContactConstraintSIMDByteCount( void )
|
|
1067
|
+
{
|
|
1068
|
+
return sizeof( b2ContactConstraintSIMD );
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// wide version of b2BodyState
|
|
1072
|
+
typedef struct b2BodyStateW
|
|
1073
|
+
{
|
|
1074
|
+
b2Vec2W v;
|
|
1075
|
+
b2FloatW w;
|
|
1076
|
+
b2FloatW flags;
|
|
1077
|
+
b2Vec2W dp;
|
|
1078
|
+
b2RotW dq;
|
|
1079
|
+
} b2BodyStateW;
|
|
1080
|
+
|
|
1081
|
+
// Custom gather/scatter for each SIMD type
|
|
1082
|
+
#if defined( B2_SIMD_AVX2 )
|
|
1083
|
+
|
|
1084
|
+
// This is a load and 8x8 transpose
|
|
1085
|
+
static b2BodyStateW b2GatherBodies( const b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices )
|
|
1086
|
+
{
|
|
1087
|
+
_Static_assert( sizeof( b2BodyState ) == 32, "b2BodyState not 32 bytes" );
|
|
1088
|
+
B2_ASSERT( ( (uintptr_t)states & 0x1F ) == 0 );
|
|
1089
|
+
// b2BodyState b2_identityBodyState = {{0.0f, 0.0f}, 0.0f, 0, {0.0f, 0.0f}, {1.0f, 0.0f}};
|
|
1090
|
+
b2FloatW identity = _mm256_setr_ps( 0.0f, 0.0f, 0.0f, 0, 0.0f, 0.0f, 1.0f, 0.0f );
|
|
1091
|
+
b2FloatW b0 = indices[0] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[0] ) );
|
|
1092
|
+
b2FloatW b1 = indices[1] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[1] ) );
|
|
1093
|
+
b2FloatW b2 = indices[2] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[2] ) );
|
|
1094
|
+
b2FloatW b3 = indices[3] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[3] ) );
|
|
1095
|
+
b2FloatW b4 = indices[4] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[4] ) );
|
|
1096
|
+
b2FloatW b5 = indices[5] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[5] ) );
|
|
1097
|
+
b2FloatW b6 = indices[6] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[6] ) );
|
|
1098
|
+
b2FloatW b7 = indices[7] == B2_NULL_INDEX ? identity : _mm256_load_ps( (float*)( states + indices[7] ) );
|
|
1099
|
+
|
|
1100
|
+
b2FloatW t0 = _mm256_unpacklo_ps( b0, b1 );
|
|
1101
|
+
b2FloatW t1 = _mm256_unpackhi_ps( b0, b1 );
|
|
1102
|
+
b2FloatW t2 = _mm256_unpacklo_ps( b2, b3 );
|
|
1103
|
+
b2FloatW t3 = _mm256_unpackhi_ps( b2, b3 );
|
|
1104
|
+
b2FloatW t4 = _mm256_unpacklo_ps( b4, b5 );
|
|
1105
|
+
b2FloatW t5 = _mm256_unpackhi_ps( b4, b5 );
|
|
1106
|
+
b2FloatW t6 = _mm256_unpacklo_ps( b6, b7 );
|
|
1107
|
+
b2FloatW t7 = _mm256_unpackhi_ps( b6, b7 );
|
|
1108
|
+
b2FloatW tt0 = _mm256_shuffle_ps( t0, t2, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1109
|
+
b2FloatW tt1 = _mm256_shuffle_ps( t0, t2, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1110
|
+
b2FloatW tt2 = _mm256_shuffle_ps( t1, t3, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1111
|
+
b2FloatW tt3 = _mm256_shuffle_ps( t1, t3, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1112
|
+
b2FloatW tt4 = _mm256_shuffle_ps( t4, t6, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1113
|
+
b2FloatW tt5 = _mm256_shuffle_ps( t4, t6, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1114
|
+
b2FloatW tt6 = _mm256_shuffle_ps( t5, t7, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1115
|
+
b2FloatW tt7 = _mm256_shuffle_ps( t5, t7, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1116
|
+
|
|
1117
|
+
b2BodyStateW simdBody;
|
|
1118
|
+
simdBody.v.X = _mm256_permute2f128_ps( tt0, tt4, 0x20 );
|
|
1119
|
+
simdBody.v.Y = _mm256_permute2f128_ps( tt1, tt5, 0x20 );
|
|
1120
|
+
simdBody.w = _mm256_permute2f128_ps( tt2, tt6, 0x20 );
|
|
1121
|
+
simdBody.flags = _mm256_permute2f128_ps( tt3, tt7, 0x20 );
|
|
1122
|
+
simdBody.dp.X = _mm256_permute2f128_ps( tt0, tt4, 0x31 );
|
|
1123
|
+
simdBody.dp.Y = _mm256_permute2f128_ps( tt1, tt5, 0x31 );
|
|
1124
|
+
simdBody.dq.C = _mm256_permute2f128_ps( tt2, tt6, 0x31 );
|
|
1125
|
+
simdBody.dq.S = _mm256_permute2f128_ps( tt3, tt7, 0x31 );
|
|
1126
|
+
return simdBody;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// This writes everything back to the solver bodies but only the velocities change
|
|
1130
|
+
static void b2ScatterBodies( b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices, const b2BodyStateW* B2_RESTRICT simdBody )
|
|
1131
|
+
{
|
|
1132
|
+
_Static_assert( sizeof( b2BodyState ) == 32, "b2BodyState not 32 bytes" );
|
|
1133
|
+
B2_ASSERT( ( (uintptr_t)states & 0x1F ) == 0 );
|
|
1134
|
+
b2FloatW t0 = _mm256_unpacklo_ps( simdBody->v.X, simdBody->v.Y );
|
|
1135
|
+
b2FloatW t1 = _mm256_unpackhi_ps( simdBody->v.X, simdBody->v.Y );
|
|
1136
|
+
b2FloatW t2 = _mm256_unpacklo_ps( simdBody->w, simdBody->flags );
|
|
1137
|
+
b2FloatW t3 = _mm256_unpackhi_ps( simdBody->w, simdBody->flags );
|
|
1138
|
+
b2FloatW t4 = _mm256_unpacklo_ps( simdBody->dp.X, simdBody->dp.Y );
|
|
1139
|
+
b2FloatW t5 = _mm256_unpackhi_ps( simdBody->dp.X, simdBody->dp.Y );
|
|
1140
|
+
b2FloatW t6 = _mm256_unpacklo_ps( simdBody->dq.C, simdBody->dq.S );
|
|
1141
|
+
b2FloatW t7 = _mm256_unpackhi_ps( simdBody->dq.C, simdBody->dq.S );
|
|
1142
|
+
b2FloatW tt0 = _mm256_shuffle_ps( t0, t2, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1143
|
+
b2FloatW tt1 = _mm256_shuffle_ps( t0, t2, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1144
|
+
b2FloatW tt2 = _mm256_shuffle_ps( t1, t3, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1145
|
+
b2FloatW tt3 = _mm256_shuffle_ps( t1, t3, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1146
|
+
b2FloatW tt4 = _mm256_shuffle_ps( t4, t6, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1147
|
+
b2FloatW tt5 = _mm256_shuffle_ps( t4, t6, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1148
|
+
b2FloatW tt6 = _mm256_shuffle_ps( t5, t7, _MM_SHUFFLE( 1, 0, 1, 0 ) );
|
|
1149
|
+
b2FloatW tt7 = _mm256_shuffle_ps( t5, t7, _MM_SHUFFLE( 3, 2, 3, 2 ) );
|
|
1150
|
+
|
|
1151
|
+
// I don't use any dummy body in the body array because this will lead to multithreaded sharing and the
|
|
1152
|
+
// associated cache flushing.
|
|
1153
|
+
if ( indices[0] != B2_NULL_INDEX )
|
|
1154
|
+
_mm256_store_ps( (float*)( states + indices[0] ), _mm256_permute2f128_ps( tt0, tt4, 0x20 ) );
|
|
1155
|
+
if ( indices[1] != B2_NULL_INDEX )
|
|
1156
|
+
_mm256_store_ps( (float*)( states + indices[1] ), _mm256_permute2f128_ps( tt1, tt5, 0x20 ) );
|
|
1157
|
+
if ( indices[2] != B2_NULL_INDEX )
|
|
1158
|
+
_mm256_store_ps( (float*)( states + indices[2] ), _mm256_permute2f128_ps( tt2, tt6, 0x20 ) );
|
|
1159
|
+
if ( indices[3] != B2_NULL_INDEX )
|
|
1160
|
+
_mm256_store_ps( (float*)( states + indices[3] ), _mm256_permute2f128_ps( tt3, tt7, 0x20 ) );
|
|
1161
|
+
if ( indices[4] != B2_NULL_INDEX )
|
|
1162
|
+
_mm256_store_ps( (float*)( states + indices[4] ), _mm256_permute2f128_ps( tt0, tt4, 0x31 ) );
|
|
1163
|
+
if ( indices[5] != B2_NULL_INDEX )
|
|
1164
|
+
_mm256_store_ps( (float*)( states + indices[5] ), _mm256_permute2f128_ps( tt1, tt5, 0x31 ) );
|
|
1165
|
+
if ( indices[6] != B2_NULL_INDEX )
|
|
1166
|
+
_mm256_store_ps( (float*)( states + indices[6] ), _mm256_permute2f128_ps( tt2, tt6, 0x31 ) );
|
|
1167
|
+
if ( indices[7] != B2_NULL_INDEX )
|
|
1168
|
+
_mm256_store_ps( (float*)( states + indices[7] ), _mm256_permute2f128_ps( tt3, tt7, 0x31 ) );
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
#elif defined( B2_SIMD_NEON )
|
|
1172
|
+
|
|
1173
|
+
// This is a load and transpose
|
|
1174
|
+
static b2BodyStateW b2GatherBodies( const b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices )
|
|
1175
|
+
{
|
|
1176
|
+
_Static_assert( sizeof( b2BodyState ) == 32, "b2BodyState not 32 bytes" );
|
|
1177
|
+
B2_ASSERT( ( (uintptr_t)states & 0x1F ) == 0 );
|
|
1178
|
+
|
|
1179
|
+
// [vx vy w flags]
|
|
1180
|
+
b2FloatW identityA = b2ZeroW();
|
|
1181
|
+
|
|
1182
|
+
// [dpx dpy dqc dqs]
|
|
1183
|
+
|
|
1184
|
+
b2FloatW identityB = b2SetW( 0.0f, 0.0f, 1.0f, 0.0f );
|
|
1185
|
+
|
|
1186
|
+
b2FloatW b1a = indices[0] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[0] ) + 0 );
|
|
1187
|
+
b2FloatW b1b = indices[0] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[0] ) + 4 );
|
|
1188
|
+
b2FloatW b2a = indices[1] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[1] ) + 0 );
|
|
1189
|
+
b2FloatW b2b = indices[1] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[1] ) + 4 );
|
|
1190
|
+
b2FloatW b3a = indices[2] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[2] ) + 0 );
|
|
1191
|
+
b2FloatW b3b = indices[2] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[2] ) + 4 );
|
|
1192
|
+
b2FloatW b4a = indices[3] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[3] ) + 0 );
|
|
1193
|
+
b2FloatW b4b = indices[3] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[3] ) + 4 );
|
|
1194
|
+
|
|
1195
|
+
// [vx1 vx3 vy1 vy3]
|
|
1196
|
+
b2FloatW t1a = b2UnpackLoW( b1a, b3a );
|
|
1197
|
+
|
|
1198
|
+
// [vx2 vx4 vy2 vy4]
|
|
1199
|
+
b2FloatW t2a = b2UnpackLoW( b2a, b4a );
|
|
1200
|
+
|
|
1201
|
+
// [w1 w3 f1 f3]
|
|
1202
|
+
b2FloatW t3a = b2UnpackHiW( b1a, b3a );
|
|
1203
|
+
|
|
1204
|
+
// [w2 w4 f2 f4]
|
|
1205
|
+
b2FloatW t4a = b2UnpackHiW( b2a, b4a );
|
|
1206
|
+
|
|
1207
|
+
b2BodyStateW simdBody;
|
|
1208
|
+
simdBody.v.X = b2UnpackLoW( t1a, t2a );
|
|
1209
|
+
simdBody.v.Y = b2UnpackHiW( t1a, t2a );
|
|
1210
|
+
simdBody.w = b2UnpackLoW( t3a, t4a );
|
|
1211
|
+
simdBody.flags = b2UnpackHiW( t3a, t4a );
|
|
1212
|
+
|
|
1213
|
+
b2FloatW t1b = b2UnpackLoW( b1b, b3b );
|
|
1214
|
+
b2FloatW t2b = b2UnpackLoW( b2b, b4b );
|
|
1215
|
+
b2FloatW t3b = b2UnpackHiW( b1b, b3b );
|
|
1216
|
+
b2FloatW t4b = b2UnpackHiW( b2b, b4b );
|
|
1217
|
+
|
|
1218
|
+
simdBody.dp.X = b2UnpackLoW( t1b, t2b );
|
|
1219
|
+
simdBody.dp.Y = b2UnpackHiW( t1b, t2b );
|
|
1220
|
+
simdBody.dq.C = b2UnpackLoW( t3b, t4b );
|
|
1221
|
+
simdBody.dq.S = b2UnpackHiW( t3b, t4b );
|
|
1222
|
+
|
|
1223
|
+
return simdBody;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// This writes only the velocities back to the solver bodies
|
|
1227
|
+
// https://developer.arm.com/documentation/102107a/0100/Floating-point-4x4-matrix-transposition
|
|
1228
|
+
static void b2ScatterBodies( b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices, const b2BodyStateW* B2_RESTRICT simdBody )
|
|
1229
|
+
{
|
|
1230
|
+
_Static_assert( sizeof( b2BodyState ) == 32, "b2BodyState not 32 bytes" );
|
|
1231
|
+
B2_ASSERT( ( (uintptr_t)states & 0x1F ) == 0 );
|
|
1232
|
+
|
|
1233
|
+
// b2FloatW x = b2SetW(0.0f, 1.0f, 2.0f, 3.0f);
|
|
1234
|
+
// b2FloatW y = b2SetW(4.0f, 5.0f, 6.0f, 7.0f);
|
|
1235
|
+
// b2FloatW z = b2SetW(8.0f, 9.0f, 10.0f, 11.0f);
|
|
1236
|
+
// b2FloatW w = b2SetW(12.0f, 13.0f, 14.0f, 15.0f);
|
|
1237
|
+
//
|
|
1238
|
+
// float32x4x2_t rr1 = vtrnq_f32( x, y );
|
|
1239
|
+
// float32x4x2_t rr2 = vtrnq_f32( z, w );
|
|
1240
|
+
//
|
|
1241
|
+
// float32x4_t b1 = vcombine_f32(vget_low_f32(rr1.val[0]), vget_low_f32(rr2.val[0]));
|
|
1242
|
+
// float32x4_t b2 = vcombine_f32(vget_low_f32(rr1.val[1]), vget_low_f32(rr2.val[1]));
|
|
1243
|
+
// float32x4_t b3 = vcombine_f32(vget_high_f32(rr1.val[0]), vget_high_f32(rr2.val[0]));
|
|
1244
|
+
// float32x4_t b4 = vcombine_f32(vget_high_f32(rr1.val[1]), vget_high_f32(rr2.val[1]));
|
|
1245
|
+
|
|
1246
|
+
// transpose
|
|
1247
|
+
float32x4x2_t r1 = vtrnq_f32( simdBody->v.X, simdBody->v.Y );
|
|
1248
|
+
float32x4x2_t r2 = vtrnq_f32( simdBody->w, simdBody->flags );
|
|
1249
|
+
|
|
1250
|
+
// I don't use any dummy body in the body array because this will lead to multithreaded sharing and the
|
|
1251
|
+
// associated cache flushing.
|
|
1252
|
+
if ( indices[0] != B2_NULL_INDEX )
|
|
1253
|
+
{
|
|
1254
|
+
float32x4_t body1 = vcombine_f32( vget_low_f32( r1.val[0] ), vget_low_f32( r2.val[0] ) );
|
|
1255
|
+
b2StoreW( (float*)( states + indices[0] ), body1 );
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if ( indices[1] != B2_NULL_INDEX )
|
|
1259
|
+
{
|
|
1260
|
+
float32x4_t body2 = vcombine_f32( vget_low_f32( r1.val[1] ), vget_low_f32( r2.val[1] ) );
|
|
1261
|
+
b2StoreW( (float*)( states + indices[1] ), body2 );
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
if ( indices[2] != B2_NULL_INDEX )
|
|
1265
|
+
{
|
|
1266
|
+
float32x4_t body3 = vcombine_f32( vget_high_f32( r1.val[0] ), vget_high_f32( r2.val[0] ) );
|
|
1267
|
+
b2StoreW( (float*)( states + indices[2] ), body3 );
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
if ( indices[3] != B2_NULL_INDEX )
|
|
1271
|
+
{
|
|
1272
|
+
float32x4_t body4 = vcombine_f32( vget_high_f32( r1.val[1] ), vget_high_f32( r2.val[1] ) );
|
|
1273
|
+
b2StoreW( (float*)( states + indices[3] ), body4 );
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
#elif defined( B2_SIMD_SSE2 )
|
|
1278
|
+
|
|
1279
|
+
// This is a load and transpose
|
|
1280
|
+
static b2BodyStateW b2GatherBodies( const b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices )
|
|
1281
|
+
{
|
|
1282
|
+
_Static_assert( sizeof( b2BodyState ) == 32, "b2BodyState not 32 bytes" );
|
|
1283
|
+
B2_ASSERT( ( (uintptr_t)states & 0x1F ) == 0 );
|
|
1284
|
+
|
|
1285
|
+
// [vx vy w flags]
|
|
1286
|
+
b2FloatW identityA = b2ZeroW();
|
|
1287
|
+
|
|
1288
|
+
// [dpx dpy dqc dqs]
|
|
1289
|
+
b2FloatW identityB = b2SetW( 0.0f, 0.0f, 1.0f, 0.0f );
|
|
1290
|
+
|
|
1291
|
+
b2FloatW b1a = indices[0] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[0] ) + 0 );
|
|
1292
|
+
b2FloatW b1b = indices[0] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[0] ) + 4 );
|
|
1293
|
+
b2FloatW b2a = indices[1] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[1] ) + 0 );
|
|
1294
|
+
b2FloatW b2b = indices[1] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[1] ) + 4 );
|
|
1295
|
+
b2FloatW b3a = indices[2] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[2] ) + 0 );
|
|
1296
|
+
b2FloatW b3b = indices[2] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[2] ) + 4 );
|
|
1297
|
+
b2FloatW b4a = indices[3] == B2_NULL_INDEX ? identityA : b2LoadW( (float*)( states + indices[3] ) + 0 );
|
|
1298
|
+
b2FloatW b4b = indices[3] == B2_NULL_INDEX ? identityB : b2LoadW( (float*)( states + indices[3] ) + 4 );
|
|
1299
|
+
|
|
1300
|
+
// [vx1 vx3 vy1 vy3]
|
|
1301
|
+
b2FloatW t1a = b2UnpackLoW( b1a, b3a );
|
|
1302
|
+
|
|
1303
|
+
// [vx2 vx4 vy2 vy4]
|
|
1304
|
+
b2FloatW t2a = b2UnpackLoW( b2a, b4a );
|
|
1305
|
+
|
|
1306
|
+
// [w1 w3 f1 f3]
|
|
1307
|
+
b2FloatW t3a = b2UnpackHiW( b1a, b3a );
|
|
1308
|
+
|
|
1309
|
+
// [w2 w4 f2 f4]
|
|
1310
|
+
b2FloatW t4a = b2UnpackHiW( b2a, b4a );
|
|
1311
|
+
|
|
1312
|
+
b2BodyStateW simdBody;
|
|
1313
|
+
simdBody.v.X = b2UnpackLoW( t1a, t2a );
|
|
1314
|
+
simdBody.v.Y = b2UnpackHiW( t1a, t2a );
|
|
1315
|
+
simdBody.w = b2UnpackLoW( t3a, t4a );
|
|
1316
|
+
simdBody.flags = b2UnpackHiW( t3a, t4a );
|
|
1317
|
+
|
|
1318
|
+
b2FloatW t1b = b2UnpackLoW( b1b, b3b );
|
|
1319
|
+
b2FloatW t2b = b2UnpackLoW( b2b, b4b );
|
|
1320
|
+
b2FloatW t3b = b2UnpackHiW( b1b, b3b );
|
|
1321
|
+
b2FloatW t4b = b2UnpackHiW( b2b, b4b );
|
|
1322
|
+
|
|
1323
|
+
simdBody.dp.X = b2UnpackLoW( t1b, t2b );
|
|
1324
|
+
simdBody.dp.Y = b2UnpackHiW( t1b, t2b );
|
|
1325
|
+
simdBody.dq.C = b2UnpackLoW( t3b, t4b );
|
|
1326
|
+
simdBody.dq.S = b2UnpackHiW( t3b, t4b );
|
|
1327
|
+
|
|
1328
|
+
return simdBody;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// This writes only the velocities back to the solver bodies
|
|
1332
|
+
static void b2ScatterBodies( b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices, const b2BodyStateW* B2_RESTRICT simdBody )
|
|
1333
|
+
{
|
|
1334
|
+
_Static_assert( sizeof( b2BodyState ) == 32, "b2BodyState not 32 bytes" );
|
|
1335
|
+
B2_ASSERT( ( (uintptr_t)states & 0x1F ) == 0 );
|
|
1336
|
+
|
|
1337
|
+
// [vx1 vy1 vx2 vy2]
|
|
1338
|
+
b2FloatW t1 = b2UnpackLoW( simdBody->v.X, simdBody->v.Y );
|
|
1339
|
+
// [vx3 vy3 vx4 vy4]
|
|
1340
|
+
b2FloatW t2 = b2UnpackHiW( simdBody->v.X, simdBody->v.Y );
|
|
1341
|
+
// [w1 f1 w2 f2]
|
|
1342
|
+
b2FloatW t3 = b2UnpackLoW( simdBody->w, simdBody->flags );
|
|
1343
|
+
// [w3 f3 w4 f4]
|
|
1344
|
+
b2FloatW t4 = b2UnpackHiW( simdBody->w, simdBody->flags );
|
|
1345
|
+
|
|
1346
|
+
// I don't use any dummy body in the body array because this will lead to multithreaded sharing and the
|
|
1347
|
+
// associated cache flushing.
|
|
1348
|
+
if ( indices[0] != B2_NULL_INDEX )
|
|
1349
|
+
{
|
|
1350
|
+
// [t1.x t1.y t3.x t3.y]
|
|
1351
|
+
b2StoreW( (float*)( states + indices[0] ), _mm_shuffle_ps( t1, t3, _MM_SHUFFLE( 1, 0, 1, 0 ) ) );
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
if ( indices[1] != B2_NULL_INDEX )
|
|
1355
|
+
{
|
|
1356
|
+
// [t1.z t1.w t3.z t3.w]
|
|
1357
|
+
b2StoreW( (float*)( states + indices[1] ), _mm_shuffle_ps( t1, t3, _MM_SHUFFLE( 3, 2, 3, 2 ) ) );
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
if ( indices[2] != B2_NULL_INDEX )
|
|
1361
|
+
{
|
|
1362
|
+
// [t2.x t2.y t4.x t4.y]
|
|
1363
|
+
b2StoreW( (float*)( states + indices[2] ), _mm_shuffle_ps( t2, t4, _MM_SHUFFLE( 1, 0, 1, 0 ) ) );
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
if ( indices[3] != B2_NULL_INDEX )
|
|
1367
|
+
{
|
|
1368
|
+
// [t2.z t2.w t4.z t4.w]
|
|
1369
|
+
b2StoreW( (float*)( states + indices[3] ), _mm_shuffle_ps( t2, t4, _MM_SHUFFLE( 3, 2, 3, 2 ) ) );
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
#else
|
|
1374
|
+
|
|
1375
|
+
// This is a load and transpose
|
|
1376
|
+
static b2BodyStateW b2GatherBodies( const b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices )
|
|
1377
|
+
{
|
|
1378
|
+
b2BodyState identity = b2_identityBodyState;
|
|
1379
|
+
|
|
1380
|
+
b2BodyState s1 = indices[0] == B2_NULL_INDEX ? identity : states[indices[0]];
|
|
1381
|
+
b2BodyState s2 = indices[1] == B2_NULL_INDEX ? identity : states[indices[1]];
|
|
1382
|
+
b2BodyState s3 = indices[2] == B2_NULL_INDEX ? identity : states[indices[2]];
|
|
1383
|
+
b2BodyState s4 = indices[3] == B2_NULL_INDEX ? identity : states[indices[3]];
|
|
1384
|
+
|
|
1385
|
+
b2BodyStateW simdBody;
|
|
1386
|
+
simdBody.v.X = (b2FloatW){ s1.linearVelocity.x, s2.linearVelocity.x, s3.linearVelocity.x, s4.linearVelocity.x };
|
|
1387
|
+
simdBody.v.Y = (b2FloatW){ s1.linearVelocity.y, s2.linearVelocity.y, s3.linearVelocity.y, s4.linearVelocity.y };
|
|
1388
|
+
simdBody.w = (b2FloatW){ s1.angularVelocity, s2.angularVelocity, s3.angularVelocity, s4.angularVelocity };
|
|
1389
|
+
simdBody.flags = (b2FloatW){ (float)s1.flags, (float)s2.flags, (float)s3.flags, (float)s4.flags };
|
|
1390
|
+
simdBody.dp.X = (b2FloatW){ s1.deltaPosition.x, s2.deltaPosition.x, s3.deltaPosition.x, s4.deltaPosition.x };
|
|
1391
|
+
simdBody.dp.Y = (b2FloatW){ s1.deltaPosition.y, s2.deltaPosition.y, s3.deltaPosition.y, s4.deltaPosition.y };
|
|
1392
|
+
simdBody.dq.C = (b2FloatW){ s1.deltaRotation.c, s2.deltaRotation.c, s3.deltaRotation.c, s4.deltaRotation.c };
|
|
1393
|
+
simdBody.dq.S = (b2FloatW){ s1.deltaRotation.s, s2.deltaRotation.s, s3.deltaRotation.s, s4.deltaRotation.s };
|
|
1394
|
+
|
|
1395
|
+
return simdBody;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// This writes only the velocities back to the solver bodies
|
|
1399
|
+
static void b2ScatterBodies( b2BodyState* B2_RESTRICT states, int* B2_RESTRICT indices, const b2BodyStateW* B2_RESTRICT simdBody )
|
|
1400
|
+
{
|
|
1401
|
+
// todo somehow skip writing to kinematic bodies
|
|
1402
|
+
|
|
1403
|
+
if ( indices[0] != B2_NULL_INDEX )
|
|
1404
|
+
{
|
|
1405
|
+
b2BodyState* state = states + indices[0];
|
|
1406
|
+
state->linearVelocity.x = simdBody->v.X.x;
|
|
1407
|
+
state->linearVelocity.y = simdBody->v.Y.x;
|
|
1408
|
+
state->angularVelocity = simdBody->w.x;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
if ( indices[1] != B2_NULL_INDEX )
|
|
1412
|
+
{
|
|
1413
|
+
b2BodyState* state = states + indices[1];
|
|
1414
|
+
state->linearVelocity.x = simdBody->v.X.y;
|
|
1415
|
+
state->linearVelocity.y = simdBody->v.Y.y;
|
|
1416
|
+
state->angularVelocity = simdBody->w.y;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
if ( indices[2] != B2_NULL_INDEX )
|
|
1420
|
+
{
|
|
1421
|
+
b2BodyState* state = states + indices[2];
|
|
1422
|
+
state->linearVelocity.x = simdBody->v.X.z;
|
|
1423
|
+
state->linearVelocity.y = simdBody->v.Y.z;
|
|
1424
|
+
state->angularVelocity = simdBody->w.z;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
if ( indices[3] != B2_NULL_INDEX )
|
|
1428
|
+
{
|
|
1429
|
+
b2BodyState* state = states + indices[3];
|
|
1430
|
+
state->linearVelocity.x = simdBody->v.X.w;
|
|
1431
|
+
state->linearVelocity.y = simdBody->v.Y.w;
|
|
1432
|
+
state->angularVelocity = simdBody->w.w;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
#endif
|
|
1437
|
+
|
|
1438
|
+
void b2PrepareContactsTask( int startIndex, int endIndex, b2StepContext* context )
|
|
1439
|
+
{
|
|
1440
|
+
b2TracyCZoneNC( prepare_contact, "Prepare Contact", b2_colorYellow, true );
|
|
1441
|
+
b2World* world = context->world;
|
|
1442
|
+
b2ContactSim** contacts = context->contacts;
|
|
1443
|
+
b2ContactConstraintSIMD* constraints = context->simdContactConstraints;
|
|
1444
|
+
b2BodyState* awakeStates = context->states;
|
|
1445
|
+
#if B2_VALIDATE
|
|
1446
|
+
b2Body* bodies = world->bodies.data;
|
|
1447
|
+
#endif
|
|
1448
|
+
|
|
1449
|
+
// Stiffer for static contacts to avoid bodies getting pushed through the ground
|
|
1450
|
+
b2Softness contactSoftness = context->contactSoftness;
|
|
1451
|
+
b2Softness staticSoftness = context->staticSoftness;
|
|
1452
|
+
|
|
1453
|
+
float warmStartScale = world->enableWarmStarting ? 1.0f : 0.0f;
|
|
1454
|
+
|
|
1455
|
+
for ( int i = startIndex; i < endIndex; ++i )
|
|
1456
|
+
{
|
|
1457
|
+
b2ContactConstraintSIMD* constraint = constraints + i;
|
|
1458
|
+
|
|
1459
|
+
for ( int j = 0; j < B2_SIMD_WIDTH; ++j )
|
|
1460
|
+
{
|
|
1461
|
+
b2ContactSim* contactSim = contacts[B2_SIMD_WIDTH * i + j];
|
|
1462
|
+
|
|
1463
|
+
if ( contactSim != NULL )
|
|
1464
|
+
{
|
|
1465
|
+
const b2Manifold* manifold = &contactSim->manifold;
|
|
1466
|
+
|
|
1467
|
+
int indexA = contactSim->bodySimIndexA;
|
|
1468
|
+
int indexB = contactSim->bodySimIndexB;
|
|
1469
|
+
|
|
1470
|
+
#if B2_VALIDATE
|
|
1471
|
+
b2Body* bodyA = bodies + contactSim->bodyIdA;
|
|
1472
|
+
int validIndexA = bodyA->setIndex == b2_awakeSet ? bodyA->localIndex : B2_NULL_INDEX;
|
|
1473
|
+
b2Body* bodyB = bodies + contactSim->bodyIdB;
|
|
1474
|
+
int validIndexB = bodyB->setIndex == b2_awakeSet ? bodyB->localIndex : B2_NULL_INDEX;
|
|
1475
|
+
|
|
1476
|
+
B2_ASSERT( indexA == validIndexA );
|
|
1477
|
+
B2_ASSERT( indexB == validIndexB );
|
|
1478
|
+
#endif
|
|
1479
|
+
constraint->indexA[j] = indexA;
|
|
1480
|
+
constraint->indexB[j] = indexB;
|
|
1481
|
+
|
|
1482
|
+
b2Vec2 vA = b2Vec2_zero;
|
|
1483
|
+
float wA = 0.0f;
|
|
1484
|
+
float mA = contactSim->invMassA;
|
|
1485
|
+
float iA = contactSim->invIA;
|
|
1486
|
+
if ( indexA != B2_NULL_INDEX )
|
|
1487
|
+
{
|
|
1488
|
+
b2BodyState* stateA = awakeStates + indexA;
|
|
1489
|
+
vA = stateA->linearVelocity;
|
|
1490
|
+
wA = stateA->angularVelocity;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
b2Vec2 vB = b2Vec2_zero;
|
|
1494
|
+
float wB = 0.0f;
|
|
1495
|
+
float mB = contactSim->invMassB;
|
|
1496
|
+
float iB = contactSim->invIB;
|
|
1497
|
+
if ( indexB != B2_NULL_INDEX )
|
|
1498
|
+
{
|
|
1499
|
+
b2BodyState* stateB = awakeStates + indexB;
|
|
1500
|
+
vB = stateB->linearVelocity;
|
|
1501
|
+
wB = stateB->angularVelocity;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
( (float*)&constraint->invMassA )[j] = mA;
|
|
1505
|
+
( (float*)&constraint->invMassB )[j] = mB;
|
|
1506
|
+
( (float*)&constraint->invIA )[j] = iA;
|
|
1507
|
+
( (float*)&constraint->invIB )[j] = iB;
|
|
1508
|
+
|
|
1509
|
+
{
|
|
1510
|
+
float k = iA + iB;
|
|
1511
|
+
( (float*)&constraint->rollingMass )[j] = k > 0.0f ? 1.0f / k : 0.0f;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
b2Softness soft = ( indexA == B2_NULL_INDEX || indexB == B2_NULL_INDEX ) ? staticSoftness : contactSoftness;
|
|
1515
|
+
|
|
1516
|
+
b2Vec2 normal = manifold->normal;
|
|
1517
|
+
( (float*)&constraint->normal.X )[j] = normal.x;
|
|
1518
|
+
( (float*)&constraint->normal.Y )[j] = normal.y;
|
|
1519
|
+
|
|
1520
|
+
( (float*)&constraint->friction )[j] = contactSim->friction;
|
|
1521
|
+
( (float*)&constraint->tangentSpeed )[j] = contactSim->tangentSpeed;
|
|
1522
|
+
( (float*)&constraint->restitution )[j] = contactSim->restitution;
|
|
1523
|
+
( (float*)&constraint->rollingResistance )[j] = contactSim->rollingResistance;
|
|
1524
|
+
( (float*)&constraint->rollingImpulse )[j] = warmStartScale * manifold->rollingImpulse;
|
|
1525
|
+
|
|
1526
|
+
( (float*)&constraint->biasRate )[j] = soft.biasRate;
|
|
1527
|
+
( (float*)&constraint->massScale )[j] = soft.massScale;
|
|
1528
|
+
( (float*)&constraint->impulseScale )[j] = soft.impulseScale;
|
|
1529
|
+
|
|
1530
|
+
b2Vec2 tangent = b2RightPerp( normal );
|
|
1531
|
+
|
|
1532
|
+
{
|
|
1533
|
+
const b2ManifoldPoint* mp = manifold->points + 0;
|
|
1534
|
+
|
|
1535
|
+
b2Vec2 rA = mp->anchorA;
|
|
1536
|
+
b2Vec2 rB = mp->anchorB;
|
|
1537
|
+
|
|
1538
|
+
( (float*)&constraint->anchorA1.X )[j] = rA.x;
|
|
1539
|
+
( (float*)&constraint->anchorA1.Y )[j] = rA.y;
|
|
1540
|
+
( (float*)&constraint->anchorB1.X )[j] = rB.x;
|
|
1541
|
+
( (float*)&constraint->anchorB1.Y )[j] = rB.y;
|
|
1542
|
+
|
|
1543
|
+
( (float*)&constraint->baseSeparation1 )[j] = mp->separation - b2Dot( b2Sub( rB, rA ), normal );
|
|
1544
|
+
|
|
1545
|
+
( (float*)&constraint->normalImpulse1 )[j] = warmStartScale * mp->normalImpulse;
|
|
1546
|
+
( (float*)&constraint->tangentImpulse1 )[j] = warmStartScale * mp->tangentImpulse;
|
|
1547
|
+
( (float*)&constraint->totalNormalImpulse1 )[j] = 0.0f;
|
|
1548
|
+
|
|
1549
|
+
float rnA = b2Cross( rA, normal );
|
|
1550
|
+
float rnB = b2Cross( rB, normal );
|
|
1551
|
+
float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
|
1552
|
+
( (float*)&constraint->normalMass1 )[j] = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
|
|
1553
|
+
|
|
1554
|
+
float rtA = b2Cross( rA, tangent );
|
|
1555
|
+
float rtB = b2Cross( rB, tangent );
|
|
1556
|
+
float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
|
|
1557
|
+
( (float*)&constraint->tangentMass1 )[j] = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;
|
|
1558
|
+
|
|
1559
|
+
// relative velocity for restitution
|
|
1560
|
+
b2Vec2 vrA = b2Add( vA, b2CrossSV( wA, rA ) );
|
|
1561
|
+
b2Vec2 vrB = b2Add( vB, b2CrossSV( wB, rB ) );
|
|
1562
|
+
( (float*)&constraint->relativeVelocity1 )[j] = b2Dot( normal, b2Sub( vrB, vrA ) );
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
int pointCount = manifold->pointCount;
|
|
1566
|
+
B2_ASSERT( 0 < pointCount && pointCount <= 2 );
|
|
1567
|
+
|
|
1568
|
+
if ( pointCount == 2 )
|
|
1569
|
+
{
|
|
1570
|
+
const b2ManifoldPoint* mp = manifold->points + 1;
|
|
1571
|
+
|
|
1572
|
+
b2Vec2 rA = mp->anchorA;
|
|
1573
|
+
b2Vec2 rB = mp->anchorB;
|
|
1574
|
+
|
|
1575
|
+
( (float*)&constraint->anchorA2.X )[j] = rA.x;
|
|
1576
|
+
( (float*)&constraint->anchorA2.Y )[j] = rA.y;
|
|
1577
|
+
( (float*)&constraint->anchorB2.X )[j] = rB.x;
|
|
1578
|
+
( (float*)&constraint->anchorB2.Y )[j] = rB.y;
|
|
1579
|
+
|
|
1580
|
+
( (float*)&constraint->baseSeparation2 )[j] = mp->separation - b2Dot( b2Sub( rB, rA ), normal );
|
|
1581
|
+
|
|
1582
|
+
( (float*)&constraint->normalImpulse2 )[j] = warmStartScale * mp->normalImpulse;
|
|
1583
|
+
( (float*)&constraint->tangentImpulse2 )[j] = warmStartScale * mp->tangentImpulse;
|
|
1584
|
+
( (float*)&constraint->totalNormalImpulse2 )[j] = 0.0f;
|
|
1585
|
+
|
|
1586
|
+
float rnA = b2Cross( rA, normal );
|
|
1587
|
+
float rnB = b2Cross( rB, normal );
|
|
1588
|
+
float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
|
1589
|
+
( (float*)&constraint->normalMass2 )[j] = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
|
|
1590
|
+
|
|
1591
|
+
float rtA = b2Cross( rA, tangent );
|
|
1592
|
+
float rtB = b2Cross( rB, tangent );
|
|
1593
|
+
float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
|
|
1594
|
+
( (float*)&constraint->tangentMass2 )[j] = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;
|
|
1595
|
+
|
|
1596
|
+
// relative velocity for restitution
|
|
1597
|
+
b2Vec2 vrA = b2Add( vA, b2CrossSV( wA, rA ) );
|
|
1598
|
+
b2Vec2 vrB = b2Add( vB, b2CrossSV( wB, rB ) );
|
|
1599
|
+
( (float*)&constraint->relativeVelocity2 )[j] = b2Dot( normal, b2Sub( vrB, vrA ) );
|
|
1600
|
+
}
|
|
1601
|
+
else
|
|
1602
|
+
{
|
|
1603
|
+
// dummy data that has no effect
|
|
1604
|
+
( (float*)&constraint->baseSeparation2 )[j] = 0.0f;
|
|
1605
|
+
( (float*)&constraint->normalImpulse2 )[j] = 0.0f;
|
|
1606
|
+
( (float*)&constraint->tangentImpulse2 )[j] = 0.0f;
|
|
1607
|
+
( (float*)&constraint->totalNormalImpulse2 )[j] = 0.0f;
|
|
1608
|
+
( (float*)&constraint->anchorA2.X )[j] = 0.0f;
|
|
1609
|
+
( (float*)&constraint->anchorA2.Y )[j] = 0.0f;
|
|
1610
|
+
( (float*)&constraint->anchorB2.X )[j] = 0.0f;
|
|
1611
|
+
( (float*)&constraint->anchorB2.Y )[j] = 0.0f;
|
|
1612
|
+
( (float*)&constraint->normalMass2 )[j] = 0.0f;
|
|
1613
|
+
( (float*)&constraint->tangentMass2 )[j] = 0.0f;
|
|
1614
|
+
( (float*)&constraint->relativeVelocity2 )[j] = 0.0f;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
else
|
|
1618
|
+
{
|
|
1619
|
+
// SIMD remainder
|
|
1620
|
+
constraint->indexA[j] = B2_NULL_INDEX;
|
|
1621
|
+
constraint->indexB[j] = B2_NULL_INDEX;
|
|
1622
|
+
|
|
1623
|
+
( (float*)&constraint->invMassA )[j] = 0.0f;
|
|
1624
|
+
( (float*)&constraint->invMassB )[j] = 0.0f;
|
|
1625
|
+
( (float*)&constraint->invIA )[j] = 0.0f;
|
|
1626
|
+
( (float*)&constraint->invIB )[j] = 0.0f;
|
|
1627
|
+
|
|
1628
|
+
( (float*)&constraint->normal.X )[j] = 0.0f;
|
|
1629
|
+
( (float*)&constraint->normal.Y )[j] = 0.0f;
|
|
1630
|
+
( (float*)&constraint->friction )[j] = 0.0f;
|
|
1631
|
+
( (float*)&constraint->tangentSpeed )[j] = 0.0f;
|
|
1632
|
+
( (float*)&constraint->rollingResistance )[j] = 0.0f;
|
|
1633
|
+
( (float*)&constraint->rollingMass )[j] = 0.0f;
|
|
1634
|
+
( (float*)&constraint->rollingImpulse )[j] = 0.0f;
|
|
1635
|
+
( (float*)&constraint->biasRate )[j] = 0.0f;
|
|
1636
|
+
( (float*)&constraint->massScale )[j] = 0.0f;
|
|
1637
|
+
( (float*)&constraint->impulseScale )[j] = 0.0f;
|
|
1638
|
+
|
|
1639
|
+
( (float*)&constraint->anchorA1.X )[j] = 0.0f;
|
|
1640
|
+
( (float*)&constraint->anchorA1.Y )[j] = 0.0f;
|
|
1641
|
+
( (float*)&constraint->anchorB1.X )[j] = 0.0f;
|
|
1642
|
+
( (float*)&constraint->anchorB1.Y )[j] = 0.0f;
|
|
1643
|
+
( (float*)&constraint->baseSeparation1 )[j] = 0.0f;
|
|
1644
|
+
( (float*)&constraint->normalImpulse1 )[j] = 0.0f;
|
|
1645
|
+
( (float*)&constraint->tangentImpulse1 )[j] = 0.0f;
|
|
1646
|
+
( (float*)&constraint->totalNormalImpulse1 )[j] = 0.0f;
|
|
1647
|
+
( (float*)&constraint->normalMass1 )[j] = 0.0f;
|
|
1648
|
+
( (float*)&constraint->tangentMass1 )[j] = 0.0f;
|
|
1649
|
+
|
|
1650
|
+
( (float*)&constraint->anchorA2.X )[j] = 0.0f;
|
|
1651
|
+
( (float*)&constraint->anchorA2.Y )[j] = 0.0f;
|
|
1652
|
+
( (float*)&constraint->anchorB2.X )[j] = 0.0f;
|
|
1653
|
+
( (float*)&constraint->anchorB2.Y )[j] = 0.0f;
|
|
1654
|
+
( (float*)&constraint->baseSeparation2 )[j] = 0.0f;
|
|
1655
|
+
( (float*)&constraint->normalImpulse2 )[j] = 0.0f;
|
|
1656
|
+
( (float*)&constraint->tangentImpulse2 )[j] = 0.0f;
|
|
1657
|
+
( (float*)&constraint->totalNormalImpulse2 )[j] = 0.0f;
|
|
1658
|
+
( (float*)&constraint->normalMass2 )[j] = 0.0f;
|
|
1659
|
+
( (float*)&constraint->tangentMass2 )[j] = 0.0f;
|
|
1660
|
+
|
|
1661
|
+
( (float*)&constraint->restitution )[j] = 0.0f;
|
|
1662
|
+
( (float*)&constraint->relativeVelocity1 )[j] = 0.0f;
|
|
1663
|
+
( (float*)&constraint->relativeVelocity2 )[j] = 0.0f;
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
b2TracyCZoneEnd( prepare_contact );
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
void b2WarmStartContactsTask( int startIndex, int endIndex, b2StepContext* context, int colorIndex )
|
|
1672
|
+
{
|
|
1673
|
+
b2TracyCZoneNC( warm_start_contact, "Warm Start", b2_colorGreen, true );
|
|
1674
|
+
|
|
1675
|
+
b2BodyState* states = context->states;
|
|
1676
|
+
b2ContactConstraintSIMD* constraints = context->graph->colors[colorIndex].simdConstraints;
|
|
1677
|
+
|
|
1678
|
+
for ( int i = startIndex; i < endIndex; ++i )
|
|
1679
|
+
{
|
|
1680
|
+
b2ContactConstraintSIMD* c = constraints + i;
|
|
1681
|
+
b2BodyStateW bA = b2GatherBodies( states, c->indexA );
|
|
1682
|
+
b2BodyStateW bB = b2GatherBodies( states, c->indexB );
|
|
1683
|
+
|
|
1684
|
+
b2FloatW tangentX = c->normal.Y;
|
|
1685
|
+
b2FloatW tangentY = b2SubW( b2ZeroW(), c->normal.X );
|
|
1686
|
+
|
|
1687
|
+
{
|
|
1688
|
+
// fixed anchors
|
|
1689
|
+
b2Vec2W rA = c->anchorA1;
|
|
1690
|
+
b2Vec2W rB = c->anchorB1;
|
|
1691
|
+
|
|
1692
|
+
b2Vec2W P;
|
|
1693
|
+
P.X = b2AddW( b2MulW( c->normalImpulse1, c->normal.X ), b2MulW( c->tangentImpulse1, tangentX ) );
|
|
1694
|
+
P.Y = b2AddW( b2MulW( c->normalImpulse1, c->normal.Y ), b2MulW( c->tangentImpulse1, tangentY ) );
|
|
1695
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2CrossW( rA, P ) );
|
|
1696
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, P.X );
|
|
1697
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, P.Y );
|
|
1698
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2CrossW( rB, P ) );
|
|
1699
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, P.X );
|
|
1700
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, P.Y );
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
{
|
|
1704
|
+
// fixed anchors
|
|
1705
|
+
b2Vec2W rA = c->anchorA2;
|
|
1706
|
+
b2Vec2W rB = c->anchorB2;
|
|
1707
|
+
|
|
1708
|
+
b2Vec2W P;
|
|
1709
|
+
P.X = b2AddW( b2MulW( c->normalImpulse2, c->normal.X ), b2MulW( c->tangentImpulse2, tangentX ) );
|
|
1710
|
+
P.Y = b2AddW( b2MulW( c->normalImpulse2, c->normal.Y ), b2MulW( c->tangentImpulse2, tangentY ) );
|
|
1711
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2CrossW( rA, P ) );
|
|
1712
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, P.X );
|
|
1713
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, P.Y );
|
|
1714
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2CrossW( rB, P ) );
|
|
1715
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, P.X );
|
|
1716
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, P.Y );
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
bA.w = b2MulSubW( bA.w, c->invIA, c->rollingImpulse );
|
|
1720
|
+
bB.w = b2MulAddW( bB.w, c->invIB, c->rollingImpulse );
|
|
1721
|
+
|
|
1722
|
+
b2ScatterBodies( states, c->indexA, &bA );
|
|
1723
|
+
b2ScatterBodies( states, c->indexB, &bB );
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
b2TracyCZoneEnd( warm_start_contact );
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
void b2SolveContactsTask( int startIndex, int endIndex, b2StepContext* context, int colorIndex, bool useBias )
|
|
1730
|
+
{
|
|
1731
|
+
b2TracyCZoneNC( solve_contact, "Solve Contact", b2_colorAliceBlue, true );
|
|
1732
|
+
|
|
1733
|
+
b2BodyState* states = context->states;
|
|
1734
|
+
b2ContactConstraintSIMD* constraints = context->graph->colors[colorIndex].simdConstraints;
|
|
1735
|
+
b2FloatW inv_h = b2SplatW( context->inv_h );
|
|
1736
|
+
b2FloatW minBiasVel = b2SplatW( -context->world->maxContactPushSpeed );
|
|
1737
|
+
b2FloatW oneW = b2SplatW( 1.0f );
|
|
1738
|
+
|
|
1739
|
+
for ( int i = startIndex; i < endIndex; ++i )
|
|
1740
|
+
{
|
|
1741
|
+
b2ContactConstraintSIMD* c = constraints + i;
|
|
1742
|
+
|
|
1743
|
+
b2BodyStateW bA = b2GatherBodies( states, c->indexA );
|
|
1744
|
+
b2BodyStateW bB = b2GatherBodies( states, c->indexB );
|
|
1745
|
+
|
|
1746
|
+
b2FloatW biasRate, massScale, impulseScale;
|
|
1747
|
+
if ( useBias )
|
|
1748
|
+
{
|
|
1749
|
+
biasRate = c->biasRate;
|
|
1750
|
+
massScale = c->massScale;
|
|
1751
|
+
impulseScale = c->impulseScale;
|
|
1752
|
+
}
|
|
1753
|
+
else
|
|
1754
|
+
{
|
|
1755
|
+
biasRate = b2ZeroW();
|
|
1756
|
+
massScale = oneW;
|
|
1757
|
+
impulseScale = b2ZeroW();
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
b2FloatW totalNormalImpulse = b2ZeroW();
|
|
1761
|
+
|
|
1762
|
+
b2Vec2W dp = { b2SubW( bB.dp.X, bA.dp.X ), b2SubW( bB.dp.Y, bA.dp.Y ) };
|
|
1763
|
+
|
|
1764
|
+
// point1 non-penetration constraint
|
|
1765
|
+
{
|
|
1766
|
+
// Fixed anchors for impulses
|
|
1767
|
+
b2Vec2W rA = c->anchorA1;
|
|
1768
|
+
b2Vec2W rB = c->anchorB1;
|
|
1769
|
+
|
|
1770
|
+
// Moving anchors for current separation
|
|
1771
|
+
b2Vec2W rsA = b2RotateVectorW( bA.dq, rA );
|
|
1772
|
+
b2Vec2W rsB = b2RotateVectorW( bB.dq, rB );
|
|
1773
|
+
|
|
1774
|
+
// compute current separation
|
|
1775
|
+
// this is subject to round-off error if the anchor is far from the body center of mass
|
|
1776
|
+
b2Vec2W ds = { b2AddW( dp.X, b2SubW( rsB.X, rsA.X ) ), b2AddW( dp.Y, b2SubW( rsB.Y, rsA.Y ) ) };
|
|
1777
|
+
b2FloatW s = b2AddW( b2DotW( c->normal, ds ), c->baseSeparation1 );
|
|
1778
|
+
|
|
1779
|
+
// Apply speculative bias if separation is greater than zero, otherwise apply soft constraint bias
|
|
1780
|
+
// The minBiasVel is meant to limit stiffness, not increase it.
|
|
1781
|
+
b2FloatW mask = b2GreaterThanW( s, b2ZeroW() );
|
|
1782
|
+
b2FloatW specBias = b2MulW( s, inv_h );
|
|
1783
|
+
b2FloatW softBias = b2MaxW( b2MulW( biasRate, s ), minBiasVel );
|
|
1784
|
+
|
|
1785
|
+
// todo try b2MaxW(softBias, specBias);
|
|
1786
|
+
b2FloatW bias = b2BlendW( softBias, specBias, mask );
|
|
1787
|
+
|
|
1788
|
+
b2FloatW pointMassScale = b2BlendW( massScale, oneW, mask );
|
|
1789
|
+
b2FloatW pointImpulseScale = b2BlendW( impulseScale, b2ZeroW(), mask );
|
|
1790
|
+
|
|
1791
|
+
// Relative velocity at contact
|
|
1792
|
+
b2FloatW dvx = b2SubW( b2SubW( bB.v.X, b2MulW( bB.w, rB.Y ) ), b2SubW( bA.v.X, b2MulW( bA.w, rA.Y ) ) );
|
|
1793
|
+
b2FloatW dvy = b2SubW( b2AddW( bB.v.Y, b2MulW( bB.w, rB.X ) ), b2AddW( bA.v.Y, b2MulW( bA.w, rA.X ) ) );
|
|
1794
|
+
b2FloatW vn = b2AddW( b2MulW( dvx, c->normal.X ), b2MulW( dvy, c->normal.Y ) );
|
|
1795
|
+
|
|
1796
|
+
// Compute normal impulse
|
|
1797
|
+
b2FloatW negImpulse = b2AddW( b2MulW( c->normalMass1, b2MulW( pointMassScale, b2AddW( vn, bias ) ) ),
|
|
1798
|
+
b2MulW( pointImpulseScale, c->normalImpulse1 ) );
|
|
1799
|
+
|
|
1800
|
+
// Clamp the accumulated impulse
|
|
1801
|
+
b2FloatW newImpulse = b2MaxW( b2SubW( c->normalImpulse1, negImpulse ), b2ZeroW() );
|
|
1802
|
+
b2FloatW impulse = b2SubW( newImpulse, c->normalImpulse1 );
|
|
1803
|
+
c->normalImpulse1 = newImpulse;
|
|
1804
|
+
c->totalNormalImpulse1 = b2AddW( c->totalNormalImpulse1, newImpulse );
|
|
1805
|
+
|
|
1806
|
+
totalNormalImpulse = b2AddW( totalNormalImpulse, newImpulse );
|
|
1807
|
+
|
|
1808
|
+
// Apply contact impulse
|
|
1809
|
+
b2FloatW Px = b2MulW( impulse, c->normal.X );
|
|
1810
|
+
b2FloatW Py = b2MulW( impulse, c->normal.Y );
|
|
1811
|
+
|
|
1812
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, Px );
|
|
1813
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, Py );
|
|
1814
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2SubW( b2MulW( rA.X, Py ), b2MulW( rA.Y, Px ) ) );
|
|
1815
|
+
|
|
1816
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, Px );
|
|
1817
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, Py );
|
|
1818
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2SubW( b2MulW( rB.X, Py ), b2MulW( rB.Y, Px ) ) );
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
// second point non-penetration constraint
|
|
1822
|
+
{
|
|
1823
|
+
// moving anchors for current separation
|
|
1824
|
+
b2Vec2W rsA = b2RotateVectorW( bA.dq, c->anchorA2 );
|
|
1825
|
+
b2Vec2W rsB = b2RotateVectorW( bB.dq, c->anchorB2 );
|
|
1826
|
+
|
|
1827
|
+
// compute current separation
|
|
1828
|
+
b2Vec2W ds = { b2AddW( dp.X, b2SubW( rsB.X, rsA.X ) ), b2AddW( dp.Y, b2SubW( rsB.Y, rsA.Y ) ) };
|
|
1829
|
+
b2FloatW s = b2AddW( b2DotW( c->normal, ds ), c->baseSeparation2 );
|
|
1830
|
+
|
|
1831
|
+
b2FloatW mask = b2GreaterThanW( s, b2ZeroW() );
|
|
1832
|
+
b2FloatW specBias = b2MulW( s, inv_h );
|
|
1833
|
+
b2FloatW softBias = b2MaxW( b2MulW( biasRate, s ), minBiasVel );
|
|
1834
|
+
b2FloatW bias = b2BlendW( softBias, specBias, mask );
|
|
1835
|
+
|
|
1836
|
+
b2FloatW pointMassScale = b2BlendW( massScale, oneW, mask );
|
|
1837
|
+
b2FloatW pointImpulseScale = b2BlendW( impulseScale, b2ZeroW(), mask );
|
|
1838
|
+
|
|
1839
|
+
// fixed anchors for Jacobians
|
|
1840
|
+
b2Vec2W rA = c->anchorA2;
|
|
1841
|
+
b2Vec2W rB = c->anchorB2;
|
|
1842
|
+
|
|
1843
|
+
// Relative velocity at contact
|
|
1844
|
+
b2FloatW dvx = b2SubW( b2SubW( bB.v.X, b2MulW( bB.w, rB.Y ) ), b2SubW( bA.v.X, b2MulW( bA.w, rA.Y ) ) );
|
|
1845
|
+
b2FloatW dvy = b2SubW( b2AddW( bB.v.Y, b2MulW( bB.w, rB.X ) ), b2AddW( bA.v.Y, b2MulW( bA.w, rA.X ) ) );
|
|
1846
|
+
b2FloatW vn = b2AddW( b2MulW( dvx, c->normal.X ), b2MulW( dvy, c->normal.Y ) );
|
|
1847
|
+
|
|
1848
|
+
// Compute normal impulse
|
|
1849
|
+
b2FloatW negImpulse = b2AddW( b2MulW( c->normalMass2, b2MulW( pointMassScale, b2AddW( vn, bias ) ) ),
|
|
1850
|
+
b2MulW( pointImpulseScale, c->normalImpulse2 ) );
|
|
1851
|
+
|
|
1852
|
+
// Clamp the accumulated impulse
|
|
1853
|
+
b2FloatW newImpulse = b2MaxW( b2SubW( c->normalImpulse2, negImpulse ), b2ZeroW() );
|
|
1854
|
+
b2FloatW impulse = b2SubW( newImpulse, c->normalImpulse2 );
|
|
1855
|
+
c->normalImpulse2 = newImpulse;
|
|
1856
|
+
c->totalNormalImpulse2 = b2AddW( c->totalNormalImpulse2, newImpulse );
|
|
1857
|
+
|
|
1858
|
+
totalNormalImpulse = b2AddW( totalNormalImpulse, newImpulse );
|
|
1859
|
+
|
|
1860
|
+
// Apply contact impulse
|
|
1861
|
+
b2FloatW Px = b2MulW( impulse, c->normal.X );
|
|
1862
|
+
b2FloatW Py = b2MulW( impulse, c->normal.Y );
|
|
1863
|
+
|
|
1864
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, Px );
|
|
1865
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, Py );
|
|
1866
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2SubW( b2MulW( rA.X, Py ), b2MulW( rA.Y, Px ) ) );
|
|
1867
|
+
|
|
1868
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, Px );
|
|
1869
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, Py );
|
|
1870
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2SubW( b2MulW( rB.X, Py ), b2MulW( rB.Y, Px ) ) );
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
b2FloatW tangentX = c->normal.Y;
|
|
1874
|
+
b2FloatW tangentY = b2SubW( b2ZeroW(), c->normal.X );
|
|
1875
|
+
|
|
1876
|
+
// point 1 friction constraint
|
|
1877
|
+
{
|
|
1878
|
+
// fixed anchors for Jacobians
|
|
1879
|
+
b2Vec2W rA = c->anchorA1;
|
|
1880
|
+
b2Vec2W rB = c->anchorB1;
|
|
1881
|
+
|
|
1882
|
+
// Relative velocity at contact
|
|
1883
|
+
b2FloatW dvx = b2SubW( b2SubW( bB.v.X, b2MulW( bB.w, rB.Y ) ), b2SubW( bA.v.X, b2MulW( bA.w, rA.Y ) ) );
|
|
1884
|
+
b2FloatW dvy = b2SubW( b2AddW( bB.v.Y, b2MulW( bB.w, rB.X ) ), b2AddW( bA.v.Y, b2MulW( bA.w, rA.X ) ) );
|
|
1885
|
+
b2FloatW vt = b2AddW( b2MulW( dvx, tangentX ), b2MulW( dvy, tangentY ) );
|
|
1886
|
+
|
|
1887
|
+
// Tangent speed (conveyor belt)
|
|
1888
|
+
vt = b2SubW( vt, c->tangentSpeed );
|
|
1889
|
+
|
|
1890
|
+
// Compute tangent force
|
|
1891
|
+
b2FloatW negImpulse = b2MulW( c->tangentMass1, vt );
|
|
1892
|
+
|
|
1893
|
+
// Clamp the accumulated force
|
|
1894
|
+
b2FloatW maxFriction = b2MulW( c->friction, c->normalImpulse1 );
|
|
1895
|
+
b2FloatW newImpulse = b2SubW( c->tangentImpulse1, negImpulse );
|
|
1896
|
+
newImpulse = b2MaxW( b2SubW( b2ZeroW(), maxFriction ), b2MinW( newImpulse, maxFriction ) );
|
|
1897
|
+
b2FloatW impulse = b2SubW( newImpulse, c->tangentImpulse1 );
|
|
1898
|
+
c->tangentImpulse1 = newImpulse;
|
|
1899
|
+
|
|
1900
|
+
// Apply contact impulse
|
|
1901
|
+
b2FloatW Px = b2MulW( impulse, tangentX );
|
|
1902
|
+
b2FloatW Py = b2MulW( impulse, tangentY );
|
|
1903
|
+
|
|
1904
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, Px );
|
|
1905
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, Py );
|
|
1906
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2SubW( b2MulW( rA.X, Py ), b2MulW( rA.Y, Px ) ) );
|
|
1907
|
+
|
|
1908
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, Px );
|
|
1909
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, Py );
|
|
1910
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2SubW( b2MulW( rB.X, Py ), b2MulW( rB.Y, Px ) ) );
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
// second point friction constraint
|
|
1914
|
+
{
|
|
1915
|
+
// fixed anchors for Jacobians
|
|
1916
|
+
b2Vec2W rA = c->anchorA2;
|
|
1917
|
+
b2Vec2W rB = c->anchorB2;
|
|
1918
|
+
|
|
1919
|
+
// Relative velocity at contact
|
|
1920
|
+
b2FloatW dvx = b2SubW( b2SubW( bB.v.X, b2MulW( bB.w, rB.Y ) ), b2SubW( bA.v.X, b2MulW( bA.w, rA.Y ) ) );
|
|
1921
|
+
b2FloatW dvy = b2SubW( b2AddW( bB.v.Y, b2MulW( bB.w, rB.X ) ), b2AddW( bA.v.Y, b2MulW( bA.w, rA.X ) ) );
|
|
1922
|
+
b2FloatW vt = b2AddW( b2MulW( dvx, tangentX ), b2MulW( dvy, tangentY ) );
|
|
1923
|
+
|
|
1924
|
+
// Tangent speed (conveyor belt)
|
|
1925
|
+
vt = b2SubW( vt, c->tangentSpeed );
|
|
1926
|
+
|
|
1927
|
+
// Compute tangent force
|
|
1928
|
+
b2FloatW negImpulse = b2MulW( c->tangentMass2, vt );
|
|
1929
|
+
|
|
1930
|
+
// Clamp the accumulated force
|
|
1931
|
+
b2FloatW maxFriction = b2MulW( c->friction, c->normalImpulse2 );
|
|
1932
|
+
b2FloatW newImpulse = b2SubW( c->tangentImpulse2, negImpulse );
|
|
1933
|
+
newImpulse = b2MaxW( b2SubW( b2ZeroW(), maxFriction ), b2MinW( newImpulse, maxFriction ) );
|
|
1934
|
+
b2FloatW impulse = b2SubW( newImpulse, c->tangentImpulse2 );
|
|
1935
|
+
c->tangentImpulse2 = newImpulse;
|
|
1936
|
+
|
|
1937
|
+
// Apply contact impulse
|
|
1938
|
+
b2FloatW Px = b2MulW( impulse, tangentX );
|
|
1939
|
+
b2FloatW Py = b2MulW( impulse, tangentY );
|
|
1940
|
+
|
|
1941
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, Px );
|
|
1942
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, Py );
|
|
1943
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2SubW( b2MulW( rA.X, Py ), b2MulW( rA.Y, Px ) ) );
|
|
1944
|
+
|
|
1945
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, Px );
|
|
1946
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, Py );
|
|
1947
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2SubW( b2MulW( rB.X, Py ), b2MulW( rB.Y, Px ) ) );
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// Rolling resistance
|
|
1951
|
+
{
|
|
1952
|
+
b2FloatW deltaLambda = b2MulW( c->rollingMass, b2SubW( bA.w, bB.w ) );
|
|
1953
|
+
b2FloatW lambda = c->rollingImpulse;
|
|
1954
|
+
b2FloatW maxLambda = b2MulW( c->rollingResistance, totalNormalImpulse );
|
|
1955
|
+
c->rollingImpulse = b2SymClampW( b2AddW( lambda, deltaLambda ), maxLambda );
|
|
1956
|
+
deltaLambda = b2SubW( c->rollingImpulse, lambda );
|
|
1957
|
+
|
|
1958
|
+
bA.w = b2MulSubW( bA.w, c->invIA, deltaLambda );
|
|
1959
|
+
bB.w = b2MulAddW( bB.w, c->invIB, deltaLambda );
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
b2ScatterBodies( states, c->indexA, &bA );
|
|
1963
|
+
b2ScatterBodies( states, c->indexB, &bB );
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
b2TracyCZoneEnd( solve_contact );
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
void b2ApplyRestitutionTask( int startIndex, int endIndex, b2StepContext* context, int colorIndex )
|
|
1970
|
+
{
|
|
1971
|
+
b2TracyCZoneNC( restitution, "Restitution", b2_colorDodgerBlue, true );
|
|
1972
|
+
|
|
1973
|
+
b2BodyState* states = context->states;
|
|
1974
|
+
b2ContactConstraintSIMD* constraints = context->graph->colors[colorIndex].simdConstraints;
|
|
1975
|
+
b2FloatW threshold = b2SplatW( context->world->restitutionThreshold );
|
|
1976
|
+
b2FloatW zero = b2ZeroW();
|
|
1977
|
+
|
|
1978
|
+
for ( int i = startIndex; i < endIndex; ++i )
|
|
1979
|
+
{
|
|
1980
|
+
b2ContactConstraintSIMD* c = constraints + i;
|
|
1981
|
+
|
|
1982
|
+
if ( b2AllZeroW( c->restitution ) )
|
|
1983
|
+
{
|
|
1984
|
+
// No lanes have restitution. Common case.
|
|
1985
|
+
continue;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
// Create a mask based on restitution so that lanes with no restitution are not affected
|
|
1989
|
+
// by the calculations below.
|
|
1990
|
+
b2FloatW restitutionMask = b2EqualsW( c->restitution, zero );
|
|
1991
|
+
|
|
1992
|
+
b2BodyStateW bA = b2GatherBodies( states, c->indexA );
|
|
1993
|
+
b2BodyStateW bB = b2GatherBodies( states, c->indexB );
|
|
1994
|
+
|
|
1995
|
+
// first point non-penetration constraint
|
|
1996
|
+
{
|
|
1997
|
+
// Set effective mass to zero if restitution should not be applied
|
|
1998
|
+
b2FloatW mask1 = b2GreaterThanW( b2AddW( c->relativeVelocity1, threshold ), zero );
|
|
1999
|
+
b2FloatW mask2 = b2EqualsW( c->totalNormalImpulse1, zero );
|
|
2000
|
+
b2FloatW mask = b2OrW( b2OrW( mask1, mask2 ), restitutionMask );
|
|
2001
|
+
b2FloatW mass = b2BlendW( c->normalMass1, zero, mask );
|
|
2002
|
+
|
|
2003
|
+
// fixed anchors for Jacobians
|
|
2004
|
+
b2Vec2W rA = c->anchorA1;
|
|
2005
|
+
b2Vec2W rB = c->anchorB1;
|
|
2006
|
+
|
|
2007
|
+
// Relative velocity at contact
|
|
2008
|
+
b2FloatW dvx = b2SubW( b2SubW( bB.v.X, b2MulW( bB.w, rB.Y ) ), b2SubW( bA.v.X, b2MulW( bA.w, rA.Y ) ) );
|
|
2009
|
+
b2FloatW dvy = b2SubW( b2AddW( bB.v.Y, b2MulW( bB.w, rB.X ) ), b2AddW( bA.v.Y, b2MulW( bA.w, rA.X ) ) );
|
|
2010
|
+
b2FloatW vn = b2AddW( b2MulW( dvx, c->normal.X ), b2MulW( dvy, c->normal.Y ) );
|
|
2011
|
+
|
|
2012
|
+
// Compute normal impulse
|
|
2013
|
+
b2FloatW negImpulse = b2MulW( mass, b2AddW( vn, b2MulW( c->restitution, c->relativeVelocity1 ) ) );
|
|
2014
|
+
|
|
2015
|
+
// Clamp the accumulated impulse
|
|
2016
|
+
b2FloatW newImpulse = b2MaxW( b2SubW( c->normalImpulse1, negImpulse ), b2ZeroW() );
|
|
2017
|
+
b2FloatW impulse = b2SubW( newImpulse, c->normalImpulse1 );
|
|
2018
|
+
c->normalImpulse1 = newImpulse;
|
|
2019
|
+
|
|
2020
|
+
// Apply contact impulse
|
|
2021
|
+
b2FloatW Px = b2MulW( impulse, c->normal.X );
|
|
2022
|
+
b2FloatW Py = b2MulW( impulse, c->normal.Y );
|
|
2023
|
+
|
|
2024
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, Px );
|
|
2025
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, Py );
|
|
2026
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2SubW( b2MulW( rA.X, Py ), b2MulW( rA.Y, Px ) ) );
|
|
2027
|
+
|
|
2028
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, Px );
|
|
2029
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, Py );
|
|
2030
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2SubW( b2MulW( rB.X, Py ), b2MulW( rB.Y, Px ) ) );
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
// second point non-penetration constraint
|
|
2034
|
+
{
|
|
2035
|
+
// Set effective mass to zero if restitution should not be applied
|
|
2036
|
+
b2FloatW mask1 = b2GreaterThanW( b2AddW( c->relativeVelocity2, threshold ), zero );
|
|
2037
|
+
b2FloatW mask2 = b2EqualsW( c->totalNormalImpulse2, zero );
|
|
2038
|
+
b2FloatW mask = b2OrW( b2OrW( mask1, mask2 ), restitutionMask );
|
|
2039
|
+
b2FloatW mass = b2BlendW( c->normalMass2, zero, mask );
|
|
2040
|
+
|
|
2041
|
+
// fixed anchors for Jacobians
|
|
2042
|
+
b2Vec2W rA = c->anchorA2;
|
|
2043
|
+
b2Vec2W rB = c->anchorB2;
|
|
2044
|
+
|
|
2045
|
+
// Relative velocity at contact
|
|
2046
|
+
b2FloatW dvx = b2SubW( b2SubW( bB.v.X, b2MulW( bB.w, rB.Y ) ), b2SubW( bA.v.X, b2MulW( bA.w, rA.Y ) ) );
|
|
2047
|
+
b2FloatW dvy = b2SubW( b2AddW( bB.v.Y, b2MulW( bB.w, rB.X ) ), b2AddW( bA.v.Y, b2MulW( bA.w, rA.X ) ) );
|
|
2048
|
+
b2FloatW vn = b2AddW( b2MulW( dvx, c->normal.X ), b2MulW( dvy, c->normal.Y ) );
|
|
2049
|
+
|
|
2050
|
+
// Compute normal impulse
|
|
2051
|
+
b2FloatW negImpulse = b2MulW( mass, b2AddW( vn, b2MulW( c->restitution, c->relativeVelocity2 ) ) );
|
|
2052
|
+
|
|
2053
|
+
// Clamp the accumulated impulse
|
|
2054
|
+
b2FloatW newImpulse = b2MaxW( b2SubW( c->normalImpulse2, negImpulse ), b2ZeroW() );
|
|
2055
|
+
b2FloatW impulse = b2SubW( newImpulse, c->normalImpulse2 );
|
|
2056
|
+
c->normalImpulse2 = newImpulse;
|
|
2057
|
+
|
|
2058
|
+
// Apply contact impulse
|
|
2059
|
+
b2FloatW Px = b2MulW( impulse, c->normal.X );
|
|
2060
|
+
b2FloatW Py = b2MulW( impulse, c->normal.Y );
|
|
2061
|
+
|
|
2062
|
+
bA.v.X = b2MulSubW( bA.v.X, c->invMassA, Px );
|
|
2063
|
+
bA.v.Y = b2MulSubW( bA.v.Y, c->invMassA, Py );
|
|
2064
|
+
bA.w = b2MulSubW( bA.w, c->invIA, b2SubW( b2MulW( rA.X, Py ), b2MulW( rA.Y, Px ) ) );
|
|
2065
|
+
|
|
2066
|
+
bB.v.X = b2MulAddW( bB.v.X, c->invMassB, Px );
|
|
2067
|
+
bB.v.Y = b2MulAddW( bB.v.Y, c->invMassB, Py );
|
|
2068
|
+
bB.w = b2MulAddW( bB.w, c->invIB, b2SubW( b2MulW( rB.X, Py ), b2MulW( rB.Y, Px ) ) );
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
b2ScatterBodies( states, c->indexA, &bA );
|
|
2072
|
+
b2ScatterBodies( states, c->indexB, &bB );
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
b2TracyCZoneEnd( restitution );
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
void b2StoreImpulsesTask( int startIndex, int endIndex, b2StepContext* context )
|
|
2079
|
+
{
|
|
2080
|
+
b2TracyCZoneNC( store_impulses, "Store", b2_colorFireBrick, true );
|
|
2081
|
+
|
|
2082
|
+
b2ContactSim** contacts = context->contacts;
|
|
2083
|
+
const b2ContactConstraintSIMD* constraints = context->simdContactConstraints;
|
|
2084
|
+
|
|
2085
|
+
b2Manifold dummy = { 0 };
|
|
2086
|
+
|
|
2087
|
+
for ( int constraintIndex = startIndex; constraintIndex < endIndex; ++constraintIndex )
|
|
2088
|
+
{
|
|
2089
|
+
const b2ContactConstraintSIMD* c = constraints + constraintIndex;
|
|
2090
|
+
const float* rollingImpulse = (float*)&c->rollingImpulse;
|
|
2091
|
+
const float* normalImpulse1 = (float*)&c->normalImpulse1;
|
|
2092
|
+
const float* normalImpulse2 = (float*)&c->normalImpulse2;
|
|
2093
|
+
const float* tangentImpulse1 = (float*)&c->tangentImpulse1;
|
|
2094
|
+
const float* tangentImpulse2 = (float*)&c->tangentImpulse2;
|
|
2095
|
+
const float* totalNormalImpulse1 = (float*)&c->totalNormalImpulse1;
|
|
2096
|
+
const float* totalNormalImpulse2 = (float*)&c->totalNormalImpulse2;
|
|
2097
|
+
const float* normalVelocity1 = (float*)&c->relativeVelocity1;
|
|
2098
|
+
const float* normalVelocity2 = (float*)&c->relativeVelocity2;
|
|
2099
|
+
|
|
2100
|
+
int baseIndex = B2_SIMD_WIDTH * constraintIndex;
|
|
2101
|
+
|
|
2102
|
+
for ( int laneIndex = 0; laneIndex < B2_SIMD_WIDTH; ++laneIndex )
|
|
2103
|
+
{
|
|
2104
|
+
b2Manifold* m = contacts[baseIndex + laneIndex] == NULL ? &dummy : &contacts[baseIndex + laneIndex]->manifold;
|
|
2105
|
+
m->rollingImpulse = rollingImpulse[laneIndex];
|
|
2106
|
+
|
|
2107
|
+
m->points[0].normalImpulse = normalImpulse1[laneIndex];
|
|
2108
|
+
m->points[0].tangentImpulse = tangentImpulse1[laneIndex];
|
|
2109
|
+
m->points[0].totalNormalImpulse = totalNormalImpulse1[laneIndex];
|
|
2110
|
+
m->points[0].normalVelocity = normalVelocity1[laneIndex];
|
|
2111
|
+
|
|
2112
|
+
m->points[1].normalImpulse = normalImpulse2[laneIndex];
|
|
2113
|
+
m->points[1].tangentImpulse = tangentImpulse2[laneIndex];
|
|
2114
|
+
m->points[1].totalNormalImpulse = totalNormalImpulse2[laneIndex];
|
|
2115
|
+
m->points[1].normalVelocity = normalVelocity2[laneIndex];
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
b2TracyCZoneEnd( store_impulses );
|
|
2120
|
+
}
|