| 1 | /*  | 
|---|
| 2 |    orxonox - the future of 3D-vertical-scrollers | 
|---|
| 3 |  | 
|---|
| 4 |    Copyright (C) 2004 orx | 
|---|
| 5 |  | 
|---|
| 6 |    This program is free software; you can redistribute it and/or modify | 
|---|
| 7 |    it under the terms of the GNU General Public License as published by | 
|---|
| 8 |    the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 9 |    any later version. | 
|---|
| 10 |  | 
|---|
| 11 |    ### File Specific: | 
|---|
| 12 |    main-programmer: Benjamin Grauer | 
|---|
| 13 |    co-programmer: ... | 
|---|
| 14 | */ | 
|---|
| 15 |  | 
|---|
| 16 |  | 
|---|
| 17 | /*!  | 
|---|
| 18 |     \file animation.h | 
|---|
| 19 |     A Set of functions to animate some floats inside of an Object | 
|---|
| 20 |  | 
|---|
| 21 |     We apologize, that most part of the Function-Definitions are located  | 
|---|
| 22 |     inside this h-file, but this must be like this because it is a template | 
|---|
| 23 |     function. | 
|---|
| 24 | */ | 
|---|
| 25 |  | 
|---|
| 26 | #ifndef _ANIMATION_H | 
|---|
| 27 | #define _ANIMATION_H | 
|---|
| 28 |  | 
|---|
| 29 | #include "list.h" | 
|---|
| 30 | #include "base_object.h" | 
|---|
| 31 |  | 
|---|
| 32 | // FORWARD DEFINITION | 
|---|
| 33 |  | 
|---|
| 34 | #define DELTA_X 0.05  //!< the percentag of the distance that doesnt have to be done by neg_exp (asymptotical) ~ maschinendelta | 
|---|
| 35 |  | 
|---|
| 36 | typedef enum ANIM_FUNCTION {ANIM_CONSTANT, | 
|---|
| 37 |                             ANIM_LINEAR, | 
|---|
| 38 |                             ANIM_SINE, | 
|---|
| 39 |                             ANIM_COSINE, | 
|---|
| 40 |                             ANIM_EXP, | 
|---|
| 41 |                             ANIM_NEG_EXP, | 
|---|
| 42 |                             ANIM_QUADRATIC, | 
|---|
| 43 |                             ANIM_RANDOM}; | 
|---|
| 44 |  | 
|---|
| 45 | typedef enum ANIM_INFINITY {ANIM_INF_CONSTANT, | 
|---|
| 46 |                             ANIM_INF_LINEAR, | 
|---|
| 47 |                             ANIM_INF_PINGPONG, | 
|---|
| 48 |                             ANIM_INF_REWIND};//, ANIM_DELETE} | 
|---|
| 49 |  | 
|---|
| 50 | typedef struct AnimKeyFrame | 
|---|
| 51 | { | 
|---|
| 52 |   float duration; | 
|---|
| 53 |   float value; | 
|---|
| 54 |   ANIM_FUNCTION animFunc; | 
|---|
| 55 | }; | 
|---|
| 56 |  | 
|---|
| 57 | class Anim | 
|---|
| 58 | { | 
|---|
| 59 |  public: | 
|---|
| 60 |   virtual ~Anim(void); | 
|---|
| 61 |   void doNotHandle(void); | 
|---|
| 62 |  | 
|---|
| 63 |   void setInfinity(ANIM_INFINITY postInfinity = ANIM_INF_CONSTANT); | 
|---|
| 64 |  | 
|---|
| 65 |   void play(); // equals resume(); | 
|---|
| 66 |   void stop(); | 
|---|
| 67 |   void pause(); | 
|---|
| 68 |   void replay(); | 
|---|
| 69 |   virtual void rewind() = 0; | 
|---|
| 70 |  | 
|---|
| 71 |   virtual void tick(float time) = 0; | 
|---|
| 72 |  | 
|---|
| 73 |   /* implement in subclasses: | 
|---|
| 74 |    *  | 
|---|
| 75 |    * De-/Constructor | 
|---|
| 76 |    * Animation Functions | 
|---|
| 77 |    * virtual tick | 
|---|
| 78 |    * List of keyFrames | 
|---|
| 79 |    * currentKeyFrame/nextKeyFrame | 
|---|
| 80 |    * virtual rewind, to go to the first Keyframe. (other functions will call this one) | 
|---|
| 81 |    */ | 
|---|
| 82 |  | 
|---|
| 83 |   /** | 
|---|
| 84 |      \returns the BaseObject, this animation operates on | 
|---|
| 85 |   */ | 
|---|
| 86 |   BaseObject* getBaseObject(void) const { return baseObject;} | 
|---|
| 87 |  | 
|---|
| 88 |  protected: | 
|---|
| 89 |   Anim(void); | 
|---|
| 90 |  | 
|---|
| 91 |   // variables | 
|---|
| 92 |  | 
|---|
| 93 |   float localTime; | 
|---|
| 94 |   ANIM_INFINITY postInfinity; | 
|---|
| 95 |  | 
|---|
| 96 |   BaseObject* baseObject;         //!< The same as object in the derived classes, but with reference to BaseObject | 
|---|
| 97 |   bool bHasKeys; | 
|---|
| 98 |   bool bHandled;                  //!< If this Animation is handled by the AnimationPlayer. | 
|---|
| 99 |   bool bRunning; | 
|---|
| 100 | }; | 
|---|
| 101 |  | 
|---|
| 102 |  | 
|---|
| 103 | //! A Class to handle some animation for single floated values. | 
|---|
| 104 | template<class T> class tAnim : public Anim | 
|---|
| 105 | { | 
|---|
| 106 |  public: | 
|---|
| 107 |   tAnim(T* object = NULL, void (T::*funcToAnim)(float) = NULL); | 
|---|
| 108 |   virtual ~tAnim(); | 
|---|
| 109 |  | 
|---|
| 110 |   virtual void rewind(); | 
|---|
| 111 |  | 
|---|
| 112 |   void setFuncToAnim(T* object, void (T::*funcToAnim)(float)); | 
|---|
| 113 |   void addKeyFrame(float value, float duration, ANIM_FUNCTION animFunc = ANIM_LINEAR); | 
|---|
| 114 |  | 
|---|
| 115 |   virtual void tick(float time); | 
|---|
| 116 |  | 
|---|
| 117 |   // animation functions | 
|---|
| 118 |   void setAnimFunc(ANIM_FUNCTION animFunc); | 
|---|
| 119 |  | 
|---|
| 120 |   float constant(float timePassed) const; | 
|---|
| 121 |   float linear(float timePassed) const; | 
|---|
| 122 |   float sine(float timePassed) const; | 
|---|
| 123 |   float cosine(float timePassed) const; | 
|---|
| 124 |   float exp(float timePassed) const; | 
|---|
| 125 |   float negExp(float timePassed) const; | 
|---|
| 126 |   float quadratic(float timePassed) const; | 
|---|
| 127 |   float random(float timePassed) const; | 
|---|
| 128 |   //  ANIM_FUNCTION animFunc; | 
|---|
| 129 |   float (tAnim<T>::*animFunc)(float) const; | 
|---|
| 130 |   AnimKeyFrame* currentKeyFrame; | 
|---|
| 131 |   AnimKeyFrame* nextKeyFrame; | 
|---|
| 132 |   tList<AnimKeyFrame>* keyFrameList; | 
|---|
| 133 |  | 
|---|
| 134 |  | 
|---|
| 135 |  | 
|---|
| 136 |  | 
|---|
| 137 |  private: | 
|---|
| 138 |   float expFactor; | 
|---|
| 139 |   T* object; | 
|---|
| 140 |   void (T::*funcToAnim)(float); | 
|---|
| 141 | }; | 
|---|
| 142 |  | 
|---|
| 143 |  | 
|---|
| 144 |  | 
|---|
| 145 | /** | 
|---|
| 146 |    \brief standard constructor | 
|---|
| 147 |  | 
|---|
| 148 | */ | 
|---|
| 149 | template<class T> | 
|---|
| 150 | tAnim<T>::tAnim (T* object, void (T::*funcToAnim)(float))  | 
|---|
| 151 | { | 
|---|
| 152 |   // create a new List | 
|---|
| 153 |   this->keyFrameList = new tList<AnimKeyFrame>(); | 
|---|
| 154 |   AnimKeyFrame* tmpKeyFrame = new AnimKeyFrame; | 
|---|
| 155 |   tmpKeyFrame->value = 0.0; | 
|---|
| 156 |   tmpKeyFrame->duration = 1.0; | 
|---|
| 157 |   keyFrameList->add(tmpKeyFrame); | 
|---|
| 158 |  | 
|---|
| 159 |   this->currentKeyFrame = tmpKeyFrame; | 
|---|
| 160 |   this->nextKeyFrame = tmpKeyFrame; | 
|---|
| 161 |  | 
|---|
| 162 |   this->animFunc = &tAnim<T>::linear; | 
|---|
| 163 |  | 
|---|
| 164 |   this->setFuncToAnim(object, funcToAnim); | 
|---|
| 165 | } | 
|---|
| 166 |  | 
|---|
| 167 |  | 
|---|
| 168 | /** | 
|---|
| 169 |    \brief standard deconstructor | 
|---|
| 170 |  | 
|---|
| 171 | */ | 
|---|
| 172 | template<class T> | 
|---|
| 173 | tAnim<T>::~tAnim ()  | 
|---|
| 174 | { | 
|---|
| 175 |   // delete all the KeyFrames | 
|---|
| 176 |   tIterator<AnimKeyFrame>* itKF = keyFrameList->getIterator(); | 
|---|
| 177 |   AnimKeyFrame*  enumKF = itKF->nextElement(); | 
|---|
| 178 |   while (enumKF) | 
|---|
| 179 |     { | 
|---|
| 180 |       delete enumKF; | 
|---|
| 181 |       enumKF = itKF->nextElement(); | 
|---|
| 182 |     } | 
|---|
| 183 |   delete itKF; | 
|---|
| 184 |   delete this->keyFrameList; | 
|---|
| 185 |  | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | template<class T> | 
|---|
| 189 | void tAnim<T>::rewind(void) | 
|---|
| 190 | { | 
|---|
| 191 |   this->currentKeyFrame = keyFrameList->firstElement(); | 
|---|
| 192 |   this->nextKeyFrame = keyFrameList->nextElement(keyFrameList->firstElement()); | 
|---|
| 193 |   this->localTime = 0.0; | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | template<class T> | 
|---|
| 197 | void tAnim<T>::setFuncToAnim(T* object, void (T::*funcToAnim)(float)) | 
|---|
| 198 | { | 
|---|
| 199 |   this->baseObject = this->object = object; | 
|---|
| 200 |   this->funcToAnim = funcToAnim; | 
|---|
| 201 | } | 
|---|
| 202 |  | 
|---|
| 203 | template<class T> | 
|---|
| 204 | void tAnim<T>::addKeyFrame(float value, float duration, ANIM_FUNCTION animFunc) | 
|---|
| 205 | { | 
|---|
| 206 |   // some small check | 
|---|
| 207 |   if (duration <= 0.0) | 
|---|
| 208 |     duration = 1.0; | 
|---|
| 209 |    | 
|---|
| 210 |  | 
|---|
| 211 |   AnimKeyFrame* tmpKeyFrame; | 
|---|
| 212 |      | 
|---|
| 213 |   if (bHasKeys) | 
|---|
| 214 |     { | 
|---|
| 215 |       tmpKeyFrame = new AnimKeyFrame; | 
|---|
| 216 |       if (this->currentKeyFrame == this->nextKeyFrame) | 
|---|
| 217 |         this->nextKeyFrame = tmpKeyFrame; | 
|---|
| 218 |       this->keyFrameList->add(tmpKeyFrame); | 
|---|
| 219 |  | 
|---|
| 220 |     } | 
|---|
| 221 |   else | 
|---|
| 222 |     { | 
|---|
| 223 |       tmpKeyFrame = this->keyFrameList->firstElement(); | 
|---|
| 224 |       bHasKeys = true; | 
|---|
| 225 |       this->setAnimFunc(animFunc); | 
|---|
| 226 |     } | 
|---|
| 227 |   tmpKeyFrame->value = value; | 
|---|
| 228 |   tmpKeyFrame->duration = duration; | 
|---|
| 229 |   tmpKeyFrame->animFunc = animFunc; | 
|---|
| 230 | } | 
|---|
| 231 |  | 
|---|
| 232 |  | 
|---|
| 233 | template<class T> | 
|---|
| 234 | void tAnim<T>::tick(float time) | 
|---|
| 235 | { | 
|---|
| 236 |   if (this->bRunning) | 
|---|
| 237 |     { | 
|---|
| 238 |       this->localTime += time; | 
|---|
| 239 |       if (localTime >= this->currentKeyFrame->duration) | 
|---|
| 240 |         { | 
|---|
| 241 |           this->localTime = 0; | 
|---|
| 242 |           if (this->currentKeyFrame == this->keyFrameList->lastElement()) | 
|---|
| 243 |             switch (this->postInfinity) | 
|---|
| 244 |               { | 
|---|
| 245 |               case ANIM_INF_CONSTANT: | 
|---|
| 246 |                 this->bRunning = false; | 
|---|
| 247 |                 break; | 
|---|
| 248 |               case ANIM_INF_REWIND: | 
|---|
| 249 |                 break; | 
|---|
| 250 |               } | 
|---|
| 251 |           //this->currentKeyFrame = this->keyFrameList->nextElement(this->currentKeyFrame); | 
|---|
| 252 |           this->currentKeyFrame = this->nextKeyFrame; | 
|---|
| 253 |           this->nextKeyFrame = this->keyFrameList->nextElement(this->nextKeyFrame); | 
|---|
| 254 |           printf("%p from:%f to:%f\n", this->currentKeyFrame,this->currentKeyFrame->value, this->nextKeyFrame->value); | 
|---|
| 255 |           this->setAnimFunc(this->currentKeyFrame->animFunc);      | 
|---|
| 256 |         } | 
|---|
| 257 |        | 
|---|
| 258 |       (this->object->*(funcToAnim))((this->*animFunc)(this->localTime)); | 
|---|
| 259 |     } | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 |  | 
|---|
| 263 | template<class T> | 
|---|
| 264 | void tAnim<T>::setAnimFunc(ANIM_FUNCTION animFunc) | 
|---|
| 265 | { | 
|---|
| 266 |   switch (animFunc) | 
|---|
| 267 |     { | 
|---|
| 268 |     default: | 
|---|
| 269 |     case ANIM_CONSTANT: | 
|---|
| 270 |       this->animFunc = &tAnim<T>::constant; | 
|---|
| 271 |       break; | 
|---|
| 272 |     case ANIM_LINEAR: | 
|---|
| 273 |       this->animFunc = &tAnim<T>::linear; | 
|---|
| 274 |       break; | 
|---|
| 275 |     case ANIM_SINE: | 
|---|
| 276 |       this->animFunc = &tAnim<T>::sine; | 
|---|
| 277 |       break; | 
|---|
| 278 |     case ANIM_COSINE: | 
|---|
| 279 |       this->animFunc = &tAnim<T>::cosine; | 
|---|
| 280 |       break; | 
|---|
| 281 |     case ANIM_EXP: | 
|---|
| 282 |       this->animFunc = &tAnim<T>::exp; | 
|---|
| 283 |       break; | 
|---|
| 284 |     case ANIM_NEG_EXP: | 
|---|
| 285 |       { | 
|---|
| 286 |         this->animFunc = &tAnim<T>::negExp; | 
|---|
| 287 |         float d = fabs(this->currentKeyFrame->value - this->nextKeyFrame->value); | 
|---|
| 288 |         expFactor =  - 1.0 / this->currentKeyFrame->duration * logf(DELTA_X); | 
|---|
| 289 |         break; | 
|---|
| 290 |       } | 
|---|
| 291 |     case ANIM_QUADRATIC: | 
|---|
| 292 |       this->animFunc = &tAnim<T>::quadratic; | 
|---|
| 293 |       break; | 
|---|
| 294 |     case ANIM_RANDOM: | 
|---|
| 295 |       this->animFunc = &tAnim<T>::random; | 
|---|
| 296 |       break; | 
|---|
| 297 |     } | 
|---|
| 298 | } | 
|---|
| 299 |  | 
|---|
| 300 |  | 
|---|
| 301 | // animation functions | 
|---|
| 302 | template<class T> | 
|---|
| 303 | float tAnim<T>::random(float timePassed) const | 
|---|
| 304 | { | 
|---|
| 305 |   return (float)rand()/(float)RAND_MAX; | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | template<class T> | 
|---|
| 309 | float tAnim<T>::constant(float timePassed) const | 
|---|
| 310 | { | 
|---|
| 311 |   return this->currentKeyFrame->value; | 
|---|
| 312 | } | 
|---|
| 313 |  | 
|---|
| 314 | template<class T> | 
|---|
| 315 | float tAnim<T>::linear(float timePassed) const  | 
|---|
| 316 | { | 
|---|
| 317 |   return this->currentKeyFrame->value + (this->nextKeyFrame->value - this->currentKeyFrame->value)  | 
|---|
| 318 |     * (timePassed / this->currentKeyFrame->duration); | 
|---|
| 319 |   //  PRINTF(0)("value is %f, %p %p\n", val, this->currentKeyFrame, this->nextKeyFrame); | 
|---|
| 320 |   //  return val; | 
|---|
| 321 | } | 
|---|
| 322 |  | 
|---|
| 323 | template<class T> | 
|---|
| 324 | float tAnim<T>::sine(float timePassed) const | 
|---|
| 325 | { | 
|---|
| 326 |   float d = this->currentKeyFrame->value - this->nextKeyFrame->value; | 
|---|
| 327 |   float e = 0.5 * d * (1 - cos(M_PI * timePassed / this->currentKeyFrame->duration)); | 
|---|
| 328 |   return this->currentKeyFrame->value - e; | 
|---|
| 329 |   /* | 
|---|
| 330 |   return his->currentKeyFrame->value - (this->nextKeyFrame->value - this->currentKeyFrame->value) | 
|---|
| 331 |     * sin(timePassed / this->currentKeyFrame->duration * M_PI); | 
|---|
| 332 |   */ | 
|---|
| 333 | } | 
|---|
| 334 |  | 
|---|
| 335 | template<class T> | 
|---|
| 336 | float tAnim<T>::cosine(float timePassed) const | 
|---|
| 337 | { | 
|---|
| 338 |   float d = this->currentKeyFrame->value - this->nextKeyFrame->value; | 
|---|
| 339 |   float e = 0.5 * d * (sin(M_PI * timePassed / this->currentKeyFrame->duration)); | 
|---|
| 340 |   if( timePassed > 0.5*this->currentKeyFrame->duration) e = (d - e); | 
|---|
| 341 |   return this->currentKeyFrame->value - e; | 
|---|
| 342 |   /* | 
|---|
| 343 |   return this->currentKeyFrame->value - (this->nextKeyFrame->value - this->currentKeyFrame->value) | 
|---|
| 344 |     * cos(timePassed / this->currentKeyFrame->duration * M_PI); | 
|---|
| 345 |   */ | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | template<class T> | 
|---|
| 349 | float tAnim<T>::exp(float timePassed) const | 
|---|
| 350 | { | 
|---|
| 351 | } | 
|---|
| 352 |  | 
|---|
| 353 | template<class T> | 
|---|
| 354 | float tAnim<T>::negExp(float timePassed) const | 
|---|
| 355 | { | 
|---|
| 356 |   float d = this->currentKeyFrame->value - this->nextKeyFrame->value; | 
|---|
| 357 |   float e = d * (1.0 - expf(- timePassed * expFactor)); | 
|---|
| 358 |   return  this->currentKeyFrame->value - e; | 
|---|
| 359 | } | 
|---|
| 360 |  | 
|---|
| 361 | template<class T> | 
|---|
| 362 | float tAnim<T>::quadratic(float timePassed) const | 
|---|
| 363 | { | 
|---|
| 364 |  | 
|---|
| 365 | } | 
|---|
| 366 |  | 
|---|
| 367 |  | 
|---|
| 368 |  | 
|---|
| 369 |  | 
|---|
| 370 |  | 
|---|
| 371 | /**********************TEST*******************************/ | 
|---|
| 372 | class aTest | 
|---|
| 373 | { | 
|---|
| 374 |  public: | 
|---|
| 375 |   aTest() { last = 0.0;} | 
|---|
| 376 |   ~aTest() {} | 
|---|
| 377 |   void littleDebug(float f) {  diff = f - last; printf("f=%f, diff=%f\n", f,diff); last = f;} | 
|---|
| 378 |  private: | 
|---|
| 379 |   float diff; | 
|---|
| 380 |   float last; | 
|---|
| 381 | }; | 
|---|
| 382 |  | 
|---|
| 383 | //aTest::aTest() {} | 
|---|
| 384 | //aTest::~aTest() {} | 
|---|
| 385 |  | 
|---|
| 386 | //void aTest::littleDebug(float f) | 
|---|
| 387 |  | 
|---|
| 388 | /**********************TEST*******************************/ | 
|---|
| 389 |  | 
|---|
| 390 |  | 
|---|
| 391 | #endif /* _ANIMATION_H */ | 
|---|