Mercurial > projects > chipmunkd
comparison trunk/chipmunkd/cpArbiter.d @ 4:7ebbd4d05553
initial commit
author | Extrawurst |
---|---|
date | Thu, 02 Dec 2010 02:11:26 +0100 |
parents | |
children | c03a41d47b60 |
comparison
equal
deleted
inserted
replaced
3:81145a61c2fe | 4:7ebbd4d05553 |
---|---|
1 | |
2 // written in the D programming language | |
3 | |
4 module chipmunkd.cpArbiter; | |
5 | |
6 import chipmunkd.cpSpace; | |
7 import chipmunkd.cpBody; | |
8 import chipmunkd.cpShape; | |
9 import chipmunkd.chipmunk; | |
10 import chipmunkd.chipmunk_types_h; | |
11 import chipmunkd.cpVect,chipmunkd.cpVect_h; | |
12 import chipmunkd.constraints.util; | |
13 | |
14 // Determines how fast penetrations resolve themselves. | |
15 //extern cpFloat cp_bias_coef; | |
16 // Amount of allowed penetration. Used to reduce vibrating contacts. | |
17 //extern cpFloat cp_collision_slop; | |
18 | |
19 // Data structure for contact points. | |
20 struct cpContact { | |
21 // Contact point and normal. | |
22 cpVect p, n; | |
23 // Penetration distance. | |
24 cpFloat dist; | |
25 | |
26 // Calculated by cpArbiterPreStep(). | |
27 cpVect r1, r2; | |
28 cpFloat nMass, tMass, bounce; | |
29 | |
30 // Persistant contact information. | |
31 cpFloat jnAcc, jtAcc, jBias; | |
32 cpFloat bias; | |
33 | |
34 // Hash value used to (mostly) uniquely identify a contact. | |
35 cpHashValue hash; | |
36 } | |
37 | |
38 //// Contacts are always allocated in groups. | |
39 //cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash); | |
40 // | |
41 //// Sum the contact impulses. (Can be used after cpSpaceStep() returns) | |
42 //cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts); | |
43 //cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts); | |
44 | |
45 enum cpArbiterState { | |
46 cpArbiterStateNormal, | |
47 cpArbiterStateFirstColl, | |
48 cpArbiterStateIgnore, | |
49 cpArbiterStateSleep, | |
50 cpArbiterStateCached, | |
51 } | |
52 | |
53 // Data structure for tracking collisions between shapes. | |
54 struct cpArbiter { | |
55 // Information on the contact points between the objects. | |
56 int numContacts; | |
57 cpContact *contacts; | |
58 | |
59 // The two shapes and bodies involved in the collision. | |
60 // These variables are NOT in the order defined by the collision handler. | |
61 // Using CP_ARBITER_GET_SHAPES and CP_ARBITER_GET_BODIES will save you from | |
62 // many headaches | |
63 cpShape* private_a; | |
64 cpShape* private_b; | |
65 | |
66 // Calculated before calling the pre-solve collision handler | |
67 // Override them with custom values if you want specialized behavior | |
68 cpFloat e; | |
69 cpFloat u; | |
70 // Used for surface_v calculations, implementation may change | |
71 cpVect surface_vr; | |
72 | |
73 // Time stamp of the arbiter. (from cpSpace) | |
74 cpTimestamp stamp; | |
75 | |
76 cpCollisionHandler *handler; | |
77 | |
78 // Are the shapes swapped in relation to the collision handler? | |
79 cpBool swappedColl; | |
80 cpArbiterState state; | |
81 } | |
82 | |
83 //// Arbiters are allocated in large buffers by the space and don't require a destroy function | |
84 //cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b); | |
85 // | |
86 //// These functions are all intended to be used internally. | |
87 //// Inject new contact points into the arbiter while preserving contact history. | |
88 //void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, struct cpCollisionHandler *handler, cpShape *a, cpShape *b); | |
89 //// Precalculate values used by the solver. | |
90 //void cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv); | |
91 //void cpArbiterApplyCachedImpulse(cpArbiter *arb); | |
92 //// Run an iteration of the solver on the arbiter. | |
93 //void cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef); | |
94 // | |
95 //// Arbiter Helper Functions | |
96 //cpVect cpArbiterTotalImpulse(cpArbiter *arb); | |
97 //cpVect cpArbiterTotalImpulseWithFriction(cpArbiter *arb); | |
98 //void cpArbiterIgnore(cpArbiter *arb); | |
99 | |
100 | |
101 static void | |
102 cpArbiterGetShapes(/+const+/ cpArbiter *arb, cpShape **a, cpShape **b) | |
103 { | |
104 if(arb.swappedColl){ | |
105 (*a) = arb.private_b, (*b) = arb.private_a; | |
106 } else { | |
107 (*a) = arb.private_a, (*b) = arb.private_b; | |
108 } | |
109 } | |
110 //#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b); | |
111 template CP_ARBITER_GET_SHAPES(string arb,string a,string b) | |
112 { | |
113 enum CP_ARBITER_GET_SHAPES = "cpShape* "~a~", "~b~";"~ | |
114 "cpArbiterGetShapes("~arb~", &"~a~", &"~b~");"; | |
115 } | |
116 | |
117 static void | |
118 cpArbiterGetBodies(/+const+/ cpArbiter *arb, cpBody **a, cpBody **b) | |
119 { | |
120 //CP_ARBITER_GET_SHAPES(arb, shape_a, shape_b); | |
121 cpShape *shape_a, shape_b; cpArbiterGetShapes(arb, &shape_a, &shape_b); | |
122 (*a) = shape_a._body; | |
123 (*b) = shape_b._body; | |
124 } | |
125 //#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b); | |
126 | |
127 static cpBool | |
128 cpArbiterIsFirstContact(const cpArbiter *arb) | |
129 { | |
130 return arb.state == cpArbiterState.cpArbiterStateFirstColl; | |
131 } | |
132 | |
133 static cpVect | |
134 cpArbiterGetNormal(const cpArbiter *arb, int i) | |
135 { | |
136 cpVect n = arb.contacts[i].n; | |
137 return arb.swappedColl ? cpvneg(n) : n; | |
138 } | |
139 | |
140 static cpVect | |
141 cpArbiterGetPoint(const cpArbiter *arb, int i) | |
142 { | |
143 return arb.contacts[i].p; | |
144 } | |
145 | |
146 cpFloat cp_bias_coef = 0.1f; | |
147 cpFloat cp_collision_slop = 0.1f; | |
148 | |
149 cpContact* | |
150 cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash) | |
151 { | |
152 con.p = p; | |
153 con.n = n; | |
154 con.dist = dist; | |
155 | |
156 con.jnAcc = 0.0f; | |
157 con.jtAcc = 0.0f; | |
158 con.jBias = 0.0f; | |
159 | |
160 con.hash = hash; | |
161 | |
162 return con; | |
163 } | |
164 | |
165 cpVect | |
166 cpArbiterTotalImpulse(cpArbiter *arb) | |
167 { | |
168 cpContact *contacts = arb.contacts; | |
169 cpVect sum = cpvzero; | |
170 | |
171 for(int i=0, count=arb.numContacts; i<count; i++){ | |
172 cpContact *con = &contacts[i]; | |
173 sum = cpvadd(sum, cpvmult(con.n, con.jnAcc)); | |
174 } | |
175 | |
176 return sum; | |
177 } | |
178 | |
179 cpVect | |
180 cpArbiterTotalImpulseWithFriction(cpArbiter *arb) | |
181 { | |
182 cpContact *contacts = arb.contacts; | |
183 cpVect sum = cpvzero; | |
184 | |
185 for(int i=0, count=arb.numContacts; i<count; i++){ | |
186 cpContact *con = &contacts[i]; | |
187 sum = cpvadd(sum, cpvrotate(con.n, cpv(con.jnAcc, con.jtAcc))); | |
188 } | |
189 | |
190 return sum; | |
191 } | |
192 | |
193 cpFloat | |
194 cpContactsEstimateCrushingImpulse(cpContact *contacts, int numContacts) | |
195 { | |
196 cpFloat fsum = 0.0f; | |
197 cpVect vsum = cpvzero; | |
198 | |
199 for(int i=0; i<numContacts; i++){ | |
200 cpContact *con = &contacts[i]; | |
201 cpVect j = cpvrotate(con.n, cpv(con.jnAcc, con.jtAcc)); | |
202 | |
203 fsum += cpvlength(j); | |
204 vsum = cpvadd(vsum, j); | |
205 } | |
206 | |
207 cpFloat vmag = cpvlength(vsum); | |
208 return (1.0f - vmag/fsum); | |
209 } | |
210 | |
211 void | |
212 cpArbiterIgnore(cpArbiter *arb) | |
213 { | |
214 arb.state = cpArbiterState.cpArbiterStateIgnore; | |
215 } | |
216 | |
217 cpArbiter* | |
218 cpArbiterAlloc() | |
219 { | |
220 return cast(cpArbiter *)cpcalloc(1, cpArbiter.sizeof); | |
221 } | |
222 | |
223 cpArbiter* | |
224 cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b) | |
225 { | |
226 arb.numContacts = 0; | |
227 arb.contacts = null; | |
228 | |
229 arb.private_a = a; | |
230 arb.private_b = b; | |
231 | |
232 arb.stamp = 0; | |
233 arb.state = cpArbiterState.cpArbiterStateFirstColl; | |
234 | |
235 return arb; | |
236 } | |
237 | |
238 cpArbiter* | |
239 cpArbiterNew(cpShape *a, cpShape *b) | |
240 { | |
241 return cpArbiterInit(cpArbiterAlloc(), a, b); | |
242 } | |
243 | |
244 void | |
245 cpArbiterDestroy(cpArbiter *arb) | |
246 { | |
247 // if(arb.contacts) cpfree(arb.contacts); | |
248 } | |
249 | |
250 void | |
251 cpArbiterFree(cpArbiter *arb) | |
252 { | |
253 if(arb){ | |
254 cpArbiterDestroy(arb); | |
255 cpfree(arb); | |
256 } | |
257 } | |
258 | |
259 void | |
260 cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, cpCollisionHandler *handler, cpShape *a, cpShape *b) | |
261 { | |
262 // Arbiters without contact data may exist if a collision function rejected the collision. | |
263 if(arb.contacts){ | |
264 // Iterate over the possible pairs to look for hash value matches. | |
265 for(int i=0; i<arb.numContacts; i++){ | |
266 cpContact *old = &arb.contacts[i]; | |
267 | |
268 for(int j=0; j<numContacts; j++){ | |
269 cpContact *new_contact = &contacts[j]; | |
270 | |
271 // This could trigger false positives, but is fairly unlikely nor serious if it does. | |
272 if(new_contact.hash == old.hash){ | |
273 // Copy the persistant contact information. | |
274 new_contact.jnAcc = old.jnAcc; | |
275 new_contact.jtAcc = old.jtAcc; | |
276 } | |
277 } | |
278 } | |
279 | |
280 // cpfree(arb.contacts); | |
281 } | |
282 | |
283 arb.contacts = contacts; | |
284 arb.numContacts = numContacts; | |
285 | |
286 arb.handler = handler; | |
287 arb.swappedColl = (a.collision_type != handler.a); | |
288 | |
289 arb.e = a.e * b.e; | |
290 arb.u = a.u * b.u; | |
291 arb.surface_vr = cpvsub(a.surface_v, b.surface_v); | |
292 | |
293 // For collisions between two similar primitive types, the order could have been swapped. | |
294 arb.private_a = a; | |
295 arb.private_b = b; | |
296 | |
297 // mark it as new if it's been cached | |
298 if(arb.state == cpArbiterState.cpArbiterStateCached) arb.state = cpArbiterState.cpArbiterStateFirstColl; | |
299 } | |
300 | |
301 void | |
302 cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv) | |
303 { | |
304 cpBody *a = arb.private_a._body; | |
305 cpBody *b = arb.private_b._body; | |
306 | |
307 for(int i=0; i<arb.numContacts; i++){ | |
308 cpContact *con = &arb.contacts[i]; | |
309 | |
310 // Calculate the offsets. | |
311 con.r1 = cpvsub(con.p, a.p); | |
312 con.r2 = cpvsub(con.p, b.p); | |
313 | |
314 // Calculate the mass normal and mass tangent. | |
315 con.nMass = 1.0f/k_scalar(a, b, con.r1, con.r2, con.n); | |
316 con.tMass = 1.0f/k_scalar(a, b, con.r1, con.r2, cpvperp(con.n)); | |
317 | |
318 // Calculate the target bias velocity. | |
319 con.bias = -cp_bias_coef*dt_inv*cpfmin(0.0f, con.dist + cp_collision_slop); | |
320 con.jBias = 0.0f; | |
321 | |
322 // Calculate the target bounce velocity. | |
323 con.bounce = normal_relative_velocity(a, b, con.r1, con.r2, con.n)*arb.e;//cpvdot(con.n, cpvsub(v2, v1))*e; | |
324 } | |
325 } | |
326 | |
327 void | |
328 cpArbiterApplyCachedImpulse(cpArbiter *arb) | |
329 { | |
330 cpShape *shapea = arb.private_a; | |
331 cpShape *shapeb = arb.private_b; | |
332 | |
333 arb.u = shapea.u * shapeb.u; | |
334 arb.surface_vr = cpvsub(shapeb.surface_v, shapea.surface_v); | |
335 | |
336 cpBody *a = shapea._body; | |
337 cpBody *b = shapeb._body; | |
338 | |
339 for(int i=0; i<arb.numContacts; i++){ | |
340 cpContact *con = &arb.contacts[i]; | |
341 apply_impulses(a, b, con.r1, con.r2, cpvrotate(con.n, cpv(con.jnAcc, con.jtAcc))); | |
342 } | |
343 } | |
344 | |
345 void | |
346 cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef) | |
347 { | |
348 cpBody *a = arb.private_a._body; | |
349 cpBody *b = arb.private_b._body; | |
350 | |
351 for(int i=0; i<arb.numContacts; i++){ | |
352 cpContact *con = &arb.contacts[i]; | |
353 cpVect n = con.n; | |
354 cpVect r1 = con.r1; | |
355 cpVect r2 = con.r2; | |
356 | |
357 // Calculate the relative bias velocities. | |
358 cpVect vb1 = cpvadd(a.v_bias, cpvmult(cpvperp(r1), a.w_bias)); | |
359 cpVect vb2 = cpvadd(b.v_bias, cpvmult(cpvperp(r2), b.w_bias)); | |
360 cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n); | |
361 | |
362 // Calculate and clamp the bias impulse. | |
363 cpFloat jbn = (con.bias - vbn)*con.nMass; | |
364 cpFloat jbnOld = con.jBias; | |
365 con.jBias = cpfmax(jbnOld + jbn, 0.0f); | |
366 jbn = con.jBias - jbnOld; | |
367 | |
368 // Apply the bias impulse. | |
369 apply_bias_impulses(a, b, r1, r2, cpvmult(n, jbn)); | |
370 | |
371 // Calculate the relative velocity. | |
372 cpVect vr = relative_velocity(a, b, r1, r2); | |
373 cpFloat vrn = cpvdot(vr, n); | |
374 | |
375 // Calculate and clamp the normal impulse. | |
376 cpFloat jn = -(con.bounce*eCoef + vrn)*con.nMass; | |
377 cpFloat jnOld = con.jnAcc; | |
378 con.jnAcc = cpfmax(jnOld + jn, 0.0f); | |
379 jn = con.jnAcc - jnOld; | |
380 | |
381 // Calculate the relative tangent velocity. | |
382 cpFloat vrt = cpvdot(cpvadd(vr, arb.surface_vr), cpvperp(n)); | |
383 | |
384 // Calculate and clamp the friction impulse. | |
385 cpFloat jtMax = arb.u*con.jnAcc; | |
386 cpFloat jt = -vrt*con.tMass; | |
387 cpFloat jtOld = con.jtAcc; | |
388 con.jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax); | |
389 jt = con.jtAcc - jtOld; | |
390 | |
391 // Apply the final impulse. | |
392 apply_impulses(a, b, r1, r2, cpvrotate(n, cpv(jn, jt))); | |
393 } | |
394 } |