aboutsummaryrefslogtreecommitdiff
path: root/src/dynamics/island_set.rs
blob: 71dc9eb67390c5e33b9cedcdb30b9205e2d972df (plain)
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
use crate::data::Coarena;
use crate::dynamics::{RigidBody, RigidBodyHandle, RigidBodySet};
use crate::geometry::{ColliderSet, NarrowPhase};
use crate::utils;
use std::collections::VecDeque;

#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct Island {
    bodies: Vec<RigidBodyHandle>,
}

impl Island {
    pub fn new() -> Self {
        Self { bodies: vec![] }
    }

    pub fn len(&self) -> usize {
        self.bodies.len()
    }

    pub fn bodies(&self) -> &[RigidBodyHandle] {
        &self.bodies
    }
}

#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct IslandSet {
    // We can't store this in the rigid-bodies because that would
    // cause borrowing issues during the traversal.
    traversal_body_timestamps: Coarena<u64>,
    islands: Vec<Island>,
    active_island: usize,
    islands_to_extract: VecDeque<RigidBodyHandle>,
    islands_extraction_queue: Vec<RigidBodyHandle>,
    // NOTE: this value must never be 0, otherwise some
    // invariants used during the traversal can break.
    traversal_timestamp: u64,
}

impl IslandSet {
    pub fn new() -> Self {
        IslandSet {
            traversal_body_timestamps: Coarena::new(),
            islands: vec![Island::new()],
            active_island: 0,
            islands_to_extract: VecDeque::new(),
            islands_extraction_queue: vec![],
            traversal_timestamp: 1,
        }
    }

    pub fn num_active_islands(&self) -> usize {
        1
    }

    pub fn is_island_sleeping(&self, island_id: usize) -> bool {
        island_id != self.active_island
    }

    pub fn active_bodies(&self) -> &[RigidBodyHandle] {
        &self.islands[self.active_island].bodies
    }

    pub fn incremental_update(&mut self, narrow_phase: &NarrowPhase) {}

    pub fn add_rigid_body(&mut self, handle: RigidBodyHandle, body: &mut RigidBody) {
        assert_eq!(body.island_id, crate::INVALID_USIZE);

        if !body.is_dynamic() {
            return;
        }

        self.traversal_body_timestamps
            .ensure_element_exists(handle.0, 0);

        if body.can_sleep() {
            body.island_id = self.islands.len();
            body.island_offset = 0;
            self.islands.push(Island {
                bodies: vec![handle],
            })
        } else {
            let mut active_island = &mut self.islands[self.active_island];
            body.island_id = self.active_island;
            body.island_offset = active_island.bodies.len();
            active_island.bodies.push(handle);
        }
    }

    pub fn contact_started(
        &mut self,
        bodies: &mut RigidBodySet,
        mut h1: RigidBodyHandle,
        mut h2: RigidBodyHandle,
    ) {
        let island1 = bodies[h1].island_id;
        let island2 = bodies[h2].island_id;

        self.wake_up_island(bodies, island1);
        self.wake_up_island(bodies, island2);
    }

    pub fn body_sleep_state_changed(&mut self, bodies: &mut RigidBodySet, handle: RigidBodyHandle) {
        let body = &mut bodies[handle];
        let island_id = body.island_id;

        if island_id == crate::INVALID_USIZE {
            self.add_rigid_body(handle, body);
        } else if island_id == self.active_island && body.can_sleep() {
            // The body is sleeping now.
            self.islands_to_extract.push_back(handle);
        } else if island_id != self.active_island && !body.can_sleep() {
            // The body is awake now.
            self.wake_up_island(bodies, island_id);
        }
    }

    #[inline(always)]
    fn push_contacting_bodies(
        handle: RigidBodyHandle,
        bodies: &mut RigidBodySet,
        colliders: &ColliderSet,
        narrow_phase: &NarrowPhase,
        queue: &mut Vec<RigidBodyHandle>,
        traversal_body_timestamps: &mut Coarena<u64>,
        first_traversal_timestamp: u64,
        traversal_timestamp: u64,
    ) -> bool {
        for collider_handle in &bodies[handle].colliders {
            if let Some(contacts) = narrow_phase.contacts_with(*collider_handle) {
                for inter in contacts {
                    let other = crate::utils::select_other((inter.0, inter.1), *collider_handle);
                    let other_body_handle = colliders[other].parent;
                    let other_body = &bodies[other_body_handle];

                    if other_body.is_dynamic() {
                        if !other_body.can_sleep() {
                            return false;
                        }

                        let other_body_timestamp =
                            &mut traversal_body_timestamps[other_body_handle.0];

                        if *other_body_timestamp >= first_traversal_timestamp
                            && *other_body_timestamp < traversal_timestamp
                        {
                            // We already saw this body during another traversal this frame.
                            // So we don't need to continue any further.
                            return false;
                        }

                        if *other_body_timestamp != traversal_timestamp {
                            *other_body_timestamp = traversal_timestamp;
                            queue.push(other_body_handle);
                        }
                    }
                }
            }
        }

        true
    }

    pub fn update_sleeping_islands(
        &mut self,
        bodies: &mut RigidBodySet,
        colliders: &mut ColliderSet,
        narrow_phase: &NarrowPhase,
    ) {
        let first_traversal_timestamp = self.traversal_timestamp + 1;
        let mut island_found = false;

        while let Some(handle) = self.islands_to_extract.pop_front() {
            self.traversal_timestamp += 1;
            island_found = self.extract_sleeping_island(
                bodies,
                colliders,
                narrow_phase,
                handle,
                first_traversal_timestamp,
            ) || island_found;

            // Make sure our `traversal_timestamp` remains correct
            // even if it overflows (can happen in very long-running
            // simulations).
            if self.traversal_timestamp == u64::MAX - 1 {
                // Stop the work now because the overflowing timestamp
                // will cause issues with the traversal. Forcibly reset all
                // the timestamps and continue next frame.
                for body in bodies.iter_mut_internal() {
                    body.1.traversal_timestamp = 0;
                }
                self.traversal_timestamp = 1;
                break;
            }
        }

        if island_found {
            // Now we need to remove from the active set all the bodies
            // we moved to a sleeping island.
            let mut i = 0;
            let mut new_len = 0;
            let active_island = &mut self.islands[self.active_island];

            while i < active_island.bodies.len() {
                let handle = active_island.bodies[i];
                let body = &mut bodies[handle];

                if body.island_id == self.active_island {
                    // This body still belongs to this island.
                    // Update its offset.
                    body.island_offset = new_len;
                    active_island.bodies[new_len] = handle;
                    new_len += 1;
                }

                i += 1;
            }

            active_island.bodies.truncate(new_len);
        }
    }

    fn extract_sleeping_island(
        &mut self,
        bodies: &mut RigidBodySet,
        colliders: &mut ColliderSet,
        narrow_phase: &NarrowPhase,
        handle: RigidBodyHandle,
        first_traversal_timestamp: u64,
    ) -> bool {
        // Attempt to extract a sleeping island by traversing the
        // contact graph starting with the given rigid-body.
        if let Some(body) = bodies.get(handle) {
            if body.is_dynamic() && body.can_sleep() {
                // Perform a breadth-first search of the contact graph starting
                // with this body. We stop the search when an active body is
                // found (meaning that the island cannot sleep), or if we
                // extracted the whole island.
                // We do a breadth-first search in order to increase our chances
                // to find a non-sleeping body quickly: if this body just started
                // sleeping, chances are that a non-sleeping body is close.
                self.islands_extraction_queue.clear();
                self.islands_extraction_queue.push