1use super::lifecycle::{get_body_full_id, get_body_sim_mut, wake_body, wake_body_with_lock};
7use crate::constants::speculative_distance;
8use crate::core::NULL_INDEX;
9use crate::id::BodyId;
10use crate::island::split_island;
11use crate::math_functions::{
12 aabb_contains, add, conjugate, cross, dot_quat, inv_rotate_vector, is_valid_position,
13 is_valid_quat, is_valid_vec3, is_valid_world_transform, length, length_squared,
14 make_matrix_from_quat, mul, mul_add, mul_mm, mul_mv, mul_quat, mul_sv, negate_quat, normalize,
15 rotate_vector, sub, sub_pos, transform_world_point, transpose, Aabb, Pos, Quat, Vec3,
16 WorldTransform,
17};
18use crate::shape::compute_fat_shape_aabb;
19use crate::solver_set::{try_sleep_island, AWAKE_SET, DISABLED_SET, FIRST_SLEEPING_SET};
20use crate::types::BodyType;
21use crate::world::World;
22
23pub fn body_apply_force(world: &mut World, body_id: BodyId, force: Vec3, point: Pos, wake: bool) {
25 crate::recording::with_recording(world, |rec| {
26 rec.write_body_apply_force(body_id, force, point, wake);
27 });
28 debug_assert!(is_valid_vec3(force));
29
30 let body_index = get_body_full_id(world, body_id);
31
32 if wake && world.bodies[body_index as usize].set_index >= FIRST_SLEEPING_SET {
33 wake_body_with_lock(world, body_index);
34 }
35
36 if world.bodies[body_index as usize].set_index == AWAKE_SET {
37 let body_sim = get_body_sim_mut(world, body_index);
38 body_sim.force = add(body_sim.force, force);
39 body_sim.torque = add(
40 body_sim.torque,
41 cross(sub_pos(point, body_sim.center), force),
42 );
43 }
44}
45
46pub fn body_apply_force_to_center(world: &mut World, body_id: BodyId, force: Vec3, wake: bool) {
48 crate::recording::with_recording(world, |rec| {
49 rec.write_body_apply_force_to_center(body_id, force, wake);
50 });
51 debug_assert!(is_valid_vec3(force));
52
53 let body_index = get_body_full_id(world, body_id);
54
55 if wake && world.bodies[body_index as usize].set_index >= FIRST_SLEEPING_SET {
56 wake_body_with_lock(world, body_index);
57 }
58
59 if world.bodies[body_index as usize].set_index == AWAKE_SET {
60 let body_sim = get_body_sim_mut(world, body_index);
61 body_sim.force = add(body_sim.force, force);
62 }
63}
64
65pub fn body_apply_torque(world: &mut World, body_id: BodyId, torque: Vec3, wake: bool) {
67 crate::recording::with_recording(world, |rec| {
68 rec.write_body_apply_torque(body_id, torque, wake);
69 });
70 debug_assert!(is_valid_vec3(torque));
71
72 let body_index = get_body_full_id(world, body_id);
73
74 if wake && world.bodies[body_index as usize].set_index >= FIRST_SLEEPING_SET {
75 wake_body_with_lock(world, body_index);
76 }
77
78 if world.bodies[body_index as usize].set_index == AWAKE_SET {
79 let body_sim = get_body_sim_mut(world, body_index);
80 body_sim.torque = add(body_sim.torque, torque);
81 }
82}
83
84pub fn body_apply_linear_impulse(
86 world: &mut World,
87 body_id: BodyId,
88 impulse: Vec3,
89 point: Pos,
90 wake: bool,
91) {
92 crate::recording::with_recording(world, |rec| {
93 rec.write_body_apply_linear_impulse(body_id, impulse, point, wake);
94 });
95 debug_assert!(is_valid_vec3(impulse));
96 debug_assert!(is_valid_position(point));
97
98 let body_index = get_body_full_id(world, body_id);
99
100 if wake && world.bodies[body_index as usize].set_index >= FIRST_SLEEPING_SET {
101 wake_body_with_lock(world, body_index);
102 }
103
104 if world.bodies[body_index as usize].set_index == AWAKE_SET {
105 let local_index = world.bodies[body_index as usize].local_index;
106 let max_linear_speed = world.max_linear_speed;
107 let set = &mut world.solver_sets[AWAKE_SET as usize];
108 let state = &mut set.body_states[local_index as usize];
109 let body_sim = &set.body_sims[local_index as usize];
110
111 state.linear_velocity = mul_add(state.linear_velocity, body_sim.inv_mass, impulse);
112
113 if length_squared(state.linear_velocity) > max_linear_speed * max_linear_speed {
114 state.linear_velocity = mul_sv(max_linear_speed, normalize(state.linear_velocity));
115 }
116
117 let delta = mul_mv(
118 body_sim.inv_inertia_world,
119 cross(sub_pos(point, body_sim.center), impulse),
120 );
121 state.angular_velocity = add(state.angular_velocity, delta);
122 }
123}
124
125pub fn body_apply_linear_impulse_to_center(
127 world: &mut World,
128 body_id: BodyId,
129 impulse: Vec3,
130 wake: bool,
131) {
132 crate::recording::with_recording(world, |rec| {
133 rec.write_body_apply_linear_impulse_to_center(body_id, impulse, wake);
134 });
135 debug_assert!(is_valid_vec3(impulse));
136
137 let body_index = get_body_full_id(world, body_id);
138
139 if wake && world.bodies[body_index as usize].set_index >= FIRST_SLEEPING_SET {
140 wake_body_with_lock(world, body_index);
141 }
142
143 if world.bodies[body_index as usize].set_index == AWAKE_SET {
144 let local_index = world.bodies[body_index as usize].local_index;
145 let max_linear_speed = world.max_linear_speed;
146 let set = &mut world.solver_sets[AWAKE_SET as usize];
147 let state = &mut set.body_states[local_index as usize];
148 let body_sim = &set.body_sims[local_index as usize];
149 state.linear_velocity = mul_add(state.linear_velocity, body_sim.inv_mass, impulse);
150
151 if length_squared(state.linear_velocity) > max_linear_speed * max_linear_speed {
152 state.linear_velocity = mul_sv(max_linear_speed, normalize(state.linear_velocity));
153 }
154 }
155}
156
157pub fn body_apply_angular_impulse(world: &mut World, body_id: BodyId, impulse: Vec3, wake: bool) {
159 crate::recording::with_recording(world, |rec| {
160 rec.write_body_apply_angular_impulse(body_id, impulse, wake);
161 });
162 debug_assert!(is_valid_vec3(impulse));
163 debug_assert!(super::lifecycle::body_is_valid(world, body_id));
164
165 let body_index = get_body_full_id(world, body_id);
166
167 if wake && world.bodies[body_index as usize].set_index >= FIRST_SLEEPING_SET {
168 wake_body_with_lock(world, body_index);
170 }
171
172 if world.bodies[body_index as usize].set_index == AWAKE_SET {
173 let local_index = world.bodies[body_index as usize].local_index;
174 let set = &mut world.solver_sets[AWAKE_SET as usize];
175 let state = &mut set.body_states[local_index as usize];
176 let body_sim = &set.body_sims[local_index as usize];
177
178 let local_impulse = inv_rotate_vector(body_sim.transform.q, impulse);
179 let local_angular_velocity_delta = mul_mv(body_sim.inv_inertia_local, local_impulse);
180 state.angular_velocity = add(
181 state.angular_velocity,
182 rotate_vector(body_sim.transform.q, local_angular_velocity_delta),
183 );
184 }
185}
186
187pub fn body_set_transform(world: &mut World, body_id: BodyId, position: Pos, rotation: Quat) {
189 crate::recording::with_recording(world, |rec| {
190 rec.write_body_set_transform(body_id, position, rotation);
191 });
192 debug_assert!(is_valid_position(position));
193 debug_assert!(is_valid_quat(rotation));
194 debug_assert!(super::lifecycle::body_is_valid(world, body_id));
195 debug_assert!(!world.locked);
196
197 let body_index = get_body_full_id(world, body_id);
198
199 {
200 let body_sim = get_body_sim_mut(world, body_index);
201 body_sim.transform.p = position;
202 body_sim.transform.q = rotation;
203 body_sim.center = transform_world_point(body_sim.transform, body_sim.local_center);
204
205 let rotation_matrix = make_matrix_from_quat(body_sim.transform.q);
206 body_sim.inv_inertia_world = mul_mm(
207 mul_mm(rotation_matrix, body_sim.inv_inertia_local),
208 transpose(rotation_matrix),
209 );
210
211 body_sim.rotation0 = body_sim.transform.q;
212 body_sim.center0 = body_sim.center;
213 }
214
215 let transform = world.solver_sets[world.bodies[body_index as usize].set_index as usize]
216 .body_sims[world.bodies[body_index as usize].local_index as usize]
217 .transform;
218 let speculative = speculative_distance();
219
220 let mut shape_id = world.bodies[body_index as usize].head_shape_id;
221 while shape_id != NULL_INDEX {
222 let next_shape_id;
223 let aabb;
224 let needs_move;
225 let fat_aabb;
226 let proxy_key;
227 {
228 let shape = &world.shapes[shape_id as usize];
229 next_shape_id = shape.next_shape_id;
230 aabb = compute_fat_shape_aabb(shape, transform, speculative);
231 needs_move = !aabb_contains(shape.fat_aabb, aabb);
232 let margin = shape.aabb_margin;
233 fat_aabb = Aabb {
234 lower_bound: crate::math_functions::Vec3 {
235 x: aabb.lower_bound.x - margin,
236 y: aabb.lower_bound.y - margin,
237 z: aabb.lower_bound.z - margin,
238 },
239 upper_bound: crate::math_functions::Vec3 {
240 x: aabb.upper_bound.x + margin,
241 y: aabb.upper_bound.y + margin,
242 z: aabb.upper_bound.z + margin,
243 },
244 };
245 proxy_key = shape.proxy_key;
246 }
247
248 {
249 let shape = &mut world.shapes[shape_id as usize];
250 shape.aabb = aabb;
251 if needs_move {
252 shape.fat_aabb = fat_aabb;
253 }
254 }
255
256 if needs_move && proxy_key != NULL_INDEX {
258 world.broad_phase.move_proxy(proxy_key, fat_aabb);
259 }
260
261 shape_id = next_shape_id;
262 }
263}
264
265pub fn body_set_awake(world: &mut World, body_id: BodyId, awake: bool) {
267 crate::recording::with_recording(world, |rec| {
268 rec.write_body_set_awake(body_id, awake);
269 });
270 debug_assert!(!world.locked);
271 if world.locked {
272 return;
273 }
274
275 world.locked = true;
276
277 let body_index = get_body_full_id(world, body_id);
278 let set_index = world.bodies[body_index as usize].set_index;
279 let island_id = world.bodies[body_index as usize].island_id;
280
281 if awake && set_index >= FIRST_SLEEPING_SET {
282 wake_body(world, body_index);
283 } else if !awake && set_index == AWAKE_SET {
284 if world.islands[island_id as usize].constraint_remove_count > 0 {
285 split_island(world, island_id);
287 }
288
289 try_sleep_island(world, island_id);
290 }
291
292 world.locked = false;
293}
294
295pub fn body_set_target_transform(
298 world: &mut World,
299 body_id: BodyId,
300 target: WorldTransform,
301 time_step: f32,
302 wake: bool,
303) {
304 crate::recording::with_recording(world, |rec| {
305 rec.write_body_set_target_transform(body_id, target, time_step, wake);
306 });
307 debug_assert!(is_valid_world_transform(target));
308
309 let body_index = get_body_full_id(world, body_id);
310
311 {
312 let body = &world.bodies[body_index as usize];
313 if body.set_index == DISABLED_SET {
314 return;
315 }
316
317 if body.type_ == BodyType::Static || time_step <= 0.0 {
318 return;
319 }
320
321 if body.set_index != AWAKE_SET && !wake {
322 return;
323 }
324 }
325
326 let (sim_local_center, sim_center, sim_q, sim_max_extent) = {
327 let body = &world.bodies[body_index as usize];
328 let sim = &world.solver_sets[body.set_index as usize].body_sims[body.local_index as usize];
329 (
330 sim.local_center,
331 sim.center,
332 sim.transform.q,
333 sim.max_extent,
334 )
335 };
336
337 let center2 = transform_world_point(target, sim_local_center);
339 let inv_time_step = 1.0 / time_step;
340 let linear_velocity = mul_sv(inv_time_step, sub_pos(center2, sim_center));
341
342 let q1 = sim_q;
347 let mut q2 = target.q;
348
349 if dot_quat(q1, q2) < 0.0 {
351 q2 = negate_quat(q2);
352 }
353
354 let dq = Quat {
355 v: sub(q2.v, q1.v),
356 s: q2.s - q1.s,
357 };
358 let omega = mul_quat(dq, conjugate(q1));
359 let angular_velocity = mul_sv(2.0 * inv_time_step, omega.v);
360
361 if world.bodies[body_index as usize].set_index != AWAKE_SET {
363 let max_velocity = length(linear_velocity) + length(mul(angular_velocity, sim_max_extent));
364
365 if max_velocity < world.bodies[body_index as usize].sleep_threshold {
367 return;
368 }
369
370 wake_body_with_lock(world, body_index);
372 }
373
374 debug_assert!(world.bodies[body_index as usize].set_index == AWAKE_SET);
375
376 let local_index = world.bodies[body_index as usize].local_index;
377 let state = &mut world.solver_sets[AWAKE_SET as usize].body_states[local_index as usize];
378 state.linear_velocity = linear_velocity;
379 state.angular_velocity = angular_velocity;
380}