chipmunk 5.3.4.5 → 6.1.3.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/ext/chipmunk/chipmunk.c +199 -28
  2. data/ext/chipmunk/chipmunk.h +123 -68
  3. data/ext/chipmunk/chipmunk_ffi.h +129 -11
  4. data/ext/chipmunk/chipmunk_private.h +232 -16
  5. data/ext/chipmunk/chipmunk_types.h +94 -30
  6. data/ext/chipmunk/chipmunk_unsafe.h +12 -3
  7. data/ext/chipmunk/constraints/cpConstraint.h +90 -34
  8. data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
  9. data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
  10. data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
  11. data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
  12. data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
  13. data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
  14. data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
  15. data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
  16. data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
  17. data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
  18. data/ext/chipmunk/constraints/util.h +36 -44
  19. data/ext/chipmunk/cpArbiter.c +159 -94
  20. data/ext/chipmunk/cpArbiter.h +135 -129
  21. data/ext/chipmunk/cpArray.c +37 -56
  22. data/ext/chipmunk/cpBB.c +1 -12
  23. data/ext/chipmunk/cpBB.h +80 -18
  24. data/ext/chipmunk/cpBBTree.c +891 -0
  25. data/ext/chipmunk/cpBody.c +185 -47
  26. data/ext/chipmunk/cpBody.h +156 -124
  27. data/ext/chipmunk/cpCollision.c +126 -115
  28. data/ext/chipmunk/cpConstraint.c +10 -6
  29. data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
  30. data/ext/chipmunk/cpDampedSpring.c +25 -18
  31. data/ext/chipmunk/cpGearJoint.c +23 -17
  32. data/ext/chipmunk/cpGrooveJoint.c +26 -22
  33. data/ext/chipmunk/cpHashSet.c +51 -51
  34. data/ext/chipmunk/cpPinJoint.c +26 -19
  35. data/ext/chipmunk/cpPivotJoint.c +23 -19
  36. data/ext/chipmunk/cpPolyShape.c +93 -69
  37. data/ext/chipmunk/cpPolyShape.h +33 -69
  38. data/ext/chipmunk/cpRatchetJoint.c +26 -21
  39. data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
  40. data/ext/chipmunk/cpShape.c +122 -133
  41. data/ext/chipmunk/cpShape.h +146 -95
  42. data/ext/chipmunk/cpSimpleMotor.c +24 -17
  43. data/ext/chipmunk/cpSlideJoint.c +28 -26
  44. data/ext/chipmunk/cpSpace.c +251 -196
  45. data/ext/chipmunk/cpSpace.h +173 -103
  46. data/ext/chipmunk/cpSpaceComponent.c +236 -159
  47. data/ext/chipmunk/cpSpaceHash.c +259 -159
  48. data/ext/chipmunk/cpSpaceQuery.c +127 -59
  49. data/ext/chipmunk/cpSpaceStep.c +235 -197
  50. data/ext/chipmunk/cpSpatialIndex.c +69 -0
  51. data/ext/chipmunk/cpSpatialIndex.h +227 -0
  52. data/ext/chipmunk/cpSweep1D.c +254 -0
  53. data/ext/chipmunk/cpVect.c +11 -26
  54. data/ext/chipmunk/cpVect.h +76 -71
  55. data/ext/chipmunk/extconf.rb +4 -31
  56. data/ext/chipmunk/prime.h +1 -1
  57. data/ext/chipmunk/rb_chipmunk.c +36 -45
  58. data/ext/chipmunk/rb_chipmunk.h +6 -3
  59. data/ext/chipmunk/rb_cpArbiter.c +2 -2
  60. data/ext/chipmunk/rb_cpBB.c +116 -35
  61. data/ext/chipmunk/rb_cpBody.c +5 -12
  62. data/ext/chipmunk/rb_cpConstraint.c +144 -9
  63. data/ext/chipmunk/rb_cpShape.c +69 -78
  64. data/ext/chipmunk/rb_cpSpace.c +81 -76
  65. metadata +61 -61
  66. data/LICENSE +0 -22
  67. data/README +0 -110
  68. data/Rakefile +0 -102
  69. data/ext/chipmunk/cpArray.h +0 -49
  70. data/ext/chipmunk/cpCollision.h +0 -28
  71. data/ext/chipmunk/cpHashSet.h +0 -82
  72. data/ext/chipmunk/cpSpaceHash.h +0 -110
  73. data/lib/chipmunk.rb +0 -194
@@ -19,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
-