// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Platform/Platform.h"
#include "Vector3.h"
#include "Quaternion.h"
struct Matrix;
///
/// Describes transformation in a 3D space.
///
API_STRUCT() struct FLAXENGINE_API Transform
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Transform);
///
/// The translation vector of the transform.
///
API_FIELD(Attributes="EditorOrder(10), EditorDisplay(null, \"Position\")") Vector3 Translation;
///
/// The rotation of the transform.
///
API_FIELD(Attributes="EditorOrder(20), EditorDisplay(null, \"Rotation\")") Quaternion Orientation;
///
/// The scale vector of the transform.
///
API_FIELD(Attributes="EditorOrder(30), Limit(float.MinValue, float.MaxValue, 0.01f)") Float3 Scale;
public:
///
/// An identity transform.
///
static Transform Identity;
public:
///
/// Empty constructor.
///
Transform() = default;
///
/// Initializes a new instance of the struct.
///
/// 3D position
Transform(const Vector3& position)
: Translation(position)
, Orientation(0.0f, 0.0f, 0.0f, 1.0f)
, Scale(1.0f)
{
}
///
/// Initializes a new instance of the struct.
///
/// 3D position
/// Transform rotation
Transform(const Vector3& position, const Quaternion& rotation)
: Translation(position)
, Orientation(rotation)
, Scale(1.0f)
{
}
///
/// Initializes a new instance of the struct.
///
/// 3D position
/// Transform rotation
/// Transform scale
Transform(const Vector3& position, const Quaternion& rotation, const Float3& scale)
: Translation(position)
, Orientation(rotation)
, Scale(scale)
{
}
Transform(const Vector3& position, const Matrix3x3& rotationScale);
public:
String ToString() const;
public:
///
/// Checks if transform is an identity transformation.
///
bool IsIdentity() const
{
return Translation.IsZero() && Orientation.IsIdentity() && Scale.IsOne();
}
///
/// Returns true if transform has one or more components equal to +/- infinity or NaN.
///
bool IsNanOrInfinity() const
{
return Translation.IsNanOrInfinity() || Orientation.IsNanOrInfinity() || Scale.IsNanOrInfinity();
}
///
/// Calculates the determinant of this transformation.
///
FORCE_INLINE float GetDeterminant() const
{
return Scale.X * Scale.Y * Scale.Z;
}
public:
///
/// Gets rotation matrix (from Orientation).
///
/// Rotation matrix
Matrix GetRotation() const;
///
/// Gets rotation matrix (from Orientation).
///
/// Matrix to set
void GetRotation(Matrix& result) const;
///
/// Sets rotation matrix (from Orientation).
///
/// Rotation matrix
void SetRotation(const Matrix& value);
///
/// Gets world matrix that describes transformation as a 4 by 4 matrix.
///
/// World matrix
Matrix GetWorld() const;
///
/// Gets world matrix that describes transformation as a 4 by 4 matrix.
///
/// World matrix
void GetWorld(Matrix& result) const;
public:
///
/// Adds translation to this transform.
///
/// The translation.
/// The result.
Transform Add(const Vector3& translation) const;
///
/// Adds transformation to this transform.
///
/// The other transformation.
/// The sum of two transformations.
Transform Add(const Transform& other) const;
///
/// Subtracts transformation from this transform.
///
/// The other transformation.
/// The different of two transformations.
Transform Subtract(const Transform& other) const;
///
/// Performs transformation of the given transform in local space to the world space of this transform.
///
/// The local space transformation.
/// The world space transformation.
Transform LocalToWorld(const Transform& other) const
{
Transform result;
LocalToWorld(other, result);
return result;
}
///
/// Performs transformation of the given transform in local space to the world space of this transform.
///
/// The local space transformation.
/// The world space transformation.
void LocalToWorld(const Transform& other, Transform& result) const;
///
/// Performs transformation of the given point in local space to the world space of this transform.
///
/// The local space point.
/// The world space point.
Vector3 LocalToWorld(const Vector3& point) const
{
Vector3 result;
LocalToWorld(point, result);
return result;
}
///
/// Performs transformation of the given vector in local space to the world space of this transform.
///
/// The local space vector.
/// The world space vector.
void LocalToWorldVector(const Vector3& vector, Vector3& result) const;
///
/// Performs transformation of the given vector in local space to the world space of this transform.
///
/// The local space vector.
/// The world space vector.
Vector3 LocalToWorldVector(const Vector3& vector) const
{
Vector3 result;
LocalToWorldVector(vector, result);
return result;
}
///
/// Performs transformation of the given point in local space to the world space of this transform.
///
/// The local space point.
/// The world space point.
void LocalToWorld(const Vector3& point, Vector3& result) const;
///
/// Performs transformation of the given transform in local space to the world space of this transform.
///
/// The world space transformation.
/// The local space transformation.
Transform WorldToLocal(const Transform& other) const
{
Transform result;
WorldToLocal(other, result);
return result;
}
///
/// Performs transformation of the given transform in world space to the local space of this transform.
///
/// The world space transformation.
/// The local space transformation.
void WorldToLocal(const Transform& other, Transform& result) const;
///
/// Performs transformation of the given point in world space to the local space of this transform.
///
/// The world space point.
/// The local space point.
void WorldToLocal(const Vector3& point, Vector3& result) const;
///
/// Performs transformation of the given point in world space to the local space of this transform.
///
/// The world space point.
/// The local space point.
Vector3 WorldToLocal(const Vector3& point) const
{
Vector3 result;
WorldToLocal(point, result);
return result;
}
///
/// Performs transformation of the given vector in world space to the local space of this transform.
///
/// The world space vector.
/// The local space vector.
void WorldToLocalVector(const Vector3& vector, Vector3& result) const;
///
/// Performs transformation of the given vector in world space to the local space of this transform.
///
/// The world space vector.
/// The local space vector.
Vector3 WorldToLocalVector(const Vector3& vector) const
{
Vector3 result;
WorldToLocalVector(vector, result);
return result;
}
public:
FORCE_INLINE Transform operator*(const Transform& other) const
{
return LocalToWorld(other);
}
FORCE_INLINE Transform operator+(const Transform& other) const
{
return Add(other);
}
FORCE_INLINE Transform operator-(const Transform& other) const
{
return Subtract(other);
}
FORCE_INLINE Transform operator+(const Vector3& other) const
{
return Add(other);
}
FORCE_INLINE bool operator==(const Transform& other) const
{
return Translation == other.Translation && Orientation == other.Orientation && Scale == other.Scale;
}
FORCE_INLINE bool operator!=(const Transform& other) const
{
return Translation != other.Translation || Orientation != other.Orientation || Scale != other.Scale;
}
static bool NearEqual(const Transform& a, const Transform& b)
{
return Vector3::NearEqual(a.Translation, b.Translation) && Quaternion::NearEqual(a.Orientation, b.Orientation) && Float3::NearEqual(a.Scale, b.Scale);
}
static bool NearEqual(const Transform& a, const Transform& b, float epsilon)
{
return Vector3::NearEqual(a.Translation, b.Translation, epsilon) && Quaternion::NearEqual(a.Orientation, b.Orientation, epsilon) && Float3::NearEqual(a.Scale, b.Scale, epsilon);
}
public:
Float3 GetRight() const;
Float3 GetLeft() const;
Float3 GetUp() const;
Float3 GetDown() const;
Float3 GetForward() const;
Float3 GetBackward() const;
public:
static Transform Lerp(const Transform& t1, const Transform& t2, float amount);
static void Lerp(const Transform& t1, const Transform& t2, float amount, Transform& result);
};
namespace Math
{
FORCE_INLINE static bool NearEqual(const Transform& a, const Transform& b)
{
return Transform::NearEqual(a, b);
}
}
template<>
struct TIsPODType
{
enum { Value = true };
};
DEFINE_DEFAULT_FORMATTING(Transform, "Translation:{0} Orientation:{1} Scale:{2}", v.Translation, v.Orientation, v.Scale);