fyrox_impl/scene/dim2/
physics.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Scene physics module.
22
23use super::collider::GeometrySource;
24use crate::{
25    core::{
26        algebra::{
27            Isometry2, Isometry3, Matrix4, Point2, Rotation3, Translation2, Translation3,
28            UnitComplex, UnitQuaternion, UnitVector2, Vector2, Vector3,
29        },
30        arrayvec::ArrayVec,
31        instant,
32        log::{Log, MessageKind},
33        math::Matrix4Ext,
34        parking_lot::Mutex,
35        pool::Handle,
36        reflect::prelude::*,
37        variable::{InheritableVariable, VariableFlags},
38        visitor::prelude::*,
39        BiDirHashMap, ImmutableString, SafeLock,
40    },
41    graph::{BaseSceneGraph, SceneGraphNode},
42    scene::{
43        self,
44        collider::{self},
45        debug::SceneDrawingContext,
46        dim2::{
47            self,
48            collider::{ColliderShape, TileMapShape},
49            joint::{JointLocalFrames, JointMotorParams, JointParams},
50            rigidbody::ApplyAction,
51        },
52        graph::{
53            isometric_global_transform,
54            physics::{FeatureId, IntegrationParameters, PhysicsPerformanceStatistics},
55            Graph, NodePool,
56        },
57        node::{Node, NodeTrait},
58        tilemap::TileMap,
59    },
60};
61pub use rapier2d::geometry::shape::*;
62use rapier2d::parry::query::DefaultQueryDispatcher;
63use rapier2d::{
64    dynamics::{
65        CCDSolver, GenericJoint, GenericJointBuilder, ImpulseJointHandle, ImpulseJointSet,
66        IslandManager, JointAxesMask, JointAxis, MultibodyJointHandle, MultibodyJointSet,
67        RigidBody, RigidBodyActivation, RigidBodyBuilder, RigidBodyHandle, RigidBodySet,
68        RigidBodyType,
69    },
70    geometry::{
71        Collider, ColliderBuilder, ColliderHandle, ColliderSet, Cuboid, DefaultBroadPhase,
72        InteractionGroups, NarrowPhase, Ray, SharedShape,
73    },
74    parry::query::ShapeCastOptions,
75    pipeline::{DebugRenderPipeline, EventHandler, PhysicsPipeline},
76};
77use std::{
78    cmp::Ordering,
79    fmt::{Debug, Formatter},
80    hash::Hash,
81    sync::Arc,
82};
83
84/// A trait for ray cast results storage. It has two implementations: Vec and ArrayVec.
85/// Latter is needed for the cases where you need to avoid runtime memory allocations
86/// and do everything on stack.
87pub trait QueryResultsStorage {
88    /// Pushes new intersection in the storage. Returns true if intersection was
89    /// successfully inserted, false otherwise.
90    fn push(&mut self, intersection: Intersection) -> bool;
91
92    /// Clears the storage.
93    fn clear(&mut self);
94
95    /// Sorts intersections by given compare function.
96    fn sort_intersections_by<C: FnMut(&Intersection, &Intersection) -> Ordering>(&mut self, cmp: C);
97}
98
99impl QueryResultsStorage for Vec<Intersection> {
100    fn push(&mut self, intersection: Intersection) -> bool {
101        self.push(intersection);
102        true
103    }
104
105    fn clear(&mut self) {
106        self.clear()
107    }
108
109    fn sort_intersections_by<C>(&mut self, cmp: C)
110    where
111        C: FnMut(&Intersection, &Intersection) -> Ordering,
112    {
113        self.sort_by(cmp);
114    }
115}
116
117impl<const CAP: usize> QueryResultsStorage for ArrayVec<Intersection, CAP> {
118    fn push(&mut self, intersection: Intersection) -> bool {
119        self.try_push(intersection).is_ok()
120    }
121
122    fn clear(&mut self) {
123        self.clear()
124    }
125
126    fn sort_intersections_by<C>(&mut self, cmp: C)
127    where
128        C: FnMut(&Intersection, &Intersection) -> Ordering,
129    {
130        self.sort_by(cmp);
131    }
132}
133
134/// A ray intersection result.
135#[derive(Debug, Clone, PartialEq)]
136pub struct Intersection {
137    /// A handle of the collider with which intersection was detected.
138    pub collider: Handle<Node>,
139
140    /// A normal at the intersection position.
141    pub normal: Vector2<f32>,
142
143    /// A position of the intersection in world coordinates.
144    pub position: Point2<f32>,
145
146    /// Additional data that contains a kind of the feature with which
147    /// intersection was detected as well as its index.
148    ///
149    /// # Important notes.
150    ///
151    /// FeatureId::Face might have index that is greater than amount of triangles in
152    /// a triangle mesh, this means that intersection was detected from "back" side of
153    /// a face. To "fix" that index, simply subtract amount of triangles of a triangle
154    /// mesh from the value.
155    pub feature: FeatureId,
156
157    /// Distance from the ray origin.
158    pub toi: f32,
159}
160
161/// A set of options for the ray cast.
162pub struct RayCastOptions {
163    /// A ray origin.
164    pub ray_origin: Point2<f32>,
165
166    /// A ray direction. Can be non-normalized.
167    pub ray_direction: Vector2<f32>,
168
169    /// Maximum distance of cast.
170    pub max_len: f32,
171
172    /// Groups to check.
173    pub groups: collider::InteractionGroups,
174
175    /// Whether to sort intersections from closest to farthest.
176    pub sort_results: bool,
177}
178
179/// Data of the contact.
180#[derive(Debug, Clone, PartialEq)]
181pub struct ContactData {
182    /// The contact point in the local-space of the first shape.
183    pub local_p1: Vector2<f32>,
184    /// The contact point in the local-space of the second shape.
185    pub local_p2: Vector2<f32>,
186    /// The distance between the two contact points.
187    pub dist: f32,
188    /// The impulse, along the contact normal, applied by this contact to the first collider's rigid-body.
189    /// The impulse applied to the second collider's rigid-body is given by `-impulse`.
190    pub impulse: f32,
191    /// The friction impulses along the basis orthonormal to the contact normal, applied to the first
192    /// collider's rigid-body.
193    pub tangent_impulse: f32,
194}
195
196/// A contact manifold between two colliders.
197#[derive(Debug, Clone, PartialEq)]
198pub struct ContactManifold {
199    /// The contacts points.
200    pub points: Vec<ContactData>,
201    /// The contact normal of all the contacts of this manifold, expressed in the local space of the first shape.
202    pub local_n1: Vector2<f32>,
203    /// The contact normal of all the contacts of this manifold, expressed in the local space of the second shape.
204    pub local_n2: Vector2<f32>,
205    /// The first rigid-body involved in this contact manifold.
206    pub rigid_body1: Handle<Node>,
207    /// The second rigid-body involved in this contact manifold.
208    pub rigid_body2: Handle<Node>,
209    /// The world-space contact normal shared by all the contact in this contact manifold.
210    pub normal: Vector2<f32>,
211}
212
213/// Contact info for pair of colliders.
214#[derive(Debug, Clone, PartialEq)]
215pub struct ContactPair {
216    /// The first collider involved in the contact pair.
217    pub collider1: Handle<Node>,
218    /// The second collider involved in the contact pair.
219    pub collider2: Handle<Node>,
220    /// The set of contact manifolds between the two colliders.
221    /// All contact manifold contain themselves contact points between the colliders.
222    pub manifolds: Vec<ContactManifold>,
223    /// Is there any active contact in this contact pair?
224    /// When false, this pair may just mean that bounding boxes are touching.
225    pub has_any_active_contact: bool,
226}
227
228impl ContactPair {
229    /// Given the handle of a collider that is expected to be part of the collision,
230    /// return the other node involved in the collision.
231    /// Often one will have a list of contact pairs for some collider, but that collider
232    /// may be the first member of some pairs and the second member of other pairs.
233    /// This method simplifies determining which objects a collider has collided with.
234    #[inline]
235    pub fn other(&self, subject: Handle<Node>) -> Handle<Node> {
236        if subject == self.collider1 {
237            self.collider2
238        } else {
239            self.collider1
240        }
241    }
242
243    fn from_native(c: &rapier2d::geometry::ContactPair, physics: &PhysicsWorld) -> Option<Self> {
244        Some(ContactPair {
245            collider1: Handle::decode_from_u128(physics.colliders.get(c.collider1)?.user_data),
246            collider2: Handle::decode_from_u128(physics.colliders.get(c.collider2)?.user_data),
247            manifolds: c
248                .manifolds
249                .iter()
250                .filter_map(|m| {
251                    Some(ContactManifold {
252                        points: m
253                            .points
254                            .iter()
255                            .map(|p| ContactData {
256                                local_p1: p.local_p1.coords,
257                                local_p2: p.local_p2.coords,
258                                dist: p.dist,
259                                impulse: p.data.impulse,
260                                tangent_impulse: p.data.tangent_impulse.x,
261                            })
262                            .collect(),
263                        local_n1: m.local_n1,
264                        local_n2: m.local_n2,
265                        rigid_body1: m.data.rigid_body1.and_then(|h| {
266                            physics
267                                .bodies
268                                .get(h)
269                                .map(|b| Handle::decode_from_u128(b.user_data))
270                        })?,
271                        rigid_body2: m.data.rigid_body2.and_then(|h| {
272                            physics
273                                .bodies
274                                .get(h)
275                                .map(|b| Handle::decode_from_u128(b.user_data))
276                        })?,
277                        normal: m.data.normal,
278                    })
279                })
280                .collect(),
281            has_any_active_contact: c.has_any_active_contact,
282        })
283    }
284}
285
286/// Intersection info for pair of colliders.
287#[derive(Debug, Clone, PartialEq)]
288pub struct IntersectionPair {
289    /// The first collider involved in the contact pair.
290    pub collider1: Handle<Node>,
291    /// The second collider involved in the contact pair.
292    pub collider2: Handle<Node>,
293    /// Is there any active contact in this contact pair?
294    /// When false, this pair may just mean that bounding boxes are touching.
295    pub has_any_active_contact: bool,
296}
297
298impl IntersectionPair {
299    /// Given the handle of a collider that is expected to be part of the collision,
300    /// return the other node involved in the collision.
301    /// Often one will have a list of contact pairs for some collider, but that collider
302    /// may be the first member of some pairs and the second member of other pairs.
303    /// This method simplifies determining which objects a collider has collided with.
304    #[inline]
305    pub fn other(&self, subject: Handle<Node>) -> Handle<Node> {
306        if subject == self.collider1 {
307            self.collider2
308        } else {
309            self.collider1
310        }
311    }
312}
313
314pub(super) struct Container<S, A>
315where
316    A: Hash + Eq + Clone,
317{
318    set: S,
319    map: BiDirHashMap<A, Handle<Node>>,
320}
321
322fn convert_joint_params(
323    params: scene::dim2::joint::JointParams,
324    local_frame1: Isometry2<f32>,
325    local_frame2: Isometry2<f32>,
326) -> GenericJoint {
327    let locked_axis = match params {
328        JointParams::BallJoint(_) => JointAxesMask::LOCKED_REVOLUTE_AXES,
329        JointParams::FixedJoint(_) => JointAxesMask::LOCKED_FIXED_AXES,
330        JointParams::PrismaticJoint(_) => JointAxesMask::LOCKED_PRISMATIC_AXES,
331    };
332
333    let mut joint = GenericJointBuilder::new(locked_axis)
334        .local_frame1(local_frame1)
335        .local_frame2(local_frame2)
336        .build();
337
338    match params {
339        scene::dim2::joint::JointParams::BallJoint(v) => {
340            if v.limits_enabled {
341                joint.set_limits(
342                    JointAxis::AngX,
343                    [v.limits_angles.start, v.limits_angles.end],
344                );
345            }
346        }
347        scene::dim2::joint::JointParams::FixedJoint(_) => {}
348        scene::dim2::joint::JointParams::PrismaticJoint(v) => {
349            if v.limits_enabled {
350                joint.set_limits(JointAxis::LinX, [v.limits.start, v.limits.end]);
351            }
352        }
353    }
354
355    joint
356}
357
358fn tile_map_to_collider_shape(
359    tile_map: &GeometrySource,
360    owner_inv_transform: Matrix4<f32>,
361    nodes: &NodePool,
362    collider_name: &ImmutableString,
363) -> Option<SharedShape> {
364    let tile_map = nodes.try_borrow(tile_map.0)?.component_ref::<TileMap>()?;
365
366    let tile_set_resource = tile_map.tile_set()?.data_ref();
367    let tile_set = tile_set_resource.as_loaded_ref()?;
368
369    let tile_scale = tile_map.tile_scale();
370    let global_transform = owner_inv_transform
371        * tile_map.global_transform()
372        * Matrix4::new_nonuniform_scaling(&Vector3::new(-tile_scale.x, tile_scale.y, 1.0));
373
374    let mut vertices = Vec::new();
375    let mut triangles = Vec::new();
376
377    let collider_uuid = tile_set.collider_name_to_uuid(collider_name)?;
378    let tile_data = tile_map.tiles()?.data_ref();
379    let tile_data = tile_data.as_loaded_ref()?;
380    for (position, handle) in tile_data.iter() {
381        let Some(tile_definition) = tile_set.get_tile_data(handle.into()) else {
382            continue;
383        };
384
385        if let Some(collider) = tile_definition.colliders.get(&collider_uuid) {
386            let position = position.cast::<f32>().to_homogeneous();
387            collider.build_collider_shape(
388                &global_transform,
389                position,
390                &mut vertices,
391                &mut triangles,
392            );
393        }
394    }
395
396    SharedShape::trimesh(vertices, triangles).ok()
397}
398
399// Converts descriptor in a shared shape.
400fn collider_shape_into_native_shape(
401    shape: &ColliderShape,
402    owner_inv_transform: Matrix4<f32>,
403    nodes: &NodePool,
404) -> Option<SharedShape> {
405    match shape {
406        ColliderShape::Ball(ball) => Some(SharedShape::ball(ball.radius)),
407        ColliderShape::Cuboid(cuboid) => {
408            Some(SharedShape(Arc::new(Cuboid::new(cuboid.half_extents))))
409        }
410        ColliderShape::Capsule(capsule) => Some(SharedShape::capsule(
411            Point2::from(capsule.begin),
412            Point2::from(capsule.end),
413            capsule.radius,
414        )),
415        ColliderShape::Segment(segment) => Some(SharedShape::segment(
416            Point2::from(segment.begin),
417            Point2::from(segment.end),
418        )),
419        ColliderShape::Triangle(triangle) => Some(SharedShape::triangle(
420            Point2::from(triangle.a),
421            Point2::from(triangle.b),
422            Point2::from(triangle.c),
423        )),
424        ColliderShape::Trimesh(_) => {
425            None // TODO
426        }
427        ColliderShape::Heightfield(_) => {
428            None // TODO
429        }
430        ColliderShape::TileMap(TileMapShape {
431            tile_map,
432            layer_name: collider_layer_name,
433        }) => tile_map_to_collider_shape(tile_map, owner_inv_transform, nodes, collider_layer_name),
434    }
435}
436
437fn isometry2_to_mat4(isometry: &Isometry2<f32>) -> Matrix4<f32> {
438    Isometry3 {
439        rotation: UnitQuaternion::from_euler_angles(0.0, 0.0, isometry.rotation.angle()),
440        translation: Translation3 {
441            vector: Vector3::new(isometry.translation.x, isometry.translation.y, 0.0),
442        },
443    }
444    .to_homogeneous()
445}
446
447/// Physics world is responsible for physics simulation in the engine. There is a very few public
448/// methods, mostly for ray casting. You should add physical entities using scene graph nodes, such
449/// as RigidBody, Collider, Joint.
450#[derive(Visit, Reflect)]
451pub struct PhysicsWorld {
452    /// A flag that defines whether physics simulation is enabled or not.
453    pub enabled: InheritableVariable<bool>,
454
455    /// A set of parameters that define behavior of every rigid body.
456    pub integration_parameters: InheritableVariable<IntegrationParameters>,
457
458    /// Current gravity vector. Default is (0.0, -9.81)
459    pub gravity: InheritableVariable<Vector2<f32>>,
460
461    /// Performance statistics of a single simulation step.
462    #[visit(skip)]
463    #[reflect(hidden)]
464    pub performance_statistics: PhysicsPerformanceStatistics,
465
466    // Current physics pipeline.
467    #[visit(skip)]
468    #[reflect(hidden)]
469    pipeline: PhysicsPipeline,
470    // Broad phase performs rough intersection checks.
471    #[visit(skip)]
472    #[reflect(hidden)]
473    broad_phase: DefaultBroadPhase,
474    // Narrow phase is responsible for precise contact generation.
475    #[visit(skip)]
476    #[reflect(hidden)]
477    narrow_phase: NarrowPhase,
478    // A continuous collision detection solver.
479    #[visit(skip)]
480    #[reflect(hidden)]
481    ccd_solver: CCDSolver,
482    // Structure responsible for maintaining the set of active rigid-bodies, and putting non-moving
483    // rigid-bodies to sleep to save computation times.
484    #[visit(skip)]
485    #[reflect(hidden)]
486    islands: IslandManager,
487    // A container of rigid bodies.
488    #[visit(skip)]
489    #[reflect(hidden)]
490    bodies: RigidBodySet,
491    // A container of colliders.
492    #[visit(skip)]
493    #[reflect(hidden)]
494    pub(crate) colliders: ColliderSet,
495    // A container of impulse joints.
496    #[visit(skip)]
497    #[reflect(hidden)]
498    joints: Container<ImpulseJointSet, ImpulseJointHandle>,
499    // A container of multibody joints.
500    #[visit(skip)]
501    #[reflect(hidden)]
502    multibody_joints: Container<MultibodyJointSet, MultibodyJointHandle>,
503    // Event handler collects info about contacts and proximity events.
504    #[visit(skip)]
505    #[reflect(hidden)]
506    event_handler: Box<dyn EventHandler>,
507    #[visit(skip)]
508    #[reflect(hidden)]
509    debug_render_pipeline: Mutex<DebugRenderPipeline>,
510}
511
512impl Clone for PhysicsWorld {
513    fn clone(&self) -> Self {
514        PhysicsWorld {
515            enabled: self.enabled.clone(),
516            integration_parameters: self.integration_parameters.clone(),
517            gravity: self.gravity.clone(),
518            ..Default::default()
519        }
520    }
521}
522
523fn isometry_from_global_transform(transform: &Matrix4<f32>) -> Isometry2<f32> {
524    Isometry2 {
525        translation: Translation2::new(transform[12], transform[13]),
526        rotation: UnitComplex::from_angle(
527            Rotation3::from_matrix_eps(&transform.basis(), f32::EPSILON, 16, Rotation3::identity())
528                .euler_angles()
529                .2,
530        ),
531    }
532}
533
534fn calculate_local_frames(
535    joint: &dyn NodeTrait,
536    body1: &dyn NodeTrait,
537    body2: &dyn NodeTrait,
538) -> (Isometry2<f32>, Isometry2<f32>) {
539    let joint_isometry = isometry_from_global_transform(&joint.global_transform());
540
541    (
542        joint_isometry * isometry_from_global_transform(&body1.global_transform()).inverse(),
543        joint_isometry * isometry_from_global_transform(&body2.global_transform()).inverse(),
544    )
545}
546
547fn u32_to_group(v: u32) -> rapier2d::geometry::Group {
548    rapier2d::geometry::Group::from_bits(v).unwrap_or_else(rapier2d::geometry::Group::all)
549}
550
551/// A filter tha describes what collider should be included or excluded from a scene query.
552#[derive(Copy, Clone, Default)]
553#[allow(clippy::type_complexity)]
554pub struct QueryFilter<'a> {
555    /// Flags indicating what particular type of colliders should be excluded from the scene query.
556    pub flags: collider::QueryFilterFlags,
557    /// If set, only colliders with collision groups compatible with this one will
558    /// be included in the scene query.
559    pub groups: Option<collider::InteractionGroups>,
560    /// If set, this collider will be excluded from the scene query.
561    pub exclude_collider: Option<Handle<Node>>,
562    /// If set, any collider attached to this rigid-body will be excluded from the scene query.
563    pub exclude_rigid_body: Option<Handle<Node>>,
564    /// If set, any collider for which this closure returns false will be excluded from the scene query.
565    pub predicate: Option<&'a dyn Fn(Handle<Node>, &collider::Collider) -> bool>,
566}
567
568/// The result of a time-of-impact (TOI) computation.
569#[derive(Copy, Clone, Debug)]
570pub struct TOI {
571    /// The time at which the objects touch.
572    pub toi: f32,
573    /// The local-space closest point on the first shape at the time of impact.
574    ///
575    /// Undefined if `status` is `Penetrating`.
576    pub witness1: Point2<f32>,
577    /// The local-space closest point on the second shape at the time of impact.
578    ///
579    /// Undefined if `status` is `Penetrating`.
580    pub witness2: Point2<f32>,
581    /// The local-space outward normal on the first shape at the time of impact.
582    ///
583    /// Undefined if `status` is `Penetrating`.
584    pub normal1: UnitVector2<f32>,
585    /// The local-space outward normal on the second shape at the time of impact.
586    ///
587    /// Undefined if `status` is `Penetrating`.
588    pub normal2: UnitVector2<f32>,
589    /// The way the time-of-impact computation algorithm terminated.
590    pub status: collider::TOIStatus,
591}
592
593impl PhysicsWorld {
594    /// Creates a new instance of the physics world.
595    pub(crate) fn new() -> Self {
596        Self {
597            enabled: true.into(),
598            pipeline: PhysicsPipeline::new(),
599            gravity: Vector2::new(0.0, -9.81).into(),
600            integration_parameters: IntegrationParameters::default().into(),
601            broad_phase: DefaultBroadPhase::new(),
602            narrow_phase: NarrowPhase::new(),
603            ccd_solver: CCDSolver::new(),
604            islands: IslandManager::new(),
605            bodies: RigidBodySet::new(),
606            colliders: ColliderSet::new(),
607            joints: Container {
608                set: ImpulseJointSet::new(),
609                map: Default::default(),
610            },
611            multibody_joints: Container {
612                set: MultibodyJointSet::new(),
613                map: Default::default(),
614            },
615            event_handler: Box::new(()),
616            performance_statistics: Default::default(),
617            debug_render_pipeline: Default::default(),
618        }
619    }
620
621    /// Update the physics pipeline with a timestep of the given length.
622    ///
623    /// * `dt`: The amount of time that has passed since the previous update.
624    ///   This may be overriden by [`PhysicsWorld::integration_parameters`] if
625    ///   `integration_parameters.dt` is `Some`, in which case that value is used
626    ///   instead of this argument.
627    /// * `dt_enabled`: If this is true then `dt` is used as usual, but if this is false
628    ///   then both the `dt` argument and `integration_parameters.dt` are ignored and
629    ///   a `dt` of zero is used instead, freezing all physics. This corresponds to the
630    ///   [`GraphUpdateSwitches::physics_dt`](crate::scene::graph::GraphUpdateSwitches::physics_dt).
631    pub(crate) fn update(&mut self, dt: f32, dt_enabled: bool) {
632        let time = instant::Instant::now();
633        let parameter_dt = self.integration_parameters.dt;
634        let parameter_dt = if parameter_dt == Some(0.0) {
635            None
636        } else {
637            parameter_dt
638        };
639        let dt = if dt_enabled {
640            parameter_dt.unwrap_or(dt)
641        } else {
642            0.0
643        };
644
645        if *self.enabled {
646            let integration_parameters = rapier2d::dynamics::IntegrationParameters {
647                dt,
648                min_ccd_dt: self.integration_parameters.min_ccd_dt,
649                contact_damping_ratio: self.integration_parameters.contact_damping_ratio,
650                contact_natural_frequency: self.integration_parameters.contact_natural_frequency,
651                joint_natural_frequency: self.integration_parameters.joint_natural_frequency,
652                joint_damping_ratio: self.integration_parameters.joint_damping_ratio,
653                warmstart_coefficient: self.integration_parameters.warmstart_coefficient,
654                length_unit: self.integration_parameters.length_unit,
655                normalized_allowed_linear_error: self.integration_parameters.allowed_linear_error,
656                normalized_max_corrective_velocity: self
657                    .integration_parameters
658                    .normalized_max_corrective_velocity,
659                normalized_prediction_distance: self.integration_parameters.prediction_distance,
660                num_solver_iterations: self.integration_parameters.num_solver_iterations,
661                num_internal_pgs_iterations: self
662                    .integration_parameters
663                    .num_internal_pgs_iterations,
664                num_internal_stabilization_iterations: self
665                    .integration_parameters
666                    .num_internal_stabilization_iterations,
667                min_island_size: self.integration_parameters.min_island_size as usize,
668                max_ccd_substeps: self.integration_parameters.max_ccd_substeps as usize,
669            };
670
671            self.pipeline.step(
672                &self.gravity,
673                &integration_parameters,
674                &mut self.islands,
675                &mut self.broad_phase,
676                &mut self.narrow_phase,
677                &mut self.bodies,
678                &mut self.colliders,
679                &mut self.joints.set,
680                &mut self.multibody_joints.set,
681                &mut self.ccd_solver,
682                &(),
683                &*self.event_handler,
684            );
685        }
686
687        self.performance_statistics.step_time += instant::Instant::now() - time;
688    }
689
690    pub(crate) fn add_body(&mut self, owner: Handle<Node>, mut body: RigidBody) -> RigidBodyHandle {
691        body.user_data = owner.encode_to_u128();
692        self.bodies.insert(body)
693    }
694
695    pub(crate) fn remove_body(&mut self, handle: RigidBodyHandle) {
696        self.bodies.remove(
697            handle,
698            &mut self.islands,
699            &mut self.colliders,
700            &mut self.joints.set,
701            &mut self.multibody_joints.set,
702            true,
703        );
704    }
705
706    pub(crate) fn add_collider(
707        &mut self,
708        owner: Handle<Node>,
709        parent_body: RigidBodyHandle,
710        mut collider: Collider,
711    ) -> ColliderHandle {
712        collider.user_data = owner.encode_to_u128();
713        self.colliders
714            .insert_with_parent(collider, parent_body, &mut self.bodies)
715    }
716
717    pub(crate) fn remove_collider(&mut self, handle: ColliderHandle) -> bool {
718        self.colliders
719            .remove(handle, &mut self.islands, &mut self.bodies, false)
720            .is_some()
721    }
722
723    pub(crate) fn add_joint(
724        &mut self,
725        owner: Handle<Node>,
726        body1: RigidBodyHandle,
727        body2: RigidBodyHandle,
728        params: GenericJoint,
729    ) -> ImpulseJointHandle {
730        let handle = self.joints.set.insert(body1, body2, params, false);
731        self.joints.map.insert(handle, owner);
732        handle
733    }
734
735    pub(crate) fn remove_joint(&mut self, handle: ImpulseJointHandle) {
736        if self.joints.set.remove(handle, false).is_some() {
737            assert!(self.joints.map.remove_by_key(&handle).is_some());
738        }
739    }
740
741    /// Draws physics world. Very useful for debugging, it allows you to see where are
742    /// rigid bodies, which colliders they have and so on.
743    pub fn draw(&self, context: &mut SceneDrawingContext) {
744        self.debug_render_pipeline.safe_lock().render(
745            context,
746            &self.bodies,
747            &self.colliders,
748            &self.joints.set,
749            &self.multibody_joints.set,
750            &self.narrow_phase,
751        );
752    }
753
754    /// Casts a ray with given options.
755    pub fn cast_ray<S: QueryResultsStorage>(&self, opts: RayCastOptions, query_buffer: &mut S) {
756        let time = instant::Instant::now();
757
758        let query = self.broad_phase.as_query_pipeline(
759            &DefaultQueryDispatcher,
760            &self.bodies,
761            &self.colliders,
762            rapier2d::pipeline::QueryFilter::new().groups(InteractionGroups::new(
763                u32_to_group(opts.groups.memberships.0),
764                u32_to_group(opts.groups.filter.0),
765            )),
766        );
767
768        query_buffer.clear();
769        let ray = Ray::new(
770            opts.ray_origin,
771            opts.ray_direction
772                .try_normalize(f32::EPSILON)
773                .unwrap_or_default(),
774        );
775        for (_, collider, intersection) in query.intersect_ray(ray, opts.max_len, true) {
776            query_buffer.push(Intersection {
777                collider: Handle::decode_from_u128(collider.user_data),
778                normal: intersection.normal,
779                position: ray.point_at(intersection.time_of_impact),
780                feature: intersection.feature.into(),
781                toi: intersection.time_of_impact,
782            });
783        }
784        if opts.sort_results {
785            query_buffer.sort_intersections_by(|a, b| {
786                if a.toi > b.toi {
787                    Ordering::Greater
788                } else if a.toi < b.toi {
789                    Ordering::Less
790                } else {
791                    Ordering::Equal
792                }
793            })
794        }
795
796        self.performance_statistics.total_ray_cast_time.set(
797            self.performance_statistics.total_ray_cast_time.get()
798                + (instant::Instant::now() - time),
799        );
800    }
801
802    /// Casts a shape at a constant linear velocity and retrieve the first collider it hits.
803    ///
804    /// This is similar to ray-casting except that we are casting a whole shape instead of just a
805    /// point (the ray origin). In the resulting `TOI`, witness and normal 1 refer to the world
806    /// collider, and are in world space.
807    ///
808    /// # Parameters
809    ///
810    /// * `graph` - a reference to the scene graph.
811    /// * `shape` - The shape to cast.
812    /// * `shape_pos` - The initial position of the shape to cast.
813    /// * `shape_vel` - The constant velocity of the shape to cast (i.e. the cast direction).
814    /// * `max_toi` - The maximum time-of-impact that can be reported by this cast. This effectively
815    ///   limits the distance traveled by the shape to `shapeVel.norm() * maxToi`.
816    /// * `stop_at_penetration` - If set to `false`, the linear shape-cast won’t immediately stop if
817    ///   the shape is penetrating another shape at its starting point **and** its trajectory is such
818    ///   that it’s on a path to exist that penetration state.
819    /// * `filter`: set of rules used to determine which collider is taken into account by this scene
820    ///   query.
821    pub fn cast_shape(
822        &self,
823        graph: &Graph,
824        shape: &dyn Shape,
825        shape_pos: &Isometry2<f32>,
826        shape_vel: &Vector2<f32>,
827        max_toi: f32,
828        stop_at_penetration: bool,
829        filter: QueryFilter,
830    ) -> Option<(Handle<Node>, TOI)> {
831        let predicate = |handle: ColliderHandle, _: &Collider| -> bool {
832            if let Some(pred) = filter.predicate {
833                let h = Handle::decode_from_u128(self.colliders.get(handle).unwrap().user_data);
834                pred(
835                    h,
836                    graph.node(h).component_ref::<collider::Collider>().unwrap(),
837                )
838            } else {
839                true
840            }
841        };
842
843        let filter = rapier2d::pipeline::QueryFilter {
844            flags: rapier2d::pipeline::QueryFilterFlags::from_bits(filter.flags.bits()).unwrap(),
845            groups: filter.groups.map(|g| {
846                InteractionGroups::new(u32_to_group(g.memberships.0), u32_to_group(g.filter.0))
847            }),
848            exclude_collider: filter
849                .exclude_collider
850                .and_then(|h| graph.try_get_node(h))
851                .and_then(|n| n.component_ref::<dim2::collider::Collider>())
852                .map(|c| c.native.get()),
853            exclude_rigid_body: filter
854                .exclude_collider
855                .and_then(|h| graph.try_get_node(h))
856                .and_then(|n| n.component_ref::<dim2::rigidbody::RigidBody>())
857                .map(|c| c.native.get()),
858            predicate: Some(&predicate),
859        };
860
861        let query = self.broad_phase.as_query_pipeline(
862            &DefaultQueryDispatcher,
863            &self.bodies,
864            &self.colliders,
865            filter,
866        );
867
868        let opts = ShapeCastOptions {
869            max_time_of_impact: max_toi,
870            target_distance: 0.0,
871            stop_at_penetration,
872            compute_impact_geometry_on_penetration: true,
873        };
874
875        query
876            .cast_shape(shape_pos, shape_vel, shape, opts)
877            .map(|(handle, toi)| {
878                (
879                    Handle::decode_from_u128(self.colliders.get(handle).unwrap().user_data),
880                    TOI {
881                        toi: toi.time_of_impact,
882                        witness1: toi.witness1,
883                        witness2: toi.witness2,
884                        normal1: toi.normal1,
885                        normal2: toi.normal2,
886                        status: toi.status.into(),
887                    },
888                )
889            })
890    }
891
892    pub(crate) fn set_rigid_body_position(
893        &mut self,
894        rigid_body: &scene::dim2::rigidbody::RigidBody,
895        new_global_transform: &Matrix4<f32>,
896    ) {
897        if let Some(native) = self.bodies.get_mut(rigid_body.native.get()) {
898            native.set_position(
899                isometry_from_global_transform(new_global_transform),
900                // Do not wake up body, it is too expensive and must be done **only** by explicit
901                // `wake_up` call!
902                false,
903            );
904        }
905    }
906
907    pub(crate) fn sync_rigid_body_node(
908        &mut self,
909        rigid_body: &mut scene::dim2::rigidbody::RigidBody,
910        parent_transform: Matrix4<f32>,
911    ) {
912        if *self.enabled {
913            if let Some(native) = self.bodies.get(rigid_body.native.get()) {
914                if native.body_type() != RigidBodyType::Fixed {
915                    let local_transform: Matrix4<f32> = parent_transform
916                        .try_inverse()
917                        .unwrap_or_else(Matrix4::identity)
918                        * isometry2_to_mat4(native.position());
919
920                    let new_local_rotation = UnitQuaternion::from_matrix_eps(
921                        &local_transform.basis(),
922                        f32::EPSILON,
923                        16,
924                        UnitQuaternion::identity(),
925                    );
926                    let new_local_position =
927                        Vector3::new(local_transform[12], local_transform[13], 0.0);
928
929                    // Do not touch local transform if position/rotation is not changing. This will
930                    // prevent redundant update of its global transform, which in its turn save some
931                    // CPU cycles.
932                    let local_transform = rigid_body.local_transform();
933                    if **local_transform.position() != new_local_position
934                        || **local_transform.rotation() != new_local_rotation
935                    {
936                        rigid_body
937                            .local_transform_mut()
938                            .set_position(new_local_position)
939                            .set_rotation(new_local_rotation);
940                    }
941
942                    rigid_body
943                        .lin_vel
944                        .set_value_with_flags(*native.linvel(), VariableFlags::MODIFIED);
945                    rigid_body
946                        .ang_vel
947                        .set_value_with_flags(native.angvel(), VariableFlags::MODIFIED);
948                    rigid_body.sleeping = native.is_sleeping();
949                }
950            }
951        }
952    }
953
954    pub(crate) fn sync_to_rigid_body_node(
955        &mut self,
956        handle: Handle<Node>,
957        rigid_body_node: &scene::dim2::rigidbody::RigidBody,
958    ) {
959        if !rigid_body_node.is_globally_enabled() {
960            self.remove_body(rigid_body_node.native.get());
961            rigid_body_node.native.set(Default::default());
962            return;
963        }
964
965        // Important notes!
966        // 1) `get_mut` is **very** expensive because it forces physics engine to recalculate contacts
967        //    and a lot of other stuff, this is why we need `anything_changed` flag.
968        if rigid_body_node.native.get() != RigidBodyHandle::invalid() {
969            let mut actions = rigid_body_node.actions.safe_lock();
970            if rigid_body_node.need_sync_model() || !actions.is_empty() {
971                if let Some(native) = self.bodies.get_mut(rigid_body_node.native.get()) {
972                    // Sync native rigid body's properties with scene node's in case if they
973                    // were changed by user.
974                    rigid_body_node
975                        .body_type
976                        .try_sync_model(|v| native.set_body_type(v.into(), false));
977                    rigid_body_node
978                        .lin_vel
979                        .try_sync_model(|v| native.set_linvel(v, false));
980                    rigid_body_node
981                        .ang_vel
982                        .try_sync_model(|v| native.set_angvel(v, false));
983                    rigid_body_node.mass.try_sync_model(|v| {
984                        native.set_additional_mass(v, true);
985                    });
986                    rigid_body_node
987                        .lin_damping
988                        .try_sync_model(|v| native.set_linear_damping(v));
989                    rigid_body_node
990                        .ang_damping
991                        .try_sync_model(|v| native.set_angular_damping(v));
992                    rigid_body_node
993                        .ccd_enabled
994                        .try_sync_model(|v| native.enable_ccd(v));
995                    rigid_body_node.can_sleep.try_sync_model(|v| {
996                        let activation = native.activation_mut();
997                        if v {
998                            activation.normalized_linear_threshold =
999                                RigidBodyActivation::default_normalized_linear_threshold();
1000                            activation.angular_threshold =
1001                                RigidBodyActivation::default_angular_threshold();
1002                        } else {
1003                            activation.sleeping = false;
1004                            activation.normalized_linear_threshold = -1.0;
1005                            activation.angular_threshold = -1.0;
1006                        };
1007                    });
1008                    rigid_body_node
1009                        .translation_locked
1010                        .try_sync_model(|v| native.lock_translations(v, false));
1011                    rigid_body_node.rotation_locked.try_sync_model(|v| {
1012                        native.set_enabled_rotations(!v, !v, !v, false);
1013                    });
1014                    rigid_body_node
1015                        .dominance
1016                        .try_sync_model(|v| native.set_dominance_group(v));
1017                    rigid_body_node
1018                        .gravity_scale
1019                        .try_sync_model(|v| native.set_gravity_scale(v, false));
1020
1021                    // We must reset any forces applied at previous update step, otherwise physics engine
1022                    // will keep pushing the rigid body infinitely.
1023                    if rigid_body_node.reset_forces.replace(false) {
1024                        native.reset_forces(false);
1025                        native.reset_torques(false);
1026                    }
1027
1028                    while let Some(action) = actions.pop_front() {
1029                        match action {
1030                            ApplyAction::Force(force) => {
1031                                native.add_force(force, false);
1032                                rigid_body_node.reset_forces.set(true);
1033                            }
1034                            ApplyAction::Torque(torque) => {
1035                                native.add_torque(torque, false);
1036                                rigid_body_node.reset_forces.set(true);
1037                            }
1038                            ApplyAction::ForceAtPoint { force, point } => {
1039                                native.add_force_at_point(force, Point2::from(point), false);
1040                                rigid_body_node.reset_forces.set(true);
1041                            }
1042                            ApplyAction::Impulse(impulse) => native.apply_impulse(impulse, false),
1043                            ApplyAction::TorqueImpulse(impulse) => {
1044                                native.apply_torque_impulse(impulse, false)
1045                            }
1046                            ApplyAction::ImpulseAtPoint { impulse, point } => {
1047                                native.apply_impulse_at_point(impulse, Point2::from(point), false)
1048                            }
1049                            ApplyAction::WakeUp => native.wake_up(true),
1050                            ApplyAction::NextTranslation(position) => {
1051                                native.set_next_kinematic_translation(position)
1052                            }
1053                            ApplyAction::NextRotation(rotation) => {
1054                                native.set_next_kinematic_rotation(rotation)
1055                            }
1056                            ApplyAction::NextPosition(position) => {
1057                                native.set_next_kinematic_position(position)
1058                            }
1059                        }
1060                    }
1061                }
1062            }
1063        } else {
1064            let mut builder = RigidBodyBuilder::new(rigid_body_node.body_type().into())
1065                .pose(isometry_from_global_transform(
1066                    &rigid_body_node.global_transform(),
1067                ))
1068                .ccd_enabled(rigid_body_node.is_ccd_enabled())
1069                .additional_mass(rigid_body_node.mass())
1070                .angvel(*rigid_body_node.ang_vel)
1071                .linvel(*rigid_body_node.lin_vel)
1072                .linear_damping(*rigid_body_node.lin_damping)
1073                .angular_damping(*rigid_body_node.ang_damping)
1074                .can_sleep(rigid_body_node.is_can_sleep())
1075                .sleeping(rigid_body_node.is_sleeping())
1076                .dominance_group(rigid_body_node.dominance())
1077                .gravity_scale(rigid_body_node.gravity_scale());
1078
1079            if rigid_body_node.is_translation_locked() {
1080                builder = builder.lock_translations();
1081            }
1082
1083            let mut body = builder.build();
1084
1085            body.set_enabled_rotations(
1086                !rigid_body_node.is_rotation_locked(),
1087                !rigid_body_node.is_rotation_locked(),
1088                !rigid_body_node.is_rotation_locked(),
1089                false,
1090            );
1091
1092            rigid_body_node.native.set(self.add_body(handle, body));
1093
1094            Log::writeln(
1095                MessageKind::Information,
1096                format!(
1097                    "Native rigid body was created for node {}",
1098                    rigid_body_node.name()
1099                ),
1100            );
1101        }
1102    }
1103
1104    pub(crate) fn sync_to_collider_node(
1105        &mut self,
1106        nodes: &NodePool,
1107        handle: Handle<Node>,
1108        collider_node: &scene::dim2::collider::Collider,
1109    ) {
1110        if !collider_node.is_globally_enabled() {
1111            self.remove_collider(collider_node.native.get());
1112            collider_node.native.set(Default::default());
1113            return;
1114        }
1115
1116        let anything_changed = collider_node.needs_sync_model();
1117
1118        // Important notes!
1119        // 1) The collider node may lack backing native physics collider in case if it
1120        //    is not attached to a rigid body.
1121        // 2) `get_mut` is **very** expensive because it forces physics engine to recalculate contacts
1122        //    and a lot of other stuff, this is why we need `anything_changed` flag.
1123        if collider_node.native.get() != ColliderHandle::invalid() {
1124            if anything_changed {
1125                if let Some(native) = self.colliders.get_mut(collider_node.native.get()) {
1126                    collider_node
1127                        .restitution
1128                        .try_sync_model(|v| native.set_restitution(v));
1129                    collider_node.collision_groups.try_sync_model(|v| {
1130                        native.set_collision_groups(InteractionGroups::new(
1131                            u32_to_group(v.memberships.0),
1132                            u32_to_group(v.filter.0),
1133                        ))
1134                    });
1135                    collider_node.solver_groups.try_sync_model(|v| {
1136                        native.set_solver_groups(InteractionGroups::new(
1137                            u32_to_group(v.memberships.0),
1138                            u32_to_group(v.filter.0),
1139                        ))
1140                    });
1141                    collider_node
1142                        .friction
1143                        .try_sync_model(|v| native.set_friction(v));
1144                    collider_node
1145                        .is_sensor
1146                        .try_sync_model(|v| native.set_sensor(v));
1147                    collider_node
1148                        .friction_combine_rule
1149                        .try_sync_model(|v| native.set_friction_combine_rule(v.into()));
1150                    collider_node
1151                        .restitution_combine_rule
1152                        .try_sync_model(|v| native.set_restitution_combine_rule(v.into()));
1153                    let mut remove_collider = false;
1154                    collider_node.shape.try_sync_model(|v| {
1155                        let inv_global_transform = isometric_global_transform(nodes, handle)
1156                            .try_inverse()
1157                            .unwrap_or_default();
1158
1159                        if let Some(shape) =
1160                            collider_shape_into_native_shape(&v, inv_global_transform, nodes)
1161                        {
1162                            native.set_shape(shape);
1163                        } else {
1164                            remove_collider = true;
1165                        }
1166                    });
1167                    if remove_collider {
1168                        self.remove_collider(collider_node.native.get());
1169                        collider_node.native.set(ColliderHandle::invalid());
1170                    }
1171                }
1172            }
1173        } else if let Some(parent_body) = nodes
1174            .try_borrow(collider_node.parent())
1175            .and_then(|n| n.cast::<dim2::rigidbody::RigidBody>())
1176        {
1177            if parent_body.native.get() != RigidBodyHandle::invalid() {
1178                let rigid_body_native = parent_body.native.get();
1179                let inv_global_transform = isometric_global_transform(nodes, handle)
1180                    .try_inverse()
1181                    .unwrap();
1182                if let Some(shape) = collider_shape_into_native_shape(
1183                    collider_node.shape(),
1184                    inv_global_transform,
1185                    nodes,
1186                ) {
1187                    let mut builder = ColliderBuilder::new(shape)
1188                        .position(Isometry2 {
1189                            rotation: UnitComplex::from_angle(
1190                                collider_node.local_transform().rotation().euler_angles().2,
1191                            ),
1192                            translation: Translation2 {
1193                                vector: collider_node.local_transform().position().xy(),
1194                            },
1195                        })
1196                        .friction(collider_node.friction())
1197                        .restitution(collider_node.restitution())
1198                        .collision_groups(InteractionGroups::new(
1199                            u32_to_group(collider_node.collision_groups().memberships.0),
1200                            u32_to_group(collider_node.collision_groups().filter.0),
1201                        ))
1202                        .friction_combine_rule(collider_node.friction_combine_rule().into())
1203                        .restitution_combine_rule(collider_node.restitution_combine_rule().into())
1204                        .solver_groups(InteractionGroups::new(
1205                            u32_to_group(collider_node.solver_groups().memberships.0),
1206                            u32_to_group(collider_node.solver_groups().filter.0),
1207                        ))
1208                        .sensor(collider_node.is_sensor());
1209
1210                    if let Some(density) = collider_node.density() {
1211                        builder = builder.density(density);
1212                    }
1213
1214                    let native_handle =
1215                        self.add_collider(handle, rigid_body_native, builder.build());
1216
1217                    collider_node.native.set(native_handle);
1218
1219                    Log::writeln(
1220                        MessageKind::Information,
1221                        format!(
1222                            "Native collider was created for node {}",
1223                            collider_node.name()
1224                        ),
1225                    );
1226                }
1227            }
1228        }
1229    }
1230
1231    pub(crate) fn sync_to_joint_node(
1232        &mut self,
1233        nodes: &NodePool,
1234        handle: Handle<Node>,
1235        joint: &scene::dim2::joint::Joint,
1236    ) {
1237        if !joint.is_globally_enabled() {
1238            self.remove_joint(joint.native.get());
1239            joint.native.set(ImpulseJointHandle(Default::default()));
1240            return;
1241        }
1242
1243        if let Some(native) = self.joints.set.get_mut(joint.native.get(), false) {
1244            joint.body1.try_sync_model(|v| {
1245                if let Some(rigid_body_node) = nodes.try_get(v) {
1246                    native.body1 = rigid_body_node.native.get();
1247                }
1248            });
1249            joint.body2.try_sync_model(|v| {
1250                if let Some(rigid_body_node) = nodes.try_get(v) {
1251                    native.body2 = rigid_body_node.native.get();
1252                }
1253            });
1254            joint.params.try_sync_model(|v| {
1255                native.data =
1256                    // Preserve local frames.
1257                    convert_joint_params(v, native.data.local_frame1, native.data.local_frame2)
1258            });
1259            joint.motor_params.try_sync_model(|v|{
1260                // The free axis is defined to be the x axis for both prismatic and ball joints in fyrox.
1261                // If you want the joint to translate / rotate along a different axis, you can rotate the joint itself.
1262                let joint_axis = match joint.params.get_value_ref(){
1263                    JointParams::PrismaticJoint(_) => JointAxis::LinX,
1264                    JointParams::BallJoint(_) => JointAxis::AngX,
1265                    _ => {
1266                        Log::warn("Try to modify motor parameters for unsupported joint type, this operation will be ignored.");
1267                        return;
1268                    }
1269                };
1270                // Force based motor model is better in the Fyrox's context
1271                native.data.set_motor_model(joint_axis, rapier2d::prelude::MotorModel::ForceBased);
1272                let JointMotorParams {
1273                    target_vel,
1274                    target_pos,
1275                    stiffness,
1276                    damping,
1277                    max_force
1278                } = v;
1279                native.data.set_motor(joint_axis, target_pos, target_vel, stiffness, damping);
1280                native.data.set_motor_max_force(joint_axis, max_force);
1281                // wake up the bodies connected to the joint to ensure they respond to the motor changes immediately
1282                // however, the rigid bodies may fall asleep any time later unless Joint::set_motor_* functions are called periodically,
1283                // or the rigid bodies are set to cannot sleep
1284                let Some(body1) = self.bodies.get_mut(native.body1) else {
1285                    return;
1286                };
1287                body1.wake_up(true);
1288                let Some(body2) = self.bodies.get_mut(native.body2) else {
1289                    return;
1290                };
1291                body2.wake_up(true);
1292            });
1293            joint.contacts_enabled.try_sync_model(|v| {
1294                native.data.set_contacts_enabled(v);
1295            });
1296            let mut local_frames = joint.local_frames.borrow_mut();
1297            if local_frames.is_none() {
1298                if let (Some(body1), Some(body2)) =
1299                    (nodes.try_get(joint.body1()), nodes.try_get(joint.body2()))
1300                {
1301                    let (local_frame1, local_frame2) = calculate_local_frames(joint, body1, body2);
1302                    native.data =
1303                        convert_joint_params((*joint.params).clone(), local_frame1, local_frame2);
1304                    *local_frames = Some(JointLocalFrames::new(&local_frame1, &local_frame2));
1305                }
1306            }
1307        } else {
1308            let body1_handle = joint.body1();
1309            let body2_handle = joint.body2();
1310            let params = joint.params().clone();
1311
1312            // A native joint can be created iff both rigid bodies are correctly assigned.
1313            if let (Some(body1), Some(body2)) =
1314                (nodes.try_get(body1_handle), nodes.try_get(body2_handle))
1315            {
1316                let native_body1 = body1.native.get();
1317                let native_body2 = body2.native.get();
1318
1319                if self.bodies.get(native_body1).is_none()
1320                    || self.bodies.get(native_body2).is_none()
1321                {
1322                    // A joint may be synced before the connected bodies, this way the connected
1323                    // rigid bodies does not have native rigid bodies, and in this case we should
1324                    // simply skip the joint and initialize it on the next frame.
1325                    return;
1326                }
1327
1328                // Calculate local frames first (if needed).
1329                let mut local_frames = joint.local_frames.borrow_mut();
1330                let (local_frame1, local_frame2) = local_frames
1331                    .clone()
1332                    .map(|frames| {
1333                        (
1334                            Isometry2 {
1335                                rotation: frames.body1.rotation,
1336                                translation: Translation2 {
1337                                    vector: frames.body1.position,
1338                                },
1339                            },
1340                            Isometry2 {
1341                                rotation: frames.body2.rotation,
1342                                translation: Translation2 {
1343                                    vector: frames.body2.position,
1344                                },
1345                            },
1346                        )
1347                    })
1348                    .unwrap_or_else(|| calculate_local_frames(joint, body1, body2));
1349
1350                let mut native_joint = convert_joint_params(params, local_frame1, local_frame2);
1351                native_joint.contacts_enabled = joint.is_contacts_enabled();
1352                let native_handle =
1353                    self.add_joint(handle, native_body1, native_body2, native_joint);
1354
1355                joint.native.set(native_handle);
1356                *local_frames = Some(JointLocalFrames::new(&local_frame1, &local_frame2));
1357
1358                Log::writeln(
1359                    MessageKind::Information,
1360                    format!("Native joint was created for node {}", joint.name()),
1361                );
1362            }
1363        }
1364    }
1365
1366    /// Intersections checks between regular colliders and sensor colliders
1367    pub(crate) fn intersections_with(
1368        &self,
1369        collider: ColliderHandle,
1370    ) -> impl Iterator<Item = IntersectionPair> + '_ {
1371        self.narrow_phase
1372            .intersection_pairs_with(collider)
1373            .filter_map(|(collider1, collider2, intersecting)| {
1374                Some(IntersectionPair {
1375                    collider1: Handle::decode_from_u128(self.colliders.get(collider1)?.user_data),
1376                    collider2: Handle::decode_from_u128(self.colliders.get(collider2)?.user_data),
1377                    has_any_active_contact: intersecting,
1378                })
1379            })
1380    }
1381
1382    /// Contacts checks between two regular colliders
1383    pub(crate) fn contacts_with(
1384        &self,
1385        collider: ColliderHandle,
1386    ) -> impl Iterator<Item = ContactPair> + '_ {
1387        self.narrow_phase
1388            .contact_pairs_with(collider)
1389            .filter_map(|c| ContactPair::from_native(c, self))
1390    }
1391
1392    /// Returns an iterator over all contact pairs generated in this frame.
1393    pub fn contacts(&self) -> impl Iterator<Item = ContactPair> + '_ {
1394        self.narrow_phase
1395            .contact_pairs()
1396            .filter_map(|c| ContactPair::from_native(c, self))
1397    }
1398}
1399
1400impl Default for PhysicsWorld {
1401    fn default() -> Self {
1402        Self::new()
1403    }
1404}
1405
1406impl Debug for PhysicsWorld {
1407    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1408        write!(f, "PhysicsWorld")
1409    }
1410}