1 /*
2  * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 module dchip.cpSpaceStep;
23 
24 import dchip.cpBB;
25 import dchip.cpBody;
26 import dchip.cpCollision;
27 import dchip.chipmunk;
28 import dchip.chipmunk_private;
29 import dchip.chipmunk_types;
30 import dchip.cpArbiter;
31 import dchip.cpArray;
32 import dchip.cpConstraint;
33 import dchip.cpHashSet;
34 import dchip.cpShape;
35 import dchip.cpSpace;
36 import dchip.cpSpaceComponent;
37 import dchip.cpSpatialIndex;
38 import dchip.util;
39 
40 cpPostStepCallback* cpSpaceGetPostStepCallback(cpSpace* space, void* key)
41 {
42     cpArray* arr = space.postStepCallbacks;
43 
44     for (int i = 0; i < arr.num; i++)
45     {
46         cpPostStepCallback* callback = cast(cpPostStepCallback*)arr.arr[i];
47 
48         if (callback && callback.key == key)
49             return callback;
50     }
51 
52     return null;
53 }
54 
55 void PostStepDoNothing(cpSpace* space, void* obj, void* data)
56 {
57 }
58 
59 cpBool cpSpaceAddPostStepCallback(cpSpace* space, cpPostStepFunc func, void* key, void* data)
60 {
61     cpAssertWarn(space.locked,
62                  "Adding a post-step callback when the space is not locked is unnecessary. "~
63                  "Post-step callbacks will not called until the end of the next call to cpSpaceStep() or the next query.");
64 
65     if (!cpSpaceGetPostStepCallback(space, key))
66     {
67         cpPostStepCallback* callback = cast(cpPostStepCallback*)cpcalloc(1, cpPostStepCallback.sizeof);
68         callback.func = (func ? func : &PostStepDoNothing);
69         callback.key  = key;
70         callback.data = data;
71 
72         cpArrayPush(space.postStepCallbacks, callback);
73         return cpTrue;
74     }
75     else
76     {
77         return cpFalse;
78     }
79 }
80 
81 //MARK: Locking Functions
82 
83 void cpSpaceLock(cpSpace* space)
84 {
85     space.locked++;
86 }
87 
88 void cpSpaceUnlock(cpSpace* space, cpBool runPostStep)
89 {
90     space.locked--;
91     cpAssertHard(space.locked >= 0, "Internal Error: Space lock underflow.");
92 
93     if (space.locked == 0)
94     {
95         cpArray* waking = space.rousedBodies;
96 
97         for (int i = 0, count = waking.num; i < count; i++)
98         {
99             cpSpaceActivateBody(space, cast(cpBody*)waking.arr[i]);
100             waking.arr[i] = null;
101         }
102 
103         waking.num = 0;
104 
105         if (space.locked == 0 && runPostStep && !space.skipPostStep)
106         {
107             space.skipPostStep = cpTrue;
108 
109             cpArray* arr = space.postStepCallbacks;
110 
111             for (int i = 0; i < arr.num; i++)
112             {
113                 cpPostStepCallback* callback = cast(cpPostStepCallback*)arr.arr[i];
114                 cpPostStepFunc func = callback.func;
115 
116                 // Mark the func as null in case calling it calls cpSpaceRunPostStepCallbacks() again.
117                 // TODO need more tests around this case I think.
118                 callback.func = null;
119 
120                 if (func)
121                     func(space, callback.key, callback.data);
122 
123                 arr.arr[i] = null;
124                 cpfree(callback);
125             }
126 
127             arr.num = 0;
128             space.skipPostStep = cpFalse;
129         }
130     }
131 }
132 
133 //MARK: Contact Buffer Functions
134 
135 struct cpContactBufferHeader
136 {
137     cpTimestamp stamp;
138     cpContactBufferHeader* next;
139     uint numContacts;
140 }
141 
142 enum CP_CONTACTS_BUFFER_SIZE = (CP_BUFFER_BYTES - cpContactBufferHeader.sizeof) / cpContact.sizeof;
143 
144 struct cpContactBuffer
145 {
146     cpContactBufferHeader header;
147     cpContact[CP_CONTACTS_BUFFER_SIZE] contacts;
148 }
149 
150 cpContactBufferHeader* cpSpaceAllocContactBuffer(cpSpace* space)
151 {
152     cpContactBuffer* buffer = cast(cpContactBuffer*)cpcalloc(1, cpContactBuffer.sizeof);
153     cpArrayPush(space.allocatedBuffers, buffer);
154     return cast(cpContactBufferHeader*)buffer;
155 }
156 
157 cpContactBufferHeader* cpContactBufferHeaderInit(cpContactBufferHeader* header, cpTimestamp stamp, cpContactBufferHeader* splice)
158 {
159     header.stamp       = stamp;
160     header.next        = (splice ? splice.next : header);
161     header.numContacts = 0;
162 
163     return header;
164 }
165 
166 void cpSpacePushFreshContactBuffer(cpSpace* space)
167 {
168     cpTimestamp stamp = space.stamp;
169 
170     cpContactBufferHeader* head = space.contactBuffersHead;
171 
172     if (!head)
173     {
174         // No buffers have been allocated, make one
175         space.contactBuffersHead = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, null);
176     }
177     else if (stamp - head.next.stamp > space.collisionPersistence)
178     {
179         // The tail buffer is available, rotate the ring
180         cpContactBufferHeader* tail = head.next;
181         space.contactBuffersHead = cpContactBufferHeaderInit(tail, stamp, tail);
182     }
183     else
184     {
185         // Allocate a new buffer and push it into the ring
186         cpContactBufferHeader* buffer = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, head);
187         space.contactBuffersHead = head.next = buffer;
188     }
189 }
190 
191 cpContact* cpContactBufferGetArray(cpSpace* space)
192 {
193     if (space.contactBuffersHead.numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE)
194     {
195         // contact buffer could overflow on the next collision, push a fresh one.
196         cpSpacePushFreshContactBuffer(space);
197     }
198 
199     cpContactBufferHeader* head = space.contactBuffersHead;
200     return &(cast(cpContactBuffer*)head).contacts[head.numContacts];
201 }
202 
203 void cpSpacePushContacts(cpSpace* space, int count)
204 {
205     cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!");
206     space.contactBuffersHead.numContacts += count;
207 }
208 
209 void cpSpacePopContacts(cpSpace* space, int count)
210 {
211     space.contactBuffersHead.numContacts -= count;
212 }
213 
214 //MARK: Collision Detection Functions
215 
216 void* cpSpaceArbiterSetTrans(cpShape** shapes, cpSpace* space)
217 {
218     if (space.pooledArbiters.num == 0)
219     {
220         // arbiter pool is exhausted, make more
221         int count = CP_BUFFER_BYTES / cpArbiter.sizeof;
222         cpAssertHard(count, "Internal Error: Buffer size too small.");
223 
224         cpArbiter* buffer = cast(cpArbiter*)cpcalloc(1, CP_BUFFER_BYTES);
225         cpArrayPush(space.allocatedBuffers, buffer);
226 
227         for (int i = 0; i < count; i++)
228             cpArrayPush(space.pooledArbiters, buffer + i);
229     }
230 
231     return cpArbiterInit(cast(cpArbiter*)cpArrayPop(space.pooledArbiters), shapes[0], shapes[1]);
232 }
233 
234 cpBool queryReject(cpShape* a, cpShape* b)
235 {
236     return (
237 
238         // BBoxes must overlap
239         !cpBBIntersects(a.bb, b.bb)
240 
241         // Don't collide shapes attached to the same body.
242         || a.body_ == b.body_
243 
244         // Don't collide objects in the same non-zero group
245         || (a.group && a.group == b.group)
246 
247         // Don't collide objects that don't share at least on layer.
248         || !(a.layers & b.layers)
249 
250         // Don't collide infinite mass objects
251         || (a.body_.m == INFINITY && b.body_.m == INFINITY)
252         );
253 }
254 
255 // Callback from the spatial hash.
256 cpCollisionID cpSpaceCollideShapes(cpShape* a, cpShape* b, cpCollisionID id, cpSpace* space)
257 {
258     // Reject any of the simple cases
259     if (queryReject(a, b))
260         return id;
261 
262     cpCollisionHandler* handler = cpSpaceLookupHandler(space, a.collision_type, b.collision_type);
263 
264     cpBool sensor = a.sensor || b.sensor;
265 
266     if (sensor && handler == &cpDefaultCollisionHandler)
267         return id;
268 
269     // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
270     // TODO remove me: a < b comparison is for debugging collisions
271     if (a.klass.type > b.klass.type || (a.klass.type == b.klass.type && a < b))
272     {
273         cpShape* temp = a;
274         a = b;
275         b = temp;
276     }
277 
278     // Narrow-phase collision detection.
279     cpContact* contacts = cpContactBufferGetArray(space);
280     int numContacts     = cpCollideShapes(a, b, &id, contacts);
281 
282     if (!numContacts)
283         return id;                  // Shapes are not colliding.
284     cpSpacePushContacts(space, numContacts);
285 
286     // Get an arbiter from space.arbiterSet for the two shapes.
287     // This is where the persistant contact magic comes from.
288     cpShape*[2] shape_pair;
289     shape_pair[0] = a;
290     shape_pair[1] = b;
291     cpHashValue arbHashID = CP_HASH_PAIR(cast(cpHashValue)a, cast(cpHashValue)b);
292     cpArbiter * arb       = cast(cpArbiter*)cpHashSetInsert(space.cachedArbiters, arbHashID, shape_pair.ptr, space, cast(cpHashSetTransFunc)&cpSpaceArbiterSetTrans);
293     cpArbiterUpdate(arb, contacts, numContacts, handler, a, b);
294 
295     // Call the begin function first if it's the first step
296     if (arb.state == cpArbiterStateFirstColl && !handler.begin(arb, space, handler.data))
297     {
298         cpArbiterIgnore(arb);         // permanently ignore the collision until separation
299     }
300 
301     if (
302 
303         // Ignore the arbiter if it has been flagged
304         (arb.state != cpArbiterStateIgnore) &&
305 
306         // Call preSolve
307         handler.preSolve(arb, space, handler.data) &&
308 
309         // Process, but don't add collisions for sensors.
310         !sensor
311         )
312     {
313         cpArrayPush(space.arbiters, arb);
314     }
315     else
316     {
317         cpSpacePopContacts(space, numContacts);
318 
319         arb.contacts    = null;
320         arb.numContacts = 0;
321 
322         // Normally arbiters are set as used after calling the post-solve callback.
323         // However, post-solve callbacks are not called for sensors or arbiters rejected from pre-solve.
324         if (arb.state != cpArbiterStateIgnore)
325             arb.state = cpArbiterStateNormal;
326     }
327 
328     // Time stamp the arbiter so we know it was used recently.
329     arb.stamp = space.stamp;
330     return id;
331 }
332 
333 // Hashset filter func to throw away old arbiters.
334 cpBool cpSpaceArbiterSetFilter(cpArbiter* arb, cpSpace* space)
335 {
336     cpTimestamp ticks = space.stamp - arb.stamp;
337 
338     cpBody* a = arb.body_a;
339     cpBody* b = arb.body_b;
340 
341     // TODO should make an arbiter state for this so it doesn't require filtering arbiters for dangling body pointers on body removal.
342     // Preserve arbiters on sensors and rejected arbiters for sleeping objects.
343     // This prevents errant separate callbacks from happenening.
344     if (
345         (cpBodyIsStatic(a) || cpBodyIsSleeping(a)) &&
346         (cpBodyIsStatic(b) || cpBodyIsSleeping(b))
347         )
348     {
349         return cpTrue;
350     }
351 
352     // Arbiter was used last frame, but not this one
353     if (ticks >= 1 && arb.state != cpArbiterStateCached)
354     {
355         arb.state = cpArbiterStateCached;
356         cpArbiterCallSeparate(arb, space);
357     }
358 
359     if (ticks >= space.collisionPersistence)
360     {
361         arb.contacts    = null;
362         arb.numContacts = 0;
363 
364         cpArrayPush(space.pooledArbiters, arb);
365         return cpFalse;
366     }
367 
368     return cpTrue;
369 }
370 
371 //MARK: All Important cpSpaceStep() Function
372 
373 void cpShapeUpdateFunc(cpShape* shape, void* unused)
374 {
375     cpBody* body_ = shape.body_;
376     cpShapeUpdate(shape, body_.p, body_.rot);
377 }
378 
379 void cpSpaceStep(cpSpace* space, cpFloat dt)
380 {
381     // don't step if the timestep is 0!
382     if (dt == 0.0f)
383         return;
384 
385     space.stamp++;
386 
387     cpFloat prev_dt = space.curr_dt;
388     space.curr_dt = dt;
389 
390     cpArray* bodies      = space.bodies;
391     cpArray* constraints = space.constraints;
392     cpArray* arbiters    = space.arbiters;
393 
394     // Reset and empty the arbiter lists.
395     for (int i = 0; i < arbiters.num; i++)
396     {
397         cpArbiter* arb = cast(cpArbiter*)arbiters.arr[i];
398         arb.state = cpArbiterStateNormal;
399 
400         // If both bodies are awake, unthread the arbiter from the contact graph.
401         if (!cpBodyIsSleeping(arb.body_a) && !cpBodyIsSleeping(arb.body_b))
402         {
403             cpArbiterUnthread(arb);
404         }
405     }
406 
407     arbiters.num = 0;
408 
409     cpSpaceLock(space);
410     {
411         // Integrate positions
412         for (int i = 0; i < bodies.num; i++)
413         {
414             cpBody* body_ = cast(cpBody*)bodies.arr[i];
415             body_.position_func(body_, dt);
416         }
417 
418         // Find colliding pairs.
419         cpSpacePushFreshContactBuffer(space);
420         cpSpatialIndexEach(space.activeShapes, safeCast!cpSpatialIndexIteratorFunc(&cpShapeUpdateFunc), null);
421         cpSpatialIndexReindexQuery(space.activeShapes, safeCast!cpSpatialIndexQueryFunc(&cpSpaceCollideShapes), space);
422     }
423     cpSpaceUnlock(space, cpFalse);
424 
425     // Rebuild the contact graph (and detect sleeping components if sleeping is enabled)
426     cpSpaceProcessComponents(space, dt);
427 
428     cpSpaceLock(space);
429     {
430         // Clear out old cached arbiters and call separate callbacks
431         cpHashSetFilter(space.cachedArbiters, cast(cpHashSetFilterFunc)&cpSpaceArbiterSetFilter, space);
432 
433         // Prestep the arbiters and constraints.
434         cpFloat slop     = space.collisionSlop;
435         cpFloat biasCoef = 1.0f - cpfpow(space.collisionBias, dt);
436 
437         for (int i = 0; i < arbiters.num; i++)
438         {
439             cpArbiterPreStep(cast(cpArbiter*)arbiters.arr[i], dt, slop, biasCoef);
440         }
441 
442         for (int i = 0; i < constraints.num; i++)
443         {
444             cpConstraint* constraint = cast(cpConstraint*)constraints.arr[i];
445 
446             cpConstraintPreSolveFunc preSolve = constraint.preSolve;
447 
448             if (preSolve)
449                 preSolve(constraint, space);
450 
451             constraint.klass.preStep(constraint, dt);
452         }
453 
454         // Integrate velocities.
455         cpFloat damping = cpfpow(space.damping, dt);
456         cpVect  gravity = space.gravity;
457 
458         for (int i = 0; i < bodies.num; i++)
459         {
460             cpBody* body_ = cast(cpBody*)bodies.arr[i];
461             body_.velocity_func(body_, gravity, damping, dt);
462         }
463 
464         // Apply cached impulses
465         cpFloat dt_coef = (prev_dt == 0.0f ? 0.0f : dt / prev_dt);
466 
467         for (int i = 0; i < arbiters.num; i++)
468         {
469             cpArbiterApplyCachedImpulse(cast(cpArbiter*)arbiters.arr[i], dt_coef);
470         }
471 
472         for (int i = 0; i < constraints.num; i++)
473         {
474             cpConstraint* constraint = cast(cpConstraint*)constraints.arr[i];
475             constraint.klass.applyCachedImpulse(constraint, dt_coef);
476         }
477 
478         // Run the impulse solver.
479         for (int i = 0; i < space.iterations; i++)
480         {
481             for (int j = 0; j < arbiters.num; j++)
482             {
483                 cpArbiterApplyImpulse(cast(cpArbiter*)arbiters.arr[j]);
484             }
485 
486             for (int j = 0; j < constraints.num; j++)
487             {
488                 cpConstraint* constraint = cast(cpConstraint*)constraints.arr[j];
489                 constraint.klass.applyImpulse(constraint, dt);
490             }
491         }
492 
493         // Run the constraint post-solve callbacks
494         for (int i = 0; i < constraints.num; i++)
495         {
496             cpConstraint* constraint = cast(cpConstraint*)constraints.arr[i];
497 
498             cpConstraintPostSolveFunc postSolve = constraint.postSolve;
499 
500             if (postSolve)
501                 postSolve(constraint, space);
502         }
503 
504         // run the post-solve callbacks
505         for (int i = 0; i < arbiters.num; i++)
506         {
507             cpArbiter* arb = cast(cpArbiter*)arbiters.arr[i];
508 
509             cpCollisionHandler* handler = arb.handler;
510             handler.postSolve(arb, space, handler.data);
511         }
512     }
513     cpSpaceUnlock(space, cpTrue);
514 }