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

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 (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,279 @@
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 Sleeping Functions
27
+
28
+ // Chipmunk uses a data structure called a disjoint set forest.
29
+ // My attempts to find a way to splice circularly linked lists in
30
+ // constant time failed, and so I found this neat data structure instead.
31
+
32
+ static inline cpBody *
33
+ componentNodeRoot(cpBody *body)
34
+ {
35
+ cpBody *parent = body->node.parent;
36
+
37
+ if(parent){
38
+ // path compression, attaches this node directly to the root
39
+ return (body->node.parent = componentNodeRoot(parent));
40
+ } else {
41
+ return body;
42
+ }
43
+ }
44
+
45
+ static inline void
46
+ componentNodeMerge(cpBody *a_root, cpBody *b_root)
47
+ {
48
+ if(a_root->node.rank < b_root->node.rank){
49
+ a_root->node.parent = b_root;
50
+ } else if(a_root->node.rank > b_root->node.rank){
51
+ b_root->node.parent = a_root;
52
+ } else if(a_root != b_root){
53
+ b_root->node.parent = a_root;
54
+ a_root->node.rank++;
55
+ }
56
+ }
57
+
58
+ void
59
+ cpSpaceActivateBody(cpSpace *space, cpBody *body)
60
+ {
61
+ if(space->locked){
62
+ // cpSpaceActivateBody() is called again once the space is unlocked
63
+ cpArrayPush(space->rousedBodies, body);
64
+ } else {
65
+ cpArrayPush(space->bodies, body);
66
+ for(cpShape *shape=body->shapesList; shape; shape=shape->next){
67
+ cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
68
+ cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
69
+ }
70
+ }
71
+ }
72
+
73
+ static inline void
74
+ componentActivate(cpBody *root)
75
+ {
76
+ if(!cpBodyIsSleeping(root)) return;
77
+
78
+ cpSpace *space = root->space;
79
+ cpAssert(space, "Trying to activate a body that was never added to a space.");
80
+
81
+ cpBody *body = root, *next;
82
+ do {
83
+ next = body->node.next;
84
+
85
+ cpComponentNode node = {NULL, NULL, 0, 0.0f};
86
+ body->node = node;
87
+
88
+ cpSpaceActivateBody(space, body);
89
+ } while((body = next) != root);
90
+
91
+ cpArrayDeleteObj(space->sleepingComponents, root);
92
+ }
93
+
94
+ void
95
+ cpBodyActivate(cpBody *body)
96
+ {
97
+ componentActivate(componentNodeRoot(body));
98
+ }
99
+
100
+ static inline void
101
+ mergeBodies(cpSpace *space, cpArray *components, cpArray *rogueBodies, cpBody *a, cpBody *b)
102
+ {
103
+ // Ignore connections to static bodies
104
+ if(cpBodyIsStatic(a) || cpBodyIsStatic(b)) return;
105
+
106
+ cpBody *a_root = componentNodeRoot(a);
107
+ cpBody *b_root = componentNodeRoot(b);
108
+
109
+ cpBool a_sleep = cpBodyIsSleeping(a_root);
110
+ cpBool b_sleep = cpBodyIsSleeping(b_root);
111
+
112
+ if(a_sleep && b_sleep){
113
+ return;
114
+ } else if(a_sleep || b_sleep){
115
+ componentActivate(a_root);
116
+ componentActivate(b_root);
117
+ }
118
+
119
+ // Add any rogue bodies found to the list and reset the idle time of anything they touch.
120
+ if(cpBodyIsRogue(a)){ cpArrayPush(rogueBodies, a); b->node.idleTime = 0.0f; }
121
+ if(cpBodyIsRogue(b)){ cpArrayPush(rogueBodies, b); a->node.idleTime = 0.0f; }
122
+
123
+ componentNodeMerge(a_root, b_root);
124
+ }
125
+
126
+ static inline cpBool
127
+ componentActive(cpBody *root, cpFloat threshold)
128
+ {
129
+ cpBody *body = root, *next;
130
+ do {
131
+ next = body->node.next;
132
+ if(body->node.idleTime < threshold) return cpTrue;
133
+ } while((body = next) != root);
134
+
135
+ return cpFalse;
136
+ }
137
+
138
+ static inline void
139
+ addToComponent(cpBody *body, cpArray *components)
140
+ {
141
+ // Check that the body is not already added to the component list
142
+ if(body->node.next) return;
143
+ cpBody *root = componentNodeRoot(body);
144
+
145
+ cpBody *next = root->node.next;
146
+ if(!next){
147
+ // If the root isn't part of a list yet, then it hasn't been
148
+ // added to the components list. Do that now.
149
+ cpArrayPush(components, root);
150
+ // Start the list
151
+ body->node.next = root;
152
+ root->node.next = body;
153
+ } else if(root != body) {
154
+ // Splice in body after the root.
155
+ body->node.next = next;
156
+ root->node.next = body;
157
+ }
158
+ }
159
+
160
+ // TODO this function needs more commenting.
161
+ void
162
+ cpSpaceProcessComponents(cpSpace *space, cpFloat dt)
163
+ {
164
+ cpArray *bodies = space->bodies;
165
+ cpArray *newBodies = cpArrayNew(bodies->num);
166
+ cpArray *rogueBodies = cpArrayNew(16);
167
+ cpArray *arbiters = space->arbiters;
168
+ cpArray *constraints = space->constraints;
169
+ cpArray *components = cpArrayNew(space->sleepingComponents->num);
170
+
171
+ cpFloat dv = space->idleSpeedThreshold;
172
+ cpFloat dvsq = (dv ? dv*dv : cpvdot(space->gravity, space->gravity)*dt*dt);
173
+
174
+ // update idling
175
+ for(int i=0; i<bodies->num; i++){
176
+ cpBody *body = (cpBody*)bodies->arr[i];
177
+
178
+ cpFloat thresh = (dvsq ? body->m*dvsq : 0.0f);
179
+ body->node.idleTime = (cpBodyKineticEnergy(body) > thresh ? 0.0f : body->node.idleTime + dt);
180
+ }
181
+
182
+ // iterate graph edges and build forests
183
+ for(int i=0; i<arbiters->num; i++){
184
+ cpArbiter *arb = (cpArbiter*)arbiters->arr[i];
185
+ mergeBodies(space, components, rogueBodies, arb->a->body, arb->b->body);
186
+ }
187
+ for(int j=0; j<constraints->num; j++){
188
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
189
+ mergeBodies(space, components, rogueBodies, constraint->a, constraint->b);
190
+ }
191
+
192
+ // iterate bodies and add them to their components
193
+ for(int i=0; i<bodies->num; i++) addToComponent((cpBody*)bodies->arr[i], components);
194
+ for(int i=0; i<rogueBodies->num; i++) addToComponent((cpBody*)rogueBodies->arr[i], components);
195
+
196
+ // iterate components, copy or deactivate
197
+ for(int i=0; i<components->num; i++){
198
+ cpBody *root = (cpBody*)components->arr[i];
199
+ if(componentActive(root, space->sleepTimeThreshold)){
200
+ cpBody *body = root, *next;
201
+ do {
202
+ next = body->node.next;
203
+
204
+ if(!cpBodyIsRogue(body)) cpArrayPush(newBodies, body);
205
+ cpComponentNode node = {NULL, NULL, 0, body->node.idleTime};
206
+ body->node = node;
207
+ } while((body = next) != root);
208
+ } else {
209
+ cpBody *body = root, *next;
210
+ do {
211
+ next = body->node.next;
212
+
213
+ for(cpShape *shape = body->shapesList; shape; shape = shape->next){
214
+ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
215
+ cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
216
+ }
217
+ } while((body = next) != root);
218
+
219
+ cpArrayPush(space->sleepingComponents, root);
220
+ }
221
+ }
222
+
223
+ space->bodies = newBodies;
224
+ cpArrayFree(bodies);
225
+ cpArrayFree(rogueBodies);
226
+ cpArrayFree(components);
227
+ }
228
+
229
+ void
230
+ cpBodySleep(cpBody *body)
231
+ {
232
+ cpBodySleepWithGroup(body, NULL);
233
+ }
234
+
235
+ void
236
+ cpBodySleepWithGroup(cpBody *body, cpBody *group){
237
+ cpAssert(!cpBodyIsStatic(body) && !cpBodyIsRogue(body), "Rogue and static bodies cannot be put to sleep.");
238
+
239
+ cpSpace *space = body->space;
240
+ cpAssert(space, "Cannot put a body to sleep that has not been added to a space.");
241
+ cpAssert(!space->locked, "Bodies can not be put to sleep during a query or a call to cpSpaceSte(). Put these calls into a post-step callback.");
242
+ cpAssert(!group || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier.");
243
+
244
+ if(cpBodyIsSleeping(body)) return;
245
+
246
+ for(cpShape *shape = body->shapesList; shape; shape = shape->next){
247
+ cpShapeCacheBB(shape);
248
+ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
249
+ cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
250
+ }
251
+
252
+ if(group){
253
+ cpBody *root = componentNodeRoot(group);
254
+
255
+ cpComponentNode node = {root, root->node.next, 0, 0.0f};
256
+ body->node = node;
257
+ root->node.next = body;
258
+ } else {
259
+ cpComponentNode node = {NULL, body, 0, 0.0f};
260
+ body->node = node;
261
+
262
+ cpArrayPush(space->sleepingComponents, body);
263
+ }
264
+
265
+ cpArrayDeleteObj(space->bodies, body);
266
+ }
267
+
268
+ static void
269
+ activateTouchingHelper(cpShape *shape, cpContactPointSet *points, cpArray **bodies){
270
+ cpBodyActivate(shape->body);
271
+ }
272
+
273
+ void
274
+ cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape){
275
+ cpArray *bodies = NULL;
276
+ cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)activateTouchingHelper, &bodies);
277
+ }
278
+
279
+
@@ -0,0 +1,534 @@
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 <math.h>
23
+ #include <stdlib.h>
24
+
25
+ #include "chipmunk_private.h"
26
+ #include "prime.h"
27
+
28
+ static cpHandle*
29
+ cpHandleInit(cpHandle *hand, void *obj)
30
+ {
31
+ hand->obj = obj;
32
+ hand->retain = 0;
33
+ hand->stamp = 0;
34
+
35
+ return hand;
36
+ }
37
+
38
+ static inline void cpHandleRetain(cpHandle *hand){hand->retain++;}
39
+
40
+ static inline void
41
+ cpHandleRelease(cpHandle *hand, cpArray *pooledHandles)
42
+ {
43
+ hand->retain--;
44
+ if(hand->retain == 0) cpArrayPush(pooledHandles, hand);
45
+ }
46
+
47
+ cpSpaceHash*
48
+ cpSpaceHashAlloc(void)
49
+ {
50
+ return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash));
51
+ }
52
+
53
+ // Frees the old table, and allocate a new one.
54
+ static void
55
+ cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
56
+ {
57
+ cpfree(hash->table);
58
+
59
+ hash->numcells = numcells;
60
+ hash->table = (cpSpaceHashBin **)cpcalloc(numcells, sizeof(cpSpaceHashBin *));
61
+ }
62
+
63
+ // Equality function for the handleset.
64
+ static int handleSetEql(void *obj, cpHandle *hand){return (obj == hand->obj);}
65
+
66
+ // Transformation function for the handleset.
67
+ static void *
68
+ handleSetTrans(void *obj, cpSpaceHash *hash)
69
+ {
70
+ if(hash->pooledHandles->num == 0){
71
+ // handle pool is exhausted, make more
72
+ int count = CP_BUFFER_BYTES/sizeof(cpHandle);
73
+ cpAssert(count, "Buffer size is too small.");
74
+
75
+ cpHandle *buffer = (cpHandle *)cpmalloc(CP_BUFFER_BYTES);
76
+ cpArrayPush(hash->allocatedBuffers, buffer);
77
+
78
+ for(int i=0; i<count; i++) cpArrayPush(hash->pooledHandles, buffer + i);
79
+ }
80
+
81
+ cpHandle *hand = cpHandleInit((cpHandle *) cpArrayPop(hash->pooledHandles), obj);
82
+ cpHandleRetain(hand);
83
+
84
+ return hand;
85
+ }
86
+
87
+ cpSpaceHash*
88
+ cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBFunc bbfunc)
89
+ {
90
+ cpSpaceHashAllocTable(hash, next_prime(numcells));
91
+ hash->celldim = celldim;
92
+ hash->bbfunc = bbfunc;
93
+
94
+ hash->handleSet = cpHashSetNew(0, (cpHashSetEqlFunc)handleSetEql, (cpHashSetTransFunc)handleSetTrans);
95
+ hash->pooledHandles = cpArrayNew(0);
96
+
97
+ hash->pooledBins = NULL;
98
+ hash->allocatedBuffers = cpArrayNew(0);
99
+
100
+ hash->stamp = 1;
101
+
102
+ return hash;
103
+ }
104
+
105
+ cpSpaceHash*
106
+ cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc)
107
+ {
108
+ return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc);
109
+ }
110
+
111
+ static inline void
112
+ recycleBin(cpSpaceHash *hash, cpSpaceHashBin *bin)
113
+ {
114
+ bin->next = hash->pooledBins;
115
+ hash->pooledBins = bin;
116
+ }
117
+
118
+ static inline void
119
+ clearHashCell(cpSpaceHash *hash, int idx)
120
+ {
121
+ cpSpaceHashBin *bin = hash->table[idx];
122
+ while(bin){
123
+ cpSpaceHashBin *next = bin->next;
124
+
125
+ cpHandleRelease(bin->handle, hash->pooledHandles);
126
+ recycleBin(hash, bin);
127
+
128
+ bin = next;
129
+ }
130
+
131
+ hash->table[idx] = NULL;
132
+ }
133
+
134
+ // Clear all cells in the hashtable.
135
+ static void
136
+ clearHash(cpSpaceHash *hash)
137
+ {
138
+ for(int i=0; i<hash->numcells; i++)
139
+ clearHashCell(hash, i);
140
+ }
141
+
142
+ static void freeWrap(void *ptr, void *unused){cpfree(ptr);}
143
+
144
+ void
145
+ cpSpaceHashDestroy(cpSpaceHash *hash)
146
+ {
147
+ clearHash(hash);
148
+
149
+ cpHashSetFree(hash->handleSet);
150
+
151
+ cpArrayEach(hash->allocatedBuffers, freeWrap, NULL);
152
+ cpArrayFree(hash->allocatedBuffers);
153
+ cpArrayFree(hash->pooledHandles);
154
+
155
+ cpfree(hash->table);
156
+ }
157
+
158
+ void
159
+ cpSpaceHashFree(cpSpaceHash *hash)
160
+ {
161
+ if(hash){
162
+ cpSpaceHashDestroy(hash);
163
+ cpfree(hash);
164
+ }
165
+ }
166
+
167
+ void
168
+ cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)
169
+ {
170
+ // Clear the hash to release the old handle locks.
171
+ clearHash(hash);
172
+
173
+ hash->celldim = celldim;
174
+ cpSpaceHashAllocTable(hash, next_prime(numcells));
175
+ }
176
+
177
+ // Return true if the chain contains the handle.
178
+ static inline cpBool
179
+ containsHandle(cpSpaceHashBin *bin, cpHandle *hand)
180
+ {
181
+ while(bin){
182
+ if(bin->handle == hand) return cpTrue;
183
+ bin = bin->next;
184
+ }
185
+
186
+ return cpFalse;
187
+ }
188
+
189
+ // Get a recycled or new bin.
190
+ static inline cpSpaceHashBin *
191
+ getEmptyBin(cpSpaceHash *hash)
192
+ {
193
+ cpSpaceHashBin *bin = hash->pooledBins;
194
+
195
+ if(bin){
196
+ hash->pooledBins = bin->next;
197
+ return bin;
198
+ } else {
199
+ // Pool is exhausted, make more
200
+ int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin);
201
+ cpAssert(count, "Buffer size is too small.");
202
+
203
+ cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpmalloc(CP_BUFFER_BYTES);
204
+ cpArrayPush(hash->allocatedBuffers, buffer);
205
+
206
+ // push all but the first one, return the first instead
207
+ for(int i=1; i<count; i++) recycleBin(hash, buffer + i);
208
+ return buffer;
209
+ }
210
+ }
211
+
212
+ // The hash function itself.
213
+ static inline cpHashValue
214
+ hash_func(cpHashValue x, cpHashValue y, cpHashValue n)
215
+ {
216
+ return (x*1640531513ul ^ y*2654435789ul) % n;
217
+ }
218
+
219
+ // Much faster than (int)floor(f)
220
+ // Profiling showed floor() to be a sizable performance hog
221
+ static inline int
222
+ floor_int(cpFloat f)
223
+ {
224
+ int i = (int)f;
225
+ return (f < 0.0f && f != i ? i - 1 : i);
226
+ }
227
+
228
+ static inline void
229
+ hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
230
+ {
231
+ // Find the dimensions in cell coordinates.
232
+ cpFloat dim = hash->celldim;
233
+ int l = floor_int(bb.l/dim); // Fix by ShiftZ
234
+ int r = floor_int(bb.r/dim);
235
+ int b = floor_int(bb.b/dim);
236
+ int t = floor_int(bb.t/dim);
237
+
238
+ int n = hash->numcells;
239
+ for(int i=l; i<=r; i++){
240
+ for(int j=b; j<=t; j++){
241
+ int idx = hash_func(i,j,n);
242
+ cpSpaceHashBin *bin = hash->table[idx];
243
+
244
+ // Don't add an object twice to the same cell.
245
+ if(containsHandle(bin, hand)) continue;
246
+
247
+ cpHandleRetain(hand);
248
+ // Insert a new bin for the handle in this cell.
249
+ cpSpaceHashBin *newBin = getEmptyBin(hash);
250
+ newBin->handle = hand;
251
+ newBin->next = bin;
252
+ hash->table[idx] = newBin;
253
+ }
254
+ }
255
+ }
256
+
257
+ void
258
+ cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB _deprecated_unused)
259
+ {
260
+ cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash);
261
+ hashHandle(hash, hand, hash->bbfunc(obj));
262
+ }
263
+
264
+ void
265
+ cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid)
266
+ {
267
+ cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
268
+
269
+ if(hand){
270
+ hand->obj = NULL;
271
+ cpHandleRelease(hand, hash->pooledHandles);
272
+
273
+ cpSpaceHashInsert(hash, obj, hashid, cpBBNew(0.0f, 0.0f, 0.0f, 0.0f));
274
+ }
275
+ }
276
+
277
+ static void handleRehashHelper(cpHandle *hand, cpSpaceHash *hash){hashHandle(hash, hand, hash->bbfunc(hand->obj));}
278
+
279
+ void
280
+ cpSpaceHashRehash(cpSpaceHash *hash)
281
+ {
282
+ clearHash(hash);
283
+ cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)handleRehashHelper, hash);
284
+ }
285
+
286
+ void
287
+ cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid)
288
+ {
289
+ cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
290
+
291
+ if(hand){
292
+ hand->obj = NULL;
293
+ cpHandleRelease(hand, hash->pooledHandles);
294
+ }
295
+ }
296
+
297
+ typedef struct eachPair {
298
+ cpSpaceHashIterator func;
299
+ void *data;
300
+ } eachPair;
301
+
302
+ static void eachHelper(cpHandle *hand, eachPair *pair){pair->func(hand->obj, pair->data);}
303
+
304
+ // Iterate over the objects in the spatial hash.
305
+ void
306
+ cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)
307
+ {
308
+ eachPair pair = {func, data};
309
+ cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)eachHelper, &pair);
310
+ }
311
+
312
+ static inline void
313
+ removeOrphanedHandles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr)
314
+ {
315
+ cpSpaceHashBin *bin = *bin_ptr;
316
+ while(bin){
317
+ cpHandle *hand = bin->handle;
318
+ cpSpaceHashBin *next = bin->next;
319
+
320
+ if(!hand->obj){
321
+ // orphaned handle, unlink and recycle the bin
322
+ (*bin_ptr) = bin->next;
323
+ recycleBin(hash, bin);
324
+
325
+ cpHandleRelease(hand, hash->pooledHandles);
326
+ } else {
327
+ bin_ptr = &bin->next;
328
+ }
329
+
330
+ bin = next;
331
+ }
332
+ }
333
+
334
+ // Calls the callback function for the objects in a given chain.
335
+ static inline void
336
+ query(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashQueryFunc func, void *data)
337
+ {
338
+ restart:
339
+ for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
340
+ cpHandle *hand = bin->handle;
341
+ void *other = hand->obj;
342
+
343
+ if(hand->stamp == hash->stamp || obj == other){
344
+ continue;
345
+ } else if(other){
346
+ func(obj, other, data);
347
+ hand->stamp = hash->stamp;
348
+ } else {
349
+ // The object for this handle has been removed
350
+ // cleanup this cell and restart the query
351
+ removeOrphanedHandles(hash, bin_ptr);
352
+ goto restart; // GCC not smart enough/able to tail call an inlined function.
353
+ }
354
+ }
355
+ }
356
+
357
+ void
358
+ cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data)
359
+ {
360
+ cpFloat dim = hash->celldim;
361
+ int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells); // Fix by ShiftZ
362
+
363
+ query(hash, &hash->table[idx], &point, func, data);
364
+ hash->stamp++;
365
+ }
366
+
367
+ void
368
+ cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data)
369
+ {
370
+ // Get the dimensions in cell coordinates.
371
+ cpFloat dim = hash->celldim;
372
+ int l = floor_int(bb.l/dim); // Fix by ShiftZ
373
+ int r = floor_int(bb.r/dim);
374
+ int b = floor_int(bb.b/dim);
375
+ int t = floor_int(bb.t/dim);
376
+
377
+ int n = hash->numcells;
378
+ cpSpaceHashBin **table = hash->table;
379
+
380
+ // Iterate over the cells and query them.
381
+ for(int i=l; i<=r; i++){
382
+ for(int j=b; j<=t; j++){
383
+ query(hash, &table[hash_func(i,j,n)], obj, func, data);
384
+ }
385
+ }
386
+
387
+ hash->stamp++;
388
+ }
389
+
390
+ // Similar to struct eachPair above.
391
+ typedef struct queryRehashPair {
392
+ cpSpaceHash *hash;
393
+ cpSpaceHashQueryFunc func;
394
+ void *data;
395
+ } queryRehashPair;
396
+
397
+ // Hashset iterator func used with cpSpaceHashQueryRehash().
398
+ static void
399
+ handleQueryRehashHelper(void *elt, void *data)
400
+ {
401
+ cpHandle *hand = (cpHandle *)elt;
402
+
403
+ // Unpack the user callback data.
404
+ queryRehashPair *pair = (queryRehashPair *)data;
405
+ cpSpaceHash *hash = pair->hash;
406
+ cpSpaceHashQueryFunc func = pair->func;
407
+
408
+ cpFloat dim = hash->celldim;
409
+ int n = hash->numcells;
410
+
411
+ void *obj = hand->obj;
412
+ cpBB bb = hash->bbfunc(obj);
413
+
414
+ int l = floor_int(bb.l/dim);
415
+ int r = floor_int(bb.r/dim);
416
+ int b = floor_int(bb.b/dim);
417
+ int t = floor_int(bb.t/dim);
418
+
419
+ cpSpaceHashBin **table = hash->table;
420
+
421
+ for(int i=l; i<=r; i++){
422
+ for(int j=b; j<=t; j++){
423
+ int idx = hash_func(i,j,n);
424
+ cpSpaceHashBin *bin = table[idx];
425
+
426
+ if(containsHandle(bin, hand)) continue;
427
+
428
+ cpHandleRetain(hand); // this MUST be done first in case the object is removed in func()
429
+ query(hash, &bin, obj, func, pair->data);
430
+
431
+ cpSpaceHashBin *newBin = getEmptyBin(hash);
432
+ newBin->handle = hand;
433
+ newBin->next = bin;
434
+ table[idx] = newBin;
435
+ }
436
+ }
437
+
438
+ // Increment the stamp for each object hashed.
439
+ hash->stamp++;
440
+ }
441
+
442
+ void
443
+ cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)
444
+ {
445
+ clearHash(hash);
446
+
447
+ queryRehashPair pair = {hash, func, data};
448
+ cpHashSetEach(hash->handleSet, &handleQueryRehashHelper, &pair);
449
+ }
450
+
451
+ static inline cpFloat
452
+ segmentQuery(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashSegmentQueryFunc func, void *data)
453
+ {
454
+ cpFloat t = 1.0f;
455
+
456
+ restart:
457
+ for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
458
+ cpHandle *hand = bin->handle;
459
+ void *other = hand->obj;
460
+
461
+ // Skip over certain conditions
462
+ if(hand->stamp == hash->stamp){
463
+ continue;
464
+ } else if(other){
465
+ t = cpfmin(t, func(obj, other, data));
466
+ hand->stamp = hash->stamp;
467
+ } else {
468
+ // The object for this handle has been removed
469
+ // cleanup this cell and restart the query
470
+ removeOrphanedHandles(hash, bin_ptr);
471
+ goto restart; // GCC not smart enough/able to tail call an inlined function.
472
+ }
473
+ }
474
+
475
+ return t;
476
+ }
477
+
478
+ // modified from http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
479
+ void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpaceHashSegmentQueryFunc func, void *data)
480
+ {
481
+ a = cpvmult(a, 1.0f/hash->celldim);
482
+ b = cpvmult(b, 1.0f/hash->celldim);
483
+
484
+ int cell_x = floor_int(a.x), cell_y = floor_int(a.y);
485
+
486
+ cpFloat t = 0;
487
+
488
+ int x_inc, y_inc;
489
+ cpFloat temp_v, temp_h;
490
+
491
+ if (b.x > a.x){
492
+ x_inc = 1;
493
+ temp_h = (cpffloor(a.x + 1.0f) - a.x);
494
+ } else {
495
+ x_inc = -1;
496
+ temp_h = (a.x - cpffloor(a.x));
497
+ }
498
+
499
+ if (b.y > a.y){
500
+ y_inc = 1;
501
+ temp_v = (cpffloor(a.y + 1.0f) - a.y);
502
+ } else {
503
+ y_inc = -1;
504
+ temp_v = (a.y - cpffloor(a.y));
505
+ }
506
+
507
+ // Division by zero is *very* slow on ARM
508
+ cpFloat dx = cpfabs(b.x - a.x), dy = cpfabs(b.y - a.y);
509
+ cpFloat dt_dx = (dx ? 1.0f/dx : INFINITY), dt_dy = (dy ? 1.0f/dy : INFINITY);
510
+
511
+ // fix NANs in horizontal directions
512
+ cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx);
513
+ cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy);
514
+
515
+ cpSpaceHashBin **table = hash->table;
516
+
517
+ int n = hash->numcells;
518
+ while(t < t_exit){
519
+ int idx = hash_func(cell_x, cell_y, n);
520
+ t_exit = cpfmin(t_exit, segmentQuery(hash, &table[idx], obj, func, data));
521
+
522
+ if (next_v < next_h){
523
+ cell_y += y_inc;
524
+ t = next_v;
525
+ next_v += dt_dy;
526
+ } else {
527
+ cell_x += x_inc;
528
+ t = next_h;
529
+ next_h += dt_dx;
530
+ }
531
+ }
532
+
533
+ hash->stamp++;
534
+ }