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.cpSimpleMotor;
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* cpSimpleMotorGetClass();
34 
35 /// @private
36 struct cpSimpleMotor
37 {
38     cpConstraint constraint;
39     cpFloat rate = 0;
40 
41     cpFloat iSum = 0;
42 
43     cpFloat jAcc = 0;
44 }
45 
46 mixin CP_DefineConstraintProperty!("cpSimpleMotor", cpFloat, "rate", "Rate");
47 
48 void preStep(cpSimpleMotor* joint, cpFloat dt)
49 {
50     cpBody* a = joint.constraint.a;
51     cpBody* b = joint.constraint.b;
52 
53     // calculate moment of inertia coefficient.
54     joint.iSum = 1.0f / (a.i_inv + b.i_inv);
55 }
56 
57 void applyCachedImpulse(cpSimpleMotor* joint, cpFloat dt_coef)
58 {
59     cpBody* a = joint.constraint.a;
60     cpBody* b = joint.constraint.b;
61 
62     cpFloat j = joint.jAcc * dt_coef;
63     a.w -= j * a.i_inv;
64     b.w += j * b.i_inv;
65 }
66 
67 void applyImpulse(cpSimpleMotor* joint, cpFloat dt)
68 {
69     cpBody* a = joint.constraint.a;
70     cpBody* b = joint.constraint.b;
71 
72     // compute relative rotational velocity
73     cpFloat wr = b.w - a.w + joint.rate;
74 
75     cpFloat jMax = joint.constraint.maxForce * dt;
76 
77     // compute normal impulse
78     cpFloat j    = -wr * joint.iSum;
79     cpFloat jOld = joint.jAcc;
80     joint.jAcc = cpfclamp(jOld + j, -jMax, jMax);
81     j = joint.jAcc - jOld;
82 
83     // apply impulse
84     a.w -= j * a.i_inv;
85     b.w += j * b.i_inv;
86 }
87 
88 cpFloat getImpulse(cpSimpleMotor* joint)
89 {
90     return cpfabs(joint.jAcc);
91 }
92 
93 __gshared cpConstraintClass klass;
94 
95 void _initModuleCtor_cpSimpleMotor()
96 {
97     klass = cpConstraintClass(
98         cast(cpConstraintPreStepImpl)&preStep,
99         cast(cpConstraintApplyCachedImpulseImpl)&applyCachedImpulse,
100         cast(cpConstraintApplyImpulseImpl)&applyImpulse,
101         cast(cpConstraintGetImpulseImpl)&getImpulse,
102     );
103 }
104 
105 const(cpConstraintClass *) cpSimpleMotorGetClass()
106 {
107     return cast(cpConstraintClass*)&klass;
108 }
109 
110 cpSimpleMotor *
111 cpSimpleMotorAlloc()
112 {
113     return cast(cpSimpleMotor*)cpcalloc(1, cpSimpleMotor.sizeof);
114 }
115 
116 cpSimpleMotor* cpSimpleMotorInit(cpSimpleMotor* joint, cpBody* a, cpBody* b, cpFloat rate)
117 {
118     cpConstraintInit(cast(cpConstraint*)joint, &klass, a, b);
119 
120     joint.rate = rate;
121 
122     joint.jAcc = 0.0f;
123 
124     return joint;
125 }
126 
127 cpConstraint* cpSimpleMotorNew(cpBody* a, cpBody* b, cpFloat rate)
128 {
129     return cast(cpConstraint*)cpSimpleMotorInit(cpSimpleMotorAlloc(), a, b, rate);
130 }