4
|
1
|
|
2 // written in the D programming language
|
|
3
|
|
4 module chipmunkd.cpSpace;
|
|
5
|
|
6 import chipmunkd.chipmunk;
|
|
7
|
|
8 // Number of frames that contact information should persist.
|
|
9 //extern cpTimestamp cp_contact_persistence;
|
|
10
|
|
11 // User collision handler function types.
|
|
12 alias cpBool function(cpArbiter *arb, cpSpace *space, void *data)cpCollisionBeginFunc;
|
|
13 alias cpBool function(cpArbiter *arb, cpSpace *space, void *data)cpCollisionPreSolveFunc;
|
|
14 alias void function(cpArbiter *arb, cpSpace *space, void *data)cpCollisionPostSolveFunc;
|
|
15 alias void function(cpArbiter *arb, cpSpace *space, void *data)cpCollisionSeparateFunc;
|
|
16
|
|
17 // Structure for holding collision pair function information.
|
|
18 // Used internally.
|
|
19 struct cpCollisionHandler {
|
|
20 cpCollisionType a;
|
|
21 cpCollisionType b;
|
|
22 cpCollisionBeginFunc begin;
|
|
23 cpCollisionPreSolveFunc preSolve;
|
|
24 cpCollisionPostSolveFunc postSolve;
|
|
25 cpCollisionSeparateFunc separate;
|
|
26 void *data;
|
|
27 }
|
|
28
|
|
29 struct cpContactBufferHeader {
|
|
30 cpTimestamp stamp;
|
|
31 cpContactBufferHeader *next;
|
|
32 uint numContacts;
|
|
33 }
|
|
34
|
|
35 struct cpSpace{
|
|
36 // *** User definable fields
|
|
37
|
|
38 // Number of iterations to use in the impulse solver to solve contacts.
|
|
39 int iterations;
|
|
40
|
|
41 // Number of iterations to use in the impulse solver to solve elastic collisions.
|
|
42 int elasticIterations;
|
|
43
|
|
44 // Default gravity to supply when integrating rigid body motions.
|
|
45 cpVect gravity;
|
|
46
|
|
47 // Default damping to supply when integrating rigid body motions.
|
|
48 cpFloat damping;
|
|
49
|
|
50 // Speed threshold for a body to be considered idle.
|
|
51 // The default value of 0 means to let the space guess a good threshold based on gravity.
|
|
52 cpFloat idleSpeedThreshold;
|
|
53
|
|
54 // Time a group of bodies must remain idle in order to fall asleep
|
|
55 // The default value of INFINITY disables the sleeping algorithm.
|
|
56 cpFloat sleepTimeThreshold;
|
|
57
|
|
58 // *** Internally Used Fields
|
|
59
|
|
60 // When the space is locked, you should not add or remove objects;
|
|
61 cpBool locked;
|
|
62
|
|
63 // Time stamp. Is incremented on every call to cpSpaceStep().
|
|
64 cpTimestamp stamp;
|
|
65
|
|
66 // The static and active shape spatial hashes.
|
|
67 cpSpaceHash* staticShapes;
|
|
68 cpSpaceHash* activeShapes;
|
|
69
|
|
70 // List of bodies in the system.
|
|
71 cpArray *bodies;
|
|
72
|
|
73 // List of groups of sleeping bodies.
|
|
74 cpArray *sleepingComponents;
|
|
75
|
|
76 // List of active arbiters for the impulse solver.
|
|
77 cpArray* arbiters, pooledArbiters;
|
|
78
|
|
79 // Linked list ring of contact buffers.
|
|
80 // Head is the newest buffer, and each buffer points to a newer buffer.
|
|
81 // Head wraps around and points to the oldest (tail) buffer.
|
23
|
82 cpContactBufferHeader* contactBuffersHead;
|
|
83 deprecated cpContactBufferHeader* _contactBuffersTail_Deprecated;
|
4
|
84
|
|
85 // List of buffers to be free()ed when destroying the space.
|
|
86 cpArray *allocatedBuffers;
|
|
87
|
|
88 // Persistant contact set.
|
|
89 cpHashSet *contactSet;
|
|
90
|
|
91 // List of constraints in the system.
|
|
92 cpArray *constraints;
|
|
93
|
|
94 // Set of collisionpair functions.
|
|
95 cpHashSet *collFuncSet;
|
|
96 // Default collision handler.
|
|
97 cpCollisionHandler defaultHandler;
|
|
98
|
|
99 cpHashSet *postStepCallbacks;
|
|
100
|
|
101 cpBody staticBody;
|
|
102 }
|
|
103
|
|
104 //// Basic allocation/destruction functions.
|
|
105 //cpSpace* cpSpaceAlloc(void);
|
|
106 //cpSpace* cpSpaceInit(cpSpace *space);
|
|
107 //cpSpace* cpSpaceNew(void);
|
|
108 //
|
|
109 //void cpSpaceDestroy(cpSpace *space);
|
|
110 //void cpSpaceFree(cpSpace *space);
|
|
111 //
|
|
112 //// Convenience function. Frees all referenced entities. (bodies, shapes and constraints)
|
|
113 //void cpSpaceFreeChildren(cpSpace *space);
|
|
114 //
|
|
115 //// Collision handler management functions.
|
|
116 //void cpSpaceSetDefaultCollisionHandler(
|
|
117 // cpSpace *space,
|
|
118 // cpCollisionBeginFunc begin,
|
|
119 // cpCollisionPreSolveFunc preSolve,
|
|
120 // cpCollisionPostSolveFunc postSolve,
|
|
121 // cpCollisionSeparateFunc separate,
|
|
122 // void *data
|
|
123 //);
|
|
124 //void cpSpaceAddCollisionHandler(
|
|
125 // cpSpace *space,
|
|
126 // cpCollisionType a, cpCollisionType b,
|
|
127 // cpCollisionBeginFunc begin,
|
|
128 // cpCollisionPreSolveFunc preSolve,
|
|
129 // cpCollisionPostSolveFunc postSolve,
|
|
130 // cpCollisionSeparateFunc separate,
|
|
131 // void *data
|
|
132 //);
|
|
133 //void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b);
|
|
134 //
|
|
135 //// Add and remove entities from the system.
|
|
136 //cpShape *cpSpaceAddShape(cpSpace *space, cpShape *shape);
|
|
137 //cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
|
|
138 //cpBody *cpSpaceAddBody(cpSpace *space, cpBody *body);
|
|
139 //cpConstraint *cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
|
|
140 //
|
|
141 //void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);
|
|
142 //void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);
|
|
143 //void cpSpaceRemoveBody(cpSpace *space, cpBody *body);
|
|
144 //void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint);
|
|
145 //
|
|
146 //// Post Step function definition
|
|
147 alias void function(cpSpace *space, void *obj, void *data) cpPostStepFunc;
|
|
148 //// Register a post step function to be called after cpSpaceStep() has finished.
|
|
149 //// obj is used a key, you can only register one callback per unique value for obj
|
|
150 //void cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data);
|
|
151 //
|
|
152 //// Point query callback function
|
|
153 alias void function(cpShape *shape, void *data) cpSpacePointQueryFunc;
|
|
154 //void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data);
|
|
155 //cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group);
|
|
156 //
|
|
157 //// Segment query callback function
|
|
158 alias void function(cpShape *shape, cpFloat t, cpVect n, void *data)cpSpaceSegmentQueryFunc;
|
|
159 //void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data);
|
|
160 //cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out);
|
|
161 //
|
|
162 //// BB query callback function
|
|
163 alias void function(cpShape *shape, void *data)cpSpaceBBQueryFunc;
|
|
164 //void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data);
|
23
|
165
|
|
166 // Shape query callback function
|
|
167 alias void function(cpShape *shape, cpContactPointSet *points, void *data)cpSpaceShapeQueryFunc;
|
|
168 //cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data);
|
|
169
|
|
170
|
|
171 //void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape);
|
|
172
|
4
|
173 //// Iterator function for iterating the bodies in a space.
|
|
174 alias void function(cpBody *_body, void *data)cpSpaceBodyIterator;
|
|
175 //void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
|
|
176 //
|
|
177 //// Spatial hash management functions.
|
|
178 //void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);
|
|
179 //void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);
|
|
180 //void cpSpaceRehashStatic(cpSpace *space);
|
|
181 //
|
|
182 //void cpSpaceRehashShape(cpSpace *space, cpShape *shape);
|
|
183 //
|
|
184 //// Update the space.
|
|
185 //void cpSpaceStep(cpSpace *space, cpFloat dt);
|
|
186
|
|
187
|
|
188 cpTimestamp cp_contact_persistence = 3;
|
|
189
|
|
190 // Equal function for contactSet.
|
|
191 static cpBool
|
|
192 contactSetEql(cpShape **shapes, cpArbiter *arb)
|
|
193 {
|
|
194 cpShape *a = shapes[0];
|
|
195 cpShape *b = shapes[1];
|
|
196
|
23
|
197 return ((a == arb.a && b == arb.b) || (b == arb.a && a == arb.b));
|
4
|
198 }
|
|
199
|
|
200 // Transformation function for contactSet.
|
|
201 static void *
|
|
202 contactSetTrans(cpShape **shapes, cpSpace *space)
|
|
203 {
|
|
204 if(space.pooledArbiters.num == 0){
|
|
205 // arbiter pool is exhausted, make more
|
|
206 int count = CP_BUFFER_BYTES/cpArbiter.sizeof;
|
|
207 assert(count, "Buffer size too small.");
|
|
208
|
|
209 cpArbiter *buffer = cast(cpArbiter *)cpmalloc(CP_BUFFER_BYTES);
|
|
210 cpArrayPush(space.allocatedBuffers, buffer);
|
|
211
|
|
212 for(int i=0; i<count; i++) cpArrayPush(space.pooledArbiters, buffer + i);
|
|
213 }
|
|
214
|
|
215 return cpArbiterInit(cast(cpArbiter *) cpArrayPop(space.pooledArbiters), shapes[0], shapes[1]);
|
|
216 }
|
|
217
|
|
218 // Equals function for collFuncSet.
|
|
219 static cpBool
|
|
220 collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
|
|
221 {
|
|
222 return ((check.a == pair.a && check.b == pair.b) || (check.b == pair.a && check.a == pair.b));
|
|
223 }
|
|
224
|
|
225 // Transformation function for collFuncSet.
|
|
226 static void *
|
|
227 collFuncSetTrans(cpCollisionHandler *handler, void *unused)
|
|
228 {
|
|
229 cpCollisionHandler *copy = cast(cpCollisionHandler *)cpmalloc(cpCollisionHandler.sizeof);
|
|
230 (*copy) = (*handler);
|
|
231
|
|
232 return copy;
|
|
233 }
|
|
234
|
|
235 // Default collision functions.
|
|
236 static cpBool alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
|
|
237 static void nothing(cpArbiter *arb, cpSpace *space, void *data){}
|
|
238
|
|
239 // BBfunc callback for the spatial hash.
|
|
240 static cpBB shapeBBFunc(cpShape *shape){return shape.bb;}
|
|
241
|
|
242 // Iterator functions for destructors.
|
|
243 static void freeWrap(void *ptr, void *unused){ cpfree(ptr);}
|
|
244 static void shapeFreeWrap(cpShape *ptr, void *unused){ cpShapeFree(ptr);}
|
|
245 static void bodyFreeWrap(cpBody *ptr, void *unused){ cpBodyFree(ptr);}
|
|
246 static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFree(ptr);}
|
|
247
|
|
248 cpSpace *
|
|
249 cpSpaceAlloc()
|
|
250 {
|
|
251 return cast(cpSpace *)cpcalloc(1, cpSpace.sizeof);
|
|
252 }
|
|
253
|
|
254 enum DEFAULT_DIM_SIZE = 100.0f;
|
|
255 enum DEFAULT_COUNT = 1000;
|
|
256 enum DEFAULT_ITERATIONS = 10;
|
|
257 enum DEFAULT_ELASTIC_ITERATIONS = 0;
|
|
258
|
|
259 cpCollisionHandler defaultHandler = {0, 0, &alwaysCollide, &alwaysCollide, ¬hing, ¬hing, null};
|
|
260
|
|
261 cpSpace*
|
|
262 cpSpaceInit(cpSpace *space)
|
|
263 {
|
|
264 space.iterations = DEFAULT_ITERATIONS;
|
|
265 space.elasticIterations = DEFAULT_ELASTIC_ITERATIONS;
|
|
266 // space.sleepTicks = 300;
|
|
267
|
|
268 space.gravity = cpvzero;
|
|
269 space.damping = 1.0f;
|
|
270
|
|
271 space.locked = 0;
|
|
272 space.stamp = 0;
|
|
273
|
|
274 space.staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, cast(cpSpaceHashBBFunc)&shapeBBFunc);
|
|
275 space.activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, cast(cpSpaceHashBBFunc)&shapeBBFunc);
|
|
276
|
|
277 space.allocatedBuffers = cpArrayNew(0);
|
|
278
|
|
279 space.bodies = cpArrayNew(0);
|
|
280 space.sleepingComponents = cpArrayNew(0);
|
|
281 space.sleepTimeThreshold = INFINITY;
|
|
282 space.idleSpeedThreshold = 0.0f;
|
|
283
|
|
284 space.arbiters = cpArrayNew(0);
|
|
285 space.pooledArbiters = cpArrayNew(0);
|
|
286
|
|
287 space.contactBuffersHead = null;
|
|
288 space.contactSet = cpHashSetNew(0, cast(cpHashSetEqlFunc)&contactSetEql, cast(cpHashSetTransFunc)&contactSetTrans);
|
|
289
|
|
290 space.constraints = cpArrayNew(0);
|
|
291
|
|
292 space.defaultHandler = defaultHandler;
|
|
293 space.collFuncSet = cpHashSetNew(0, cast(cpHashSetEqlFunc)&collFuncSetEql, cast(cpHashSetTransFunc)&collFuncSetTrans);
|
|
294 space.collFuncSet.default_value = &space.defaultHandler;
|
|
295
|
|
296 space.postStepCallbacks = null;
|
|
297
|
|
298 cpBodyInit(&space.staticBody, INFINITY, INFINITY);
|
|
299 space.staticBody.space = space;
|
|
300
|
|
301 return space;
|
|
302 }
|
|
303
|
|
304 cpSpace*
|
|
305 cpSpaceNew()
|
|
306 {
|
|
307 return cpSpaceInit(cpSpaceAlloc());
|
|
308 }
|
|
309
|
|
310 void
|
|
311 cpSpaceDestroy(cpSpace *space)
|
|
312 {
|
|
313 cpSpaceHashFree(space.staticShapes);
|
|
314 cpSpaceHashFree(space.activeShapes);
|
|
315
|
|
316 cpArrayFree(space.bodies);
|
|
317 cpArrayFree(space.sleepingComponents);
|
|
318
|
|
319 cpArrayFree(space.constraints);
|
|
320
|
|
321 cpHashSetFree(space.contactSet);
|
|
322
|
|
323 cpArrayFree(space.arbiters);
|
|
324 cpArrayFree(space.pooledArbiters);
|
|
325
|
|
326 if(space.allocatedBuffers){
|
|
327 cpArrayEach(space.allocatedBuffers, &freeWrap, null);
|
|
328 cpArrayFree(space.allocatedBuffers);
|
|
329 }
|
|
330
|
|
331 if(space.postStepCallbacks){
|
|
332 cpHashSetEach(space.postStepCallbacks, &freeWrap, null);
|
|
333 cpHashSetFree(space.postStepCallbacks);
|
|
334 }
|
|
335
|
|
336 if(space.collFuncSet){
|
|
337 cpHashSetEach(space.collFuncSet, &freeWrap, null);
|
|
338 cpHashSetFree(space.collFuncSet);
|
|
339 }
|
|
340 }
|
|
341
|
|
342 void
|
|
343 cpSpaceFree(cpSpace *space)
|
|
344 {
|
|
345 if(space){
|
|
346 cpSpaceDestroy(space);
|
|
347 cpfree(space);
|
|
348 }
|
|
349 }
|
|
350
|
|
351 void
|
|
352 cpSpaceFreeChildren(cpSpace *space)
|
|
353 {
|
|
354 cpArray *components = space.sleepingComponents;
|
|
355 while(components.num) cpBodyActivate(cast(cpBody *)components.arr[0]);
|
|
356
|
|
357 cpSpaceHashEach(space.staticShapes, cast(cpSpaceHashIterator)&shapeFreeWrap, null);
|
|
358 cpSpaceHashEach(space.activeShapes, cast(cpSpaceHashIterator)&shapeFreeWrap, null);
|
|
359 cpArrayEach(space.bodies, cast(cpArrayIter)&bodyFreeWrap, null);
|
|
360 cpArrayEach(space.constraints, cast(cpArrayIter)&constraintFreeWrap, null);
|
|
361 }
|
|
362
|
|
363 void
|
|
364 cpSpaceAddCollisionHandler(
|
|
365 cpSpace *space,
|
|
366 cpCollisionType a, cpCollisionType b,
|
|
367 cpCollisionBeginFunc begin,
|
|
368 cpCollisionPreSolveFunc preSolve,
|
|
369 cpCollisionPostSolveFunc postSolve,
|
|
370 cpCollisionSeparateFunc separate,
|
|
371 void *data
|
|
372 ){
|
|
373 // Remove any old function so the new one will get added.
|
|
374 cpSpaceRemoveCollisionHandler(space, a, b);
|
|
375
|
|
376 cpCollisionHandler handler = {
|
|
377 a, b,
|
|
378 begin ? begin : &alwaysCollide,
|
|
379 preSolve ? preSolve : &alwaysCollide,
|
|
380 postSolve ? postSolve : ¬hing,
|
|
381 separate ? separate : ¬hing,
|
|
382 data
|
|
383 };
|
|
384
|
|
385 cpHashSetInsert(space.collFuncSet, CP_HASH_PAIR(a, b), &handler, null);
|
|
386 }
|
|
387
|
|
388 void
|
|
389 cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)
|
|
390 {
|
|
391 struct tmp{cpCollisionType a, b;} tmp ids = {a, b};
|
|
392 cpCollisionHandler *old_handler = cast(cpCollisionHandler *) cpHashSetRemove(space.collFuncSet, CP_HASH_PAIR(a, b), &ids);
|
|
393 cpfree(old_handler);
|
|
394 }
|
|
395
|
|
396 void
|
|
397 cpSpaceSetDefaultCollisionHandler(
|
|
398 cpSpace *space,
|
|
399 cpCollisionBeginFunc begin,
|
|
400 cpCollisionPreSolveFunc preSolve,
|
|
401 cpCollisionPostSolveFunc postSolve,
|
|
402 cpCollisionSeparateFunc separate,
|
|
403 void *data
|
|
404 ){
|
|
405 cpCollisionHandler handler = {
|
|
406 0, 0,
|
|
407 begin ? begin : &alwaysCollide,
|
|
408 preSolve ? preSolve : &alwaysCollide,
|
|
409 postSolve ? postSolve : ¬hing,
|
|
410 separate ? separate : ¬hing,
|
|
411 data
|
|
412 };
|
|
413
|
|
414 space.defaultHandler = handler;
|
|
415 }
|
|
416
|
|
417 //#pragma mark Body, Shape, and Joint Management
|
|
418
|
|
419 void cpAssertSpaceUnlocked(cpSpace* _space){
|
|
420 assert(!_space.locked,
|
|
421 "This addition/removal cannot be done safely during a call to cpSpaceStep(). "
|
|
422 "Put these calls into a Post Step Callback."
|
|
423 );}
|
|
424
|
|
425 static void
|
|
426 cpBodyAddShape(cpBody *_body, cpShape *shape)
|
|
427 {
|
|
428 shape.next = shape._body.shapesList;
|
|
429 shape._body.shapesList = shape;
|
|
430 }
|
|
431
|
|
432 static void
|
|
433 cpBodyRemoveShape(cpBody *_body, cpShape *shape)
|
|
434 {
|
|
435 cpShape **prev_ptr = &_body.shapesList;
|
|
436 cpShape *node = _body.shapesList;
|
|
437
|
|
438 while(node && node != shape){
|
|
439 prev_ptr = &node.next;
|
|
440 node = node.next;
|
|
441 }
|
|
442
|
|
443 assert(node, "Attempted to remove a shape from a body it was never attached to.");
|
|
444 (*prev_ptr) = node.next;
|
|
445 }
|
|
446
|
|
447 cpShape *
|
|
448 cpSpaceAddShape(cpSpace *space, cpShape *shape)
|
|
449 {
|
|
450 cpBody *_body = shape._body;
|
|
451 if(!_body || _body == &space.staticBody) return cpSpaceAddStaticShape(space, shape);
|
|
452
|
|
453 assert(!cpHashSetFind(space.activeShapes.handleSet, shape.hashid, shape),
|
|
454 "Cannot add the same shape more than once.");
|
|
455 cpAssertSpaceUnlocked(space);
|
|
456
|
|
457 cpBodyActivate(_body);
|
|
458 cpBodyAddShape(_body, shape);
|
|
459
|
|
460 cpShapeCacheBB(shape);
|
|
461 cpSpaceHashInsert(space.activeShapes, shape, shape.hashid, shape.bb);
|
|
462
|
|
463 return shape;
|
|
464 }
|
|
465
|
|
466 cpShape *
|
|
467 cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
|
|
468 {
|
|
469 assert(!cpHashSetFind(space.staticShapes.handleSet, shape.hashid, shape),
|
|
470 "Cannot add the same static shape more than once.");
|
|
471 cpAssertSpaceUnlocked(space);
|
|
472
|
|
473 if(!shape._body) shape._body = &space.staticBody;
|
|
474
|
|
475 cpShapeCacheBB(shape);
|
23
|
476 cpSpaceActivateShapesTouchingShape(space, shape);
|
4
|
477 cpSpaceHashInsert(space.staticShapes, shape, shape.hashid, shape.bb);
|
|
478
|
|
479 return shape;
|
|
480 }
|
|
481
|
|
482 cpBody *
|
|
483 cpSpaceAddBody(cpSpace *space, cpBody *_body)
|
|
484 {
|
23
|
485 mixin(cpAssertWarn!("!cpBodyIsStatic(_body)", "Static bodies cannot be added to a space as they are not meant to be simulated.",__FILE__,__LINE__));
|
4
|
486 assert(!_body.space, "Cannot add a body to a more than one space or to the same space twice.");
|
|
487 // cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback
|
|
488
|
|
489 cpArrayPush(space.bodies, _body);
|
|
490 _body.space = space;
|
|
491
|
|
492 return _body;
|
|
493 }
|
|
494
|
|
495 cpConstraint *
|
|
496 cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
|
|
497 {
|
|
498 assert(!cpArrayContains(space.constraints, constraint), "Cannot add the same constraint more than once.");
|
|
499 // cpAssertSpaceUnlocked(space); This should be safe as long as its not from a constraint callback.
|
|
500
|
|
501 if(!constraint.a) constraint.a = &space.staticBody;
|
|
502 if(!constraint.b) constraint.b = &space.staticBody;
|
|
503
|
|
504 cpBodyActivate(constraint.a);
|
|
505 cpBodyActivate(constraint.b);
|
|
506 cpArrayPush(space.constraints, constraint);
|
|
507
|
|
508 return constraint;
|
|
509 }
|
|
510
|
|
511 struct removalContext {
|
|
512 cpSpace *space;
|
|
513 cpShape *shape;
|
|
514 }
|
|
515
|
|
516 // Hashset filter func to throw away old arbiters.
|
|
517 static cpBool
|
|
518 contactSetFilterRemovedShape(cpArbiter *arb, removalContext *context)
|
|
519 {
|
23
|
520 if(context.shape == arb.a || context.shape == arb.b){
|
|
521 if(arb.state != cpArbiterState.cpArbiterStateCached){
|
|
522 arb.handler.separate(arb, context.space, arb.handler.data);
|
|
523 }
|
|
524
|
4
|
525 cpArrayPush(context.space.pooledArbiters, arb);
|
|
526 return cpFalse;
|
|
527 }
|
|
528
|
|
529 return cpTrue;
|
|
530 }
|
|
531
|
|
532 void
|
|
533 cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
|
|
534 {
|
|
535 cpBody *_body = shape._body;
|
|
536 if(cpBodyIsStatic(_body)){
|
|
537 cpSpaceRemoveStaticShape(space, shape);
|
|
538 return;
|
|
539 }
|
|
540
|
|
541 cpBodyActivate(_body);
|
|
542
|
|
543 cpAssertSpaceUnlocked(space);
|
13
|
544 mixin(cpAssertWarn!("cpHashSetFind(space.activeShapes.handleSet, shape.hashid, shape) !is null",
|
|
545 "Cannot remove a shape that was never added to the space. (Removed twice maybe?)",__FILE__,__LINE__));
|
4
|
546
|
|
547 cpBodyRemoveShape(_body, shape);
|
|
548
|
|
549 removalContext context = {space, shape};
|
|
550 cpHashSetFilter(space.contactSet, cast(cpHashSetFilterFunc)&contactSetFilterRemovedShape, &context);
|
|
551 cpSpaceHashRemove(space.activeShapes, shape, shape.hashid);
|
|
552 }
|
|
553
|
|
554 void
|
|
555 cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
|
|
556 {
|
13
|
557 mixin(cpAssertWarn!("cpHashSetFind(space.staticShapes.handleSet, shape.hashid, shape) !is null",
|
|
558 "Cannot remove a static or sleeping shape that was never added to the space. (Removed twice maybe?)",__FILE__,__LINE__));
|
4
|
559 cpAssertSpaceUnlocked(space);
|
|
560
|
|
561 removalContext context = {space, shape};
|
|
562 cpHashSetFilter(space.contactSet, cast(cpHashSetFilterFunc)&contactSetFilterRemovedShape, &context);
|
|
563 cpSpaceHashRemove(space.staticShapes, shape, shape.hashid);
|
|
564
|
23
|
565 cpSpaceActivateShapesTouchingShape(space, shape);
|
4
|
566 }
|
|
567
|
|
568 void
|
|
569 cpSpaceRemoveBody(cpSpace *space, cpBody *_body)
|
|
570 {
|
13
|
571 mixin(cpAssertWarn!("_body.space == space",
|
|
572 "Cannot remove a body that was never added to the space. (Removed twice maybe?)"));
|
4
|
573 cpAssertSpaceUnlocked(space);
|
|
574
|
|
575 cpBodyActivate(_body);
|
|
576 cpArrayDeleteObj(space.bodies, _body);
|
|
577 _body.space = null;
|
|
578 }
|
|
579
|
|
580 void
|
|
581 cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
|
|
582 {
|
13
|
583 mixin(cpAssertWarn!("cpArrayContains(space.constraints, constraint)",
|
|
584 "Cannot remove a constraint that was never added to the space. (Removed twice maybe?)",__FILE__,__LINE__));
|
4
|
585 // cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback.
|
|
586
|
|
587 cpBodyActivate(constraint.a);
|
|
588 cpBodyActivate(constraint.b);
|
|
589 cpArrayDeleteObj(space.constraints, constraint);
|
|
590 }
|
|
591
|
|
592 //#pragma mark Spatial Hash Management
|
|
593
|
|
594 static void updateBBCache(cpShape *shape, void *unused){cpShapeCacheBB(shape);}
|
|
595
|
|
596 void
|
|
597 cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
|
|
598 {
|
|
599 cpSpaceHashResize(space.staticShapes, dim, count);
|
|
600 cpSpaceHashRehash(space.staticShapes);
|
|
601 }
|
|
602
|
|
603 void
|
|
604 cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)
|
|
605 {
|
|
606 cpSpaceHashResize(space.activeShapes, dim, count);
|
|
607 }
|
|
608
|
|
609 void
|
|
610 cpSpaceRehashStatic(cpSpace *space)
|
|
611 {
|
|
612 cpSpaceHashEach(space.staticShapes, cast(cpSpaceHashIterator)&updateBBCache, null);
|
|
613 cpSpaceHashRehash(space.staticShapes);
|
|
614 }
|
|
615
|
|
616 void
|
|
617 cpSpaceRehashShape(cpSpace *space, cpShape *shape)
|
|
618 {
|
|
619 cpShapeCacheBB(shape);
|
|
620
|
|
621 // attempt to rehash the shape in both hashes
|
|
622 cpSpaceHashRehashObject(space.activeShapes, shape, shape.hashid);
|
|
623 cpSpaceHashRehashObject(space.staticShapes, shape, shape.hashid);
|
|
624 }
|
|
625
|