| 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/BsCurveCache.h" | 
| 7 | #include "Math/BsVector3.h" | 
| 8 | #include "Math/BsVector2.h" | 
| 9 | #include "Math/BsQuaternion.h" | 
| 10 | #include "Allocators/BsPoolAlloc.h" | 
| 11 |  | 
| 12 | namespace bs | 
| 13 | { | 
| 14 | 	/** @addtogroup Animation-Internal | 
| 15 | 	 *  @{ | 
| 16 | 	 */ | 
| 17 |  | 
| 18 | 	/** Animation keyframe, represented as an endpoint of a cubic hermite spline. */ | 
| 19 | 	template <class T> | 
| 20 | 	struct TKeyframe | 
| 21 | 	{ | 
| 22 | 		T value; /**< Value of the key. */ | 
| 23 | 		T inTangent; /**< Input tangent (going from the previous key to this one) of the key. */ | 
| 24 | 		T outTangent; /**< Output tangent (going from this key to next one) of the key. */ | 
| 25 | 		float time; /**< Position of the key along the animation spline. */ | 
| 26 |  | 
| 27 | 		bool operator== (const TKeyframe<T>& rhs) const | 
| 28 | 		{ | 
| 29 | 			return (value == rhs.value && inTangent == rhs.inTangent && outTangent == rhs.outTangent && time == rhs.time); | 
| 30 | 		} | 
| 31 |  | 
| 32 | 		bool operator!= (const TKeyframe<T>& rhs) const | 
| 33 | 		{ | 
| 34 | 			return !operator==(rhs); | 
| 35 | 		} | 
| 36 | 	}; | 
| 37 |  | 
| 38 | 	/** Keyframe specialization for integers (no tangents). */ | 
| 39 | 	template <> | 
| 40 | 	struct BS_SCRIPT_EXPORT(m:Animation,n:KeyFrameInt,pl:true) TKeyframe<INT32> | 
| 41 | 	{ | 
| 42 | 		INT32 value; /**< Value of the key. */ | 
| 43 | 		float time; /**< Position of the key along the animation spline. */ | 
| 44 |  | 
| 45 | 		bool operator== (const TKeyframe<INT32>& rhs) const | 
| 46 | 		{ | 
| 47 | 			return (value == rhs.value && time == rhs.time); | 
| 48 | 		} | 
| 49 |  | 
| 50 | 		bool operator!= (const TKeyframe<INT32>& rhs) const | 
| 51 | 		{ | 
| 52 | 			return !operator==(rhs); | 
| 53 | 		} | 
| 54 | 	}; | 
| 55 |  | 
| 56 | 	template struct BS_SCRIPT_EXPORT(m:Animation,n:KeyFrame,pl:true) TKeyframe<float>; | 
| 57 | 	template struct BS_SCRIPT_EXPORT(m:Animation,n:KeyFrameVec3,pl:true) TKeyframe<Vector3>; | 
| 58 | 	template struct BS_SCRIPT_EXPORT(m:Animation,n:KeyFrameVec2,pl:true) TKeyframe<Vector2>; | 
| 59 | 	template struct BS_SCRIPT_EXPORT(m:Animation,n:KeyFrameQuat,pl:true) TKeyframe<Quaternion>; | 
| 60 |  | 
| 61 | 	/** | 
| 62 | 	 * Animation spline represented by a set of keyframes, each representing an endpoint of a cubic hermite curve. The | 
| 63 | 	 * spline can be evaluated at any time, and uses caching to speed up multiple sequential evaluations. | 
| 64 | 	 */ | 
| 65 | 	template <class T> | 
| 66 | 	class BS_CORE_EXPORT TAnimationCurve // Note: Curves are expected to be immutable for threading purposes | 
| 67 | 	{ | 
| 68 | 	public: | 
| 69 | 		typedef TKeyframe<T> KeyFrame; | 
| 70 |  | 
| 71 | 		TAnimationCurve() = default; | 
| 72 |  | 
| 73 | 		/** | 
| 74 | 		 * Creates a new animation curve. | 
| 75 | 		 *  | 
| 76 | 		 * @param[in]	keyframes	Keyframes to initialize the curve with. They must be sorted by time. | 
| 77 | 		 */ | 
| 78 | 		BS_SCRIPT_EXPORT() | 
| 79 | 		TAnimationCurve(const Vector<KeyFrame>& keyframes); | 
| 80 |  | 
| 81 | 		/** | 
| 82 | 		 * Evaluate the animation curve using caching. Caching can significantly speed of evaluation if the evaluation | 
| 83 | 		 * happens sequential order (which should be true for most curves). If evaluation is not happening in sequential | 
| 84 | 		 * order using the non-caching version of evaluate() might yield better performance. | 
| 85 | 		 * | 
| 86 | 		 * @param[in]	time			%Time to evaluate the curve at. | 
| 87 | 		 * @param[in]	cache			Cached data from previous requests that can be used for speeding up sequential calls | 
| 88 | 		 *								to this method. Caller should ensure to maintain a persistent instance of this data | 
| 89 | 		 *								for every animation using this curve in order to ensure cache is maintained. | 
| 90 | 		 * @param[in]	loop			If true the curve will loop when it goes past the end or beggining. Otherwise the | 
| 91 | 		 *								curve value will be clamped. | 
| 92 | 		 * @return						Interpolated value from the curve at provided time. | 
| 93 | 		 */ | 
| 94 | 		T evaluate(float time, const TCurveCache<T>& cache, bool loop = true) const; | 
| 95 |  | 
| 96 | 		/** | 
| 97 | 		 * Evaluate the animation curve at the specified time. If evaluating multiple values in a sequential order consider | 
| 98 | 		 * using the cached version of evaluate() for better performance. | 
| 99 | 		 * | 
| 100 | 		 * @param[in]	time	%Time to evaluate the curve at.		 | 
| 101 | 		 * @param[in]	loop	If true the curve will loop when it goes past the end or beggining. Otherwise the curve  | 
| 102 | 		 *						value will be clamped. | 
| 103 | 		 * @return				Interpolated value from the curve at provided time. | 
| 104 | 		 */ | 
| 105 | 		BS_SCRIPT_EXPORT() | 
| 106 | 		T evaluate(float time, bool loop = true) const; | 
| 107 |  | 
| 108 | 		/** | 
| 109 | 		 * Evaluates the integrated animation curve. (e.g. evaluating a curve containing velocity values will return | 
| 110 | 		 * a position). | 
| 111 | 		 * | 
| 112 | 		 * @param[in]	time				%Time to evaluate the curve at. | 
| 113 | 		 * @param[in]	integrationCache	Cache storing the values required for integration. Generated the first time | 
| 114 | 		 *									this method is called and re-used on subsequent calls. Caller must ensure to | 
| 115 | 		 *									use the cache only with the curve it was originally used on. Separate caches | 
| 116 | 		 *									need to be used for single and double integration evaluation. | 
| 117 | 		 * @return							Interpolated value from the curve at provided time. | 
| 118 | 		 */ | 
| 119 | 		T evaluateIntegrated(float time, const TCurveIntegrationCache<T>& integrationCache) const; | 
| 120 |  | 
| 121 | 		/** | 
| 122 | 		 * Evaluates the double integrated animation curve. (e.g. evaluating a curve containing acceleration values will | 
| 123 | 		 * return a position). | 
| 124 | 		 * | 
| 125 | 		 * @param[in]	time				%Time to evaluate the curve at. | 
| 126 | 		 * @param[in]	integrationCache	Cache storing the values required for integration. Generated the first time | 
| 127 | 		 *									this method is called and re-used on subsequent calls. Caller must ensure to | 
| 128 | 		 *									use the cache only with the curve it was originally used on. Separate caches | 
| 129 | 		 *									need to be used for single and double integration evaluation. | 
| 130 | 		 * @return							Interpolated value from the curve at provided time. | 
| 131 | 		 */ | 
| 132 | 		T evaluateIntegratedDouble(float time, const TCurveIntegrationCache<T>& integrationCache) const; | 
| 133 |  | 
| 134 | 		/** | 
| 135 | 		 * Evaluate the animation curve at the specified time and returns a new keyframe containing the evaluated value | 
| 136 | 		 * and tangents. | 
| 137 | 		 * | 
| 138 | 		 * @param[in]	time	%Time to evaluate the curve at.		 | 
| 139 | 		 * @param[in]	loop	If true the curve will loop when it goes past the end or beginning. Otherwise the curve  | 
| 140 | 		 *						value will be clamped. | 
| 141 | 		 * @return				Keyframe containing the interpolated value and tangents at provided time. | 
| 142 | 		 */ | 
| 143 | 		KeyFrame evaluateKey(float time, bool loop = true) const; | 
| 144 |  | 
| 145 | 		/**  | 
| 146 | 		 * Splits a piece of the animation curve into a separate animation curve.  | 
| 147 | 		 * | 
| 148 | 		 * @param[in]	start	Beginning time of the split curve. | 
| 149 | 		 * @param[in]	end		End time of the split curve. | 
| 150 | 		 * @return				New curve with data corresponding to the provided split times. | 
| 151 | 		 */ | 
| 152 | 		TAnimationCurve<T> split(float start, float end); | 
| 153 |  | 
| 154 | 		/**  | 
| 155 | 		 * Converts a normal curve into an additive curve. It is assumed the first keyframe in the curve is the reference | 
| 156 | 		 * key from which to generate the additive curve. Such curves can then be added on top of a curve containing | 
| 157 | 		 * reference keys. | 
| 158 | 		 */ | 
| 159 | 		void makeAdditive(); | 
| 160 |  | 
| 161 | 		/** Returns the time of the first and last keyframe in the curve. */ | 
| 162 | 		std::pair<float, float> getTimeRange() const; | 
| 163 |  | 
| 164 | 		/** Calculates the minimal and maximal value of the curve. */ | 
| 165 | 		std::pair<T, T> calculateRange() const; | 
| 166 |  | 
| 167 | 		/** Calculates the minimal and maximal value of the integrated curve. */ | 
| 168 | 		std::pair<T, T> calculateRangeIntegrated(const TCurveIntegrationCache<T>& cache) const; | 
| 169 |  | 
| 170 | 		/** Calculates the minimal and maximal value of the doubly integrated curve. */ | 
| 171 | 		std::pair<T, T> calculateRangeIntegratedDouble(const TCurveIntegrationCache<T>& cache) const; | 
| 172 |  | 
| 173 | 		/** Returns the length of the animation curve, from time zero to last keyframe. */ | 
| 174 | 		float getLength() const { return mEnd; } | 
| 175 |  | 
| 176 | 		/** Returns the total number of key-frames in the curve. */ | 
| 177 | 		UINT32 getNumKeyFrames() const { return (UINT32)mKeyframes.size(); } | 
| 178 |  | 
| 179 | 		/** Returns a keyframe at the specified index. */ | 
| 180 | 		const TKeyframe<T>& getKeyFrame(UINT32 idx) const { return mKeyframes[idx]; } | 
| 181 |  | 
| 182 | 		/** Returns a list of all keyframes in the curve. */ | 
| 183 | 		BS_SCRIPT_EXPORT(n:KeyFrames,pr:getter) | 
| 184 | 		const Vector<TKeyframe<T>>& getKeyFrames() const { return mKeyframes; } | 
| 185 |  | 
| 186 | 		bool operator== (const TAnimationCurve<T>& rhs) const; | 
| 187 | 		bool operator!= (const TAnimationCurve<T>& rhs) const { return !operator==(rhs); } | 
| 188 | 	private: | 
| 189 | 		friend struct RTTIPlainType<TAnimationCurve<T>>; | 
| 190 |  | 
| 191 | 		/**  | 
| 192 | 		 * Returns a pair of keys that can be used for interpolating to field the value at the provided time. This attempts | 
| 193 | 		 * to find keys using the cache first, and if not possible falls back to a full search. | 
| 194 | 		 * | 
| 195 | 		 * @param[in]	time			Time for which to find the relevant keys from. It is expected to be clamped to a | 
| 196 | 		 *								valid range within the curve. | 
| 197 | 		 * @param[in]	cache			Animation instance data holding the time to evaluate the curve at, and any cached | 
| 198 | 		 *								data from previous requests. Time is expected to be clamped to a valid range | 
| 199 | 		 *								within the curve. | 
| 200 | 		 * @param[out]	leftKey			Index of the key to interpolate from. | 
| 201 | 		 * @param[out]	rightKey		Index of the key to interpolate to. | 
| 202 | 		 */ | 
| 203 | 		void findKeys(float time, const TCurveCache<T>& cache, UINT32& leftKey, UINT32& rightKey) const; | 
| 204 |  | 
| 205 | 		/**  | 
| 206 | 		 * Returns a pair of keys that can be used for interpolating to field the value at the provided time.  | 
| 207 | 		 * | 
| 208 | 		 * @param[in]	time			Time for which to find the relevant keys from. It is expected to be clamped to a | 
| 209 | 		 *								valid range within the curve. | 
| 210 | 		 * @param[out]	leftKey			Index of the key to interpolate from. | 
| 211 | 		 * @param[out]	rightKey		Index of the key to interpolate to. | 
| 212 | 		 */ | 
| 213 | 		void findKeys(float time, UINT32& leftKey, UINT32& rightKey) const; | 
| 214 |  | 
| 215 | 		/** Returns a keyframe index nearest to the provided time. */ | 
| 216 | 		UINT32 findKey(float time); | 
| 217 |  | 
| 218 | 		/**  | 
| 219 | 		 * Calculates a key in-between the provided two keys.  | 
| 220 | 		 * | 
| 221 | 		 * @param[in]	lhs		Key to interpolate from. | 
| 222 | 		 * @param[in]	rhs		Key to interpolate to. | 
| 223 | 		 * @param[in]	time	Curve time to interpolate the keys at. | 
| 224 | 		 * @return				Interpolated key value. | 
| 225 | 		 */ | 
| 226 | 		KeyFrame evaluateKey(const KeyFrame& lhs, const KeyFrame& rhs, float time) const; | 
| 227 |  | 
| 228 | 		/** Creates a cache used for quick evaluation of single integrated curves. */ | 
| 229 | 		void buildIntegrationCache(const TCurveIntegrationCache<T>& cache) const; | 
| 230 |  | 
| 231 | 		/** Creates a cache used for quick evaluation of double integrated curves. */ | 
| 232 | 		void buildDoubleIntegrationCache(const TCurveIntegrationCache<T>& cache) const; | 
| 233 |  | 
| 234 | 		static const UINT32 CACHE_LOOKAHEAD; | 
| 235 |  | 
| 236 | 		Vector<KeyFrame> mKeyframes; | 
| 237 | 		float mStart = 0.0f; | 
| 238 | 		float mEnd = 0.0f; | 
| 239 | 		float mLength = 0.0f; | 
| 240 | 	}; | 
| 241 |  | 
| 242 | #ifdef BS_SBGEN | 
| 243 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:AnimationCurve) TAnimationCurve<float>; | 
| 244 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:Vector3Curve) TAnimationCurve<Vector3>; | 
| 245 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:Vector2Curve) TAnimationCurve<Vector2>; | 
| 246 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:QuaternionCurve) TAnimationCurve<Quaternion>; | 
| 247 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:IntegerCurve) TAnimationCurve<INT32>; | 
| 248 | #endif | 
| 249 |  | 
| 250 | 	/** Flags that describe an animation curve. */ | 
| 251 | 	enum BS_SCRIPT_EXPORT(n:AnimationCurveFlags) class AnimationCurveFlag | 
| 252 | 	{ | 
| 253 | 		/** | 
| 254 | 		 * If enabled, the curve was imported from an external file and not created within the engine. This will affect | 
| 255 | 		 * how are animation results applied to scene objects (with imported animations it is assumed the curve is | 
| 256 | 		 * animating bones and with in-engine curves it is assumed the curve is animating scene objects). | 
| 257 | 		 */ | 
| 258 | 		ImportedCurve = 1 << 0, | 
| 259 | 		/** Signifies the curve is used to animate between different frames within a morph channel. In range [0, 1]. */ | 
| 260 | 		MorphFrame = 1 << 1, | 
| 261 | 		/** Signifies the curve is used to adjust the weight of a morph channel. In range [0, 1]. */ | 
| 262 | 		MorphWeight = 1 << 2 | 
| 263 | 	}; | 
| 264 |  | 
| 265 | 	typedef Flags<AnimationCurveFlag> AnimationCurveFlags; | 
| 266 | 	BS_FLAGS_OPERATORS(AnimationCurveFlag); | 
| 267 |  | 
| 268 | 	/** An animation curve and its name. */ | 
| 269 | 	template <class T> | 
| 270 | 	struct TNamedAnimationCurve | 
| 271 | 	{ | 
| 272 | 		TNamedAnimationCurve() = default; | 
| 273 |  | 
| 274 | 		/** | 
| 275 | 		 * Constructs a new named animation curve. | 
| 276 | 		 *  | 
| 277 | 		 * @param[in]	name	Name of the curve. | 
| 278 | 		 * @param[in]	curve	Curve containing the animation data. | 
| 279 | 		 */ | 
| 280 | 		TNamedAnimationCurve(const String& name, const TAnimationCurve<T> curve) | 
| 281 | 			:name(name), curve(curve) | 
| 282 | 		{ } | 
| 283 |  | 
| 284 | 		/** | 
| 285 | 		 * Constructs a new named animation curve. | 
| 286 | 		 *  | 
| 287 | 		 * @param[in]	name	Name of the curve. | 
| 288 | 		 * @param[in]	flags	Flags that describe the animation curve. | 
| 289 | 		 * @param[in]	curve	Curve containing the animation data. | 
| 290 | 		 */ | 
| 291 | 		TNamedAnimationCurve(const String& name, AnimationCurveFlags flags, const TAnimationCurve<T> curve) | 
| 292 | 			:name(name), curve(curve) | 
| 293 | 		{ } | 
| 294 |  | 
| 295 | 		/** Name of the curve. */ | 
| 296 | 		String name; | 
| 297 |  | 
| 298 | 		/** Flags that describe the animation curve. */ | 
| 299 | 		AnimationCurveFlags flags; | 
| 300 |  | 
| 301 | 		/** Actual curve containing animation data. */ | 
| 302 | 		TAnimationCurve<T> curve; | 
| 303 | 	}; | 
| 304 |  | 
| 305 | #ifdef BS_SBGEN | 
| 306 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:NamedFloatCurve,pl:true) TNamedAnimationCurve<float>; | 
| 307 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:NamedVector3Curve,pl:true) TNamedAnimationCurve<Vector3>; | 
| 308 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:NamedVector2Curve,pl:true) TNamedAnimationCurve<Vector2>; | 
| 309 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:NamedQuaternionCurve,pl:true) TNamedAnimationCurve<Quaternion>; | 
| 310 | 	template class BS_SCRIPT_EXPORT(m:Animation,n:NamedIntegerCurve,pl:true) TNamedAnimationCurve<INT32>; | 
| 311 | #endif | 
| 312 |  | 
| 313 | 	/** @} */ | 
| 314 |  | 
| 315 | 	IMPLEMENT_GLOBAL_POOL(TAnimationCurve<float>, 32) | 
| 316 | } | 
| 317 |  |