Add Spline
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Engine/Core/Math/Quaternion.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
|
||||
namespace AnimationUtils
|
||||
{
|
||||
@@ -40,6 +41,12 @@ namespace AnimationUtils
|
||||
return Quaternion::Identity;
|
||||
}
|
||||
|
||||
template<>
|
||||
FORCE_INLINE Transform GetZero<Transform>()
|
||||
{
|
||||
return Transform::Identity;
|
||||
}
|
||||
|
||||
template<>
|
||||
FORCE_INLINE Color GetZero<Color>()
|
||||
{
|
||||
@@ -66,6 +73,16 @@ namespace AnimationUtils
|
||||
Quaternion::Slerp(a, b, oneThird, result);
|
||||
}
|
||||
|
||||
template<>
|
||||
FORCE_INLINE void GetTangent<Transform>(const Transform& a, const Transform& b, float length, Transform& result)
|
||||
{
|
||||
const float oneThird = 1.0f / 3.0f;
|
||||
const float oneThirdLength = length * oneThird;
|
||||
result.Translation = a.Translation + b.Translation * oneThirdLength;
|
||||
Quaternion::Slerp(a.Orientation, b.Orientation, oneThird, result.Orientation);
|
||||
result.Scale = a.Scale + b.Scale * oneThirdLength;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
FORCE_INLINE static void Interpolate(const T& a, const T& b, float alpha, T& result)
|
||||
{
|
||||
@@ -203,4 +220,12 @@ namespace AnimationUtils
|
||||
Quaternion::Slerp(p12, p23, alpha, p123);
|
||||
Quaternion::Slerp(p012, p123, alpha, result);
|
||||
}
|
||||
|
||||
template<>
|
||||
void Bezier<Transform>(const Transform& p0, const Transform& p1, const Transform& p2, const Transform& p3, float alpha, Transform& result)
|
||||
{
|
||||
Bezier<Vector3>(p0.Translation, p1.Translation, p2.Translation, p3.Translation, alpha, result.Translation);
|
||||
Bezier<Quaternion>(p0.Orientation, p1.Orientation, p2.Orientation, p3.Orientation, alpha, result.Orientation);
|
||||
Bezier<Vector3>(p0.Scale, p1.Scale, p2.Scale, p3.Scale, alpha, result.Scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
@@ -338,6 +339,7 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// A single keyframe that can be injected into linear curve.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Keyframe : IComparable, IComparable<Keyframe>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -586,6 +588,7 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// A single keyframe that can be injected into Bezier curve.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Keyframe : IComparable, IComparable<Keyframe>
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -52,6 +52,11 @@ public:
|
||||
{
|
||||
result = a;
|
||||
}
|
||||
|
||||
bool operator==(const StepCurveKeyframe& other) const
|
||||
{
|
||||
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value);
|
||||
}
|
||||
} PACK_END();
|
||||
|
||||
/// <summary>
|
||||
@@ -97,6 +102,11 @@ public:
|
||||
result.Time = a.Time + (b.Time - a.Time) * alpha;
|
||||
AnimationUtils::Interpolate(a.Value, b.Value, alpha, result.Value);
|
||||
}
|
||||
|
||||
bool operator==(const LinearCurveKeyframe& other) const
|
||||
{
|
||||
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value);
|
||||
}
|
||||
} PACK_END();
|
||||
|
||||
/// <summary>
|
||||
@@ -164,6 +174,11 @@ public:
|
||||
result.TangentIn /= length;
|
||||
result.TangentOut = result.TangentIn;
|
||||
}
|
||||
|
||||
bool operator==(const HermiteCurveKeyframe& other) const
|
||||
{
|
||||
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value) && Math::NearEqual(TangentIn, other.TangentIn) && Math::NearEqual(TangentOut, other.TangentOut);
|
||||
}
|
||||
} PACK_END();
|
||||
|
||||
/// <summary>
|
||||
@@ -240,6 +255,11 @@ public:
|
||||
result.TangentIn = a.TangentOut;
|
||||
result.TangentOut = b.TangentIn;
|
||||
}
|
||||
|
||||
bool operator==(const BezierCurveKeyframe& other) const
|
||||
{
|
||||
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value) && Math::NearEqual(TangentIn, other.TangentIn) && Math::NearEqual(TangentOut, other.TangentOut);
|
||||
}
|
||||
} PACK_END();
|
||||
|
||||
// @formatter:on
|
||||
@@ -708,6 +728,30 @@ public:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FORCE_INLINE KeyFrame& operator[](int32 index)
|
||||
{
|
||||
return _keyframes[index];
|
||||
}
|
||||
|
||||
FORCE_INLINE const KeyFrame& operator[](int32 index) const
|
||||
{
|
||||
return _keyframes[index];
|
||||
}
|
||||
|
||||
bool operator==(const Curve& other) const
|
||||
{
|
||||
if (_keyframes.Count() != other._keyframes.Count())
|
||||
return false;
|
||||
for (int32 i = 0; i < _keyframes.Count(); i++)
|
||||
{
|
||||
if (!(_keyframes[i] == other._keyframes[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
171
Source/Engine/Animations/CurveSerialization.h
Normal file
171
Source/Engine/Animations/CurveSerialization.h
Normal file
@@ -0,0 +1,171 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Curve.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
|
||||
// @formatter:off
|
||||
|
||||
namespace Serialization
|
||||
{
|
||||
// StepCurveKeyframe
|
||||
|
||||
template<class T>
|
||||
inline bool ShouldSerialize(const StepCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
if (!otherObj)
|
||||
return true;
|
||||
const auto other = (const StepCurveKeyframe<T>*)otherObj;
|
||||
return !(v == *other);
|
||||
}
|
||||
template<class T>
|
||||
inline void Serialize(ISerializable::SerializeStream& stream, const StepCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
stream.StartObject();
|
||||
stream.JKEY("Time");
|
||||
Serialize(stream, v.Time, nullptr);
|
||||
stream.JKEY("Value");
|
||||
Serialize(stream, v.Value, nullptr);
|
||||
stream.EndObject();
|
||||
}
|
||||
template<class T>
|
||||
inline void Deserialize(ISerializable::DeserializeStream& stream, StepCurveKeyframe<T>& v, ISerializeModifier* modifier)
|
||||
{
|
||||
DESERIALIZE_MEMBER(Time, v.Time);
|
||||
DESERIALIZE_MEMBER(Value, v.Value);
|
||||
}
|
||||
|
||||
// LinearCurveKeyframe
|
||||
|
||||
template<class T>
|
||||
inline bool ShouldSerialize(const LinearCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
if (!otherObj)
|
||||
return true;
|
||||
const auto other = (const LinearCurveKeyframe<T>*)otherObj;
|
||||
return !(v == *other);
|
||||
}
|
||||
template<class T>
|
||||
inline void Serialize(ISerializable::SerializeStream& stream, const LinearCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
stream.StartObject();
|
||||
stream.JKEY("Time");
|
||||
Serialize(stream, v.Time, nullptr);
|
||||
stream.JKEY("Value");
|
||||
Serialize(stream, v.Value, nullptr);
|
||||
stream.EndObject();
|
||||
}
|
||||
template<class T>
|
||||
inline void Deserialize(ISerializable::DeserializeStream& stream, LinearCurveKeyframe<T>& v, ISerializeModifier* modifier)
|
||||
{
|
||||
DESERIALIZE_MEMBER(Time, v.Time);
|
||||
DESERIALIZE_MEMBER(Value, v.Value);
|
||||
}
|
||||
|
||||
// HermiteCurveKeyframe
|
||||
|
||||
template<class T>
|
||||
inline bool ShouldSerialize(const HermiteCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
if (!otherObj)
|
||||
return true;
|
||||
const auto other = (const HermiteCurveKeyframe<T>*)otherObj;
|
||||
return !(v == *other);
|
||||
}
|
||||
template<class T>
|
||||
inline void Serialize(ISerializable::SerializeStream& stream, const HermiteCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
stream.StartObject();
|
||||
stream.JKEY("Time");
|
||||
Serialize(stream, v.Time, nullptr);
|
||||
stream.JKEY("Value");
|
||||
Serialize(stream, v.Value, nullptr);
|
||||
stream.JKEY("TangentIn");
|
||||
Serialize(stream, v.TangentIn, nullptr);
|
||||
stream.JKEY("TangentOut");
|
||||
Serialize(stream, v.TangentOut, nullptr);
|
||||
stream.EndObject();
|
||||
}
|
||||
template<class T>
|
||||
inline void Deserialize(ISerializable::DeserializeStream& stream, HermiteCurveKeyframe<T>& v, ISerializeModifier* modifier)
|
||||
{
|
||||
DESERIALIZE_MEMBER(Time, v.Time);
|
||||
DESERIALIZE_MEMBER(Value, v.Value);
|
||||
DESERIALIZE_MEMBER(TangentIn, v.TangentIn);
|
||||
DESERIALIZE_MEMBER(TangentOut, v.TangentOut);
|
||||
}
|
||||
|
||||
// BezierCurveKeyframe
|
||||
|
||||
template<class T>
|
||||
inline bool ShouldSerialize(const BezierCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
if (!otherObj)
|
||||
return true;
|
||||
const auto other = (const BezierCurveKeyframe<T>*)otherObj;
|
||||
return !(v == *other);
|
||||
}
|
||||
template<class T>
|
||||
inline void Serialize(ISerializable::SerializeStream& stream, const BezierCurveKeyframe<T>& v, const void* otherObj)
|
||||
{
|
||||
stream.StartObject();
|
||||
stream.JKEY("Time");
|
||||
Serialize(stream, v.Time, nullptr);
|
||||
stream.JKEY("Value");
|
||||
Serialize(stream, v.Value, nullptr);
|
||||
stream.JKEY("TangentIn");
|
||||
Serialize(stream, v.TangentIn, nullptr);
|
||||
stream.JKEY("TangentOut");
|
||||
Serialize(stream, v.TangentOut, nullptr);
|
||||
stream.EndObject();
|
||||
}
|
||||
template<class T>
|
||||
inline void Deserialize(ISerializable::DeserializeStream& stream, BezierCurveKeyframe<T>& v, ISerializeModifier* modifier)
|
||||
{
|
||||
DESERIALIZE_MEMBER(Time, v.Time);
|
||||
DESERIALIZE_MEMBER(Value, v.Value);
|
||||
DESERIALIZE_MEMBER(TangentIn, v.TangentIn);
|
||||
DESERIALIZE_MEMBER(TangentOut, v.TangentOut);
|
||||
}
|
||||
|
||||
// Curve
|
||||
|
||||
template<class T, typename KeyFrame>
|
||||
inline bool ShouldSerialize(const Curve<T, KeyFrame>& v, const void* otherObj)
|
||||
{
|
||||
if (!otherObj)
|
||||
return true;
|
||||
const auto other = (const Curve<T, KeyFrame>*)otherObj;
|
||||
return !(v == *other);
|
||||
}
|
||||
template<class T, typename KeyFrame>
|
||||
inline void Serialize(ISerializable::SerializeStream& stream, const Curve<T, KeyFrame>& v, const void* otherObj)
|
||||
{
|
||||
stream.StartObject();
|
||||
stream.JKEY("Keyframes");
|
||||
stream.StartArray();
|
||||
for (auto& k : v.GetKeyframes())
|
||||
Serialize(stream, k, nullptr);
|
||||
stream.EndArray();
|
||||
stream.EndObject();
|
||||
}
|
||||
template<class T, typename KeyFrame>
|
||||
inline void Deserialize(ISerializable::DeserializeStream& stream, Curve<T, KeyFrame>& v, ISerializeModifier* modifier)
|
||||
{
|
||||
if (!stream.IsObject())
|
||||
return;
|
||||
const auto mKeyframes = SERIALIZE_FIND_MEMBER(stream, "Keyframes");
|
||||
if (mKeyframes != stream.MemberEnd())
|
||||
{
|
||||
const auto& keyframesArray = mKeyframes->value.GetArray();
|
||||
auto& keyframes = v.GetKeyframes();
|
||||
keyframes.Resize(keyframesArray.Size());
|
||||
for (rapidjson::SizeType i = 0; i < keyframesArray.Size(); i++)
|
||||
Deserialize(keyframesArray[i], keyframes[i], modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @formatter:on
|
||||
Reference in New Issue
Block a user