chipmunk 5.3.4.0-x86-mingw32 → 5.3.4.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/README +33 -13
  2. data/Rakefile +20 -7
  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 +219 -241
  9. data/ext/chipmunk/rb_cpConstraint.c +173 -185
  10. data/ext/chipmunk/rb_cpShape.c +347 -251
  11. data/ext/chipmunk/rb_cpSpace.c +376 -408
  12. data/ext/chipmunk/rb_cpVect.c +132 -170
  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/1.9/chipmunk.so +0 -0
  69. data/lib/chipmunk.rb +19 -8
  70. metadata +84 -42
  71. data/lib/1.8/chipmunk.so +0 -0
@@ -0,0 +1,405 @@
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
+ #include "chipmunk_unsafe.h"
28
+
29
+ #define CP_DefineShapeGetter(struct, type, member, name) \
30
+ CP_DeclareShapeGetter(struct, type, name){ \
31
+ cpAssert(shape->klass == &struct##Class, "shape is not a "#struct); \
32
+ return ((struct *)shape)->member; \
33
+ }
34
+ cpHashValue SHAPE_ID_COUNTER = 0;
35
+
36
+ void
37
+ cpResetShapeIdCounter(void)
38
+ {
39
+ SHAPE_ID_COUNTER = 0;
40
+ }
41
+
42
+
43
+ cpShape*
44
+ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
45
+ {
46
+ shape->klass = klass;
47
+
48
+ shape->hashid = SHAPE_ID_COUNTER;
49
+ SHAPE_ID_COUNTER++;
50
+
51
+ shape->body = body;
52
+ shape->sensor = 0;
53
+
54
+ shape->e = 0.0f;
55
+ shape->u = 0.0f;
56
+ shape->surface_v = cpvzero;
57
+
58
+ shape->collision_type = 0;
59
+ shape->group = CP_NO_GROUP;
60
+ shape->layers = CP_ALL_LAYERS;
61
+
62
+ shape->data = NULL;
63
+ shape->next = NULL;
64
+
65
+ // cpShapeCacheBB(shape);
66
+
67
+ return shape;
68
+ }
69
+
70
+ void
71
+ cpShapeDestroy(cpShape *shape)
72
+ {
73
+ if(shape->klass && shape->klass->destroy) {
74
+ shape->klass->destroy(shape);
75
+ }
76
+ }
77
+
78
+ void
79
+ cpShapeFree(cpShape *shape)
80
+ {
81
+ if(shape){
82
+ cpShapeDestroy(shape);
83
+ cpfree(shape);
84
+ }
85
+ }
86
+
87
+ // TODO this function should really take a position and rotation explicitly and be renamed
88
+ cpBB
89
+ cpShapeCacheBB(cpShape *shape)
90
+ {
91
+ cpBody *body = shape->body;
92
+
93
+ shape->bb = shape->klass->cacheData(shape, body->p, body->rot);
94
+ return shape->bb;
95
+ }
96
+
97
+ cpBool
98
+ cpShapePointQuery(cpShape *shape, cpVect p){
99
+ return shape->klass->pointQuery(shape, p);
100
+ }
101
+
102
+ cpBool
103
+ cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){
104
+ cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero};
105
+ (*info) = blank;
106
+
107
+ shape->klass->segmentQuery(shape, a, b, info);
108
+ return (info->shape != NULL);
109
+ }
110
+
111
+ void
112
+ cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info)
113
+ {
114
+ printf("Segment Query:\n");
115
+ printf("\tt: %f\n", info->t);
116
+ // printf("\tdist: %f\n", info->dist);
117
+ // printf("\tpoint: %s\n", cpvstr(info->point));
118
+ printf("\tn: %s\n", cpvstr(info->n));
119
+ }
120
+
121
+
122
+
123
+
124
+ cpCircleShape *
125
+ cpCircleShapeAlloc(void)
126
+ {
127
+ return (cpCircleShape *)cpcalloc(1, sizeof(cpCircleShape));
128
+ }
129
+
130
+ static inline cpBB
131
+ bbFromCircle(const cpVect c, const cpFloat r)
132
+ {
133
+ return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);
134
+ }
135
+
136
+ static cpBB
137
+ cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
138
+ {
139
+ cpCircleShape *circle = (cpCircleShape *)shape;
140
+
141
+ circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
142
+ return bbFromCircle(circle->tc, circle->r);
143
+ }
144
+
145
+ static cpBool
146
+ cpCircleShapePointQuery(cpShape *shape, cpVect p){
147
+ cpCircleShape *circle = (cpCircleShape *)shape;
148
+ return cpvnear(circle->tc, p, circle->r);
149
+ }
150
+
151
+ static void
152
+ circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info)
153
+ {
154
+ // offset the line to be relative to the circle
155
+ a = cpvsub(a, center);
156
+ b = cpvsub(b, center);
157
+
158
+ cpFloat qa = cpvdot(a, a) - 2.0f*cpvdot(a, b) + cpvdot(b, b);
159
+ cpFloat qb = -2.0f*cpvdot(a, a) + 2.0f*cpvdot(a, b);
160
+ cpFloat qc = cpvdot(a, a) - r*r;
161
+
162
+ cpFloat det = qb*qb - 4.0f*qa*qc;
163
+
164
+ if(det >= 0.0f){
165
+ cpFloat t = (-qb - cpfsqrt(det))/(2.0f*qa);
166
+ if(0.0f<= t && t <= 1.0f){
167
+ info->shape = shape;
168
+ info->t = t;
169
+ info->n = cpvnormalize(cpvlerp(a, b, t));
170
+ }
171
+ }
172
+ }
173
+
174
+ static void
175
+ cpCircleShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
176
+ {
177
+ cpCircleShape *circle = (cpCircleShape *)shape;
178
+ circleSegmentQuery(shape, circle->tc, circle->r, a, b, info);
179
+ }
180
+
181
+ static const cpShapeClass cpCircleShapeClass = {
182
+ CP_CIRCLE_SHAPE,
183
+ cpCircleShapeCacheData,
184
+ NULL,
185
+ cpCircleShapePointQuery,
186
+ cpCircleShapeSegmentQuery,
187
+ };
188
+
189
+ cpCircleShape *
190
+ cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)
191
+ {
192
+ circle->c = offset;
193
+ circle->r = radius;
194
+
195
+ cpShapeInit((cpShape *)circle, &cpCircleShapeClass, body);
196
+
197
+ return circle;
198
+ }
199
+
200
+ cpShape *
201
+ cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)
202
+ {
203
+ return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset);
204
+ }
205
+
206
+ CP_DefineShapeGetter(cpCircleShape, cpVect, c, Offset)
207
+ CP_DefineShapeGetter(cpCircleShape, cpFloat, r, Radius)
208
+
209
+ cpSegmentShape *
210
+ cpSegmentShapeAlloc(void)
211
+ {
212
+ return (cpSegmentShape *)cpcalloc(1, sizeof(cpSegmentShape));
213
+ }
214
+
215
+ static cpBB
216
+ cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
217
+ {
218
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
219
+
220
+ seg->ta = cpvadd(p, cpvrotate(seg->a, rot));
221
+ seg->tb = cpvadd(p, cpvrotate(seg->b, rot));
222
+ seg->tn = cpvrotate(seg->n, rot);
223
+
224
+ cpFloat l,r,s,t;
225
+
226
+ if(seg->ta.x < seg->tb.x){
227
+ l = seg->ta.x;
228
+ r = seg->tb.x;
229
+ } else {
230
+ l = seg->tb.x;
231
+ r = seg->ta.x;
232
+ }
233
+
234
+ if(seg->ta.y < seg->tb.y){
235
+ s = seg->ta.y;
236
+ t = seg->tb.y;
237
+ } else {
238
+ s = seg->tb.y;
239
+ t = seg->ta.y;
240
+ }
241
+
242
+ cpFloat rad = seg->r;
243
+ return cpBBNew(l - rad, s - rad, r + rad, t + rad);
244
+ }
245
+
246
+ static cpBool
247
+ cpSegmentShapePointQuery(cpShape *shape, cpVect p){
248
+ if(!cpBBcontainsVect(shape->bb, p)) return cpFalse;
249
+
250
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
251
+
252
+ // Calculate normal distance from segment.
253
+ cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
254
+ cpFloat dist = cpfabs(dn) - seg->r;
255
+ if(dist > 0.0f) return cpFalse;
256
+
257
+ // Calculate tangential distance along segment.
258
+ cpFloat dt = -cpvcross(seg->tn, p);
259
+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
260
+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
261
+
262
+ // Decision tree to decide which feature of the segment to collide with.
263
+ if(dt <= dtMin){
264
+ if(dt < (dtMin - seg->r)){
265
+ return cpFalse;
266
+ } else {
267
+ return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
268
+ }
269
+ } else {
270
+ if(dt < dtMax){
271
+ return cpTrue;
272
+ } else {
273
+ if(dt < (dtMax + seg->r)) {
274
+ return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
275
+ } else {
276
+ return cpFalse;
277
+ }
278
+ }
279
+ }
280
+
281
+ return cpTrue;
282
+ }
283
+
284
+ static inline cpBool inUnitRange(cpFloat t){return (0.0f < t && t < 1.0f);}
285
+
286
+ static void
287
+ cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
288
+ {
289
+ // TODO this function could be optimized better.
290
+
291
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
292
+ cpVect n = seg->tn;
293
+ // flip n if a is behind the axis
294
+ if(cpvdot(a, n) < cpvdot(seg->ta, n))
295
+ n = cpvneg(n);
296
+
297
+ cpFloat an = cpvdot(a, n);
298
+ cpFloat bn = cpvdot(b, n);
299
+
300
+ if(an != bn){
301
+ cpFloat d = cpvdot(seg->ta, n) + seg->r;
302
+ cpFloat t = (d - an)/(bn - an);
303
+
304
+ if(0.0f < t && t < 1.0f){
305
+ cpVect point = cpvlerp(a, b, t);
306
+ cpFloat dt = -cpvcross(seg->tn, point);
307
+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
308
+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
309
+
310
+ if(dtMin < dt && dt < dtMax){
311
+ info->shape = shape;
312
+ info->t = t;
313
+ info->n = n;
314
+
315
+ return; // don't continue on and check endcaps
316
+ }
317
+ }
318
+ }
319
+
320
+ if(seg->r) {
321
+ cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero};
322
+ cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero};
323
+ circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1);
324
+ circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2);
325
+
326
+ if(info1.t < info2.t){
327
+ (*info) = info1;
328
+ } else {
329
+ (*info) = info2;
330
+ }
331
+ }
332
+ }
333
+
334
+ static const cpShapeClass cpSegmentShapeClass = {
335
+ CP_SEGMENT_SHAPE,
336
+ cpSegmentShapeCacheData,
337
+ NULL,
338
+ cpSegmentShapePointQuery,
339
+ cpSegmentShapeSegmentQuery,
340
+ };
341
+
342
+ cpSegmentShape *
343
+ cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r)
344
+ {
345
+ seg->a = a;
346
+ seg->b = b;
347
+ seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));
348
+
349
+ seg->r = r;
350
+
351
+ cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body);
352
+
353
+ return seg;
354
+ }
355
+
356
+ cpShape*
357
+ cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r)
358
+ {
359
+ return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r);
360
+ }
361
+
362
+ CP_DefineShapeGetter(cpSegmentShape, cpVect, a, A)
363
+ CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B)
364
+ CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal)
365
+ CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius)
366
+
367
+ // Unsafe API (chipmunk_unsafe.h)
368
+
369
+ void
370
+ cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)
371
+ {
372
+ cpAssert(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
373
+ cpCircleShape *circle = (cpCircleShape *)shape;
374
+
375
+ circle->r = radius;
376
+ }
377
+
378
+ void
379
+ cpCircleShapeSetOffset(cpShape *shape, cpVect offset)
380
+ {
381
+ cpAssert(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
382
+ cpCircleShape *circle = (cpCircleShape *)shape;
383
+
384
+ circle->c = offset;
385
+ }
386
+
387
+ void
388
+ cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)
389
+ {
390
+ cpAssert(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
391
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
392
+
393
+ seg->a = a;
394
+ seg->b = b;
395
+ seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));
396
+ }
397
+
398
+ void
399
+ cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius)
400
+ {
401
+ cpAssert(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
402
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
403
+
404
+ seg->r = radius;
405
+ }
@@ -0,0 +1,499 @@
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 <string.h>
25
+ #include <math.h>
26
+
27
+ #include "chipmunk_private.h"
28
+
29
+ cpTimestamp cp_contact_persistence = 3;
30
+
31
+ #pragma mark Contact Set Helpers
32
+
33
+ // Equal function for contactSet.
34
+ static cpBool
35
+ contactSetEql(cpShape **shapes, cpArbiter *arb)
36
+ {
37
+ cpShape *a = shapes[0];
38
+ cpShape *b = shapes[1];
39
+
40
+ return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));
41
+ }
42
+
43
+ // Transformation function for contactSet.
44
+ static void *
45
+ contactSetTrans(cpShape **shapes, cpSpace *space)
46
+ {
47
+ if(space->pooledArbiters->num == 0){
48
+ // arbiter pool is exhausted, make more
49
+ int count = CP_BUFFER_BYTES/sizeof(cpArbiter);
50
+ cpAssert(count, "Buffer size too small.");
51
+
52
+ cpArbiter *buffer = (cpArbiter *)cpmalloc(CP_BUFFER_BYTES);
53
+ cpArrayPush(space->allocatedBuffers, buffer);
54
+
55
+ for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);
56
+ }
57
+
58
+ return cpArbiterInit((cpArbiter *) cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);
59
+ }
60
+
61
+ #pragma mark Collision Pair Function Helpers
62
+
63
+ // Equals function for collFuncSet.
64
+ static cpBool
65
+ collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
66
+ {
67
+ return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b));
68
+ }
69
+
70
+ // Transformation function for collFuncSet.
71
+ static void *
72
+ collFuncSetTrans(cpCollisionHandler *handler, void *unused)
73
+ {
74
+ cpCollisionHandler *copy = (cpCollisionHandler *)cpmalloc(sizeof(cpCollisionHandler));
75
+ (*copy) = (*handler);
76
+
77
+ return copy;
78
+ }
79
+
80
+ #pragma mark Misc Helper Funcs
81
+
82
+ // Default collision functions.
83
+ static cpBool alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
84
+ static void nothing(cpArbiter *arb, cpSpace *space, void *data){}
85
+
86
+ // BBfunc callback for the spatial hash.
87
+ static cpBB shapeBBFunc(cpShape *shape){return shape->bb;}
88
+
89
+ // Iterator functions for destructors.
90
+ static void freeWrap(void *ptr, void *unused){ cpfree(ptr);}
91
+ static void shapeFreeWrap(cpShape *ptr, void *unused){ cpShapeFree(ptr);}
92
+ static void bodyFreeWrap(cpBody *ptr, void *unused){ cpBodyFree(ptr);}
93
+ static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFree(ptr);}
94
+
95
+ #pragma mark Memory Management Functions
96
+
97
+ cpSpace *
98
+ cpSpaceAlloc(void)
99
+ {
100
+ return (cpSpace *)cpcalloc(1, sizeof(cpSpace));
101
+ }
102
+
103
+ #define DEFAULT_DIM_SIZE 100.0f
104
+ #define DEFAULT_COUNT 1000
105
+ #define DEFAULT_ITERATIONS 10
106
+ #define DEFAULT_ELASTIC_ITERATIONS 0
107
+
108
+ cpCollisionHandler defaultHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL};
109
+
110
+ cpSpace*
111
+ cpSpaceInit(cpSpace *space)
112
+ {
113
+ space->iterations = DEFAULT_ITERATIONS;
114
+ space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;
115
+ // space->sleepTicks = 300;
116
+
117
+ space->gravity = cpvzero;
118
+ space->damping = 1.0f;
119
+
120
+ space->locked = 0;
121
+ space->stamp = 0;
122
+
123
+ space->staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
124
+ space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
125
+
126
+ space->allocatedBuffers = cpArrayNew(0);
127
+
128
+ space->bodies = cpArrayNew(0);
129
+ space->sleepingComponents = cpArrayNew(0);
130
+ space->rousedBodies = cpArrayNew(0);
131
+
132
+ space->sleepTimeThreshold = INFINITY;
133
+ space->idleSpeedThreshold = 0.0f;
134
+
135
+ space->arbiters = cpArrayNew(0);
136
+ space->pooledArbiters = cpArrayNew(0);
137
+
138
+ space->contactBuffersHead = NULL;
139
+ space->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);
140
+
141
+ space->constraints = cpArrayNew(0);
142
+
143
+ space->defaultHandler = defaultHandler;
144
+ space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);
145
+ space->collFuncSet->default_value = &space->defaultHandler;
146
+
147
+ space->postStepCallbacks = NULL;
148
+
149
+ cpBodyInitStatic(&space->staticBody);
150
+
151
+ return space;
152
+ }
153
+
154
+ cpSpace*
155
+ cpSpaceNew(void)
156
+ {
157
+ return cpSpaceInit(cpSpaceAlloc());
158
+ }
159
+
160
+ void
161
+ cpSpaceDestroy(cpSpace *space)
162
+ {
163
+ cpSpaceHashFree(space->staticShapes);
164
+ cpSpaceHashFree(space->activeShapes);
165
+
166
+ cpArrayFree(space->bodies);
167
+ cpArrayFree(space->sleepingComponents);
168
+ cpArrayFree(space->rousedBodies);
169
+
170
+ cpArrayFree(space->constraints);
171
+
172
+ cpHashSetFree(space->contactSet);
173
+
174
+ cpArrayFree(space->arbiters);
175
+ cpArrayFree(space->pooledArbiters);
176
+
177
+ if(space->allocatedBuffers){
178
+ cpArrayEach(space->allocatedBuffers, freeWrap, NULL);
179
+ cpArrayFree(space->allocatedBuffers);
180
+ }
181
+
182
+ if(space->postStepCallbacks){
183
+ cpHashSetEach(space->postStepCallbacks, freeWrap, NULL);
184
+ cpHashSetFree(space->postStepCallbacks);
185
+ }
186
+
187
+ if(space->collFuncSet){
188
+ cpHashSetEach(space->collFuncSet, freeWrap, NULL);
189
+ cpHashSetFree(space->collFuncSet);
190
+ }
191
+ }
192
+
193
+ void
194
+ cpSpaceFree(cpSpace *space)
195
+ {
196
+ if(space){
197
+ cpSpaceDestroy(space);
198
+ cpfree(space);
199
+ }
200
+ }
201
+
202
+ void
203
+ cpSpaceFreeChildren(cpSpace *space)
204
+ {
205
+ cpArray *components = space->sleepingComponents;
206
+ while(components->num) cpBodyActivate((cpBody *)components->arr[0]);
207
+
208
+ cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
209
+ cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
210
+ cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL);
211
+ cpArrayEach(space->constraints, (cpArrayIter)&constraintFreeWrap, NULL);
212
+ }
213
+
214
+ #pragma mark Collision Handler Function Management
215
+
216
+ void
217
+ cpSpaceAddCollisionHandler(
218
+ cpSpace *space,
219
+ cpCollisionType a, cpCollisionType b,
220
+ cpCollisionBeginFunc begin,
221
+ cpCollisionPreSolveFunc preSolve,
222
+ cpCollisionPostSolveFunc postSolve,
223
+ cpCollisionSeparateFunc separate,
224
+ void *data
225
+ ){
226
+ // Remove any old function so the new one will get added.
227
+ cpSpaceRemoveCollisionHandler(space, a, b);
228
+
229
+ cpCollisionHandler handler = {
230
+ a, b,
231
+ begin ? begin : alwaysCollide,
232
+ preSolve ? preSolve : alwaysCollide,
233
+ postSolve ? postSolve : nothing,
234
+ separate ? separate : nothing,
235
+ data
236
+ };
237
+
238
+ cpHashSetInsert(space->collFuncSet, CP_HASH_PAIR(a, b), &handler, NULL);
239
+ }
240
+
241
+ void
242
+ cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)
243
+ {
244
+ struct{cpCollisionType a, b;} ids = {a, b};
245
+ cpCollisionHandler *old_handler = (cpCollisionHandler *) cpHashSetRemove(space->collFuncSet, CP_HASH_PAIR(a, b), &ids);
246
+ cpfree(old_handler);
247
+ }
248
+
249
+ void
250
+ cpSpaceSetDefaultCollisionHandler(
251
+ cpSpace *space,
252
+ cpCollisionBeginFunc begin,
253
+ cpCollisionPreSolveFunc preSolve,
254
+ cpCollisionPostSolveFunc postSolve,
255
+ cpCollisionSeparateFunc separate,
256
+ void *data
257
+ ){
258
+ cpCollisionHandler handler = {
259
+ 0, 0,
260
+ begin ? begin : alwaysCollide,
261
+ preSolve ? preSolve : alwaysCollide,
262
+ postSolve ? postSolve : nothing,
263
+ separate ? separate : nothing,
264
+ data
265
+ };
266
+
267
+ space->defaultHandler = handler;
268
+ }
269
+
270
+ #pragma mark Body, Shape, and Joint Management
271
+
272
+ #define cpAssertSpaceUnlocked(space) \
273
+ cpAssert(!space->locked, \
274
+ "This addition/removal cannot be done safely during a call to cpSpaceStep() or during a query. " \
275
+ "Put these calls into a post-step callback." \
276
+ );
277
+
278
+ static void
279
+ cpBodyAddShape(cpBody *body, cpShape *shape)
280
+ {
281
+ shape->next = shape->body->shapesList;
282
+ shape->body->shapesList = shape;
283
+ }
284
+
285
+ static void
286
+ cpBodyRemoveShape(cpBody *body, cpShape *shape)
287
+ {
288
+ cpShape **prev_ptr = &body->shapesList;
289
+ cpShape *node = body->shapesList;
290
+
291
+ while(node && node != shape){
292
+ prev_ptr = &node->next;
293
+ node = node->next;
294
+ }
295
+
296
+ cpAssert(node, "Attempted to remove a shape from a body it was never attached to.");
297
+ (*prev_ptr) = node->next;
298
+ }
299
+
300
+ cpShape *
301
+ cpSpaceAddShape(cpSpace *space, cpShape *shape)
302
+ {
303
+ cpBody *body = shape->body;
304
+ if(!body || cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape);
305
+
306
+ cpAssert(!cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
307
+ "Cannot add the same shape more than once.");
308
+ cpAssertSpaceUnlocked(space);
309
+
310
+ cpBodyActivate(body);
311
+ cpBodyAddShape(body, shape);
312
+
313
+ cpShapeCacheBB(shape);
314
+ cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
315
+
316
+ return shape;
317
+ }
318
+
319
+ cpShape *
320
+ cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
321
+ {
322
+ cpAssert(!cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
323
+ "Cannot add the same static shape more than once.");
324
+ cpAssertSpaceUnlocked(space);
325
+
326
+ if(!shape->body) shape->body = &space->staticBody;
327
+
328
+ cpShapeCacheBB(shape);
329
+ cpSpaceActivateShapesTouchingShape(space, shape);
330
+ cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
331
+
332
+ return shape;
333
+ }
334
+
335
+ cpBody *
336
+ cpSpaceAddBody(cpSpace *space, cpBody *body)
337
+ {
338
+ cpAssertWarn(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated.");
339
+ cpAssert(!body->space, "Cannot add a body to a more than one space or to the same space twice.");
340
+ // cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback
341
+
342
+ cpArrayPush(space->bodies, body);
343
+ body->space = space;
344
+
345
+ return body;
346
+ }
347
+
348
+ cpConstraint *
349
+ cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
350
+ {
351
+ cpAssert(!cpArrayContains(space->constraints, constraint), "Cannot add the same constraint more than once.");
352
+ // cpAssertSpaceUnlocked(space); This should be safe as long as its not from a constraint callback.
353
+
354
+ if(!constraint->a) constraint->a = &space->staticBody;
355
+ if(!constraint->b) constraint->b = &space->staticBody;
356
+
357
+ cpBodyActivate(constraint->a);
358
+ cpBodyActivate(constraint->b);
359
+ cpArrayPush(space->constraints, constraint);
360
+
361
+ return constraint;
362
+ }
363
+
364
+ typedef struct removalContext {
365
+ cpSpace *space;
366
+ cpShape *shape;
367
+ } removalContext;
368
+
369
+ // Hashset filter func to throw away old arbiters.
370
+ static cpBool
371
+ contactSetFilterRemovedShape(cpArbiter *arb, removalContext *context)
372
+ {
373
+ if(context->shape == arb->a || context->shape == arb->b){
374
+ if(arb->state != cpArbiterStateCached){
375
+ arb->handler->separate(arb, context->space, arb->handler->data);
376
+ }
377
+
378
+ cpArrayPush(context->space->pooledArbiters, arb);
379
+ return cpFalse;
380
+ }
381
+
382
+ return cpTrue;
383
+ }
384
+
385
+ void
386
+ cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
387
+ {
388
+ cpBody *body = shape->body;
389
+ if(cpBodyIsStatic(body)){
390
+ cpSpaceRemoveStaticShape(space, shape);
391
+ return;
392
+ }
393
+
394
+ cpBodyActivate(body);
395
+
396
+ cpAssertSpaceUnlocked(space);
397
+ cpAssertWarn(cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
398
+ "Cannot remove a shape that was not added to the space. (Removed twice maybe?)");
399
+
400
+ cpBodyRemoveShape(body, shape);
401
+
402
+ removalContext context = {space, shape};
403
+ cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
404
+ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
405
+ }
406
+
407
+ void
408
+ cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
409
+ {
410
+ cpAssertWarn(cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
411
+ "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)");
412
+ cpAssertSpaceUnlocked(space);
413
+
414
+ removalContext context = {space, shape};
415
+ cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
416
+ cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
417
+
418
+ cpSpaceActivateShapesTouchingShape(space, shape);
419
+ }
420
+
421
+ void
422
+ cpSpaceRemoveBody(cpSpace *space, cpBody *body)
423
+ {
424
+ cpAssertWarn(body->space == space,
425
+ "Cannot remove a body that was not added to the space. (Removed twice maybe?)");
426
+ cpAssertSpaceUnlocked(space);
427
+
428
+ cpBodyActivate(body);
429
+ cpArrayDeleteObj(space->bodies, body);
430
+ body->space = NULL;
431
+ }
432
+
433
+ void
434
+ cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
435
+ {
436
+ cpAssertWarn(cpArrayContains(space->constraints, constraint),
437
+ "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");
438
+ // cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback.
439
+
440
+ cpBodyActivate(constraint->a);
441
+ cpBodyActivate(constraint->b);
442
+ cpArrayDeleteObj(space->constraints, constraint);
443
+ }
444
+
445
+ #pragma mark Spatial Hash Management
446
+
447
+ static void updateBBCache(cpShape *shape, void *unused){cpShapeCacheBB(shape);}
448
+
449
+ void
450
+ cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
451
+ {
452
+ cpSpaceHashResize(space->staticShapes, dim, count);
453
+ cpSpaceHashRehash(space->staticShapes);
454
+ }
455
+
456
+ void
457
+ cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)
458
+ {
459
+ cpSpaceHashResize(space->activeShapes, dim, count);
460
+ }
461
+
462
+ void
463
+ cpSpaceRehashStatic(cpSpace *space)
464
+ {
465
+ cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&updateBBCache, NULL);
466
+ cpSpaceHashRehash(space->staticShapes);
467
+ }
468
+
469
+ void
470
+ cpSpaceRehashShape(cpSpace *space, cpShape *shape)
471
+ {
472
+ cpShapeCacheBB(shape);
473
+
474
+ // attempt to rehash the shape in both hashes
475
+ cpSpaceHashRehashObject(space->activeShapes, shape, shape->hashid);
476
+ cpSpaceHashRehashObject(space->staticShapes, shape, shape->hashid);
477
+ }
478
+
479
+ void
480
+ cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
481
+ {
482
+ cpArray *bodies = space->bodies;
483
+
484
+ for(int i=0; i<bodies->num; i++){
485
+ func((cpBody *)bodies->arr[i], data);
486
+ }
487
+
488
+ cpArray *components = space->sleepingComponents;
489
+ for(int i=0; i<components->num; i++){
490
+ cpBody *root = (cpBody *)components->arr[i];
491
+ cpBody *body = root, *next;
492
+ do {
493
+ next = body->node.next;
494
+ func(body, data);
495
+ } while((body = next) != root);
496
+ }
497
+ }
498
+
499
+