1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Physics/BsJoint.h"
7
8namespace bs
9{
10 class PhysicsScene;
11 /** @addtogroup Physics
12 * @{
13 */
14
15 struct D6_JOINT_DESC;
16
17 /** Specifies axes that the D6 joint can constrain motion on. */
18 enum class BS_SCRIPT_EXPORT(m:Physics) D6JointAxis
19 {
20 X, /**< Movement on the X axis. */
21 Y, /**< Movement on the Y axis. */
22 Z, /**< Movement on the Z axis. */
23 Twist, /**< Rotation around the X axis. */
24 SwingY, /**< Rotation around the Y axis. */
25 SwingZ, /**< Rotation around the Z axis. */
26 Count
27 };
28
29 /** Specifies type of constraint placed on a specific axis. */
30 enum class BS_SCRIPT_EXPORT(m:Physics) D6JointMotion
31 {
32 Locked, /**< Axis is immovable. */
33 Limited, /**< Axis will be constrained by the specified limits. */
34 Free, /**< Axis will not be constrained. */
35 Count
36 };
37
38 /** Type of drives that can be used for moving or rotating bodies attached to the joint. */
39 enum class BS_SCRIPT_EXPORT(m:Physics) D6JointDriveType
40 {
41 X, /**< Linear movement on the X axis using the linear drive model. */
42 Y, /**< Linear movement on the Y axis using the linear drive model. */
43 Z, /**< Linear movement on the Z axis using the linear drive model. */
44 /**
45 * Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with
46 * SLERP mode.
47 */
48 Swing,
49 /**
50 * Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with
51 * SLERP mode.
52 */
53 Twist,
54 /**
55 * Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation
56 * by interpolating the quaternion values directly over the shortest path (applies to all three axes, which
57 * they all must be unlocked).
58 */
59 SLERP,
60 Count
61 };
62
63 /**
64 * Specifies parameters for a drive that will attempt to move the joint bodies to the specified drive position and
65 * velocity.
66 */
67 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) D6JointDrive
68 {
69 bool operator==(const D6JointDrive& other) const
70 {
71 return stiffness == other.stiffness && damping == other.damping && forceLimit == other.forceLimit &&
72 acceleration == other.acceleration;
73 }
74
75 /** Spring strength. Force proportional to the position error. */
76 float stiffness = 0.0f;
77
78 /** Damping strength. Force propertional to the velocity error. */
79 float damping = 0.0f;
80
81 /** Maximum force the drive can apply. */
82 float forceLimit = FLT_MAX;
83
84 /**
85 * If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as
86 * they account for the masses of the actors to which the joint is attached.
87 */
88 bool acceleration = false;
89 };
90
91 /**
92 * Represents the most customizable type of joint. This joint type can be used to create all other built-in joint
93 * types, and to design your own custom ones, but is less intuitive to use. Allows a specification of a linear
94 * constraint (for example for slider), twist constraint (rotating around X) and swing constraint (rotating around Y and
95 * Z). It also allows you to constrain limits to only specific axes or completely lock specific axes.
96 */
97 class BS_CORE_EXPORT D6Joint : public Joint
98 {
99 public:
100 D6Joint(const D6_JOINT_DESC& desc) { }
101 virtual ~D6Joint() { }
102
103 /**
104 * Returns motion constraint for the specified axis.
105 *
106 * @see setMotion
107 */
108 virtual D6JointMotion getMotion(D6JointAxis axis) const = 0;
109
110 /**
111 * Allows you to constrain motion of the specified axis. Be aware that when setting drives for a specific axis
112 * you must also take care not to constrain its motion in a conflicting way (for example you cannot add a drive that
113 * moves the joint on X axis, and then lock the X axis).
114 *
115 * Unlocking translations degrees of freedom allows the bodies to move along the subset of the unlocked axes.
116 * (for example unlocking just one translational axis is the equivalent of a slider joint.)
117 *
118 * Angular degrees of freedom are partitioned as twist (around X axis) and swing (around Y and Z axes). Different
119 * effects can be achieves by unlocking their various combinations:
120 * - If a single degree of angular freedom is unlocked it should be the twist degree as it has extra options for
121 * that case (for example for a hinge joint).
122 * - If both swing degrees are unlocked but twist is locked the result is a zero-twist joint.
123 * - If one swing and one twist degree of freedom are unlocked the result is a zero-swing joint (for example an arm
124 * attached at the elbow)
125 * - If all angular degrees of freedom are unlocked the result is the same as the spherical joint.
126 */
127 virtual void setMotion(D6JointAxis axis, D6JointMotion motion) = 0;
128
129 /** Returns the current rotation of the joint around the X axis. */
130 virtual Radian getTwist() const = 0;
131
132 /** Returns the current rotation of the joint around the Y axis. */
133 virtual Radian getSwingY() const = 0;
134
135 /** Returns the current rotation of the joint around the Z axis. */
136 virtual Radian getSwingZ() const = 0;
137
138 /** @copydoc setLimitLinear() */
139 virtual LimitLinear getLimitLinear() const = 0;
140
141 /** Determines the linear limit used for constraining translation degrees of freedom. */
142 virtual void setLimitLinear(const LimitLinear& limit) = 0;
143
144 /** @copydoc setLimitTwist() */
145 virtual LimitAngularRange getLimitTwist() const = 0;
146
147 /** Determines the angular limit used for constraining the twist (rotation around X) degree of freedom. */
148 virtual void setLimitTwist(const LimitAngularRange& limit) = 0;
149
150 /** @copydoc setLimitSwing() */
151 virtual LimitConeRange getLimitSwing() const = 0;
152
153 /** Determines the cone limit used for constraining the swing (rotation around Y and Z) degree of freedom. */
154 virtual void setLimitSwing(const LimitConeRange& limit) = 0;
155
156 /** @copydoc setDrive() */
157 virtual D6JointDrive getDrive(D6JointDriveType type) const = 0;
158
159 /**
160 * Determines a drive that will attempt to move the specified degree(s) of freedom to the wanted position and
161 * velocity.
162 */
163 virtual void setDrive(D6JointDriveType type, const D6JointDrive& drive) = 0;
164
165 /** Returns the drive's target position relative to the joint's first body. */
166 virtual Vector3 getDrivePosition() const = 0;
167
168 /** Returns the drive's target rotation relative to the joint's first body. */
169 virtual Quaternion getDriveRotation() const = 0;
170
171 /** Sets the drive's target position and rotation relative to the joint's first body. */
172 virtual void setDriveTransform(const Vector3& position, const Quaternion& rotation) = 0;
173
174 /** Returns the drive's target linear velocity. */
175 virtual Vector3 getDriveLinearVelocity() const = 0;
176
177 /** Returns the drive's target angular velocity. */
178 virtual Vector3 getDriveAngularVelocity() const = 0;
179
180 /** Sets the drive's target linear and angular velocities. */
181 virtual void setDriveVelocity(const Vector3& linear, const Vector3& angular) = 0;
182
183 /**
184 * Creates a new D6 joint.
185 *
186 * @param[in] scene Scene to which to add the joint.
187 * @param[in] desc Settings describing the joint.
188 */
189 static SPtr<D6Joint> create(PhysicsScene& scene, const D6_JOINT_DESC& desc);
190 };
191
192 /** Structure used for initializing a new D6Joint. */
193 struct D6_JOINT_DESC : JOINT_DESC
194 {
195 D6_JOINT_DESC() { }
196
197 D6JointMotion motion[(UINT32)D6JointAxis::Count] = { D6JointMotion::Locked };
198 D6JointDrive drive[(UINT32)D6JointDriveType::Count];
199 LimitLinear limitLinear;
200 LimitAngularRange limitTwist;
201 LimitConeRange limitSwing;
202 Vector3 drivePosition = Vector3::ZERO;
203 Quaternion driveRotation = Quaternion::IDENTITY;
204 Vector3 driveLinearVelocity = Vector3::ZERO;
205 Vector3 driveAngularVelocity = Vector3::ZERO;
206 };
207
208 /** @} */
209}