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 }