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