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.
- 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
|
-
|