1use super::{body_flags, create_island_for_body, make_body_id, Body, BodySim, BodyState};
6use crate::constants::huge;
7use crate::core::NULL_INDEX;
8use crate::id::BodyId;
9use crate::math_functions::{
10 is_valid_float, is_valid_position, is_valid_rotation, is_valid_vec2,
11 ROT_IDENTITY as ROT_IDENTITY_,
12};
13use crate::solver_set::{SolverSet, AWAKE_SET, DISABLED_SET, STATIC_SET};
14use crate::types::BodyType;
15use crate::world::World;
16
17pub fn create_body(world: &mut World, def: &crate::types::BodyDef) -> BodyId {
19 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
20 debug_assert!(is_valid_position(def.position));
21 debug_assert!(is_valid_rotation(def.rotation));
22 debug_assert!(is_valid_vec2(def.linear_velocity));
23 debug_assert!(is_valid_float(def.angular_velocity));
24 debug_assert!(is_valid_float(def.linear_damping) && def.linear_damping >= 0.0);
25 debug_assert!(is_valid_float(def.angular_damping) && def.angular_damping >= 0.0);
26 debug_assert!(is_valid_float(def.sleep_threshold) && def.sleep_threshold >= 0.0);
27 debug_assert!(is_valid_float(def.gravity_scale));
28
29 debug_assert!(!world.locked);
30 if world.locked {
31 return BodyId::default();
32 }
33
34 let is_awake = (def.is_awake || !def.enable_sleep) && def.is_enabled;
35
36 let set_id;
38 if !def.is_enabled {
39 set_id = DISABLED_SET;
41 } else if def.type_ == BodyType::Static {
42 set_id = STATIC_SET;
43 } else if is_awake {
44 set_id = AWAKE_SET;
45 } else {
46 set_id = world.solver_set_id_pool.alloc_id();
48 if set_id == world.solver_sets.len() as i32 {
49 world.solver_sets.push(SolverSet::default());
52 } else {
53 debug_assert!(world.solver_sets[set_id as usize].set_index == NULL_INDEX);
54 }
55
56 world.solver_sets[set_id as usize].set_index = set_id;
57 }
58
59 debug_assert!(0 <= set_id && set_id < world.solver_sets.len() as i32);
60
61 let body_id = world.body_id_pool.alloc_id();
62
63 let mut lock_flags = 0u32;
64 lock_flags |= if def.motion_locks.linear_x {
65 body_flags::LOCK_LINEAR_X
66 } else {
67 0
68 };
69 lock_flags |= if def.motion_locks.linear_y {
70 body_flags::LOCK_LINEAR_Y
71 } else {
72 0
73 };
74 lock_flags |= if def.motion_locks.angular_z {
75 body_flags::LOCK_ANGULAR_Z
76 } else {
77 0
78 };
79
80 let set = &mut world.solver_sets[set_id as usize];
81 let mut body_sim = BodySim {
82 transform: crate::math_functions::WorldTransform {
83 p: def.position,
84 q: def.rotation,
85 },
86 center: def.position,
87 rotation0: def.rotation,
88 center0: def.position,
89 min_extent: huge(),
90 max_extent: 0.0,
91 linear_damping: def.linear_damping,
92 angular_damping: def.angular_damping,
93 gravity_scale: def.gravity_scale,
94 body_id,
95 flags: lock_flags,
96 ..Default::default()
97 };
98 body_sim.flags |= if def.is_bullet {
99 body_flags::IS_BULLET
100 } else {
101 0
102 };
103 body_sim.flags |= if def.allow_fast_rotation {
104 body_flags::ALLOW_FAST_ROTATION
105 } else {
106 0
107 };
108 body_sim.flags |= if def.type_ == BodyType::Dynamic {
109 body_flags::DYNAMIC_FLAG
110 } else {
111 0
112 };
113 body_sim.flags |= if def.enable_sleep {
114 body_flags::ENABLE_SLEEP
115 } else {
116 0
117 };
118 body_sim.flags |= if def.enable_contact_recycling {
119 body_flags::BODY_ENABLE_CONTACT_RECYCLING
120 } else {
121 0
122 };
123 let sim_flags = body_sim.flags;
124 set.body_sims.push(body_sim);
125 let local_index = set.body_sims.len() as i32 - 1;
126
127 if set_id == AWAKE_SET {
128 set.body_states.push(BodyState {
129 linear_velocity: def.linear_velocity,
130 angular_velocity: def.angular_velocity,
131 delta_rotation: ROT_IDENTITY_,
132 flags: sim_flags,
133 ..Default::default()
134 });
135 }
136
137 if body_id == world.bodies.len() as i32 {
138 world.bodies.push(Body::default());
139 } else {
140 debug_assert!(world.bodies[body_id as usize].id == NULL_INDEX);
141 }
142
143 let body = &mut world.bodies[body_id as usize];
144
145 body.name = def
148 .name
149 .chars()
150 .take(crate::constants::NAME_LENGTH as usize)
151 .collect();
152
153 body.user_data = def.user_data;
154 body.set_index = set_id;
155 body.local_index = local_index;
156 body.generation += 1;
157 body.head_shape_id = NULL_INDEX;
158 body.shape_count = 0;
159 body.head_chain_id = NULL_INDEX;
160 body.head_contact_key = NULL_INDEX;
161 body.contact_count = 0;
162 body.head_joint_key = NULL_INDEX;
163 body.joint_count = 0;
164 body.island_id = NULL_INDEX;
165 body.island_index = NULL_INDEX;
166 body.body_move_index = NULL_INDEX;
167 body.id = body_id;
168 body.mass = 0.0;
169 body.inertia = 0.0;
170 body.sleep_threshold = def.sleep_threshold;
171 body.sleep_time = 0.0;
172 body.type_ = def.type_;
173 body.flags = sim_flags;
174
175 if set_id >= AWAKE_SET {
177 create_island_for_body(world, set_id, body_id);
178 }
179
180 world.validate_solver_sets();
181
182 let id = make_body_id(world, body_id);
183
184 crate::recording::record_op(world, |rec, _| {
186 crate::recording::write_create_body(rec, def, id)
187 });
188
189 id
190}
191
192pub fn update_body_mass_data(world: &mut World, body_id: i32) {
195 use crate::collision::MassData;
196 use crate::math_functions::{
197 add, cross_sv, dot, max_float, min_float, mul_add, mul_sv, sub, sub_pos,
198 transform_world_point, VEC2_ZERO,
199 };
200 use crate::shape::{compute_shape_extent, compute_shape_mass};
201
202 let (set_index, local_index, body_type, head_shape_id, shape_count) = {
203 let body = &mut world.bodies[body_id as usize];
204 body.flags &= !body_flags::DIRTY_MASS;
206 body.mass = 0.0;
208 body.inertia = 0.0;
209 (
210 body.set_index,
211 body.local_index,
212 body.type_,
213 body.head_shape_id,
214 body.shape_count,
215 )
216 };
217
218 {
219 let sim = &mut world.solver_sets[set_index as usize].body_sims[local_index as usize];
220 sim.inv_mass = 0.0;
221 sim.inv_inertia = 0.0;
222 sim.local_center = VEC2_ZERO;
223 sim.min_extent = huge();
224 sim.max_extent = 0.0;
225 }
226
227 if body_type != BodyType::Dynamic {
229 {
230 let sim = &mut world.solver_sets[set_index as usize].body_sims[local_index as usize];
231 sim.center = sim.transform.p;
232 sim.center0 = sim.center;
233 }
234
235 if body_type == BodyType::Kinematic {
237 let mut shape_id = head_shape_id;
238 while shape_id != NULL_INDEX {
239 let extent = {
240 let s = &world.shapes[shape_id as usize];
241 let e = compute_shape_extent(s, VEC2_ZERO);
242 shape_id = s.next_shape_id;
243 e
244 };
245 let sim =
246 &mut world.solver_sets[set_index as usize].body_sims[local_index as usize];
247 sim.min_extent = min_float(sim.min_extent, extent.min_extent);
248 sim.max_extent = max_float(sim.max_extent, extent.max_extent);
249 }
250 }
251
252 return;
253 }
254
255 let mut masses: Vec<MassData> = Vec::with_capacity(shape_count as usize);
257
258 let mut local_center = VEC2_ZERO;
260 let mut shape_id = head_shape_id;
261 while shape_id != NULL_INDEX {
262 let (mass_data, next) = {
263 let s = &world.shapes[shape_id as usize];
264 let next = s.next_shape_id;
265 if s.density == 0.0 {
266 (MassData::default(), next)
267 } else {
268 (compute_shape_mass(s), next)
269 }
270 };
271 shape_id = next;
272
273 if mass_data.mass != 0.0 {
274 world.bodies[body_id as usize].mass += mass_data.mass;
275 local_center = mul_add(local_center, mass_data.mass, mass_data.center);
276 }
277 masses.push(mass_data);
278 }
279
280 let body_mass = world.bodies[body_id as usize].mass;
282 if body_mass > 0.0 {
283 let inv_mass = 1.0 / body_mass;
284 world.solver_sets[set_index as usize].body_sims[local_index as usize].inv_mass = inv_mass;
285 local_center = mul_sv(inv_mass, local_center);
286 }
287
288 for mass_data in &masses {
290 if mass_data.mass == 0.0 {
291 continue;
292 }
293
294 let offset = sub(local_center, mass_data.center);
296 let inertia = mass_data.rotational_inertia + mass_data.mass * dot(offset, offset);
297 world.bodies[body_id as usize].inertia += inertia;
298 }
299
300 debug_assert!(world.bodies[body_id as usize].inertia >= 0.0);
301
302 let inertia = world.bodies[body_id as usize].inertia;
303 if inertia > 0.0 {
304 world.solver_sets[set_index as usize].body_sims[local_index as usize].inv_inertia =
305 1.0 / inertia;
306 } else {
307 world.bodies[body_id as usize].inertia = 0.0;
308 world.solver_sets[set_index as usize].body_sims[local_index as usize].inv_inertia = 0.0;
309 }
310
311 let old_center = {
313 let sim = &mut world.solver_sets[set_index as usize].body_sims[local_index as usize];
314 let old = sim.center;
315 sim.local_center = local_center;
316 sim.center = transform_world_point(sim.transform, sim.local_center);
317 sim.center0 = sim.center;
318 old
319 };
320
321 if set_index == AWAKE_SET {
323 let new_center =
324 world.solver_sets[set_index as usize].body_sims[local_index as usize].center;
325 let state = &mut world.solver_sets[AWAKE_SET as usize].body_states[local_index as usize];
326 let delta_linear = cross_sv(state.angular_velocity, sub_pos(new_center, old_center));
327 state.linear_velocity = add(state.linear_velocity, delta_linear);
328 }
329
330 let mut shape_id = head_shape_id;
332 while shape_id != NULL_INDEX {
333 let extent = {
334 let s = &world.shapes[shape_id as usize];
335 let e = compute_shape_extent(s, local_center);
336 shape_id = s.next_shape_id;
337 e
338 };
339 let sim = &mut world.solver_sets[set_index as usize].body_sims[local_index as usize];
340 sim.min_extent = min_float(sim.min_extent, extent.min_extent);
341 sim.max_extent = max_float(sim.max_extent, extent.max_extent);
342 }
343}
344
345pub(crate) fn destroy_body_contacts(world: &mut World, body_id: i32, wake_bodies: bool) {
347 let mut edge_key = world.bodies[body_id as usize].head_contact_key;
348 while edge_key != NULL_INDEX {
349 let contact_id = edge_key >> 1;
350 let edge_index = edge_key & 1;
351
352 edge_key = world.contacts[contact_id as usize].edges[edge_index as usize].next_key;
353 crate::contact::destroy_contact(world, contact_id, wake_bodies);
354 }
355
356 world.validate_solver_sets();
357}
358
359pub fn destroy_body(world: &mut World, body_id: BodyId) {
362 use super::{remove_body_from_island, remove_body_sim};
363 use crate::body::get_body_full_id;
364 use crate::solver_set::FIRST_SLEEPING_SET;
365
366 crate::recording::record_op(world, |rec, _| {
367 crate::recording::write_body_marker(rec, crate::recording::OP_DESTROY_BODY, body_id)
368 });
369
370 let body_index = get_body_full_id(world, body_id);
371
372 let wake_bodies = true;
374
375 let mut edge_key = world.bodies[body_index as usize].head_joint_key;
377 while edge_key != NULL_INDEX {
378 let joint_id = edge_key >> 1;
379 let edge_index = edge_key & 1;
380
381 edge_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
382
383 crate::joint::destroy_joint_internal(world, joint_id, wake_bodies);
385 }
386
387 destroy_body_contacts(world, body_index, wake_bodies);
389
390 let mut shape_id = world.bodies[body_index as usize].head_shape_id;
392 while shape_id != NULL_INDEX {
393 if world.shapes[shape_id as usize].sensor_index != NULL_INDEX {
394 crate::sensor::destroy_sensor(world, shape_id);
395 }
396
397 {
398 let (shapes, broad_phase) = (&mut world.shapes, &mut world.broad_phase);
399 crate::shape::destroy_shape_proxy(&mut shapes[shape_id as usize], broad_phase);
400 }
401
402 world.shape_id_pool.free_id(shape_id);
404 world.shapes[shape_id as usize].id = NULL_INDEX;
405
406 shape_id = world.shapes[shape_id as usize].next_shape_id;
407 }
408
409 let mut chain_id = world.bodies[body_index as usize].head_chain_id;
412 while chain_id != NULL_INDEX {
413 {
415 let chain = &mut world.chain_shapes[chain_id as usize];
416 chain.shape_indices = Vec::new();
417 chain.materials = Vec::new();
418 }
419
420 world.chain_id_pool.free_id(chain_id);
422 world.chain_shapes[chain_id as usize].id = NULL_INDEX;
423
424 chain_id = world.chain_shapes[chain_id as usize].next_chain_id;
425 }
426
427 remove_body_from_island(world, body_index);
428
429 let (set_index, local_index) = {
431 let body = &world.bodies[body_index as usize];
432 (body.set_index, body.local_index)
433 };
434 remove_body_sim(
435 &mut world.solver_sets[set_index as usize].body_sims,
436 &mut world.bodies,
437 local_index,
438 );
439
440 if set_index == AWAKE_SET {
442 world.solver_sets[set_index as usize]
443 .body_states
444 .swap_remove(local_index as usize);
445 } else if set_index >= FIRST_SLEEPING_SET
446 && world.solver_sets[set_index as usize].body_sims.is_empty()
447 {
448 crate::solver_set::destroy_solver_set(world, set_index);
450 }
451
452 let raw_id = world.bodies[body_index as usize].id;
454 world.body_id_pool.free_id(raw_id);
455
456 let body = &mut world.bodies[body_index as usize];
457 body.set_index = NULL_INDEX;
458 body.local_index = NULL_INDEX;
459 body.id = NULL_INDEX;
460
461 world.validate_solver_sets();
462}