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