aboutsummaryrefslogtreecommitdiff
path: root/src/dynamics/rigid_body_set.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/dynamics/rigid_body_set.rs')
-rw-r--r--src/dynamics/rigid_body_set.rs160
1 files changed, 122 insertions, 38 deletions
diff --git a/src/dynamics/rigid_body_set.rs b/src/dynamics/rigid_body_set.rs
index 99d6f10..83f1c51 100644
--- a/src/dynamics/rigid_body_set.rs
+++ b/src/dynamics/rigid_body_set.rs
@@ -2,8 +2,8 @@
use rayon::prelude::*;
use crate::data::arena::Arena;
-use crate::dynamics::{Joint, RigidBody};
-use crate::geometry::{ColliderSet, ContactPair, InteractionGraph};
+use crate::dynamics::{BodyStatus, Joint, JointSet, RigidBody};
+use crate::geometry::{ColliderHandle, ColliderSet, ContactPair, InteractionGraph};
use crossbeam::channel::{Receiver, Sender};
use std::ops::{Deref, DerefMut, Index, IndexMut};
@@ -128,9 +128,23 @@ impl RigidBodySet {
pub(crate) fn activate(&mut self, handle: RigidBodyHandle) {
let mut rb = &mut self.bodies[handle];
- if self.active_dynamic_set.get(rb.active_set_id) != Some(&handle) {
- rb.active_set_id = self.active_dynamic_set.len();
- self.active_dynamic_set.push(handle);
+ match rb.body_status {
+ // XXX: this case should only concern the dynamic bodies.
+ // For static bodies we should use the modified_inactive_set, or something
+ // similar. Right now we do this for static bodies as well so the broad-phase
+ // takes them into account the first time they are inserted.
+ BodyStatus::Dynamic | BodyStatus::Static => {
+ if self.active_dynamic_set.get(rb.active_set_id) != Some(&handle) {
+ rb.active_set_id = self.active_dynamic_set.len();
+ self.active_dynamic_set.push(handle);
+ }
+ }
+ BodyStatus::Kinematic => {
+ if self.active_kinematic_set.get(rb.active_set_id) != Some(&handle) {
+ rb.active_set_id = self.active_kinematic_set.len();
+ self.active_kinematic_set.push(handle);
+ }
+ }
}
}
@@ -143,13 +157,14 @@ impl RigidBodySet {
pub fn insert(&mut self, rb: RigidBody) -> RigidBodyHandle {
let handle = self.bodies.insert(rb);
let rb = &mut self.bodies[handle];
- rb.active_set_id = self.active_dynamic_set.len();
if !rb.is_sleeping() && rb.is_dynamic() {
+ rb.active_set_id = self.active_dynamic_set.len();
self.active_dynamic_set.push(handle);
}
if rb.is_kinematic() {
+ rb.active_set_id = self.active_kinematic_set.len();
self.active_kinematic_set.push(handle);
}
@@ -160,29 +175,57 @@ impl RigidBodySet {
handle
}
- pub(crate) fn num_islands(&self) -> usize {
- self.active_islands.len() - 1
- }
-
- pub(crate) fn remove_internal(&mut self, handle: RigidBodyHandle) -> Option<RigidBody> {
+ /// Removes a rigid-body, and all its attached colliders and joints, from these sets.
+ pub fn remove(
+ &mut self,
+ handle: RigidBodyHandle,
+ colliders: &mut ColliderSet,
+ joints: &mut JointSet,
+ ) -> Option<RigidBody> {
let rb = self.bodies.remove(handle)?;
- // Remove this body from the active dynamic set.
- if self.active_dynamic_set.get(rb.active_set_id) == Some(&handle) {
- self.active_dynamic_set.swap_remove(rb.active_set_id);
+ /*
+ * Update active sets.
+ */
+ let mut active_sets = [&mut self.active_kinematic_set, &mut self.active_dynamic_set];
+
+ for active_set in &mut active_sets {
+ if active_set.get(rb.active_set_id) == Some(&handle) {
+ active_set.swap_remove(rb.active_set_id);
- if let Some(replacement) = self.active_dynamic_set.get(rb.active_set_id) {
- self.bodies[*replacement].active_set_id = rb.active_set_id;
+ if let Some(replacement) = active_set.get(rb.active_set_id) {
+ self.bodies[*replacement].active_set_id = rb.active_set_id;
+ }
}
}
+ /*
+ * Remove colliders attached to this rigid-body.
+ */
+ for collider in &rb.colliders {
+ colliders.remove(*collider, self);
+ }
+
+ /*
+ * Remove joints attached to this rigid-body.
+ */
+ joints.remove_rigid_body(rb.joint_graph_index, self);
+
Some(rb)
}
+ pub(crate) fn num_islands(&self) -> usize {
+ self.active_islands.len() - 1
+ }
+
/// Forces the specified rigid-body to wake up if it is dynamic.
- pub fn wake_up(&mut self, handle: RigidBodyHandle) {
+ ///
+ /// If `strong` is `true` then it is assured that the rigid-body will
+ /// remain awake during multiple subsequent timesteps.
+ pub fn wake_up(&mut self, handle: RigidBodyHandle, strong: bool) {
if let Some(rb) = self.bodies.get_mut(handle) {
+ // TODO: what about kinematic bodies?
if rb.is_dynamic() {
- rb.wake_up();
+ rb.wake_up(strong);
if self.active_dynamic_set.get(rb.active_set_id) != Some(&handle) {
rb.active_set_id = self.active_dynamic_set.len();
@@ -214,8 +257,11 @@ impl RigidBodySet {
///
/// Using this is discouraged in favor of `self.get_mut(handle)` which does not
/// suffer form the ABA problem.
- pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(&mut RigidBody, RigidBodyHandle)> {
- self.bodies.get_unknown_gen_mut(i)
+ pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(RigidBodyMut, RigidBodyHandle)> {
+ let sender = &self.activation_channel.0;
+ self.bodies
+ .get_unknown_gen_mut(i)
+ .map(|(rb, handle)| (RigidBodyMut::new(handle, rb, sender), handle))
}
/// Gets the rigid-body with the given handle.
@@ -256,6 +302,16 @@ impl RigidBodySet {
.map(move |(h, rb)| (h, RigidBodyMut::new(h, rb, sender)))
}
+ /// Iter through all the active kinematic rigid-bodies on this set.
+ pub fn iter_active_kinematic<'a>(
+ &'a self,
+ ) -> impl Iterator<Item = (RigidBodyHandle, &'a RigidBody)> {
+ let bodies: &'a _ = &self.bodies;
+ self.active_kinematic_set
+ .iter()
+ .filter_map(move |h| Some((*h, bodies.get(*h)?)))
+ }
+
/// Iter through all the active dynamic rigid-bodies on this set.
pub fn iter_active_dynamic<'a>(
&'a self,
@@ -425,6 +481,45 @@ impl RigidBodySet {
}
}
+ // Read all the contacts and push objects touching touching this rigid-body.
+ #[inline(always)]
+ fn push_contacting_colliders(
+ rb: &RigidBody,
+ colliders: &ColliderSet,
+ contact_graph: &InteractionGraph<ContactPair>,
+ stack: &mut Vec<ColliderHandle>,
+ ) {
+ for collider_handle in &rb.colliders {
+ let collider = &colliders[*collider_handle];
+
+ for inter in contact_graph.interactions_with(collider.contact_graph_index) {
+ for manifold in &inter.2.manifolds {
+ if manifold.num_active_contacts() > 0 {
+ let other =
+ crate::utils::other_handle((inter.0, inter.1), *collider_handle);
+ let other_body = colliders[other].parent;
+ stack.push(other_body);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Now iterate on all active kinematic bodies and push all the bodies
+ // touching them to the stack so they can be woken up.
+ for h in self.active_kinematic_set.iter() {
+ let rb = &self.bodies[*h];
+
+ if !rb.is_moving() {
+ // If the kinematic body does not move, it does not have
+ // to wake up any dynamic body.
+ continue;
+ }
+
+ push_contacting_colliders(rb, colliders, contact_graph, &mut self.stack);
+ }
+
// println!("Selection: {}", instant::now() - t);
// let t = instant::now();
@@ -443,7 +538,9 @@ impl RigidBodySet {
// We already visited this body and its neighbors.
// Also, we don't propagate awake state through static bodies.
continue;
- } else if self.stack.len() < island_marker {
+ }
+
+ if self.stack.len() < island_marker {
if self.active_dynamic_set.len() - *self.active_islands.last().unwrap()
>= min_island_size
{
@@ -454,29 +551,16 @@ impl RigidBodySet {
island_marker = self.stack.len();
}
- rb.wake_up();
+ rb.wake_up(false);
rb.active_island_id = self.active_islands.len() - 1;
rb.active_set_id = self.active_dynamic_set.len();
rb.active_set_offset = rb.active_set_id - self.active_islands[rb.active_island_id];
rb.active_set_timestamp = self.active_set_timestamp;
self.active_dynamic_set.push(handle);
- // Read all the contacts and push objects touching this one.
- for collider_handle in &rb.colliders {
- let collider = &colliders[*collider_handle];
-
- for inter in contact_graph.interactions_with(collider.contact_graph_index) {
- for manifold in &inter.2.manifolds {
- if manifold.num_active_contacts() > 0 {
- let other =
- crate::utils::other_handle((inter.0, inter.1), *collider_handle);
- let other_body = colliders[other].parent;
- self.stack.push(other_body);
- break;
- }
- }
- }
- }
+ // Transmit the active state to all the rigid-bodies with colliders
+ // in contact or joined with this collider.
+ push_contacting_colliders(rb, colliders, contact_graph, &mut self.stack);
for inter in joint_graph.interactions_with(rb.joint_graph_index) {
let other = crate::utils::other_handle((inter.0, inter.1), handle);