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        {
67            let rb = bodies.index_mut_internal(*handle);
68            let changes = rb.changes;
69            let activation = rb.activation;
70
71            if rb.is_enabled() {
72                // The body's status changed. We need to make sure
73                // it is on the correct active set.
74                if let Some(islands) = islands.as_deref_mut() {
75                    islands.rigid_body_updated(*handle, bodies);
76                }
77            }
78
79            let rb = bodies.index_mut_internal(*handle);
80
81            // Update the colliders' positions.
82            if changes.contains(RigidBodyChanges::POSITION)
83                || changes.contains(RigidBodyChanges::COLLIDERS)
84            {
85                rb.colliders
86                    .update_positions(colliders, modified_colliders, &rb.pos.position);
87            }
88
89            if changes.contains(RigidBodyChanges::DOMINANCE)
90                || changes.contains(RigidBodyChanges::TYPE)
91            {
92                for handle in rb.colliders.0.iter() {
93                    // NOTE: we can’t just use `colliders.get_mut_internal_with_modification_tracking`
94                    // here because that would modify the `modified_colliders` inside of the `ColliderSet`
95                    // instead of the one passed to this method.
96                    let co = colliders.index_mut_internal(*handle);
97                    modified_colliders.push_once(*handle, co);
98                    co.changes |= ColliderChanges::PARENT_EFFECTIVE_DOMINANCE;
99                }
100            }
101
102            if changes.contains(RigidBodyChanges::ENABLED_OR_DISABLED) {
103                // Propagate the rigid-body’s enabled/disable status to its colliders.
104                for handle in rb.colliders.0.iter() {
105                    // NOTE: we can’t just use `colliders.get_mut_internal_with_modification_tracking`
106                    // here because that would modify the `modified_colliders` inside of the `ColliderSet`
107                    // instead of the one passed to this method.
108                    let co = colliders.index_mut_internal(*handle);
109                    modified_colliders.push_once(*handle, co);
110
111                    if rb.enabled && co.flags.enabled == ColliderEnabled::DisabledByParent {
112                        co.flags.enabled = ColliderEnabled::Enabled;
113                    } else if !rb.enabled && co.flags.enabled == ColliderEnabled::Enabled {
114                        co.flags.enabled = ColliderEnabled::DisabledByParent;
115                    }
116
117                    co.changes |= ColliderChanges::ENABLED_OR_DISABLED;
118                }
119
120                // Propagate the rigid-body’s enabled/disable status to its attached impulse joints.
121                impulse_joints.map_attached_joints_mut(*handle, |_, _, _, joint| {
122                    if rb.enabled && joint.data.enabled == JointEnabled::DisabledByAttachedBody {
123                        joint.data.enabled = JointEnabled::Enabled;
124                    } else if !rb.enabled && joint.data.enabled == JointEnabled::Enabled {
125                        joint.data.enabled = JointEnabled::DisabledByAttachedBody;
126                    }
127                });
128
129                // FIXME: Propagate the rigid-body’s enabled/disable status to its attached multibody joints.
130
131                // Remove the rigid-body from the island manager.
132                if !rb.enabled {
133                    final_action = Some(FinalAction::RemoveFromIsland);
134                }
135            }
136
137            // NOTE: recompute the mass-properties AFTER dealing with the rigid-body changes
138            //       that imply a collider change (in particular, after propagation of the
139            //       enabled/disabled status).
140            if changes
141                .intersects(RigidBodyChanges::LOCAL_MASS_PROPERTIES | RigidBodyChanges::COLLIDERS)
142            {
143                rb.mprops.recompute_mass_properties_from_colliders(
144                    colliders,
145                    &rb.colliders,
146                    rb.body_type,
147                    &rb.pos.position,
148                );
149            }
150
151            rb.activation = activation;
152        }
153
154        // Adjust some ids, if needed.
155        if let Some(islands) = islands.as_deref_mut() {
156            if let Some(action) = final_action {
157                match action {
158                    FinalAction::RemoveFromIsland => {
159                        let rb = bodies.index_mut_internal(*handle);
160                        let ids = rb.ids;
161                        islands.rigid_body_removed_or_disabled(*handle, &ids, bodies);
162                    }
163                };
164            }
165        }
166    }
167}