chipmunk 5.3.4.0 → 5.3.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/README +36 -13
  2. data/Rakefile +23 -9
  3. data/ext/chipmunk/extconf.rb +55 -12
  4. data/ext/chipmunk/rb_chipmunk.c +92 -98
  5. data/ext/chipmunk/rb_chipmunk.h +44 -34
  6. data/ext/chipmunk/rb_cpArbiter.c +135 -98
  7. data/ext/chipmunk/rb_cpBB.c +84 -101
  8. data/ext/chipmunk/rb_cpBody.c +221 -243
  9. data/ext/chipmunk/rb_cpConstraint.c +173 -185
  10. data/ext/chipmunk/rb_cpShape.c +353 -240
  11. data/ext/chipmunk/rb_cpSpace.c +376 -408
  12. data/ext/chipmunk/rb_cpVect.c +135 -173
  13. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk.h +163 -0
  14. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_ffi.h +59 -0
  15. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_private.h +49 -0
  16. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_types.h +151 -0
  17. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_unsafe.h +54 -0
  18. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpConstraint.h +105 -0
  19. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpDampedRotarySpring.h +46 -0
  20. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpDampedSpring.h +53 -0
  21. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpGearJoint.h +41 -0
  22. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpGrooveJoint.h +48 -0
  23. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpPinJoint.h +43 -0
  24. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpPivotJoint.h +42 -0
  25. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpRatchetJoint.h +40 -0
  26. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpRotaryLimitJoint.h +39 -0
  27. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpSimpleMotor.h +37 -0
  28. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpSlideJoint.h +44 -0
  29. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/util.h +134 -0
  30. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpArbiter.h +188 -0
  31. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpArray.h +49 -0
  32. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpBB.h +74 -0
  33. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpBody.h +219 -0
  34. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpCollision.h +28 -0
  35. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpHashSet.h +82 -0
  36. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpPolyShape.h +103 -0
  37. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpShape.h +177 -0
  38. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpSpace.h +206 -0
  39. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpSpaceHash.h +110 -0
  40. data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpVect.h +207 -0
  41. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/chipmunk.c +151 -0
  42. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpConstraint.c +54 -0
  43. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpDampedRotarySpring.c +105 -0
  44. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpDampedSpring.c +115 -0
  45. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpGearJoint.c +113 -0
  46. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpGrooveJoint.c +161 -0
  47. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpPinJoint.c +116 -0
  48. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpPivotJoint.c +114 -0
  49. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpRatchetJoint.c +126 -0
  50. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpRotaryLimitJoint.c +120 -0
  51. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpSimpleMotor.c +97 -0
  52. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpSlideJoint.c +129 -0
  53. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpArbiter.c +280 -0
  54. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpArray.c +143 -0
  55. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpBB.c +47 -0
  56. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpBody.c +192 -0
  57. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpCollision.c +411 -0
  58. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpHashSet.c +253 -0
  59. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpPolyShape.c +240 -0
  60. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpShape.c +405 -0
  61. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpace.c +499 -0
  62. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceComponent.c +279 -0
  63. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceHash.c +534 -0
  64. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceQuery.c +246 -0
  65. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceStep.c +398 -0
  66. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpVect.c +71 -0
  67. data/ext/chipmunk/vendor/chipmunk-5.3.4/src/prime.h +68 -0
  68. data/lib/chipmunk.rb +19 -8
  69. metadata +85 -38
@@ -0,0 +1,246 @@
1
+ /* Copyright (c) 2007 Scott Lembcke
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ * SOFTWARE.
20
+ */
21
+
22
+ #include <stdlib.h>
23
+
24
+ #include "chipmunk_private.h"
25
+
26
+ #pragma mark Point Query Functions
27
+
28
+ typedef struct pointQueryContext {
29
+ cpLayers layers;
30
+ cpGroup group;
31
+ cpSpacePointQueryFunc func;
32
+ void *data;
33
+ } pointQueryContext;
34
+
35
+ static void
36
+ pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
37
+ {
38
+ if(
39
+ !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
40
+ cpShapePointQuery(shape, *point)
41
+ ){
42
+ context->func(shape, context->data);
43
+ }
44
+ }
45
+
46
+ void
47
+ cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)
48
+ {
49
+ pointQueryContext context = {layers, group, func, data};
50
+
51
+ cpSpaceLock(space); {
52
+ cpSpaceHashPointQuery(space->activeShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
53
+ cpSpaceHashPointQuery(space->staticShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
54
+ } cpSpaceUnlock(space);
55
+ }
56
+
57
+ static void
58
+ rememberLastPointQuery(cpShape *shape, cpShape **outShape)
59
+ {
60
+ if(!shape->sensor) *outShape = shape;
61
+ }
62
+
63
+ cpShape *
64
+ cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)
65
+ {
66
+ cpShape *shape = NULL;
67
+ cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)rememberLastPointQuery, &shape);
68
+
69
+ return shape;
70
+ }
71
+
72
+
73
+ #pragma mark Segment Query Functions
74
+
75
+ typedef struct segQueryContext {
76
+ cpVect start, end;
77
+ cpLayers layers;
78
+ cpGroup group;
79
+ cpSpaceSegmentQueryFunc func;
80
+ } segQueryContext;
81
+
82
+ static cpFloat
83
+ segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
84
+ {
85
+ cpSegmentQueryInfo info;
86
+
87
+ if(
88
+ !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
89
+ cpShapeSegmentQuery(shape, context->start, context->end, &info)
90
+ ){
91
+ context->func(shape, info.t, info.n, data);
92
+ }
93
+
94
+ return 1.0f;
95
+ }
96
+
97
+ void
98
+ cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
99
+ {
100
+ segQueryContext context = {
101
+ start, end,
102
+ layers, group,
103
+ func,
104
+ };
105
+
106
+ 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);
110
+ }
111
+
112
+ typedef struct segQueryFirstContext {
113
+ cpVect start, end;
114
+ cpLayers layers;
115
+ cpGroup group;
116
+ } segQueryFirstContext;
117
+
118
+ static cpFloat
119
+ segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo *out)
120
+ {
121
+ cpSegmentQueryInfo info;
122
+
123
+ if(
124
+ !(shape->group && context->group == shape->group) &&
125
+ (context->layers&shape->layers) &&
126
+ !shape->sensor &&
127
+ cpShapeSegmentQuery(shape, context->start, context->end, &info) &&
128
+ info.t < out->t
129
+ ){
130
+ *out = info;
131
+ }
132
+
133
+ return out->t;
134
+ }
135
+
136
+ cpShape *
137
+ cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out)
138
+ {
139
+ cpSegmentQueryInfo info = {NULL, 1.0f, cpvzero};
140
+ if(out){
141
+ (*out) = info;
142
+ } else {
143
+ out = &info;
144
+ }
145
+
146
+ segQueryFirstContext context = {
147
+ start, end,
148
+ layers, group
149
+ };
150
+
151
+ cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
152
+ cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
153
+
154
+ return out->shape;
155
+ }
156
+
157
+ #pragma mark BB Query Functions
158
+
159
+ typedef struct bbQueryContext {
160
+ cpLayers layers;
161
+ cpGroup group;
162
+ cpSpaceBBQueryFunc func;
163
+ void *data;
164
+ } bbQueryContext;
165
+
166
+ static void
167
+ bbQueryHelper(cpBB *bb, cpShape *shape, bbQueryContext *context)
168
+ {
169
+ if(
170
+ !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
171
+ cpBBintersects(*bb, shape->bb)
172
+ ){
173
+ context->func(shape, context->data);
174
+ }
175
+ }
176
+
177
+ void
178
+ cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data)
179
+ {
180
+ bbQueryContext context = {layers, group, func, data};
181
+
182
+ cpSpaceLock(space); {
183
+ cpSpaceHashQuery(space->activeShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
184
+ cpSpaceHashQuery(space->staticShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
185
+ } cpSpaceUnlock(space);
186
+ }
187
+
188
+ #pragma mark Shape Query Functions
189
+
190
+ typedef struct shapeQueryContext {
191
+ cpSpaceShapeQueryFunc func;
192
+ void *data;
193
+ cpBool anyCollision;
194
+ } shapeQueryContext;
195
+
196
+ // Callback from the spatial hash.
197
+ static void
198
+ shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
199
+ {
200
+ // Reject any of the simple cases
201
+ if(
202
+ (a->group && a->group == b->group) ||
203
+ !(a->layers & b->layers) ||
204
+ a->sensor || b->sensor
205
+ ) return;
206
+
207
+ cpContact contacts[CP_MAX_CONTACTS_PER_ARBITER];
208
+ int numContacts = 0;
209
+
210
+ // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
211
+ if(a->klass->type <= b->klass->type){
212
+ numContacts = cpCollideShapes(a, b, contacts);
213
+ } else {
214
+ numContacts = cpCollideShapes(b, a, contacts);
215
+ for(int i=0; i<numContacts; i++) contacts[i].n = cpvneg(contacts[i].n);
216
+ }
217
+
218
+ if(numContacts){
219
+ context->anyCollision = cpTrue;
220
+
221
+ if(context->func){
222
+ cpContactPointSet set = {numContacts, {}};
223
+ for(int i=0; i<set.count; i++){
224
+ set.points[i].point = contacts[i].p;
225
+ set.points[i].normal = contacts[i].p;
226
+ set.points[i].dist = contacts[i].dist;
227
+ }
228
+
229
+ context->func(b, &set, context->data);
230
+ }
231
+ }
232
+ }
233
+
234
+ cpBool
235
+ cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data)
236
+ {
237
+ cpBB bb = cpShapeCacheBB(shape);
238
+ shapeQueryContext context = {func, data, cpFalse};
239
+
240
+ cpSpaceLock(space); {
241
+ cpSpaceHashQuery(space->activeShapes, shape, bb, (cpSpaceHashQueryFunc)shapeQueryHelper, &context);
242
+ cpSpaceHashQuery(space->staticShapes, shape, bb, (cpSpaceHashQueryFunc)shapeQueryHelper, &context);
243
+ } cpSpaceUnlock(space);
244
+
245
+ return context.anyCollision;
246
+ }
@@ -0,0 +1,398 @@
1
+ /* Copyright (c) 2007 Scott Lembcke
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ * SOFTWARE.
20
+ */
21
+
22
+ #include <stdlib.h>
23
+ //#include <stdio.h>
24
+ #include <math.h>
25
+
26
+ #include "chipmunk_private.h"
27
+
28
+ #pragma mark Post Step Callback Functions
29
+
30
+ typedef struct PostStepCallback {
31
+ cpPostStepFunc func;
32
+ void *obj;
33
+ void *data;
34
+ } PostStepCallback;
35
+
36
+ static cpBool
37
+ postStepFuncSetEql(PostStepCallback *a, PostStepCallback *b){
38
+ return a->obj == b->obj;
39
+ }
40
+
41
+ static void *
42
+ postStepFuncSetTrans(PostStepCallback *callback, void *ignored)
43
+ {
44
+ PostStepCallback *value = (PostStepCallback *)cpmalloc(sizeof(PostStepCallback));
45
+ (*value) = (*callback);
46
+
47
+ return value;
48
+ }
49
+
50
+ void
51
+ cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data)
52
+ {
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);
59
+ }
60
+
61
+ void *
62
+ cpSpaceGetPostStepData(cpSpace *space, void *obj)
63
+ {
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;
70
+ }
71
+ }
72
+
73
+ #pragma mark Contact Buffer Functions
74
+
75
+ #define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(cpContact))
76
+ typedef struct cpContactBuffer {
77
+ cpContactBufferHeader header;
78
+ cpContact contacts[CP_CONTACTS_BUFFER_SIZE];
79
+ } cpContactBuffer;
80
+
81
+ static cpContactBufferHeader *
82
+ cpSpaceAllocContactBuffer(cpSpace *space)
83
+ {
84
+ cpContactBuffer *buffer = (cpContactBuffer *)cpmalloc(sizeof(cpContactBuffer));
85
+ cpArrayPush(space->allocatedBuffers, buffer);
86
+ return (cpContactBufferHeader *)buffer;
87
+ }
88
+
89
+ static cpContactBufferHeader *
90
+ cpContactBufferHeaderInit(cpContactBufferHeader *header, cpTimestamp stamp, cpContactBufferHeader *splice)
91
+ {
92
+ header->stamp = stamp;
93
+ header->next = (splice ? splice->next : header);
94
+ header->numContacts = 0;
95
+
96
+ return header;
97
+ }
98
+
99
+ static void
100
+ cpSpacePushFreshContactBuffer(cpSpace *space)
101
+ {
102
+ cpTimestamp stamp = space->stamp;
103
+
104
+ cpContactBufferHeader *head = space->contactBuffersHead;
105
+
106
+ if(!head){
107
+ // No buffers have been allocated, make one
108
+ space->contactBuffersHead = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, NULL);
109
+ } else if(stamp - head->next->stamp > cp_contact_persistence){
110
+ // The tail buffer is available, rotate the ring
111
+ cpContactBufferHeader *tail = head->next;
112
+ space->contactBuffersHead = cpContactBufferHeaderInit(tail, stamp, tail);
113
+ } else {
114
+ // Allocate a new buffer and push it into the ring
115
+ cpContactBufferHeader *buffer = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, head);
116
+ space->contactBuffersHead = head->next = buffer;
117
+ }
118
+ }
119
+
120
+
121
+ static cpContact *
122
+ cpContactBufferGetArray(cpSpace *space)
123
+ {
124
+ if(space->contactBuffersHead->numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){
125
+ // contact buffer could overflow on the next collision, push a fresh one.
126
+ cpSpacePushFreshContactBuffer(space);
127
+ }
128
+
129
+ cpContactBufferHeader *head = space->contactBuffersHead;
130
+ return ((cpContactBuffer *)head)->contacts + head->numContacts;
131
+ }
132
+
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!");
136
+ space->contactBuffersHead->numContacts += count;
137
+ }
138
+
139
+ static inline void
140
+ cpSpacePopContacts(cpSpace *space, int count){
141
+ space->contactBuffersHead->numContacts -= count;
142
+ }
143
+
144
+ #pragma mark Collision Detection Functions
145
+
146
+ static inline cpBool
147
+ queryReject(cpShape *a, cpShape *b)
148
+ {
149
+ return
150
+ // BBoxes must overlap
151
+ !cpBBintersects(a->bb, b->bb)
152
+ // Don't collide shapes attached to the same body.
153
+ || a->body == b->body
154
+ // Don't collide objects in the same non-zero group
155
+ || (a->group && a->group == b->group)
156
+ // Don't collide objects that don't share at least on layer.
157
+ || !(a->layers & b->layers);
158
+ }
159
+
160
+ // Callback from the spatial hash.
161
+ static void
162
+ queryFunc(cpShape *a, cpShape *b, cpSpace *space)
163
+ {
164
+ // Reject any of the simple cases
165
+ if(queryReject(a,b)) return;
166
+
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);
171
+
172
+ cpBool sensor = a->sensor || b->sensor;
173
+ if(sensor && handler == &space->defaultHandler) return;
174
+
175
+ // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
176
+ if(a->klass->type > b->klass->type){
177
+ cpShape *temp = a;
178
+ a = b;
179
+ b = temp;
180
+ }
181
+
182
+ // Narrow-phase collision detection.
183
+ cpContact *contacts = cpContactBufferGetArray(space);
184
+ int numContacts = cpCollideShapes(a, b, contacts);
185
+ if(!numContacts) return; // Shapes are not colliding.
186
+ cpSpacePushContacts(space, numContacts);
187
+
188
+ // Get an arbiter from space->contactSet for the two shapes.
189
+ // This is where the persistant contact magic comes from.
190
+ 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);
193
+ cpArbiterUpdate(arb, contacts, numContacts, handler, a, b);
194
+
195
+ // Call the begin function first if it's the first step
196
+ if(arb->state == cpArbiterStateFirstColl && !handler->begin(arb, space, handler->data)){
197
+ cpArbiterIgnore(arb); // permanently ignore the collision until separation
198
+ }
199
+
200
+ if(
201
+ // Ignore the arbiter if it has been flagged
202
+ (arb->state != cpArbiterStateIgnore) &&
203
+ // Call preSolve
204
+ handler->preSolve(arb, space, handler->data) &&
205
+ // Process, but don't add collisions for sensors.
206
+ !sensor
207
+ ){
208
+ cpArrayPush(space->arbiters, arb);
209
+ } else {
210
+ cpSpacePopContacts(space, numContacts);
211
+
212
+ arb->contacts = NULL;
213
+ arb->numContacts = 0;
214
+
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.
217
+ if(arb->state != cpArbiterStateIgnore) arb->state = cpArbiterStateNormal;
218
+ }
219
+
220
+ // Time stamp the arbiter so we know it was used recently.
221
+ arb->stamp = space->stamp;
222
+ }
223
+
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
+ // Hashset filter func to throw away old arbiters.
232
+ static cpBool
233
+ contactSetFilter(cpArbiter *arb, cpSpace *space)
234
+ {
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
+ cpTimestamp ticks = space->stamp - arb->stamp;
255
+
256
+ // was used last frame, but not this one
257
+ if(ticks >= 1 && arb->state != cpArbiterStateCached){
258
+ arb->handler->separate(arb, space, arb->handler->data);
259
+ arb->state = cpArbiterStateCached;
260
+ }
261
+
262
+ if(ticks >= cp_contact_persistence){
263
+ arb->contacts = NULL;
264
+ arb->numContacts = 0;
265
+
266
+ cpArrayPush(space->pooledArbiters, arb);
267
+ return cpFalse;
268
+ }
269
+
270
+ return cpTrue;
271
+ }
272
+
273
+ // Hashset filter func to call and throw away post step callbacks.
274
+ static void
275
+ postStepCallbackSetIter(PostStepCallback *callback, cpSpace *space)
276
+ {
277
+ callback->func(space, callback->obj, callback->data);
278
+ cpfree(callback);
279
+ }
280
+
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
+ void
288
+ cpSpaceStep(cpSpace *space, cpFloat dt)
289
+ {
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);
317
+
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
+ }
323
+
324
+ // Clear out old cached arbiters and dispatch untouch functions
325
+ cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilter, space);
326
+
327
+ // Prestep the arbiters.
328
+ 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);
345
+ }
346
+ }
347
+
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
+ }
354
+
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);
365
+
366
+ for(int j=0; j<constraints->num; j++){
367
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
368
+ constraint->klass->applyImpulse(constraint);
369
+ }
370
+ }
371
+
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];
377
+
378
+ cpCollisionHandler *handler = arb->handler;
379
+ handler->postSolve(arb, space, handler->data);
380
+
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;
391
+
392
+ cpHashSetEach(callbacks, (cpHashSetIterFunc)postStepCallbackSetIter, space);
393
+ cpHashSetFree(callbacks);
394
+ }
395
+
396
+ // Increment the stamp.
397
+ space->stamp++;
398
+ }