My Project
animated.h
1 #pragma once
2 #include <utility>
3 #include <vector>
4 
5 #include "modelheaders.h"
6 #include "AnimInstanceBase.h"
7 #include "IAnimated.h"
8 
9 namespace ParaEngine
10 {
11  typedef std::pair<uint32, uint32> AnimRange;
12 
13  // global time for global sequences
14  extern int globalTime;
15 
16  /* Generic animated value class:
17  * T is the data type to animate
18  * D is the data type stored in the file (by default this is the same as T)
19  * Conv is a conversion object that defines T conv(D) to convert from D to T
20  * (by default this is an identity function)
21  */
22  template <class T, class D = T, class Conv = Identity<T> >
23  class Animated : public IAnimated
24  {
25  public:
26  Animated() :used(false), type(INTERPOLATION_LINEAR), seq(-1), globals(0) {};
28  bool used;
30  int type;
36  int seq;
38  int *globals;
39 
40  std::vector<AnimRange> ranges;
41  std::vector<int> times;
42  std::vector<T> data;
43  // for nonlinear interpolations:
44  std::vector<T> in, out;
45 
46  inline static float Absolute1(float v){ return fabs(v); };
47  inline static float Absolute1(double v){ return (float)abs(v); };
48  inline static float Absolute1(const Vector3& v){ return fabs(v.x) + fabs(v.y) + fabs(v.z); };
49  inline static float Absolute1(const Quaternion& v){ return fabs(v.x) + fabs(v.y) + fabs(v.z) + fabs(v.w); };
50  inline static float Absolute1(const Vector2& v){ return fabs(v.x) + fabs(v.y); };
51 
54  {
55  int nSize = (int)data.size();
56  if (used && nSize>0)
57  {
58  auto firstValue = data[0];
59  for (int i = 1; i < nSize; ++i)
60  {
61  if (data[i] != firstValue)
62  return true;
63  }
64  }
65  return false;
66  }
67 
69  void SetConstantKey(T key)
70  {
71  int nSize = (int)data.size();
72  for (int i = 0; i < nSize; ++i)
73  {
74  if (data[i] != key)
75  return;
76  }
77  used = false;
78  }
80  void SetConstantKey(T key, float fEpsilon)
81  {
82  int nSize = (int)data.size();
83  for (int i = 0; i < nSize; ++i)
84  {
85  if (Absolute1(data[i] - key) > fEpsilon)
86  return;
87  }
88  used = false;
89  }
90 
92  T getValue(int anim, int time)
93  {
94  if (type != INTERPOLATION_NONE || data.size() > 1) {
95  AnimRange range;
96 
97  // obtain a time value and a data range
98  if (seq >= 0) {
101  if (globals[seq] == 0)
102  time = 0;
103  else
104  time = globalTime % globals[seq];
105  range.first = 0;
106  range.second = (uint32)(data.size()) - 1;
107  }
108  else if (seq == -2)
109  {
111  range = ranges[0];
112  if (range.second > range.first)
113  time = times[range.first] + globalTime % (times[range.second] - times[range.first]);
114  else
115  time = 0;
116  }
117  else if (seq == -1){
119  if (anim >= 0 && anim < (int)ranges.size())
120  {
121  range = ranges[anim];
122  }
123  else
124  {
125  // default value
126  return data[0];
127  }
128  // there is a chance that time = times[times.size()-1]
129  //time %= times[times.size()-1]; // I think this might not be necessary?
130  }
131  if (time >= times[range.second])
132  {
133  return data[range.second];
134  }
135  else if (range.first != range.second && time > times[range.first])
136  {
137  size_t pos = range.first; // this can be 0.
138  {
155  int nStart = (int)range.first;
156  int nEnd = (int)range.second - 1;
157  while (true)
158  {
159  if (nStart >= nEnd)
160  { // if no item left.
161  pos = nStart;
162  break;
163  }
164  int nMid = (nStart + nEnd) / 2;
165  int startP = (times[nMid]);
166  int endP = (times[nMid + 1]);
167 
168  if (startP <= time && time < endP)
169  { // if (middle item is target)
170  pos = nMid;
171  break;
172  }
173  else if (time < startP)
174  { // if (target < middle item)
175  nEnd = nMid;
176  }
177  else if (time >= endP)
178  { // if (target >= middle item)
179  nStart = nMid + 1;
180  }
181  }// while(nStart<=nEnd)
182  }
183  int t1 = times[pos];
184  int t2 = times[pos + 1];
185  float r = (time - t1) / (float)(t2 - t1);
186 
187  if (type == INTERPOLATION_LINEAR)
188  return interpolate<T>(r, data[pos], data[pos + 1]);
189  else if (type == INTERPOLATION_LINEAR_CROSSFRAME)
190  {
191  if ((t2 - t1) <= 34) // if the two key frames are less than 33 milliseconds away, do not interpolate, instead use the first one.
192  return data[pos];
193  else
194  return interpolate<T>(r, data[pos], data[pos + 1]);
195  }
196  else {
197  // INTERPOLATION_HERMITE is only used in cameras afraid?
198  // return interpolateHermite<T>(r,data[pos],data[pos+1],in[pos],out[pos]);
199  // TODO: use linear interpolation anyway
200  return interpolate<T>(r, data[pos], data[pos + 1]);
201  }
202  }
203  else{
204  return data[range.first];
205  }
206  }
207  else {
208  // default value
209  return data[0];
210  }
211  }
212 
213  // default value
214  T getDefaultValue()
215  {
216  return data[0];
217  }
218 
231  T getValue(int nCurrentAnim, int currentFrame, int nBlendingAnim, int blendingFrame, float blendingFactor)
232  {
233  if (blendingFactor == 0.0f)
234  {
235  return getValue(nCurrentAnim, currentFrame);
236  }
237  else
238  {
239  if (blendingFactor == 1.0f)
240  {
241  return getValue(nBlendingAnim, blendingFrame);
242  }
243  else
244  {
245  T v1 = getValue(nCurrentAnim, currentFrame);
246  T v2 = getValue(nBlendingAnim, blendingFrame);
247 
248  return interpolate<T>(blendingFactor, v1, v2);
249  }
250  }
251  }
252 
254  T getValue(const AnimIndex& Index)
255  {
256  return (Index.Provider == 0) ? getValue(Index.nIndex, Index.nCurrentFrame) : getDefaultValue();
257  }
258 
260  T getValue(const AnimIndex& CurrentAnim, const AnimIndex& BlendingAnim, float blendingFactor)
261  {
262  if (blendingFactor == 0.0f)
263  {
264  return getValue(CurrentAnim);
265  }
266  else
267  {
268  if (blendingFactor == 1.0f)
269  {
270  return getValue(BlendingAnim);
271  }
272  else
273  {
274  T v1 = getValue(CurrentAnim);
275  T v2 = getValue(BlendingAnim);
276 
277  return interpolate<T>(blendingFactor, v1, v2);
278  }
279  }
280  }
281 
282  static T BlendValues(const T& currentValue, const T& blendingValue, float blendingFactor)
283  {
284  if (blendingFactor == 0.0f)
285  {
286  return currentValue;
287  }
288  else
289  {
290  if (blendingFactor == 1.0f)
291  {
292  return blendingValue;
293  }
294  else
295  {
296  return interpolate<T>(blendingFactor, currentValue, blendingValue);
297  }
298  }
299  }
300 
301  void SetRangeByAnimIndex(int nAnimIndex, const AnimRange& range)
302  {
303  if ((int)ranges.size() <= nAnimIndex)
304  ranges.resize(nAnimIndex + 1, range);
305  else
306  ranges[nAnimIndex] = range;
307  }
308  void AppendKey(int time_, const T& data_)
309  {
310  times.push_back(time_);
311  data.push_back(data_);
312  }
313 
314  void UpdateLastKey(int time_, const T& data_)
315  {
316  int KeyCount = GetKeyNum();
317  if (KeyCount > 0)
318  {
319  times[KeyCount - 1] = time_;
320  data[KeyCount - 1] = data_;
321  }
322  else
323  AppendKey(time_, data_);
324  }
325  int GetKeyNum()
326  {
327  return (int)data.size();
328  }
329 
335  void CompressKeyLinear(float fEpsilon)
336  {
337  Animated <T>c_data; // compressed data
338 
339  // add initial key
340  int nKeyCount, nFirstKeyIndex, nLastKeyIndex, i, curtime;
341  T curkey;
342  nLastKeyIndex = nFirstKeyIndex = c_data.GetKeyNum();
343  curkey = data[0];
344 
345  c_data.AppendKey(times[0], curkey);
346 
347  T lastKey = curkey;
348  T lastlastKey = lastKey;
349 
350  // output animation keys
351  nKeyCount = GetKeyNum();
352 
353  for (i = 1; i < nKeyCount; ++i)
354  {
355  curtime = times[i];
356  curkey = data[i];
357 
358  T predicatedKey = lastKey * 2 - lastlastKey;
359  T delta = (curkey - predicatedKey);
360 
361 
362  if (Absolute1(delta) >= fEpsilon)
363  {
364  // add new key
365  if (nLastKeyIndex == nFirstKeyIndex)
366  {
367  // if this is the second key, modify the first key's time to animSequence.timeStart, and insert a constant key if necessary.
368  int nKeyIndex = c_data.GetKeyNum() - 1;
369  int nTime = c_data.times[nKeyIndex];
370  c_data.times[nKeyIndex] = 0;
371  if (i > 2)
372  {
373  c_data.AppendKey(nTime, lastKey);
374  ++nLastKeyIndex;
375  }
376  }
377  c_data.AppendKey(curtime, curkey);
378  predicatedKey = curkey;
379  ++nLastKeyIndex;
380  }
381  else
382  {
383  // override the last key
384  c_data.UpdateLastKey(curtime, predicatedKey);
385  }
386 
387  lastlastKey = lastKey;
388  lastKey = predicatedKey;
389  }
390  if (nFirstKeyIndex == nLastKeyIndex)
391  c_data.UpdateLastKey(0, lastKey);
392  c_data.SetRangeByAnimIndex(0, AnimRange(nFirstKeyIndex, nLastKeyIndex));
393 
395  // copy back
396  times = c_data.times;
397  data = c_data.data;
398  SetRangeByAnimIndex(0, AnimRange(nFirstKeyIndex, nLastKeyIndex));
399  }
400 
401  virtual int GetNumKeys()
402  {
403  return (int)data.size();
404  }
405 
406  virtual void SetNumKeys(int nKeyCount)
407  {
408  if (GetNumKeys() != nKeyCount)
409  {
410  data.resize(nKeyCount);
411  times.resize(nKeyCount);
412  }
413  }
414 
415  virtual void SetTime(int nIndex, int nTime)
416  {
417  if (nIndex < (int)times.size())
418  times[nIndex] = nTime;
419  }
420 
421  virtual int GetTime(int nIndex)
422  {
423  return (nIndex < (int)times.size()) ? times[nIndex] : 0;
424  }
425  };
426 
428 
429 }
void CompressKeyLinear(float fEpsilon)
if multiple adjacent keys can be linearly interpolated and get an error smaller than fEpsilon...
Definition: animated.h:335
bool CheckIsAnimated()
check if all key are equal
Definition: animated.h:53
int * globals
a reference to the global sequence object which is an array of time ranges for global sequences...
Definition: animated.h:38
T getValue(int anim, int time)
this function will return the interpolated animation vector at the specified anim id and frame number...
Definition: animated.h:92
different physics engine has different winding order.
Definition: EventBinding.h:32
int seq
Definition: animated.h:36
Implementation of a Quaternion, i.e.
Definition: ParaQuaternion.h:10
Standard 3-dimensional vector.
Definition: ParaVector3.h:16
Standard 2-dimensional vector.
Definition: ParaVector2.h:16
Definition: animated.h:23
T getValue(const AnimIndex &Index)
it accept anim index of both local and external animation
Definition: animated.h:254
bool used
whether it is a constant value(not animated).
Definition: animated.h:26
base class for AnimatedVariable.
Definition: IAnimated.h:18
void SetConstantKey(T key)
if all animated values equals to the key, this animation will be set unused
Definition: animated.h:69
void SetConstantKey(T key, float fEpsilon)
if all animated values are very close to a given key, this animation will be set unused ...
Definition: animated.h:80
it presents a given in bone animation providers or parax local model bone animation pools ...
Definition: AnimInstanceBase.h:13
virtual void SetTime(int nIndex, int nTime)
only applied to Animated attribute
Definition: animated.h:415
T getValue(const AnimIndex &CurrentAnim, const AnimIndex &BlendingAnim, float blendingFactor)
it accept anim index of both local and external animation
Definition: animated.h:260
virtual void SetNumKeys(int nKeyCount)
get set the total number of animated keys.
Definition: animated.h:406
virtual int GetNumKeys()
get total number of animated keys.
Definition: animated.h:401
T getValue(int nCurrentAnim, int currentFrame, int nBlendingAnim, int blendingFrame, float blendingFactor)
get value with motion blending with a specified blending frame.
Definition: animated.h:231
int type
interpolation of type Interpolations
Definition: animated.h:30