logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
use super::*;

/// `D6Joint` component. A D6 joint, like a `Joint`, connects two dynamic, or one static and one dynamic, entity physically.
/// It doesn't have to be a component of one of the entities it connects, but that can be convenient at times.
///
/// The `D6Joint` has 6 degrees of freedom (hence the name): 3 translational, and 3 rotational.
/// These can all be controlled individually.
///
/// Important: By default all six dimensions of motion are locked, so by default a `D6Joint` acts like a fix-joint,
/// gluing the bodies to each other. To do something else you need to unlock the dimensions with the `motion` accessor.
/// For instance, so create a ball-socket joint you would unlock the rotational degrees of movement but keep the
/// translational degrees locked.
///
/// A joint normally connects two entities, but you can also leave one of the entities
/// to the default `None` value too attach an entity to the world frame,
/// a static infinite-mass invisible global frame.
///
/// Usually accessed through `entity.d6_joint`().
///
/// The [NVIDIA `PhysX` documentation](https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/guide/Manual/Joints.html)
/// has some more details. Some naming is a little different from the official API, but overall the concepts are the same.

pub struct D6Joint {
    id: Entity,
}

impl std::fmt::Debug for D6Joint {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("D6Joint")
            .field("entity", &self.id.name())
            .finish_non_exhaustive()
    }
}

#[derive(Copy, Clone, Debug)]
/// The parameters for a drive on a D6 joint.
pub struct D6DriveParams {
    /// Stiffness of the drive spring: The amount of torque needed to move the joint to its target orientation (not used for velocity drive).
    pub stiffness: f32,
    /// Damping of the drive spring: Tweak to apply damping to the spring to smooth out any oscillations.
    pub damping: f32,
    /// Force limit: Maximum force/acceleration the drive can apply.
    pub force_limit: f32,
}

#[derive(Copy, Clone, Debug)]
/// The parameters for a simple spring.
pub struct D6SpringParams {
    /// Stiffness of the spring
    pub stiffness: f32,
    /// Damping of the spring.
    pub damping: f32,
}

impl D6Joint {
    impl_world_accessor!(
        /// The first entity of the joint.
        D6Joint,
        Entity1,
        Entity,
        entity_1,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The second entity of the joint.
        D6Joint,
        Entity2,
        Entity,
        entity_2,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The position of the joint relative to the first entity (`entity_1`)
        D6Joint,
        RelativePosition1,
        Vec3,
        relative_offset_1,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The orientation of the joint relative to the first entity (`entity_1`)
        D6Joint,
        RelativeOrientation1,
        Quat,
        relative_orientation_1,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The position of the joint relative to the second entity (`entity_2`)
        D6Joint,
        RelativePosition2,
        Vec3,
        relative_offset_2,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The orientation of the joint relative to the second entity (`entity_2`)
        D6Joint,
        RelativeOrientation2,
        Quat,
        relative_orientation_2,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Sets the force threshold for breaking the joint. Default is std::f32::MAX (effectively unbreakable).
        D6Joint,
        BreakForce,
        f32,
        break_force,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Sets the torque threshold for breaking the joint. Default is std::f32::MAX (effectively unbreakable).
        D6Joint,
        BreakTorque,
        f32,
        break_torque,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Lets you check whether the joint is broken. Cannot be modified.
        D6Joint,
        IsBroken,
        bool,
        is_broken,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// If non-zero, linear projection is enabled (a way of resolving tricky physics situations by moving
        /// the parts into place), and the linear projection tolerance is set to this value.
        ///
        /// Projection is a on-physical process that violates conservation laws and collision meshes.
        /// Only turn it on if you absolutely need to.
        D6Joint,
        ProjectionLinearTolerance,
        f32,
        projection_linear_tolerance,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// If non-zero, projection is enabled (a way of resolving tricky physics situations by turning
        /// the parts into place), and the angular projection tolerance is set to this value.
        ///
        /// Projection is a on-physical process that violates conservation laws and collision meshes.
        /// Only turn it on if you absolutely need to.
        D6Joint,
        ProjectionAngularTolerance,
        f32,
        projection_angular_tolerance,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Turns on joint drive. Note that this disables the use of limits on the joint.
        D6Joint,
        DriveEnabled,
        bool,
        drive_enable,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Get the raw translation between the two parts of the joint.
        D6Joint,
        RelativePosition,
        Vec3,
        relative_position,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// Get the raw rotation between the two parts of the joint. Not decomposed into TSS (twist, swing1, swing2).
        D6Joint,
        RelativeRotation,
        Quat,
        relative_rotation,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// Gets the rotation decomposed into TSS (twist, swing1, swing2).
        D6Joint,
        RelativeAngles,
        Vec3,
        relative_angles,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// The limit bounds of a D6 joint. x is min, y is max, what exactly it limits depends on the joint type.
        D6Joint,
        LinearLimit,
        f32,
        linear_limit,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The linear limit type of a D6 joint.
        D6Joint,
        LinearLimitType,
        JointLimitType,
        linear_limit_type,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The linear limit spring of a D6 joint.
        D6Joint,
        LinearLimitSpring,
        D6SpringParams,
        linear_limit_spring,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The twist limit bounds of a D6 joint.
        D6Joint,
        TwistLimit,
        Vec2,
        twist_limit,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The linear limit type of a D6 joint.
        D6Joint,
        TwistLimitType,
        JointLimitType,
        twist_limit_type,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The linear limit spring of a D6 joint.
        D6Joint,
        TwistLimitSpring,
        D6SpringParams,
        twist_limit_spring,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The swing limit bounds of a D6 joint (angular)
        D6Joint,
        SwingLimit,
        Vec2,
        swing_limit,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The linear limit type of a D6 joint.
        D6Joint,
        SwingLimitType,
        JointLimitType,
        swing_limit_type,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The swing limit spring of a D6 joint.
        D6Joint,
        SwingLimitSpring,
        D6SpringParams,
        swing_limit_spring,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Goal position of the D6 drive.
        D6Joint,
        DrivePosition,
        Vec3,
        drive_position,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Goal rotation of the D6 drive.
        D6Joint,
        DriveRotation,
        Quat,
        drive_rotation,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Goal linear velocity of the D6 drive.
        D6Joint,
        DriveLinearVelocity,
        Vec3,
        drive_linear_velocity,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Goal angular velocity of the D6 drive.
        D6Joint,
        DriveAngularVelocity,
        Vec3,
        drive_angular_velocity,
        ValueAccessorReadWrite
    );

    impl_world_accessor_indexed!(
        /// Set the motion type of each of the D6 joint's six axes, `D6Axis`. Can be locked, limited or free.
        ///
        /// By default, all six axis are locked, so you need to unlock any axis you would like enable movement of.
        ///
        /// ## Hinge
        ///
        /// Free movement aroudn the X axis:
        ///
        /// ``` rust
        /// joint.motion(D6Axis::Twist).set(D6MotionType::Free);
        /// ```
        ///
        /// ## Ball-socket joint
        ///
        /// ``` rust
        /// joint.motion(D6Axis::Twist).set(D6MotionType::Free);
        /// joint.motion(D6Axis::Swing1).set(D6MotionType::Free);
        /// joint.motion(D6Axis::Swing2).set(D6MotionType::Free);
        /// ```
        D6Joint,
        MotionX,
        D6MotionType,
        motion,
        D6Axis,
        ValueAccessorReadWrite
    );

    impl_world_accessor_indexed!(
        /// Lets you control the six possible drives from `D6Drive` by setting a `D6DriveParams`.
        D6Joint,
        DriveParamsX,
        D6DriveParams,
        drive_params,
        D6Drive,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Controls whether drive is a force (false) or acceleration (true). Acceleration is much easier to tune since it
        /// will automatically compute the appropriate force for the masses involved, so it's the default and
        /// recommended value.
        D6Joint,
        DriveIsAcceleration,
        bool,
        drive_is_acceleration,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Returns the linear force currently exerted on the joint constraint.
        D6Joint,
        LinearForce,
        Vec3,
        linear_force,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// Returns the angular force currently exerted on the joint constraint.
        D6Joint,
        AngularForce,
        Vec3,
        angular_force,
        ValueAccessorRead
    );
}

impl_world_component!(D6Joint);