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,25 +19,24 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
23
-
24
22
  #include "chipmunk_private.h"
25
23
 
26
- #pragma mark Point Query Functions
24
+ //MARK: Point Query Functions
27
25
 
28
- typedef struct pointQueryContext {
26
+ struct PointQueryContext {
27
+ cpVect point;
29
28
  cpLayers layers;
30
29
  cpGroup group;
31
30
  cpSpacePointQueryFunc func;
32
31
  void *data;
33
- } pointQueryContext;
32
+ };
34
33
 
35
34
  static void
36
- pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
35
+ PointQuery(struct PointQueryContext *context, cpShape *shape, void *data)
37
36
  {
38
37
  if(
39
38
  !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
40
- cpShapePointQuery(shape, *point)
39
+ cpShapePointQuery(shape, context->point)
41
40
  ){
42
41
  context->func(shape, context->data);
43
42
  }
@@ -46,16 +45,17 @@ pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
46
45
  void
47
46
  cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)
48
47
  {
49
- pointQueryContext context = {layers, group, func, data};
48
+ struct PointQueryContext context = {point, layers, group, func, data};
49
+ cpBB bb = cpBBNewForCircle(point, 0.0f);
50
50
 
51
51
  cpSpaceLock(space); {
52
- cpSpaceHashPointQuery(space->activeShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
53
- cpSpaceHashPointQuery(space->staticShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
54
- } cpSpaceUnlock(space);
52
+ cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)PointQuery, data);
53
+ cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)PointQuery, data);
54
+ } cpSpaceUnlock(space, cpTrue);
55
55
  }
56
56
 
57
57
  static void
58
- rememberLastPointQuery(cpShape *shape, cpShape **outShape)
58
+ PointQueryFirst(cpShape *shape, cpShape **outShape)
59
59
  {
60
60
  if(!shape->sensor) *outShape = shape;
61
61
  }
@@ -64,23 +64,94 @@ cpShape *
64
64
  cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)
65
65
  {
66
66
  cpShape *shape = NULL;
67
- cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)rememberLastPointQuery, &shape);
67
+ cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)PointQueryFirst, &shape);
68
68
 
69
69
  return shape;
70
70
  }
71
71
 
72
+ //MARK: Nearest Point Query Functions
73
+
74
+ struct NearestPointQueryContext {
75
+ cpVect point;
76
+ cpFloat maxDistance;
77
+ cpLayers layers;
78
+ cpGroup group;
79
+ cpSpaceNearestPointQueryFunc func;
80
+ };
81
+
82
+ static void
83
+ NearestPointQuery(struct NearestPointQueryContext *context, cpShape *shape, void *data)
84
+ {
85
+ if(
86
+ !(shape->group && context->group == shape->group) && (context->layers&shape->layers)
87
+ ){
88
+ cpNearestPointQueryInfo info;
89
+ cpShapeNearestPointQuery(shape, context->point, &info);
90
+
91
+ if(info.shape && info.d < context->maxDistance) context->func(shape, info.d, info.p, data);
92
+ }
93
+ }
94
+
95
+ void
96
+ cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data)
97
+ {
98
+ struct NearestPointQueryContext context = {point, maxDistance, layers, group, func};
99
+ cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
100
+
101
+ cpSpaceLock(space); {
102
+ cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
103
+ cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
104
+ } cpSpaceUnlock(space, cpTrue);
105
+ }
106
+
107
+ static void
108
+ NearestPointQueryNearest(struct NearestPointQueryContext *context, cpShape *shape, cpNearestPointQueryInfo *out)
109
+ {
110
+ if(
111
+ !(shape->group && context->group == shape->group) && (context->layers&shape->layers) && !shape->sensor
112
+ ){
113
+ cpNearestPointQueryInfo info;
114
+ cpShapeNearestPointQuery(shape, context->point, &info);
115
+
116
+ if(info.d < out->d) (*out) = info;
117
+ }
118
+ }
119
+
120
+ cpShape *
121
+ cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out)
122
+ {
123
+ cpNearestPointQueryInfo info = {NULL, cpvzero, maxDistance};
124
+ if(out){
125
+ (*out) = info;
126
+ } else {
127
+ out = &info;
128
+ }
129
+
130
+ struct NearestPointQueryContext context = {
131
+ point, maxDistance,
132
+ layers, group,
133
+ NULL
134
+ };
135
+
136
+ cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
137
+ cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
138
+ cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
139
+
140
+ return out->shape;
141
+ }
142
+
72
143
 
73
- #pragma mark Segment Query Functions
144
+ //MARK: Segment Query Functions
74
145
 
75
- typedef struct segQueryContext {
146
+ struct SegmentQueryContext {
76
147
  cpVect start, end;
77
148
  cpLayers layers;
78
149
  cpGroup group;
79
150
  cpSpaceSegmentQueryFunc func;
80
- } segQueryContext;
151
+ };
81
152
 
82
153
  static cpFloat
83
- segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
154
+ SegmentQuery(struct SegmentQueryContext *context, cpShape *shape, void *data)
84
155
  {
85
156
  cpSegmentQueryInfo info;
86
157
 
@@ -97,37 +168,30 @@ segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
97
168
  void
98
169
  cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
99
170
  {
100
- segQueryContext context = {
171
+ struct SegmentQueryContext context = {
101
172
  start, end,
102
173
  layers, group,
103
174
  func,
104
175
  };
105
176
 
106
177
  cpSpaceLock(space); {
107
- cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFunc, data);
108
- cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFunc, data);
109
- } cpSpaceUnlock(space);
178
+ cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
179
+ cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
180
+ } cpSpaceUnlock(space, cpTrue);
110
181
  }
111
182
 
112
- typedef struct segQueryFirstContext {
113
- cpVect start, end;
114
- cpLayers layers;
115
- cpGroup group;
116
- } segQueryFirstContext;
117
-
118
183
  static cpFloat
119
- segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo *out)
184
+ SegmentQueryFirst(struct SegmentQueryContext *context, cpShape *shape, cpSegmentQueryInfo *out)
120
185
  {
121
186
  cpSegmentQueryInfo info;
122
187
 
123
188
  if(
124
- !(shape->group && context->group == shape->group) &&
125
- (context->layers&shape->layers) &&
189
+ !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
126
190
  !shape->sensor &&
127
191
  cpShapeSegmentQuery(shape, context->start, context->end, &info) &&
128
192
  info.t < out->t
129
193
  ){
130
- *out = info;
194
+ (*out) = info;
131
195
  }
132
196
 
133
197
  return out->t;
@@ -143,65 +207,66 @@ cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers laye
143
207
  out = &info;
144
208
  }
145
209
 
146
- segQueryFirstContext context = {
210
+ struct SegmentQueryContext context = {
147
211
  start, end,
148
- layers, group
212
+ layers, group,
213
+ NULL
149
214
  };
150
215
 
151
- cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
152
- cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
216
+ cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
217
+ cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
153
218
 
154
219
  return out->shape;
155
220
  }
156
221
 
157
- #pragma mark BB Query Functions
222
+ //MARK: BB Query Functions
158
223
 
159
- typedef struct bbQueryContext {
224
+ struct BBQueryContext {
225
+ cpBB bb;
160
226
  cpLayers layers;
161
227
  cpGroup group;
162
228
  cpSpaceBBQueryFunc func;
163
- void *data;
164
- } bbQueryContext;
229
+ };
165
230
 
166
231
  static void
167
- bbQueryHelper(cpBB *bb, cpShape *shape, bbQueryContext *context)
232
+ BBQuery(struct BBQueryContext *context, cpShape *shape, void *data)
168
233
  {
169
234
  if(
170
235
  !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
171
- cpBBintersects(*bb, shape->bb)
236
+ cpBBIntersects(context->bb, shape->bb)
172
237
  ){
173
- context->func(shape, context->data);
238
+ context->func(shape, data);
174
239
  }
175
240
  }
176
241
 
177
242
  void
178
243
  cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data)
179
244
  {
180
- bbQueryContext context = {layers, group, func, data};
245
+ struct BBQueryContext context = {bb, layers, group, func};
181
246
 
182
247
  cpSpaceLock(space); {
183
- cpSpaceHashQuery(space->activeShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
184
- cpSpaceHashQuery(space->staticShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
185
- } cpSpaceUnlock(space);
248
+ cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
249
+ cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
250
+ } cpSpaceUnlock(space, cpTrue);
186
251
  }
187
252
 
188
- #pragma mark Shape Query Functions
253
+ //MARK: Shape Query Functions
189
254
 
190
- typedef struct shapeQueryContext {
255
+ struct ShapeQueryContext {
191
256
  cpSpaceShapeQueryFunc func;
192
257
  void *data;
193
258
  cpBool anyCollision;
194
- } shapeQueryContext;
259
+ };
195
260
 
196
261
  // Callback from the spatial hash.
197
262
  static void
198
- shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
263
+ ShapeQuery(cpShape *a, cpShape *b, struct ShapeQueryContext *context)
199
264
  {
200
265
  // Reject any of the simple cases
201
266
  if(
202
267
  (a->group && a->group == b->group) ||
203
268
  !(a->layers & b->layers) ||
204
- a->sensor || b->sensor
269
+ a == b
205
270
  ) return;
206
271
 
207
272
  cpContact contacts[CP_MAX_CONTACTS_PER_ARBITER];
@@ -216,13 +281,15 @@ shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
216
281
  }
217
282
 
218
283
  if(numContacts){
219
- context->anyCollision = cpTrue;
284
+ context->anyCollision = !(a->sensor || b->sensor);
220
285
 
221
286
  if(context->func){
222
- cpContactPointSet set = {numContacts, {}};
287
+ cpContactPointSet set;
288
+ set.count = numContacts;
289
+
223
290
  for(int i=0; i<set.count; i++){
224
291
  set.points[i].point = contacts[i].p;
225
- set.points[i].normal = contacts[i].p;
292
+ set.points[i].normal = contacts[i].n;
226
293
  set.points[i].dist = contacts[i].dist;
227
294
  }
228
295
 
@@ -234,13 +301,14 @@ shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
234
301
  cpBool
235
302
  cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data)
236
303
  {
237
- cpBB bb = cpShapeCacheBB(shape);
238
- shapeQueryContext context = {func, data, cpFalse};
304
+ cpBody *body = shape->body;
305
+ cpBB bb = (body ? cpShapeUpdate(shape, body->p, body->rot) : shape->bb);
306
+ struct ShapeQueryContext context = {func, data, cpFalse};
239
307
 
240
308
  cpSpaceLock(space); {
241
- cpSpaceHashQuery(space->activeShapes, shape, bb, (cpSpaceHashQueryFunc)shapeQueryHelper, &context);
242
- cpSpaceHashQuery(space->staticShapes, shape, bb, (cpSpaceHashQueryFunc)shapeQueryHelper, &context);
243
- } cpSpaceUnlock(space);
309
+ cpSpatialIndexQuery(space->activeShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
310
+ cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
311
+ } cpSpaceUnlock(space, cpTrue);
244
312
 
245
313
  return context.anyCollision;
246
314
  }
@@ -19,58 +19,98 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
23
- //#include <stdio.h>
24
- #include <math.h>
25
-
26
22
  #include "chipmunk_private.h"
27
23
 
28
- #pragma mark Post Step Callback Functions
29
-
30
- typedef struct PostStepCallback {
31
- cpPostStepFunc func;
32
- void *obj;
33
- void *data;
34
- } PostStepCallback;
24
+ //MARK: Post Step Callback Functions
35
25
 
36
- static cpBool
37
- postStepFuncSetEql(PostStepCallback *a, PostStepCallback *b){
38
- return a->obj == b->obj;
26
+ cpPostStepCallback *
27
+ cpSpaceGetPostStepCallback(cpSpace *space, void *key)
28
+ {
29
+ cpArray *arr = space->postStepCallbacks;
30
+ for(int i=0; i<arr->num; i++){
31
+ cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
32
+ if(callback && callback->key == key) return callback;
33
+ }
34
+
35
+ return NULL;
39
36
  }
40
37
 
41
- static void *
42
- postStepFuncSetTrans(PostStepCallback *callback, void *ignored)
38
+ static void PostStepDoNothing(cpSpace *space, void *obj, void *data){}
39
+
40
+ cpBool
41
+ cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data)
43
42
  {
44
- PostStepCallback *value = (PostStepCallback *)cpmalloc(sizeof(PostStepCallback));
45
- (*value) = (*callback);
46
-
47
- return value;
43
+ cpAssertWarn(space->locked,
44
+ "Adding a post-step callback when the space is not locked is unnecessary. "
45
+ "Post-step callbacks will not called until the end of the next call to cpSpaceStep() or the next query.");
46
+
47
+ if(!cpSpaceGetPostStepCallback(space, key)){
48
+ cpPostStepCallback *callback = (cpPostStepCallback *)cpcalloc(1, sizeof(cpPostStepCallback));
49
+ callback->func = (func ? func : PostStepDoNothing);
50
+ callback->key = key;
51
+ callback->data = data;
52
+
53
+ cpArrayPush(space->postStepCallbacks, callback);
54
+ return cpTrue;
55
+ } else {
56
+ return cpFalse;
57
+ }
48
58
  }
49
59
 
60
+ //MARK: Locking Functions
61
+
50
62
  void
51
- cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data)
63
+ cpSpaceLock(cpSpace *space)
52
64
  {
53
- if(!space->postStepCallbacks){
54
- space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql, (cpHashSetTransFunc)postStepFuncSetTrans);
55
- }
56
-
57
- PostStepCallback callback = {func, obj, data};
58
- cpHashSetInsert(space->postStepCallbacks, (cpHashValue)(size_t)obj, &callback, NULL);
65
+ space->locked++;
59
66
  }
60
67
 
61
- void *
62
- cpSpaceGetPostStepData(cpSpace *space, void *obj)
68
+ void
69
+ cpSpaceUnlock(cpSpace *space, cpBool runPostStep)
63
70
  {
64
- if(space->postStepCallbacks){
65
- PostStepCallback query = {NULL, obj, NULL};
66
- PostStepCallback *callback = (PostStepCallback *)cpHashSetFind(space->postStepCallbacks, (cpHashValue)(size_t)obj, &query);
67
- return (callback ? callback->data : NULL);
68
- } else {
69
- return NULL;
71
+ space->locked--;
72
+ cpAssertHard(space->locked >= 0, "Internal Error: Space lock underflow.");
73
+
74
+ if(space->locked == 0){
75
+ cpArray *waking = space->rousedBodies;
76
+
77
+ for(int i=0, count=waking->num; i<count; i++){
78
+ cpSpaceActivateBody(space, (cpBody *)waking->arr[i]);
79
+ waking->arr[i] = NULL;
80
+ }
81
+
82
+ waking->num = 0;
83
+
84
+ if(space->locked == 0 && runPostStep && !space->skipPostStep){
85
+ space->skipPostStep = cpTrue;
86
+
87
+ cpArray *arr = space->postStepCallbacks;
88
+ for(int i=0; i<arr->num; i++){
89
+ cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
90
+ cpPostStepFunc func = callback->func;
91
+
92
+ // Mark the func as NULL in case calling it calls cpSpaceRunPostStepCallbacks() again.
93
+ // TODO need more tests around this case I think.
94
+ callback->func = NULL;
95
+ if(func) func(space, callback->key, callback->data);
96
+
97
+ arr->arr[i] = NULL;
98
+ cpfree(callback);
99
+ }
100
+
101
+ arr->num = 0;
102
+ space->skipPostStep = cpFalse;
103
+ }
70
104
  }
71
105
  }
72
106
 
73
- #pragma mark Contact Buffer Functions
107
+ //MARK: Contact Buffer Functions
108
+
109
+ struct cpContactBufferHeader {
110
+ cpTimestamp stamp;
111
+ cpContactBufferHeader *next;
112
+ unsigned int numContacts;
113
+ };
74
114
 
75
115
  #define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(cpContact))
76
116
  typedef struct cpContactBuffer {
@@ -81,7 +121,7 @@ typedef struct cpContactBuffer {
81
121
  static cpContactBufferHeader *
82
122
  cpSpaceAllocContactBuffer(cpSpace *space)
83
123
  {
84
- cpContactBuffer *buffer = (cpContactBuffer *)cpmalloc(sizeof(cpContactBuffer));
124
+ cpContactBuffer *buffer = (cpContactBuffer *)cpcalloc(1, sizeof(cpContactBuffer));
85
125
  cpArrayPush(space->allocatedBuffers, buffer);
86
126
  return (cpContactBufferHeader *)buffer;
87
127
  }
@@ -96,7 +136,7 @@ cpContactBufferHeaderInit(cpContactBufferHeader *header, cpTimestamp stamp, cpCo
96
136
  return header;
97
137
  }
98
138
 
99
- static void
139
+ void
100
140
  cpSpacePushFreshContactBuffer(cpSpace *space)
101
141
  {
102
142
  cpTimestamp stamp = space->stamp;
@@ -106,7 +146,7 @@ cpSpacePushFreshContactBuffer(cpSpace *space)
106
146
  if(!head){
107
147
  // No buffers have been allocated, make one
108
148
  space->contactBuffersHead = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, NULL);
109
- } else if(stamp - head->next->stamp > cp_contact_persistence){
149
+ } else if(stamp - head->next->stamp > space->collisionPersistence){
110
150
  // The tail buffer is available, rotate the ring
111
151
  cpContactBufferHeader *tail = head->next;
112
152
  space->contactBuffersHead = cpContactBufferHeaderInit(tail, stamp, tail);
@@ -118,7 +158,7 @@ cpSpacePushFreshContactBuffer(cpSpace *space)
118
158
  }
119
159
 
120
160
 
121
- static cpContact *
161
+ cpContact *
122
162
  cpContactBufferGetArray(cpSpace *space)
123
163
  {
124
164
  if(space->contactBuffersHead->numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){
@@ -130,47 +170,65 @@ cpContactBufferGetArray(cpSpace *space)
130
170
  return ((cpContactBuffer *)head)->contacts + head->numContacts;
131
171
  }
132
172
 
133
- static inline void
134
- cpSpacePushContacts(cpSpace *space, int count){
135
- cpAssert(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal error, too many contact point overflow!");
173
+ void
174
+ cpSpacePushContacts(cpSpace *space, int count)
175
+ {
176
+ cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!");
136
177
  space->contactBuffersHead->numContacts += count;
137
178
  }
138
179
 
139
- static inline void
180
+ static void
140
181
  cpSpacePopContacts(cpSpace *space, int count){
141
182
  space->contactBuffersHead->numContacts -= count;
142
183
  }
143
184
 
144
- #pragma mark Collision Detection Functions
185
+ //MARK: Collision Detection Functions
186
+
187
+ static void *
188
+ cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space)
189
+ {
190
+ if(space->pooledArbiters->num == 0){
191
+ // arbiter pool is exhausted, make more
192
+ int count = CP_BUFFER_BYTES/sizeof(cpArbiter);
193
+ cpAssertHard(count, "Internal Error: Buffer size too small.");
194
+
195
+ cpArbiter *buffer = (cpArbiter *)cpcalloc(1, CP_BUFFER_BYTES);
196
+ cpArrayPush(space->allocatedBuffers, buffer);
197
+
198
+ for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);
199
+ }
200
+
201
+ return cpArbiterInit((cpArbiter *)cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);
202
+ }
145
203
 
146
204
  static inline cpBool
147
205
  queryReject(cpShape *a, cpShape *b)
148
206
  {
149
- return
207
+ return (
150
208
  // BBoxes must overlap
151
- !cpBBintersects(a->bb, b->bb)
209
+ !cpBBIntersects(a->bb, b->bb)
152
210
  // Don't collide shapes attached to the same body.
153
211
  || a->body == b->body
154
212
  // Don't collide objects in the same non-zero group
155
213
  || (a->group && a->group == b->group)
156
214
  // Don't collide objects that don't share at least on layer.
157
- || !(a->layers & b->layers);
215
+ || !(a->layers & b->layers)
216
+ // Don't collide infinite mass objects
217
+ || (a->body->m == INFINITY && b->body->m == INFINITY)
218
+ );
158
219
  }
159
220
 
160
221
  // Callback from the spatial hash.
161
- static void
162
- queryFunc(cpShape *a, cpShape *b, cpSpace *space)
222
+ void
223
+ cpSpaceCollideShapes(cpShape *a, cpShape *b, cpSpace *space)
163
224
  {
164
225
  // Reject any of the simple cases
165
226
  if(queryReject(a,b)) return;
166
227
 
167
- // Find the collision pair function for the shapes.
168
- struct{cpCollisionType a, b;} ids = {a->collision_type, b->collision_type};
169
- cpHashValue collHashID = CP_HASH_PAIR(a->collision_type, b->collision_type);
170
- cpCollisionHandler *handler = (cpCollisionHandler *)cpHashSetFind(space->collFuncSet, collHashID, &ids);
228
+ cpCollisionHandler *handler = cpSpaceLookupHandler(space, a->collision_type, b->collision_type);
171
229
 
172
230
  cpBool sensor = a->sensor || b->sensor;
173
- if(sensor && handler == &space->defaultHandler) return;
231
+ if(sensor && handler == &cpDefaultCollisionHandler) return;
174
232
 
175
233
  // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
176
234
  if(a->klass->type > b->klass->type){
@@ -185,11 +243,11 @@ queryFunc(cpShape *a, cpShape *b, cpSpace *space)
185
243
  if(!numContacts) return; // Shapes are not colliding.
186
244
  cpSpacePushContacts(space, numContacts);
187
245
 
188
- // Get an arbiter from space->contactSet for the two shapes.
246
+ // Get an arbiter from space->arbiterSet for the two shapes.
189
247
  // This is where the persistant contact magic comes from.
190
248
  cpShape *shape_pair[] = {a, b};
191
- cpHashValue arbHashID = CP_HASH_PAIR((size_t)a, (size_t)b);
192
- cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->contactSet, arbHashID, shape_pair, space);
249
+ cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);
250
+ cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, space, (cpHashSetTransFunc)cpSpaceArbiterSetTrans);
193
251
  cpArbiterUpdate(arb, contacts, numContacts, handler, a, b);
194
252
 
195
253
  // Call the begin function first if it's the first step
@@ -212,8 +270,8 @@ queryFunc(cpShape *a, cpShape *b, cpSpace *space)
212
270
  arb->contacts = NULL;
213
271
  arb->numContacts = 0;
214
272
 
215
- // Normally arbiters are set as used after calling the post-step callback.
216
- // However, post-step callbacks are not called for sensors or arbiters rejected from pre-solve.
273
+ // Normally arbiters are set as used after calling the post-solve callback.
274
+ // However, post-solve callbacks are not called for sensors or arbiters rejected from pre-solve.
217
275
  if(arb->state != cpArbiterStateIgnore) arb->state = cpArbiterStateNormal;
218
276
  }
219
277
 
@@ -221,45 +279,31 @@ queryFunc(cpShape *a, cpShape *b, cpSpace *space)
221
279
  arb->stamp = space->stamp;
222
280
  }
223
281
 
224
- // Iterator for active/static hash collisions.
225
- static void
226
- active2staticIter(cpShape *shape, cpSpace *space)
227
- {
228
- cpSpaceHashQuery(space->staticShapes, shape, shape->bb, (cpSpaceHashQueryFunc)queryFunc, space);
229
- }
230
-
231
282
  // Hashset filter func to throw away old arbiters.
232
- static cpBool
233
- contactSetFilter(cpArbiter *arb, cpSpace *space)
283
+ cpBool
284
+ cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space)
234
285
  {
235
- if(space->sleepTimeThreshold != INFINITY){
236
- cpBody *a = arb->a->body;
237
- cpBody *b = arb->b->body;
238
-
239
- // both bodies are either static or sleeping
240
- cpBool sleepingNow =
241
- (cpBodyIsStatic(a) || cpBodyIsSleeping(a)) &&
242
- (cpBodyIsStatic(b) || cpBodyIsSleeping(b));
243
-
244
- if(sleepingNow){
245
- arb->state = cpArbiterStateSleep;
246
- return cpTrue;
247
- } else if(arb->state == cpArbiterStateSleep){
248
- // wake up the arbiter and continue as normal
249
- arb->state = cpArbiterStateNormal;
250
- // TODO is it possible that cpArbiterStateIgnore should be set here instead?
251
- }
252
- }
253
-
254
286
  cpTimestamp ticks = space->stamp - arb->stamp;
255
287
 
256
- // was used last frame, but not this one
288
+ cpBody *a = arb->body_a, *b = arb->body_b;
289
+
290
+ // TODO should make an arbiter state for this so it doesn't require filtering arbiters for dangling body pointers on body removal.
291
+ // Preserve arbiters on sensors and rejected arbiters for sleeping objects.
292
+ // This prevents errant separate callbacks from happenening.
293
+ if(
294
+ (cpBodyIsStatic(a) || cpBodyIsSleeping(a)) &&
295
+ (cpBodyIsStatic(b) || cpBodyIsSleeping(b))
296
+ ){
297
+ return cpTrue;
298
+ }
299
+
300
+ // Arbiter was used last frame, but not this one
257
301
  if(ticks >= 1 && arb->state != cpArbiterStateCached){
258
- arb->handler->separate(arb, space, arb->handler->data);
259
302
  arb->state = cpArbiterStateCached;
303
+ cpArbiterCallSeparate(arb, space);
260
304
  }
261
305
 
262
- if(ticks >= cp_contact_persistence){
306
+ if(ticks >= space->collisionPersistence){
263
307
  arb->contacts = NULL;
264
308
  arb->numContacts = 0;
265
309
 
@@ -270,129 +314,123 @@ contactSetFilter(cpArbiter *arb, cpSpace *space)
270
314
  return cpTrue;
271
315
  }
272
316
 
273
- // Hashset filter func to call and throw away post step callbacks.
274
- static void
275
- postStepCallbackSetIter(PostStepCallback *callback, cpSpace *space)
317
+ //MARK: All Important cpSpaceStep() Function
318
+
319
+ void
320
+ cpShapeUpdateFunc(cpShape *shape, void *unused)
276
321
  {
277
- callback->func(space, callback->obj, callback->data);
278
- cpfree(callback);
322
+ cpBody *body = shape->body;
323
+ cpShapeUpdate(shape, body->p, body->rot);
279
324
  }
280
325
 
281
- #pragma mark All Important cpSpaceStep() Function
282
-
283
- void cpSpaceProcessComponents(cpSpace *space, cpFloat dt);
284
-
285
- static void updateBBCache(cpShape *shape, void *unused){cpShapeCacheBB(shape);}
286
-
287
326
  void
288
327
  cpSpaceStep(cpSpace *space, cpFloat dt)
289
328
  {
290
- if(!dt) return; // don't step if the timestep is 0!
291
- cpFloat dt_inv = 1.0f/dt;
292
-
293
- cpArray *bodies = space->bodies;
294
- cpArray *constraints = space->constraints;
295
-
296
- // Empty the arbiter list.
297
- space->arbiters->num = 0;
298
-
299
- // Integrate positions.
300
- for(int i=0; i<bodies->num; i++){
301
- cpBody *body = (cpBody *)bodies->arr[i];
302
- body->position_func(body, dt);
303
- }
304
-
305
- // Pre-cache BBoxes and shape data.
306
- cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)updateBBCache, NULL);
307
-
308
- cpSpaceLock(space);
309
-
310
- // Collide!
311
- cpSpacePushFreshContactBuffer(space);
312
- if(space->staticShapes->handleSet->entries)
313
- cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)active2staticIter, space);
314
- cpSpaceHashQueryRehash(space->activeShapes, (cpSpaceHashQueryFunc)queryFunc, space);
315
-
316
- cpSpaceUnlock(space);
329
+ // don't step if the timestep is 0!
330
+ if(dt == 0.0f) return;
317
331
 
318
- // If body sleeping is enabled, do that now.
319
- if(space->sleepTimeThreshold != INFINITY){
320
- cpSpaceProcessComponents(space, dt);
321
- bodies = space->bodies; // rebuilt by processContactComponents()
322
- }
332
+ space->stamp++;
323
333
 
324
- // Clear out old cached arbiters and dispatch untouch functions
325
- cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilter, space);
326
-
327
- // Prestep the arbiters.
334
+ cpFloat prev_dt = space->curr_dt;
335
+ space->curr_dt = dt;
336
+
337
+ cpArray *bodies = space->bodies;
338
+ cpArray *constraints = space->constraints;
328
339
  cpArray *arbiters = space->arbiters;
329
- for(int i=0; i<arbiters->num; i++)
330
- cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt_inv);
331
-
332
- // Prestep the constraints.
333
- for(int i=0; i<constraints->num; i++){
334
- cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
335
- constraint->klass->preStep(constraint, dt, dt_inv);
336
- }
337
-
338
- for(int i=0; i<space->elasticIterations; i++){
339
- for(int j=0; j<arbiters->num; j++)
340
- cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 1.0f);
341
-
342
- for(int j=0; j<constraints->num; j++){
343
- cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
344
- constraint->klass->applyImpulse(constraint);
340
+
341
+ // Reset and empty the arbiter lists.
342
+ for(int i=0; i<arbiters->num; i++){
343
+ cpArbiter *arb = (cpArbiter *)arbiters->arr[i];
344
+ arb->state = cpArbiterStateNormal;
345
+
346
+ // If both bodies are awake, unthread the arbiter from the contact graph.
347
+ if(!cpBodyIsSleeping(arb->body_a) && !cpBodyIsSleeping(arb->body_b)){
348
+ cpArbiterUnthread(arb);
345
349
  }
346
350
  }
351
+ arbiters->num = 0;
347
352
 
348
- // Integrate velocities.
349
- cpFloat damping = cpfpow(1.0f/space->damping, -dt);
350
- for(int i=0; i<bodies->num; i++){
351
- cpBody *body = (cpBody *)bodies->arr[i];
352
- body->velocity_func(body, space->gravity, damping, dt);
353
- }
353
+ cpSpaceLock(space); {
354
+ // Integrate positions
355
+ for(int i=0; i<bodies->num; i++){
356
+ cpBody *body = (cpBody *)bodies->arr[i];
357
+ body->position_func(body, dt);
358
+ }
359
+
360
+ // Find colliding pairs.
361
+ cpSpacePushFreshContactBuffer(space);
362
+ cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)cpShapeUpdateFunc, NULL);
363
+ cpSpatialIndexReindexQuery(space->activeShapes, (cpSpatialIndexQueryFunc)cpSpaceCollideShapes, space);
364
+ } cpSpaceUnlock(space, cpFalse);
365
+
366
+ // Rebuild the contact graph (and detect sleeping components if sleeping is enabled)
367
+ cpSpaceProcessComponents(space, dt);
368
+
369
+ cpSpaceLock(space); {
370
+ // Clear out old cached arbiters and call separate callbacks
371
+ cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cpSpaceArbiterSetFilter, space);
372
+
373
+ // Prestep the arbiters and constraints.
374
+ cpFloat slop = space->collisionSlop;
375
+ cpFloat biasCoef = 1.0f - cpfpow(space->collisionBias, dt);
376
+ for(int i=0; i<arbiters->num; i++){
377
+ cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt, slop, biasCoef);
378
+ }
354
379
 
355
- for(int i=0; i<arbiters->num; i++)
356
- cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i]);
357
-
358
- // run the old-style elastic solver if elastic iterations are disabled
359
- cpFloat elasticCoef = (space->elasticIterations ? 0.0f : 1.0f);
360
-
361
- // Run the impulse solver.
362
- for(int i=0; i<space->iterations; i++){
363
- for(int j=0; j<arbiters->num; j++)
364
- cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], elasticCoef);
380
+ for(int i=0; i<constraints->num; i++){
381
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
365
382
 
366
- for(int j=0; j<constraints->num; j++){
367
- cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
368
- constraint->klass->applyImpulse(constraint);
383
+ cpConstraintPreSolveFunc preSolve = constraint->preSolve;
384
+ if(preSolve) preSolve(constraint, space);
385
+
386
+ constraint->klass->preStep(constraint, dt);
369
387
  }
370
- }
371
388
 
372
- cpSpaceLock(space);
373
-
374
- // run the post solve callbacks
375
- for(int i=0; i<arbiters->num; i++){
376
- cpArbiter *arb = (cpArbiter *) arbiters->arr[i];
389
+ // Integrate velocities.
390
+ cpFloat damping = cpfpow(space->damping, dt);
391
+ cpVect gravity = space->gravity;
392
+ for(int i=0; i<bodies->num; i++){
393
+ cpBody *body = (cpBody *)bodies->arr[i];
394
+ body->velocity_func(body, gravity, damping, dt);
395
+ }
377
396
 
378
- cpCollisionHandler *handler = arb->handler;
379
- handler->postSolve(arb, space, handler->data);
397
+ // Apply cached impulses
398
+ cpFloat dt_coef = (prev_dt == 0.0f ? 0.0f : dt/prev_dt);
399
+ for(int i=0; i<arbiters->num; i++){
400
+ cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i], dt_coef);
401
+ }
380
402
 
381
- arb->state = cpArbiterStateNormal;
382
- }
383
-
384
- cpSpaceUnlock(space);
385
-
386
- // Run the post step callbacks
387
- // Loop because post step callbacks may create more post step callbacks
388
- while(space->postStepCallbacks){
389
- cpHashSet *callbacks = space->postStepCallbacks;
390
- space->postStepCallbacks = NULL;
403
+ for(int i=0; i<constraints->num; i++){
404
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
405
+ constraint->klass->applyCachedImpulse(constraint, dt_coef);
406
+ }
391
407
 
392
- cpHashSetEach(callbacks, (cpHashSetIterFunc)postStepCallbackSetIter, space);
393
- cpHashSetFree(callbacks);
394
- }
395
-
396
- // Increment the stamp.
397
- space->stamp++;
408
+ // Run the impulse solver.
409
+ for(int i=0; i<space->iterations; i++){
410
+ for(int j=0; j<arbiters->num; j++){
411
+ cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j]);
412
+ }
413
+
414
+ for(int j=0; j<constraints->num; j++){
415
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
416
+ constraint->klass->applyImpulse(constraint, dt);
417
+ }
418
+ }
419
+
420
+ // Run the constraint post-solve callbacks
421
+ for(int i=0; i<constraints->num; i++){
422
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
423
+
424
+ cpConstraintPostSolveFunc postSolve = constraint->postSolve;
425
+ if(postSolve) postSolve(constraint, space);
426
+ }
427
+
428
+ // run the post-solve callbacks
429
+ for(int i=0; i<arbiters->num; i++){
430
+ cpArbiter *arb = (cpArbiter *) arbiters->arr[i];
431
+
432
+ cpCollisionHandler *handler = arb->handler;
433
+ handler->postSolve(arb, space, handler->data);
434
+ }
435
+ } cpSpaceUnlock(space, cpTrue);
398
436
  }