chipmunk 5.3.4.5 → 6.1.3.0.rc1
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.
- data/ext/chipmunk/chipmunk.c +199 -28
- data/ext/chipmunk/chipmunk.h +123 -68
- data/ext/chipmunk/chipmunk_ffi.h +129 -11
- data/ext/chipmunk/chipmunk_private.h +232 -16
- data/ext/chipmunk/chipmunk_types.h +94 -30
- data/ext/chipmunk/chipmunk_unsafe.h +12 -3
- data/ext/chipmunk/constraints/cpConstraint.h +90 -34
- data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
- data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
- data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
- data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
- data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
- data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
- data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
- data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
- data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
- data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
- data/ext/chipmunk/constraints/util.h +36 -44
- data/ext/chipmunk/cpArbiter.c +159 -94
- data/ext/chipmunk/cpArbiter.h +135 -129
- data/ext/chipmunk/cpArray.c +37 -56
- data/ext/chipmunk/cpBB.c +1 -12
- data/ext/chipmunk/cpBB.h +80 -18
- data/ext/chipmunk/cpBBTree.c +891 -0
- data/ext/chipmunk/cpBody.c +185 -47
- data/ext/chipmunk/cpBody.h +156 -124
- data/ext/chipmunk/cpCollision.c +126 -115
- data/ext/chipmunk/cpConstraint.c +10 -6
- data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
- data/ext/chipmunk/cpDampedSpring.c +25 -18
- data/ext/chipmunk/cpGearJoint.c +23 -17
- data/ext/chipmunk/cpGrooveJoint.c +26 -22
- data/ext/chipmunk/cpHashSet.c +51 -51
- data/ext/chipmunk/cpPinJoint.c +26 -19
- data/ext/chipmunk/cpPivotJoint.c +23 -19
- data/ext/chipmunk/cpPolyShape.c +93 -69
- data/ext/chipmunk/cpPolyShape.h +33 -69
- data/ext/chipmunk/cpRatchetJoint.c +26 -21
- data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
- data/ext/chipmunk/cpShape.c +122 -133
- data/ext/chipmunk/cpShape.h +146 -95
- data/ext/chipmunk/cpSimpleMotor.c +24 -17
- data/ext/chipmunk/cpSlideJoint.c +28 -26
- data/ext/chipmunk/cpSpace.c +251 -196
- data/ext/chipmunk/cpSpace.h +173 -103
- data/ext/chipmunk/cpSpaceComponent.c +236 -159
- data/ext/chipmunk/cpSpaceHash.c +259 -159
- data/ext/chipmunk/cpSpaceQuery.c +127 -59
- data/ext/chipmunk/cpSpaceStep.c +235 -197
- data/ext/chipmunk/cpSpatialIndex.c +69 -0
- data/ext/chipmunk/cpSpatialIndex.h +227 -0
- data/ext/chipmunk/cpSweep1D.c +254 -0
- data/ext/chipmunk/cpVect.c +11 -26
- data/ext/chipmunk/cpVect.h +76 -71
- data/ext/chipmunk/extconf.rb +4 -31
- data/ext/chipmunk/prime.h +1 -1
- data/ext/chipmunk/rb_chipmunk.c +36 -45
- data/ext/chipmunk/rb_chipmunk.h +6 -3
- data/ext/chipmunk/rb_cpArbiter.c +2 -2
- data/ext/chipmunk/rb_cpBB.c +116 -35
- data/ext/chipmunk/rb_cpBody.c +5 -12
- data/ext/chipmunk/rb_cpConstraint.c +144 -9
- data/ext/chipmunk/rb_cpShape.c +69 -78
- data/ext/chipmunk/rb_cpSpace.c +81 -76
- metadata +61 -61
- data/LICENSE +0 -22
- data/README +0 -110
- data/Rakefile +0 -102
- data/ext/chipmunk/cpArray.h +0 -49
- data/ext/chipmunk/cpCollision.h +0 -28
- data/ext/chipmunk/cpHashSet.h +0 -82
- data/ext/chipmunk/cpSpaceHash.h +0 -110
- data/lib/chipmunk.rb +0 -194
data/ext/chipmunk/cpSpace.c
CHANGED
@@ -19,20 +19,16 @@
|
|
19
19
|
* SOFTWARE.
|
20
20
|
*/
|
21
21
|
|
22
|
-
#include <
|
23
|
-
//#include <stdio.h>
|
22
|
+
#include <stdio.h>
|
24
23
|
#include <string.h>
|
25
|
-
#include <math.h>
|
26
24
|
|
27
25
|
#include "chipmunk_private.h"
|
28
26
|
|
29
|
-
|
27
|
+
//MARK: Contact Set Helpers
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
// Equal function for contactSet.
|
29
|
+
// Equal function for arbiterSet.
|
34
30
|
static cpBool
|
35
|
-
|
31
|
+
arbiterSetEql(cpShape **shapes, cpArbiter *arb)
|
36
32
|
{
|
37
33
|
cpShape *a = shapes[0];
|
38
34
|
cpShape *b = shapes[1];
|
@@ -40,59 +36,37 @@ contactSetEql(cpShape **shapes, cpArbiter *arb)
|
|
40
36
|
return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));
|
41
37
|
}
|
42
38
|
|
43
|
-
//
|
44
|
-
static void *
|
45
|
-
contactSetTrans(cpShape **shapes, cpSpace *space)
|
46
|
-
{
|
47
|
-
if(space->pooledArbiters->num == 0){
|
48
|
-
// arbiter pool is exhausted, make more
|
49
|
-
int count = CP_BUFFER_BYTES/sizeof(cpArbiter);
|
50
|
-
cpAssert(count, "Buffer size too small.");
|
51
|
-
|
52
|
-
cpArbiter *buffer = (cpArbiter *)cpmalloc(CP_BUFFER_BYTES);
|
53
|
-
cpArrayPush(space->allocatedBuffers, buffer);
|
54
|
-
|
55
|
-
for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);
|
56
|
-
}
|
57
|
-
|
58
|
-
return cpArbiterInit((cpArbiter *) cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);
|
59
|
-
}
|
60
|
-
|
61
|
-
#pragma mark Collision Pair Function Helpers
|
39
|
+
//MARK: Collision Handler Set HelperFunctions
|
62
40
|
|
63
|
-
// Equals function for
|
41
|
+
// Equals function for collisionHandlers.
|
64
42
|
static cpBool
|
65
|
-
|
43
|
+
handlerSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
|
66
44
|
{
|
67
45
|
return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b));
|
68
46
|
}
|
69
47
|
|
70
|
-
// Transformation function for
|
48
|
+
// Transformation function for collisionHandlers.
|
71
49
|
static void *
|
72
|
-
|
50
|
+
handlerSetTrans(cpCollisionHandler *handler, void *unused)
|
73
51
|
{
|
74
|
-
cpCollisionHandler *copy = (cpCollisionHandler *)
|
52
|
+
cpCollisionHandler *copy = (cpCollisionHandler *)cpcalloc(1, sizeof(cpCollisionHandler));
|
75
53
|
(*copy) = (*handler);
|
76
54
|
|
77
55
|
return copy;
|
78
56
|
}
|
79
57
|
|
80
|
-
|
58
|
+
//MARK: Misc Helper Funcs
|
81
59
|
|
82
60
|
// Default collision functions.
|
83
61
|
static cpBool alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
|
84
62
|
static void nothing(cpArbiter *arb, cpSpace *space, void *data){}
|
85
63
|
|
86
|
-
//
|
87
|
-
static
|
64
|
+
// function to get the estimated velocity of a shape for the cpBBTree.
|
65
|
+
static cpVect shapeVelocityFunc(cpShape *shape){return shape->body->v;}
|
88
66
|
|
89
|
-
|
90
|
-
static void freeWrap(void *ptr, void *unused){ cpfree(ptr);}
|
91
|
-
static void shapeFreeWrap(cpShape *ptr, void *unused){ cpShapeFree(ptr);}
|
92
|
-
static void bodyFreeWrap(cpBody *ptr, void *unused){ cpBodyFree(ptr);}
|
93
|
-
static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFree(ptr);}
|
67
|
+
static void freeWrap(void *ptr, void *unused){cpfree(ptr);}
|
94
68
|
|
95
|
-
|
69
|
+
//MARK: Memory Management Functions
|
96
70
|
|
97
71
|
cpSpace *
|
98
72
|
cpSpaceAlloc(void)
|
@@ -100,28 +74,35 @@ cpSpaceAlloc(void)
|
|
100
74
|
return (cpSpace *)cpcalloc(1, sizeof(cpSpace));
|
101
75
|
}
|
102
76
|
|
103
|
-
|
104
|
-
#define DEFAULT_COUNT 1000
|
105
|
-
#define DEFAULT_ITERATIONS 10
|
106
|
-
#define DEFAULT_ELASTIC_ITERATIONS 0
|
107
|
-
|
108
|
-
cpCollisionHandler defaultHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL};
|
77
|
+
cpCollisionHandler cpDefaultCollisionHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL};
|
109
78
|
|
110
79
|
cpSpace*
|
111
80
|
cpSpaceInit(cpSpace *space)
|
112
81
|
{
|
113
|
-
|
114
|
-
|
115
|
-
|
82
|
+
#ifndef NDEBUG
|
83
|
+
static cpBool done = cpFalse;
|
84
|
+
if(!done){
|
85
|
+
printf("Initializing cpSpace - Chipmunk v%s (Debug Enabled)\n", cpVersionString);
|
86
|
+
printf("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n");
|
87
|
+
done = cpTrue;
|
88
|
+
}
|
89
|
+
#endif
|
90
|
+
|
91
|
+
space->iterations = 10;
|
116
92
|
|
117
93
|
space->gravity = cpvzero;
|
118
94
|
space->damping = 1.0f;
|
119
95
|
|
96
|
+
space->collisionSlop = 0.1f;
|
97
|
+
space->collisionBias = cpfpow(1.0f - 0.1f, 60.0f);
|
98
|
+
space->collisionPersistence = 3;
|
99
|
+
|
120
100
|
space->locked = 0;
|
121
101
|
space->stamp = 0;
|
122
102
|
|
123
|
-
space->staticShapes =
|
124
|
-
space->activeShapes =
|
103
|
+
space->staticShapes = cpBBTreeNew((cpSpatialIndexBBFunc)cpShapeGetBB, NULL);
|
104
|
+
space->activeShapes = cpBBTreeNew((cpSpatialIndexBBFunc)cpShapeGetBB, space->staticShapes);
|
105
|
+
cpBBTreeSetVelocityFunc(space->activeShapes, (cpBBTreeVelocityFunc)shapeVelocityFunc);
|
125
106
|
|
126
107
|
space->allocatedBuffers = cpArrayNew(0);
|
127
108
|
|
@@ -131,22 +112,25 @@ cpSpaceInit(cpSpace *space)
|
|
131
112
|
|
132
113
|
space->sleepTimeThreshold = INFINITY;
|
133
114
|
space->idleSpeedThreshold = 0.0f;
|
115
|
+
space->enableContactGraph = cpFalse;
|
134
116
|
|
135
117
|
space->arbiters = cpArrayNew(0);
|
136
118
|
space->pooledArbiters = cpArrayNew(0);
|
137
119
|
|
138
120
|
space->contactBuffersHead = NULL;
|
139
|
-
space->
|
121
|
+
space->cachedArbiters = cpHashSetNew(0, (cpHashSetEqlFunc)arbiterSetEql);
|
140
122
|
|
141
123
|
space->constraints = cpArrayNew(0);
|
142
124
|
|
143
|
-
space->defaultHandler =
|
144
|
-
space->
|
145
|
-
space->
|
125
|
+
space->defaultHandler = cpDefaultCollisionHandler;
|
126
|
+
space->collisionHandlers = cpHashSetNew(0, (cpHashSetEqlFunc)handlerSetEql);
|
127
|
+
cpHashSetSetDefaultValue(space->collisionHandlers, &cpDefaultCollisionHandler);
|
146
128
|
|
147
|
-
space->postStepCallbacks =
|
129
|
+
space->postStepCallbacks = cpArrayNew(0);
|
130
|
+
space->skipPostStep = cpFalse;
|
148
131
|
|
149
|
-
cpBodyInitStatic(&space->
|
132
|
+
cpBodyInitStatic(&space->_staticBody);
|
133
|
+
space->staticBody = &space->_staticBody;
|
150
134
|
|
151
135
|
return space;
|
152
136
|
}
|
@@ -160,8 +144,10 @@ cpSpaceNew(void)
|
|
160
144
|
void
|
161
145
|
cpSpaceDestroy(cpSpace *space)
|
162
146
|
{
|
163
|
-
|
164
|
-
|
147
|
+
cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)cpBodyActivate, NULL);
|
148
|
+
|
149
|
+
cpSpatialIndexFree(space->staticShapes);
|
150
|
+
cpSpatialIndexFree(space->activeShapes);
|
165
151
|
|
166
152
|
cpArrayFree(space->bodies);
|
167
153
|
cpArrayFree(space->sleepingComponents);
|
@@ -169,25 +155,23 @@ cpSpaceDestroy(cpSpace *space)
|
|
169
155
|
|
170
156
|
cpArrayFree(space->constraints);
|
171
157
|
|
172
|
-
cpHashSetFree(space->
|
158
|
+
cpHashSetFree(space->cachedArbiters);
|
173
159
|
|
174
160
|
cpArrayFree(space->arbiters);
|
175
161
|
cpArrayFree(space->pooledArbiters);
|
176
162
|
|
177
163
|
if(space->allocatedBuffers){
|
178
|
-
|
164
|
+
cpArrayFreeEach(space->allocatedBuffers, cpfree);
|
179
165
|
cpArrayFree(space->allocatedBuffers);
|
180
166
|
}
|
181
167
|
|
182
168
|
if(space->postStepCallbacks){
|
183
|
-
|
184
|
-
|
169
|
+
cpArrayFreeEach(space->postStepCallbacks, cpfree);
|
170
|
+
cpArrayFree(space->postStepCallbacks);
|
185
171
|
}
|
186
172
|
|
187
|
-
if(space->
|
188
|
-
|
189
|
-
cpHashSetFree(space->collFuncSet);
|
190
|
-
}
|
173
|
+
if(space->collisionHandlers) cpHashSetEach(space->collisionHandlers, freeWrap, NULL);
|
174
|
+
cpHashSetFree(space->collisionHandlers);
|
191
175
|
}
|
192
176
|
|
193
177
|
void
|
@@ -199,19 +183,13 @@ cpSpaceFree(cpSpace *space)
|
|
199
183
|
}
|
200
184
|
}
|
201
185
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
|
209
|
-
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
|
210
|
-
cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL);
|
211
|
-
cpArrayEach(space->constraints, (cpArrayIter)&constraintFreeWrap, NULL);
|
212
|
-
}
|
186
|
+
#define cpAssertSpaceUnlocked(space) \
|
187
|
+
cpAssertHard(!space->locked, \
|
188
|
+
"This addition/removal cannot be done safely during a call to cpSpaceStep() or during a query. " \
|
189
|
+
"Put these calls into a post-step callback." \
|
190
|
+
);
|
213
191
|
|
214
|
-
|
192
|
+
//MARK: Collision Handler Function Management
|
215
193
|
|
216
194
|
void
|
217
195
|
cpSpaceAddCollisionHandler(
|
@@ -223,6 +201,8 @@ cpSpaceAddCollisionHandler(
|
|
223
201
|
cpCollisionSeparateFunc separate,
|
224
202
|
void *data
|
225
203
|
){
|
204
|
+
cpAssertSpaceUnlocked(space);
|
205
|
+
|
226
206
|
// Remove any old function so the new one will get added.
|
227
207
|
cpSpaceRemoveCollisionHandler(space, a, b);
|
228
208
|
|
@@ -235,14 +215,16 @@ cpSpaceAddCollisionHandler(
|
|
235
215
|
data
|
236
216
|
};
|
237
217
|
|
238
|
-
cpHashSetInsert(space->
|
218
|
+
cpHashSetInsert(space->collisionHandlers, CP_HASH_PAIR(a, b), &handler, NULL, (cpHashSetTransFunc)handlerSetTrans);
|
239
219
|
}
|
240
220
|
|
241
221
|
void
|
242
222
|
cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)
|
243
223
|
{
|
244
|
-
|
245
|
-
|
224
|
+
cpAssertSpaceUnlocked(space);
|
225
|
+
|
226
|
+
struct { cpCollisionType a, b; } ids = {a, b};
|
227
|
+
cpCollisionHandler *old_handler = (cpCollisionHandler *) cpHashSetRemove(space->collisionHandlers, CP_HASH_PAIR(a, b), &ids);
|
246
228
|
cpfree(old_handler);
|
247
229
|
}
|
248
230
|
|
@@ -255,6 +237,8 @@ cpSpaceSetDefaultCollisionHandler(
|
|
255
237
|
cpCollisionSeparateFunc separate,
|
256
238
|
void *data
|
257
239
|
){
|
240
|
+
cpAssertSpaceUnlocked(space);
|
241
|
+
|
258
242
|
cpCollisionHandler handler = {
|
259
243
|
0, 0,
|
260
244
|
begin ? begin : alwaysCollide,
|
@@ -265,53 +249,25 @@ cpSpaceSetDefaultCollisionHandler(
|
|
265
249
|
};
|
266
250
|
|
267
251
|
space->defaultHandler = handler;
|
252
|
+
cpHashSetSetDefaultValue(space->collisionHandlers, &space->defaultHandler);
|
268
253
|
}
|
269
254
|
|
270
|
-
|
271
|
-
|
272
|
-
#define cpAssertSpaceUnlocked(space) \
|
273
|
-
cpAssert(!space->locked, \
|
274
|
-
"This addition/removal cannot be done safely during a call to cpSpaceStep() or during a query. " \
|
275
|
-
"Put these calls into a post-step callback." \
|
276
|
-
);
|
277
|
-
|
278
|
-
static void
|
279
|
-
cpBodyAddShape(cpBody *body, cpShape *shape)
|
280
|
-
{
|
281
|
-
shape->next = shape->body->shapesList;
|
282
|
-
shape->body->shapesList = shape;
|
283
|
-
}
|
284
|
-
|
285
|
-
static void
|
286
|
-
cpBodyRemoveShape(cpBody *body, cpShape *shape)
|
287
|
-
{
|
288
|
-
cpShape **prev_ptr = &body->shapesList;
|
289
|
-
cpShape *node = body->shapesList;
|
290
|
-
|
291
|
-
while(node && node != shape){
|
292
|
-
prev_ptr = &node->next;
|
293
|
-
node = node->next;
|
294
|
-
}
|
295
|
-
|
296
|
-
cpAssert(node, "Attempted to remove a shape from a body it was never attached to.");
|
297
|
-
(*prev_ptr) = node->next;
|
298
|
-
}
|
299
|
-
|
255
|
+
//MARK: Body, Shape, and Joint Management
|
300
256
|
cpShape *
|
301
257
|
cpSpaceAddShape(cpSpace *space, cpShape *shape)
|
302
258
|
{
|
303
259
|
cpBody *body = shape->body;
|
304
|
-
if(
|
260
|
+
if(cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape);
|
305
261
|
|
306
|
-
|
307
|
-
"Cannot add the same shape more than once.");
|
262
|
+
cpAssertHard(!shape->space, "This shape is already added to a space and cannot be added to another.");
|
308
263
|
cpAssertSpaceUnlocked(space);
|
309
264
|
|
310
265
|
cpBodyActivate(body);
|
311
266
|
cpBodyAddShape(body, shape);
|
312
267
|
|
313
|
-
|
314
|
-
|
268
|
+
cpShapeUpdate(shape, body->p, body->rot);
|
269
|
+
cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid);
|
270
|
+
shape->space = space;
|
315
271
|
|
316
272
|
return shape;
|
317
273
|
}
|
@@ -319,15 +275,14 @@ cpSpaceAddShape(cpSpace *space, cpShape *shape)
|
|
319
275
|
cpShape *
|
320
276
|
cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
|
321
277
|
{
|
322
|
-
|
323
|
-
"Cannot add the same static shape more than once.");
|
278
|
+
cpAssertHard(!shape->space, "This shape is already added to a space and cannot be added to another.");
|
324
279
|
cpAssertSpaceUnlocked(space);
|
325
280
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
281
|
+
cpBody *body = shape->body;
|
282
|
+
cpBodyAddShape(body, shape);
|
283
|
+
cpShapeUpdate(shape, body->p, body->rot);
|
284
|
+
cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid);
|
285
|
+
shape->space = space;
|
331
286
|
|
332
287
|
return shape;
|
333
288
|
}
|
@@ -335,9 +290,9 @@ cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
|
|
335
290
|
cpBody *
|
336
291
|
cpSpaceAddBody(cpSpace *space, cpBody *body)
|
337
292
|
{
|
338
|
-
|
339
|
-
|
340
|
-
|
293
|
+
cpAssertHard(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated.");
|
294
|
+
cpAssertHard(!body->space, "This body is already added to a space and cannot be added to another.");
|
295
|
+
cpAssertSpaceUnlocked(space);
|
341
296
|
|
342
297
|
cpArrayPush(space->bodies, body);
|
343
298
|
body->space = space;
|
@@ -348,84 +303,102 @@ cpSpaceAddBody(cpSpace *space, cpBody *body)
|
|
348
303
|
cpConstraint *
|
349
304
|
cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
|
350
305
|
{
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
if(!constraint->a) constraint->a = &space->staticBody;
|
355
|
-
if(!constraint->b) constraint->b = &space->staticBody;
|
306
|
+
cpAssertHard(!constraint->space, "This shape is already added to a space and cannot be added to another.");
|
307
|
+
cpAssertSpaceUnlocked(space);
|
356
308
|
|
357
309
|
cpBodyActivate(constraint->a);
|
358
310
|
cpBodyActivate(constraint->b);
|
359
311
|
cpArrayPush(space->constraints, constraint);
|
360
312
|
|
313
|
+
// Push onto the heads of the bodies' constraint lists
|
314
|
+
cpBody *a = constraint->a, *b = constraint->b;
|
315
|
+
constraint->next_a = a->constraintList; a->constraintList = constraint;
|
316
|
+
constraint->next_b = b->constraintList; b->constraintList = constraint;
|
317
|
+
constraint->space = space;
|
318
|
+
|
361
319
|
return constraint;
|
362
320
|
}
|
363
321
|
|
364
|
-
|
322
|
+
struct arbiterFilterContext {
|
365
323
|
cpSpace *space;
|
324
|
+
cpBody *body;
|
366
325
|
cpShape *shape;
|
367
|
-
}
|
326
|
+
};
|
368
327
|
|
369
|
-
// Hashset filter func to throw away old arbiters.
|
370
328
|
static cpBool
|
371
|
-
|
329
|
+
cachedArbitersFilter(cpArbiter *arb, struct arbiterFilterContext *context)
|
372
330
|
{
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
331
|
+
cpShape *shape = context->shape;
|
332
|
+
cpBody *body = context->body;
|
333
|
+
|
334
|
+
|
335
|
+
// Match on the filter shape, or if it's NULL the filter body
|
336
|
+
if(
|
337
|
+
(body == arb->body_a && (shape == arb->a || shape == NULL)) ||
|
338
|
+
(body == arb->body_b && (shape == arb->b || shape == NULL))
|
339
|
+
){
|
340
|
+
// Call separate when removing shapes.
|
341
|
+
if(shape && arb->state != cpArbiterStateCached) cpArbiterCallSeparate(arb, context->space);
|
377
342
|
|
343
|
+
cpArbiterUnthread(arb);
|
344
|
+
cpArrayDeleteObj(context->space->arbiters, arb);
|
378
345
|
cpArrayPush(context->space->pooledArbiters, arb);
|
346
|
+
|
379
347
|
return cpFalse;
|
380
348
|
}
|
381
349
|
|
382
350
|
return cpTrue;
|
383
351
|
}
|
384
352
|
|
353
|
+
void
|
354
|
+
cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter)
|
355
|
+
{
|
356
|
+
cpSpaceLock(space); {
|
357
|
+
struct arbiterFilterContext context = {space, body, filter};
|
358
|
+
cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cachedArbitersFilter, &context);
|
359
|
+
} cpSpaceUnlock(space, cpTrue);
|
360
|
+
}
|
361
|
+
|
385
362
|
void
|
386
363
|
cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
|
387
364
|
{
|
388
365
|
cpBody *body = shape->body;
|
389
366
|
if(cpBodyIsStatic(body)){
|
390
367
|
cpSpaceRemoveStaticShape(space, shape);
|
391
|
-
|
368
|
+
} else {
|
369
|
+
cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a shape that was not added to the space. (Removed twice maybe?)");
|
370
|
+
cpAssertSpaceUnlocked(space);
|
371
|
+
|
372
|
+
cpBodyActivate(body);
|
373
|
+
cpBodyRemoveShape(body, shape);
|
374
|
+
cpSpaceFilterArbiters(space, body, shape);
|
375
|
+
cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid);
|
376
|
+
shape->space = NULL;
|
392
377
|
}
|
393
|
-
|
394
|
-
cpBodyActivate(body);
|
395
|
-
|
396
|
-
cpAssertSpaceUnlocked(space);
|
397
|
-
cpAssertWarn(cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
|
398
|
-
"Cannot remove a shape that was not added to the space. (Removed twice maybe?)");
|
399
|
-
|
400
|
-
cpBodyRemoveShape(body, shape);
|
401
|
-
|
402
|
-
removalContext context = {space, shape};
|
403
|
-
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
|
404
|
-
cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
|
405
378
|
}
|
406
379
|
|
407
380
|
void
|
408
381
|
cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
|
409
382
|
{
|
410
|
-
|
411
|
-
"Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)");
|
383
|
+
cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)");
|
412
384
|
cpAssertSpaceUnlocked(space);
|
413
385
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
386
|
+
cpBody *body = shape->body;
|
387
|
+
if(cpBodyIsStatic(body)) cpBodyActivateStatic(body, shape);
|
388
|
+
cpBodyRemoveShape(body, shape);
|
389
|
+
cpSpaceFilterArbiters(space, body, shape);
|
390
|
+
cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid);
|
391
|
+
shape->space = NULL;
|
419
392
|
}
|
420
393
|
|
421
394
|
void
|
422
395
|
cpSpaceRemoveBody(cpSpace *space, cpBody *body)
|
423
396
|
{
|
424
|
-
|
425
|
-
"Cannot remove a body that was not added to the space. (Removed twice maybe?)");
|
397
|
+
cpAssertHard(cpSpaceContainsBody(space, body), "Cannot remove a body that was not added to the space. (Removed twice maybe?)");
|
426
398
|
cpAssertSpaceUnlocked(space);
|
427
399
|
|
428
400
|
cpBodyActivate(body);
|
401
|
+
// cpSpaceFilterArbiters(space, body, NULL);
|
429
402
|
cpArrayDeleteObj(space->bodies, body);
|
430
403
|
body->space = NULL;
|
431
404
|
}
|
@@ -433,67 +406,149 @@ cpSpaceRemoveBody(cpSpace *space, cpBody *body)
|
|
433
406
|
void
|
434
407
|
cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
|
435
408
|
{
|
436
|
-
|
437
|
-
|
438
|
-
// cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback.
|
409
|
+
cpAssertHard(cpSpaceContainsConstraint(space, constraint), "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");
|
410
|
+
cpAssertSpaceUnlocked(space);
|
439
411
|
|
440
412
|
cpBodyActivate(constraint->a);
|
441
413
|
cpBodyActivate(constraint->b);
|
442
414
|
cpArrayDeleteObj(space->constraints, constraint);
|
415
|
+
|
416
|
+
cpBodyRemoveConstraint(constraint->a, constraint);
|
417
|
+
cpBodyRemoveConstraint(constraint->b, constraint);
|
418
|
+
constraint->space = NULL;
|
419
|
+
}
|
420
|
+
|
421
|
+
cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape)
|
422
|
+
{
|
423
|
+
return (shape->space == space);
|
424
|
+
}
|
425
|
+
|
426
|
+
cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body)
|
427
|
+
{
|
428
|
+
return (body->space == space);
|
429
|
+
}
|
430
|
+
|
431
|
+
cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint)
|
432
|
+
{
|
433
|
+
return (constraint->space == space);
|
434
|
+
}
|
435
|
+
|
436
|
+
|
437
|
+
//MARK: Iteration
|
438
|
+
|
439
|
+
void
|
440
|
+
cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data)
|
441
|
+
{
|
442
|
+
cpSpaceLock(space); {
|
443
|
+
cpArray *bodies = space->bodies;
|
444
|
+
|
445
|
+
for(int i=0; i<bodies->num; i++){
|
446
|
+
func((cpBody *)bodies->arr[i], data);
|
447
|
+
}
|
448
|
+
|
449
|
+
cpArray *components = space->sleepingComponents;
|
450
|
+
for(int i=0; i<components->num; i++){
|
451
|
+
cpBody *root = (cpBody *)components->arr[i];
|
452
|
+
|
453
|
+
cpBody *body = root;
|
454
|
+
while(body){
|
455
|
+
cpBody *next = body->node.next;
|
456
|
+
func(body, data);
|
457
|
+
body = next;
|
458
|
+
}
|
459
|
+
}
|
460
|
+
} cpSpaceUnlock(space, cpTrue);
|
443
461
|
}
|
444
462
|
|
445
|
-
|
463
|
+
typedef struct spaceShapeContext {
|
464
|
+
cpSpaceShapeIteratorFunc func;
|
465
|
+
void *data;
|
466
|
+
} spaceShapeContext;
|
446
467
|
|
447
|
-
static void
|
468
|
+
static void
|
469
|
+
spaceEachShapeIterator(cpShape *shape, spaceShapeContext *context)
|
470
|
+
{
|
471
|
+
context->func(shape, context->data);
|
472
|
+
}
|
448
473
|
|
449
474
|
void
|
450
|
-
|
475
|
+
cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data)
|
451
476
|
{
|
452
|
-
|
453
|
-
|
477
|
+
cpSpaceLock(space); {
|
478
|
+
spaceShapeContext context = {func, data};
|
479
|
+
cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)spaceEachShapeIterator, &context);
|
480
|
+
cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)spaceEachShapeIterator, &context);
|
481
|
+
} cpSpaceUnlock(space, cpTrue);
|
454
482
|
}
|
455
483
|
|
456
484
|
void
|
457
|
-
|
485
|
+
cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data)
|
458
486
|
{
|
459
|
-
|
487
|
+
cpSpaceLock(space); {
|
488
|
+
cpArray *constraints = space->constraints;
|
489
|
+
|
490
|
+
for(int i=0; i<constraints->num; i++){
|
491
|
+
func((cpConstraint *)constraints->arr[i], data);
|
492
|
+
}
|
493
|
+
} cpSpaceUnlock(space, cpTrue);
|
494
|
+
}
|
495
|
+
|
496
|
+
//MARK: Spatial Index Management
|
497
|
+
|
498
|
+
static void
|
499
|
+
updateBBCache(cpShape *shape, void *unused)
|
500
|
+
{
|
501
|
+
cpBody *body = shape->body;
|
502
|
+
cpShapeUpdate(shape, body->p, body->rot);
|
460
503
|
}
|
461
504
|
|
462
505
|
void
|
463
|
-
|
506
|
+
cpSpaceReindexStatic(cpSpace *space)
|
464
507
|
{
|
465
|
-
|
466
|
-
|
508
|
+
cpAssertHard(!space->locked, "You cannot manually reindex objects while the space is locked. Wait until the current query or step is complete.");
|
509
|
+
|
510
|
+
cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)&updateBBCache, NULL);
|
511
|
+
cpSpatialIndexReindex(space->staticShapes);
|
467
512
|
}
|
468
513
|
|
469
514
|
void
|
470
|
-
|
515
|
+
cpSpaceReindexShape(cpSpace *space, cpShape *shape)
|
471
516
|
{
|
472
|
-
|
517
|
+
cpAssertHard(!space->locked, "You cannot manually reindex objects while the space is locked. Wait until the current query or step is complete.");
|
518
|
+
|
519
|
+
cpBody *body = shape->body;
|
520
|
+
cpShapeUpdate(shape, body->p, body->rot);
|
473
521
|
|
474
522
|
// attempt to rehash the shape in both hashes
|
475
|
-
|
476
|
-
|
523
|
+
cpSpatialIndexReindexObject(space->activeShapes, shape, shape->hashid);
|
524
|
+
cpSpatialIndexReindexObject(space->staticShapes, shape, shape->hashid);
|
477
525
|
}
|
478
526
|
|
479
527
|
void
|
480
|
-
|
528
|
+
cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body)
|
481
529
|
{
|
482
|
-
|
483
|
-
|
484
|
-
for(int i=0; i<bodies->num; i++){
|
485
|
-
func((cpBody *)bodies->arr[i], data);
|
486
|
-
}
|
487
|
-
|
488
|
-
cpArray *components = space->sleepingComponents;
|
489
|
-
for(int i=0; i<components->num; i++){
|
490
|
-
cpBody *root = (cpBody *)components->arr[i];
|
491
|
-
cpBody *body = root, *next;
|
492
|
-
do {
|
493
|
-
next = body->node.next;
|
494
|
-
func(body, data);
|
495
|
-
} while((body = next) != root);
|
496
|
-
}
|
530
|
+
CP_BODY_FOREACH_SHAPE(body, shape) cpSpaceReindexShape(space, shape);
|
497
531
|
}
|
498
532
|
|
499
533
|
|
534
|
+
static void
|
535
|
+
copyShapes(cpShape *shape, cpSpatialIndex *index)
|
536
|
+
{
|
537
|
+
cpSpatialIndexInsert(index, shape, shape->hashid);
|
538
|
+
}
|
539
|
+
|
540
|
+
void
|
541
|
+
cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count)
|
542
|
+
{
|
543
|
+
cpSpatialIndex *staticShapes = cpSpaceHashNew(dim, count, (cpSpatialIndexBBFunc)cpShapeGetBB, NULL);
|
544
|
+
cpSpatialIndex *activeShapes = cpSpaceHashNew(dim, count, (cpSpatialIndexBBFunc)cpShapeGetBB, staticShapes);
|
545
|
+
|
546
|
+
cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)copyShapes, staticShapes);
|
547
|
+
cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)copyShapes, activeShapes);
|
548
|
+
|
549
|
+
cpSpatialIndexFree(space->staticShapes);
|
550
|
+
cpSpatialIndexFree(space->activeShapes);
|
551
|
+
|
552
|
+
space->staticShapes = staticShapes;
|
553
|
+
space->activeShapes = activeShapes;
|
554
|
+
}
|