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.cpBody;
23 
24 import std.string;
25 
26 import dchip.chipmunk;
27 import dchip.chipmunk_private;
28 import dchip.chipmunk_types;
29 import dchip.constraints_util;
30 import dchip.cpArray;
31 import dchip.cpArbiter;
32 import dchip.cpConstraint;
33 import dchip.cpShape;
34 import dchip.cpSpace;
35 import dchip.cpSpaceComponent;
36 import dchip.cpVect;
37 
38 /// Chipmunk's rigid body_ type. Rigid bodies hold the physical properties of an object like
39 /// it's mass, and position and velocity of it's center of gravity. They don't have an shape on their own.
40 /// They are given a shape by creating collision shapes (cpShape) that point to the body_.
41 
42 /// Rigid body_ velocity update function type.
43 alias cpBodyVelocityFunc = void function(cpBody* bdy, cpVect gravity, cpFloat damping, cpFloat dt);
44 
45 /// Rigid body_ position update function type.
46 alias cpBodyPositionFunc = void function(cpBody* bdy, cpFloat dt);
47 
48 /// Used internally to track information on the collision graph.
49 /// @private
50 struct cpComponentNode
51 {
52     cpBody* root;
53     cpBody* next;
54     cpFloat idleTime = 0;
55 }
56 
57 /// Chipmunk's rigid body_ struct.
58 struct cpBody
59 {
60     /// Function that is called to integrate the body_'s velocity. (Defaults to cpBodyUpdateVelocity)
61     cpBodyVelocityFunc velocity_func;
62 
63     /// Function that is called to integrate the body_'s position. (Defaults to cpBodyUpdatePosition)
64     cpBodyPositionFunc position_func;
65 
66     /// Mass of the body_.
67     /// Must agree with cpBody.m_inv! Use cpBodySetMass() when changing the mass for this reason.
68     cpFloat m = 0;
69 
70     /// Mass inverse.
71     cpFloat m_inv = 0;
72 
73     /// Moment of inertia of the body_.
74     /// Must agree with cpBody.i_inv! Use cpBodySetMoment() when changing the moment for this reason.
75     cpFloat i = 0;
76 
77     /// Moment of inertia inverse.
78     cpFloat i_inv = 0;
79 
80     /// Position of the rigid body_'s center of gravity.
81     cpVect p;
82 
83     /// Velocity of the rigid body_'s center of gravity.
84     cpVect v;
85 
86     /// Force acting on the rigid body_'s center of gravity.
87     cpVect f;
88 
89     /// Rotation of the body_ around it's center of gravity in radians.
90     /// Must agree with cpBody.rot! Use cpBodySetAngle() when changing the angle for this reason.
91     cpFloat a = 0;
92 
93     /// Angular velocity of the body_ around it's center of gravity in radians/second.
94     cpFloat w = 0;
95 
96     /// Torque applied to the body_ around it's center of gravity.
97     cpFloat t = 0;
98 
99     /// Cached unit length vector representing the angle of the body_.
100     /// Used for fast rotations using cpvrotate().
101     cpVect rot;
102 
103     /// User definable data pointer.
104     /// Generally this points to your the game object class so you can access it
105     /// when given a cpBody reference in a callback.
106     cpDataPointer data;
107 
108     /// Maximum velocity allowed when updating the velocity.
109     cpFloat v_limit = 0;
110 
111     /// Maximum rotational rate (in radians/second) allowed when updating the angular velocity.
112     cpFloat w_limit = 0;
113 
114     version (CHIP_ALLOW_PRIVATE_ACCESS)
115         cpVect v_bias;
116     else
117         package cpVect v_bias;
118 
119     version (CHIP_ALLOW_PRIVATE_ACCESS)
120         cpFloat w_bias = 0;
121     else
122         package cpFloat w_bias = 0;
123 
124     version (CHIP_ALLOW_PRIVATE_ACCESS)
125         cpSpace * space;
126     else
127         package cpSpace * space;
128 
129     version (CHIP_ALLOW_PRIVATE_ACCESS)
130         cpShape * shapeList;
131     else
132         package cpShape * shapeList;
133 
134     version (CHIP_ALLOW_PRIVATE_ACCESS)
135         cpArbiter * arbiterList;
136     else
137         package cpArbiter *arbiterList;
138 
139     version (CHIP_ALLOW_PRIVATE_ACCESS)
140         cpConstraint * constraintList;
141     else
142         package cpConstraint * constraintList;
143 
144     version (CHIP_ALLOW_PRIVATE_ACCESS)
145         cpComponentNode node;
146     else
147         package cpComponentNode node;
148 }
149 
150 /// Check that the properties of a body_ is sane.
151 version (CHIP_ENABLE_WARNINGS)
152 {
153     void cpBodyAssertSane(T)(T bdy)
154     {
155         cpBodySanityCheck(bdy);
156     }
157 }
158 else
159 {
160     void cpBodyAssertSane(T)(T bdy) { }
161 }
162 
163 // Defined in cpSpace.c
164 /// Wake up a sleeping or idle body_.
165 void cpBodyActivate(cpBody* body_)
166 {
167     if (!cpBodyIsRogue(body_))
168     {
169         body_.node.idleTime = 0.0f;
170         ComponentActivate(ComponentRoot(body_));
171     }
172 
173     mixin(CP_BODY_FOREACH_ARBITER!("body_", "arb", q{
174         // Reset the idle timer of things the body_ is touching as well.
175         // That way things don't get left hanging in the air.
176         cpBody* other = (arb.body_a == body_ ? arb.body_b : arb.body_a);
177 
178         if (!cpBodyIsStatic(other))
179             other.node.idleTime = 0.0f;
180     }));
181 }
182 
183 /// Wake up any sleeping or idle bodies touching a static body_.
184 void cpBodyActivateStatic(cpBody* body_, cpShape* filter)
185 {
186     cpAssertHard(cpBodyIsStatic(body_), "cpBodyActivateStatic() called on a non-static body_.");
187 
188     mixin(CP_BODY_FOREACH_ARBITER!("body_", "arb", q{
189         if (!filter || filter == arb.a || filter == arb.b)
190         {
191             cpBodyActivate(arb.body_a == body_ ? arb.body_b : arb.body_a);
192         }
193     }));
194 
195     // TODO should also activate joints?
196 }
197 
198 /// Force a body_ to fall asleep immediately.
199 void cpBodySleep(cpBody* body_)
200 {
201     cpBodySleepWithGroup(body_, null);
202 }
203 
204 /// Force a body_ to fall asleep immediately along with other bodies in a group.
205 void cpBodySleepWithGroup(cpBody* body_, cpBody* group)
206 {
207     cpAssertHard(!cpBodyIsRogue(body_), "Rogue (and static) bodies cannot be put to sleep.");
208 
209     cpSpace* space = body_.space;
210     cpAssertHard(!space.locked, "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback.");
211     cpAssertHard(group == null || cpBodyIsSleeping(group), "Cannot use a non-sleeping body_ as a group identifier.");
212 
213     if (cpBodyIsSleeping(body_))
214     {
215         cpAssertHard(ComponentRoot(body_) == ComponentRoot(group), "The body_ is already sleeping and it's group cannot be reassigned.");
216         return;
217     }
218 
219     mixin(CP_BODY_FOREACH_SHAPE!("body_", "shape", "cpShapeUpdate(shape, body_.p, body_.rot);"));
220     cpSpaceDeactivateBody(space, body_);
221 
222     if (group)
223     {
224         cpBody* root = ComponentRoot(group);
225 
226         cpComponentNode node = { root, root.node.next, 0.0f };
227         body_.node = node;
228 
229         root.node.next = body_;
230     }
231     else
232     {
233         cpComponentNode node = { body_, null, 0.0f };
234         body_.node = node;
235 
236         cpArrayPush(space.sleepingComponents, body_);
237     }
238 
239     cpArrayDeleteObj(space.bodies, body_);
240 }
241 
242 /// Returns true if the body_ is sleeping.
243 cpBool cpBodyIsSleeping(const cpBody* bdy)
244 {
245     return (bdy.node.root != (cast(cpBody*)null));
246 }
247 
248 /// Returns true if the body_ is static.
249 cpBool cpBodyIsStatic(const cpBody* bdy)
250 {
251     return bdy.node.idleTime == INFINITY;
252 }
253 
254 /// Returns true if the body_ has not been added to a space.
255 /// Note: Static bodies are a subtype of rogue bodies.
256 cpBool cpBodyIsRogue(const cpBody* bdy)
257 {
258     return (bdy.space == (cast(cpSpace*)null));
259 }
260 
261 mixin template CP_DefineBodyStructGetter(type, string member, string name)
262 {
263     mixin(q{
264         type cpBodyGet%s(const cpBody * bdy) { return cast(typeof(return))bdy.%s; }
265     }.format(name, member));
266 }
267 
268 mixin template CP_DefineBodyStructSetter(type, string member, string name)
269 {
270     mixin(q{
271         void cpBodySet%s(cpBody * bdy, const type value)
272         {
273             cpBodyActivate(bdy);
274             bdy.%s = cast(typeof(bdy.%s))value;
275             cpBodyAssertSane(bdy);
276         }
277     }.format(name, member, member));
278 }
279 
280 mixin template CP_DefineBodyStructProperty(type, string member, string name)
281 {
282     mixin CP_DefineBodyStructGetter!(type, member, name);
283     mixin CP_DefineBodyStructSetter!(type, member, name);
284 }
285 
286 // TODO add to docs
287 mixin CP_DefineBodyStructGetter!(cpSpace*, "space", "Space");
288 
289 mixin CP_DefineBodyStructGetter!(cpFloat, "m", "Mass");
290 
291 mixin CP_DefineBodyStructGetter!(cpFloat, "i", "Moment");
292 
293 mixin CP_DefineBodyStructGetter!(cpVect, "p", "Pos");
294 
295 mixin CP_DefineBodyStructProperty!(cpVect, "v", "Vel");
296 mixin CP_DefineBodyStructProperty!(cpVect, "f", "Force");
297 mixin CP_DefineBodyStructGetter!(cpFloat, "a", "Angle");
298 
299 mixin CP_DefineBodyStructProperty!(cpFloat, "w", "AngVel");
300 mixin CP_DefineBodyStructProperty!(cpFloat, "t", "Torque");
301 mixin CP_DefineBodyStructGetter!(cpVect, "rot", "Rot");
302 mixin CP_DefineBodyStructProperty!(cpFloat, "v_limit", "VelLimit");
303 mixin CP_DefineBodyStructProperty!(cpFloat, "w_limit", "AngVelLimit");
304 mixin CP_DefineBodyStructProperty!(cpDataPointer, "data", "UserData");
305 
306 /// Convert body_ relative/local coordinates to absolute/world coordinates.
307 cpVect cpBodyLocal2World(const cpBody* bdy, const cpVect v)
308 {
309     return cpvadd(bdy.p, cpvrotate(v, bdy.rot));
310 }
311 
312 /// Convert body_ absolute/world coordinates to  relative/local coordinates.
313 cpVect cpBodyWorld2Local(const cpBody* bdy, const cpVect v)
314 {
315     return cpvunrotate(cpvsub(v, bdy.p), bdy.rot);
316 }
317 
318 /// Get the kinetic energy of a body_.
319 cpFloat cpBodyKineticEnergy(const cpBody* bdy)
320 {
321     // Need to do some fudging to avoid NaNs
322     cpFloat vsq = cpvdot(bdy.v, bdy.v);
323     cpFloat wsq = bdy.w * bdy.w;
324     return (vsq ? vsq * bdy.m : 0.0f) + (wsq ? wsq * bdy.i : 0.0f);
325 }
326 
327 /// Body/shape iterator callback function type.
328 alias cpBodyShapeIteratorFunc= void function(cpBody* bdy, cpShape* shape, void* data);
329 
330 /// Body/constraint iterator callback function type.
331 alias cpBodyConstraintIteratorFunc= void function(cpBody* bdy, cpConstraint* constraint, void* data);
332 
333 /// Body/arbiter iterator callback function type.
334 alias cpBodyArbiterIteratorFunc = void function(cpBody* bdy, cpArbiter* arbiter, void* data);
335 
336 // initialized in cpInitChipmunk()
337 __gshared cpBody cpStaticBodySingleton;
338 
339 cpBody* cpBodyAlloc()
340 {
341     return cast(cpBody*)cpcalloc(1, cpBody.sizeof);
342 }
343 
344 cpBody* cpBodyInit(cpBody* body_, cpFloat m, cpFloat i)
345 {
346     body_.space          = null;
347     body_.shapeList      = null;
348     body_.arbiterList    = null;
349     body_.constraintList = null;
350 
351     body_.velocity_func = &cpBodyUpdateVelocity;
352     body_.position_func = &cpBodyUpdatePosition;
353 
354     cpComponentNode node = { null, null, 0.0f };
355     body_.node = node;
356 
357     body_.p = cpvzero;
358     body_.v = cpvzero;
359     body_.f = cpvzero;
360 
361     body_.w = 0.0f;
362     body_.t = 0.0f;
363 
364     body_.v_bias = cpvzero;
365     body_.w_bias = 0.0f;
366 
367     body_.v_limit = cast(cpFloat)INFINITY;
368     body_.w_limit = cast(cpFloat)INFINITY;
369 
370     body_.data = null;
371 
372     // Setters must be called after full initialization so the sanity checks don't assert on garbage data.
373     cpBodySetMass(body_, m);
374     cpBodySetMoment(body_, i);
375     cpBodySetAngle(body_, 0.0f);
376 
377     return body_;
378 }
379 
380 cpBody* cpBodyNew(cpFloat m, cpFloat i)
381 {
382     return cpBodyInit(cpBodyAlloc(), m, i);
383 }
384 
385 cpBody* cpBodyInitStatic(cpBody* body_)
386 {
387     cpBodyInit(body_, cast(cpFloat)INFINITY, cast(cpFloat)INFINITY);
388     body_.node.idleTime = cast(cpFloat)INFINITY;
389 
390     return body_;
391 }
392 
393 cpBody* cpBodyNewStatic()
394 {
395     return cpBodyInitStatic(cpBodyAlloc());
396 }
397 
398 void cpBodyDestroy(cpBody* body_)
399 {
400 }
401 
402 extern(C) void cpBodyFreeVoid(void* body_)
403 {
404     cpBodyFree(cast(cpBody*)body_);
405 }
406 
407 void cpBodyFree(cpBody* body_)
408 {
409     if (body_)
410     {
411         cpBodyDestroy(body_);
412         cpfree(body_);
413     }
414 }
415 
416 void cpv_assert_nan(cpVect v, string message)
417 {
418     cpAssertSoft(v.x == v.x && v.y == v.y, message);
419 }
420 
421 void cpv_assert_infinite(cpVect v, string message)
422 {
423     cpAssertSoft(cpfabs(v.x) != INFINITY && cpfabs(v.y) != INFINITY, message);
424 }
425 
426 void cpv_assert_sane(cpVect v, string message)
427 {
428     cpv_assert_nan(v, message);
429     cpv_assert_infinite(v, message);
430 }
431 
432 void cpBodySanityCheck(cpBody* body_)
433 {
434     cpAssertSoft(body_.m == body_.m && body_.m_inv == body_.m_inv, "Body's mass is invalid.");
435     cpAssertSoft(body_.i == body_.i && body_.i_inv == body_.i_inv, "Body's moment is invalid.");
436 
437     cpv_assert_sane(body_.p, "Body's position is invalid.");
438     cpv_assert_sane(body_.v, "Body's velocity is invalid.");
439     cpv_assert_sane(body_.f, "Body's force is invalid.");
440 
441     cpAssertSoft(body_.a == body_.a && cpfabs(body_.a) != INFINITY, "Body's angle is invalid.");
442     cpAssertSoft(body_.w == body_.w && cpfabs(body_.w) != INFINITY, "Body's angular velocity is invalid.");
443     cpAssertSoft(body_.t == body_.t && cpfabs(body_.t) != INFINITY, "Body's torque is invalid.");
444 
445     cpv_assert_sane(body_.rot, "Body's rotation vector is invalid.");
446 
447     cpAssertSoft(body_.v_limit == body_.v_limit, "Body's velocity limit is invalid.");
448     cpAssertSoft(body_.w_limit == body_.w_limit, "Body's angular velocity limit is invalid.");
449 }
450 
451 void cpBodySetMass(cpBody* body_, cpFloat mass)
452 {
453     cpAssertHard(mass > 0.0f, "Mass must be positive and non-zero.");
454 
455     cpBodyActivate(body_);
456     body_.m     = mass;
457     body_.m_inv = 1.0f / mass;
458     cpBodyAssertSane(body_);
459 }
460 
461 void cpBodySetMoment(cpBody* body_, cpFloat moment)
462 {
463     cpAssertHard(moment > 0.0f, "Moment of Inertia must be positive and non-zero.");
464 
465     cpBodyActivate(body_);
466     body_.i     = moment;
467     body_.i_inv = 1.0f / moment;
468     cpBodyAssertSane(body_);
469 }
470 
471 void cpBodyAddShape(cpBody* body_, cpShape* shape)
472 {
473     cpShape* next = body_.shapeList;
474 
475     if (next)
476         next.prev = shape;
477 
478     shape.next     = next;
479     body_.shapeList = shape;
480 }
481 
482 void cpBodyRemoveShape(cpBody* body_, cpShape* shape)
483 {
484     cpShape* prev = shape.prev;
485     cpShape* next = shape.next;
486 
487     if (prev)
488     {
489         prev.next = next;
490     }
491     else
492     {
493         body_.shapeList = next;
494     }
495 
496     if (next)
497     {
498         next.prev = prev;
499     }
500 
501     shape.prev = null;
502     shape.next = null;
503 }
504 
505 cpConstraint* filterConstraints(cpConstraint* node, cpBody* body_, cpConstraint* filter)
506 {
507     if (node == filter)
508     {
509         return cpConstraintNext(node, body_);
510     }
511     else if (node.a == body_)
512     {
513         node.next_a = filterConstraints(node.next_a, body_, filter);
514     }
515     else
516     {
517         node.next_b = filterConstraints(node.next_b, body_, filter);
518     }
519 
520     return node;
521 }
522 
523 void cpBodyRemoveConstraint(cpBody* body_, cpConstraint* constraint)
524 {
525     body_.constraintList = filterConstraints(body_.constraintList, body_, constraint);
526 }
527 
528 void cpBodySetPos(cpBody* body_, cpVect pos)
529 {
530     cpBodyActivate(body_);
531     body_.p = pos;
532     cpBodyAssertSane(body_);
533 }
534 
535 void setAngle(cpBody* body_, cpFloat angle)
536 {
537     body_.a   = angle;  //fmod(a, (cpFloat)M_PI*2.0f);
538     body_.rot = cpvforangle(angle);
539     cpBodyAssertSane(body_);
540 }
541 
542 void cpBodySetAngle(cpBody* body_, cpFloat angle)
543 {
544     cpBodyActivate(body_);
545     setAngle(body_, angle);
546 }
547 
548 void cpBodyUpdateVelocity(cpBody* body_, cpVect gravity, cpFloat damping, cpFloat dt)
549 {
550     body_.v = cpvclamp(cpvadd(cpvmult(body_.v, damping), cpvmult(cpvadd(gravity, cpvmult(body_.f, body_.m_inv)), dt)), body_.v_limit);
551 
552     cpFloat w_limit = body_.w_limit;
553     body_.w = cpfclamp(body_.w * damping + body_.t * body_.i_inv * dt, -w_limit, w_limit);
554 
555     cpBodySanityCheck(body_);
556 }
557 
558 void cpBodyUpdatePosition(cpBody* body_, cpFloat dt)
559 {
560     body_.p = cpvadd(body_.p, cpvmult(cpvadd(body_.v, body_.v_bias), dt));
561     setAngle(body_, body_.a + (body_.w + body_.w_bias) * dt);
562 
563     body_.v_bias = cpvzero;
564     body_.w_bias = 0.0f;
565 
566     cpBodySanityCheck(body_);
567 }
568 
569 void cpBodyResetForces(cpBody* body_)
570 {
571     cpBodyActivate(body_);
572     body_.f = cpvzero;
573     body_.t = 0.0f;
574 }
575 
576 void cpBodyApplyForce(cpBody* body_, cpVect force, cpVect r)
577 {
578     cpBodyActivate(body_);
579     body_.f  = cpvadd(body_.f, force);
580     body_.t += cpvcross(r, force);
581 }
582 
583 void cpBodyApplyImpulse(cpBody* body_, const cpVect j, const cpVect r)
584 {
585     cpBodyActivate(body_);
586     apply_impulse(body_, j, r);
587 }
588 
589 cpVect cpBodyGetVelAtPoint(cpBody* body_, cpVect r)
590 {
591     return cpvadd(body_.v, cpvmult(cpvperp(r), body_.w));
592 }
593 
594 cpVect cpBodyGetVelAtWorldPoint(cpBody* body_, cpVect point)
595 {
596     return cpBodyGetVelAtPoint(body_, cpvsub(point, body_.p));
597 }
598 
599 cpVect cpBodyGetVelAtLocalPoint(cpBody* body_, cpVect point)
600 {
601     return cpBodyGetVelAtPoint(body_, cpvrotate(point, body_.rot));
602 }
603 
604 void cpBodyEachShape(cpBody* body_, cpBodyShapeIteratorFunc func, void* data)
605 {
606     cpShape* shape = body_.shapeList;
607 
608     while (shape)
609     {
610         cpShape* next = shape.next;
611         func(body_, shape, data);
612         shape = next;
613     }
614 }
615 
616 void cpBodyEachConstraint(cpBody* body_, cpBodyConstraintIteratorFunc func, void* data)
617 {
618     cpConstraint* constraint = body_.constraintList;
619 
620     while (constraint)
621     {
622         cpConstraint* next = cpConstraintNext(constraint, body_);
623         func(body_, constraint, data);
624         constraint = next;
625     }
626 }
627 
628 void cpBodyEachArbiter(cpBody* body_, cpBodyArbiterIteratorFunc func, void* data)
629 {
630     cpArbiter* arb = body_.arbiterList;
631 
632     while (arb)
633     {
634         cpArbiter* next = cpArbiterNext(arb, body_);
635 
636         arb.swappedColl = (body_ == arb.body_b);
637         func(body_, arb, data);
638 
639         arb = next;
640     }
641 }
642 
643 void cpBodyPushArbiter(cpBody* body_, cpArbiter* arb)
644 {
645     cpAssertSoft(cpArbiterThreadForBody(arb, body_).next == null, "Internal Error: Dangling contact graph pointers detected. (A)");
646     cpAssertSoft(cpArbiterThreadForBody(arb, body_).prev == null, "Internal Error: Dangling contact graph pointers detected. (B)");
647 
648     cpArbiter* next = body_.arbiterList;
649     cpAssertSoft(next == null || cpArbiterThreadForBody(next, body_).prev == null, "Internal Error: Dangling contact graph pointers detected. (C)");
650     cpArbiterThreadForBody(arb, body_).next = next;
651 
652     if (next)
653         cpArbiterThreadForBody(next, body_).prev = arb;
654     body_.arbiterList = arb;
655 }
656 
657 /** Workaround for https://github.com/slembcke/Chipmunk2D/issues/56. */
658 void cpBodyActivateWrap(cpBody* body_, void* data)
659 {
660     cpBodyActivate(body_);
661 }