1#![allow(dead_code)]
29
30use crate::body::{body_flags, BodyState, IDENTITY_BODY_STATE};
31use crate::contact::ContactSim;
32use crate::core::NULL_INDEX;
33use crate::math_functions::{
34 add, clamp_float, cross, cross_sv, dot, max_float, mul_add, mul_sub, mul_sv, right_perp,
35 rotate_vector, sub, Vec2, VEC2_ZERO,
36};
37use crate::solver::{Softness, StepContext};
38
39#[derive(Debug, Clone, Copy, PartialEq, Default)]
41pub struct ContactConstraintPoint {
42 pub anchor_a: Vec2,
43 pub anchor_b: Vec2,
44 pub base_separation: f32,
45 pub relative_velocity: f32,
46 pub normal_impulse: f32,
47 pub tangent_impulse: f32,
48 pub total_normal_impulse: f32,
49 pub normal_mass: f32,
50 pub tangent_mass: f32,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Default)]
55pub struct ContactConstraint {
56 pub index_a: i32,
58 pub index_b: i32,
59 pub points: [ContactConstraintPoint; 2],
60 pub normal: Vec2,
61 pub inv_mass_a: f32,
62 pub inv_mass_b: f32,
63 pub inv_i_a: f32,
64 pub inv_i_b: f32,
65 pub friction: f32,
66 pub restitution: f32,
67 pub tangent_speed: f32,
68 pub rolling_resistance: f32,
69 pub rolling_mass: f32,
70 pub rolling_impulse: f32,
71 pub softness: Softness,
72 pub point_count: i32,
73}
74
75pub fn prepare_contacts(
79 constraints: &mut [ContactConstraint],
80 contacts: &[ContactSim],
81 states: &[BodyState],
82 context: &StepContext,
83) {
84 debug_assert!(constraints.len() == contacts.len());
85
86 let contact_softness = context.contact_softness;
89 let static_softness = context.static_softness;
90
91 let warm_start_scale = if context.enable_warm_starting {
92 1.0
93 } else {
94 0.0
95 };
96
97 for (constraint, contact_sim) in constraints.iter_mut().zip(contacts.iter()) {
98 let manifold = &contact_sim.manifold;
99 let point_count = manifold.point_count;
100
101 debug_assert!(0 < point_count && point_count <= 2);
102
103 let index_a = contact_sim.body_sim_index_a;
104 let index_b = contact_sim.body_sim_index_b;
105
106 constraint.index_a = index_a + 1;
108 constraint.index_b = index_b + 1;
109 constraint.normal = manifold.normal;
110 constraint.friction = contact_sim.friction;
111 constraint.restitution = contact_sim.restitution;
112 constraint.rolling_resistance = contact_sim.rolling_resistance;
113 constraint.rolling_impulse = warm_start_scale * manifold.rolling_impulse;
114 constraint.tangent_speed = contact_sim.tangent_speed;
115 constraint.point_count = point_count;
116
117 let mut v_a = VEC2_ZERO;
118 let mut w_a = 0.0;
119 let m_a = contact_sim.inv_mass_a;
120 let i_a = contact_sim.inv_i_a;
121 if index_a != NULL_INDEX {
122 let state_a = &states[index_a as usize];
123 v_a = state_a.linear_velocity;
124 w_a = state_a.angular_velocity;
125 }
126
127 let mut v_b = VEC2_ZERO;
128 let mut w_b = 0.0;
129 let m_b = contact_sim.inv_mass_b;
130 let i_b = contact_sim.inv_i_b;
131 if index_b != NULL_INDEX {
132 let state_b = &states[index_b as usize];
133 v_b = state_b.linear_velocity;
134 w_b = state_b.angular_velocity;
135 }
136
137 if index_a == NULL_INDEX || index_b == NULL_INDEX {
138 constraint.softness = static_softness;
139 } else {
140 constraint.softness = contact_softness;
141 }
142
143 constraint.inv_mass_a = m_a;
145 constraint.inv_i_a = i_a;
146 constraint.inv_mass_b = m_b;
147 constraint.inv_i_b = i_b;
148
149 {
150 let k = i_a + i_b;
151 constraint.rolling_mass = if k > 0.0 { 1.0 / k } else { 0.0 };
152 }
153
154 let normal = constraint.normal;
155 let tangent = right_perp(constraint.normal);
156
157 for j in 0..point_count as usize {
158 let mp = &manifold.points[j];
159 let cp = &mut constraint.points[j];
160
161 cp.normal_impulse = warm_start_scale * mp.normal_impulse;
162 cp.tangent_impulse = warm_start_scale * mp.tangent_impulse;
163 cp.total_normal_impulse = 0.0;
164
165 let r_a = mp.anchor_a;
166 let r_b = mp.anchor_b;
167
168 cp.anchor_a = r_a;
169 cp.anchor_b = r_b;
170 cp.base_separation = mp.separation - dot(sub(r_b, r_a), normal);
171
172 let rn_a = cross(r_a, normal);
173 let rn_b = cross(r_b, normal);
174 let k_normal = m_a + m_b + i_a * rn_a * rn_a + i_b * rn_b * rn_b;
175 cp.normal_mass = if k_normal > 0.0 { 1.0 / k_normal } else { 0.0 };
176
177 let rt_a = cross(r_a, tangent);
178 let rt_b = cross(r_b, tangent);
179 let k_tangent = m_a + m_b + i_a * rt_a * rt_a + i_b * rt_b * rt_b;
180 cp.tangent_mass = if k_tangent > 0.0 {
181 1.0 / k_tangent
182 } else {
183 0.0
184 };
185
186 let vr_a = add(v_a, cross_sv(w_a, r_a));
188 let vr_b = add(v_b, cross_sv(w_b, r_b));
189 cp.relative_velocity = dot(normal, sub(vr_b, vr_a));
190 }
191 }
192}
193
194pub fn warm_start_contacts(constraints: &mut [ContactConstraint], states: &mut [BodyState]) {
196 for constraint in constraints.iter_mut() {
197 let index_a = constraint.index_a - 1;
198 let index_b = constraint.index_b - 1;
199
200 let mut state_a = if index_a == NULL_INDEX {
203 IDENTITY_BODY_STATE
204 } else {
205 states[index_a as usize]
206 };
207 let mut state_b = if index_b == NULL_INDEX {
208 IDENTITY_BODY_STATE
209 } else {
210 states[index_b as usize]
211 };
212
213 let mut v_a = state_a.linear_velocity;
214 let mut w_a = state_a.angular_velocity;
215 let mut v_b = state_b.linear_velocity;
216 let mut w_b = state_b.angular_velocity;
217
218 let m_a = constraint.inv_mass_a;
219 let i_a = constraint.inv_i_a;
220 let m_b = constraint.inv_mass_b;
221 let i_b = constraint.inv_i_b;
222
223 let normal = constraint.normal;
224 let tangent = right_perp(constraint.normal);
225 let point_count = constraint.point_count;
226
227 for j in 0..point_count as usize {
228 let cp = &mut constraint.points[j];
229
230 let r_a = cp.anchor_a;
232 let r_b = cp.anchor_b;
233
234 let p = add(
235 mul_sv(cp.normal_impulse, normal),
236 mul_sv(cp.tangent_impulse, tangent),
237 );
238
239 cp.total_normal_impulse += cp.normal_impulse;
240
241 w_a -= i_a * cross(r_a, p);
242 v_a = mul_add(v_a, -m_a, p);
243 w_b += i_b * cross(r_b, p);
244 v_b = mul_add(v_b, m_b, p);
245 }
246
247 w_a -= i_a * constraint.rolling_impulse;
248 w_b += i_b * constraint.rolling_impulse;
249
250 if state_a.flags & body_flags::DYNAMIC_FLAG != 0 {
251 state_a.linear_velocity = v_a;
252 state_a.angular_velocity = w_a;
253 states[index_a as usize] = state_a;
254 }
255
256 if state_b.flags & body_flags::DYNAMIC_FLAG != 0 {
257 state_b.linear_velocity = v_b;
258 state_b.angular_velocity = w_b;
259 states[index_b as usize] = state_b;
260 }
261 }
262}
263
264pub fn solve_contacts(
266 constraints: &mut [ContactConstraint],
267 states: &mut [BodyState],
268 context: &StepContext,
269 use_bias: bool,
270) {
271 let inv_h = context.inv_h;
272 let contact_speed = context.contact_speed;
273
274 for constraint in constraints.iter_mut() {
275 let m_a = constraint.inv_mass_a;
276 let i_a = constraint.inv_i_a;
277 let m_b = constraint.inv_mass_b;
278 let i_b = constraint.inv_i_b;
279
280 let index_a = constraint.index_a - 1;
281 let index_b = constraint.index_b - 1;
282
283 let mut state_a = if index_a == NULL_INDEX {
286 IDENTITY_BODY_STATE
287 } else {
288 states[index_a as usize]
289 };
290 let mut v_a = state_a.linear_velocity;
291 let mut w_a = state_a.angular_velocity;
292 let dq_a = state_a.delta_rotation;
293
294 let mut state_b = if index_b == NULL_INDEX {
295 IDENTITY_BODY_STATE
296 } else {
297 states[index_b as usize]
298 };
299 let mut v_b = state_b.linear_velocity;
300 let mut w_b = state_b.angular_velocity;
301 let dq_b = state_b.delta_rotation;
302
303 let dp = sub(state_b.delta_position, state_a.delta_position);
304
305 let normal = constraint.normal;
306 let tangent = right_perp(normal);
307 let friction = constraint.friction;
308 let softness = constraint.softness;
309
310 let point_count = constraint.point_count;
311 let mut total_normal_impulse = 0.0;
312
313 for j in 0..point_count as usize {
315 let cp = &mut constraint.points[j];
316
317 let r_a = cp.anchor_a;
319 let r_b = cp.anchor_b;
320
321 let ds = add(dp, sub(rotate_vector(dq_b, r_b), rotate_vector(dq_a, r_a)));
325 let s = cp.base_separation + dot(ds, normal);
326
327 let mut velocity_bias = 0.0;
328 let mut mass_scale = 1.0;
329 let mut impulse_scale = 0.0;
330 if s > 0.0 {
331 velocity_bias = s * inv_h;
333 } else if use_bias {
334 velocity_bias =
335 max_float(softness.mass_scale * softness.bias_rate * s, -contact_speed);
336 mass_scale = softness.mass_scale;
337 impulse_scale = softness.impulse_scale;
338 }
339
340 let vr_a = add(v_a, cross_sv(w_a, r_a));
342 let vr_b = add(v_b, cross_sv(w_b, r_b));
343 let vn = dot(sub(vr_b, vr_a), normal);
344
345 let mut impulse = -cp.normal_mass * (mass_scale * vn + velocity_bias)
347 - impulse_scale * cp.normal_impulse;
348
349 let new_impulse = max_float(cp.normal_impulse + impulse, 0.0);
351 impulse = new_impulse - cp.normal_impulse;
352 cp.normal_impulse = new_impulse;
353 cp.total_normal_impulse += impulse;
354
355 total_normal_impulse += new_impulse;
356
357 let p = mul_sv(impulse, normal);
359 v_a = mul_sub(v_a, m_a, p);
360 w_a -= i_a * cross(r_a, p);
361
362 v_b = mul_add(v_b, m_b, p);
363 w_b += i_b * cross(r_b, p);
364 }
365
366 if !use_bias {
367 for j in 0..point_count as usize {
369 let cp = &mut constraint.points[j];
370
371 let r_a = cp.anchor_a;
373 let r_b = cp.anchor_b;
374
375 let vr_b = add(v_b, cross_sv(w_b, r_b));
377 let vr_a = add(v_a, cross_sv(w_a, r_a));
378
379 let vt = dot(sub(vr_b, vr_a), tangent) - constraint.tangent_speed;
382
383 let mut impulse = cp.tangent_mass * (-vt);
385
386 let max_friction = friction * cp.normal_impulse;
388 let new_impulse =
389 clamp_float(cp.tangent_impulse + impulse, -max_friction, max_friction);
390 impulse = new_impulse - cp.tangent_impulse;
391 cp.tangent_impulse = new_impulse;
392
393 let p = mul_sv(impulse, tangent);
395 v_a = mul_sub(v_a, m_a, p);
396 w_a -= i_a * cross(r_a, p);
397 v_b = mul_add(v_b, m_b, p);
398 w_b += i_b * cross(r_b, p);
399 }
400
401 {
403 let mut delta_lambda = -constraint.rolling_mass * (w_b - w_a);
404 let lambda = constraint.rolling_impulse;
405 let max_lambda = constraint.rolling_resistance * total_normal_impulse;
406 constraint.rolling_impulse =
407 clamp_float(lambda + delta_lambda, -max_lambda, max_lambda);
408 delta_lambda = constraint.rolling_impulse - lambda;
409
410 w_a -= i_a * delta_lambda;
411 w_b += i_b * delta_lambda;
412 }
413 }
414
415 if state_a.flags & body_flags::DYNAMIC_FLAG != 0 {
416 state_a.linear_velocity = v_a;
417 state_a.angular_velocity = w_a;
418 states[index_a as usize] = state_a;
419 }
420
421 if state_b.flags & body_flags::DYNAMIC_FLAG != 0 {
422 state_b.linear_velocity = v_b;
423 state_b.angular_velocity = w_b;
424 states[index_b as usize] = state_b;
425 }
426 }
427}
428
429pub fn apply_restitution(
431 constraints: &mut [ContactConstraint],
432 states: &mut [BodyState],
433 context: &StepContext,
434) {
435 let threshold = context.restitution_threshold;
436
437 for constraint in constraints.iter_mut() {
438 let restitution = constraint.restitution;
439 if restitution == 0.0 {
440 continue;
441 }
442
443 let m_a = constraint.inv_mass_a;
444 let i_a = constraint.inv_i_a;
445 let m_b = constraint.inv_mass_b;
446 let i_b = constraint.inv_i_b;
447
448 let index_a = constraint.index_a - 1;
449 let index_b = constraint.index_b - 1;
450
451 let mut state_a = if index_a == NULL_INDEX {
453 IDENTITY_BODY_STATE
454 } else {
455 states[index_a as usize]
456 };
457 let mut v_a = state_a.linear_velocity;
458 let mut w_a = state_a.angular_velocity;
459
460 let mut state_b = if index_b == NULL_INDEX {
461 IDENTITY_BODY_STATE
462 } else {
463 states[index_b as usize]
464 };
465 let mut v_b = state_b.linear_velocity;
466 let mut w_b = state_b.angular_velocity;
467
468 let normal = constraint.normal;
469 let point_count = constraint.point_count;
470
471 for j in 0..point_count as usize {
474 let cp = &mut constraint.points[j];
475
476 if cp.relative_velocity > -threshold || cp.total_normal_impulse == 0.0 {
481 continue;
482 }
483
484 let r_a = cp.anchor_a;
486 let r_b = cp.anchor_b;
487
488 let vr_b = add(v_b, cross_sv(w_b, r_b));
490 let vr_a = add(v_a, cross_sv(w_a, r_a));
491 let vn = dot(sub(vr_b, vr_a), normal);
492
493 let mut impulse = -cp.normal_mass * (vn + restitution * cp.relative_velocity);
495
496 let new_impulse = max_float(cp.normal_impulse + impulse, 0.0);
498 impulse = new_impulse - cp.normal_impulse;
499 cp.normal_impulse = new_impulse;
500 cp.total_normal_impulse += impulse;
501
502 let p = mul_sv(impulse, normal);
504 v_a = mul_sub(v_a, m_a, p);
505 w_a -= i_a * cross(r_a, p);
506 v_b = mul_add(v_b, m_b, p);
507 w_b += i_b * cross(r_b, p);
508 }
509
510 if state_a.flags & body_flags::DYNAMIC_FLAG != 0 {
511 state_a.linear_velocity = v_a;
512 state_a.angular_velocity = w_a;
513 states[index_a as usize] = state_a;
514 }
515
516 if state_b.flags & body_flags::DYNAMIC_FLAG != 0 {
517 state_b.linear_velocity = v_b;
518 state_b.angular_velocity = w_b;
519 states[index_b as usize] = state_b;
520 }
521 }
522}
523
524pub fn store_impulses(constraints: &[ContactConstraint], contacts: &mut [ContactSim]) {
526 for (constraint, contact) in constraints.iter().zip(contacts.iter_mut()) {
527 let manifold = &mut contact.manifold;
528 let point_count = manifold.point_count;
529
530 for j in 0..point_count as usize {
531 manifold.points[j].normal_impulse = constraint.points[j].normal_impulse;
532 manifold.points[j].tangent_impulse = constraint.points[j].tangent_impulse;
533 manifold.points[j].total_normal_impulse = constraint.points[j].total_normal_impulse;
534 manifold.points[j].normal_velocity = constraint.points[j].relative_velocity;
535 }
536
537 manifold.rolling_impulse = constraint.rolling_impulse;
538 }
539}