Mercurial > projects > chipmunkd
annotate trunk/chipmunkd/cpSpace.d @ 28:4541ca17975b
use __gshared as chipmunk heavily relies on globals and D would otherwise make them TLS
author | Extrawurst |
---|---|
date | Mon, 13 Dec 2010 21:40:56 +0100 |
parents | 4ceef5833c8c |
children | 80058cee1a77 |
rev | line source |
---|---|
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 | |
28
4541ca17975b
use __gshared as chipmunk heavily relies on globals and D would otherwise make them TLS
Extrawurst
parents:
23
diff
changeset
|
188 __gshared cpTimestamp cp_contact_persistence = 3; |
4 | 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 | |
28
4541ca17975b
use __gshared as chipmunk heavily relies on globals and D would otherwise make them TLS
Extrawurst
parents:
23
diff
changeset
|
259 __gshared cpCollisionHandler defaultHandler = {0, 0, &alwaysCollide, &alwaysCollide, ¬hing, ¬hing, null}; |
4 | 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 |