/* 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: Patrick Boenzli co-programmer: Benjamin Grauer 2005-04-17: Benjamin Grauer Rewritte all functions, so it will fit into the Animation-class */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ANIM #include "animation3d.h" #include "p_node.h" using namespace std; /** \brief standard constructor */ Animation3D::Animation3D(PNode* object) { this->object = object; // create a new List this->keyFrameList = new tList(); KeyFrame3D* tmpKeyFrame = new KeyFrame3D; tmpKeyFrame->position = Vector(); tmpKeyFrame->direction = Quaternion(); keyFrameList->add(tmpKeyFrame); this->currentKeyFrame = tmpKeyFrame; this->nextKeyFrame = tmpKeyFrame; this->animFunc = &Animation3D::linear; } /** \brief standard deconstructor deletes all the Keyframes */ Animation3D::~Animation3D(void) { // delete all the KeyFrames tIterator* itKF = keyFrameList->getIterator(); KeyFrame3D* 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) */ void Animation3D::rewind(void) { this->currentKeyFrame = keyFrameList->firstElement(); this->nextKeyFrame = keyFrameList->nextElement(keyFrameList->firstElement()); this->localTime = 0.0; this->setAnimFunc(this->currentKeyFrame->animFunc); } /** \brief Appends a new Keyframe \param position The position of the new Keyframe \param direction The direction 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 */ void Animation3D::addKeyFrame(Vector position, Quaternion direction, float duration, ANIM_FUNCTION animFunc) { // some small check if (duration <= 0.0) duration = 1.0; KeyFrame3D* tmpKeyFrame; // when adding the first frame if (this->keyFrameCount == 0) { tmpKeyFrame = this->keyFrameList->firstElement(); this->setAnimFunc(animFunc); } else { tmpKeyFrame = new KeyFrame3D; // when adding the second frame if (this->currentKeyFrame == this->nextKeyFrame) this->nextKeyFrame = tmpKeyFrame; this->keyFrameList->add(tmpKeyFrame); } tmpKeyFrame->position = position; tmpKeyFrame->direction = direction; tmpKeyFrame->duration = duration; tmpKeyFrame->animFunc = animFunc; this->keyFrameCount++; } /** \brief ticks the Animation \param dt how much time to tick */ void Animation3D::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); this->setAnimFunc(this->currentKeyFrame->animFunc); if( this->currentKeyFrame->animFunc == ANIM_NEG_EXP) { this->tmpVect = this->nextKeyFrame->position - this->currentKeyFrame->position; this->deltaT = 1/this->currentKeyFrame->duration * logf(1.0 + 600.0/this->tmpVect.len()); } } /* now animate it */ (this->*animFunc)(this->localTime); /* switch( this->movMode) { case LINEAR: *this->tmpVect = *this->currentFrame->position - *this->lastFrame->position; *this->tmpVect = *this->tmpVect * this->localTime / this->currentFrame->time; this->currentFrame->object->setRelCoor(*this->lastFrame->position + *this->tmpVect); *this->lastPosition = *this->tmpVect; break; case EXP: break; case NEG_EXP: *this->tmpVect = *this->currentFrame->position - *this->lastFrame->position; *this->tmpVect = *this->tmpVect * (1 - expf(- this->localTime * this->deltaT)); this->currentFrame->object->setRelCoor(*this->lastFrame->position + *this->tmpVect); *this->lastPosition = *this->tmpVect; break; case SIN: *this->tmpVect = *this->currentFrame->position - *this->lastFrame->position; *this->tmpVect = *this->tmpVect * 0.5*(1 - cos(M_PI * this->localTime / this->currentFrame->time)); this->currentFrame->object->setRelCoor(*this->lastFrame->position + *this->tmpVect); *this->lastPosition = *this->tmpVect; break; case COS: break; case QUADRATIC: *this->tmpVect = *this->currentFrame->position - *this->lastFrame->position; *this->tmpVect = *this->tmpVect * 1/3 * ldexpf(this->localTime, 3); break; default: break; } */ } } /** \brief Sets The kind of Animation between this keyframe and the next one \param animFunc The Type of Animation to set */ void Animation3D::setAnimFunc(ANIM_FUNCTION animFunc) { switch (animFunc) { default: case ANIM_CONSTANT: this->animFunc = &Animation3D::constant; break; case ANIM_LINEAR: this->animFunc = &Animation3D::linear; break; case ANIM_SINE: this->animFunc = &Animation3D::sine; break; case ANIM_COSINE: this->animFunc = &Animation3D::cosine; break; case ANIM_EXP: this->animFunc = &Animation3D::exp; break; case ANIM_NEG_EXP: this->animFunc = &Animation3D::negExp; break; case ANIM_QUADRATIC: this->animFunc = &Animation3D::quadratic; break; case ANIM_RANDOM: this->animFunc = &Animation3D::random; break; } } /** \brief stays at the value of the currentKeyFrame \param timePassed The time passed since this Keyframe began */ void Animation3D::constant(float timePassed) const { this->object->setRelCoor(this->currentKeyFrame->position); /* this->tmpVect = this->nextKeyFrame->position - this->currentKeyFrame->position; this->tmpVect = this->tmpVect * this->localTime / this->currentKeyFrame->duration; this->currentFrame->object->setRelCoor(*this->lastFrame->position + *this->tmpVect); this->lastPosition = this->tmpVect; */ } /** \brief linear interpolation between this keyframe and the next one \param timePassed The time passed since this Keyframe began \todo implement also do this for direction */ void Animation3D::linear(float timePassed) const { this->object->setRelCoor(this->currentKeyFrame->position + (this->nextKeyFrame->position - this->currentKeyFrame->position) * (timePassed/this->currentKeyFrame->duration)); } /** \brief a Sinusodial Interpolation between this keyframe and the next one \param timePassed The time passed since this Keyframe began \todo implement */ void Animation3D::sine(float timePassed) const { this->linear(timePassed); } /** \brief a cosine interpolation between this keyframe and the next one \param timePassed The time passed since this Keyframe began \todo implement */ void Animation3D::cosine(float timePassed) const { this->linear(timePassed); } /** \brief an exponential interpolation between this keyframe and the next one \param timePassed The time passed since this Keyframe began */ void Animation3D::exp(float timePassed) const { this->linear(timePassed); } /** \brief a negative exponential interpolation between this keyframe and the next one \param timePassed The time passed since this Keyframe began \todo implement */ void Animation3D::negExp(float timePassed) const { this->linear(timePassed); } /** \brief a quadratic interpolation between this keyframe and the next one \param timePassed The time passed since this Keyframe began \todo implement */ void Animation3D::quadratic(float timePassed) const { this->linear(timePassed); } /** \brief some random animation (fluctuating) \param timePassed The time passed since this Keyframe began */ void Animation3D::random(float timePassed) const { this->object->setRelCoor(this->currentKeyFrame->position + (this->nextKeyFrame->position - this->currentKeyFrame->position) * (float)rand()/(float)RAND_MAX); this->object->setRelDir(this->currentKeyFrame->direction + (this->nextKeyFrame->direction - this->currentKeyFrame->direction)* (float)rand()/(float)RAND_MAX); }