rapier3d/pipeline/
user_changes.rs

1use crate::dynamics::{
2    ImpulseJointSet, IslandManager, JointEnabled, MultibodyJointSet, RigidBodyChanges,
3    RigidBodyHandle, RigidBodySet,
4};
5use crate::geometry::{
6    ColliderChanges, ColliderEnabled, ColliderHandle, ColliderPosition, ColliderSet,
7    ModifiedColliders,
8};
9
10pub(crate) fn handle_user_changes_to_colliders(
11    bodies: &mut RigidBodySet,
12    colliders: &mut ColliderSet,
13    modified_colliders: &[ColliderHandle],
14) {
15    for handle in modified_colliders {
16        // NOTE: we use `get` because the collider may no longer
17        //       exist if it has been removed.
18        if let Some(co) = colliders.get_mut_internal(*handle) {
19            if co.changes.contains(ColliderChanges::PARENT) {
20                if let Some(co_parent) = co.parent {
21                    let parent_rb = &bodies[co_parent.handle];
22
23                    co.pos = ColliderPosition(parent_rb.pos.position * co_parent.pos_wrt_parent);
24                    co.changes |= ColliderChanges::POSITION;
25                }
26            }
27
28            if co.changes.intersects(
29                ColliderChanges::SHAPE
30                    | ColliderChanges::LOCAL_MASS_PROPERTIES
31                    | ColliderChanges::ENABLED_OR_DISABLED
32                    | ColliderChanges::PARENT,
33            ) {
34                if let Some(rb) = co
35                    .parent
36                    .and_then(|p| bodies.get_mut_internal_with_modification_tracking(p.handle))
37                {
38                    rb.changes |= RigidBodyChanges::LOCAL_MASS_PROPERTIES;
39                }
40            }
41        }
42    }
43}
44
45pub(crate) fn handle_user_changes_to_rigid_bodies(
46    mut islands: Option<&mut IslandManager>,
47    bodies: &mut RigidBodySet,
48    colliders: &mut ColliderSet,
49    impulse_joints: &mut ImpulseJointSet,
50    _multibody_joints: &mut MultibodyJointSet, // FIXME: propagate disabled state to multibodies
51    modified_bodies: &[RigidBodyHandle],
52    modified_colliders: &mut ModifiedColliders,
53) {
54    enum FinalAction {
55        RemoveFromIsland,
56    }
57
58    for handle in modified_bodies {
59        let mut final_action = None;
60
61        if !bodies.contains(*handle) {
62            // The body no longer exists.
63            continue;
64        }
65
66        let rb = bodies.index_mut_internal(*handle);
67        let mut ids = rb.ids;
68        let changes = rb.changes;
69        let activation = rb.activation;
70
71        {
72            if rb.is_enabled() {
73                // The body's status changed. We need to make sure
74                // it is on the correct active set.
75                if let Some(islands) = islands.as_deref_mut() {
76                    // Push the body to the active set if it is not inside the active set yet, and
77                    // is not longer sleeping or became dynamic.
78                    if (changes.contains(RigidBodyChanges::SLEEP) || changes.contains(RigidBodyChanges::TYPE))
79                        && rb.is_enabled()
80                        && !rb.activation.sleeping // May happen if the body was put to sleep manually.
81                        && rb.is_dynamic_or_kinematic() // Only dynamic bodies are in the active dynamic set.
82                        && islands.active_set.get(ids.active_set_id) != Some(handle)
83                    {
84                        ids.active_set_id = islands.active_set.len(); // This will handle the case where the activation_channel contains duplicates.
85                        islands.active_set.push(*handle);
86                    }
87                }
88            }
89
90            // Update the colliders' positions.
91            if changes.contains(RigidBodyChanges::POSITION)
92                || changes.contains(RigidBodyChanges::COLLIDERS)
93            {
94                rb.colliders
95                    .update_positions(colliders, modified_colliders, &rb.pos.position);
96            }
97
98            if changes.contains(RigidBodyChanges::DOMINANCE)
99                || changes.contains(RigidBodyChanges::TYPE)
100            {
101                for handle in rb.colliders.0.iter() {
102                    // NOTE: we can’t just use `colliders.get_mut_internal_with_modification_tracking`
103                    // here because that would modify the `modified_colliders` inside of the `ColliderSet`
104                    // instead of the one passed to this method.
105                    let co = colliders.index_mut_internal(*handle);
106                    modified_colliders.push_once(*handle, co);
107                    co.changes |= ColliderChanges::PARENT_EFFECTIVE_DOMINANCE;
108                }
109            }
110
111            if changes.contains(RigidBodyChanges::ENABLED_OR_DISABLED) {
112                // Propagate the rigid-body’s enabled/disable status to its colliders.
113                for handle in rb.colliders.0.iter() {
114                    // NOTE: we can’t just use `colliders.get_mut_internal_with_modification_tracking`
115                    // here because that would modify the `modified_colliders` inside of the `ColliderSet`
116                    // instead of the one passed to this method.
117                    let co = colliders.index_mut_internal(*handle);
118                    modified_colliders.push_once(*handle, co);
119
120                    if rb.enabled && co.flags.enabled == ColliderEnabled::DisabledByParent {
121                        co.flags.enabled = ColliderEnabled::Enabled;
122                    } else if !rb.enabled && co.flags.enabled == ColliderEnabled::Enabled {
123                        co.flags.enabled = ColliderEnabled::DisabledByParent;
124                    }
125
126                    co.changes |= ColliderChanges::ENABLED_OR_DISABLED;
127                }
128
129                // Propagate the rigid-body’s enabled/disable status to its attached impulse joints.
130                impulse_joints.map_attached_joints_mut(*handle, |_, _, _, joint| {
131                    if rb.enabled && joint.data.enabled == JointEnabled::DisabledByAttachedBody {
132                        joint.data.enabled = JointEnabled::Enabled;
133                    } else if !rb.enabled && joint.data.enabled == JointEnabled::Enabled {
134                        joint.data.enabled = JointEnabled::DisabledByAttachedBody;
135                    }
136                });
137
138                // FIXME: Propagate the rigid-body’s enabled/disable status to its attached multibody joints.
139
140                // Remove the rigid-body from the island manager.
141                if !rb.enabled {
142                    final_action = Some(FinalAction::RemoveFromIsland);
143                }
144            }
145
146            // NOTE: recompute the mass-properties AFTER dealing with the rigid-body changes
147            //       that imply a collider change (in particular, after propagation of the
148            //       enabled/disabled status).
149            if changes
150                .intersects(RigidBodyChanges::LOCAL_MASS_PROPERTIES | RigidBodyChanges::COLLIDERS)
151            {
152                rb.mprops.recompute_mass_properties_from_colliders(
153                    colliders,
154                    &rb.colliders,
155                    rb.body_type,
156                    &rb.pos.position,
157                );
158            }
159
160            rb.ids = ids;
161            rb.activation = activation;
162        }
163
164        // Adjust some ids, if needed.
165        if let Some(islands) = islands.as_deref_mut() {
166            if let Some(action) = final_action {
167                match action {
168                    FinalAction::RemoveFromIsland => {
169                        let ids = rb.ids;
170                        islands.rigid_body_removed(*handle, &ids, bodies);
171                    }
172                };
173            }
174        }
175    }
176}