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 make_joint_id(world, joint_id)
332}
333
334pub fn create_motor_joint(world: &mut World, def: &MotorJointDef) -> JointId {
336 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
337
338 let joint_id = create_joint(world, &def.base, JointType::Motor);
339
340 let joint_sim = get_joint_sim(world, joint_id);
341 let joint = joint_sim.motor_mut();
342 *joint = MotorJoint::default();
343 joint.linear_velocity = def.linear_velocity;
344 joint.max_velocity_force = def.max_velocity_force;
345 joint.angular_velocity = def.angular_velocity;
346 joint.max_velocity_torque = def.max_velocity_torque;
347 joint.linear_hertz = def.linear_hertz;
348 joint.linear_damping_ratio = def.linear_damping_ratio;
349 joint.max_spring_force = def.max_spring_force;
350 joint.angular_hertz = def.angular_hertz;
351 joint.angular_damping_ratio = def.angular_damping_ratio;
352 joint.max_spring_torque = def.max_spring_torque;
353
354 make_joint_id(world, joint_id)
355}
356
357pub fn create_filter_joint(world: &mut World, def: &FilterJointDef) -> JointId {
359 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
360
361 let joint_id = create_joint(world, &def.base, JointType::Filter);
362
363 make_joint_id(world, joint_id)
364}
365
366pub fn create_prismatic_joint(world: &mut World, def: &PrismaticJointDef) -> JointId {
368 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
369 debug_assert!(def.lower_translation <= def.upper_translation);
370
371 let joint_id = create_joint(world, &def.base, JointType::Prismatic);
372
373 let joint_sim = get_joint_sim(world, joint_id);
374 let joint = joint_sim.prismatic_mut();
375 *joint = PrismaticJoint::default();
376 joint.hertz = def.hertz;
377 joint.damping_ratio = def.damping_ratio;
378 joint.target_translation = def.target_translation;
379 joint.lower_translation = def.lower_translation;
380 joint.upper_translation = def.upper_translation;
381 joint.max_motor_force = def.max_motor_force;
382 joint.motor_speed = def.motor_speed;
383 joint.enable_spring = def.enable_spring;
384 joint.enable_limit = def.enable_limit;
385 joint.enable_motor = def.enable_motor;
386
387 make_joint_id(world, joint_id)
388}
389
390pub fn create_revolute_joint(world: &mut World, def: &RevoluteJointDef) -> JointId {
392 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
393 debug_assert!(def.lower_angle <= def.upper_angle);
394 debug_assert!(def.lower_angle >= -0.99 * PI);
395 debug_assert!(def.upper_angle <= 0.99 * PI);
396
397 let joint_id = create_joint(world, &def.base, JointType::Revolute);
398
399 let joint_sim = get_joint_sim(world, joint_id);
400 let joint = joint_sim.revolute_mut();
401 *joint = RevoluteJoint::default();
402 joint.target_angle = clamp_float(def.target_angle, -PI, PI);
403 joint.hertz = def.hertz;
404 joint.damping_ratio = def.damping_ratio;
405 joint.lower_angle = def.lower_angle;
406 joint.upper_angle = def.upper_angle;
407 joint.max_motor_torque = def.max_motor_torque;
408 joint.motor_speed = def.motor_speed;
409 joint.enable_spring = def.enable_spring;
410 joint.enable_limit = def.enable_limit;
411 joint.enable_motor = def.enable_motor;
412
413 make_joint_id(world, joint_id)
414}
415
416pub fn create_weld_joint(world: &mut World, def: &WeldJointDef) -> JointId {
418 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
419
420 let joint_id = create_joint(world, &def.base, JointType::Weld);
421
422 let joint_sim = get_joint_sim(world, joint_id);
423 let joint = joint_sim.weld_mut();
424 *joint = WeldJoint::default();
425 joint.linear_hertz = def.linear_hertz;
426 joint.linear_damping_ratio = def.linear_damping_ratio;
427 joint.angular_hertz = def.angular_hertz;
428 joint.angular_damping_ratio = def.angular_damping_ratio;
429
430 make_joint_id(world, joint_id)
431}
432
433pub fn create_wheel_joint(world: &mut World, def: &WheelJointDef) -> JointId {
435 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
436 debug_assert!(def.lower_translation <= def.upper_translation);
437
438 let joint_id = create_joint(world, &def.base, JointType::Wheel);
439
440 let joint_sim = get_joint_sim(world, joint_id);
441 let joint = joint_sim.wheel_mut();
442 *joint = WheelJoint::default();
443 joint.lower_translation = def.lower_translation;
444 joint.upper_translation = def.upper_translation;
445 joint.max_motor_torque = def.max_motor_torque;
446 joint.motor_speed = def.motor_speed;
447 joint.hertz = def.hertz;
448 joint.damping_ratio = def.damping_ratio;
449 joint.enable_spring = def.enable_spring;
450 joint.enable_limit = def.enable_limit;
451 joint.enable_motor = def.enable_motor;
452
453 make_joint_id(world, joint_id)
454}
455
456pub fn destroy_joint(world: &mut World, joint_id: JointId, wake_attached: bool) {
458 let joint_index = get_joint_full_id(world, joint_id);
459 destroy_joint_internal(world, joint_index, wake_attached);
460}