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.
Files changed (73) hide show
  1. data/ext/chipmunk/chipmunk.c +199 -28
  2. data/ext/chipmunk/chipmunk.h +123 -68
  3. data/ext/chipmunk/chipmunk_ffi.h +129 -11
  4. data/ext/chipmunk/chipmunk_private.h +232 -16
  5. data/ext/chipmunk/chipmunk_types.h +94 -30
  6. data/ext/chipmunk/chipmunk_unsafe.h +12 -3
  7. data/ext/chipmunk/constraints/cpConstraint.h +90 -34
  8. data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
  9. data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
  10. data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
  11. data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
  12. data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
  13. data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
  14. data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
  15. data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
  16. data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
  17. data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
  18. data/ext/chipmunk/constraints/util.h +36 -44
  19. data/ext/chipmunk/cpArbiter.c +159 -94
  20. data/ext/chipmunk/cpArbiter.h +135 -129
  21. data/ext/chipmunk/cpArray.c +37 -56
  22. data/ext/chipmunk/cpBB.c +1 -12
  23. data/ext/chipmunk/cpBB.h +80 -18
  24. data/ext/chipmunk/cpBBTree.c +891 -0
  25. data/ext/chipmunk/cpBody.c +185 -47
  26. data/ext/chipmunk/cpBody.h +156 -124
  27. data/ext/chipmunk/cpCollision.c +126 -115
  28. data/ext/chipmunk/cpConstraint.c +10 -6
  29. data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
  30. data/ext/chipmunk/cpDampedSpring.c +25 -18
  31. data/ext/chipmunk/cpGearJoint.c +23 -17
  32. data/ext/chipmunk/cpGrooveJoint.c +26 -22
  33. data/ext/chipmunk/cpHashSet.c +51 -51
  34. data/ext/chipmunk/cpPinJoint.c +26 -19
  35. data/ext/chipmunk/cpPivotJoint.c +23 -19
  36. data/ext/chipmunk/cpPolyShape.c +93 -69
  37. data/ext/chipmunk/cpPolyShape.h +33 -69
  38. data/ext/chipmunk/cpRatchetJoint.c +26 -21
  39. data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
  40. data/ext/chipmunk/cpShape.c +122 -133
  41. data/ext/chipmunk/cpShape.h +146 -95
  42. data/ext/chipmunk/cpSimpleMotor.c +24 -17
  43. data/ext/chipmunk/cpSlideJoint.c +28 -26
  44. data/ext/chipmunk/cpSpace.c +251 -196
  45. data/ext/chipmunk/cpSpace.h +173 -103
  46. data/ext/chipmunk/cpSpaceComponent.c +236 -159
  47. data/ext/chipmunk/cpSpaceHash.c +259 -159
  48. data/ext/chipmunk/cpSpaceQuery.c +127 -59
  49. data/ext/chipmunk/cpSpaceStep.c +235 -197
  50. data/ext/chipmunk/cpSpatialIndex.c +69 -0
  51. data/ext/chipmunk/cpSpatialIndex.h +227 -0
  52. data/ext/chipmunk/cpSweep1D.c +254 -0
  53. data/ext/chipmunk/cpVect.c +11 -26
  54. data/ext/chipmunk/cpVect.h +76 -71
  55. data/ext/chipmunk/extconf.rb +4 -31
  56. data/ext/chipmunk/prime.h +1 -1
  57. data/ext/chipmunk/rb_chipmunk.c +36 -45
  58. data/ext/chipmunk/rb_chipmunk.h +6 -3
  59. data/ext/chipmunk/rb_cpArbiter.c +2 -2
  60. data/ext/chipmunk/rb_cpBB.c +116 -35
  61. data/ext/chipmunk/rb_cpBody.c +5 -12
  62. data/ext/chipmunk/rb_cpConstraint.c +144 -9
  63. data/ext/chipmunk/rb_cpShape.c +69 -78
  64. data/ext/chipmunk/rb_cpSpace.c +81 -76
  65. metadata +61 -61
  66. data/LICENSE +0 -22
  67. data/README +0 -110
  68. data/Rakefile +0 -102
  69. data/ext/chipmunk/cpArray.h +0 -49
  70. data/ext/chipmunk/cpCollision.h +0 -28
  71. data/ext/chipmunk/cpHashSet.h +0 -82
  72. data/ext/chipmunk/cpSpaceHash.h +0 -110
  73. data/lib/chipmunk.rb +0 -194
@@ -19,20 +19,16 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
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
- cpTimestamp cp_contact_persistence = 3;
27
+ //MARK: Contact Set Helpers
30
28
 
31
- #pragma mark Contact Set Helpers
32
-
33
- // Equal function for contactSet.
29
+ // Equal function for arbiterSet.
34
30
  static cpBool
35
- contactSetEql(cpShape **shapes, cpArbiter *arb)
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
- // Transformation function for contactSet.
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 collFuncSet.
41
+ // Equals function for collisionHandlers.
64
42
  static cpBool
65
- collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
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 collFuncSet.
48
+ // Transformation function for collisionHandlers.
71
49
  static void *
72
- collFuncSetTrans(cpCollisionHandler *handler, void *unused)
50
+ handlerSetTrans(cpCollisionHandler *handler, void *unused)
73
51
  {
74
- cpCollisionHandler *copy = (cpCollisionHandler *)cpmalloc(sizeof(cpCollisionHandler));
52
+ cpCollisionHandler *copy = (cpCollisionHandler *)cpcalloc(1, sizeof(cpCollisionHandler));
75
53
  (*copy) = (*handler);
76
54
 
77
55
  return copy;
78
56
  }
79
57
 
80
- #pragma mark Misc Helper Funcs
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
- // BBfunc callback for the spatial hash.
87
- static cpBB shapeBBFunc(cpShape *shape){return shape->bb;}
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
- // Iterator functions for destructors.
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
- #pragma mark Memory Management Functions
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
- #define DEFAULT_DIM_SIZE 100.0f
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
- space->iterations = DEFAULT_ITERATIONS;
114
- space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;
115
- // space->sleepTicks = 300;
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 = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
124
- space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
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->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);
121
+ space->cachedArbiters = cpHashSetNew(0, (cpHashSetEqlFunc)arbiterSetEql);
140
122
 
141
123
  space->constraints = cpArrayNew(0);
142
124
 
143
- space->defaultHandler = defaultHandler;
144
- space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);
145
- space->collFuncSet->default_value = &space->defaultHandler;
125
+ space->defaultHandler = cpDefaultCollisionHandler;
126
+ space->collisionHandlers = cpHashSetNew(0, (cpHashSetEqlFunc)handlerSetEql);
127
+ cpHashSetSetDefaultValue(space->collisionHandlers, &cpDefaultCollisionHandler);
146
128
 
147
- space->postStepCallbacks = NULL;
129
+ space->postStepCallbacks = cpArrayNew(0);
130
+ space->skipPostStep = cpFalse;
148
131
 
149
- cpBodyInitStatic(&space->staticBody);
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
- cpSpaceHashFree(space->staticShapes);
164
- cpSpaceHashFree(space->activeShapes);
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->contactSet);
158
+ cpHashSetFree(space->cachedArbiters);
173
159
 
174
160
  cpArrayFree(space->arbiters);
175
161
  cpArrayFree(space->pooledArbiters);
176
162
 
177
163
  if(space->allocatedBuffers){
178
- cpArrayEach(space->allocatedBuffers, freeWrap, NULL);
164
+ cpArrayFreeEach(space->allocatedBuffers, cpfree);
179
165
  cpArrayFree(space->allocatedBuffers);
180
166
  }
181
167
 
182
168
  if(space->postStepCallbacks){
183
- cpHashSetEach(space->postStepCallbacks, freeWrap, NULL);
184
- cpHashSetFree(space->postStepCallbacks);
169
+ cpArrayFreeEach(space->postStepCallbacks, cpfree);
170
+ cpArrayFree(space->postStepCallbacks);
185
171
  }
186
172
 
187
- if(space->collFuncSet){
188
- cpHashSetEach(space->collFuncSet, freeWrap, NULL);
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
- void
203
- cpSpaceFreeChildren(cpSpace *space)
204
- {
205
- cpArray *components = space->sleepingComponents;
206
- while(components->num) cpBodyActivate((cpBody *)components->arr[0]);
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
- #pragma mark Collision Handler Function Management
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->collFuncSet, CP_HASH_PAIR(a, b), &handler, NULL);
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
- struct{cpCollisionType a, b;} ids = {a, b};
245
- cpCollisionHandler *old_handler = (cpCollisionHandler *) cpHashSetRemove(space->collFuncSet, CP_HASH_PAIR(a, b), &ids);
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
- #pragma mark Body, Shape, and Joint Management
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(!body || cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape);
260
+ if(cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape);
305
261
 
306
- cpAssert(!cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
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
- cpShapeCacheBB(shape);
314
- cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
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
- cpAssert(!cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
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
- if(!shape->body) shape->body = &space->staticBody;
327
-
328
- cpShapeCacheBB(shape);
329
- cpSpaceActivateShapesTouchingShape(space, shape);
330
- cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
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
- cpAssertWarn(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated.");
339
- cpAssert(!body->space, "Cannot add a body to a more than one space or to the same space twice.");
340
- // cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback
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
- cpAssert(!cpArrayContains(space->constraints, constraint), "Cannot add the same constraint more than once.");
352
- // cpAssertSpaceUnlocked(space); This should be safe as long as its not from a constraint callback.
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
- typedef struct removalContext {
322
+ struct arbiterFilterContext {
365
323
  cpSpace *space;
324
+ cpBody *body;
366
325
  cpShape *shape;
367
- } removalContext;
326
+ };
368
327
 
369
- // Hashset filter func to throw away old arbiters.
370
328
  static cpBool
371
- contactSetFilterRemovedShape(cpArbiter *arb, removalContext *context)
329
+ cachedArbitersFilter(cpArbiter *arb, struct arbiterFilterContext *context)
372
330
  {
373
- if(context->shape == arb->a || context->shape == arb->b){
374
- if(arb->state != cpArbiterStateCached){
375
- arb->handler->separate(arb, context->space, arb->handler->data);
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
- return;
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
- cpAssertWarn(cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
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
- removalContext context = {space, shape};
415
- cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
416
- cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
417
-
418
- cpSpaceActivateShapesTouchingShape(space, shape);
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
- cpAssertWarn(body->space == space,
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
- cpAssertWarn(cpArrayContains(space->constraints, constraint),
437
- "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");
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
- #pragma mark Spatial Hash Management
463
+ typedef struct spaceShapeContext {
464
+ cpSpaceShapeIteratorFunc func;
465
+ void *data;
466
+ } spaceShapeContext;
446
467
 
447
- static void updateBBCache(cpShape *shape, void *unused){cpShapeCacheBB(shape);}
468
+ static void
469
+ spaceEachShapeIterator(cpShape *shape, spaceShapeContext *context)
470
+ {
471
+ context->func(shape, context->data);
472
+ }
448
473
 
449
474
  void
450
- cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
475
+ cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data)
451
476
  {
452
- cpSpaceHashResize(space->staticShapes, dim, count);
453
- cpSpaceHashRehash(space->staticShapes);
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
- cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)
485
+ cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data)
458
486
  {
459
- cpSpaceHashResize(space->activeShapes, dim, count);
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
- cpSpaceRehashStatic(cpSpace *space)
506
+ cpSpaceReindexStatic(cpSpace *space)
464
507
  {
465
- cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&updateBBCache, NULL);
466
- cpSpaceHashRehash(space->staticShapes);
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
- cpSpaceRehashShape(cpSpace *space, cpShape *shape)
515
+ cpSpaceReindexShape(cpSpace *space, cpShape *shape)
471
516
  {
472
- cpShapeCacheBB(shape);
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
- cpSpaceHashRehashObject(space->activeShapes, shape, shape->hashid);
476
- cpSpaceHashRehashObject(space->staticShapes, shape, shape->hashid);
523
+ cpSpatialIndexReindexObject(space->activeShapes, shape, shape->hashid);
524
+ cpSpatialIndexReindexObject(space->staticShapes, shape, shape->hashid);
477
525
  }
478
526
 
479
527
  void
480
- cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
528
+ cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body)
481
529
  {
482
- cpArray *bodies = space->bodies;
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
+ }