chipmunk 5.3.4.5 → 6.1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/ext/chipmunk/chipmunk.c +199 -28
  2. data/ext/chipmunk/chipmunk.h +123 -68
  3. data/ext/chipmunk/chipmunk_ffi.h +129 -11
  4. data/ext/chipmunk/chipmunk_private.h +232 -16
  5. data/ext/chipmunk/chipmunk_types.h +94 -30
  6. data/ext/chipmunk/chipmunk_unsafe.h +12 -3
  7. data/ext/chipmunk/constraints/cpConstraint.h +90 -34
  8. data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
  9. data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
  10. data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
  11. data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
  12. data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
  13. data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
  14. data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
  15. data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
  16. data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
  17. data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
  18. data/ext/chipmunk/constraints/util.h +36 -44
  19. data/ext/chipmunk/cpArbiter.c +159 -94
  20. data/ext/chipmunk/cpArbiter.h +135 -129
  21. data/ext/chipmunk/cpArray.c +37 -56
  22. data/ext/chipmunk/cpBB.c +1 -12
  23. data/ext/chipmunk/cpBB.h +80 -18
  24. data/ext/chipmunk/cpBBTree.c +891 -0
  25. data/ext/chipmunk/cpBody.c +185 -47
  26. data/ext/chipmunk/cpBody.h +156 -124
  27. data/ext/chipmunk/cpCollision.c +126 -115
  28. data/ext/chipmunk/cpConstraint.c +10 -6
  29. data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
  30. data/ext/chipmunk/cpDampedSpring.c +25 -18
  31. data/ext/chipmunk/cpGearJoint.c +23 -17
  32. data/ext/chipmunk/cpGrooveJoint.c +26 -22
  33. data/ext/chipmunk/cpHashSet.c +51 -51
  34. data/ext/chipmunk/cpPinJoint.c +26 -19
  35. data/ext/chipmunk/cpPivotJoint.c +23 -19
  36. data/ext/chipmunk/cpPolyShape.c +93 -69
  37. data/ext/chipmunk/cpPolyShape.h +33 -69
  38. data/ext/chipmunk/cpRatchetJoint.c +26 -21
  39. data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
  40. data/ext/chipmunk/cpShape.c +122 -133
  41. data/ext/chipmunk/cpShape.h +146 -95
  42. data/ext/chipmunk/cpSimpleMotor.c +24 -17
  43. data/ext/chipmunk/cpSlideJoint.c +28 -26
  44. data/ext/chipmunk/cpSpace.c +251 -196
  45. data/ext/chipmunk/cpSpace.h +173 -103
  46. data/ext/chipmunk/cpSpaceComponent.c +236 -159
  47. data/ext/chipmunk/cpSpaceHash.c +259 -159
  48. data/ext/chipmunk/cpSpaceQuery.c +127 -59
  49. data/ext/chipmunk/cpSpaceStep.c +235 -197
  50. data/ext/chipmunk/cpSpatialIndex.c +69 -0
  51. data/ext/chipmunk/cpSpatialIndex.h +227 -0
  52. data/ext/chipmunk/cpSweep1D.c +254 -0
  53. data/ext/chipmunk/cpVect.c +11 -26
  54. data/ext/chipmunk/cpVect.h +76 -71
  55. data/ext/chipmunk/extconf.rb +4 -31
  56. data/ext/chipmunk/prime.h +1 -1
  57. data/ext/chipmunk/rb_chipmunk.c +36 -45
  58. data/ext/chipmunk/rb_chipmunk.h +6 -3
  59. data/ext/chipmunk/rb_cpArbiter.c +2 -2
  60. data/ext/chipmunk/rb_cpBB.c +116 -35
  61. data/ext/chipmunk/rb_cpBody.c +5 -12
  62. data/ext/chipmunk/rb_cpConstraint.c +144 -9
  63. data/ext/chipmunk/rb_cpShape.c +69 -78
  64. data/ext/chipmunk/rb_cpSpace.c +81 -76
  65. metadata +61 -61
  66. data/LICENSE +0 -22
  67. data/README +0 -110
  68. data/Rakefile +0 -102
  69. data/ext/chipmunk/cpArray.h +0 -49
  70. data/ext/chipmunk/cpCollision.h +0 -28
  71. data/ext/chipmunk/cpHashSet.h +0 -82
  72. data/ext/chipmunk/cpSpaceHash.h +0 -110
  73. data/lib/chipmunk.rb +0 -194
@@ -19,120 +19,138 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- struct cpSpace;
23
-
24
- // Number of frames that contact information should persist.
25
- extern cpTimestamp cp_contact_persistence;
26
-
27
- // User collision handler function types.
28
- typedef cpBool (*cpCollisionBeginFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
29
- typedef cpBool (*cpCollisionPreSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
30
- typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
31
- typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
32
-
33
- // Structure for holding collision pair function information.
34
- // Used internally.
35
- typedef struct cpCollisionHandler {
36
- cpCollisionType a;
37
- cpCollisionType b;
38
- cpCollisionBeginFunc begin;
39
- cpCollisionPreSolveFunc preSolve;
40
- cpCollisionPostSolveFunc postSolve;
41
- cpCollisionSeparateFunc separate;
42
- void *data;
43
- } cpCollisionHandler;
44
-
45
- typedef struct cpContactBufferHeader {
46
- cpTimestamp stamp;
47
- struct cpContactBufferHeader *next;
48
- unsigned int numContacts;
49
- } cpContactBufferHeader;
50
-
51
- typedef struct cpSpace{
52
- // *** User definable fields
53
-
54
- // Number of iterations to use in the impulse solver to solve contacts.
22
+ /// @defgroup cpSpace cpSpace
23
+ /// @{
24
+
25
+ typedef struct cpContactBufferHeader cpContactBufferHeader;
26
+ typedef void (*cpSpaceArbiterApplyImpulseFunc)(cpArbiter *arb);
27
+
28
+ /// Basic Unit of Simulation in Chipmunk
29
+ struct cpSpace {
30
+ /// Number of iterations to use in the impulse solver to solve contacts.
55
31
  int iterations;
56
32
 
57
- // Number of iterations to use in the impulse solver to solve elastic collisions.
58
- int elasticIterations;
59
-
60
- // Default gravity to supply when integrating rigid body motions.
33
+ /// Gravity to pass to rigid bodies when integrating velocity.
61
34
  cpVect gravity;
62
35
 
63
- // Default damping to supply when integrating rigid body motions.
36
+ /// Damping rate expressed as the fraction of velocity bodies retain each second.
37
+ /// A value of 0.9 would mean that each body's velocity will drop 10% per second.
38
+ /// The default value is 1.0, meaning no damping is applied.
39
+ /// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring.
64
40
  cpFloat damping;
65
41
 
66
- // Speed threshold for a body to be considered idle.
67
- // The default value of 0 means to let the space guess a good threshold based on gravity.
42
+ /// Speed threshold for a body to be considered idle.
43
+ /// The default value of 0 means to let the space guess a good threshold based on gravity.
68
44
  cpFloat idleSpeedThreshold;
69
45
 
70
- // Time a group of bodies must remain idle in order to fall asleep
71
- // The default value of INFINITY disables the sleeping algorithm.
46
+ /// Time a group of bodies must remain idle in order to fall asleep.
47
+ /// Enabling sleeping also implicitly enables the the contact graph.
48
+ /// The default value of INFINITY disables the sleeping algorithm.
72
49
  cpFloat sleepTimeThreshold;
73
50
 
74
- // *** Internally Used Fields
51
+ /// Amount of encouraged penetration between colliding shapes.
52
+ /// Used to reduce oscillating contacts and keep the collision cache warm.
53
+ /// Defaults to 0.1. If you have poor simulation quality,
54
+ /// increase this number as much as possible without allowing visible amounts of overlap.
55
+ cpFloat collisionSlop;
75
56
 
76
- // When the space lock count is non zero you cannot add or remove objects
77
- CP_PRIVATE(int locked);
57
+ /// Determines how fast overlapping shapes are pushed apart.
58
+ /// Expressed as a fraction of the error remaining after each second.
59
+ /// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz.
60
+ cpFloat collisionBias;
61
+
62
+ /// Number of frames that contact information should persist.
63
+ /// Defaults to 3. There is probably never a reason to change this value.
64
+ cpTimestamp collisionPersistence;
65
+
66
+ /// Rebuild the contact graph during each step. Must be enabled to use the cpBodyEachArbiter() function.
67
+ /// Disabled by default for a small performance boost. Enabled implicitly when the sleeping feature is enabled.
68
+ cpBool enableContactGraph;
69
+
70
+ /// User definable data pointer.
71
+ /// Generally this points to your game's controller or game state
72
+ /// class so you can access it when given a cpSpace reference in a callback.
73
+ cpDataPointer data;
74
+
75
+ /// The designated static body for this space.
76
+ /// You can modify this body, or replace it with your own static body.
77
+ /// By default it points to a statically allocated cpBody in the cpSpace struct.
78
+ cpBody *staticBody;
78
79
 
79
- // Time stamp. Is incremented on every call to cpSpaceStep().
80
80
  CP_PRIVATE(cpTimestamp stamp);
81
+ CP_PRIVATE(cpFloat curr_dt);
81
82
 
82
- // The static and active shape spatial hashes.
83
- CP_PRIVATE(cpSpaceHash *staticShapes);
84
- CP_PRIVATE(cpSpaceHash *activeShapes);
85
-
86
- // List of bodies in the system.
87
83
  CP_PRIVATE(cpArray *bodies);
88
-
89
- // List of groups of sleeping bodies.
84
+ CP_PRIVATE(cpArray *rousedBodies);
90
85
  CP_PRIVATE(cpArray *sleepingComponents);
91
86
 
92
- // List of bodies that have been flagged to be awoken.
93
- CP_PRIVATE(cpArray *rousedBodies);
87
+ CP_PRIVATE(cpSpatialIndex *staticShapes);
88
+ CP_PRIVATE(cpSpatialIndex *activeShapes);
94
89
 
95
- // List of active arbiters for the impulse solver.
96
90
  CP_PRIVATE(cpArray *arbiters);
97
- CP_PRIVATE(cpArray *pooledArbiters);
98
-
99
- // Linked list ring of contact buffers.
100
- // Head is the newest buffer, and each buffer points to a newer buffer.
101
- // Head wraps around and points to the oldest (tail) buffer.
102
91
  CP_PRIVATE(cpContactBufferHeader *contactBuffersHead);
103
- CP_PRIVATE(cpContactBufferHeader *_contactBuffersTail_Deprecated);
92
+ CP_PRIVATE(cpHashSet *cachedArbiters);
93
+ CP_PRIVATE(cpArray *pooledArbiters);
94
+ CP_PRIVATE(cpArray *constraints);
104
95
 
105
- // List of buffers to be free()ed when destroying the space.
106
96
  CP_PRIVATE(cpArray *allocatedBuffers);
97
+ CP_PRIVATE(int locked);
107
98
 
108
- // Persistant contact set.
109
- CP_PRIVATE(cpHashSet *contactSet);
110
-
111
- // List of constraints in the system.
112
- CP_PRIVATE(cpArray *constraints);
113
-
114
- // Set of collisionpair functions.
115
- CP_PRIVATE(cpHashSet *collFuncSet);
116
- // Default collision handler.
99
+ CP_PRIVATE(cpHashSet *collisionHandlers);
117
100
  CP_PRIVATE(cpCollisionHandler defaultHandler);
118
101
 
119
- CP_PRIVATE(cpHashSet *postStepCallbacks);
102
+ CP_PRIVATE(cpBool skipPostStep);
103
+ CP_PRIVATE(cpArray *postStepCallbacks);
120
104
 
121
- cpBody staticBody;
122
- } cpSpace;
105
+ CP_PRIVATE(cpBody _staticBody);
106
+ };
123
107
 
124
- // Basic allocation/destruction functions.
108
+ /// Allocate a cpSpace.
125
109
  cpSpace* cpSpaceAlloc(void);
110
+ /// Initialize a cpSpace.
126
111
  cpSpace* cpSpaceInit(cpSpace *space);
112
+ /// Allocate and initialize a cpSpace.
127
113
  cpSpace* cpSpaceNew(void);
128
114
 
115
+ /// Destroy a cpSpace.
129
116
  void cpSpaceDestroy(cpSpace *space);
117
+ /// Destroy and free a cpSpace.
130
118
  void cpSpaceFree(cpSpace *space);
131
119
 
132
- // Convenience function. Frees all referenced entities. (bodies, shapes and constraints)
133
- void cpSpaceFreeChildren(cpSpace *space);
120
+ #define CP_DefineSpaceStructGetter(type, member, name) \
121
+ static inline type cpSpaceGet##name(const cpSpace *space){return space->member;}
122
+
123
+ #define CP_DefineSpaceStructSetter(type, member, name) \
124
+ static inline void cpSpaceSet##name(cpSpace *space, type value){space->member = value;}
125
+
126
+ #define CP_DefineSpaceStructProperty(type, member, name) \
127
+ CP_DefineSpaceStructGetter(type, member, name) \
128
+ CP_DefineSpaceStructSetter(type, member, name)
129
+
130
+ CP_DefineSpaceStructProperty(int, iterations, Iterations)
131
+ CP_DefineSpaceStructProperty(cpVect, gravity, Gravity)
132
+ CP_DefineSpaceStructProperty(cpFloat, damping, Damping)
133
+ CP_DefineSpaceStructProperty(cpFloat, idleSpeedThreshold, IdleSpeedThreshold)
134
+ CP_DefineSpaceStructProperty(cpFloat, sleepTimeThreshold, SleepTimeThreshold)
135
+ CP_DefineSpaceStructProperty(cpFloat, collisionSlop, CollisionSlop)
136
+ CP_DefineSpaceStructProperty(cpFloat, collisionBias, CollisionBias)
137
+ CP_DefineSpaceStructProperty(cpTimestamp, collisionPersistence, CollisionPersistence)
138
+ CP_DefineSpaceStructProperty(cpBool, enableContactGraph, EnableContactGraph)
139
+ CP_DefineSpaceStructProperty(cpDataPointer, data, UserData)
140
+ CP_DefineSpaceStructGetter(cpBody*, staticBody, StaticBody)
141
+ CP_DefineSpaceStructGetter(cpFloat, CP_PRIVATE(curr_dt), CurrentTimeStep)
142
+
143
+ /// returns true from inside a callback and objects cannot be added/removed.
144
+ static inline cpBool
145
+ cpSpaceIsLocked(cpSpace *space)
146
+ {
147
+ return space->CP_PRIVATE(locked);
148
+ }
134
149
 
135
- // Collision handler management functions.
150
+ /// Set a default collision handler for this space.
151
+ /// The default collision handler is invoked for each colliding pair of shapes
152
+ /// that isn't explicitly handled by a specific collision handler.
153
+ /// You can pass NULL for any function you don't want to implement.
136
154
  void cpSpaceSetDefaultCollisionHandler(
137
155
  cpSpace *space,
138
156
  cpCollisionBeginFunc begin,
@@ -141,6 +159,9 @@ void cpSpaceSetDefaultCollisionHandler(
141
159
  cpCollisionSeparateFunc separate,
142
160
  void *data
143
161
  );
162
+
163
+ /// Set a collision handler to be used whenever the two shapes with the given collision types collide.
164
+ /// You can pass NULL for any function you don't want to implement.
144
165
  void cpSpaceAddCollisionHandler(
145
166
  cpSpace *space,
146
167
  cpCollisionType a, cpCollisionType b,
@@ -150,57 +171,106 @@ void cpSpaceAddCollisionHandler(
150
171
  cpCollisionSeparateFunc separate,
151
172
  void *data
152
173
  );
174
+
175
+ /// Unset a collision handler.
153
176
  void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b);
154
177
 
155
- // Add and remove entities from the system.
156
- cpShape *cpSpaceAddShape(cpSpace *space, cpShape *shape);
157
- cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
158
- cpBody *cpSpaceAddBody(cpSpace *space, cpBody *body);
159
- cpConstraint *cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
178
+ /// Add a collision shape to the simulation.
179
+ /// If the shape is attached to a static body, it will be added as a static shape.
180
+ cpShape* cpSpaceAddShape(cpSpace *space, cpShape *shape);
181
+ /// Explicity add a shape as a static shape to the simulation.
182
+ cpShape* cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
183
+ /// Add a rigid body to the simulation.
184
+ cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body);
185
+ /// Add a constraint to the simulation.
186
+ cpConstraint* cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
160
187
 
188
+ /// Remove a collision shape from the simulation.
161
189
  void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);
190
+ /// Remove a collision shape added using cpSpaceAddStaticShape() from the simulation.
162
191
  void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);
192
+ /// Remove a rigid body from the simulation.
163
193
  void cpSpaceRemoveBody(cpSpace *space, cpBody *body);
194
+ /// Remove a constraint from the simulation.
164
195
  void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint);
165
196
 
166
- // Post Step function definition
167
- typedef void (*cpPostStepFunc)(cpSpace *space, void *obj, void *data);
168
- // Register a post step function to be called after cpSpaceStep() has finished.
169
- // obj is used a key, you can only register one callback per unique value for obj
170
- void cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data);
197
+ /// Test if a collision shape has been added to the space.
198
+ cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape);
199
+ /// Test if a rigid body has been added to the space.
200
+ cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body);
201
+ /// Test if a constraint has been added to the space.
202
+ cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint);
171
203
 
172
- // Point query callback function
204
+ /// Post Step callback function type.
205
+ typedef void (*cpPostStepFunc)(cpSpace *space, void *key, void *data);
206
+ /// Schedule a post-step callback to be called when cpSpaceStep() finishes.
207
+ /// You can only register one callback per unique value for @c key.
208
+ /// Returns true only if @c key has never been scheduled before.
209
+ /// It's possible to pass @c NULL for @c func if you only want to mark @c key as being used.
210
+ cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data);
211
+
212
+ /// Point query callback function type.
173
213
  typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);
214
+ /// Query the space at a point and call @c func for each shape found.
174
215
  void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data);
216
+ /// Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
175
217
  cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group);
176
218
 
177
- // Segment query callback function
219
+ /// Nearest point query callback function type.
220
+ typedef void (*cpSpaceNearestPointQueryFunc)(cpShape *shape, cpFloat distance, cpVect point, void *data);
221
+ /// Query the space at a point and call @c func for each shape found.
222
+ void cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data);
223
+ /// Query the space at a point and return the nearest shape found. Returns NULL if no shapes were found.
224
+ cpShape *cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out);
225
+
226
+ /// Segment query callback function type.
178
227
  typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data);
228
+ /// Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.
179
229
  void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data);
230
+ /// Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.
180
231
  cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out);
181
232
 
182
- // BB query callback function
233
+ /// Rectangle Query callback function type.
183
234
  typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data);
235
+ /// Perform a fast rectangle query on the space calling @c func for each shape found.
236
+ /// Only the shape's bounding boxes are checked for overlap, not their full shape.
184
237
  void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data);
185
238
 
186
- // Shape query callback function
239
+ /// Shape query callback function type.
187
240
  typedef void (*cpSpaceShapeQueryFunc)(cpShape *shape, cpContactPointSet *points, void *data);
241
+ /// Query a space for any shapes overlapping the given shape and call @c func for each shape found.
188
242
  cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data);
189
243
 
190
-
244
+ /// Call cpBodyActivate() for any shape that is overlaps the given shape.
191
245
  void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape);
192
246
 
193
247
 
194
- // Iterator function for iterating the bodies in a space.
195
- typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
196
- void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
248
+ /// Space/body iterator callback function type.
249
+ typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data);
250
+ /// Call @c func for each body in the space.
251
+ void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data);
252
+
253
+ /// Space/body iterator callback function type.
254
+ typedef void (*cpSpaceShapeIteratorFunc)(cpShape *shape, void *data);
255
+ /// Call @c func for each shape in the space.
256
+ void cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data);
197
257
 
198
- // Spatial hash management functions.
199
- void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);
200
- void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);
201
- void cpSpaceRehashStatic(cpSpace *space);
258
+ /// Space/constraint iterator callback function type.
259
+ typedef void (*cpSpaceConstraintIteratorFunc)(cpConstraint *constraint, void *data);
260
+ /// Call @c func for each shape in the space.
261
+ void cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data);
202
262
 
203
- void cpSpaceRehashShape(cpSpace *space, cpShape *shape);
263
+ /// Update the collision detection info for the static shapes in the space.
264
+ void cpSpaceReindexStatic(cpSpace *space);
265
+ /// Update the collision detection data for a specific shape in the space.
266
+ void cpSpaceReindexShape(cpSpace *space, cpShape *shape);
267
+ /// Update the collision detection data for all shapes attached to a body.
268
+ void cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body);
204
269
 
205
- // Update the space.
270
+ /// Switch the space to use a spatial has as it's spatial index.
271
+ void cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count);
272
+
273
+ /// Step the space forward in time by @c dt.
206
274
  void cpSpaceStep(cpSpace *space, cpFloat dt);
275
+
276
+ /// @}
@@ -19,74 +19,121 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
22
+ #include <string.h>
23
23
 
24
24
  #include "chipmunk_private.h"
25
25
 
26
- #pragma mark Sleeping Functions
26
+ //MARK: Sleeping Functions
27
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)
28
+ void
29
+ cpSpaceActivateBody(cpSpace *space, cpBody *body)
34
30
  {
35
- cpBody *parent = body->node.parent;
31
+ cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rogue body.");
36
32
 
37
- if(parent){
38
- // path compression, attaches this node directly to the root
39
- return (body->node.parent = componentNodeRoot(parent));
33
+ if(space->locked){
34
+ // cpSpaceActivateBody() is called again once the space is unlocked
35
+ if(!cpArrayContains(space->rousedBodies, body)) cpArrayPush(space->rousedBodies, body);
40
36
  } else {
41
- return body;
37
+ cpArrayPush(space->bodies, body);
38
+
39
+ CP_BODY_FOREACH_SHAPE(body, shape){
40
+ cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid);
41
+ cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid);
42
+ }
43
+
44
+ CP_BODY_FOREACH_ARBITER(body, arb){
45
+ cpBody *bodyA = arb->body_a;
46
+
47
+ // Arbiters are shared between two bodies that are always woken up together.
48
+ // You only want to restore the arbiter once, so bodyA is arbitrarily chosen to own the arbiter.
49
+ // The edge case is when static bodies are involved as the static bodies never actually sleep.
50
+ // If the static body is bodyB then all is good. If the static body is bodyA, that can easily be checked.
51
+ if(body == bodyA || cpBodyIsStatic(bodyA)){
52
+ int numContacts = arb->numContacts;
53
+ cpContact *contacts = arb->contacts;
54
+
55
+ // Restore contact values back to the space's contact buffer memory
56
+ arb->contacts = cpContactBufferGetArray(space);
57
+ memcpy(arb->contacts, contacts, numContacts*sizeof(cpContact));
58
+ cpSpacePushContacts(space, numContacts);
59
+
60
+ // Reinsert the arbiter into the arbiter cache
61
+ cpShape *a = arb->a, *b = arb->b;
62
+ cpShape *shape_pair[] = {a, b};
63
+ cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);
64
+ cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, arb, NULL);
65
+
66
+ // Update the arbiter's state
67
+ arb->stamp = space->stamp;
68
+ arb->handler = cpSpaceLookupHandler(space, a->collision_type, b->collision_type);
69
+ cpArrayPush(space->arbiters, arb);
70
+
71
+ cpfree(contacts);
72
+ }
73
+ }
74
+
75
+ CP_BODY_FOREACH_CONSTRAINT(body, constraint){
76
+ cpBody *bodyA = constraint->a;
77
+ if(body == bodyA || cpBodyIsStatic(bodyA)) cpArrayPush(space->constraints, constraint);
78
+ }
42
79
  }
43
80
  }
44
81
 
45
- static inline void
46
- componentNodeMerge(cpBody *a_root, cpBody *b_root)
82
+ static void
83
+ cpSpaceDeactivateBody(cpSpace *space, cpBody *body)
47
84
  {
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++;
85
+ cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to deactivate a rouge body.");
86
+
87
+ cpArrayDeleteObj(space->bodies, body);
88
+
89
+ CP_BODY_FOREACH_SHAPE(body, shape){
90
+ cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid);
91
+ cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid);
92
+ }
93
+
94
+ CP_BODY_FOREACH_ARBITER(body, arb){
95
+ cpBody *bodyA = arb->body_a;
96
+ if(body == bodyA || cpBodyIsStatic(bodyA)){
97
+ cpSpaceUncacheArbiter(space, arb);
98
+
99
+ // Save contact values to a new block of memory so they won't time out
100
+ size_t bytes = arb->numContacts*sizeof(cpContact);
101
+ cpContact *contacts = (cpContact *)cpcalloc(1, bytes);
102
+ memcpy(contacts, arb->contacts, bytes);
103
+ arb->contacts = contacts;
104
+ }
105
+ }
106
+
107
+ CP_BODY_FOREACH_CONSTRAINT(body, constraint){
108
+ cpBody *bodyA = constraint->a;
109
+ if(body == bodyA || cpBodyIsStatic(bodyA)) cpArrayDeleteObj(space->constraints, constraint);
55
110
  }
56
111
  }
57
112
 
58
- void
59
- cpSpaceActivateBody(cpSpace *space, cpBody *body)
113
+ static inline cpBody *
114
+ ComponentRoot(cpBody *body)
60
115
  {
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
- }
116
+ return (body ? body->node.root : NULL);
71
117
  }
72
118
 
73
119
  static inline void
74
- componentActivate(cpBody *root)
120
+ ComponentActivate(cpBody *root)
75
121
  {
76
- if(!cpBodyIsSleeping(root)) return;
122
+ if(!root || !cpBodyIsSleeping(root)) return;
123
+ cpAssertHard(!cpBodyIsRogue(root), "Internal Error: ComponentActivate() called on a rogue body.");
77
124
 
78
125
  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;
126
+ cpBody *body = root;
127
+ while(body){
128
+ cpBody *next = body->node.next;
87
129
 
130
+ body->node.idleTime = 0.0f;
131
+ body->node.root = NULL;
132
+ body->node.next = NULL;
88
133
  cpSpaceActivateBody(space, body);
89
- } while((body = next) != root);
134
+
135
+ body = next;
136
+ }
90
137
 
91
138
  cpArrayDeleteObj(space->sleepingComponents, root);
92
139
  }
@@ -94,136 +141,167 @@ componentActivate(cpBody *root)
94
141
  void
95
142
  cpBodyActivate(cpBody *body)
96
143
  {
97
- componentActivate(componentNodeRoot(body));
144
+ if(!cpBodyIsRogue(body)){
145
+ body->node.idleTime = 0.0f;
146
+ ComponentActivate(ComponentRoot(body));
147
+ }
148
+
149
+ CP_BODY_FOREACH_ARBITER(body, arb){
150
+ // Reset the idle timer of things the body is touching as well.
151
+ // That way things don't get left hanging in the air.
152
+ cpBody *other = (arb->body_a == body ? arb->body_b : arb->body_a);
153
+ if(!cpBodyIsStatic(other)) other->node.idleTime = 0.0f;
154
+ }
98
155
  }
99
156
 
100
- static inline void
101
- mergeBodies(cpSpace *space, cpArray *components, cpArray *rogueBodies, cpBody *a, cpBody *b)
157
+ void
158
+ cpBodyActivateStatic(cpBody *body, cpShape *filter)
102
159
  {
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);
160
+ cpAssertHard(cpBodyIsStatic(body), "cpBodyActivateStatic() called on a non-static body.");
111
161
 
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; }
162
+ CP_BODY_FOREACH_ARBITER(body, arb){
163
+ if(!filter || filter == arb->a || filter == arb->b){
164
+ cpBodyActivate(arb->body_a == body ? arb->body_b : arb->body_a);
165
+ }
166
+ }
122
167
 
123
- componentNodeMerge(a_root, b_root);
168
+ // TODO should also activate joints?
124
169
  }
125
170
 
126
- static inline cpBool
127
- componentActive(cpBody *root, cpFloat threshold)
171
+ static inline void
172
+ cpBodyPushArbiter(cpBody *body, cpArbiter *arb)
128
173
  {
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);
174
+ cpAssertSoft(cpArbiterThreadForBody(arb, body)->next == NULL, "Internal Error: Dangling contact graph pointers detected. (A)");
175
+ cpAssertSoft(cpArbiterThreadForBody(arb, body)->prev == NULL, "Internal Error: Dangling contact graph pointers detected. (B)");
134
176
 
135
- return cpFalse;
177
+ cpArbiter *next = body->arbiterList;
178
+ cpAssertSoft(next == NULL || cpArbiterThreadForBody(next, body)->prev == NULL, "Internal Error: Dangling contact graph pointers detected. (C)");
179
+ cpArbiterThreadForBody(arb, body)->next = next;
180
+
181
+ if(next) cpArbiterThreadForBody(next, body)->prev = arb;
182
+ body->arbiterList = arb;
136
183
  }
137
184
 
138
185
  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;
186
+ ComponentAdd(cpBody *root, cpBody *body){
187
+ body->node.root = root;
188
+
189
+ if(body != root){
190
+ body->node.next = root->node.next;
156
191
  root->node.next = body;
157
192
  }
158
193
  }
159
194
 
160
- // TODO this function needs more commenting.
195
+ static inline void
196
+ FloodFillComponent(cpBody *root, cpBody *body)
197
+ {
198
+ // Rogue bodies cannot be put to sleep and prevent bodies they are touching from sleepining anyway.
199
+ // Static bodies (which are a type of rogue body) are effectively sleeping all the time.
200
+ if(!cpBodyIsRogue(body)){
201
+ cpBody *other_root = ComponentRoot(body);
202
+ if(other_root == NULL){
203
+ ComponentAdd(root, body);
204
+ CP_BODY_FOREACH_ARBITER(body, arb) FloodFillComponent(root, (body == arb->body_a ? arb->body_b : arb->body_a));
205
+ CP_BODY_FOREACH_CONSTRAINT(body, constraint) FloodFillComponent(root, (body == constraint->a ? constraint->b : constraint->a));
206
+ } else {
207
+ cpAssertSoft(other_root == root, "Internal Error: Inconsistency dectected in the contact graph.");
208
+ }
209
+ }
210
+ }
211
+
212
+ static inline cpBool
213
+ ComponentActive(cpBody *root, cpFloat threshold)
214
+ {
215
+ CP_BODY_FOREACH_COMPONENT(root, body){
216
+ if(body->node.idleTime < threshold) return cpTrue;
217
+ }
218
+
219
+ return cpFalse;
220
+ }
221
+
161
222
  void
162
223
  cpSpaceProcessComponents(cpSpace *space, cpFloat dt)
163
224
  {
225
+ cpBool sleep = (space->sleepTimeThreshold != INFINITY);
164
226
  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
227
 
174
- // update idling
228
+ #ifndef NDEBUG
175
229
  for(int i=0; i<bodies->num; i++){
176
230
  cpBody *body = (cpBody*)bodies->arr[i];
177
231
 
178
- cpFloat thresh = (dvsq ? body->m*dvsq : 0.0f);
179
- body->node.idleTime = (cpBodyKineticEnergy(body) > thresh ? 0.0f : body->node.idleTime + dt);
232
+ cpAssertSoft(body->node.next == NULL, "Internal Error: Dangling next pointer detected in contact graph.");
233
+ cpAssertSoft(body->node.root == NULL, "Internal Error: Dangling root pointer detected in contact graph.");
180
234
  }
235
+ #endif
181
236
 
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);
237
+ // Calculate the kinetic energy of all the bodies.
238
+ if(sleep){
239
+ cpFloat dv = space->idleSpeedThreshold;
240
+ cpFloat dvsq = (dv ? dv*dv : cpvlengthsq(space->gravity)*dt*dt);
241
+
242
+ // update idling and reset component nodes
243
+ for(int i=0; i<bodies->num; i++){
244
+ cpBody *body = (cpBody*)bodies->arr[i];
245
+
246
+ // Need to deal with infinite mass objects
247
+ cpFloat keThreshold = (dvsq ? body->m*dvsq : 0.0f);
248
+ body->node.idleTime = (cpBodyKineticEnergy(body) > keThreshold ? 0.0f : body->node.idleTime + dt);
249
+ }
190
250
  }
191
251
 
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);
252
+ // Awaken any sleeping bodies found and then push arbiters to the bodies' lists.
253
+ cpArray *arbiters = space->arbiters;
254
+ for(int i=0, count=arbiters->num; i<count; i++){
255
+ cpArbiter *arb = (cpArbiter*)arbiters->arr[i];
256
+ cpBody *a = arb->body_a, *b = arb->body_b;
257
+
258
+ if(sleep){
259
+ if((cpBodyIsRogue(b) && !cpBodyIsStatic(b)) || cpBodyIsSleeping(a)) cpBodyActivate(a);
260
+ if((cpBodyIsRogue(a) && !cpBodyIsStatic(a)) || cpBodyIsSleeping(b)) cpBodyActivate(b);
261
+ }
262
+
263
+ cpBodyPushArbiter(a, arb);
264
+ cpBodyPushArbiter(b, arb);
265
+ }
195
266
 
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;
267
+ if(sleep){
268
+ // Bodies should be held active if connected by a joint to a non-static rouge body.
269
+ cpArray *constraints = space->constraints;
270
+ for(int i=0; i<constraints->num; i++){
271
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
272
+ cpBody *a = constraint->a, *b = constraint->b;
273
+
274
+ if(cpBodyIsRogue(b) && !cpBodyIsStatic(b)) cpBodyActivate(a);
275
+ if(cpBodyIsRogue(a) && !cpBodyIsStatic(a)) cpBodyActivate(b);
276
+ }
277
+
278
+ // Generate components and deactivate sleeping ones
279
+ for(int i=0; i<bodies->num;){
280
+ cpBody *body = (cpBody*)bodies->arr[i];
281
+
282
+ if(ComponentRoot(body) == NULL){
283
+ // Body not in a component yet. Perform a DFS to flood fill mark
284
+ // the component in the contact graph using this body as the root.
285
+ FloodFillComponent(body, body);
212
286
 
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);
287
+ // Check if the component should be put to sleep.
288
+ if(!ComponentActive(body, space->sleepTimeThreshold)){
289
+ cpArrayPush(space->sleepingComponents, body);
290
+ CP_BODY_FOREACH_COMPONENT(body, other) cpSpaceDeactivateBody(space, other);
291
+
292
+ // cpSpaceDeactivateBody() removed the current body from the list.
293
+ // Skip incrementing the index counter.
294
+ continue;
216
295
  }
217
- } while((body = next) != root);
296
+ }
218
297
 
219
- cpArrayPush(space->sleepingComponents, root);
298
+ i++;
299
+
300
+ // Only sleeping bodies retain their component node pointers.
301
+ body->node.root = NULL;
302
+ body->node.next = NULL;
220
303
  }
221
304
  }
222
-
223
- space->bodies = newBodies;
224
- cpArrayFree(bodies);
225
- cpArrayFree(rogueBodies);
226
- cpArrayFree(components);
227
305
  }
228
306
 
229
307
  void
@@ -234,29 +312,29 @@ cpBodySleep(cpBody *body)
234
312
 
235
313
  void
236
314
  cpBodySleepWithGroup(cpBody *body, cpBody *group){
237
- cpAssert(!cpBodyIsStatic(body) && !cpBodyIsRogue(body), "Rogue and static bodies cannot be put to sleep.");
315
+ cpAssertHard(!cpBodyIsRogue(body), "Rogue (and static) bodies cannot be put to sleep.");
238
316
 
239
317
  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;
318
+ cpAssertHard(!space->locked, "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback.");
319
+ cpAssertHard(group == NULL || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier.");
245
320
 
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);
321
+ if(cpBodyIsSleeping(body)){
322
+ cpAssertHard(ComponentRoot(body) == ComponentRoot(group), "The body is already sleeping and it's group cannot be reassigned.");
323
+ return;
250
324
  }
251
325
 
326
+ CP_BODY_FOREACH_SHAPE(body, shape) cpShapeUpdate(shape, body->p, body->rot);
327
+ cpSpaceDeactivateBody(space, body);
328
+
252
329
  if(group){
253
- cpBody *root = componentNodeRoot(group);
330
+ cpBody *root = ComponentRoot(group);
254
331
 
255
- cpComponentNode node = {root, root->node.next, 0, 0.0f};
332
+ cpComponentNode node = {root, root->node.next, 0.0f};
256
333
  body->node = node;
334
+
257
335
  root->node.next = body;
258
336
  } else {
259
- cpComponentNode node = {NULL, body, 0, 0.0f};
337
+ cpComponentNode node = {body, NULL, 0.0f};
260
338
  body->node = node;
261
339
 
262
340
  cpArrayPush(space->sleepingComponents, body);
@@ -266,14 +344,13 @@ cpBodySleepWithGroup(cpBody *body, cpBody *group){
266
344
  }
267
345
 
268
346
  static void
269
- activateTouchingHelper(cpShape *shape, cpContactPointSet *points, cpArray **bodies){
347
+ activateTouchingHelper(cpShape *shape, cpContactPointSet *points, cpShape *other){
270
348
  cpBodyActivate(shape->body);
271
349
  }
272
350
 
273
351
  void
274
352
  cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape){
275
- cpArray *bodies = NULL;
276
- cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)activateTouchingHelper, &bodies);
353
+ if(space->sleepTimeThreshold != INFINITY){
354
+ cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)activateTouchingHelper, shape);
355
+ }
277
356
  }
278
-
279
-