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.
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
+ }