Skip to main content

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