1#![allow(clippy::needless_range_loop)]
23
24use super::wide::{
25 cross_w, dot_w, gather_bodies, rotate_vector_w, scatter_bodies, FloatW, Vec2W, SIMD_WIDTH,
26};
27use crate::body::BodyState;
28use crate::contact::ContactSim;
29use crate::core::NULL_INDEX;
30use crate::math_functions::max_float;
31use crate::math_functions::min_float;
32use crate::math_functions::{cross, dot, right_perp, sub, Vec2};
33use crate::solver::{make_soft, StepContext};
34
35#[derive(Debug, Clone, Copy, PartialEq, Default)]
37pub struct ContactConstraintWide {
38 pub index_a: [i32; SIMD_WIDTH],
40 pub index_b: [i32; SIMD_WIDTH],
41
42 pub inv_mass_a: FloatW,
43 pub inv_mass_b: FloatW,
44 pub inv_i_a: FloatW,
45 pub inv_i_b: FloatW,
46 pub normal: Vec2W,
47 pub friction: FloatW,
48 pub tangent_speed: FloatW,
49 pub rolling_resistance: FloatW,
50 pub rolling_mass: FloatW,
51 pub rolling_impulse: FloatW,
52 pub bias_rate: FloatW,
53 pub mass_scale: FloatW,
54 pub impulse_scale: FloatW,
55 pub anchor_a1: Vec2W,
56 pub anchor_b1: Vec2W,
57 pub normal_mass1: FloatW,
58 pub tangent_mass1: FloatW,
59 pub base_separation1: FloatW,
60 pub normal_impulse1: FloatW,
61 pub total_normal_impulse1: FloatW,
62 pub tangent_impulse1: FloatW,
63 pub anchor_a2: Vec2W,
64 pub anchor_b2: Vec2W,
65 pub base_separation2: FloatW,
66 pub normal_impulse2: FloatW,
67 pub total_normal_impulse2: FloatW,
68 pub tangent_impulse2: FloatW,
69 pub normal_mass2: FloatW,
70 pub tangent_mass2: FloatW,
71 pub restitution: FloatW,
72 pub relative_velocity1: FloatW,
73 pub relative_velocity2: FloatW,
74}
75
76#[inline]
78pub fn wide_block_count(contact_count: usize) -> usize {
79 contact_count.div_ceil(SIMD_WIDTH)
80}
81
82#[allow(clippy::too_many_arguments)]
86pub fn prepare_contacts_wide(
87 wide: &mut [ContactConstraintWide],
88 contacts: &[ContactSim],
89 states: &[BodyState],
90 context: &StepContext,
91 enable_softening: bool,
92 contact_hertz: f32,
93 contact_damping_ratio: f32,
94) {
95 debug_assert!(wide.len() == wide_block_count(contacts.len()));
96
97 let contact_softness = context.contact_softness;
100 let static_softness = context.static_softness;
101
102 let warm_start_scale = if context.enable_warm_starting {
103 1.0
104 } else {
105 0.0
106 };
107
108 for (i, contact_sim) in contacts.iter().enumerate() {
109 let block = i / SIMD_WIDTH;
110 let lane = i % SIMD_WIDTH;
111 let constraint = &mut wide[block];
112
113 let manifold = &contact_sim.manifold;
114 let point_count = manifold.point_count;
115 debug_assert!(0 < point_count && point_count <= 2);
116
117 let index_a = contact_sim.body_sim_index_a;
118 let index_b = contact_sim.body_sim_index_b;
119
120 constraint.index_a[lane] = index_a + 1;
122 constraint.index_b[lane] = index_b + 1;
123
124 let mut v_a = Vec2 { x: 0.0, y: 0.0 };
125 let mut w_a = 0.0;
126 let m_a = contact_sim.inv_mass_a;
127 let i_a = contact_sim.inv_i_a;
128 if index_a != NULL_INDEX {
129 let state_a = &states[index_a as usize];
130 v_a = state_a.linear_velocity;
131 w_a = state_a.angular_velocity;
132 }
133
134 let mut v_b = Vec2 { x: 0.0, y: 0.0 };
135 let mut w_b = 0.0;
136 let m_b = contact_sim.inv_mass_b;
137 let i_b = contact_sim.inv_i_b;
138 if index_b != NULL_INDEX {
139 let state_b = &states[index_b as usize];
140 v_b = state_b.linear_velocity;
141 w_b = state_b.angular_velocity;
142 }
143
144 constraint.inv_mass_a.0[lane] = m_a;
145 constraint.inv_mass_b.0[lane] = m_b;
146 constraint.inv_i_a.0[lane] = i_a;
147 constraint.inv_i_b.0[lane] = i_b;
148
149 {
150 let k = i_a + i_b;
151 constraint.rolling_mass.0[lane] = if k > 0.0 { 1.0 / k } else { 0.0 };
152 }
153
154 let soft = if index_a == NULL_INDEX || index_b == NULL_INDEX {
158 static_softness
159 } else if enable_softening {
160 let contact_hertz = min_float(contact_hertz, 0.125 * context.inv_h);
161 let ratio = if m_a < m_b {
162 max_float(0.5, m_a / m_b)
163 } else if m_b < m_a {
164 max_float(0.5, m_b / m_a)
165 } else {
166 1.0
167 };
168 make_soft(
169 ratio * contact_hertz,
170 ratio * contact_damping_ratio,
171 context.h,
172 )
173 } else {
174 contact_softness
175 };
176
177 let normal = manifold.normal;
178 constraint.normal.x.0[lane] = normal.x;
179 constraint.normal.y.0[lane] = normal.y;
180
181 constraint.friction.0[lane] = contact_sim.friction;
182 constraint.tangent_speed.0[lane] = contact_sim.tangent_speed;
183 constraint.restitution.0[lane] = contact_sim.restitution;
184 constraint.rolling_resistance.0[lane] = contact_sim.rolling_resistance;
185 constraint.rolling_impulse.0[lane] = warm_start_scale * manifold.rolling_impulse;
186
187 constraint.bias_rate.0[lane] = soft.bias_rate;
188 constraint.mass_scale.0[lane] = soft.mass_scale;
189 constraint.impulse_scale.0[lane] = soft.impulse_scale;
190
191 let tangent = right_perp(normal);
192
193 {
195 let mp = &manifold.points[0];
196 let r_a = mp.anchor_a;
197 let r_b = mp.anchor_b;
198
199 constraint.anchor_a1.x.0[lane] = r_a.x;
200 constraint.anchor_a1.y.0[lane] = r_a.y;
201 constraint.anchor_b1.x.0[lane] = r_b.x;
202 constraint.anchor_b1.y.0[lane] = r_b.y;
203
204 constraint.base_separation1.0[lane] = mp.separation - dot(sub(r_b, r_a), normal);
205
206 constraint.normal_impulse1.0[lane] = warm_start_scale * mp.normal_impulse;
207 constraint.tangent_impulse1.0[lane] = warm_start_scale * mp.tangent_impulse;
208 constraint.total_normal_impulse1.0[lane] = 0.0;
209
210 let rn_a = cross(r_a, normal);
211 let rn_b = cross(r_b, normal);
212 let k_normal = m_a + m_b + i_a * rn_a * rn_a + i_b * rn_b * rn_b;
213 constraint.normal_mass1.0[lane] = if k_normal > 0.0 { 1.0 / k_normal } else { 0.0 };
214
215 let rt_a = cross(r_a, tangent);
216 let rt_b = cross(r_b, tangent);
217 let k_tangent = m_a + m_b + i_a * rt_a * rt_a + i_b * rt_b * rt_b;
218 constraint.tangent_mass1.0[lane] = if k_tangent > 0.0 {
219 1.0 / k_tangent
220 } else {
221 0.0
222 };
223
224 let vr_a = crate::math_functions::add(v_a, crate::math_functions::cross_sv(w_a, r_a));
225 let vr_b = crate::math_functions::add(v_b, crate::math_functions::cross_sv(w_b, r_b));
226 constraint.relative_velocity1.0[lane] = dot(normal, sub(vr_b, vr_a));
227 }
228
229 if point_count == 2 {
230 let mp = &manifold.points[1];
231 let r_a = mp.anchor_a;
232 let r_b = mp.anchor_b;
233
234 constraint.anchor_a2.x.0[lane] = r_a.x;
235 constraint.anchor_a2.y.0[lane] = r_a.y;
236 constraint.anchor_b2.x.0[lane] = r_b.x;
237 constraint.anchor_b2.y.0[lane] = r_b.y;
238
239 constraint.base_separation2.0[lane] = mp.separation - dot(sub(r_b, r_a), normal);
240
241 constraint.normal_impulse2.0[lane] = warm_start_scale * mp.normal_impulse;
242 constraint.tangent_impulse2.0[lane] = warm_start_scale * mp.tangent_impulse;
243 constraint.total_normal_impulse2.0[lane] = 0.0;
244
245 let rn_a = cross(r_a, normal);
246 let rn_b = cross(r_b, normal);
247 let k_normal = m_a + m_b + i_a * rn_a * rn_a + i_b * rn_b * rn_b;
248 constraint.normal_mass2.0[lane] = if k_normal > 0.0 { 1.0 / k_normal } else { 0.0 };
249
250 let rt_a = cross(r_a, tangent);
251 let rt_b = cross(r_b, tangent);
252 let k_tangent = m_a + m_b + i_a * rt_a * rt_a + i_b * rt_b * rt_b;
253 constraint.tangent_mass2.0[lane] = if k_tangent > 0.0 {
254 1.0 / k_tangent
255 } else {
256 0.0
257 };
258
259 let vr_a = crate::math_functions::add(v_a, crate::math_functions::cross_sv(w_a, r_a));
260 let vr_b = crate::math_functions::add(v_b, crate::math_functions::cross_sv(w_b, r_b));
261 constraint.relative_velocity2.0[lane] = dot(normal, sub(vr_b, vr_a));
262 } else {
263 constraint.base_separation2.0[lane] = 0.0;
265 constraint.normal_impulse2.0[lane] = 0.0;
266 constraint.tangent_impulse2.0[lane] = 0.0;
267 constraint.total_normal_impulse2.0[lane] = 0.0;
268 constraint.anchor_a2.x.0[lane] = 0.0;
269 constraint.anchor_a2.y.0[lane] = 0.0;
270 constraint.anchor_b2.x.0[lane] = 0.0;
271 constraint.anchor_b2.y.0[lane] = 0.0;
272 constraint.normal_mass2.0[lane] = 0.0;
273 constraint.tangent_mass2.0[lane] = 0.0;
274 constraint.relative_velocity2.0[lane] = 0.0;
275 }
276 }
277}
278
279pub fn warm_start_contacts_wide(wide: &mut [ContactConstraintWide], states: &mut [BodyState]) {
281 for c in wide.iter_mut() {
282 let mut b_a = gather_bodies(states, &c.index_a);
283 let mut b_b = gather_bodies(states, &c.index_b);
284
285 let tangent_x = c.normal.y;
286 let tangent_y = FloatW::zero().sub(c.normal.x);
287
288 {
290 let r_a = c.anchor_a1;
291 let r_b = c.anchor_b1;
292
293 let p = Vec2W {
294 x: c.normal_impulse1
295 .mul(c.normal.x)
296 .add(c.tangent_impulse1.mul(tangent_x)),
297 y: c.normal_impulse1
298 .mul(c.normal.y)
299 .add(c.tangent_impulse1.mul(tangent_y)),
300 };
301 b_a.w = b_a.w.mul_sub(c.inv_i_a, cross_w(r_a, p));
302 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, p.x);
303 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, p.y);
304 b_b.w = b_b.w.mul_add(c.inv_i_b, cross_w(r_b, p));
305 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, p.x);
306 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, p.y);
307
308 c.total_normal_impulse1 = c.total_normal_impulse1.add(c.normal_impulse1);
309 }
310
311 {
313 let r_a = c.anchor_a2;
314 let r_b = c.anchor_b2;
315
316 let p = Vec2W {
317 x: c.normal_impulse2
318 .mul(c.normal.x)
319 .add(c.tangent_impulse2.mul(tangent_x)),
320 y: c.normal_impulse2
321 .mul(c.normal.y)
322 .add(c.tangent_impulse2.mul(tangent_y)),
323 };
324 b_a.w = b_a.w.mul_sub(c.inv_i_a, cross_w(r_a, p));
325 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, p.x);
326 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, p.y);
327 b_b.w = b_b.w.mul_add(c.inv_i_b, cross_w(r_b, p));
328 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, p.x);
329 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, p.y);
330
331 c.total_normal_impulse2 = c.total_normal_impulse2.add(c.normal_impulse2);
332 }
333
334 b_a.w = b_a.w.mul_sub(c.inv_i_a, c.rolling_impulse);
335 b_b.w = b_b.w.mul_add(c.inv_i_b, c.rolling_impulse);
336
337 scatter_bodies(states, &c.index_a, &b_a);
338 scatter_bodies(states, &c.index_b, &b_b);
339 }
340}
341
342pub fn solve_contacts_wide(
344 wide: &mut [ContactConstraintWide],
345 states: &mut [BodyState],
346 context: &StepContext,
347 use_bias: bool,
348) {
349 let inv_h = FloatW::splat(context.inv_h);
350 let contact_speed = FloatW::splat(-context.contact_speed);
351 let one_w = FloatW::splat(1.0);
352 let zero = FloatW::zero();
353
354 for c in wide.iter_mut() {
355 let mut b_a = gather_bodies(states, &c.index_a);
356 let mut b_b = gather_bodies(states, &c.index_b);
357
358 let (bias_rate, mass_scale, impulse_scale) = if use_bias {
359 (c.mass_scale.mul(c.bias_rate), c.mass_scale, c.impulse_scale)
360 } else {
361 (zero, one_w, zero)
362 };
363
364 let mut total_normal_impulse = zero;
365
366 let dp = Vec2W {
367 x: b_b.dp.x.sub(b_a.dp.x),
368 y: b_b.dp.y.sub(b_a.dp.y),
369 };
370
371 {
373 let r_a = c.anchor_a1;
374 let r_b = c.anchor_b1;
375
376 let rs_a = rotate_vector_w(b_a.dq, r_a);
377 let rs_b = rotate_vector_w(b_b.dq, r_b);
378
379 let ds = Vec2W {
380 x: dp.x.add(rs_b.x.sub(rs_a.x)),
381 y: dp.y.add(rs_b.y.sub(rs_a.y)),
382 };
383 let s = dot_w(c.normal, ds).add(c.base_separation1);
384
385 let mask = s.greater_than(zero);
386 let spec_bias = s.mul(inv_h);
387 let soft_bias = bias_rate.mul(s).max(contact_speed);
388 let bias = FloatW::blend(soft_bias, spec_bias, mask);
389
390 let point_mass_scale = FloatW::blend(mass_scale, one_w, mask);
391 let point_impulse_scale = FloatW::blend(impulse_scale, zero, mask);
392
393 let dvx = b_b
394 .v
395 .x
396 .sub(b_b.w.mul(r_b.y))
397 .sub(b_a.v.x.sub(b_a.w.mul(r_a.y)));
398 let dvy = b_b
399 .v
400 .y
401 .add(b_b.w.mul(r_b.x))
402 .sub(b_a.v.y.add(b_a.w.mul(r_a.x)));
403 let vn = dvx.mul(c.normal.x).add(dvy.mul(c.normal.y));
404
405 let neg_impulse = c
406 .normal_mass1
407 .mul(point_mass_scale.mul(vn).add(bias))
408 .add(point_impulse_scale.mul(c.normal_impulse1));
409
410 let new_impulse = c.normal_impulse1.sub(neg_impulse).max(zero);
411 let impulse = new_impulse.sub(c.normal_impulse1);
412 c.normal_impulse1 = new_impulse;
413 c.total_normal_impulse1 = c.total_normal_impulse1.add(impulse);
414
415 total_normal_impulse = total_normal_impulse.add(new_impulse);
416
417 let px = impulse.mul(c.normal.x);
418 let py = impulse.mul(c.normal.y);
419
420 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, px);
421 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, py);
422 b_a.w = b_a.w.mul_sub(c.inv_i_a, r_a.x.mul(py).sub(r_a.y.mul(px)));
423
424 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, px);
425 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, py);
426 b_b.w = b_b.w.mul_add(c.inv_i_b, r_b.x.mul(py).sub(r_b.y.mul(px)));
427 }
428
429 {
431 let rs_a = rotate_vector_w(b_a.dq, c.anchor_a2);
432 let rs_b = rotate_vector_w(b_b.dq, c.anchor_b2);
433
434 let ds = Vec2W {
435 x: dp.x.add(rs_b.x.sub(rs_a.x)),
436 y: dp.y.add(rs_b.y.sub(rs_a.y)),
437 };
438 let s = dot_w(c.normal, ds).add(c.base_separation2);
439
440 let mask = s.greater_than(zero);
441 let spec_bias = s.mul(inv_h);
442 let soft_bias = bias_rate.mul(s).max(contact_speed);
443 let bias = FloatW::blend(soft_bias, spec_bias, mask);
444
445 let point_mass_scale = FloatW::blend(mass_scale, one_w, mask);
446 let point_impulse_scale = FloatW::blend(impulse_scale, zero, mask);
447
448 let r_a = c.anchor_a2;
449 let r_b = c.anchor_b2;
450
451 let dvx = b_b
452 .v
453 .x
454 .sub(b_b.w.mul(r_b.y))
455 .sub(b_a.v.x.sub(b_a.w.mul(r_a.y)));
456 let dvy = b_b
457 .v
458 .y
459 .add(b_b.w.mul(r_b.x))
460 .sub(b_a.v.y.add(b_a.w.mul(r_a.x)));
461 let vn = dvx.mul(c.normal.x).add(dvy.mul(c.normal.y));
462
463 let neg_impulse = c
464 .normal_mass2
465 .mul(point_mass_scale.mul(vn).add(bias))
466 .add(point_impulse_scale.mul(c.normal_impulse2));
467
468 let new_impulse = c.normal_impulse2.sub(neg_impulse).max(zero);
469 let impulse = new_impulse.sub(c.normal_impulse2);
470 c.normal_impulse2 = new_impulse;
471 c.total_normal_impulse2 = c.total_normal_impulse2.add(impulse);
472
473 total_normal_impulse = total_normal_impulse.add(new_impulse);
474
475 let px = impulse.mul(c.normal.x);
476 let py = impulse.mul(c.normal.y);
477
478 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, px);
479 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, py);
480 b_a.w = b_a.w.mul_sub(c.inv_i_a, r_a.x.mul(py).sub(r_a.y.mul(px)));
481
482 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, px);
483 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, py);
484 b_b.w = b_b.w.mul_add(c.inv_i_b, r_b.x.mul(py).sub(r_b.y.mul(px)));
485 }
486
487 if !use_bias {
488 if !c.rolling_resistance.all_zero() {
490 let delta_lambda = c.rolling_mass.mul(b_a.w.sub(b_b.w));
491 let lambda = c.rolling_impulse;
492 let max_lambda = c.rolling_resistance.mul(total_normal_impulse);
493 c.rolling_impulse = lambda.add(delta_lambda).sym_clamp(max_lambda);
494 let delta_lambda = c.rolling_impulse.sub(lambda);
495
496 b_a.w = b_a.w.mul_sub(c.inv_i_a, delta_lambda);
497 b_b.w = b_b.w.mul_add(c.inv_i_b, delta_lambda);
498 }
499
500 let tangent_x = c.normal.y;
501 let tangent_y = zero.sub(c.normal.x);
502
503 {
505 let r_a = c.anchor_a1;
506 let r_b = c.anchor_b1;
507
508 let dvx = b_b
509 .v
510 .x
511 .sub(b_b.w.mul(r_b.y))
512 .sub(b_a.v.x.sub(b_a.w.mul(r_a.y)));
513 let dvy = b_b
514 .v
515 .y
516 .add(b_b.w.mul(r_b.x))
517 .sub(b_a.v.y.add(b_a.w.mul(r_a.x)));
518 let vt = dvx.mul(tangent_x).add(dvy.mul(tangent_y));
519 let vt = vt.sub(c.tangent_speed);
520
521 let neg_impulse = c.tangent_mass1.mul(vt);
522
523 let max_friction = c.friction.mul(c.normal_impulse1);
524 let new_impulse = c.tangent_impulse1.sub(neg_impulse);
525 let new_impulse = zero.sub(max_friction).max(new_impulse.min(max_friction));
526 let impulse = new_impulse.sub(c.tangent_impulse1);
527 c.tangent_impulse1 = new_impulse;
528
529 let px = impulse.mul(tangent_x);
530 let py = impulse.mul(tangent_y);
531
532 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, px);
533 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, py);
534 b_a.w = b_a.w.mul_sub(c.inv_i_a, r_a.x.mul(py).sub(r_a.y.mul(px)));
535
536 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, px);
537 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, py);
538 b_b.w = b_b.w.mul_add(c.inv_i_b, r_b.x.mul(py).sub(r_b.y.mul(px)));
539 }
540
541 {
543 let r_a = c.anchor_a2;
544 let r_b = c.anchor_b2;
545
546 let dvx = b_b
547 .v
548 .x
549 .sub(b_b.w.mul(r_b.y))
550 .sub(b_a.v.x.sub(b_a.w.mul(r_a.y)));
551 let dvy = b_b
552 .v
553 .y
554 .add(b_b.w.mul(r_b.x))
555 .sub(b_a.v.y.add(b_a.w.mul(r_a.x)));
556 let vt = dvx.mul(tangent_x).add(dvy.mul(tangent_y));
557 let vt = vt.sub(c.tangent_speed);
558
559 let neg_impulse = c.tangent_mass2.mul(vt);
560
561 let max_friction = c.friction.mul(c.normal_impulse2);
562 let new_impulse = c.tangent_impulse2.sub(neg_impulse);
563 let new_impulse = zero.sub(max_friction).max(new_impulse.min(max_friction));
564 let impulse = new_impulse.sub(c.tangent_impulse2);
565 c.tangent_impulse2 = new_impulse;
566
567 let px = impulse.mul(tangent_x);
568 let py = impulse.mul(tangent_y);
569
570 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, px);
571 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, py);
572 b_a.w = b_a.w.mul_sub(c.inv_i_a, r_a.x.mul(py).sub(r_a.y.mul(px)));
573
574 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, px);
575 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, py);
576 b_b.w = b_b.w.mul_add(c.inv_i_b, r_b.x.mul(py).sub(r_b.y.mul(px)));
577 }
578 }
579
580 scatter_bodies(states, &c.index_a, &b_a);
581 scatter_bodies(states, &c.index_b, &b_b);
582 }
583}
584
585pub fn apply_restitution_wide(
587 wide: &mut [ContactConstraintWide],
588 states: &mut [BodyState],
589 context: &StepContext,
590) {
591 let threshold = FloatW::splat(context.restitution_threshold);
592 let zero = FloatW::zero();
593
594 for c in wide.iter_mut() {
595 if c.restitution.all_zero() {
596 continue;
598 }
599
600 let restitution_mask = c.restitution.equals(zero);
602
603 let mut b_a = gather_bodies(states, &c.index_a);
604 let mut b_b = gather_bodies(states, &c.index_b);
605
606 {
608 let mask1 = c.relative_velocity1.add(threshold).greater_than(zero);
609 let mask2 = c.total_normal_impulse1.equals(zero);
610 let mask = mask1.or(mask2).or(restitution_mask);
611 let mass = FloatW::blend(c.normal_mass1, zero, mask);
612
613 let r_a = c.anchor_a1;
614 let r_b = c.anchor_b1;
615
616 let dvx = b_b
617 .v
618 .x
619 .sub(b_b.w.mul(r_b.y))
620 .sub(b_a.v.x.sub(b_a.w.mul(r_a.y)));
621 let dvy = b_b
622 .v
623 .y
624 .add(b_b.w.mul(r_b.x))
625 .sub(b_a.v.y.add(b_a.w.mul(r_a.x)));
626 let vn = dvx.mul(c.normal.x).add(dvy.mul(c.normal.y));
627
628 let neg_impulse = mass.mul(vn.add(c.restitution.mul(c.relative_velocity1)));
629
630 let new_impulse = c.normal_impulse1.sub(neg_impulse).max(zero);
631 let delta_impulse = new_impulse.sub(c.normal_impulse1);
632 c.normal_impulse1 = new_impulse;
633 c.total_normal_impulse1 = c.total_normal_impulse1.add(delta_impulse);
634
635 let px = delta_impulse.mul(c.normal.x);
636 let py = delta_impulse.mul(c.normal.y);
637
638 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, px);
639 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, py);
640 b_a.w = b_a.w.mul_sub(c.inv_i_a, r_a.x.mul(py).sub(r_a.y.mul(px)));
641
642 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, px);
643 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, py);
644 b_b.w = b_b.w.mul_add(c.inv_i_b, r_b.x.mul(py).sub(r_b.y.mul(px)));
645 }
646
647 {
649 let mask1 = c.relative_velocity2.add(threshold).greater_than(zero);
650 let mask2 = c.total_normal_impulse2.equals(zero);
651 let mask = mask1.or(mask2).or(restitution_mask);
652 let mass = FloatW::blend(c.normal_mass2, zero, mask);
653
654 let r_a = c.anchor_a2;
655 let r_b = c.anchor_b2;
656
657 let dvx = b_b
658 .v
659 .x
660 .sub(b_b.w.mul(r_b.y))
661 .sub(b_a.v.x.sub(b_a.w.mul(r_a.y)));
662 let dvy = b_b
663 .v
664 .y
665 .add(b_b.w.mul(r_b.x))
666 .sub(b_a.v.y.add(b_a.w.mul(r_a.x)));
667 let vn = dvx.mul(c.normal.x).add(dvy.mul(c.normal.y));
668
669 let neg_impulse = mass.mul(vn.add(c.restitution.mul(c.relative_velocity2)));
670
671 let new_impulse = c.normal_impulse2.sub(neg_impulse).max(zero);
672 let delta_impulse = new_impulse.sub(c.normal_impulse2);
673 c.normal_impulse2 = new_impulse;
674 c.total_normal_impulse2 = c.total_normal_impulse2.add(delta_impulse);
675
676 let px = delta_impulse.mul(c.normal.x);
677 let py = delta_impulse.mul(c.normal.y);
678
679 b_a.v.x = b_a.v.x.mul_sub(c.inv_mass_a, px);
680 b_a.v.y = b_a.v.y.mul_sub(c.inv_mass_a, py);
681 b_a.w = b_a.w.mul_sub(c.inv_i_a, r_a.x.mul(py).sub(r_a.y.mul(px)));
682
683 b_b.v.x = b_b.v.x.mul_add(c.inv_mass_b, px);
684 b_b.v.y = b_b.v.y.mul_add(c.inv_mass_b, py);
685 b_b.w = b_b.w.mul_add(c.inv_i_b, r_b.x.mul(py).sub(r_b.y.mul(px)));
686 }
687
688 scatter_bodies(states, &c.index_a, &b_a);
689 scatter_bodies(states, &c.index_b, &b_b);
690 }
691}
692
693pub fn store_impulses_wide(wide: &[ContactConstraintWide], contacts: &mut [ContactSim]) {
697 for (i, contact) in contacts.iter_mut().enumerate() {
698 let block = i / SIMD_WIDTH;
699 let lane = i % SIMD_WIDTH;
700 let c = &wide[block];
701
702 let manifold = &mut contact.manifold;
703 manifold.rolling_impulse = c.rolling_impulse.0[lane];
704
705 manifold.points[0].normal_impulse = c.normal_impulse1.0[lane];
706 manifold.points[0].tangent_impulse = c.tangent_impulse1.0[lane];
707 manifold.points[0].total_normal_impulse = c.total_normal_impulse1.0[lane];
708 manifold.points[0].normal_velocity = c.relative_velocity1.0[lane];
709
710 manifold.points[1].normal_impulse = c.normal_impulse2.0[lane];
711 manifold.points[1].tangent_impulse = c.tangent_impulse2.0[lane];
712 manifold.points[1].total_normal_impulse = c.total_normal_impulse2.0[lane];
713 manifold.points[1].normal_velocity = c.relative_velocity2.0[lane];
714 }
715}