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 "Animation/BsAnimationCurve.h"
7
8namespace bs
9{
10 /** @addtogroup Animation
11 * @{
12 */
13
14 /** Contains information and helper methods for various curve types. */
15 template<class T>
16 struct TCurveProperties {};
17
18 template<>
19 struct TCurveProperties<float>
20 {
21 enum { NumComponents = 1 };
22 static float getZero() { return 0.0f; }
23 static float getComponent(float val, UINT32 i) { return val; }
24 static void setComponent(float& val, UINT32 i, float newVal) { val = newVal; }
25 };
26
27 template<>
28 struct TCurveProperties<INT32>
29 {
30 enum { NumComponents = 1 };
31 static INT32 getZero() { return 0; }
32 };
33
34 template<>
35 struct TCurveProperties<Vector2>
36 {
37 enum { NumComponents = 2 };
38 static Vector2 getZero() { return Vector2::ZERO; }
39 static float getComponent(const Vector2& val, UINT32 i) { return val[i]; }
40 static void setComponent(Vector2& val, UINT32 i, float newVal) { val[i] = newVal; }
41 };
42
43 template<>
44 struct TCurveProperties<Vector3>
45 {
46 enum { NumComponents = 3 };
47 static Vector3 getZero() { return Vector3::ZERO; }
48 static float getComponent(const Vector3& val, UINT32 i) { return val[i]; }
49 static void setComponent(Vector3& val, UINT32 i, float newVal) { val[i] = newVal; }
50 };
51
52 template<>
53 struct TCurveProperties<Quaternion>
54 {
55 enum { NumComponents = 4 };
56 static Quaternion getZero() { return Quaternion::ZERO; }
57 static float getComponent(const Quaternion& val, UINT32 i) { return val[i]; }
58 static void setComponent(Quaternion& val, UINT32 i, float newVal) { val[i] = newVal; }
59 };
60
61 /** Helper class for dealing with animations, animation clips and curves. */
62 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Animation) AnimationUtility
63 {
64 public:
65 /**
66 * Wraps or clamps the provided time value between the provided range.
67 *
68 * @param[in,out] time Time value to wrap/clamp.
69 * @param[in] start Start of the range.
70 * @param[in] end End of the range.
71 * @param[in] loop If true the value will be wrapped, otherwise clamped to range.
72 */
73 static void wrapTime(float& time, float start, float end, bool loop);
74
75 /** Converts a curve in euler angles (in degrees) into a curve using quaternions. */
76 BS_SCRIPT_EXPORT()
77 static SPtr<TAnimationCurve<Quaternion>> eulerToQuaternionCurve(const SPtr<TAnimationCurve<Vector3>>& eulerCurve,
78 EulerAngleOrder order = EulerAngleOrder::YXZ);
79
80 /** Converts a curve in quaternions into a curve using euler angles (in degrees). */
81 BS_SCRIPT_EXPORT()
82 static SPtr<TAnimationCurve<Vector3>> quaternionToEulerCurve(const SPtr<TAnimationCurve<Quaternion>>& quatCurve);
83
84 /** Splits a Vector3 curve into three individual curves, one for each component. */
85 BS_SCRIPT_EXPORT()
86 static Vector<SPtr<TAnimationCurve<float>>> splitCurve3D(const SPtr<TAnimationCurve<Vector3>>& compoundCurve);
87
88 /** Combines three single component curves into a Vector3 curve. */
89 BS_SCRIPT_EXPORT()
90 static SPtr<TAnimationCurve<Vector3>> combineCurve3D(const Vector<SPtr<TAnimationCurve<float>>>& curveComponents);
91
92 /** Splits a Vector2 curve into two individual curves, one for each component. */
93 BS_SCRIPT_EXPORT()
94 static Vector<SPtr<TAnimationCurve<float>>> splitCurve2D(const SPtr<TAnimationCurve<Vector2>>& compoundCurve);
95
96 /** Combines two single component curves into a Vector2 curve. */
97 BS_SCRIPT_EXPORT()
98 static SPtr<TAnimationCurve<Vector2>> combineCurve2D(const Vector<SPtr<TAnimationCurve<float>>>& curveComponents);
99
100 /** Splits a multi-component curve into multiple individual curves, one for each component. */
101 template<class T>
102 static void splitCurve(const TAnimationCurve<T>& compoundCurve,
103 TAnimationCurve<float> (&output)[TCurveProperties<T>::NumComponents]);
104
105 /** Combines multiple single component curves into a multi-component curve. */
106 template<class T>
107 static void combineCurve(const TAnimationCurve<float> (&curveComponents)[TCurveProperties<T>::NumComponents],
108 TAnimationCurve<T>& output);
109 /**
110 * Calculates the total range covered by a set of curves.
111 *
112 * @param[in] curves Curves to calculate range for.
113 * @param[out] xMin Minimum time value present in the curves.
114 * @param[out] xMax Maximum time value present in the curves.
115 * @param[out] yMin Minimum curve value present in the curves.
116 * @param[out] yMax Maximum curve value present in the curves.
117 */
118 static void calculateRange(const Vector<TAnimationCurve<float>>& curves,
119 float& xMin, float& xMax, float& yMin, float& yMax);
120
121 /** @copydoc calculateRange(const Vector<TAnimationCurve<float>>&, float&, float&, float&, float&) */
122 BS_SCRIPT_EXPORT()
123 static void calculateRange(const Vector<SPtr<TAnimationCurve<float>>>& curves,
124 float& xMin, float& xMax, float& yMin, float& yMax);
125
126 /** Scales all curve values and tangents by the specified scale factor. */
127 template<class T>
128 static TAnimationCurve<T> scaleCurve(const TAnimationCurve<T>& curve, float factor);
129
130 /** Adds a time offset to all keyframes in the provided curve. */
131 template<class T>
132 static TAnimationCurve<T> offsetCurve(const TAnimationCurve<T>& curve, float offset);
133
134 /** Updates the provided list of keyframes by automatically calculating their tangents. */
135 template<class T>
136 static void calculateTangents(Vector<TKeyframe<T>>& keyframes);
137 };
138
139 /** Type of tangent on a keyframe in an animation curve. */
140 enum class BS_SCRIPT_EXPORT(m:Animation) TangentType
141 {
142 In = 1 << 0,
143 Out = 1 << 1
144 };
145
146 /**
147 * Flags that are used for describing how are tangents calculated for a specific keyframe in an animation curve.
148 * Modes for "in" and "out" tangents can be combined.
149 */
150 enum class BS_SCRIPT_EXPORT(m:Animation,n:TangentMode) TangentModeBits
151 {
152 /** Both tangents are calculated automatically based on the two surrounding keyframes. */
153 Auto = 0,
154 /** Left tangent is calculated automatically based on the two surrounding keyframes. */
155 InAuto = (int)TangentType::In | 1 << 2,
156 /** Left tangent is manually adjusted by the user. */
157 InFree = (int)TangentType::In | 1 << 3,
158 /** Tangent is calculated automatically based on the previous keyframe. */
159 InLinear = (int)TangentType::In | 1 << 4,
160 /** Tangent is infinite, ensuring there is a instantaneus jump between previous and current keyframe value. */
161 InStep = (int)TangentType::In | 1 << 5,
162 /** Right tangents are calculated automatically based on the two surrounding keyframes. */
163 OutAuto = (int)TangentType::Out | 1 << 6,
164 /** Right tangent is manually adjusted by the user. */
165 OutFree = (int)TangentType::Out | 1 << 7,
166 /** Tangent is calculated automatically based on the next keyframe. */
167 OutLinear = (int)TangentType::Out | 1 << 8,
168 /** Tangent is infinite, ensuring there is a instantaneus jump between current and next keyframe value. */
169 OutStep = (int)TangentType::Out | 1 << 9,
170 /** Both tangents are manually adjusted by the user. */
171 Free = 1 << 10,
172 };
173
174 typedef Flags<TangentModeBits> TangentMode;
175 BS_FLAGS_OPERATORS(TangentModeBits)
176
177 /* Structure containing a reference to a keyframe as a curve index, and a keyframe index within that curve. */
178 struct BS_SCRIPT_EXPORT(pl:true,m:Animation) KeyframeRef
179 {
180 KeyframeRef() = default;
181 KeyframeRef(INT32 curveIdx, INT32 keyIdx)
182 :curveIdx(curveIdx), keyIdx(keyIdx)
183 { }
184
185 INT32 curveIdx = 0;
186 INT32 keyIdx = 0;
187 };
188
189 /** Structure containing a reference to a keyframe tangent, as a keyframe reference and type of the tangent. */
190 struct BS_SCRIPT_EXPORT(pl:true,m:Animation) TangentRef
191 {
192 TangentRef() = default;
193 TangentRef(KeyframeRef keyframeRef, TangentType type)
194 :keyframeRef(keyframeRef), type(type)
195 { }
196
197 KeyframeRef keyframeRef;
198 TangentType type = TangentType::In;
199 };
200
201 /** @} */
202}