/* 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; singletonRef = NULL; } /** \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->workingAnimator = NULL; this->bDescriptive = false; } /* Vector* lastPosition; Vector* tmpVect; tList* frames; animationMode animMode; movementMode movMode; bool bRunning; float deltaT; */ /** \brief select an object to work on by using this function \param object wo work on */ void SimpleAnimation::selectObject(WorldEntity* entity) { Animation3D* anim = getAnimationFromWorldEntity(entity); if( anim == NULL) { anim = new Animation3D; anim->object = entity; anim->lastPosition = new Vector(); anim->tmpVect = new Vector(); anim->frames = new tList(); anim->animMode = LOOP; anim->bRunning = false; deltaT = 0.0; this->animators->add(anim); } this->workingAnimator = anim; } /** \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 || this->workingAnimator == NULL) { 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->workingAnimator->object; this->workingAnimator->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 || this->workingAnimator == NULL) { 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->workingAnimator->object; this->workingAnimator->frames->add(frame); } /** \brief adds a already defined keyframe \param the keyframe to add */ void SimpleAnimation::addKeyFrame(KeyFrame* frame) { if( !this->bDescriptive || this->workingAnimator == NULL) { PRINTF(1)("SimpleAnimation: executing animation code outside a AnimationBegin()/AnimationEnd() - ignoring\n"); return; } frame->object = this->workingAnimator->object; this->workingAnimator->frames->add(frame); } void SimpleAnimation::setAnimationMode(animationMode mode) { if( !this->bDescriptive || this->workingAnimator == NULL) { PRINTF(1)("SimpleAnimation: executing animation code outside a AnimationBegin()/AnimationEnd() - ignoring\n"); return; } this->workingAnimator->animMode = mode; } /** \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; } if( this->workingAnimator == NULL) { PRINTF(1)("You have no target selected to start: either do this with start(target) or by prev selecting it\n"); return; } this->workingAnimator->localTime = 0.0; this->workingAnimator->bRunning = true; this->workingAnimator->currentFrame = this->workingAnimator->frames->firstElement(); this->workingAnimator->lastFrame = this->workingAnimator->frames->nextElement(this->workingAnimator->currentFrame); /* tIterator* iterator = this->animators->getIterator(); Animation* anim = iterator->nextElement(); while( anim != NULL) { printf("SimpleAnimation::start() - initializing an animaion\n"); anim->currentFrame = anim->frames->firstElement(); anim->lastFrame = anim->frames->nextElement(anim->currentFrame); anim = iterator->nextElement(); } */ } /** \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) { tIterator* iterator = this->animators->getIterator(); Animation3D* anim = iterator->nextElement(); while( anim != NULL) { if( anim->bRunning) { anim->localTime += time; /* first get the current frame via time-stamps */ while( anim->localTime > anim->currentFrame->time) { PRINTF(4)("SimpleAnimation::tick(...) - changing Frame\n"); anim->localTime -= anim->currentFrame->time; //this->currentFrame->object->setRelCoor(*this->currentFrame->position); *anim->lastPosition = *anim->currentFrame->position; anim->lastFrame = anim->currentFrame; anim->currentFrame = anim->frames->nextElement(anim->currentFrame); if( anim->currentFrame == anim->frames->firstElement() && anim->animMode == SINGLE) { anim->bRunning = false; return; } 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 * anim->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 - expf(- anim->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 * anim->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(anim->localTime, 3); break; default: break; } } anim = iterator->nextElement(); } delete anim; } Animation3D* SimpleAnimation::getAnimationFromWorldEntity(WorldEntity* entity) { tIterator* iterator = this->animators->getIterator(); Animation3D* anim = iterator->nextElement(); while( anim != NULL) { if( anim->object == entity) return anim; anim = iterator->nextElement(); } delete iterator; return NULL; }