2 * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
4 * Permission to use, copy, modify, distribute and sell this software
5 * and its documentation for any purpose is hereby granted without fee,
6 * provided that the above copyright notice appear in all copies.
7 * Erin Catto makes no representations about the suitability
8 * of this software for any purpose.
9 * It is provided "as is" without express or implied warranty.
11 module b2dlite
.arbiter
;
13 import b2dlite
.mathutils
;
33 float separation
= 0.0f;
34 float Pn
= 0.0f; // accumulated normal impulse
35 float Pt
= 0.0f; // accumulated tangent impulse
36 float Pnb
= 0.0f; // accumulated normal impulse for position bias
37 float massNormal
, massTangent
;
44 private import b2dlite
.bbody
: Body
;
50 Contact
[MAX_POINTS
] contacts
;
60 this (Body b1
, Body b2
) {
61 import std
.math
: sqrt
;
62 import b2dlite
.collide
: Collide
;
71 numContacts
= Collide(contacts
.ptr
, body1
, body2
);
72 friction
= sqrt(body1
.friction
*body2
.friction
);
77 glColor3f(1.0f, 0.0f, 0.0f);
79 for (int i = 0; i < numContacts; ++i) glVertex2f(contacts[i].position.x, contacts[i].position.y);
85 void Update (Contact
* newContacts
, int numNewContacts
) {
86 import b2dlite
.world
: World
;
88 Contact
[2] mergedContacts
;
89 for (int i
= 0; i
< numNewContacts
; ++i
) {
90 Contact
*cNew
= newContacts
+i
;
92 for (int j
= 0; j
< numContacts
; ++j
) {
93 Contact
* cOld
= contacts
.ptr
+j
;
94 if (cNew
.feature
.value
== cOld
.feature
.value
) { k
= j
; break; }
97 Contact
* c
= mergedContacts
.ptr
+i
;
98 Contact
* cOld
= contacts
.ptr
+k
;
100 if (World
.warmStarting
) {
110 mergedContacts
[i
] = newContacts
[i
];
113 for (int i
= 0; i
< numNewContacts
; ++i
) contacts
[i
] = mergedContacts
[i
];
114 numContacts
= numNewContacts
;
117 void PreStep (float inv_dt
) {
118 import b2dlite
.world
: World
;
120 enum k_allowedPenetration
= 0.01f;
121 float k_biasFactor
= (World
.positionCorrection ?
0.2f : 0.0f);
122 for (int i
= 0; i
< numContacts
; ++i
) {
123 Contact
*c
= contacts
.ptr
+i
;
124 Vec2 r1
= c
.position
-body1
.position
;
125 Vec2 r2
= c
.position
-body2
.position
;
127 // precompute normal mass, tangent mass, and bias
128 float rn1
= Dot(r1
, c
.normal
);
129 float rn2
= Dot(r2
, c
.normal
);
130 float kNormal
= body1
.invMass
+body2
.invMass
;
131 kNormal
+= body1
.invI
*(Dot(r1
, r1
)-rn1
*rn1
)+body2
.invI
*(Dot(r2
, r2
)-rn2
*rn2
);
132 c
.massNormal
= 1.0f/kNormal
;
134 Vec2 tangent
= Cross(c
.normal
, 1.0f);
135 float rt1
= Dot(r1
, tangent
);
136 float rt2
= Dot(r2
, tangent
);
137 float kTangent
= body1
.invMass
+body2
.invMass
;
138 kTangent
+= body1
.invI
*(Dot(r1
, r1
)-rt1
*rt1
)+body2
.invI
*(Dot(r2
, r2
)-rt2
*rt2
);
139 c
.massTangent
= 1.0f/kTangent
;
141 c
.bias
= -k_biasFactor
*inv_dt
*Min(0.0f, c
.separation
+k_allowedPenetration
);
143 if (World
.accumulateImpulses
) {
144 // apply normal + friction impulse
145 Vec2 P
= c
.Pn
*c
.normal
+c
.Pt
*tangent
;
147 body1
.velocity
-= body1
.invMass
*P
;
148 body1
.angularVelocity
-= body1
.invI
*Cross(r1
, P
);
150 body2
.velocity
+= body2
.invMass
*P
;
151 body2
.angularVelocity
+= body2
.invI
*Cross(r2
, P
);
156 void ApplyImpulse () {
157 import b2dlite
.world
: World
;
162 for (int i
= 0; i
< numContacts
; ++i
) {
163 Contact
*c
= contacts
.ptr
+i
;
164 c
.r1
= c
.position
-b1
.position
;
165 c
.r2
= c
.position
-b2
.position
;
167 // relative velocity at contact
168 Vec2 dv
= b2
.velocity
+Cross(b2
.angularVelocity
, c
.r2
)-b1
.velocity
-Cross(b1
.angularVelocity
, c
.r1
);
170 // compute normal impulse
171 float vn
= Dot(dv
, c
.normal
);
173 float dPn
= c
.massNormal
*(-vn
+c
.bias
);
175 if (World
.accumulateImpulses
) {
176 // clamp the accumulated impulse
178 c
.Pn
= Max(Pn0
+dPn
, 0.0f);
181 dPn
= Max(dPn
, 0.0f);
184 // apply contact impulse
185 Vec2 Pn
= dPn
*c
.normal
;
187 b1
.velocity
-= b1
.invMass
*Pn
;
188 b1
.angularVelocity
-= b1
.invI
*Cross(c
.r1
, Pn
);
190 b2
.velocity
+= b2
.invMass
*Pn
;
191 b2
.angularVelocity
+= b2
.invI
*Cross(c
.r2
, Pn
);
193 // relative velocity at contact
194 dv
= b2
.velocity
+Cross(b2
.angularVelocity
, c
.r2
)-b1
.velocity
-Cross(b1
.angularVelocity
, c
.r1
);
196 Vec2 tangent
= Cross(c
.normal
, 1.0f);
197 float vt
= Dot(dv
, tangent
);
198 float dPt
= c
.massTangent
*(-vt
);
200 if (World
.accumulateImpulses
) {
201 // compute friction impulse
202 float maxPt
= friction
*c
.Pn
;
204 float oldTangentImpulse
= c
.Pt
;
205 c
.Pt
= Clamp(oldTangentImpulse
+dPt
, -maxPt
, maxPt
);
206 dPt
= c
.Pt
-oldTangentImpulse
;
208 float maxPt
= friction
*dPn
;
209 dPt
= Clamp(dPt
, -maxPt
, maxPt
);
212 // apply contact impulse
213 Vec2 Pt
= dPt
*tangent
;
215 b1
.velocity
-= b1
.invMass
*Pt
;
216 b1
.angularVelocity
-= b1
.invI
*Cross(c
.r1
, Pt
);
218 b2
.velocity
+= b2
.invMass
*Pt
;
219 b2
.angularVelocity
+= b2
.invI
*Cross(c
.r2
, Pt
);
224 int opCmp() (in Arbiter a2) {
225 //if (this.body1 < a2.body1) return -1;
226 if (this.body1 > a2.body1) return -1;
227 if (this.body1 == a2.body1 && this.body2 < a2.body2) return -1;
234 //extern int Collide (Contact *contacts, Body body1, Body body2);