/* 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: ... */ #include "simple_animation.h" #include "stdincl.h" #include "vector.h" #include "world_entity.h" using namespace std; SimpleAnimation* SimpleAnimation::singletonRef = 0; /** \brief gets the singleton instance \returns singleton instance */ SimpleAnimation* SimpleAnimation::getInstance() { if( singletonRef == NULL) singletonRef = new SimpleAnimation(); return singletonRef; } /** \brief standard constructor */ SimpleAnimation::SimpleAnimation () { this->setClassName ("SimpleAnimation"); this->frames = new tList(); this->animators = new tList(); this->localTime = 0; this->bRunning = false; this->currentFrame = NULL; this->lastFrame = NULL; this->tmpVect = new Vector(); this->lastPosition = new Vector(); this->deltaT = 0.2; } /** \brief standard deconstructor */ SimpleAnimation::~SimpleAnimation () { tIterator* iterator = this->frames->getIterator(); KeyFrame* frame = iterator->nextElement(); while( frame != NULL) { delete frame; frame = iterator->nextElement(); } delete iterator; delete this->frames; } /** \brief this determines the start of an Animator Describtion this can then be followed by different commands like addKeyFrame(..) etc. and will be closed with AnimatiorEnd() */ void SimpleAnimation::animatorBegin() { this->bDescriptive = true; } /** \brief this determines the end of an Animator Describtion this can then be followed by different commands like addKeyFrame(..) etc. and will be closed with AnimatiorEnd() */ void SimpleAnimation::animatorEnd() { this->workingObject = NULL; this->bDescriptive = false; } /** \brief select an object to work on by using this function \param object wo work on */ void SimpleAnimation::selectObject(WorldEntity* entity) { this->workingObject = entity; } /** \brief adds a keyframe with properties \param the point of the object \param and the direction of it \param at this time */ void SimpleAnimation::addKeyFrame(Vector* point, Quaternion* direction, float time) { if( !this->bDescriptive) { PRINTF(1)("SimpleAnimation: executing animation code outside a AnimationBegin()/AnimationEnd() - ignoring\n"); return; } KeyFrame* frame = new KeyFrame; frame->position = point; frame->direction = direction; frame->time = time; frame->mode = DEFAULT_ANIMATION_MODE; frame->object = this->workingObject; this->frames->add(frame); } /** \brief adds a keyframe with properties \param the point of the object \param and the direction of it \param at this time \param function of the velocity of the movement */ void SimpleAnimation::addKeyFrame(Vector* point, Quaternion* direction, float time, movementMode mode) { if( !this->bDescriptive) { PRINTF(1)("SimpleAnimation: executing animation code outside a AnimationBegin()/AnimationEnd() - ignoring\n"); return; } KeyFrame* frame = new KeyFrame; frame->position = point; frame->direction = direction; frame->time = time; frame->mode = mode; frame->object = this->workingObject; this->frames->add(frame); } /** \brief adds a already defined keyframe \param the keyframe to add */ void SimpleAnimation::addKeyFrame(KeyFrame* frame) { if( !this->bDescriptive) { PRINTF(1)("SimpleAnimation: executing animation code outside a AnimationBegin()/AnimationEnd() - ignoring\n"); return; } frame->object = this->workingObject; this->frames->add(frame); } /** \brief clear the list of keyframes, deleting all keyframes included */ void SimpleAnimation::reset() { tIterator* iterator = this->frames->getIterator(); KeyFrame* frame = iterator->nextElement(); while( frame != NULL) { delete frame; frame = iterator->nextElement(); } delete iterator; delete this->frames; this->frames = new tList(); this->localTime = 0; this->bRunning = false; this->currentFrame = NULL; this->lastFrame = NULL; } /** \brief starts the animation, therefore listens to tick signals */ void SimpleAnimation::start() { if( this->bRunning) { PRINTF(2)("SimpleAnimatin is already running. You are trying to start it again.\n"); return; } this->localTime = 0; this->lastFrame = this->frames->firstElement(); this->currentFrame = this->frames->nextElement(this->currentFrame); this->bRunning = true; } /** \brief stops the animation, immune to tick signals */ void SimpleAnimation::stop() { this->bRunning = false; } /** \brief stops and then starts the animation from begining */ void SimpleAnimation::restart() { this->localTime = 0; this->lastFrame = this->frames->firstElement(); this->currentFrame = this->frames->nextElement(this->currentFrame); this->bRunning = true; } /** \brief pauses the animation until resumed */ void SimpleAnimation::pause() { this->bRunning = false; } /** \brief resumes a pause, if not paused, no effect */ void SimpleAnimation::resume() { this->bRunning = true; } /** \brief heart beat, next animation step */ void SimpleAnimation::tick(float time) { this->localTime += time; tIterator* iterator = this->animators->getIterator(); Animation* anim = iterator->nextElement(); while( anim != NULL) { if( anim->bRunning) { /* first get the current frame via time-stamps */ while( this->localTime > anim->currentFrame->time) { printf("SimpleAnimation::tick(...) - changing Frame\n"); //this->currentFrame->object->setRelCoor(*this->currentFrame->position); *anim->lastPosition = *anim->currentFrame->position; anim->lastFrame = anim->currentFrame; anim->currentFrame = anim->frames->nextElement(anim->currentFrame); anim->movMode = anim->currentFrame->mode; if( anim->movMode == NEG_EXP) { *anim->tmpVect = *anim->currentFrame->position - *anim->lastFrame->position; anim->deltaT = 1/anim->currentFrame->time * logf(1.0 + 600.0/anim->tmpVect->len()); } } /* now animate it */ switch( anim->movMode) { case LINEAR: *anim->tmpVect = *anim->currentFrame->position - *anim->lastFrame->position; *anim->tmpVect = *anim->tmpVect * this->localTime / anim->currentFrame->time; anim->currentFrame->object->setRelCoor(*anim->lastFrame->position + *anim->tmpVect); *anim->lastPosition = *anim->tmpVect; break; case EXP: break; case NEG_EXP: *anim->tmpVect = *anim->currentFrame->position - *anim->lastFrame->position; *anim->tmpVect = *anim->tmpVect * (1 - exp(- this->localTime * anim->deltaT)); anim->currentFrame->object->setRelCoor(*anim->lastFrame->position + *anim->tmpVect); *anim->lastPosition = *anim->tmpVect; break; case SIN: *anim->tmpVect = *anim->currentFrame->position - *anim->lastFrame->position; *anim->tmpVect = *anim->tmpVect * 0.5*(1 - cos(M_PI * this->localTime / anim->currentFrame->time)); anim->currentFrame->object->setRelCoor(*anim->lastFrame->position + *anim->tmpVect); *anim->lastPosition = *anim->tmpVect; break; case COS: break; case QUADRATIC: *anim->tmpVect = *anim->currentFrame->position - *anim->lastFrame->position; *anim->tmpVect = *anim->tmpVect * 1/3 * ldexpf(this->localTime, 3); break; default: break; } } anim = iterator->nextElement(); } delete anim; }