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,1884 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Erin Catto
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
#include "body.h"
|
|
5
|
+
|
|
6
|
+
#include "aabb.h"
|
|
7
|
+
#include "array.h"
|
|
8
|
+
#include "contact.h"
|
|
9
|
+
#include "core.h"
|
|
10
|
+
#include "id_pool.h"
|
|
11
|
+
#include "island.h"
|
|
12
|
+
#include "joint.h"
|
|
13
|
+
#include "shape.h"
|
|
14
|
+
#include "solver_set.h"
|
|
15
|
+
#include "world.h"
|
|
16
|
+
|
|
17
|
+
// needed for dll export
|
|
18
|
+
#include "sensor.h"
|
|
19
|
+
|
|
20
|
+
#include "box2d/box2d.h"
|
|
21
|
+
#include "box2d/id.h"
|
|
22
|
+
|
|
23
|
+
#include <string.h>
|
|
24
|
+
|
|
25
|
+
// Implement functions for b2BodyArray
|
|
26
|
+
B2_ARRAY_SOURCE( b2Body, b2Body )
|
|
27
|
+
B2_ARRAY_SOURCE( b2BodySim, b2BodySim )
|
|
28
|
+
B2_ARRAY_SOURCE( b2BodyState, b2BodyState )
|
|
29
|
+
|
|
30
|
+
// Get a validated body from a world using an id.
|
|
31
|
+
b2Body* b2GetBodyFullId( b2World* world, b2BodyId bodyId )
|
|
32
|
+
{
|
|
33
|
+
B2_ASSERT( b2Body_IsValid( bodyId ) );
|
|
34
|
+
|
|
35
|
+
// id index starts at one so that zero can represent null
|
|
36
|
+
return b2BodyArray_Get( &world->bodies, bodyId.index1 - 1 );
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
b2Transform b2GetBodyTransformQuick( b2World* world, b2Body* body )
|
|
40
|
+
{
|
|
41
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, body->setIndex );
|
|
42
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, body->localIndex );
|
|
43
|
+
return bodySim->transform;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
b2Transform b2GetBodyTransform( b2World* world, int bodyId )
|
|
47
|
+
{
|
|
48
|
+
b2Body* body = b2BodyArray_Get( &world->bodies, bodyId );
|
|
49
|
+
return b2GetBodyTransformQuick( world, body );
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Create a b2BodyId from a raw id.
|
|
53
|
+
b2BodyId b2MakeBodyId( b2World* world, int bodyId )
|
|
54
|
+
{
|
|
55
|
+
b2Body* body = b2BodyArray_Get( &world->bodies, bodyId );
|
|
56
|
+
return (b2BodyId){ bodyId + 1, world->worldId, body->generation };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
b2BodySim* b2GetBodySim( b2World* world, b2Body* body )
|
|
60
|
+
{
|
|
61
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, body->setIndex );
|
|
62
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, body->localIndex );
|
|
63
|
+
return bodySim;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
b2BodyState* b2GetBodyState( b2World* world, b2Body* body )
|
|
67
|
+
{
|
|
68
|
+
if ( body->setIndex == b2_awakeSet )
|
|
69
|
+
{
|
|
70
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
71
|
+
return b2BodyStateArray_Get( &set->bodyStates, body->localIndex );
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return NULL;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static void b2CreateIslandForBody( b2World* world, int setIndex, b2Body* body )
|
|
78
|
+
{
|
|
79
|
+
B2_ASSERT( body->islandId == B2_NULL_INDEX );
|
|
80
|
+
B2_ASSERT( body->islandPrev == B2_NULL_INDEX );
|
|
81
|
+
B2_ASSERT( body->islandNext == B2_NULL_INDEX );
|
|
82
|
+
B2_ASSERT( setIndex != b2_disabledSet );
|
|
83
|
+
|
|
84
|
+
b2Island* island = b2CreateIsland( world, setIndex );
|
|
85
|
+
|
|
86
|
+
body->islandId = island->islandId;
|
|
87
|
+
island->headBody = body->id;
|
|
88
|
+
island->tailBody = body->id;
|
|
89
|
+
island->bodyCount = 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static void b2RemoveBodyFromIsland( b2World* world, b2Body* body )
|
|
93
|
+
{
|
|
94
|
+
if ( body->islandId == B2_NULL_INDEX )
|
|
95
|
+
{
|
|
96
|
+
B2_ASSERT( body->islandPrev == B2_NULL_INDEX );
|
|
97
|
+
B2_ASSERT( body->islandNext == B2_NULL_INDEX );
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
int islandId = body->islandId;
|
|
102
|
+
b2Island* island = b2IslandArray_Get( &world->islands, islandId );
|
|
103
|
+
|
|
104
|
+
// Fix the island's linked list of sims
|
|
105
|
+
if ( body->islandPrev != B2_NULL_INDEX )
|
|
106
|
+
{
|
|
107
|
+
b2Body* prevBody = b2BodyArray_Get( &world->bodies, body->islandPrev );
|
|
108
|
+
prevBody->islandNext = body->islandNext;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if ( body->islandNext != B2_NULL_INDEX )
|
|
112
|
+
{
|
|
113
|
+
b2Body* nextBody = b2BodyArray_Get( &world->bodies, body->islandNext );
|
|
114
|
+
nextBody->islandPrev = body->islandPrev;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
B2_ASSERT( island->bodyCount > 0 );
|
|
118
|
+
island->bodyCount -= 1;
|
|
119
|
+
bool islandDestroyed = false;
|
|
120
|
+
|
|
121
|
+
if ( island->headBody == body->id )
|
|
122
|
+
{
|
|
123
|
+
island->headBody = body->islandNext;
|
|
124
|
+
|
|
125
|
+
if ( island->headBody == B2_NULL_INDEX )
|
|
126
|
+
{
|
|
127
|
+
// Destroy empty island
|
|
128
|
+
B2_ASSERT( island->tailBody == body->id );
|
|
129
|
+
B2_ASSERT( island->bodyCount == 0 );
|
|
130
|
+
B2_ASSERT( island->contactCount == 0 );
|
|
131
|
+
B2_ASSERT( island->jointCount == 0 );
|
|
132
|
+
|
|
133
|
+
// Free the island
|
|
134
|
+
b2DestroyIsland( world, island->islandId );
|
|
135
|
+
islandDestroyed = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else if ( island->tailBody == body->id )
|
|
139
|
+
{
|
|
140
|
+
island->tailBody = body->islandPrev;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if ( islandDestroyed == false )
|
|
144
|
+
{
|
|
145
|
+
b2ValidateIsland( world, islandId );
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
body->islandId = B2_NULL_INDEX;
|
|
149
|
+
body->islandPrev = B2_NULL_INDEX;
|
|
150
|
+
body->islandNext = B2_NULL_INDEX;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static void b2DestroyBodyContacts( b2World* world, b2Body* body, bool wakeBodies )
|
|
154
|
+
{
|
|
155
|
+
// Destroy the attached contacts
|
|
156
|
+
int edgeKey = body->headContactKey;
|
|
157
|
+
while ( edgeKey != B2_NULL_INDEX )
|
|
158
|
+
{
|
|
159
|
+
int contactId = edgeKey >> 1;
|
|
160
|
+
int edgeIndex = edgeKey & 1;
|
|
161
|
+
|
|
162
|
+
b2Contact* contact = b2ContactArray_Get( &world->contacts, contactId );
|
|
163
|
+
edgeKey = contact->edges[edgeIndex].nextKey;
|
|
164
|
+
b2DestroyContact( world, contact, wakeBodies );
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
b2ValidateSolverSets( world );
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
b2BodyId b2CreateBody( b2WorldId worldId, const b2BodyDef* def )
|
|
171
|
+
{
|
|
172
|
+
B2_CHECK_DEF( def );
|
|
173
|
+
B2_ASSERT( b2IsValidVec2( def->position ) );
|
|
174
|
+
B2_ASSERT( b2IsValidRotation( def->rotation ) );
|
|
175
|
+
B2_ASSERT( b2IsValidVec2( def->linearVelocity ) );
|
|
176
|
+
B2_ASSERT( b2IsValidFloat( def->angularVelocity ) );
|
|
177
|
+
B2_ASSERT( b2IsValidFloat( def->linearDamping ) && def->linearDamping >= 0.0f );
|
|
178
|
+
B2_ASSERT( b2IsValidFloat( def->angularDamping ) && def->angularDamping >= 0.0f );
|
|
179
|
+
B2_ASSERT( b2IsValidFloat( def->sleepThreshold ) && def->sleepThreshold >= 0.0f );
|
|
180
|
+
B2_ASSERT( b2IsValidFloat( def->gravityScale ) );
|
|
181
|
+
|
|
182
|
+
b2World* world = b2GetWorldFromId( worldId );
|
|
183
|
+
B2_ASSERT( world->locked == false );
|
|
184
|
+
|
|
185
|
+
if ( world->locked )
|
|
186
|
+
{
|
|
187
|
+
return b2_nullBodyId;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
bool isAwake = ( def->isAwake || def->enableSleep == false ) && def->isEnabled;
|
|
191
|
+
|
|
192
|
+
// determine the solver set
|
|
193
|
+
int setId;
|
|
194
|
+
if ( def->isEnabled == false )
|
|
195
|
+
{
|
|
196
|
+
// any body type can be disabled
|
|
197
|
+
setId = b2_disabledSet;
|
|
198
|
+
}
|
|
199
|
+
else if ( def->type == b2_staticBody )
|
|
200
|
+
{
|
|
201
|
+
setId = b2_staticSet;
|
|
202
|
+
}
|
|
203
|
+
else if ( isAwake == true )
|
|
204
|
+
{
|
|
205
|
+
setId = b2_awakeSet;
|
|
206
|
+
}
|
|
207
|
+
else
|
|
208
|
+
{
|
|
209
|
+
// new set for a sleeping body in its own island
|
|
210
|
+
setId = b2AllocId( &world->solverSetIdPool );
|
|
211
|
+
if ( setId == world->solverSets.count )
|
|
212
|
+
{
|
|
213
|
+
// Create a zero initialized solver set. All sub-arrays are also zero initialized.
|
|
214
|
+
b2SolverSetArray_Push( &world->solverSets, (b2SolverSet){ 0 } );
|
|
215
|
+
}
|
|
216
|
+
else
|
|
217
|
+
{
|
|
218
|
+
B2_ASSERT( world->solverSets.data[setId].setIndex == B2_NULL_INDEX );
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
world->solverSets.data[setId].setIndex = setId;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
B2_ASSERT( 0 <= setId && setId < world->solverSets.count );
|
|
225
|
+
|
|
226
|
+
int bodyId = b2AllocId( &world->bodyIdPool );
|
|
227
|
+
|
|
228
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, setId );
|
|
229
|
+
b2BodySim* bodySim = b2BodySimArray_Add( &set->bodySims );
|
|
230
|
+
*bodySim = (b2BodySim){ 0 };
|
|
231
|
+
bodySim->transform.p = def->position;
|
|
232
|
+
bodySim->transform.q = def->rotation;
|
|
233
|
+
bodySim->center = def->position;
|
|
234
|
+
bodySim->rotation0 = bodySim->transform.q;
|
|
235
|
+
bodySim->center0 = bodySim->center;
|
|
236
|
+
bodySim->minExtent = B2_HUGE;
|
|
237
|
+
bodySim->maxExtent = 0.0f;
|
|
238
|
+
bodySim->linearDamping = def->linearDamping;
|
|
239
|
+
bodySim->angularDamping = def->angularDamping;
|
|
240
|
+
bodySim->gravityScale = def->gravityScale;
|
|
241
|
+
bodySim->bodyId = bodyId;
|
|
242
|
+
bodySim->isBullet = def->isBullet;
|
|
243
|
+
bodySim->allowFastRotation = def->allowFastRotation;
|
|
244
|
+
|
|
245
|
+
if ( setId == b2_awakeSet )
|
|
246
|
+
{
|
|
247
|
+
b2BodyState* bodyState = b2BodyStateArray_Add( &set->bodyStates );
|
|
248
|
+
B2_ASSERT( ( (uintptr_t)bodyState & 0x1F ) == 0 );
|
|
249
|
+
|
|
250
|
+
*bodyState = (b2BodyState){ 0 };
|
|
251
|
+
bodyState->linearVelocity = def->linearVelocity;
|
|
252
|
+
bodyState->angularVelocity = def->angularVelocity;
|
|
253
|
+
bodyState->deltaRotation = b2Rot_identity;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if ( bodyId == world->bodies.count )
|
|
257
|
+
{
|
|
258
|
+
b2BodyArray_Push( &world->bodies, (b2Body){ 0 } );
|
|
259
|
+
}
|
|
260
|
+
else
|
|
261
|
+
{
|
|
262
|
+
B2_ASSERT( world->bodies.data[bodyId].id == B2_NULL_INDEX );
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
b2Body* body = b2BodyArray_Get( &world->bodies, bodyId );
|
|
266
|
+
|
|
267
|
+
if ( def->name )
|
|
268
|
+
{
|
|
269
|
+
int i = 0;
|
|
270
|
+
while ( i < 31 && def->name[i] != 0 )
|
|
271
|
+
{
|
|
272
|
+
body->name[i] = def->name[i];
|
|
273
|
+
i += 1;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
while ( i < 32)
|
|
277
|
+
{
|
|
278
|
+
body->name[i] = 0;
|
|
279
|
+
i += 1;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
{
|
|
284
|
+
memset( body->name, 0, 32 * sizeof( char ) );
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
body->userData = def->userData;
|
|
288
|
+
body->setIndex = setId;
|
|
289
|
+
body->localIndex = set->bodySims.count - 1;
|
|
290
|
+
body->generation += 1;
|
|
291
|
+
body->headShapeId = B2_NULL_INDEX;
|
|
292
|
+
body->shapeCount = 0;
|
|
293
|
+
body->headChainId = B2_NULL_INDEX;
|
|
294
|
+
body->headContactKey = B2_NULL_INDEX;
|
|
295
|
+
body->contactCount = 0;
|
|
296
|
+
body->headJointKey = B2_NULL_INDEX;
|
|
297
|
+
body->jointCount = 0;
|
|
298
|
+
body->islandId = B2_NULL_INDEX;
|
|
299
|
+
body->islandPrev = B2_NULL_INDEX;
|
|
300
|
+
body->islandNext = B2_NULL_INDEX;
|
|
301
|
+
body->bodyMoveIndex = B2_NULL_INDEX;
|
|
302
|
+
body->id = bodyId;
|
|
303
|
+
body->mass = 0.0f;
|
|
304
|
+
body->inertia = 0.0f;
|
|
305
|
+
body->sleepThreshold = def->sleepThreshold;
|
|
306
|
+
body->sleepTime = 0.0f;
|
|
307
|
+
body->type = def->type;
|
|
308
|
+
body->enableSleep = def->enableSleep;
|
|
309
|
+
body->fixedRotation = def->fixedRotation;
|
|
310
|
+
body->isSpeedCapped = false;
|
|
311
|
+
body->isMarked = false;
|
|
312
|
+
|
|
313
|
+
// dynamic and kinematic bodies that are enabled need a island
|
|
314
|
+
if ( setId >= b2_awakeSet )
|
|
315
|
+
{
|
|
316
|
+
b2CreateIslandForBody( world, setId, body );
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
b2ValidateSolverSets( world );
|
|
320
|
+
|
|
321
|
+
b2BodyId id = { bodyId + 1, world->worldId, body->generation };
|
|
322
|
+
return id;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
bool b2WakeBody( b2World* world, b2Body* body )
|
|
326
|
+
{
|
|
327
|
+
if ( body->setIndex >= b2_firstSleepingSet )
|
|
328
|
+
{
|
|
329
|
+
b2WakeSolverSet( world, body->setIndex );
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
void b2DestroyBody( b2BodyId bodyId )
|
|
337
|
+
{
|
|
338
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
339
|
+
if ( world == NULL )
|
|
340
|
+
{
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
345
|
+
|
|
346
|
+
// Wake bodies attached to this body, even if this body is static.
|
|
347
|
+
bool wakeBodies = true;
|
|
348
|
+
|
|
349
|
+
// Destroy the attached joints
|
|
350
|
+
int edgeKey = body->headJointKey;
|
|
351
|
+
while ( edgeKey != B2_NULL_INDEX )
|
|
352
|
+
{
|
|
353
|
+
int jointId = edgeKey >> 1;
|
|
354
|
+
int edgeIndex = edgeKey & 1;
|
|
355
|
+
|
|
356
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
357
|
+
edgeKey = joint->edges[edgeIndex].nextKey;
|
|
358
|
+
|
|
359
|
+
// Careful because this modifies the list being traversed
|
|
360
|
+
b2DestroyJointInternal( world, joint, wakeBodies );
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Destroy all contacts attached to this body.
|
|
364
|
+
b2DestroyBodyContacts( world, body, wakeBodies );
|
|
365
|
+
|
|
366
|
+
// Destroy the attached shapes and their broad-phase proxies.
|
|
367
|
+
int shapeId = body->headShapeId;
|
|
368
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
369
|
+
{
|
|
370
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
371
|
+
|
|
372
|
+
if ( shape->sensorIndex != B2_NULL_INDEX )
|
|
373
|
+
{
|
|
374
|
+
b2DestroySensor( world, shape );
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
b2DestroyShapeProxy( shape, &world->broadPhase );
|
|
378
|
+
|
|
379
|
+
// Return shape to free list.
|
|
380
|
+
b2FreeId( &world->shapeIdPool, shapeId );
|
|
381
|
+
shape->id = B2_NULL_INDEX;
|
|
382
|
+
|
|
383
|
+
shapeId = shape->nextShapeId;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Destroy the attached chains. The associated shapes have already been destroyed above.
|
|
387
|
+
int chainId = body->headChainId;
|
|
388
|
+
while ( chainId != B2_NULL_INDEX )
|
|
389
|
+
{
|
|
390
|
+
b2ChainShape* chain = b2ChainShapeArray_Get( &world->chainShapes, chainId );
|
|
391
|
+
|
|
392
|
+
b2FreeChainData( chain );
|
|
393
|
+
|
|
394
|
+
// Return chain to free list.
|
|
395
|
+
b2FreeId( &world->chainIdPool, chainId );
|
|
396
|
+
chain->id = B2_NULL_INDEX;
|
|
397
|
+
|
|
398
|
+
chainId = chain->nextChainId;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
b2RemoveBodyFromIsland( world, body );
|
|
402
|
+
|
|
403
|
+
// Remove body sim from solver set that owns it
|
|
404
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, body->setIndex );
|
|
405
|
+
int movedIndex = b2BodySimArray_RemoveSwap( &set->bodySims, body->localIndex );
|
|
406
|
+
if ( movedIndex != B2_NULL_INDEX )
|
|
407
|
+
{
|
|
408
|
+
// Fix moved body index
|
|
409
|
+
b2BodySim* movedSim = set->bodySims.data + body->localIndex;
|
|
410
|
+
int movedId = movedSim->bodyId;
|
|
411
|
+
b2Body* movedBody = b2BodyArray_Get( &world->bodies, movedId );
|
|
412
|
+
B2_ASSERT( movedBody->localIndex == movedIndex );
|
|
413
|
+
movedBody->localIndex = body->localIndex;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Remove body state from awake set
|
|
417
|
+
if ( body->setIndex == b2_awakeSet )
|
|
418
|
+
{
|
|
419
|
+
int result = b2BodyStateArray_RemoveSwap( &set->bodyStates, body->localIndex );
|
|
420
|
+
B2_ASSERT( result == movedIndex );
|
|
421
|
+
B2_UNUSED( result );
|
|
422
|
+
}
|
|
423
|
+
else if ( set->setIndex >= b2_firstSleepingSet && set->bodySims.count == 0 )
|
|
424
|
+
{
|
|
425
|
+
// Remove solver set if it's now an orphan.
|
|
426
|
+
b2DestroySolverSet( world, set->setIndex );
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Free body and id (preserve body generation)
|
|
430
|
+
b2FreeId( &world->bodyIdPool, body->id );
|
|
431
|
+
|
|
432
|
+
body->setIndex = B2_NULL_INDEX;
|
|
433
|
+
body->localIndex = B2_NULL_INDEX;
|
|
434
|
+
body->id = B2_NULL_INDEX;
|
|
435
|
+
|
|
436
|
+
b2ValidateSolverSets( world );
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
int b2Body_GetContactCapacity( b2BodyId bodyId )
|
|
440
|
+
{
|
|
441
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
442
|
+
if ( world == NULL )
|
|
443
|
+
{
|
|
444
|
+
return 0;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
448
|
+
|
|
449
|
+
// Conservative and fast
|
|
450
|
+
return body->contactCount;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
int b2Body_GetContactData( b2BodyId bodyId, b2ContactData* contactData, int capacity )
|
|
454
|
+
{
|
|
455
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
456
|
+
if ( world == NULL )
|
|
457
|
+
{
|
|
458
|
+
return 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
462
|
+
|
|
463
|
+
int contactKey = body->headContactKey;
|
|
464
|
+
int index = 0;
|
|
465
|
+
while ( contactKey != B2_NULL_INDEX && index < capacity )
|
|
466
|
+
{
|
|
467
|
+
int contactId = contactKey >> 1;
|
|
468
|
+
int edgeIndex = contactKey & 1;
|
|
469
|
+
|
|
470
|
+
b2Contact* contact = b2ContactArray_Get( &world->contacts, contactId );
|
|
471
|
+
|
|
472
|
+
// Is contact touching?
|
|
473
|
+
if ( contact->flags & b2_contactTouchingFlag )
|
|
474
|
+
{
|
|
475
|
+
b2Shape* shapeA = b2ShapeArray_Get( &world->shapes, contact->shapeIdA );
|
|
476
|
+
b2Shape* shapeB = b2ShapeArray_Get( &world->shapes, contact->shapeIdB );
|
|
477
|
+
|
|
478
|
+
contactData[index].shapeIdA = (b2ShapeId){ shapeA->id + 1, bodyId.world0, shapeA->generation };
|
|
479
|
+
contactData[index].shapeIdB = (b2ShapeId){ shapeB->id + 1, bodyId.world0, shapeB->generation };
|
|
480
|
+
|
|
481
|
+
b2ContactSim* contactSim = b2GetContactSim( world, contact );
|
|
482
|
+
contactData[index].manifold = contactSim->manifold;
|
|
483
|
+
|
|
484
|
+
index += 1;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
contactKey = contact->edges[edgeIndex].nextKey;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
B2_ASSERT( index <= capacity );
|
|
491
|
+
|
|
492
|
+
return index;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
b2AABB b2Body_ComputeAABB( b2BodyId bodyId )
|
|
496
|
+
{
|
|
497
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
498
|
+
if ( world == NULL )
|
|
499
|
+
{
|
|
500
|
+
return (b2AABB){ 0 };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
504
|
+
if ( body->headShapeId == B2_NULL_INDEX )
|
|
505
|
+
{
|
|
506
|
+
b2Transform transform = b2GetBodyTransform( world, body->id );
|
|
507
|
+
return (b2AABB){ transform.p, transform.p };
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, body->headShapeId );
|
|
511
|
+
b2AABB aabb = shape->aabb;
|
|
512
|
+
while ( shape->nextShapeId != B2_NULL_INDEX )
|
|
513
|
+
{
|
|
514
|
+
shape = b2ShapeArray_Get( &world->shapes, shape->nextShapeId );
|
|
515
|
+
aabb = b2AABB_Union( aabb, shape->aabb );
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return aabb;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
void b2UpdateBodyMassData( b2World* world, b2Body* body )
|
|
522
|
+
{
|
|
523
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
524
|
+
|
|
525
|
+
// Compute mass data from shapes. Each shape has its own density.
|
|
526
|
+
body->mass = 0.0f;
|
|
527
|
+
body->inertia = 0.0f;
|
|
528
|
+
|
|
529
|
+
bodySim->invMass = 0.0f;
|
|
530
|
+
bodySim->invInertia = 0.0f;
|
|
531
|
+
bodySim->localCenter = b2Vec2_zero;
|
|
532
|
+
bodySim->minExtent = B2_HUGE;
|
|
533
|
+
bodySim->maxExtent = 0.0f;
|
|
534
|
+
|
|
535
|
+
// Static and kinematic sims have zero mass.
|
|
536
|
+
if ( body->type != b2_dynamicBody )
|
|
537
|
+
{
|
|
538
|
+
bodySim->center = bodySim->transform.p;
|
|
539
|
+
|
|
540
|
+
// Need extents for kinematic bodies for sleeping to work correctly.
|
|
541
|
+
if ( body->type == b2_kinematicBody )
|
|
542
|
+
{
|
|
543
|
+
int shapeId = body->headShapeId;
|
|
544
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
545
|
+
{
|
|
546
|
+
const b2Shape* s = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
547
|
+
|
|
548
|
+
b2ShapeExtent extent = b2ComputeShapeExtent( s, b2Vec2_zero );
|
|
549
|
+
bodySim->minExtent = b2MinFloat( bodySim->minExtent, extent.minExtent );
|
|
550
|
+
bodySim->maxExtent = b2MaxFloat( bodySim->maxExtent, extent.maxExtent );
|
|
551
|
+
|
|
552
|
+
shapeId = s->nextShapeId;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Accumulate mass over all shapes.
|
|
560
|
+
b2Vec2 localCenter = b2Vec2_zero;
|
|
561
|
+
int shapeId = body->headShapeId;
|
|
562
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
563
|
+
{
|
|
564
|
+
const b2Shape* s = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
565
|
+
shapeId = s->nextShapeId;
|
|
566
|
+
|
|
567
|
+
if ( s->density == 0.0f )
|
|
568
|
+
{
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
b2MassData massData = b2ComputeShapeMass( s );
|
|
573
|
+
body->mass += massData.mass;
|
|
574
|
+
localCenter = b2MulAdd( localCenter, massData.mass, massData.center );
|
|
575
|
+
body->inertia += massData.rotationalInertia;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Compute center of mass.
|
|
579
|
+
if ( body->mass > 0.0f )
|
|
580
|
+
{
|
|
581
|
+
bodySim->invMass = 1.0f / body->mass;
|
|
582
|
+
localCenter = b2MulSV( bodySim->invMass, localCenter );
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if ( body->inertia > 0.0f && body->fixedRotation == false )
|
|
586
|
+
{
|
|
587
|
+
// Center the inertia about the center of mass.
|
|
588
|
+
body->inertia -= body->mass * b2Dot( localCenter, localCenter );
|
|
589
|
+
B2_ASSERT( body->inertia > 0.0f );
|
|
590
|
+
bodySim->invInertia = 1.0f / body->inertia;
|
|
591
|
+
}
|
|
592
|
+
else
|
|
593
|
+
{
|
|
594
|
+
body->inertia = 0.0f;
|
|
595
|
+
bodySim->invInertia = 0.0f;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Move center of mass.
|
|
599
|
+
b2Vec2 oldCenter = bodySim->center;
|
|
600
|
+
bodySim->localCenter = localCenter;
|
|
601
|
+
bodySim->center = b2TransformPoint( bodySim->transform, bodySim->localCenter );
|
|
602
|
+
bodySim->center0 = bodySim->center;
|
|
603
|
+
|
|
604
|
+
// Update center of mass velocity
|
|
605
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
606
|
+
if ( state != NULL )
|
|
607
|
+
{
|
|
608
|
+
b2Vec2 deltaLinear = b2CrossSV( state->angularVelocity, b2Sub( bodySim->center, oldCenter ) );
|
|
609
|
+
state->linearVelocity = b2Add( state->linearVelocity, deltaLinear );
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Compute body extents relative to center of mass
|
|
613
|
+
shapeId = body->headShapeId;
|
|
614
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
615
|
+
{
|
|
616
|
+
const b2Shape* s = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
617
|
+
|
|
618
|
+
b2ShapeExtent extent = b2ComputeShapeExtent( s, localCenter );
|
|
619
|
+
bodySim->minExtent = b2MinFloat( bodySim->minExtent, extent.minExtent );
|
|
620
|
+
bodySim->maxExtent = b2MaxFloat( bodySim->maxExtent, extent.maxExtent );
|
|
621
|
+
|
|
622
|
+
shapeId = s->nextShapeId;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
b2Vec2 b2Body_GetPosition( b2BodyId bodyId )
|
|
627
|
+
{
|
|
628
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
629
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
630
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
631
|
+
return transform.p;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
b2Rot b2Body_GetRotation( b2BodyId bodyId )
|
|
635
|
+
{
|
|
636
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
637
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
638
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
639
|
+
return transform.q;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
b2Transform b2Body_GetTransform( b2BodyId bodyId )
|
|
643
|
+
{
|
|
644
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
645
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
646
|
+
return b2GetBodyTransformQuick( world, body );
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
b2Vec2 b2Body_GetLocalPoint( b2BodyId bodyId, b2Vec2 worldPoint )
|
|
650
|
+
{
|
|
651
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
652
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
653
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
654
|
+
return b2InvTransformPoint( transform, worldPoint );
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
b2Vec2 b2Body_GetWorldPoint( b2BodyId bodyId, b2Vec2 localPoint )
|
|
658
|
+
{
|
|
659
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
660
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
661
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
662
|
+
return b2TransformPoint( transform, localPoint );
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
b2Vec2 b2Body_GetLocalVector( b2BodyId bodyId, b2Vec2 worldVector )
|
|
666
|
+
{
|
|
667
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
668
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
669
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
670
|
+
return b2InvRotateVector( transform.q, worldVector );
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
b2Vec2 b2Body_GetWorldVector( b2BodyId bodyId, b2Vec2 localVector )
|
|
674
|
+
{
|
|
675
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
676
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
677
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
678
|
+
return b2RotateVector( transform.q, localVector );
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
void b2Body_SetTransform( b2BodyId bodyId, b2Vec2 position, b2Rot rotation )
|
|
682
|
+
{
|
|
683
|
+
B2_ASSERT( b2IsValidVec2( position ) );
|
|
684
|
+
B2_ASSERT( b2IsValidRotation( rotation ) );
|
|
685
|
+
B2_ASSERT( b2Body_IsValid( bodyId ) );
|
|
686
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
687
|
+
B2_ASSERT( world->locked == false );
|
|
688
|
+
|
|
689
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
690
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
691
|
+
|
|
692
|
+
bodySim->transform.p = position;
|
|
693
|
+
bodySim->transform.q = rotation;
|
|
694
|
+
bodySim->center = b2TransformPoint( bodySim->transform, bodySim->localCenter );
|
|
695
|
+
|
|
696
|
+
bodySim->rotation0 = bodySim->transform.q;
|
|
697
|
+
bodySim->center0 = bodySim->center;
|
|
698
|
+
|
|
699
|
+
b2BroadPhase* broadPhase = &world->broadPhase;
|
|
700
|
+
|
|
701
|
+
b2Transform transform = bodySim->transform;
|
|
702
|
+
const float margin = B2_AABB_MARGIN;
|
|
703
|
+
const float speculativeDistance = B2_SPECULATIVE_DISTANCE;
|
|
704
|
+
|
|
705
|
+
int shapeId = body->headShapeId;
|
|
706
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
707
|
+
{
|
|
708
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
709
|
+
b2AABB aabb = b2ComputeShapeAABB( shape, transform );
|
|
710
|
+
aabb.lowerBound.x -= speculativeDistance;
|
|
711
|
+
aabb.lowerBound.y -= speculativeDistance;
|
|
712
|
+
aabb.upperBound.x += speculativeDistance;
|
|
713
|
+
aabb.upperBound.y += speculativeDistance;
|
|
714
|
+
shape->aabb = aabb;
|
|
715
|
+
|
|
716
|
+
if ( b2AABB_Contains( shape->fatAABB, aabb ) == false )
|
|
717
|
+
{
|
|
718
|
+
b2AABB fatAABB;
|
|
719
|
+
fatAABB.lowerBound.x = aabb.lowerBound.x - margin;
|
|
720
|
+
fatAABB.lowerBound.y = aabb.lowerBound.y - margin;
|
|
721
|
+
fatAABB.upperBound.x = aabb.upperBound.x + margin;
|
|
722
|
+
fatAABB.upperBound.y = aabb.upperBound.y + margin;
|
|
723
|
+
shape->fatAABB = fatAABB;
|
|
724
|
+
|
|
725
|
+
// They body could be disabled
|
|
726
|
+
if ( shape->proxyKey != B2_NULL_INDEX )
|
|
727
|
+
{
|
|
728
|
+
b2BroadPhase_MoveProxy( broadPhase, shape->proxyKey, fatAABB );
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
shapeId = shape->nextShapeId;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
b2Vec2 b2Body_GetLinearVelocity( b2BodyId bodyId )
|
|
737
|
+
{
|
|
738
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
739
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
740
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
741
|
+
if ( state != NULL )
|
|
742
|
+
{
|
|
743
|
+
return state->linearVelocity;
|
|
744
|
+
}
|
|
745
|
+
return b2Vec2_zero;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
float b2Body_GetAngularVelocity( b2BodyId bodyId )
|
|
749
|
+
{
|
|
750
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
751
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
752
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
753
|
+
if ( state != NULL )
|
|
754
|
+
{
|
|
755
|
+
return state->angularVelocity;
|
|
756
|
+
}
|
|
757
|
+
return 0.0;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
void b2Body_SetLinearVelocity( b2BodyId bodyId, b2Vec2 linearVelocity )
|
|
761
|
+
{
|
|
762
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
763
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
764
|
+
|
|
765
|
+
if ( body->type == b2_staticBody )
|
|
766
|
+
{
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if ( b2LengthSquared( linearVelocity ) > 0.0f )
|
|
771
|
+
{
|
|
772
|
+
b2WakeBody( world, body );
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
776
|
+
if ( state == NULL )
|
|
777
|
+
{
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
state->linearVelocity = linearVelocity;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
void b2Body_SetAngularVelocity( b2BodyId bodyId, float angularVelocity )
|
|
785
|
+
{
|
|
786
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
787
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
788
|
+
|
|
789
|
+
if ( body->type == b2_staticBody || body->fixedRotation )
|
|
790
|
+
{
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if ( angularVelocity != 0.0f )
|
|
795
|
+
{
|
|
796
|
+
b2WakeBody( world, body );
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
800
|
+
if ( state == NULL )
|
|
801
|
+
{
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
state->angularVelocity = angularVelocity;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
void b2Body_SetTargetTransform( b2BodyId bodyId, b2Transform target, float timeStep )
|
|
809
|
+
{
|
|
810
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
811
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
812
|
+
|
|
813
|
+
if ( body->type == b2_staticBody || timeStep <= 0.0f )
|
|
814
|
+
{
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
b2BodySim* sim = b2GetBodySim( world, body );
|
|
819
|
+
|
|
820
|
+
// Compute linear velocity
|
|
821
|
+
b2Vec2 center1 = sim->center;
|
|
822
|
+
b2Vec2 center2 = b2TransformPoint( target, sim->localCenter );
|
|
823
|
+
float invTimeStep = 1.0f / timeStep;
|
|
824
|
+
b2Vec2 linearVelocity = b2MulSV( invTimeStep, b2Sub( center2, center1 ) );
|
|
825
|
+
|
|
826
|
+
// Compute angular velocity
|
|
827
|
+
float angularVelocity = 0.0f;
|
|
828
|
+
if ( body->fixedRotation == false )
|
|
829
|
+
{
|
|
830
|
+
b2Rot q1 = sim->transform.q;
|
|
831
|
+
b2Rot q2 = target.q;
|
|
832
|
+
float deltaAngle = b2RelativeAngle( q2, q1 );
|
|
833
|
+
angularVelocity = invTimeStep * deltaAngle;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Return if velocity would be zero
|
|
837
|
+
if ( b2LengthSquared( linearVelocity ) == 0.0f && b2AbsFloat( angularVelocity ) == 0.0f )
|
|
838
|
+
{
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Must wake for state to exist
|
|
843
|
+
b2WakeBody( world, body );
|
|
844
|
+
|
|
845
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
846
|
+
if ( state == NULL )
|
|
847
|
+
{
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
state->linearVelocity = linearVelocity;
|
|
852
|
+
state->angularVelocity = angularVelocity;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
b2Vec2 b2Body_GetLocalPointVelocity( b2BodyId bodyId, b2Vec2 localPoint )
|
|
856
|
+
{
|
|
857
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
858
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
859
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
860
|
+
if ( state == NULL )
|
|
861
|
+
{
|
|
862
|
+
return b2Vec2_zero;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, body->setIndex );
|
|
866
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, body->localIndex );
|
|
867
|
+
|
|
868
|
+
b2Vec2 r = b2RotateVector( bodySim->transform.q, b2Sub( localPoint, bodySim->localCenter ) );
|
|
869
|
+
b2Vec2 v = b2Add( state->linearVelocity, b2CrossSV( state->angularVelocity, r ) );
|
|
870
|
+
return v;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
b2Vec2 b2Body_GetWorldPointVelocity( b2BodyId bodyId, b2Vec2 worldPoint )
|
|
874
|
+
{
|
|
875
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
876
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
877
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
878
|
+
if ( state == NULL )
|
|
879
|
+
{
|
|
880
|
+
return b2Vec2_zero;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, body->setIndex );
|
|
884
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, body->localIndex );
|
|
885
|
+
|
|
886
|
+
b2Vec2 r = b2Sub( worldPoint, bodySim->center );
|
|
887
|
+
b2Vec2 v = b2Add( state->linearVelocity, b2CrossSV( state->angularVelocity, r ) );
|
|
888
|
+
return v;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
void b2Body_ApplyForce( b2BodyId bodyId, b2Vec2 force, b2Vec2 point, bool wake )
|
|
892
|
+
{
|
|
893
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
894
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
895
|
+
|
|
896
|
+
if ( wake && body->setIndex >= b2_firstSleepingSet )
|
|
897
|
+
{
|
|
898
|
+
b2WakeBody( world, body );
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if ( body->setIndex == b2_awakeSet )
|
|
902
|
+
{
|
|
903
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
904
|
+
bodySim->force = b2Add( bodySim->force, force );
|
|
905
|
+
bodySim->torque += b2Cross( b2Sub( point, bodySim->center ), force );
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
void b2Body_ApplyForceToCenter( b2BodyId bodyId, b2Vec2 force, bool wake )
|
|
910
|
+
{
|
|
911
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
912
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
913
|
+
|
|
914
|
+
if ( wake && body->setIndex >= b2_firstSleepingSet )
|
|
915
|
+
{
|
|
916
|
+
b2WakeBody( world, body );
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if ( body->setIndex == b2_awakeSet )
|
|
920
|
+
{
|
|
921
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
922
|
+
bodySim->force = b2Add( bodySim->force, force );
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
void b2Body_ApplyTorque( b2BodyId bodyId, float torque, bool wake )
|
|
927
|
+
{
|
|
928
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
929
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
930
|
+
|
|
931
|
+
if ( wake && body->setIndex >= b2_firstSleepingSet )
|
|
932
|
+
{
|
|
933
|
+
b2WakeBody( world, body );
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if ( body->setIndex == b2_awakeSet )
|
|
937
|
+
{
|
|
938
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
939
|
+
bodySim->torque += torque;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
void b2Body_ApplyLinearImpulse( b2BodyId bodyId, b2Vec2 impulse, b2Vec2 point, bool wake )
|
|
944
|
+
{
|
|
945
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
946
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
947
|
+
|
|
948
|
+
if ( wake && body->setIndex >= b2_firstSleepingSet )
|
|
949
|
+
{
|
|
950
|
+
b2WakeBody( world, body );
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if ( body->setIndex == b2_awakeSet )
|
|
954
|
+
{
|
|
955
|
+
int localIndex = body->localIndex;
|
|
956
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
957
|
+
b2BodyState* state = b2BodyStateArray_Get( &set->bodyStates, localIndex );
|
|
958
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, localIndex );
|
|
959
|
+
state->linearVelocity = b2MulAdd( state->linearVelocity, bodySim->invMass, impulse );
|
|
960
|
+
state->angularVelocity += bodySim->invInertia * b2Cross( b2Sub( point, bodySim->center ), impulse );
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
void b2Body_ApplyLinearImpulseToCenter( b2BodyId bodyId, b2Vec2 impulse, bool wake )
|
|
965
|
+
{
|
|
966
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
967
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
968
|
+
|
|
969
|
+
if ( wake && body->setIndex >= b2_firstSleepingSet )
|
|
970
|
+
{
|
|
971
|
+
b2WakeBody( world, body );
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if ( body->setIndex == b2_awakeSet )
|
|
975
|
+
{
|
|
976
|
+
int localIndex = body->localIndex;
|
|
977
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
978
|
+
b2BodyState* state = b2BodyStateArray_Get( &set->bodyStates, localIndex );
|
|
979
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, localIndex );
|
|
980
|
+
state->linearVelocity = b2MulAdd( state->linearVelocity, bodySim->invMass, impulse );
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
void b2Body_ApplyAngularImpulse( b2BodyId bodyId, float impulse, bool wake )
|
|
985
|
+
{
|
|
986
|
+
B2_ASSERT( b2Body_IsValid( bodyId ) );
|
|
987
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
988
|
+
|
|
989
|
+
int id = bodyId.index1 - 1;
|
|
990
|
+
b2Body* body = b2BodyArray_Get( &world->bodies, id );
|
|
991
|
+
B2_ASSERT( body->generation == bodyId.generation );
|
|
992
|
+
|
|
993
|
+
if ( wake && body->setIndex >= b2_firstSleepingSet )
|
|
994
|
+
{
|
|
995
|
+
// this will not invalidate body pointer
|
|
996
|
+
b2WakeBody( world, body );
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if ( body->setIndex == b2_awakeSet )
|
|
1000
|
+
{
|
|
1001
|
+
int localIndex = body->localIndex;
|
|
1002
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
1003
|
+
b2BodyState* state = b2BodyStateArray_Get( &set->bodyStates, localIndex );
|
|
1004
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &set->bodySims, localIndex );
|
|
1005
|
+
state->angularVelocity += bodySim->invInertia * impulse;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
b2BodyType b2Body_GetType( b2BodyId bodyId )
|
|
1010
|
+
{
|
|
1011
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1012
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1013
|
+
return body->type;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Changing the body type is quite complex mainly due to joints.
|
|
1017
|
+
// Considerations:
|
|
1018
|
+
// - body and joints must be moved to the correct set
|
|
1019
|
+
// - islands must be updated
|
|
1020
|
+
// - graph coloring must be correct
|
|
1021
|
+
// - any body connected to a joint may be disabled
|
|
1022
|
+
// - joints between static bodies must go into the static set
|
|
1023
|
+
void b2Body_SetType( b2BodyId bodyId, b2BodyType type )
|
|
1024
|
+
{
|
|
1025
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1026
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1027
|
+
|
|
1028
|
+
b2BodyType originalType = body->type;
|
|
1029
|
+
if ( originalType == type )
|
|
1030
|
+
{
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
if ( body->setIndex == b2_disabledSet )
|
|
1035
|
+
{
|
|
1036
|
+
// Disabled bodies don't change solver sets or islands when they change type.
|
|
1037
|
+
body->type = type;
|
|
1038
|
+
|
|
1039
|
+
// Body type affects the mass
|
|
1040
|
+
b2UpdateBodyMassData( world, body );
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Destroy all contacts but don't wake bodies.
|
|
1045
|
+
bool wakeBodies = false;
|
|
1046
|
+
b2DestroyBodyContacts( world, body, wakeBodies );
|
|
1047
|
+
|
|
1048
|
+
// Wake this body because we assume below that it is awake or static.
|
|
1049
|
+
b2WakeBody( world, body );
|
|
1050
|
+
|
|
1051
|
+
// Unlink all joints and wake attached bodies.
|
|
1052
|
+
{
|
|
1053
|
+
int jointKey = body->headJointKey;
|
|
1054
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1055
|
+
{
|
|
1056
|
+
int jointId = jointKey >> 1;
|
|
1057
|
+
int edgeIndex = jointKey & 1;
|
|
1058
|
+
|
|
1059
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1060
|
+
if ( joint->islandId != B2_NULL_INDEX )
|
|
1061
|
+
{
|
|
1062
|
+
b2UnlinkJoint( world, joint );
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// A body going from static to dynamic or kinematic goes to the awake set
|
|
1066
|
+
// and other attached bodies must be awake as well. For consistency, this is
|
|
1067
|
+
// done for all cases.
|
|
1068
|
+
b2Body* bodyA = b2BodyArray_Get( &world->bodies, joint->edges[0].bodyId );
|
|
1069
|
+
b2Body* bodyB = b2BodyArray_Get( &world->bodies, joint->edges[1].bodyId );
|
|
1070
|
+
b2WakeBody( world, bodyA );
|
|
1071
|
+
b2WakeBody( world, bodyB );
|
|
1072
|
+
|
|
1073
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
body->type = type;
|
|
1078
|
+
|
|
1079
|
+
if ( originalType == b2_staticBody )
|
|
1080
|
+
{
|
|
1081
|
+
// Body is going from static to dynamic or kinematic. It only makes sense to move it to the awake set.
|
|
1082
|
+
B2_ASSERT( body->setIndex == b2_staticSet );
|
|
1083
|
+
|
|
1084
|
+
b2SolverSet* staticSet = b2SolverSetArray_Get( &world->solverSets, b2_staticSet );
|
|
1085
|
+
b2SolverSet* awakeSet = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
1086
|
+
|
|
1087
|
+
// Transfer body to awake set
|
|
1088
|
+
b2TransferBody( world, awakeSet, staticSet, body );
|
|
1089
|
+
|
|
1090
|
+
// Create island for body
|
|
1091
|
+
b2CreateIslandForBody( world, b2_awakeSet, body );
|
|
1092
|
+
|
|
1093
|
+
// Transfer static joints to awake set
|
|
1094
|
+
int jointKey = body->headJointKey;
|
|
1095
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1096
|
+
{
|
|
1097
|
+
int jointId = jointKey >> 1;
|
|
1098
|
+
int edgeIndex = jointKey & 1;
|
|
1099
|
+
|
|
1100
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1101
|
+
|
|
1102
|
+
// Transfer the joint if it is in the static set
|
|
1103
|
+
if ( joint->setIndex == b2_staticSet )
|
|
1104
|
+
{
|
|
1105
|
+
b2TransferJoint( world, awakeSet, staticSet, joint );
|
|
1106
|
+
}
|
|
1107
|
+
else if ( joint->setIndex == b2_awakeSet )
|
|
1108
|
+
{
|
|
1109
|
+
// In this case the joint must be re-inserted into the constraint graph to ensure the correct
|
|
1110
|
+
// graph color.
|
|
1111
|
+
|
|
1112
|
+
// First transfer to the static set.
|
|
1113
|
+
b2TransferJoint( world, staticSet, awakeSet, joint );
|
|
1114
|
+
|
|
1115
|
+
// Now transfer it back to the awake set and into the graph coloring.
|
|
1116
|
+
b2TransferJoint( world, awakeSet, staticSet, joint );
|
|
1117
|
+
}
|
|
1118
|
+
else
|
|
1119
|
+
{
|
|
1120
|
+
// Otherwise the joint must be disabled.
|
|
1121
|
+
B2_ASSERT( joint->setIndex == b2_disabledSet );
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// Recreate shape proxies in movable tree.
|
|
1128
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
1129
|
+
int shapeId = body->headShapeId;
|
|
1130
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1131
|
+
{
|
|
1132
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1133
|
+
shapeId = shape->nextShapeId;
|
|
1134
|
+
b2DestroyShapeProxy( shape, &world->broadPhase );
|
|
1135
|
+
bool forcePairCreation = true;
|
|
1136
|
+
b2BodyType proxyType = type;
|
|
1137
|
+
b2CreateShapeProxy( shape, &world->broadPhase, proxyType, transform, forcePairCreation );
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
else if ( type == b2_staticBody )
|
|
1141
|
+
{
|
|
1142
|
+
// The body is going from dynamic/kinematic to static. It should be awake.
|
|
1143
|
+
B2_ASSERT( body->setIndex == b2_awakeSet );
|
|
1144
|
+
|
|
1145
|
+
b2SolverSet* staticSet = b2SolverSetArray_Get( &world->solverSets, b2_staticSet );
|
|
1146
|
+
b2SolverSet* awakeSet = b2SolverSetArray_Get( &world->solverSets, b2_awakeSet );
|
|
1147
|
+
|
|
1148
|
+
// Transfer body to static set
|
|
1149
|
+
b2TransferBody( world, staticSet, awakeSet, body );
|
|
1150
|
+
|
|
1151
|
+
// Remove body from island.
|
|
1152
|
+
b2RemoveBodyFromIsland( world, body );
|
|
1153
|
+
|
|
1154
|
+
b2BodySim* bodySim = b2BodySimArray_Get( &staticSet->bodySims, body->localIndex );
|
|
1155
|
+
bodySim->isFast = false;
|
|
1156
|
+
|
|
1157
|
+
// Maybe transfer joints to static set.
|
|
1158
|
+
int jointKey = body->headJointKey;
|
|
1159
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1160
|
+
{
|
|
1161
|
+
int jointId = jointKey >> 1;
|
|
1162
|
+
int edgeIndex = jointKey & 1;
|
|
1163
|
+
|
|
1164
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1165
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1166
|
+
|
|
1167
|
+
int otherEdgeIndex = edgeIndex ^ 1;
|
|
1168
|
+
b2Body* otherBody = b2BodyArray_Get( &world->bodies, joint->edges[otherEdgeIndex].bodyId );
|
|
1169
|
+
|
|
1170
|
+
// Skip disabled joint
|
|
1171
|
+
if ( joint->setIndex == b2_disabledSet )
|
|
1172
|
+
{
|
|
1173
|
+
// Joint is disable, should be connected to a disabled body
|
|
1174
|
+
B2_ASSERT( otherBody->setIndex == b2_disabledSet );
|
|
1175
|
+
continue;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// Since the body was not static, the joint must be awake.
|
|
1179
|
+
B2_ASSERT( joint->setIndex == b2_awakeSet );
|
|
1180
|
+
|
|
1181
|
+
// Only transfer joint to static set if both bodies are static.
|
|
1182
|
+
if ( otherBody->setIndex == b2_staticSet )
|
|
1183
|
+
{
|
|
1184
|
+
b2TransferJoint( world, staticSet, awakeSet, joint );
|
|
1185
|
+
}
|
|
1186
|
+
else
|
|
1187
|
+
{
|
|
1188
|
+
// The other body must be awake.
|
|
1189
|
+
B2_ASSERT( otherBody->setIndex == b2_awakeSet );
|
|
1190
|
+
|
|
1191
|
+
// The joint must live in a graph color.
|
|
1192
|
+
B2_ASSERT( 0 <= joint->colorIndex && joint->colorIndex < B2_GRAPH_COLOR_COUNT );
|
|
1193
|
+
|
|
1194
|
+
// In this case the joint must be re-inserted into the constraint graph to ensure the correct
|
|
1195
|
+
// graph color.
|
|
1196
|
+
|
|
1197
|
+
// First transfer to the static set.
|
|
1198
|
+
b2TransferJoint( world, staticSet, awakeSet, joint );
|
|
1199
|
+
|
|
1200
|
+
// Now transfer it back to the awake set and into the graph coloring.
|
|
1201
|
+
b2TransferJoint( world, awakeSet, staticSet, joint );
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Recreate shape proxies in static tree.
|
|
1206
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
1207
|
+
int shapeId = body->headShapeId;
|
|
1208
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1209
|
+
{
|
|
1210
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1211
|
+
shapeId = shape->nextShapeId;
|
|
1212
|
+
b2DestroyShapeProxy( shape, &world->broadPhase );
|
|
1213
|
+
bool forcePairCreation = true;
|
|
1214
|
+
b2CreateShapeProxy( shape, &world->broadPhase, b2_staticBody, transform, forcePairCreation );
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
else
|
|
1218
|
+
{
|
|
1219
|
+
B2_ASSERT( originalType == b2_dynamicBody || originalType == b2_kinematicBody );
|
|
1220
|
+
B2_ASSERT( type == b2_dynamicBody || type == b2_kinematicBody );
|
|
1221
|
+
|
|
1222
|
+
// Recreate shape proxies in static tree.
|
|
1223
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
1224
|
+
int shapeId = body->headShapeId;
|
|
1225
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1226
|
+
{
|
|
1227
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1228
|
+
shapeId = shape->nextShapeId;
|
|
1229
|
+
b2DestroyShapeProxy( shape, &world->broadPhase );
|
|
1230
|
+
b2BodyType proxyType = type;
|
|
1231
|
+
bool forcePairCreation = true;
|
|
1232
|
+
b2CreateShapeProxy( shape, &world->broadPhase, proxyType, transform, forcePairCreation );
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// Relink all joints
|
|
1237
|
+
{
|
|
1238
|
+
int jointKey = body->headJointKey;
|
|
1239
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1240
|
+
{
|
|
1241
|
+
int jointId = jointKey >> 1;
|
|
1242
|
+
int edgeIndex = jointKey & 1;
|
|
1243
|
+
|
|
1244
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1245
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1246
|
+
|
|
1247
|
+
int otherEdgeIndex = edgeIndex ^ 1;
|
|
1248
|
+
int otherBodyId = joint->edges[otherEdgeIndex].bodyId;
|
|
1249
|
+
b2Body* otherBody = b2BodyArray_Get( &world->bodies, otherBodyId );
|
|
1250
|
+
|
|
1251
|
+
if ( otherBody->setIndex == b2_disabledSet )
|
|
1252
|
+
{
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
if ( body->type == b2_staticBody && otherBody->type == b2_staticBody )
|
|
1257
|
+
{
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
b2LinkJoint( world, joint, false );
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
b2MergeAwakeIslands( world );
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// Body type affects the mass
|
|
1268
|
+
b2UpdateBodyMassData( world, body );
|
|
1269
|
+
|
|
1270
|
+
b2ValidateSolverSets( world );
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
void b2Body_SetName( b2BodyId bodyId, const char* name )
|
|
1274
|
+
{
|
|
1275
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1276
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1277
|
+
|
|
1278
|
+
if ( name != NULL )
|
|
1279
|
+
{
|
|
1280
|
+
for ( int i = 0; i < 31; ++i )
|
|
1281
|
+
{
|
|
1282
|
+
body->name[i] = name[i];
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
body->name[31] = 0;
|
|
1286
|
+
}
|
|
1287
|
+
else
|
|
1288
|
+
{
|
|
1289
|
+
memset( body->name, 0, 32 * sizeof( char ) );
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
const char* b2Body_GetName( b2BodyId bodyId )
|
|
1294
|
+
{
|
|
1295
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1296
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1297
|
+
return body->name;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
void b2Body_SetUserData( b2BodyId bodyId, void* userData )
|
|
1301
|
+
{
|
|
1302
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1303
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1304
|
+
body->userData = userData;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
void* b2Body_GetUserData( b2BodyId bodyId )
|
|
1308
|
+
{
|
|
1309
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1310
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1311
|
+
return body->userData;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
float b2Body_GetMass( b2BodyId bodyId )
|
|
1315
|
+
{
|
|
1316
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1317
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1318
|
+
return body->mass;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
float b2Body_GetRotationalInertia( b2BodyId bodyId )
|
|
1322
|
+
{
|
|
1323
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1324
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1325
|
+
return body->inertia;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
b2Vec2 b2Body_GetLocalCenterOfMass( b2BodyId bodyId )
|
|
1329
|
+
{
|
|
1330
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1331
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1332
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1333
|
+
return bodySim->localCenter;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
b2Vec2 b2Body_GetWorldCenterOfMass( b2BodyId bodyId )
|
|
1337
|
+
{
|
|
1338
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1339
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1340
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1341
|
+
return bodySim->center;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
void b2Body_SetMassData( b2BodyId bodyId, b2MassData massData )
|
|
1345
|
+
{
|
|
1346
|
+
B2_ASSERT( b2IsValidFloat( massData.mass ) && massData.mass >= 0.0f );
|
|
1347
|
+
B2_ASSERT( b2IsValidFloat( massData.rotationalInertia ) && massData.rotationalInertia >= 0.0f );
|
|
1348
|
+
B2_ASSERT( b2IsValidVec2( massData.center ) );
|
|
1349
|
+
|
|
1350
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1351
|
+
if ( world == NULL )
|
|
1352
|
+
{
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1357
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1358
|
+
|
|
1359
|
+
body->mass = massData.mass;
|
|
1360
|
+
body->inertia = massData.rotationalInertia;
|
|
1361
|
+
bodySim->localCenter = massData.center;
|
|
1362
|
+
|
|
1363
|
+
b2Vec2 center = b2TransformPoint( bodySim->transform, massData.center );
|
|
1364
|
+
bodySim->center = center;
|
|
1365
|
+
bodySim->center0 = center;
|
|
1366
|
+
|
|
1367
|
+
bodySim->invMass = body->mass > 0.0f ? 1.0f / body->mass : 0.0f;
|
|
1368
|
+
bodySim->invInertia = body->inertia > 0.0f ? 1.0f / body->inertia : 0.0f;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
b2MassData b2Body_GetMassData( b2BodyId bodyId )
|
|
1372
|
+
{
|
|
1373
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1374
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1375
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1376
|
+
b2MassData massData = { body->mass, bodySim->localCenter, body->inertia };
|
|
1377
|
+
return massData;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
void b2Body_ApplyMassFromShapes( b2BodyId bodyId )
|
|
1381
|
+
{
|
|
1382
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1383
|
+
if ( world == NULL )
|
|
1384
|
+
{
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1389
|
+
b2UpdateBodyMassData( world, body );
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
void b2Body_SetLinearDamping( b2BodyId bodyId, float linearDamping )
|
|
1393
|
+
{
|
|
1394
|
+
B2_ASSERT( b2IsValidFloat( linearDamping ) && linearDamping >= 0.0f );
|
|
1395
|
+
|
|
1396
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1397
|
+
if ( world == NULL )
|
|
1398
|
+
{
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1403
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1404
|
+
bodySim->linearDamping = linearDamping;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
float b2Body_GetLinearDamping( b2BodyId bodyId )
|
|
1408
|
+
{
|
|
1409
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1410
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1411
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1412
|
+
return bodySim->linearDamping;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
void b2Body_SetAngularDamping( b2BodyId bodyId, float angularDamping )
|
|
1416
|
+
{
|
|
1417
|
+
B2_ASSERT( b2IsValidFloat( angularDamping ) && angularDamping >= 0.0f );
|
|
1418
|
+
|
|
1419
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1420
|
+
if ( world == NULL )
|
|
1421
|
+
{
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1426
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1427
|
+
bodySim->angularDamping = angularDamping;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
float b2Body_GetAngularDamping( b2BodyId bodyId )
|
|
1431
|
+
{
|
|
1432
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1433
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1434
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1435
|
+
return bodySim->angularDamping;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
void b2Body_SetGravityScale( b2BodyId bodyId, float gravityScale )
|
|
1439
|
+
{
|
|
1440
|
+
B2_ASSERT( b2Body_IsValid( bodyId ) );
|
|
1441
|
+
B2_ASSERT( b2IsValidFloat( gravityScale ) );
|
|
1442
|
+
|
|
1443
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1444
|
+
if ( world == NULL )
|
|
1445
|
+
{
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1450
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1451
|
+
bodySim->gravityScale = gravityScale;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
float b2Body_GetGravityScale( b2BodyId bodyId )
|
|
1455
|
+
{
|
|
1456
|
+
B2_ASSERT( b2Body_IsValid( bodyId ) );
|
|
1457
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1458
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1459
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1460
|
+
return bodySim->gravityScale;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
bool b2Body_IsAwake( b2BodyId bodyId )
|
|
1464
|
+
{
|
|
1465
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1466
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1467
|
+
return body->setIndex == b2_awakeSet;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
void b2Body_SetAwake( b2BodyId bodyId, bool awake )
|
|
1471
|
+
{
|
|
1472
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1473
|
+
if ( world == NULL )
|
|
1474
|
+
{
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1479
|
+
|
|
1480
|
+
if ( awake && body->setIndex >= b2_firstSleepingSet )
|
|
1481
|
+
{
|
|
1482
|
+
b2WakeBody( world, body );
|
|
1483
|
+
}
|
|
1484
|
+
else if ( awake == false && body->setIndex == b2_awakeSet )
|
|
1485
|
+
{
|
|
1486
|
+
b2Island* island = b2IslandArray_Get( &world->islands, body->islandId );
|
|
1487
|
+
if ( island->constraintRemoveCount > 0 )
|
|
1488
|
+
{
|
|
1489
|
+
// Must split the island before sleeping. This is expensive.
|
|
1490
|
+
b2SplitIsland( world, body->islandId );
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
b2TrySleepIsland( world, body->islandId );
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
bool b2Body_IsEnabled( b2BodyId bodyId )
|
|
1498
|
+
{
|
|
1499
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1500
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1501
|
+
return body->setIndex != b2_disabledSet;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
bool b2Body_IsSleepEnabled( b2BodyId bodyId )
|
|
1505
|
+
{
|
|
1506
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1507
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1508
|
+
return body->enableSleep;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
void b2Body_SetSleepThreshold( b2BodyId bodyId, float sleepThreshold )
|
|
1512
|
+
{
|
|
1513
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1514
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1515
|
+
body->sleepThreshold = sleepThreshold;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
float b2Body_GetSleepThreshold( b2BodyId bodyId )
|
|
1519
|
+
{
|
|
1520
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1521
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1522
|
+
return body->sleepThreshold;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
void b2Body_EnableSleep( b2BodyId bodyId, bool enableSleep )
|
|
1526
|
+
{
|
|
1527
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1528
|
+
if ( world == NULL )
|
|
1529
|
+
{
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1534
|
+
body->enableSleep = enableSleep;
|
|
1535
|
+
|
|
1536
|
+
if ( enableSleep == false )
|
|
1537
|
+
{
|
|
1538
|
+
b2WakeBody( world, body );
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// Disabling a body requires a lot of detailed bookkeeping, but it is a valuable feature.
|
|
1543
|
+
// The most challenging aspect that joints may connect to bodies that are not disabled.
|
|
1544
|
+
void b2Body_Disable( b2BodyId bodyId )
|
|
1545
|
+
{
|
|
1546
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1547
|
+
if ( world == NULL )
|
|
1548
|
+
{
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1553
|
+
if ( body->setIndex == b2_disabledSet )
|
|
1554
|
+
{
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
// Destroy contacts and wake bodies touching this body. This avoid floating bodies.
|
|
1559
|
+
// This is necessary even for static bodies.
|
|
1560
|
+
bool wakeBodies = true;
|
|
1561
|
+
b2DestroyBodyContacts( world, body, wakeBodies );
|
|
1562
|
+
|
|
1563
|
+
// Disabled bodies are not in an island.
|
|
1564
|
+
b2RemoveBodyFromIsland( world, body );
|
|
1565
|
+
|
|
1566
|
+
// Remove shapes from broad-phase
|
|
1567
|
+
int shapeId = body->headShapeId;
|
|
1568
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1569
|
+
{
|
|
1570
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1571
|
+
shapeId = shape->nextShapeId;
|
|
1572
|
+
b2DestroyShapeProxy( shape, &world->broadPhase );
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// Transfer simulation data to disabled set
|
|
1576
|
+
b2SolverSet* set = b2SolverSetArray_Get( &world->solverSets, body->setIndex );
|
|
1577
|
+
b2SolverSet* disabledSet = b2SolverSetArray_Get( &world->solverSets, b2_disabledSet );
|
|
1578
|
+
|
|
1579
|
+
// Transfer body sim
|
|
1580
|
+
b2TransferBody( world, disabledSet, set, body );
|
|
1581
|
+
|
|
1582
|
+
// Unlink joints and transfer
|
|
1583
|
+
int jointKey = body->headJointKey;
|
|
1584
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1585
|
+
{
|
|
1586
|
+
int jointId = jointKey >> 1;
|
|
1587
|
+
int edgeIndex = jointKey & 1;
|
|
1588
|
+
|
|
1589
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1590
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1591
|
+
|
|
1592
|
+
// joint may already be disabled by other body
|
|
1593
|
+
if ( joint->setIndex == b2_disabledSet )
|
|
1594
|
+
{
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
B2_ASSERT( joint->setIndex == set->setIndex || set->setIndex == b2_staticSet );
|
|
1599
|
+
|
|
1600
|
+
// Remove joint from island
|
|
1601
|
+
if ( joint->islandId != B2_NULL_INDEX )
|
|
1602
|
+
{
|
|
1603
|
+
b2UnlinkJoint( world, joint );
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// Transfer joint to disabled set
|
|
1607
|
+
b2SolverSet* jointSet = b2SolverSetArray_Get( &world->solverSets, joint->setIndex );
|
|
1608
|
+
b2TransferJoint( world, disabledSet, jointSet, joint );
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
b2ValidateConnectivity( world );
|
|
1612
|
+
b2ValidateSolverSets( world );
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
void b2Body_Enable( b2BodyId bodyId )
|
|
1616
|
+
{
|
|
1617
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1618
|
+
if ( world == NULL )
|
|
1619
|
+
{
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1624
|
+
if ( body->setIndex != b2_disabledSet )
|
|
1625
|
+
{
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
b2SolverSet* disabledSet = b2SolverSetArray_Get( &world->solverSets, b2_disabledSet );
|
|
1630
|
+
int setId = body->type == b2_staticBody ? b2_staticSet : b2_awakeSet;
|
|
1631
|
+
b2SolverSet* targetSet = b2SolverSetArray_Get( &world->solverSets, setId );
|
|
1632
|
+
|
|
1633
|
+
b2TransferBody( world, targetSet, disabledSet, body );
|
|
1634
|
+
|
|
1635
|
+
b2Transform transform = b2GetBodyTransformQuick( world, body );
|
|
1636
|
+
|
|
1637
|
+
// Add shapes to broad-phase
|
|
1638
|
+
b2BodyType proxyType = body->type;
|
|
1639
|
+
bool forcePairCreation = true;
|
|
1640
|
+
int shapeId = body->headShapeId;
|
|
1641
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1642
|
+
{
|
|
1643
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1644
|
+
shapeId = shape->nextShapeId;
|
|
1645
|
+
|
|
1646
|
+
b2CreateShapeProxy( shape, &world->broadPhase, proxyType, transform, forcePairCreation );
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
if ( setId != b2_staticSet )
|
|
1650
|
+
{
|
|
1651
|
+
b2CreateIslandForBody( world, setId, body );
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// Transfer joints. If the other body is disabled, don't transfer.
|
|
1655
|
+
// If the other body is sleeping, wake it.
|
|
1656
|
+
bool mergeIslands = false;
|
|
1657
|
+
int jointKey = body->headJointKey;
|
|
1658
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1659
|
+
{
|
|
1660
|
+
int jointId = jointKey >> 1;
|
|
1661
|
+
int edgeIndex = jointKey & 1;
|
|
1662
|
+
|
|
1663
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1664
|
+
B2_ASSERT( joint->setIndex == b2_disabledSet );
|
|
1665
|
+
B2_ASSERT( joint->islandId == B2_NULL_INDEX );
|
|
1666
|
+
|
|
1667
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1668
|
+
|
|
1669
|
+
b2Body* bodyA = b2BodyArray_Get( &world->bodies, joint->edges[0].bodyId );
|
|
1670
|
+
b2Body* bodyB = b2BodyArray_Get( &world->bodies, joint->edges[1].bodyId );
|
|
1671
|
+
|
|
1672
|
+
if ( bodyA->setIndex == b2_disabledSet || bodyB->setIndex == b2_disabledSet )
|
|
1673
|
+
{
|
|
1674
|
+
// one body is still disabled
|
|
1675
|
+
continue;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// Transfer joint first
|
|
1679
|
+
int jointSetId;
|
|
1680
|
+
if ( bodyA->setIndex == b2_staticSet && bodyB->setIndex == b2_staticSet )
|
|
1681
|
+
{
|
|
1682
|
+
jointSetId = b2_staticSet;
|
|
1683
|
+
}
|
|
1684
|
+
else if ( bodyA->setIndex == b2_staticSet )
|
|
1685
|
+
{
|
|
1686
|
+
jointSetId = bodyB->setIndex;
|
|
1687
|
+
}
|
|
1688
|
+
else
|
|
1689
|
+
{
|
|
1690
|
+
jointSetId = bodyA->setIndex;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
b2SolverSet* jointSet = b2SolverSetArray_Get( &world->solverSets, jointSetId );
|
|
1694
|
+
b2TransferJoint( world, jointSet, disabledSet, joint );
|
|
1695
|
+
|
|
1696
|
+
// Now that the joint is in the correct set, I can link the joint in the island.
|
|
1697
|
+
if ( jointSetId != b2_staticSet )
|
|
1698
|
+
{
|
|
1699
|
+
b2LinkJoint( world, joint, mergeIslands );
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// Now merge islands
|
|
1704
|
+
b2MergeAwakeIslands( world );
|
|
1705
|
+
|
|
1706
|
+
b2ValidateSolverSets( world );
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
void b2Body_SetFixedRotation( b2BodyId bodyId, bool flag )
|
|
1710
|
+
{
|
|
1711
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1712
|
+
if ( world == NULL )
|
|
1713
|
+
{
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1718
|
+
if ( body->fixedRotation != flag )
|
|
1719
|
+
{
|
|
1720
|
+
body->fixedRotation = flag;
|
|
1721
|
+
|
|
1722
|
+
b2BodyState* state = b2GetBodyState( world, body );
|
|
1723
|
+
if ( state != NULL )
|
|
1724
|
+
{
|
|
1725
|
+
state->angularVelocity = 0.0f;
|
|
1726
|
+
}
|
|
1727
|
+
b2UpdateBodyMassData( world, body );
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
bool b2Body_IsFixedRotation( b2BodyId bodyId )
|
|
1732
|
+
{
|
|
1733
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1734
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1735
|
+
return body->fixedRotation;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
void b2Body_SetBullet( b2BodyId bodyId, bool flag )
|
|
1739
|
+
{
|
|
1740
|
+
b2World* world = b2GetWorldLocked( bodyId.world0 );
|
|
1741
|
+
if ( world == NULL )
|
|
1742
|
+
{
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1747
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1748
|
+
bodySim->isBullet = flag;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
bool b2Body_IsBullet( b2BodyId bodyId )
|
|
1752
|
+
{
|
|
1753
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1754
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1755
|
+
b2BodySim* bodySim = b2GetBodySim( world, body );
|
|
1756
|
+
return bodySim->isBullet;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
void b2Body_EnableContactEvents( b2BodyId bodyId, bool flag )
|
|
1760
|
+
{
|
|
1761
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1762
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1763
|
+
int shapeId = body->headShapeId;
|
|
1764
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1765
|
+
{
|
|
1766
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1767
|
+
shape->enableContactEvents = flag;
|
|
1768
|
+
shapeId = shape->nextShapeId;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
void b2Body_EnableHitEvents( b2BodyId bodyId, bool flag )
|
|
1773
|
+
{
|
|
1774
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1775
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1776
|
+
int shapeId = body->headShapeId;
|
|
1777
|
+
while ( shapeId != B2_NULL_INDEX )
|
|
1778
|
+
{
|
|
1779
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1780
|
+
shape->enableHitEvents = flag;
|
|
1781
|
+
shapeId = shape->nextShapeId;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
b2WorldId b2Body_GetWorld( b2BodyId bodyId )
|
|
1786
|
+
{
|
|
1787
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1788
|
+
return (b2WorldId){ bodyId.world0 + 1, world->generation };
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
int b2Body_GetShapeCount( b2BodyId bodyId )
|
|
1792
|
+
{
|
|
1793
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1794
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1795
|
+
return body->shapeCount;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
int b2Body_GetShapes( b2BodyId bodyId, b2ShapeId* shapeArray, int capacity )
|
|
1799
|
+
{
|
|
1800
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1801
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1802
|
+
int shapeId = body->headShapeId;
|
|
1803
|
+
int shapeCount = 0;
|
|
1804
|
+
while ( shapeId != B2_NULL_INDEX && shapeCount < capacity )
|
|
1805
|
+
{
|
|
1806
|
+
b2Shape* shape = b2ShapeArray_Get( &world->shapes, shapeId );
|
|
1807
|
+
b2ShapeId id = { shape->id + 1, bodyId.world0, shape->generation };
|
|
1808
|
+
shapeArray[shapeCount] = id;
|
|
1809
|
+
shapeCount += 1;
|
|
1810
|
+
|
|
1811
|
+
shapeId = shape->nextShapeId;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
return shapeCount;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
int b2Body_GetJointCount( b2BodyId bodyId )
|
|
1818
|
+
{
|
|
1819
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1820
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1821
|
+
return body->jointCount;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
int b2Body_GetJoints( b2BodyId bodyId, b2JointId* jointArray, int capacity )
|
|
1825
|
+
{
|
|
1826
|
+
b2World* world = b2GetWorld( bodyId.world0 );
|
|
1827
|
+
b2Body* body = b2GetBodyFullId( world, bodyId );
|
|
1828
|
+
int jointKey = body->headJointKey;
|
|
1829
|
+
|
|
1830
|
+
int jointCount = 0;
|
|
1831
|
+
while ( jointKey != B2_NULL_INDEX && jointCount < capacity )
|
|
1832
|
+
{
|
|
1833
|
+
int jointId = jointKey >> 1;
|
|
1834
|
+
int edgeIndex = jointKey & 1;
|
|
1835
|
+
|
|
1836
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1837
|
+
|
|
1838
|
+
b2JointId id = { jointId + 1, bodyId.world0, joint->generation };
|
|
1839
|
+
jointArray[jointCount] = id;
|
|
1840
|
+
jointCount += 1;
|
|
1841
|
+
|
|
1842
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
return jointCount;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
bool b2ShouldBodiesCollide( b2World* world, b2Body* bodyA, b2Body* bodyB )
|
|
1849
|
+
{
|
|
1850
|
+
if ( bodyA->type != b2_dynamicBody && bodyB->type != b2_dynamicBody )
|
|
1851
|
+
{
|
|
1852
|
+
return false;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
int jointKey;
|
|
1856
|
+
int otherBodyId;
|
|
1857
|
+
if ( bodyA->jointCount < bodyB->jointCount )
|
|
1858
|
+
{
|
|
1859
|
+
jointKey = bodyA->headJointKey;
|
|
1860
|
+
otherBodyId = bodyB->id;
|
|
1861
|
+
}
|
|
1862
|
+
else
|
|
1863
|
+
{
|
|
1864
|
+
jointKey = bodyB->headJointKey;
|
|
1865
|
+
otherBodyId = bodyA->id;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
while ( jointKey != B2_NULL_INDEX )
|
|
1869
|
+
{
|
|
1870
|
+
int jointId = jointKey >> 1;
|
|
1871
|
+
int edgeIndex = jointKey & 1;
|
|
1872
|
+
int otherEdgeIndex = edgeIndex ^ 1;
|
|
1873
|
+
|
|
1874
|
+
b2Joint* joint = b2JointArray_Get( &world->joints, jointId );
|
|
1875
|
+
if ( joint->collideConnected == false && joint->edges[otherEdgeIndex].bodyId == otherBodyId )
|
|
1876
|
+
{
|
|
1877
|
+
return false;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
jointKey = joint->edges[edgeIndex].nextKey;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
return true;
|
|
1884
|
+
}
|