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.cpGrooveJoint; 23 24 import std..string; 25 26 import dchip.constraints_util; 27 import dchip.chipmunk; 28 import dchip.cpBody; 29 import dchip.cpConstraint; 30 import dchip.chipmunk_types; 31 import dchip.cpVect; 32 33 //~ const cpConstraintClass* cpGrooveJointGetClass(); 34 35 /// @private 36 struct cpGrooveJoint 37 { 38 cpConstraint constraint; 39 cpVect grv_n, grv_a, grv_b; 40 cpVect anchr2; 41 42 cpVect grv_tn; 43 cpFloat clamp = 0; 44 cpVect r1, r2; 45 cpMat2x2 k; 46 47 cpVect jAcc; 48 cpVect bias; 49 } 50 51 mixin CP_DefineConstraintGetter!("cpGrooveJoint", cpVect, "grv_a", "GrooveA"); 52 53 /// Set endpoint a of a groove joint's groove 54 void cpGrooveJointSetGrooveA(cpConstraint* constraint, cpVect value); 55 mixin CP_DefineConstraintGetter!("cpGrooveJoint", cpVect, "grv_b", "GrooveB"); 56 57 /// Set endpoint b of a groove joint's groove 58 void cpGrooveJointSetGrooveB(cpConstraint* constraint, cpVect value); 59 mixin CP_DefineConstraintProperty!("cpGrooveJoint", cpVect, "anchr2", "Anchr2"); 60 61 void preStep(cpGrooveJoint* joint, cpFloat dt) 62 { 63 cpBody* a = joint.constraint.a; 64 cpBody* b = joint.constraint.b; 65 66 // calculate endpoints in worldspace 67 cpVect ta = cpBodyLocal2World(a, joint.grv_a); 68 cpVect tb = cpBodyLocal2World(a, joint.grv_b); 69 70 // calculate axis 71 cpVect n = cpvrotate(joint.grv_n, a.rot); 72 cpFloat d = cpvdot(ta, n); 73 74 joint.grv_tn = n; 75 joint.r2 = cpvrotate(joint.anchr2, b.rot); 76 77 // calculate tangential distance along the axis of r2 78 cpFloat td = cpvcross(cpvadd(b.p, joint.r2), n); 79 80 // calculate clamping factor and r2 81 if (td <= cpvcross(ta, n)) 82 { 83 joint.clamp = 1.0f; 84 joint.r1 = cpvsub(ta, a.p); 85 } 86 else if (td >= cpvcross(tb, n)) 87 { 88 joint.clamp = -1.0f; 89 joint.r1 = cpvsub(tb, a.p); 90 } 91 else 92 { 93 joint.clamp = 0.0f; 94 joint.r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a.p); 95 } 96 97 // Calculate mass tensor 98 joint.k = k_tensor(a, b, joint.r1, joint.r2); 99 100 // calculate bias velocity 101 cpVect delta = cpvsub(cpvadd(b.p, joint.r2), cpvadd(a.p, joint.r1)); 102 joint.bias = cpvclamp(cpvmult(delta, -bias_coef(joint.constraint.errorBias, dt) / dt), joint.constraint.maxBias); 103 } 104 105 void applyCachedImpulse(cpGrooveJoint* joint, cpFloat dt_coef) 106 { 107 cpBody* a = joint.constraint.a; 108 cpBody* b = joint.constraint.b; 109 110 apply_impulses(a, b, joint.r1, joint.r2, cpvmult(joint.jAcc, dt_coef)); 111 } 112 113 cpVect grooveConstrain(cpGrooveJoint* joint, cpVect j, cpFloat dt) 114 { 115 cpVect n = joint.grv_tn; 116 cpVect jClamp = (joint.clamp * cpvcross(j, n) > 0.0f) ? j : cpvproject(j, n); 117 return cpvclamp(jClamp, joint.constraint.maxForce * dt); 118 } 119 120 void applyImpulse(cpGrooveJoint* joint, cpFloat dt) 121 { 122 cpBody* a = joint.constraint.a; 123 cpBody* b = joint.constraint.b; 124 125 cpVect r1 = joint.r1; 126 cpVect r2 = joint.r2; 127 128 // compute impulse 129 cpVect vr = relative_velocity(a, b, r1, r2); 130 131 cpVect j = cpMat2x2Transform(joint.k, cpvsub(joint.bias, vr)); 132 cpVect jOld = joint.jAcc; 133 joint.jAcc = grooveConstrain(joint, cpvadd(jOld, j), dt); 134 j = cpvsub(joint.jAcc, jOld); 135 136 // apply impulse 137 apply_impulses(a, b, joint.r1, joint.r2, j); 138 } 139 140 cpFloat getImpulse(cpGrooveJoint* joint) 141 { 142 return cpvlength(joint.jAcc); 143 } 144 145 __gshared cpConstraintClass klass; 146 147 void _initModuleCtor_cpGrooveJoint() 148 { 149 klass = cpConstraintClass( 150 cast(cpConstraintPreStepImpl)&preStep, 151 cast(cpConstraintApplyCachedImpulseImpl)&applyCachedImpulse, 152 cast(cpConstraintApplyImpulseImpl)&applyImpulse, 153 cast(cpConstraintGetImpulseImpl)&getImpulse, 154 ); 155 } 156 157 const(cpConstraintClass *) cpGrooveJointGetClass() 158 { 159 return cast(cpConstraintClass*)&klass; 160 } 161 162 cpGrooveJoint * 163 cpGrooveJointAlloc() 164 { 165 return cast(cpGrooveJoint*)cpcalloc(1, cpGrooveJoint.sizeof); 166 } 167 168 cpGrooveJoint* cpGrooveJointInit(cpGrooveJoint* joint, cpBody* a, cpBody* b, cpVect groove_a, cpVect groove_b, cpVect anchr2) 169 { 170 cpConstraintInit(cast(cpConstraint*)joint, &klass, a, b); 171 172 joint.grv_a = groove_a; 173 joint.grv_b = groove_b; 174 joint.grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a))); 175 joint.anchr2 = anchr2; 176 177 joint.jAcc = cpvzero; 178 179 return joint; 180 } 181 182 cpConstraint* cpGrooveJointNew(cpBody* a, cpBody* b, cpVect groove_a, cpVect groove_b, cpVect anchr2) 183 { 184 return cast(cpConstraint*)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2); 185 } 186 187 void cpGrooveJointSetGrooveA(cpConstraint* constraint, cpVect value) 188 { 189 cpGrooveJoint* g = cast(cpGrooveJoint*)constraint; 190 mixin(cpConstraintCheckCast("constraint", "cpGrooveJoint")); 191 192 g.grv_a = value; 193 g.grv_n = cpvperp(cpvnormalize(cpvsub(g.grv_b, value))); 194 195 cpConstraintActivateBodies(constraint); 196 } 197 198 void cpGrooveJointSetGrooveB(cpConstraint* constraint, cpVect value) 199 { 200 cpGrooveJoint* g = cast(cpGrooveJoint*)constraint; 201 mixin(cpConstraintCheckCast("constraint", "cpGrooveJoint")); 202 203 g.grv_b = value; 204 g.grv_n = cpvperp(cpvnormalize(cpvsub(value, g.grv_a))); 205 206 cpConstraintActivateBodies(constraint); 207 }