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