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