1use super::{body_flags, Body, BodySim, IDENTITY_BODY_STATE};
7use crate::constants::huge;
8use crate::core::{NULL_INDEX, SECRET_COOKIE};
9use crate::id::{BodyId, NULL_BODY_ID};
10use crate::island::{create_island, destroy_island, validate_island};
11use crate::math_functions::{
12 is_valid_float, is_valid_position, is_valid_quat, is_valid_vec3, length, WorldTransform,
13};
14use crate::solver_set::{
15 destroy_solver_set, wake_solver_set, SolverSet, AWAKE_SET, DISABLED_SET, FIRST_SLEEPING_SET,
16 STATIC_SET,
17};
18use crate::types::BodyType;
19use crate::world::World;
20
21pub fn get_body_full_id(world: &World, body_id: BodyId) -> i32 {
23 debug_assert!(body_is_valid(world, body_id));
24 body_id.index1 - 1
25}
26
27pub fn make_body_id(world: &World, body_index: i32) -> BodyId {
29 let body = &world.bodies[body_index as usize];
30 BodyId {
31 index1: body_index + 1,
32 world0: world.world_id,
33 generation: body.generation,
34 }
35}
36
37pub fn body_is_valid(world: &World, id: BodyId) -> bool {
40 if id.index1 < 1 || (world.bodies.len() as i32) < id.index1 {
41 return false;
42 }
43
44 let body = &world.bodies[(id.index1 - 1) as usize];
45 if body.set_index == NULL_INDEX {
46 return false;
47 }
48
49 debug_assert!(body.local_index != NULL_INDEX);
50
51 if body.generation != id.generation {
52 return false;
53 }
54
55 true
56}
57
58pub fn get_body_transform_quick(world: &World, body: &Body) -> WorldTransform {
60 world.solver_sets[body.set_index as usize].body_sims[body.local_index as usize].transform
61}
62
63pub fn get_body_transform(world: &World, body_index: i32) -> WorldTransform {
65 get_body_transform_quick(world, &world.bodies[body_index as usize])
66}
67
68pub fn get_body_sim(world: &World, body_index: i32) -> &BodySim {
70 let body = &world.bodies[body_index as usize];
71 &world.solver_sets[body.set_index as usize].body_sims[body.local_index as usize]
72}
73
74pub fn get_body_sim_mut(world: &mut World, body_index: i32) -> &mut BodySim {
76 let set_index = world.bodies[body_index as usize].set_index;
77 let local_index = world.bodies[body_index as usize].local_index;
78 &mut world.solver_sets[set_index as usize].body_sims[local_index as usize]
79}
80
81pub fn get_body_state_index(world: &World, body_index: i32) -> Option<i32> {
83 let body = &world.bodies[body_index as usize];
84 if body.set_index == AWAKE_SET {
85 Some(body.local_index)
86 } else {
87 None
88 }
89}
90
91pub fn sync_body_flags(world: &mut World, body_index: i32) {
93 let flags = world.bodies[body_index as usize].flags & !body_flags::BODY_TRANSIENT_FLAGS;
94 {
95 let sim = get_body_sim_mut(world, body_index);
96 sim.flags = flags;
97 }
98 if let Some(local_index) = get_body_state_index(world, body_index) {
99 world.solver_sets[AWAKE_SET as usize].body_states[local_index as usize].flags = flags;
100 }
101}
102
103pub fn should_bodies_collide(world: &World, body_id_a: i32, body_id_b: i32) -> bool {
105 let body_a = &world.bodies[body_id_a as usize];
106 let body_b = &world.bodies[body_id_b as usize];
107
108 let (mut joint_key, other_body_id) = if body_a.joint_count < body_b.joint_count {
109 (body_a.head_joint_key, body_b.id)
110 } else {
111 (body_b.head_joint_key, body_a.id)
112 };
113
114 while joint_key != NULL_INDEX {
115 let joint_id = joint_key >> 1;
116 let edge_index = joint_key & 1;
117 let other_edge_index = edge_index ^ 1;
118 let joint = &world.joints[joint_id as usize];
119 if !joint.collide_connected
120 && joint.edges[other_edge_index as usize].body_id == other_body_id
121 {
122 return false;
123 }
124 joint_key = joint.edges[edge_index as usize].next_key;
125 }
126
127 true
128}
129
130pub(crate) fn create_island_for_body(world: &mut World, set_index: i32, body_index: i32) {
132 debug_assert!(world.bodies[body_index as usize].island_id == NULL_INDEX);
133 debug_assert!(set_index != DISABLED_SET);
134
135 let island_id = create_island(world, set_index);
136 world.islands[island_id as usize].bodies.push(body_index);
137 let body = &mut world.bodies[body_index as usize];
138 body.island_id = island_id;
139 body.island_index = 0;
140
141 validate_island(world, island_id);
142}
143
144pub(crate) fn remove_body_from_island(world: &mut World, body_index: i32) {
146 let (island_id, island_index) = {
147 let body = &world.bodies[body_index as usize];
148 (body.island_id, body.island_index)
149 };
150 if island_id == NULL_INDEX {
151 debug_assert!(island_index == NULL_INDEX);
152 return;
153 }
154
155 {
156 let local_index = island_index;
157 let last = world.islands[island_id as usize].bodies.len() - 1;
158 let moved_body_id = world.islands[island_id as usize].bodies[last];
159 world.islands[island_id as usize].bodies[local_index as usize] = moved_body_id;
160 debug_assert!(world.bodies[moved_body_id as usize].island_index == last as i32);
161 world.bodies[moved_body_id as usize].island_index = local_index;
162 world.islands[island_id as usize].bodies.pop();
163 }
164
165 if world.islands[island_id as usize].bodies.is_empty() {
166 debug_assert!(world.islands[island_id as usize].contacts.is_empty());
167 debug_assert!(world.islands[island_id as usize].joints.is_empty());
168 destroy_island(world, island_id);
169 } else {
170 validate_island(world, island_id);
171 }
172
173 let body = &mut world.bodies[body_index as usize];
174 body.island_id = NULL_INDEX;
175 body.island_index = NULL_INDEX;
176}
177
178pub fn is_body_awake(world: &World, body_index: i32) -> bool {
180 world.bodies[body_index as usize].set_index == AWAKE_SET
181}
182
183pub fn wake_body(world: &mut World, body_index: i32) -> bool {
185 let set_index = world.bodies[body_index as usize].set_index;
186 if set_index >= FIRST_SLEEPING_SET {
187 wake_solver_set(world, set_index);
188 world.validate_solver_sets();
189 return true;
190 }
191 false
192}
193
194pub fn wake_body_with_lock(world: &mut World, body_index: i32) -> bool {
196 debug_assert!(!world.locked);
197 world.locked = true;
198 let woke = wake_body(world, body_index);
199 world.locked = false;
200 woke
201}
202
203pub fn create_body(world: &mut World, def: &crate::types::BodyDef) -> BodyId {
207 debug_assert!(def.internal_value == SECRET_COOKIE);
208 debug_assert!(is_valid_position(def.position));
209 debug_assert!(is_valid_quat(def.rotation));
210 debug_assert!(is_valid_vec3(def.linear_velocity));
211 debug_assert!(is_valid_vec3(def.angular_velocity));
212 debug_assert!(is_valid_float(def.linear_damping) && def.linear_damping >= 0.0);
213 debug_assert!(is_valid_float(def.angular_damping) && def.angular_damping >= 0.0);
214 debug_assert!(is_valid_float(def.sleep_threshold) && def.sleep_threshold >= 0.0);
215 debug_assert!(is_valid_float(def.gravity_scale));
216
217 debug_assert!(!world.locked);
218 if world.locked {
219 return NULL_BODY_ID;
220 }
221
222 world.locked = true;
223
224 let is_awake = (def.is_awake || !def.enable_sleep) && def.is_enabled;
225
226 let set_id;
228 if !def.is_enabled {
229 set_id = DISABLED_SET;
230 } else if def.type_ == BodyType::Static {
231 set_id = STATIC_SET;
232 } else if is_awake {
233 set_id = AWAKE_SET;
234 } else {
235 set_id = world.solver_set_id_pool.alloc_id();
237 if set_id == world.solver_sets.len() as i32 {
238 world.solver_sets.push(SolverSet::default());
239 } else {
240 debug_assert!(world.solver_sets[set_id as usize].set_index == NULL_INDEX);
241 }
242 world.solver_sets[set_id as usize].set_index = set_id;
243 }
244
245 debug_assert!(0 <= set_id && set_id < world.solver_sets.len() as i32);
246
247 let body_id = world.body_id_pool.alloc_id();
248
249 let mut lock_flags = 0u32;
250 lock_flags |= if def.motion_locks.linear_x {
251 body_flags::LOCK_LINEAR_X
252 } else {
253 0
254 };
255 lock_flags |= if def.motion_locks.linear_y {
256 body_flags::LOCK_LINEAR_Y
257 } else {
258 0
259 };
260 lock_flags |= if def.motion_locks.linear_z {
261 body_flags::LOCK_LINEAR_Z
262 } else {
263 0
264 };
265 lock_flags |= if def.motion_locks.angular_x {
266 body_flags::LOCK_ANGULAR_X
267 } else {
268 0
269 };
270 lock_flags |= if def.motion_locks.angular_y {
271 body_flags::LOCK_ANGULAR_Y
272 } else {
273 0
274 };
275 lock_flags |= if def.motion_locks.angular_z {
276 body_flags::LOCK_ANGULAR_Z
277 } else {
278 0
279 };
280
281 let mut body_sim = BodySim {
282 transform: WorldTransform {
283 p: def.position,
284 q: def.rotation,
285 },
286 center: def.position,
287 rotation0: def.rotation,
288 center0: def.position,
289 min_extent: huge(),
290 max_extent: crate::math_functions::VEC3_ZERO,
291 linear_damping: def.linear_damping,
292 angular_damping: def.angular_damping,
293 gravity_scale: def.gravity_scale,
294 body_id,
295 flags: lock_flags,
296 ..Default::default()
297 };
298 body_sim.flags |= if def.is_bullet {
299 body_flags::IS_BULLET
300 } else {
301 0
302 };
303 body_sim.flags |= if def.allow_fast_rotation {
304 body_flags::ALLOW_FAST_ROTATION
305 } else {
306 0
307 };
308 body_sim.flags |= if def.type_ == BodyType::Dynamic {
309 body_flags::DYNAMIC_FLAG
310 } else {
311 0
312 };
313 body_sim.flags |= if def.enable_sleep {
314 body_flags::ENABLE_SLEEP
315 } else {
316 0
317 };
318 body_sim.flags |= if def.enable_contact_recycling {
319 body_flags::BODY_ENABLE_CONTACT_RECYCLING
320 } else {
321 0
322 };
323 let sim_flags = body_sim.flags;
324
325 let local_index = {
326 let set = &mut world.solver_sets[set_id as usize];
327 set.body_sims.push(body_sim);
328 let local_index = set.body_sims.len() as i32 - 1;
329
330 if set_id == AWAKE_SET {
331 let mut body_state = IDENTITY_BODY_STATE;
332 body_state.linear_velocity = def.linear_velocity;
333 body_state.angular_velocity = def.angular_velocity;
334 body_state.flags = sim_flags;
335 set.body_states.push(body_state);
336
337 set.body_sims[local_index as usize].max_angular_velocity =
338 length(def.angular_velocity) + 5.0;
339 }
340 local_index
341 };
342
343 if body_id == world.bodies.len() as i32 {
344 world.bodies.push(Body::default());
345 } else {
346 debug_assert!(world.bodies[body_id as usize].id == NULL_INDEX);
347 }
348
349 let name_id = world.names.add_name(&def.name);
350
351 {
352 let body = &mut world.bodies[body_id as usize];
353 body.user_data = def.user_data;
354 body.set_index = set_id;
355 body.local_index = local_index;
356 body.generation = body.generation.wrapping_add(1);
357 body.head_shape_id = NULL_INDEX;
358 body.shape_count = 0;
359 body.head_chain_id = NULL_INDEX;
360 body.head_contact_key = NULL_INDEX;
361 body.contact_count = 0;
362 body.head_joint_key = NULL_INDEX;
363 body.joint_count = 0;
364 body.island_id = NULL_INDEX;
365 body.island_index = NULL_INDEX;
366 body.body_move_index = NULL_INDEX;
367 body.id = body_id;
368 body.sleep_threshold = def.sleep_threshold;
369 body.sleep_time = 0.0;
370 body.sleep_velocity = 0.0;
371 body.mass = 0.0;
372 body.inertia = crate::math_functions::MAT3_ZERO;
373 body.name_id = name_id;
374 body.type_ = def.type_;
375 body.flags = sim_flags;
376 }
377
378 if set_id >= AWAKE_SET {
380 create_island_for_body(world, set_id, body_id);
381 }
382
383 world.validate_solver_sets();
384
385 let id = make_body_id(world, body_id);
386 world.locked = false;
387
388 crate::recording::capture::rec(world, |rec, wid| {
389 rec.write_create_body(wid, def, id);
390 });
391
392 id
393}
394
395pub(crate) fn destroy_body_contacts(world: &mut World, body_index: i32, wake_bodies: bool) {
397 let mut edge_key = world.bodies[body_index as usize].head_contact_key;
398 while edge_key != NULL_INDEX {
399 let contact_id = edge_key >> 1;
400 let edge_index = edge_key & 1;
401 edge_key = world.contacts[contact_id as usize].edges[edge_index as usize].next_key;
402 crate::contact::destroy_contact(world, contact_id, wake_bodies);
403 }
404
405 world.validate_solver_sets();
406}
407
408pub fn destroy_body(world: &mut World, body_id: BodyId) {
410 debug_assert!(!world.locked);
411 if world.locked {
412 return;
413 }
414
415 crate::recording::capture::rec(world, |_rec, _wid| {
416 _rec.write_destroy_body(body_id);
417 });
418
419 world.locked = true;
420
421 let body_index = get_body_full_id(world, body_id);
422
423 let wake_bodies = true;
425
426 let mut edge_key = world.bodies[body_index as usize].head_joint_key;
428 while edge_key != NULL_INDEX {
429 let joint_id = edge_key >> 1;
430 let edge_index = edge_key & 1;
431 edge_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
432
433 crate::joint::destroy_joint_internal(world, joint_id, wake_bodies);
435 }
436
437 destroy_body_contacts(world, body_index, wake_bodies);
438
439 let mut shape_id = world.bodies[body_index as usize].head_shape_id;
441 while shape_id != NULL_INDEX {
442 let next = world.shapes[shape_id as usize].next_shape_id;
443 crate::shape::lifecycle::destroy_shape_internal(world, shape_id, body_index, true);
444 shape_id = next;
445 }
446
447 remove_body_from_island(world, body_index);
448
449 let (set_index, local_index) = {
450 let body = &world.bodies[body_index as usize];
451 (body.set_index, body.local_index)
452 };
453
454 let set = &mut world.solver_sets[set_index as usize];
455 let moved_index = {
456 let last = set.body_sims.len() as i32 - 1;
457 set.body_sims.swap_remove(local_index as usize);
458 if local_index < last {
459 Some(last)
460 } else {
461 None
462 }
463 };
464
465 if let Some(moved) = moved_index {
466 let moved_sim = &set.body_sims[local_index as usize];
467 let moved_id = moved_sim.body_id;
468 let moved_body = &mut world.bodies[moved_id as usize];
469 debug_assert!(moved_body.local_index == moved);
470 moved_body.local_index = local_index;
471 }
472
473 if set_index == AWAKE_SET {
474 let result = {
475 let last = world.solver_sets[AWAKE_SET as usize].body_states.len() as i32 - 1;
476 world.solver_sets[AWAKE_SET as usize]
477 .body_states
478 .swap_remove(local_index as usize);
479 if local_index < last {
480 Some(last)
481 } else {
482 None
483 }
484 };
485 debug_assert!(result == moved_index);
486 let _ = result;
487 } else if set_index >= FIRST_SLEEPING_SET
488 && world.solver_sets[set_index as usize].body_sims.is_empty()
489 {
490 destroy_solver_set(world, set_index);
491 }
492
493 world.body_id_pool.free_id(body_index);
494
495 let body = &mut world.bodies[body_index as usize];
496 body.set_index = NULL_INDEX;
497 body.local_index = NULL_INDEX;
498 body.id = NULL_INDEX;
499
500 world.validate_solver_sets();
501 world.locked = false;
502}