box2d_rust/contact_solver/
wide.rs1#![allow(clippy::needless_range_loop)]
33#![allow(clippy::should_implement_trait)]
34
35use crate::body::{body_flags, BodyState, IDENTITY_BODY_STATE};
36use crate::core::NULL_INDEX;
37use crate::math_functions::Vec2;
38
39pub const SIMD_WIDTH: usize = 4;
42
43#[derive(Debug, Clone, Copy, PartialEq, Default)]
45pub struct FloatW(pub [f32; SIMD_WIDTH]);
46
47#[derive(Debug, Clone, Copy, PartialEq, Default)]
51pub struct MaskW(pub [bool; SIMD_WIDTH]);
52
53impl MaskW {
54 #[inline]
56 pub fn or(self, other: MaskW) -> MaskW {
57 let mut r = [false; SIMD_WIDTH];
58 for i in 0..SIMD_WIDTH {
59 r[i] = self.0[i] || other.0[i];
60 }
61 MaskW(r)
62 }
63}
64
65impl FloatW {
66 #[inline]
68 pub fn zero() -> FloatW {
69 FloatW([0.0; SIMD_WIDTH])
70 }
71
72 #[inline]
74 pub fn splat(scalar: f32) -> FloatW {
75 FloatW([scalar; SIMD_WIDTH])
76 }
77
78 #[inline]
80 pub fn add(self, b: FloatW) -> FloatW {
81 let mut r = [0.0; SIMD_WIDTH];
82 for i in 0..SIMD_WIDTH {
83 r[i] = self.0[i] + b.0[i];
84 }
85 FloatW(r)
86 }
87
88 #[inline]
90 pub fn sub(self, b: FloatW) -> FloatW {
91 let mut r = [0.0; SIMD_WIDTH];
92 for i in 0..SIMD_WIDTH {
93 r[i] = self.0[i] - b.0[i];
94 }
95 FloatW(r)
96 }
97
98 #[inline]
100 pub fn mul(self, b: FloatW) -> FloatW {
101 let mut r = [0.0; SIMD_WIDTH];
102 for i in 0..SIMD_WIDTH {
103 r[i] = self.0[i] * b.0[i];
104 }
105 FloatW(r)
106 }
107
108 #[inline]
110 pub fn mul_add(self, b: FloatW, c: FloatW) -> FloatW {
111 let mut r = [0.0; SIMD_WIDTH];
112 for i in 0..SIMD_WIDTH {
113 r[i] = self.0[i] + b.0[i] * c.0[i];
114 }
115 FloatW(r)
116 }
117
118 #[inline]
120 pub fn mul_sub(self, b: FloatW, c: FloatW) -> FloatW {
121 let mut r = [0.0; SIMD_WIDTH];
122 for i in 0..SIMD_WIDTH {
123 r[i] = self.0[i] - b.0[i] * c.0[i];
124 }
125 FloatW(r)
126 }
127
128 #[inline]
130 pub fn min(self, b: FloatW) -> FloatW {
131 let mut r = [0.0; SIMD_WIDTH];
132 for i in 0..SIMD_WIDTH {
133 r[i] = if self.0[i] < b.0[i] {
134 self.0[i]
135 } else {
136 b.0[i]
137 };
138 }
139 FloatW(r)
140 }
141
142 #[inline]
144 pub fn max(self, b: FloatW) -> FloatW {
145 let mut r = [0.0; SIMD_WIDTH];
146 for i in 0..SIMD_WIDTH {
147 r[i] = if self.0[i] > b.0[i] {
148 self.0[i]
149 } else {
150 b.0[i]
151 };
152 }
153 FloatW(r)
154 }
155
156 #[inline]
158 pub fn sym_clamp(self, b: FloatW) -> FloatW {
159 let mut r = [0.0; SIMD_WIDTH];
160 for i in 0..SIMD_WIDTH {
161 let nb = -b.0[i];
162 let m = if self.0[i] < b.0[i] {
163 self.0[i]
164 } else {
165 b.0[i]
166 };
167 r[i] = if nb > m { nb } else { m };
168 }
169 FloatW(r)
170 }
171
172 #[inline]
174 pub fn greater_than(self, b: FloatW) -> MaskW {
175 let mut r = [false; SIMD_WIDTH];
176 for i in 0..SIMD_WIDTH {
177 r[i] = self.0[i] > b.0[i];
178 }
179 MaskW(r)
180 }
181
182 #[inline]
184 pub fn equals(self, b: FloatW) -> MaskW {
185 let mut r = [false; SIMD_WIDTH];
186 for i in 0..SIMD_WIDTH {
187 r[i] = self.0[i] == b.0[i];
188 }
189 MaskW(r)
190 }
191
192 #[inline]
194 pub fn all_zero(self) -> bool {
195 self.0[0] == 0.0 && self.0[1] == 0.0 && self.0[2] == 0.0 && self.0[3] == 0.0
196 }
197
198 #[inline]
200 pub fn blend(a: FloatW, b: FloatW, mask: MaskW) -> FloatW {
201 let mut r = [0.0; SIMD_WIDTH];
202 for i in 0..SIMD_WIDTH {
203 r[i] = if mask.0[i] { b.0[i] } else { a.0[i] };
204 }
205 FloatW(r)
206 }
207}
208
209#[derive(Debug, Clone, Copy, PartialEq, Default)]
211pub struct Vec2W {
212 pub x: FloatW,
213 pub y: FloatW,
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Default)]
218pub struct RotW {
219 pub c: FloatW,
220 pub s: FloatW,
221}
222
223#[inline]
225pub fn dot_w(a: Vec2W, b: Vec2W) -> FloatW {
226 a.x.mul(b.x).add(a.y.mul(b.y))
227}
228
229#[inline]
231pub fn cross_w(a: Vec2W, b: Vec2W) -> FloatW {
232 a.x.mul(b.y).sub(a.y.mul(b.x))
233}
234
235#[inline]
237pub fn rotate_vector_w(q: RotW, v: Vec2W) -> Vec2W {
238 Vec2W {
239 x: q.c.mul(v.x).sub(q.s.mul(v.y)),
240 y: q.s.mul(v.x).add(q.c.mul(v.y)),
241 }
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Default)]
246pub struct BodyStateW {
247 pub v: Vec2W,
248 pub w: FloatW,
249 pub flags: FloatW,
250 pub dp: Vec2W,
251 pub dq: RotW,
252}
253
254#[inline]
259pub fn gather_bodies(states: &[BodyState], indices: &[i32; SIMD_WIDTH]) -> BodyStateW {
260 let mut out = BodyStateW::default();
261 for lane in 0..SIMD_WIDTH {
262 let i = indices[lane] - 1;
264 let s = if i == NULL_INDEX {
265 IDENTITY_BODY_STATE
266 } else {
267 states[i as usize]
268 };
269 out.v.x.0[lane] = s.linear_velocity.x;
270 out.v.y.0[lane] = s.linear_velocity.y;
271 out.w.0[lane] = s.angular_velocity;
272 out.flags.0[lane] = s.flags as f32;
273 out.dp.x.0[lane] = s.delta_position.x;
274 out.dp.y.0[lane] = s.delta_position.y;
275 out.dq.c.0[lane] = s.delta_rotation.c;
276 out.dq.s.0[lane] = s.delta_rotation.s;
277 }
278 out
279}
280
281#[inline]
286pub fn scatter_bodies(states: &mut [BodyState], indices: &[i32; SIMD_WIDTH], body: &BodyStateW) {
287 for lane in 0..SIMD_WIDTH {
288 let i = indices[lane] - 1;
290 if i == NULL_INDEX {
291 continue;
292 }
293 let state = &mut states[i as usize];
294 if state.flags & body_flags::DYNAMIC_FLAG != 0 {
295 state.linear_velocity = Vec2 {
296 x: body.v.x.0[lane],
297 y: body.v.y.0[lane],
298 };
299 state.angular_velocity = body.w.0[lane];
300 }
301 }
302}