/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ /*! \file t_animation.h */ #ifndef _T_ANIMATION_H #define _T_ANIMATION_H #include "animation.h" #define DELTA_X 0.05 //!< the percentag of the distance that doesnt have to be done by neg_exp (asymptotical) ~ maschinendelta //! A Struct for Keyframes that simply hold a float typedef struct KeyFrameF { float duration; //!< duration of this keyframe float value; //!< value of this keyframe ANIM_FUNCTION animFunc; //!< with whitch function to iterate to the next KeyFrameF }; //! A Class to handle some animation for single floated values. template class tAnimation : public Animation { public: tAnimation(T* object = NULL, void (T::*funcToAnim)(float) = NULL); virtual ~tAnimation(); void setFuncToAnim(T* object, void (T::*funcToAnim)(float)); void addKeyFrame(float value, float duration, ANIM_FUNCTION animFunc = ANIM_DEFAULT_FUNCTION); virtual void rewind(); virtual void tick(float dt); private: // animation functions void setAnimFunc(ANIM_FUNCTION animFunc); float constant(float timePassed) const; float linear(float timePassed) const; float sine(float timePassed) const; float cosine(float timePassed) const; float exp(float timePassed) const; float negExp(float timePassed) const; float quadratic(float timePassed) const; float random(float timePassed) const; // ANIM_FUNCTION animFunc float (tAnimation::*animFunc)(float) const; //!< A Function for the AnimationType KeyFrameF* currentKeyFrame; //!< The current KeyFrame KeyFrameF* nextKeyFrame; //!< The KeyFrame we iterate to tList* keyFrameList; //!< The KeyFrameList T* object; //!< The Object from which to Animate something void (T::*funcToAnim)(float); //!< The function to Animate float expFactor; //!< some factors }; /** * standard constructor */ template tAnimation::tAnimation (T* object, void (T::*funcToAnim)(float)) { // create a new List this->keyFrameList = new tList(); KeyFrameF* tmpKeyFrame = new KeyFrameF; tmpKeyFrame->value = 0.0; tmpKeyFrame->duration = 1.0; keyFrameList->add(tmpKeyFrame); this->currentKeyFrame = tmpKeyFrame; this->nextKeyFrame = tmpKeyFrame; this->animFunc = &tAnimation::linear; this->setFuncToAnim(object, funcToAnim); } /** * standard deconstructor deletes all the Keyframes */ template tAnimation::~tAnimation () { // delete all the KeyFrames tIterator* itKF = keyFrameList->getIterator(); KeyFrameF* enumKF = itKF->nextElement(); while (enumKF) { delete enumKF; enumKF = itKF->nextElement(); } delete itKF; delete this->keyFrameList; } /** * rewinds the Animation to the beginning (first KeyFrame and time == 0) */ template void tAnimation::rewind() { this->currentKeyFrame = keyFrameList->firstElement(); this->nextKeyFrame = keyFrameList->nextElement(keyFrameList->firstElement()); this->localTime = 0.0; this->setAnimFunc(this->currentKeyFrame->animFunc); } /** * sets the Function we want to animate * @param object from what object do we want to animate * @param funcToAnim which function */ template void tAnimation::setFuncToAnim(T* object, void (T::*funcToAnim)(float)) { this->baseObject = this->object = object; this->funcToAnim = funcToAnim; } /** * Appends a new Keyframe * @param value the value of the new KeyFrame * @param duration The duration from the new KeyFrame to the next one * @param animFunc The function to animate between this keyFrame and the next one */ template void tAnimation::addKeyFrame(float value, float duration, ANIM_FUNCTION animFunc) { // some small check if (duration <= 0.0) duration = 1.0; if (animFunc == ANIM_NULL) animFunc = ANIM_DEFAULT_FUNCTION; KeyFrameF* tmpKeyFrame; // when adding the first frame if (this->keyFrameCount == 0) { tmpKeyFrame = this->keyFrameList->firstElement(); this->setAnimFunc(animFunc); } else { tmpKeyFrame = new KeyFrameF; // when adding the second frame if (this->currentKeyFrame == this->nextKeyFrame) this->nextKeyFrame = tmpKeyFrame; this->keyFrameList->add(tmpKeyFrame); } tmpKeyFrame->value = value; tmpKeyFrame->duration = duration; tmpKeyFrame->animFunc = animFunc; this->keyFrameCount++; } /** * ticks the Animation * @param dt how much time to tick */ template void tAnimation::tick(float dt) { if (this->bRunning) { this->localTime += dt; if (localTime >= this->currentKeyFrame->duration) { if (likely(this->keyFramesToPlay != 0)) { if (unlikely(this->keyFramesToPlay > 0)) --this->keyFramesToPlay; // switching to the next Key-Frame this->localTime -= this->currentKeyFrame->duration; this->currentKeyFrame = this->nextKeyFrame; // checking, if we should still Play the animation if (this->currentKeyFrame == this->keyFrameList->lastElement()) this->handleInfinity(); this->nextKeyFrame = this->keyFrameList->nextElement(this->currentKeyFrame); //printf("%p from:%f to:%f\n", this->currentKeyFrame,this->currentKeyFrame->value, this->nextKeyFrame->value); this->setAnimFunc(this->currentKeyFrame->animFunc); } else this->pause(); } (this->object->*(funcToAnim))((this->*animFunc)(this->localTime)); } } /** * Sets The kind of Animation between this keyframe and the next one * @param animFunc The Type of Animation to set */ template void tAnimation::setAnimFunc(ANIM_FUNCTION animFunc) { switch (animFunc) { default: case ANIM_CONSTANT: this->animFunc = &tAnimation::constant; break; case ANIM_LINEAR: this->animFunc = &tAnimation::linear; break; case ANIM_SINE: this->animFunc = &tAnimation::sine; break; case ANIM_COSINE: this->animFunc = &tAnimation::cosine; break; case ANIM_EXP: this->animFunc = &tAnimation::exp; break; case ANIM_NEG_EXP: { this->animFunc = &tAnimation::negExp; expFactor = - 1.0 / this->currentKeyFrame->duration * logf(DELTA_X); break; } case ANIM_QUADRATIC: this->animFunc = &tAnimation::quadratic; break; case ANIM_RANDOM: this->animFunc = &tAnimation::random; break; } } // animation functions /** * stays at the value of the currentKeyFrame * @param timePassed The time passed since this Keyframe began */ template float tAnimation::constant(float timePassed) const { return this->currentKeyFrame->value; } /** * linear interpolation between this keyframe and the next one * @param timePassed The time passed since this Keyframe began */ template float tAnimation::linear(float timePassed) const { return this->currentKeyFrame->value + (this->nextKeyFrame->value - this->currentKeyFrame->value) * (timePassed / this->currentKeyFrame->duration); } /** * a Sinusodial Interpolation between this keyframe and the next one * @param timePassed The time passed since this Keyframe began */ template float tAnimation::sine(float timePassed) const { if (timePassed * 2.0 < this->currentKeyFrame->duration) return this->currentKeyFrame->value + (this->nextKeyFrame->value - this->currentKeyFrame->value) * sin( M_PI * timePassed / this->currentKeyFrame->duration)/2; else return this->nextKeyFrame->value - (this->nextKeyFrame->value - this->currentKeyFrame->value) * sin( M_PI * (1.0 - timePassed / this->currentKeyFrame->duration))/2; /* printf("::%f::::%f::\n",timePassed/this->currentKeyFrame->duration,retVal); return retVal; */ } /** * a cosine interpolation between this keyframe and the next one * @param timePassed The time passed since this Keyframe began */ template float tAnimation::cosine(float timePassed) const { return ((this->nextKeyFrame->value + this->currentKeyFrame->value) + (this->currentKeyFrame->value - this->nextKeyFrame->value) * cos( M_PI * timePassed / this->currentKeyFrame->duration))/2; } /** * an exponential interpolation between this keyframe and the next one * @param timePassed The time passed since this Keyframe began */ template float tAnimation::exp(float timePassed) const { return this->linear(timePassed); } /** * a negative exponential interpolation between this keyframe and the next one * @param timePassed The time passed since this Keyframe began */ template float tAnimation::negExp(float timePassed) const { float d = this->currentKeyFrame->value - this->nextKeyFrame->value; float e = d * (1.0 - expf(- timePassed * expFactor)); return this->currentKeyFrame->value - e; } /** * a quadratic interpolation between this keyframe and the next one * @param timePassed The time passed since this Keyframe began */ template float tAnimation::quadratic(float timePassed) const { this->linear(timePassed); } /** * some random animation (fluctuating) * @param timePassed The time passed since this Keyframe began */ template float tAnimation::random(float timePassed) const { return this->currentKeyFrame->value + (this->nextKeyFrame->value - this->currentKeyFrame->value) * (float)rand()/(float)RAND_MAX; } #endif /* _T_ANIMATION_H */