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.
- data/ext/chipmunk/chipmunk.c +199 -28
- data/ext/chipmunk/chipmunk.h +123 -68
- data/ext/chipmunk/chipmunk_ffi.h +129 -11
- data/ext/chipmunk/chipmunk_private.h +232 -16
- data/ext/chipmunk/chipmunk_types.h +94 -30
- data/ext/chipmunk/chipmunk_unsafe.h +12 -3
- data/ext/chipmunk/constraints/cpConstraint.h +90 -34
- data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
- data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
- data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
- data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
- data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
- data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
- data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
- data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
- data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
- data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
- data/ext/chipmunk/constraints/util.h +36 -44
- data/ext/chipmunk/cpArbiter.c +159 -94
- data/ext/chipmunk/cpArbiter.h +135 -129
- data/ext/chipmunk/cpArray.c +37 -56
- data/ext/chipmunk/cpBB.c +1 -12
- data/ext/chipmunk/cpBB.h +80 -18
- data/ext/chipmunk/cpBBTree.c +891 -0
- data/ext/chipmunk/cpBody.c +185 -47
- data/ext/chipmunk/cpBody.h +156 -124
- data/ext/chipmunk/cpCollision.c +126 -115
- data/ext/chipmunk/cpConstraint.c +10 -6
- data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
- data/ext/chipmunk/cpDampedSpring.c +25 -18
- data/ext/chipmunk/cpGearJoint.c +23 -17
- data/ext/chipmunk/cpGrooveJoint.c +26 -22
- data/ext/chipmunk/cpHashSet.c +51 -51
- data/ext/chipmunk/cpPinJoint.c +26 -19
- data/ext/chipmunk/cpPivotJoint.c +23 -19
- data/ext/chipmunk/cpPolyShape.c +93 -69
- data/ext/chipmunk/cpPolyShape.h +33 -69
- data/ext/chipmunk/cpRatchetJoint.c +26 -21
- data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
- data/ext/chipmunk/cpShape.c +122 -133
- data/ext/chipmunk/cpShape.h +146 -95
- data/ext/chipmunk/cpSimpleMotor.c +24 -17
- data/ext/chipmunk/cpSlideJoint.c +28 -26
- data/ext/chipmunk/cpSpace.c +251 -196
- data/ext/chipmunk/cpSpace.h +173 -103
- data/ext/chipmunk/cpSpaceComponent.c +236 -159
- data/ext/chipmunk/cpSpaceHash.c +259 -159
- data/ext/chipmunk/cpSpaceQuery.c +127 -59
- data/ext/chipmunk/cpSpaceStep.c +235 -197
- data/ext/chipmunk/cpSpatialIndex.c +69 -0
- data/ext/chipmunk/cpSpatialIndex.h +227 -0
- data/ext/chipmunk/cpSweep1D.c +254 -0
- data/ext/chipmunk/cpVect.c +11 -26
- data/ext/chipmunk/cpVect.h +76 -71
- data/ext/chipmunk/extconf.rb +4 -31
- data/ext/chipmunk/prime.h +1 -1
- data/ext/chipmunk/rb_chipmunk.c +36 -45
- data/ext/chipmunk/rb_chipmunk.h +6 -3
- data/ext/chipmunk/rb_cpArbiter.c +2 -2
- data/ext/chipmunk/rb_cpBB.c +116 -35
- data/ext/chipmunk/rb_cpBody.c +5 -12
- data/ext/chipmunk/rb_cpConstraint.c +144 -9
- data/ext/chipmunk/rb_cpShape.c +69 -78
- data/ext/chipmunk/rb_cpSpace.c +81 -76
- metadata +61 -61
- data/LICENSE +0 -22
- data/README +0 -110
- data/Rakefile +0 -102
- data/ext/chipmunk/cpArray.h +0 -49
- data/ext/chipmunk/cpCollision.h +0 -28
- data/ext/chipmunk/cpHashSet.h +0 -82
- data/ext/chipmunk/cpSpaceHash.h +0 -110
- data/lib/chipmunk.rb +0 -194
data/ext/chipmunk/cpSpace.h
CHANGED
@@ -19,120 +19,138 @@
|
|
19
19
|
* SOFTWARE.
|
20
20
|
*/
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
71
|
-
|
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
|
-
|
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
|
-
|
77
|
-
|
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
|
-
|
93
|
-
CP_PRIVATE(
|
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(
|
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
|
-
|
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(
|
102
|
+
CP_PRIVATE(cpBool skipPostStep);
|
103
|
+
CP_PRIVATE(cpArray *postStepCallbacks);
|
120
104
|
|
121
|
-
cpBody
|
122
|
-
}
|
105
|
+
CP_PRIVATE(cpBody _staticBody);
|
106
|
+
};
|
123
107
|
|
124
|
-
|
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
|
-
|
133
|
-
|
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
|
-
|
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
|
-
|
156
|
-
|
157
|
-
cpShape
|
158
|
-
|
159
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
195
|
-
typedef void (*
|
196
|
-
|
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
|
-
|
199
|
-
void
|
200
|
-
|
201
|
-
void
|
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
|
-
|
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
|
-
|
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 <
|
22
|
+
#include <string.h>
|
23
23
|
|
24
24
|
#include "chipmunk_private.h"
|
25
25
|
|
26
|
-
|
26
|
+
//MARK: Sleeping Functions
|
27
27
|
|
28
|
-
|
29
|
-
|
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
|
-
|
31
|
+
cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rogue body.");
|
36
32
|
|
37
|
-
if(
|
38
|
-
//
|
39
|
-
|
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
|
-
|
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
|
46
|
-
|
82
|
+
static void
|
83
|
+
cpSpaceDeactivateBody(cpSpace *space, cpBody *body)
|
47
84
|
{
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
59
|
-
|
113
|
+
static inline cpBody *
|
114
|
+
ComponentRoot(cpBody *body)
|
60
115
|
{
|
61
|
-
|
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
|
-
|
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
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
101
|
-
|
157
|
+
void
|
158
|
+
cpBodyActivateStatic(cpBody *body, cpShape *filter)
|
102
159
|
{
|
103
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
168
|
+
// TODO should also activate joints?
|
124
169
|
}
|
125
170
|
|
126
|
-
static inline
|
127
|
-
|
171
|
+
static inline void
|
172
|
+
cpBodyPushArbiter(cpBody *body, cpArbiter *arb)
|
128
173
|
{
|
129
|
-
|
130
|
-
|
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
|
-
|
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
|
-
|
140
|
-
|
141
|
-
|
142
|
-
if(body
|
143
|
-
|
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
|
-
|
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
|
-
|
228
|
+
#ifndef NDEBUG
|
175
229
|
for(int i=0; i<bodies->num; i++){
|
176
230
|
cpBody *body = (cpBody*)bodies->arr[i];
|
177
231
|
|
178
|
-
|
179
|
-
body->node.
|
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
|
-
//
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
-
//
|
193
|
-
|
194
|
-
for(int i=0; i<
|
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
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
cpBody *body =
|
210
|
-
|
211
|
-
|
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
|
-
|
214
|
-
|
215
|
-
|
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
|
-
}
|
296
|
+
}
|
218
297
|
|
219
|
-
|
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
|
-
|
315
|
+
cpAssertHard(!cpBodyIsRogue(body), "Rogue (and static) bodies cannot be put to sleep.");
|
238
316
|
|
239
317
|
cpSpace *space = body->space;
|
240
|
-
|
241
|
-
|
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
|
-
|
247
|
-
|
248
|
-
|
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 =
|
330
|
+
cpBody *root = ComponentRoot(group);
|
254
331
|
|
255
|
-
cpComponentNode node = {root, root->node.next, 0
|
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 = {
|
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,
|
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
|
-
|
276
|
-
|
353
|
+
if(space->sleepTimeThreshold != INFINITY){
|
354
|
+
cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)activateTouchingHelper, shape);
|
355
|
+
}
|
277
356
|
}
|
278
|
-
|
279
|
-
|