chipmunk 5.3.4.5 → 6.1.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|