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