// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#pragma once
#include "Joint.h"
#include "Limits.h"
///
/// Specifies axes that the D6 joint can constrain motion on.
///
API_ENUM() enum class D6JointAxis
{
///
/// Movement on the X axis.
///
X = 0,
///
/// Movement on the Y axis.
///
Y = 1,
///
/// Movement on the Z axis.
///
Z = 2,
///
/// Rotation around the X axis.
///
Twist = 3,
///
/// Rotation around the Y axis.
///
SwingY = 4,
///
/// Rotation around the Z axis.
///
SwingZ = 5,
API_ENUM(Attributes="HideInEditor")
MAX
};
///
/// Specifies type of constraint placed on a specific axis.
///
API_ENUM() enum class D6JointMotion
{
///
/// Axis is immovable.
///
Locked,
///
/// Axis will be constrained by the specified limits.
///
Limited,
///
/// Axis will not be constrained.
///
Free,
API_ENUM(Attributes="HideInEditor")
MAX
};
///
/// Type of drives that can be used for moving or rotating bodies attached to the joint.
///
///
/// Each drive is an implicit force-limited damped spring:
/// force = spring * (target position - position) + damping * (targetVelocity - velocity)
///
/// Alternatively, the spring may be configured to generate a specified acceleration instead of a force.
///
/// A linear axis is affected by drive only if the corresponding drive flag is set.There are two possible models
/// for angular drive : swing / twist, which may be used to drive one or more angular degrees of freedom, or slerp,
/// which may only be used to drive all three angular degrees simultaneously.
///
API_ENUM() enum class D6JointDriveType
{
///
/// Linear movement on the X axis using the linear drive model.
///
X = 0,
///
/// Linear movement on the Y axis using the linear drive model.
///
Y = 1,
///
/// Linear movement on the Z axis using the linear drive model.
///
Z = 2,
///
/// Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with Slerp mode.
///
Swing = 3,
///
/// Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with Slerp mode.
///
Twist = 4,
///
/// Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation
/// by interpolating the quaternion values directly over the shortest path (applies to all three axes, which
/// they all must be unlocked).
///
Slerp = 5,
API_ENUM(Attributes="HideInEditor")
MAX
};
///
/// Specifies parameters for a drive that will attempt to move the joint bodies to the specified drive position and velocity.
///
API_STRUCT() struct D6JointDrive
{
DECLARE_SCRIPTING_TYPE_MINIMAL(D6JointDrive);
///
/// The spring strength. Force proportional to the position error.
///
API_FIELD() float Stiffness = 0.0f;
///
/// Damping strength. Force proportional to the velocity error.
///
API_FIELD() float Damping = 0.0f;
///
/// The maximum force the drive can apply.
///
API_FIELD() float ForceLimit = MAX_float;
///
/// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as they account for the masses of the actors to which the joint is attached.
///
API_FIELD() bool Acceleration = false;
public:
bool operator==(const D6JointDrive& other) const
{
return Stiffness == other.Stiffness && Damping == other.Damping && ForceLimit == other.ForceLimit && Acceleration == other.Acceleration;
}
};
///
/// Physics joint that is the most customizable type of joint. This joint type can be used to create all other built-in joint
/// types, and to design your own custom ones, but is less intuitive to use. Allows a specification of a linear
/// constraint (for example for a slider), twist constraint (rotating around X) and swing constraint (rotating around Y and Z).
/// It also allows you to constrain limits to only specific axes or completely lock specific axes.
///
///
API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Joints/D6 Joint\"), ActorToolbox(\"Physics\")")
class FLAXENGINE_API D6Joint : public Joint
{
DECLARE_SCENE_OBJECT(D6Joint);
private:
D6JointMotion _motion[static_cast(D6JointAxis::MAX)];
D6JointDrive _drive[static_cast(D6JointDriveType::MAX)];
LimitLinear _limitLinear;
LimitAngularRange _limitTwist;
LimitConeRange _limitSwing;
public:
///
/// Gets the motion type around the specified axis.
///
/// Each axis may independently specify that the degree of freedom is locked (blocking relative movement along or around this axis), limited by the corresponding limit, or free.
/// The axis the degree of freedom around which the motion type is specified.
/// The value.
API_FUNCTION() FORCE_INLINE D6JointMotion GetMotion(const D6JointAxis axis) const
{
return _motion[static_cast(axis)];
}
///
/// Sets the motion type around the specified axis.
///
/// Each axis may independently specify that the degree of freedom is locked (blocking relative movement along or around this axis), limited by the corresponding limit, or free.
/// The axis the degree of freedom around which the motion type is specified.
/// The value.
API_FUNCTION() void SetMotion(const D6JointAxis axis, const D6JointMotion value);
///
/// Gets the drive parameters for the specified drive type.
///
/// The type of drive being specified.
/// The value.
API_FUNCTION() FORCE_INLINE D6JointDrive GetDrive(const D6JointDriveType index) const
{
return _drive[static_cast(index)];
}
///
/// Sets the drive parameters for the specified drive type.
///
/// The type of drive being specified.
/// The value.
API_FUNCTION() void SetDrive(const D6JointDriveType index, const D6JointDrive& value);
public:
///
/// Determines the linear limit used for constraining translation degrees of freedom.
///
API_PROPERTY(Attributes="EditorOrder(200), EditorDisplay(\"Joint\")")
FORCE_INLINE LimitLinear GetLimitLinear() const
{
return _limitLinear;
}
///
/// Determines the linear limit used for constraining translation degrees of freedom.
///
API_PROPERTY() void SetLimitLinear(const LimitLinear& value);
///
/// Determines the angular limit used for constraining the twist (rotation around X) degree of freedom.
///
API_PROPERTY(Attributes="EditorOrder(210), EditorDisplay(\"Joint\")")
FORCE_INLINE LimitAngularRange GetLimitTwist() const
{
return _limitTwist;
}
///
/// Determines the angular limit used for constraining the twist (rotation around X) degree of freedom.
///
API_PROPERTY() void SetLimitTwist(const LimitAngularRange& value);
///
/// Determines the cone limit used for constraining the swing (rotation around Y and Z) degree of freedom.
///
API_PROPERTY(Attributes="EditorOrder(220), EditorDisplay(\"Joint\")")
FORCE_INLINE LimitConeRange GetLimitSwing() const
{
return _limitSwing;
}
///
/// Determines the cone limit used for constraining the swing (rotation around Y and Z) degree of freedom.
///
API_PROPERTY() void SetLimitSwing(const LimitConeRange& value);
public:
///
/// Gets the drive's target position relative to the joint's first body.
///
API_PROPERTY(Attributes="HideInEditor") Vector3 GetDrivePosition() const;
///
/// Sets the drive's target position relative to the joint's first body.
///
API_PROPERTY() void SetDrivePosition(const Vector3& value);
///
/// Gets the drive's target rotation relative to the joint's first body.
///
API_PROPERTY(Attributes="HideInEditor") Quaternion GetDriveRotation() const;
///
/// Sets the drive's target rotation relative to the joint's first body.
///
API_PROPERTY() void SetDriveRotation(const Quaternion& value);
///
/// Gets the drive's target linear velocity.
///
API_PROPERTY(Attributes="HideInEditor") Vector3 GetDriveLinearVelocity() const;
///
/// Sets the drive's target linear velocity.
///
API_PROPERTY() void SetDriveLinearVelocity(const Vector3& value);
///
/// Gets the drive's target angular velocity.
///
API_PROPERTY(Attributes="HideInEditor") Vector3 GetDriveAngularVelocity() const;
///
/// Sets the drive's target angular velocity.
///
API_PROPERTY() void SetDriveAngularVelocity(const Vector3& value);
public:
///
/// Gets the twist angle of the joint (in the range (-2*Pi, 2*Pi]).
///
API_PROPERTY() float GetCurrentTwist() const;
///
/// Gets the current swing angle of the joint from the Y axis.
///
API_PROPERTY() float GetCurrentSwingY() const;
///
/// Gets the current swing angle of the joint from the Z axis.
///
API_PROPERTY() float GetCurrentSwingZ() const;
public:
// [Joint]
#if USE_EDITOR
void OnDebugDrawSelected() override;
#endif
void Serialize(SerializeStream& stream, const void* otherObj) override;
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
protected:
// [Joint]
void* CreateJoint(const PhysicsJointDesc& desc) override;
};