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.cpConstraint; 23 24 import std..string; 25 26 import dchip.cpBody; 27 import dchip.chipmunk; 28 import dchip.chipmunk_types; 29 import dchip.cpSpace; 30 31 alias cpConstraintPreStepImpl = void function(cpConstraint* constraint, cpFloat dt); 32 alias cpConstraintApplyCachedImpulseImpl = void function(cpConstraint* constraint, cpFloat dt_coef); 33 alias cpConstraintApplyImpulseImpl = void function(cpConstraint* constraint, cpFloat dt); 34 alias cpConstraintGetImpulseImpl = cpFloat function(cpConstraint* constraint); 35 36 /// @private 37 struct cpConstraintClass 38 { 39 cpConstraintPreStepImpl preStep; 40 cpConstraintApplyCachedImpulseImpl applyCachedImpulse; 41 cpConstraintApplyImpulseImpl applyImpulse; 42 cpConstraintGetImpulseImpl getImpulse; 43 } 44 45 /// Callback function type that gets called before solving a joint. 46 alias cpConstraintPreSolveFunc = void function(cpConstraint* constraint, cpSpace* space); 47 48 /// Callback function type that gets called after solving a joint. 49 alias cpConstraintPostSolveFunc = void function(cpConstraint* constraint, cpSpace* space); 50 51 /// Opaque cpConstraint struct. 52 struct cpConstraint 53 { 54 version (CHIP_ALLOW_PRIVATE_ACCESS) 55 /* const */ cpConstraintClass * klass; 56 else 57 package /* const */ cpConstraintClass * klass; 58 59 /// The first body connected to this constraint. 60 cpBody* a; 61 62 /// The second body connected to this constraint. 63 cpBody* b; 64 65 version (CHIP_ALLOW_PRIVATE_ACCESS) 66 cpSpace * space; 67 else 68 package cpSpace * space; 69 70 version (CHIP_ALLOW_PRIVATE_ACCESS) 71 cpConstraint * next_a; 72 else 73 package cpConstraint * next_a; 74 75 version (CHIP_ALLOW_PRIVATE_ACCESS) 76 cpConstraint * next_b; 77 else 78 package cpConstraint * next_b; 79 80 /// The maximum force that this constraint is allowed to use. 81 /// Defaults to infinity. 82 cpFloat maxForce = 0; 83 84 /// The rate at which joint error is corrected. 85 /// Defaults to pow(1.0 - 0.1, 60.0) meaning that it will 86 /// correct 10% of the error every 1/60th of a second. 87 cpFloat errorBias = 0; 88 89 /// The maximum rate at which joint error is corrected. 90 /// Defaults to infinity. 91 cpFloat maxBias = 0; 92 93 /// Function called before the solver runs. 94 /// Animate your joint anchors, update your motor torque, etc. 95 cpConstraintPreSolveFunc preSolve; 96 97 /// Function called after the solver runs. 98 /// Use the applied impulse to perform effects like breakable joints. 99 cpConstraintPostSolveFunc postSolve; 100 101 /// User definable data pointer. 102 /// Generally this points to your the game object class so you can access it 103 /// when given a cpConstraint reference in a callback. 104 cpDataPointer data; 105 } 106 107 /// @private 108 void cpConstraintActivateBodies(cpConstraint* constraint) 109 { 110 cpBody* a = constraint.a; 111 112 if (a) 113 cpBodyActivate(a); 114 115 cpBody* b = constraint.b; 116 117 if (b) 118 cpBodyActivate(b); 119 } 120 121 mixin template CP_DefineConstraintStructGetter(type, string member, string name) 122 { 123 mixin(q{ 124 type cpConstraintGet%s(const cpConstraint * constraint) { return cast(typeof(return))constraint.%s; } 125 }.format(name, member)); 126 } 127 128 mixin template CP_DefineConstraintStructSetter(type, string member, string name) 129 { 130 mixin(q{ 131 void cpConstraintSet%s(cpConstraint * constraint, type value) 132 { 133 cpConstraintActivateBodies(constraint); 134 constraint.%s = value; 135 } 136 }.format(name, member)); 137 } 138 139 mixin template CP_DefineConstraintStructProperty(type, string member, string name) 140 { 141 mixin CP_DefineConstraintStructGetter!(type, member, name); 142 mixin CP_DefineConstraintStructSetter!(type, member, name); 143 } 144 145 mixin CP_DefineConstraintStructGetter!(cpSpace*, "space", "Space"); 146 147 mixin CP_DefineConstraintStructGetter!(cpBody*, "a", "A"); 148 mixin CP_DefineConstraintStructGetter!(cpBody*, "b", "B"); 149 mixin CP_DefineConstraintStructProperty!(cpFloat, "maxForce", "MaxForce"); 150 mixin CP_DefineConstraintStructProperty!(cpFloat, "errorBias", "ErrorBias"); 151 mixin CP_DefineConstraintStructProperty!(cpFloat, "maxBias", "MaxBias"); 152 mixin CP_DefineConstraintStructProperty!(cpConstraintPreSolveFunc, "preSolve", "PreSolveFunc"); 153 mixin CP_DefineConstraintStructProperty!(cpConstraintPostSolveFunc, "postSolve", "PostSolveFunc"); 154 mixin CP_DefineConstraintStructProperty!(cpDataPointer, "data", "UserData"); 155 156 // Get the last impulse applied by this constraint. 157 cpFloat cpConstraintGetImpulse(cpConstraint* constraint) 158 { 159 return constraint.klass.getImpulse(constraint); 160 } 161 162 string cpConstraintCheckCast(string constraint, string struct_) 163 { 164 return `cpAssertHard(%1$s.klass == %2$sGetClass(), "Constraint is not a %2$s");`.format(constraint, struct_); 165 } 166 167 mixin template CP_DefineConstraintGetter(string struct_, type, string member, string name) 168 { 169 enum mixStr = `mixin(cpConstraintCheckCast("constraint", "%1$s"));`.format(struct_); 170 171 mixin(q{ 172 type %1$sGet%2$s(const cpConstraint* constraint) 173 { 174 %4$s 175 return cast(typeof(return))((cast(%1$s*)constraint).%3$s); 176 } 177 }.format(struct_, name, member, mixStr)); 178 } 179 180 mixin template CP_DefineConstraintSetter(string struct_, type, string member, string name) 181 { 182 enum mixStr = `mixin(cpConstraintCheckCast("constraint", "%1$s"));`.format(struct_); 183 184 mixin(q{ 185 void %1$sSet%2$s(cpConstraint * constraint, type value) 186 { 187 %4$s 188 cpConstraintActivateBodies(constraint); 189 (cast(%1$s*)constraint).%3$s= value; 190 } 191 }.format(struct_, name, member, mixStr)); 192 } 193 194 mixin template CP_DefineConstraintProperty(string struct_, type, string member, string name) 195 { 196 mixin CP_DefineConstraintGetter!(struct_, type, member, name); 197 mixin CP_DefineConstraintSetter!(struct_, type, member, name); 198 } 199 200 void cpConstraintDestroy(cpConstraint* constraint) 201 { 202 } 203 204 void cpConstraintFree(cpConstraint* constraint) 205 { 206 if (constraint) 207 { 208 cpConstraintDestroy(constraint); 209 cpfree(constraint); 210 } 211 } 212 213 // *** declared in util.h TODO move declaration to chipmunk_private.h 214 215 void cpConstraintInit(cpConstraint* constraint, const cpConstraintClass* klass, cpBody* a, cpBody* b) 216 { 217 constraint.klass = cast(typeof(constraint.klass))klass; 218 219 constraint.a = a; 220 constraint.b = b; 221 constraint.space = null; 222 223 constraint.next_a = null; 224 constraint.next_b = null; 225 226 constraint.maxForce = cast(cpFloat)INFINITY; 227 constraint.errorBias = cpfpow(1.0f - 0.1f, 60.0f); 228 constraint.maxBias = cast(cpFloat)INFINITY; 229 230 constraint.preSolve = null; 231 constraint.postSolve = null; 232 }