rapier3d/dynamics/soft_body/soft_body_set/
soft_body_set_clusters.rs1use super::soft_body_set_proxies::spawn_proxy;
3use super::{SoftBodyIslandEvent, SoftBodySet};
4use crate::alloc_prelude::*;
5use crate::dynamics::soft_body::{SoftBodyCluster, SoftBodyHandle, SoftClusterRemoval};
6use crate::dynamics::{
7 ImpulseJointSet, IslandManager, MultibodyJointSet, RigidBodyHandle, RigidBodySet,
8};
9use crate::geometry::ColliderSet;
10use crate::math::Rotation;
11
12impl SoftBodySet {
13 pub fn add_cluster(
17 &mut self,
18 handle: SoftBodyHandle,
19 particles: &[u32],
20 bodies: &mut RigidBodySet,
21 colliders: &mut ColliderSet,
22 ) -> Option<u32> {
23 let sb = self.bodies.get_mut(handle.0)?;
24 let n = sb.particles.len() as u32;
25 let mut list: Vec<u32> = particles.iter().copied().filter(|&v| v < n).collect();
26 list.sort_unstable();
27 list.dedup();
28 if list.is_empty() {
29 return None;
30 }
31 let index = sb.clusters.len() as u32;
32 let proxy = spawn_proxy(&sb.particle_settings, sb.user_data, handle, index, bodies);
33 for &v in &list {
34 sb.cluster_refs[v as usize] += 1;
35 }
36 let cell = sb.matching_cell(&list);
37 sb.clusters.push(SoftBodyCluster {
38 particles: list,
39 proxy,
40 meshes: Vec::new(),
41 rotation: Rotation::IDENTITY,
42 cell,
43 shape_matching: false,
44 shape_matching_target: None,
45 prev_shape_matching_target: None,
46 last_gather: Default::default(),
47 shape_impulses: Vec::new(),
48 });
49 sb.modified = true;
50 Self::update_cluster_proxies(sb, bodies, colliders);
53 self.island_events.push(SoftBodyIslandEvent { handle });
54 Some(index)
55 }
56
57 #[allow(clippy::too_many_arguments)]
61 pub fn remove_cluster(
62 &mut self,
63 handle: SoftBodyHandle,
64 cluster: u32,
65 islands: &mut IslandManager,
66 bodies: &mut RigidBodySet,
67 colliders: &mut ColliderSet,
68 impulse_joints: &mut ImpulseJointSet,
69 multibody_joints: &mut MultibodyJointSet,
70 ) -> Option<SoftClusterRemoval> {
71 let (counts, proxy) = self.dissolve_cluster(handle, cluster, islands, bodies, colliders)?;
72 bodies.remove(
75 proxy,
76 islands,
77 colliders,
78 impulse_joints,
79 multibody_joints,
80 self,
81 true,
82 );
83 Some(counts)
84 }
85
86 pub(crate) fn on_proxy_removed(
90 &mut self,
91 handle: SoftBodyHandle,
92 cluster: u32,
93 islands: &mut IslandManager,
94 bodies: &mut RigidBodySet,
95 colliders: &mut ColliderSet,
96 ) {
97 let _ = self.dissolve_cluster(handle, cluster, islands, bodies, colliders);
98 }
99
100 fn dissolve_cluster(
105 &mut self,
106 handle: SoftBodyHandle,
107 cluster: u32,
108 islands: &mut IslandManager,
109 bodies: &mut RigidBodySet,
110 colliders: &mut ColliderSet,
111 ) -> Option<(SoftClusterRemoval, RigidBodyHandle)> {
112 let (mut counts, proxy, root, last) = {
115 let sb = self.bodies.get_mut(handle.0)?;
116 let c = sb.clusters.get_mut(cluster as usize)?;
117 if !c.is_live() {
118 return None;
119 }
120 let (particles, proxy) = c.tombstone();
121
122 let mut dead = alloc::vec![false; sb.particles.len()];
124 for &v in &particles {
125 if let Some(r) = sb.cluster_refs.get_mut(v as usize) {
126 *r = r.saturating_sub(1);
127 if *r == 0 {
128 dead[v as usize] = true;
129 }
130 }
131 }
132 let (counts, _) = sb.remove_dead_particles(&dead);
133
134 if sb.root_body == proxy {
136 let next_root = sb
137 .live_clusters()
138 .next()
139 .map(|(_, c)| c.proxy)
140 .unwrap_or(RigidBodyHandle::invalid());
141 sb.root_body = next_root;
142 }
143 let last = sb.num_live_clusters() == 0;
144 (counts, proxy, sb.root_body, last)
145 };
146 counts.soft_body_removed = last;
147
148 if last {
149 let sb = self.bodies.remove(handle.0).unwrap();
151 islands.persistent.unlink_soft_body_attachments(handle);
152 islands.persistent.unlink_soft_body_proxy_chain(handle);
153 self.attached_to_stale |= !sb.attachments.is_empty();
154 return Some((counts, proxy));
155 }
156
157 if counts.particles > 0 {
158 Self::update_colliders(&self.bodies[handle.0], bodies, colliders, true);
160 }
161 self.attached_to_stale |= counts.attachments > 0;
162 self.island_events.push(SoftBodyIslandEvent { handle });
163 if let Some(rb) = bodies.get_mut(root) {
164 rb.wake_up(true);
165 }
166 Some((counts, proxy))
167 }
168}