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.chipmunk_private;
23 
24 import std..string;
25 
26 import dchip.cpArray;
27 import dchip.cpBody;
28 import dchip.chipmunk;
29 import dchip.chipmunk_types;
30 import dchip.cpArbiter;
31 import dchip.cpConstraint;
32 import dchip.cpHashSet;
33 import dchip.cpPolyShape;
34 import dchip.cpShape;
35 import dchip.cpSpace;
36 import dchip.cpSpatialIndex;
37 import dchip.cpVect;
38 
39 enum CP_HASH_COEF = 3344921057uL;
40 
41 cpHashValue CP_HASH_PAIR(T1, T2)(T1 a, T2 b)
42 {
43     return cast(cpHashValue)(cast(cpHashValue)a * CP_HASH_COEF ^ cast(cpHashValue)b * CP_HASH_COEF);
44 }
45 
46 // TODO: Eww. Magic numbers.
47 enum MAGIC_EPSILON = 1e-5;
48 
49 struct cpArray
50 {
51     int num, max;
52     void** arr;
53 }
54 
55 cpConstraint* cpConstraintNext(cpConstraint* node, cpBody* bdy)
56 {
57     return (node.a == bdy ? node.next_a : node.next_b);
58 }
59 
60 template CP_BODY_FOREACH_CONSTRAINT(string bdy, string var, string code)
61 {
62     enum CP_BODY_FOREACH_CONSTRAINT = format("for (cpConstraint* %2$s = %1$s.constraintList; %2$s; %2$s = cpConstraintNext(%2$s, %1$s)) { %3$s }",
63              bdy, var, code);
64 }
65 
66 cpArbiter* cpArbiterNext(cpArbiter* node, cpBody* bdy)
67 {
68     return (node.body_a == bdy ? node.thread_a.next : node.thread_b.next);
69 }
70 
71 template CP_BODY_FOREACH_ARBITER(string bdy, string var, string code)
72 {
73     enum CP_BODY_FOREACH_ARBITER = format("for (cpArbiter* %2$s = %1$s.arbiterList; %2$s; %2$s = cpArbiterNext(%2$s, %1$s)) { %3$s }",
74              bdy, var, code);
75 }
76 
77 template CP_BODY_FOREACH_SHAPE(string bdy, string var, string code)
78 {
79     enum CP_BODY_FOREACH_SHAPE = format("for (cpShape* %2$s = %1$s.shapeList; %2$s; %2$s = %2$s.next) { %3$s }",
80             bdy, var, code);
81 }
82 
83 template CP_BODY_FOREACH_COMPONENT(string root, string var, string code)
84 {
85     enum CP_BODY_FOREACH_COMPONENT = format("for (cpBody* %2$s = %1$s; %2$s; %2$s = %2$s.node.next) { %3$s }",
86              root, var, code);
87 }
88 
89 alias cpHashSetEqlFunc = cpBool function(void* ptr, void* elt);
90 alias cpHashSetTransFunc = void* function(void* ptr, void* data);
91 
92 alias cpHashSetIteratorFunc = void function(void* elt, void* data);
93 alias cpHashSetFilterFunc = cpBool function(void* elt, void* data);
94 
95 // TODO should move this to the cpVect API. It's pretty useful.
96 cpVect cpClosetPointOnSegment(const cpVect p, const cpVect a, const cpVect b)
97 {
98     cpVect  delta = cpvsub(a, b);
99     cpFloat t     = cpfclamp01(cpvdot(delta, cpvsub(p, b)) / cpvlengthsq(delta));
100     return cpvadd(b, cpvmult(delta, t));
101 }
102 
103 cpBool cpShapeActive(cpShape* shape)
104 {
105     return shape.prev || (shape.body_ && shape.body_.shapeList == shape);
106 }
107 
108 void CircleSegmentQuery(cpShape* shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo* info)
109 {
110     cpVect da = cpvsub(a, center);
111     cpVect db = cpvsub(b, center);
112 
113     cpFloat qa = cpvdot(da, da) - 2.0f * cpvdot(da, db) + cpvdot(db, db);
114     cpFloat qb = -2.0f * cpvdot(da, da) + 2.0f * cpvdot(da, db);
115     cpFloat qc = cpvdot(da, da) - r * r;
116 
117     cpFloat det = qb * qb - 4.0f * qa * qc;
118 
119     if (det >= 0.0f)
120     {
121         cpFloat t = (-qb - cpfsqrt(det)) / (2.0f * qa);
122 
123         if (0.0f <= t && t <= 1.0f)
124         {
125             info.shape = shape;
126             info.t     = t;
127             info.n     = cpvnormalize(cpvlerp(da, db, t));
128         }
129     }
130 }
131 
132 // TODO doesn't really need to be inline, but need a better place to put this function
133 cpSplittingPlane cpSplittingPlaneNew(cpVect a, cpVect b)
134 {
135     cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));
136     cpSplittingPlane plane = { n, cpvdot(n, a) };
137     return plane;
138 }
139 
140 cpFloat cpSplittingPlaneCompare(cpSplittingPlane plane, cpVect v)
141 {
142     return cpvdot(plane.n, v) - plane.d;
143 }
144 
145 struct cpPostStepCallback
146 {
147     cpPostStepFunc func;
148     void* key;
149     void* data;
150 }
151 
152 cpCollisionHandler* cpSpaceLookupHandler(cpSpace* space, cpCollisionType a, cpCollisionType b)
153 {
154     cpCollisionType[2] types = void;
155     types[0] = a;
156     types[1] = b;
157     return cast(cpCollisionHandler*)cpHashSetFind(space.collisionHandlers, CP_HASH_PAIR(a, b), types.ptr);
158 }
159 
160 void cpSpaceUncacheArbiter(cpSpace* space, cpArbiter* arb)
161 {
162     cpShape* a = arb.a, b = arb.b;
163     cpShape*[2] shape_pair = void;
164     shape_pair[0] = a;
165     shape_pair[1] = b;
166     cpHashValue arbHashID = CP_HASH_PAIR(cast(cpHashValue)a, cast(cpHashValue)b);
167     cpHashSetRemove(space.cachedArbiters, arbHashID, shape_pair.ptr);
168     cpArrayDeleteObj(space.arbiters, arb);
169 }
170 
171 struct cpContact
172 {
173     cpVect p, n;
174     cpFloat dist = 0;
175 
176     cpVect r1, r2;
177     cpFloat nMass = 0, tMass = 0, bounce = 0;
178 
179     cpFloat jnAcc = 0, jtAcc = 0, jBias = 0;
180     cpFloat bias = 0;
181 
182     cpHashValue hash;
183 }
184 
185 void cpArbiterCallSeparate(cpArbiter* arb, cpSpace* space)
186 {
187     // The handler needs to be looked up again as the handler cached on the arbiter may have been deleted since the last step.
188     cpCollisionHandler* handler = cpSpaceLookupHandler(space, arb.a.collision_type, arb.b.collision_type);
189     handler.separate(arb, space, handler.data);
190 }
191 
192 cpArbiterThread* cpArbiterThreadForBody(cpArbiter* arb, cpBody* bdy)
193 {
194     return (arb.body_a == bdy ? &arb.thread_a : &arb.thread_b);
195 }