1use super::*;
15use crate::body::get_body_full_id;
16use crate::constants::linear_slop;
17use crate::core::NULL_INDEX;
18use crate::id::JointId;
19use crate::island::link_joint;
20use crate::math_functions::{
21 clamp_float, is_valid_float, is_valid_transform, max_float, max_int, PI,
22};
23use crate::solver_set::{
24 merge_solver_sets, wake_solver_set, AWAKE_SET, DISABLED_SET, FIRST_SLEEPING_SET, STATIC_SET,
25};
26use crate::types::{
27 BodyType, DistanceJointDef, FilterJointDef, JointDef, MotorJointDef, PrismaticJointDef,
28 RevoluteJointDef, WeldJointDef, WheelJointDef,
29};
30use crate::world::World;
31
32fn empty_payload(joint_type: JointType) -> JointPayload {
35 match joint_type {
36 JointType::Distance => JointPayload::Distance(DistanceJoint::default()),
37 JointType::Filter => JointPayload::Filter,
38 JointType::Motor => JointPayload::Motor(MotorJoint::default()),
39 JointType::Prismatic => JointPayload::Prismatic(PrismaticJoint::default()),
40 JointType::Revolute => JointPayload::Revolute(RevoluteJoint::default()),
41 JointType::Weld => JointPayload::Weld(WeldJoint::default()),
42 JointType::Wheel => JointPayload::Wheel(WheelJoint::default()),
43 }
44}
45
46pub(crate) fn destroy_contacts_between_bodies(world: &mut World, body_id_a: i32, body_id_b: i32) {
48 let (mut contact_key, other_body_id) = {
50 let body_a = &world.bodies[body_id_a as usize];
51 let body_b = &world.bodies[body_id_b as usize];
52 if body_a.contact_count < body_b.contact_count {
53 (body_a.head_contact_key, body_b.id)
54 } else {
55 (body_b.head_contact_key, body_a.id)
56 }
57 };
58
59 let wake_bodies = false;
61
62 while contact_key != NULL_INDEX {
64 let contact_id = contact_key >> 1;
65 let edge_index = contact_key & 1;
66
67 contact_key = world.contacts[contact_id as usize].edges[edge_index as usize].next_key;
68
69 let other_edge_index = edge_index ^ 1;
70 if world.contacts[contact_id as usize].edges[other_edge_index as usize].body_id
71 == other_body_id
72 {
73 crate::contact::destroy_contact(world, contact_id, wake_bodies);
76 }
77 }
78
79 world.validate_solver_sets();
80}
81
82pub(crate) fn create_joint(world: &mut World, def: &JointDef, joint_type: JointType) -> i32 {
85 debug_assert!(is_valid_transform(def.local_frame_a));
86 debug_assert!(is_valid_transform(def.local_frame_b));
87 debug_assert!(def.body_id_a != def.body_id_b);
88
89 let body_id_a = get_body_full_id(world, def.body_id_a);
90 let body_id_b = get_body_full_id(world, def.body_id_b);
91 let max_set_index = max_int(
92 world.bodies[body_id_a as usize].set_index,
93 world.bodies[body_id_b as usize].set_index,
94 );
95
96 let joint_id = world.joint_id_pool.alloc_id();
98 if joint_id == world.joints.len() as i32 {
99 world.joints.push(Joint::default());
100 }
101
102 {
103 let joint = &mut world.joints[joint_id as usize];
104 joint.joint_id = joint_id;
105 joint.user_data = def.user_data;
106 joint.generation = joint.generation.wrapping_add(1);
107 joint.set_index = NULL_INDEX;
108 joint.color_index = NULL_INDEX;
109 joint.local_index = NULL_INDEX;
110 joint.island_id = NULL_INDEX;
111 joint.island_index = NULL_INDEX;
112 joint.draw_scale = def.draw_scale;
113 joint.type_ = joint_type;
114 joint.collide_connected = def.collide_connected;
115 }
116
117 {
119 let head_joint_key = world.bodies[body_id_a as usize].head_joint_key;
120 {
121 let joint = &mut world.joints[joint_id as usize];
122 joint.edges[0].body_id = body_id_a;
123 joint.edges[0].prev_key = NULL_INDEX;
124 joint.edges[0].next_key = head_joint_key;
125 }
126
127 let key_a = joint_id << 1;
128 if head_joint_key != NULL_INDEX {
129 let head_joint = &mut world.joints[(head_joint_key >> 1) as usize];
130 head_joint.edges[(head_joint_key & 1) as usize].prev_key = key_a;
131 }
132 let body_a = &mut world.bodies[body_id_a as usize];
133 body_a.head_joint_key = key_a;
134 body_a.joint_count += 1;
135 }
136
137 {
139 let head_joint_key = world.bodies[body_id_b as usize].head_joint_key;
140 {
141 let joint = &mut world.joints[joint_id as usize];
142 joint.edges[1].body_id = body_id_b;
143 joint.edges[1].prev_key = NULL_INDEX;
144 joint.edges[1].next_key = head_joint_key;
145 }
146
147 let key_b = (joint_id << 1) | 1;
148 if head_joint_key != NULL_INDEX {
149 let head_joint = &mut world.joints[(head_joint_key >> 1) as usize];
150 head_joint.edges[(head_joint_key & 1) as usize].prev_key = key_b;
151 }
152 let body_b = &mut world.bodies[body_id_b as usize];
153 body_b.head_joint_key = key_b;
154 body_b.joint_count += 1;
155 }
156
157 let set_a = world.bodies[body_id_a as usize].set_index;
158 let set_b = world.bodies[body_id_b as usize].set_index;
159 let type_a = world.bodies[body_id_a as usize].type_;
160 let type_b = world.bodies[body_id_b as usize].type_;
161
162 if set_a == DISABLED_SET || set_b == DISABLED_SET {
163 let local_index = world.solver_sets[DISABLED_SET as usize].joint_sims.len() as i32;
165 {
166 let joint = &mut world.joints[joint_id as usize];
167 joint.set_index = DISABLED_SET;
168 joint.local_index = local_index;
169 }
170
171 let joint_sim = JointSim {
172 joint_id,
173 body_id_a,
174 body_id_b,
175 payload: empty_payload(joint_type),
176 ..JointSim::default()
177 };
178 world.solver_sets[DISABLED_SET as usize]
179 .joint_sims
180 .push(joint_sim);
181 } else if type_a != BodyType::Dynamic && type_b != BodyType::Dynamic {
182 let local_index = world.solver_sets[STATIC_SET as usize].joint_sims.len() as i32;
184 {
185 let joint = &mut world.joints[joint_id as usize];
186 joint.set_index = STATIC_SET;
187 joint.local_index = local_index;
188 }
189
190 let joint_sim = JointSim {
191 joint_id,
192 body_id_a,
193 body_id_b,
194 payload: empty_payload(joint_type),
195 ..JointSim::default()
196 };
197 world.solver_sets[STATIC_SET as usize]
198 .joint_sims
199 .push(joint_sim);
200 } else if set_a == AWAKE_SET || set_b == AWAKE_SET {
201 if max_set_index >= FIRST_SLEEPING_SET {
203 wake_solver_set(world, max_set_index);
204 }
205
206 world.joints[joint_id as usize].set_index = AWAKE_SET;
207
208 let (color_index, local_index) =
209 crate::constraint_graph::create_joint_in_graph(world, joint_id);
210 {
211 let joint_sim = &mut world.constraint_graph.colors[color_index as usize].joint_sims
212 [local_index as usize];
213 joint_sim.joint_id = joint_id;
214 joint_sim.body_id_a = body_id_a;
215 joint_sim.body_id_b = body_id_b;
216 joint_sim.payload = empty_payload(joint_type);
217 }
218 } else {
219 debug_assert!(set_a >= FIRST_SLEEPING_SET || set_b >= FIRST_SLEEPING_SET);
221 debug_assert!(set_a != STATIC_SET || set_b != STATIC_SET);
222
223 let set_index = max_set_index;
225
226 let local_index = world.solver_sets[set_index as usize].joint_sims.len() as i32;
227 {
228 let joint = &mut world.joints[joint_id as usize];
229 joint.set_index = set_index;
230 joint.local_index = local_index;
231 }
232
233 let joint_sim = JointSim {
235 joint_id,
236 body_id_a,
237 body_id_b,
238 payload: empty_payload(joint_type),
239 ..JointSim::default()
240 };
241 world.solver_sets[set_index as usize]
242 .joint_sims
243 .push(joint_sim);
244
245 if set_a != set_b && set_a >= FIRST_SLEEPING_SET && set_b >= FIRST_SLEEPING_SET {
246 merge_solver_sets(world, set_a, set_b);
249 debug_assert!(
250 world.bodies[body_id_a as usize].set_index
251 == world.bodies[body_id_b as usize].set_index
252 );
253 }
254 }
255
256 debug_assert!(is_valid_float(def.force_threshold) && def.force_threshold >= 0.0);
257 debug_assert!(is_valid_float(def.torque_threshold) && def.torque_threshold >= 0.0);
258
259 {
260 let joint_sim = get_joint_sim(world, joint_id);
261 joint_sim.local_frame_a = def.local_frame_a;
262 joint_sim.local_frame_b = def.local_frame_b;
263 joint_sim.constraint_hertz = def.constraint_hertz;
264 joint_sim.constraint_damping_ratio = def.constraint_damping_ratio;
265 joint_sim.constraint_softness = crate::solver::Softness {
266 bias_rate: 0.0,
267 mass_scale: 1.0,
268 impulse_scale: 0.0,
269 };
270 joint_sim.force_threshold = def.force_threshold;
271 joint_sim.torque_threshold = def.torque_threshold;
272
273 debug_assert!(joint_sim.joint_id == joint_id);
274 debug_assert!(joint_sim.body_id_a == body_id_a);
275 debug_assert!(joint_sim.body_id_b == body_id_b);
276 }
277
278 if world.joints[joint_id as usize].set_index > DISABLED_SET {
279 link_joint(world, joint_id);
281 }
282
283 if !def.collide_connected {
286 destroy_contacts_between_bodies(world, body_id_a, body_id_b);
287 }
288
289 world.validate_solver_sets();
290
291 joint_id
292}
293
294pub(crate) fn make_joint_id(world: &World, joint_id: i32) -> JointId {
296 JointId {
297 index1: joint_id + 1,
298 world0: world.world_id,
299 generation: world.joints[joint_id as usize].generation,
300 }
301}
302
303pub fn create_distance_joint(world: &mut World, def: &DistanceJointDef) -> JointId {
305 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
306 debug_assert!(is_valid_float(def.length) && def.length > 0.0);
307 debug_assert!(def.lower_spring_force <= def.upper_spring_force);
308
309 let joint_id = create_joint(world, &def.base, JointType::Distance);
310
311 let joint_sim = get_joint_sim(world, joint_id);
312 let joint = joint_sim.distance_mut();
313 *joint = DistanceJoint::default();
314 joint.length = max_float(def.length, linear_slop());
315 joint.hertz = def.hertz;
316 joint.damping_ratio = def.damping_ratio;
317 joint.min_length = max_float(def.min_length, linear_slop());
318 joint.max_length = max_float(def.min_length, def.max_length);
319 joint.max_motor_force = def.max_motor_force;
320 joint.motor_speed = def.motor_speed;
321 joint.enable_spring = def.enable_spring;
322 joint.lower_spring_force = def.lower_spring_force;
323 joint.upper_spring_force = def.upper_spring_force;
324 joint.enable_limit = def.enable_limit;
325 joint.enable_motor = def.enable_motor;
326 joint.impulse = 0.0;
327 joint.lower_impulse = 0.0;
328 joint.upper_impulse = 0.0;
329 joint.motor_impulse = 0.0;
330
331 let id = make_joint_id(world, joint_id);
332
333 crate::recording::record_op(world, |rec, _| {
335 crate::recording::write_create_joint(
336 rec,
337 crate::recording::OP_CREATE_DISTANCE_JOINT,
338 |buf| crate::recording::rec_w_distancejointdef(buf, def),
339 id,
340 )
341 });
342
343 id
344}
345
346pub fn create_motor_joint(world: &mut World, def: &MotorJointDef) -> JointId {
348 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
349
350 let joint_id = create_joint(world, &def.base, JointType::Motor);
351
352 let joint_sim = get_joint_sim(world, joint_id);
353 let joint = joint_sim.motor_mut();
354 *joint = MotorJoint::default();
355 joint.linear_velocity = def.linear_velocity;
356 joint.max_velocity_force = def.max_velocity_force;
357 joint.angular_velocity = def.angular_velocity;
358 joint.max_velocity_torque = def.max_velocity_torque;
359 joint.linear_hertz = def.linear_hertz;
360 joint.linear_damping_ratio = def.linear_damping_ratio;
361 joint.max_spring_force = def.max_spring_force;
362 joint.angular_hertz = def.angular_hertz;
363 joint.angular_damping_ratio = def.angular_damping_ratio;
364 joint.max_spring_torque = def.max_spring_torque;
365
366 let id = make_joint_id(world, joint_id);
367
368 crate::recording::record_op(world, |rec, _| {
370 crate::recording::write_create_joint(
371 rec,
372 crate::recording::OP_CREATE_MOTOR_JOINT,
373 |buf| crate::recording::rec_w_motorjointdef(buf, def),
374 id,
375 )
376 });
377
378 id
379}
380
381pub fn create_filter_joint(world: &mut World, def: &FilterJointDef) -> JointId {
383 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
384
385 let joint_id = create_joint(world, &def.base, JointType::Filter);
386
387 let id = make_joint_id(world, joint_id);
388
389 crate::recording::record_op(world, |rec, _| {
391 crate::recording::write_create_joint(
392 rec,
393 crate::recording::OP_CREATE_FILTER_JOINT,
394 |buf| crate::recording::rec_w_filterjointdef(buf, def),
395 id,
396 )
397 });
398
399 id
400}
401
402pub fn create_prismatic_joint(world: &mut World, def: &PrismaticJointDef) -> JointId {
404 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
405 debug_assert!(def.lower_translation <= def.upper_translation);
406
407 let joint_id = create_joint(world, &def.base, JointType::Prismatic);
408
409 let joint_sim = get_joint_sim(world, joint_id);
410 let joint = joint_sim.prismatic_mut();
411 *joint = PrismaticJoint::default();
412 joint.hertz = def.hertz;
413 joint.damping_ratio = def.damping_ratio;
414 joint.target_translation = def.target_translation;
415 joint.lower_translation = def.lower_translation;
416 joint.upper_translation = def.upper_translation;
417 joint.max_motor_force = def.max_motor_force;
418 joint.motor_speed = def.motor_speed;
419 joint.enable_spring = def.enable_spring;
420 joint.enable_limit = def.enable_limit;
421 joint.enable_motor = def.enable_motor;
422
423 let id = make_joint_id(world, joint_id);
424
425 crate::recording::record_op(world, |rec, _| {
427 crate::recording::write_create_joint(
428 rec,
429 crate::recording::OP_CREATE_PRISMATIC_JOINT,
430 |buf| crate::recording::rec_w_prismaticjointdef(buf, def),
431 id,
432 )
433 });
434
435 id
436}
437
438pub fn create_revolute_joint(world: &mut World, def: &RevoluteJointDef) -> JointId {
440 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
441 debug_assert!(def.lower_angle <= def.upper_angle);
442 debug_assert!(def.lower_angle >= -0.99 * PI);
443 debug_assert!(def.upper_angle <= 0.99 * PI);
444
445 let joint_id = create_joint(world, &def.base, JointType::Revolute);
446
447 let joint_sim = get_joint_sim(world, joint_id);
448 let joint = joint_sim.revolute_mut();
449 *joint = RevoluteJoint::default();
450 joint.target_angle = clamp_float(def.target_angle, -PI, PI);
451 joint.hertz = def.hertz;
452 joint.damping_ratio = def.damping_ratio;
453 joint.lower_angle = def.lower_angle;
454 joint.upper_angle = def.upper_angle;
455 joint.max_motor_torque = def.max_motor_torque;
456 joint.motor_speed = def.motor_speed;
457 joint.enable_spring = def.enable_spring;
458 joint.enable_limit = def.enable_limit;
459 joint.enable_motor = def.enable_motor;
460
461 let id = make_joint_id(world, joint_id);
462
463 crate::recording::record_op(world, |rec, _| {
465 crate::recording::write_create_joint(
466 rec,
467 crate::recording::OP_CREATE_REVOLUTE_JOINT,
468 |buf| crate::recording::rec_w_revolutejointdef(buf, def),
469 id,
470 )
471 });
472
473 id
474}
475
476pub fn create_weld_joint(world: &mut World, def: &WeldJointDef) -> JointId {
478 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
479
480 let joint_id = create_joint(world, &def.base, JointType::Weld);
481
482 let joint_sim = get_joint_sim(world, joint_id);
483 let joint = joint_sim.weld_mut();
484 *joint = WeldJoint::default();
485 joint.linear_hertz = def.linear_hertz;
486 joint.linear_damping_ratio = def.linear_damping_ratio;
487 joint.angular_hertz = def.angular_hertz;
488 joint.angular_damping_ratio = def.angular_damping_ratio;
489
490 let id = make_joint_id(world, joint_id);
491
492 crate::recording::record_op(world, |rec, _| {
494 crate::recording::write_create_joint(
495 rec,
496 crate::recording::OP_CREATE_WELD_JOINT,
497 |buf| crate::recording::rec_w_weldjointdef(buf, def),
498 id,
499 )
500 });
501
502 id
503}
504
505pub fn create_wheel_joint(world: &mut World, def: &WheelJointDef) -> JointId {
507 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
508 debug_assert!(def.lower_translation <= def.upper_translation);
509
510 let joint_id = create_joint(world, &def.base, JointType::Wheel);
511
512 let joint_sim = get_joint_sim(world, joint_id);
513 let joint = joint_sim.wheel_mut();
514 *joint = WheelJoint::default();
515 joint.lower_translation = def.lower_translation;
516 joint.upper_translation = def.upper_translation;
517 joint.max_motor_torque = def.max_motor_torque;
518 joint.motor_speed = def.motor_speed;
519 joint.hertz = def.hertz;
520 joint.damping_ratio = def.damping_ratio;
521 joint.enable_spring = def.enable_spring;
522 joint.enable_limit = def.enable_limit;
523 joint.enable_motor = def.enable_motor;
524
525 let id = make_joint_id(world, joint_id);
526
527 crate::recording::record_op(world, |rec, _| {
529 crate::recording::write_create_joint(
530 rec,
531 crate::recording::OP_CREATE_WHEEL_JOINT,
532 |buf| crate::recording::rec_w_wheeljointdef(buf, def),
533 id,
534 )
535 });
536
537 id
538}
539
540pub fn destroy_joint(world: &mut World, joint_id: JointId, wake_attached: bool) {
542 crate::recording::record_op(world, |rec, _| {
543 crate::recording::write_destroy_joint(rec, joint_id, wake_attached)
544 });
545 let joint_index = get_joint_full_id(world, joint_id);
546 destroy_joint_internal(world, joint_index, wake_attached);
547}