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,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
  }