/* 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->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) { if( !this->bRunning) return; this->localTime += time; /* first get the current frame via time-stamps */ while( this->localTime > this->currentFrame->time) { printf("SimpleAnimation::tick(...) - changing Frame\n"); this->localTime -= this->currentFrame->time; //this->currentFrame->object->setRelCoor(*this->currentFrame->position); *this->lastPosition = *this->currentFrame->position; this->lastFrame = this->currentFrame; this->currentFrame = this->frames->nextElement(this->currentFrame); this->mode = this->currentFrame->mode; if( this->mode == NEG_EXP) { *this->tmpVect = *this->currentFrame->position - *this->lastFrame->position; deltaT = 1/this->currentFrame->time * logf(1.0 + 600.0/this->tmpVect->len()); } } /* now animate it */ switch( this->mode) { 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 - exp(- 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; } }