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 <cfloat>
6
7#include "BsCorePrerequisites.h"
8#include "Physics/BsPhysicsCommon.h"
9#include "Physics/BsFJoint.h"
10
11namespace bs
12{
13 /** @addtogroup Physics
14 * @{
15 */
16
17 struct JOINT_DESC;
18
19 /**
20 * Base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (for example a door
21 * hinge). One of the bodies in the joint must always be movable (non-kinematic).
22 */
23 class BS_CORE_EXPORT Joint
24 {
25 public:
26 Joint() = default;
27 virtual ~Joint() = default;
28
29 /** @copydoc FJoint::getBody */
30 Rigidbody* getBody(JointBody body) const;
31
32 /** @copydoc FJoint::setBody */
33 void setBody(JointBody body, Rigidbody* value);
34
35 /** @copydoc FJoint::getPosition */
36 Vector3 getPosition(JointBody body) const;
37
38 /** @copydoc FJoint::getRotation */
39 Quaternion getRotation(JointBody body) const;
40
41 /** @copydoc FJoint::setTransform */
42 void setTransform(JointBody body, const Vector3& position, const Quaternion& rotation);
43
44 /** @copydoc FJoint::getBreakForce */
45 float getBreakForce() const;
46
47 /** @copydoc FJoint::setBreakForce */
48 void setBreakForce(float force);
49
50 /** @copydoc FJoint::getBreakTorque */
51 float getBreakTorque() const;
52
53 /** @copydoc FJoint::setBreakTorque */
54 void setBreakTorque(float torque);
55
56 /** @copydoc FJoint::getEnableCollision */
57 bool getEnableCollision() const;
58
59 /** @copydoc FJoint::setEnableCollision */
60 void setEnableCollision(bool value);
61
62 /** Triggered when the joint's break force or torque is exceeded. */
63 Event<void()> onJointBreak;
64
65 /** @name Internal
66 * @{
67 */
68
69 /**
70 * Sets the object that owns this physics object, if any. Used for high level systems so they can easily map their
71 * high level physics objects from the low level ones returned by various queries and events.
72 */
73 void _setOwner(PhysicsOwnerType type, void* owner) { mOwner.type = type; mOwner.ownerData = owner; }
74
75 /**
76 * Gets the object that owns this physics object, if any. Used for high level systems so they can easily map their
77 * high level physics objects from the low level ones returned by various queries and events.
78 */
79 void* _getOwner(PhysicsOwnerType type) const { return mOwner.type == type ? mOwner.ownerData : nullptr; }
80
81 /** @} */
82
83 protected:
84 PhysicsObjectOwner mOwner;
85 FJoint* mInternal = nullptr;
86 };
87
88 /** Structure used for initializing a new Joint. */
89 struct JOINT_DESC
90 {
91 struct BodyInfo
92 {
93 Rigidbody* body = nullptr;
94 Vector3 position = Vector3::ZERO;
95 Quaternion rotation = Quaternion::IDENTITY;
96 };
97
98 BodyInfo bodies[2];
99 float breakForce = FLT_MAX;
100 float breakTorque = FLT_MAX;
101 bool enableCollision = false;
102 };
103
104 /**
105 * Controls spring parameters for a physics joint limits. If a limit is soft (body bounces back due to restition when
106 * the limit is reached) the spring will pull the body back towards the limit using the specified parameters.
107 */
108 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) Spring
109 {
110 /** Constructs a spring with no force. */
111 Spring() { }
112
113 /**
114 * Constructs a spring.
115 *
116 * @param stiffness Spring strength. Force proportional to the position error.
117 * @param damping Damping strength. Force propertional to the velocity error.
118 */
119 Spring(float stiffness, float damping)
120 :stiffness(stiffness), damping(damping)
121 { }
122
123 bool operator==(const Spring& other) const
124 {
125 return stiffness == other.stiffness && damping == other.damping;
126 }
127
128 /** Spring strength. Force proportional to the position error. */
129 float stiffness = 0.0f;
130
131 /** Damping strength. Force propertional to the velocity error. */
132 float damping = 0.0f;
133 };
134
135 /** Contains common values used by all Joint limit types. */
136 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) LimitCommon
137 {
138 LimitCommon(float contactDist = -1.0f)
139 :contactDist(contactDist)
140 { }
141
142 LimitCommon(const Spring& spring, float restitution = 0.0f)
143 : restitution(restitution), spring(spring)
144 { }
145
146 /**
147 * Distance from the limit at which it becomes active. Allows the solver to activate earlier than the limit is
148 * reached to avoid breaking the limit.
149 */
150 float contactDist = -1.0f;
151
152 /**
153 * Controls how do objects react when the limit is reached, values closer to zero specify non-ellastic collision,
154 * while those closer to one specify more ellastic (i.e bouncy) collision. Must be in [0, 1] range.
155 */
156 float restitution = 0.0f;
157
158 /** Spring that controls how are the bodies pulled back towards the limit when they breach it. */
159 Spring spring;
160 };
161
162 /** Represents a joint limit between two distance values. Lower value must be less than the upper value. */
163 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) LimitLinearRange : LimitCommon
164 {
165 /** Constructs an empty limit. */
166 LimitLinearRange()
167 { }
168
169 /**
170 * Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
171 *
172 * @param lower Lower distance of the limit. Must be less than @p upper.
173 * @param upper Upper distance of the limit. Must be more than @p lower.
174 * @param contactDist Distance from the limit at which it becomes active. Allows the solver to activate earlier
175 * than the limit is reached to avoid breaking the limit. Specify -1 for the default.
176 */
177 LimitLinearRange(float lower, float upper, float contactDist = -1.0f)
178 :LimitCommon(contactDist), lower(lower), upper(upper)
179 { }
180
181 /**
182 * Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
183 * parameter and will be pulled back towards the limit by the provided spring.
184 *
185 * @param lower Lower distance of the limit. Must be less than @p upper.
186 * @param upper Upper distance of the limit. Must be more than @p lower.
187 * @param spring Spring that controls how are the bodies pulled back towards the limit when they breach it.
188 * @param restitution Controls how do objects react when the limit is reached, values closer to zero specify
189 * non-ellastic collision, while those closer to one specify more ellastic (i.e bouncy)
190 * collision. Must be in [0, 1] range.
191 */
192 LimitLinearRange(float lower, float upper, const Spring& spring, float restitution = 0.0f)
193 :LimitCommon(spring, restitution), lower(lower), upper(upper)
194 { }
195
196 bool operator==(const LimitLinearRange& other) const
197 {
198 return lower == other.lower && upper == other.upper && contactDist == other.contactDist &&
199 restitution == other.restitution && spring == other.spring;
200 }
201
202 /** Lower distance of the limit. Must be less than #upper. */
203 float lower = 0.0f;
204
205 /** Upper distance of the limit. Must be more than #lower. */
206 float upper = 0.0f;
207 };
208
209 /** Represents a joint limit between zero a single distance value. */
210 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) LimitLinear : LimitCommon
211 {
212 /** Constructs an empty limit. */
213 LimitLinear()
214 { }
215
216 /**
217 * Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
218 *
219 * @param extent Distance at which the limit becomes active.
220 * @param contactDist Distance from the limit at which it becomes active. Allows the solver to activate earlier
221 * than the limit is reached to avoid breaking the limit. Specify -1 for the default.
222 */
223 LimitLinear(float extent, float contactDist = -1.0f)
224 :LimitCommon(contactDist), extent(extent)
225 { }
226
227 /**
228 * Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
229 * parameter and will be pulled back towards the limit by the provided spring.
230 *
231 * @param extent Distance at which the limit becomes active.
232 * @param spring Spring that controls how are the bodies pulled back towards the limit when they breach it.
233 * @param restitution Controls how do objects react when the limit is reached, values closer to zero specify
234 * non-ellastic collision, while those closer to one specify more ellastic (i.e bouncy)
235 * collision. Must be in [0, 1] range.
236 */
237 LimitLinear(float extent, const Spring& spring, float restitution = 0.0f)
238 :LimitCommon(spring, restitution), extent(extent)
239 { }
240
241 bool operator==(const LimitLinear& other) const
242 {
243 return extent == other.extent && contactDist == other.contactDist && restitution == other.restitution &&
244 spring == other.spring;
245 }
246
247 /** Distance at which the limit becomes active. */
248 float extent = 0.0f;
249 };
250
251 /** Represents a joint limit between two angles. */
252 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) LimitAngularRange : LimitCommon
253 {
254 /** Constructs an empty limit. */
255 LimitAngularRange()
256 { }
257
258 /**
259 * Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
260 *
261 * @param lower Lower angle of the limit. Must be less than @p upper.
262 * @param upper Upper angle of the limit. Must be more than @p lower.
263 * @param contactDist Distance from the limit at which it becomes active. Allows the solver to activate earlier
264 * than the limit is reached to avoid breaking the limit. Specify -1 for the default.
265 */
266 LimitAngularRange(Radian lower, Radian upper, float contactDist = -1.0f)
267 :LimitCommon(contactDist), lower(lower), upper(upper)
268 { }
269
270 /**
271 * Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
272 * parameter and will be pulled back towards the limit by the provided spring.
273 *
274 * @param lower Lower angle of the limit. Must be less than @p upper.
275 * @param upper Upper angle of the limit. Must be more than @p lower.
276 * @param spring Spring that controls how are the bodies pulled back towards the limit when they breach it.
277 * @param restitution Controls how do objects react when the limit is reached, values closer to zero specify
278 * non-ellastic collision, while those closer to one specify more ellastic (i.e bouncy)
279 * collision. Must be in [0, 1] range.
280 */
281 LimitAngularRange(Radian lower, Radian upper, const Spring& spring, float restitution = 0.0f)
282 :LimitCommon(spring, restitution), lower(lower), upper(upper)
283 { }
284
285 bool operator==(const LimitAngularRange& other) const
286 {
287 return lower == other.lower && upper == other.upper && contactDist == other.contactDist &&
288 restitution == other.restitution && spring == other.spring;
289 }
290
291 /** Lower angle of the limit. Must be less than #upper. */
292 BS_SCRIPT_EXPORT(range:[0,359])
293 Radian lower = Radian(0.0f);
294
295 /** Upper angle of the limit. Must be less than #lower. */
296 BS_SCRIPT_EXPORT(range:[0,359])
297 Radian upper = Radian(0.0f);
298 };
299
300 /** Represents a joint limit that contraints movement to within an elliptical cone. */
301 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) LimitConeRange : LimitCommon
302 {
303 /** Constructs a limit with a 45 degree cone. */
304 LimitConeRange()
305 { }
306
307 /**
308 * Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
309 *
310 * @param yLimitAngle Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
311 * @param zLimitAngle Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
312 * @param contactDist Distance from the limit at which it becomes active. Allows the solver to activate
313 * earlier than the limit is reached to avoid breaking the limit. Specify -1 for the
314 * default.
315 */
316 LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, float contactDist = -1.0f)
317 :LimitCommon(contactDist), yLimitAngle(yLimitAngle), zLimitAngle(zLimitAngle)
318 { }
319
320 /**
321 * Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
322 * parameter and will be pulled back towards the limit by the provided spring.
323 *
324 * @param yLimitAngle Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
325 * @param zLimitAngle Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
326 * @param spring Spring that controls how are the bodies pulled back towards the limit when they breach it.
327 * @param restitution Controls how do objects react when the limit is reached, values closer to zero specify
328 * non-ellastic collision, while those closer to one specify more ellastic (i.e bouncy)
329 * collision. Must be in [0, 1] range.
330 */
331 LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, const Spring& spring, float restitution = 0.0f)
332 :LimitCommon(spring, restitution), yLimitAngle(yLimitAngle), zLimitAngle(zLimitAngle)
333 { }
334
335 bool operator==(const LimitConeRange& other) const
336 {
337 return yLimitAngle == other.yLimitAngle && zLimitAngle == other.zLimitAngle &&
338 contactDist == other.contactDist && restitution == other.restitution && spring == other.spring;
339 }
340
341 /** Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis. */
342 BS_SCRIPT_EXPORT(range:[0,180])
343 Radian yLimitAngle = Radian(Math::HALF_PI);
344
345 /** Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis. */
346 BS_SCRIPT_EXPORT(range:[0,180])
347 Radian zLimitAngle = Radian(Math::HALF_PI);
348 };
349
350 /** @} */
351}
352