/* 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" //! 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_LINEAR); 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 }; /** \brief 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); } /** \brief 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; } /** \brief rewinds the Animation to the beginning (first KeyFrame and time == 0) */ template void tAnimation::rewind(void) { this->currentKeyFrame = keyFrameList->firstElement(); this->nextKeyFrame = keyFrameList->nextElement(keyFrameList->firstElement()); this->localTime = 0.0; } /** \brief 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; } /** \brief 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; KeyFrameF* tmpKeyFrame; if (bHasKeys) { tmpKeyFrame = new KeyFrameF; if (this->currentKeyFrame == this->nextKeyFrame) this->nextKeyFrame = tmpKeyFrame; this->keyFrameList->add(tmpKeyFrame); } else { tmpKeyFrame = this->keyFrameList->firstElement(); bHasKeys = true; this->setAnimFunc(animFunc); } tmpKeyFrame->value = value; tmpKeyFrame->duration = duration; tmpKeyFrame->animFunc = animFunc; } /** \brief 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) { // 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); } (this->object->*(funcToAnim))((this->*animFunc)(this->localTime)); } } /** \brief 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; float d = fabs(this->currentKeyFrame->value - this->nextKeyFrame->value); 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 /** \brief 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; } /** \brief 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); // PRINTF(0)("value is %f, %p %p\n", val, this->currentKeyFrame, this->nextKeyFrame); // return val; } /** \brief 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 { float d = this->currentKeyFrame->value - this->nextKeyFrame->value; float e = 0.5 * d * (1 - cos(M_PI * timePassed / this->currentKeyFrame->duration)); return this->currentKeyFrame->value - e; /* return his->currentKeyFrame->value - (this->nextKeyFrame->value - this->currentKeyFrame->value) * sin(timePassed / this->currentKeyFrame->duration * M_PI); */ } /** \brief 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 { float d = this->currentKeyFrame->value - this->nextKeyFrame->value; float e = 0.5 * d * (sin(M_PI * timePassed / this->currentKeyFrame->duration)); if( timePassed > 0.5*this->currentKeyFrame->duration) e = (d - e); return this->currentKeyFrame->value - e; /* return this->currentKeyFrame->value - (this->nextKeyFrame->value - this->currentKeyFrame->value) * cos(timePassed / this->currentKeyFrame->duration * M_PI); */ } /** \brief 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 { } /** \brief 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; } /** \brief 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); } /** \brief some random animation (fluctuating) \param timePassed The time passed since this Keyframe began */ template float tAnimation::random(float timePassed) const { return this->currentKeyFrame->value * (float)rand()/(float)RAND_MAX; } #endif /* _T_ANIMATION_H */