/* 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: ... co-programmer: ... */ //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ #include "quick_animation.h" #include "compiler.h" #include "debug.h" #ifndef NULL #define NULL 0 #endif using namespace std; /** * standard constructor */ QuickAnimation::QuickAnimation () { this->setClassID(CL_QUICK_ANIMATION, "QuickAnimation"); // initialize the First KeyFrame (will be deleted if a new one gets created) this->count = 0; this->first = this->current = new QuickKeyFrame; this->first->next = this->first->prev = this->first; this->first->position = 0.0; this->first->value = 0.0; } /** * deletes all the deconstructor stuff */ QuickAnimation::~QuickAnimation () { this->current = this->first; QuickKeyFrame* delKF = this->first; do { delKF = this->current; this->current = this->current->next; delete delKF; } while (this->current != this->first); } /** * adds a new entry to the list of keyframes * @param position the position to add the key to * @param value the Value to set for the position * @returns false if the key existed already for a given position */ void QuickAnimation::addEntry(float position, float value) { // create the new KeyFrame QuickKeyFrame* newKey = new QuickKeyFrame; newKey->position = position; newKey->value = value; // if we add a KeyFrame for the first Time: if (unlikely (this->count == 0)) { delete this->first; newKey->next = newKey; newKey->prev = newKey; this->first = newKey; this->current = newKey; } // if the KeyFrame is in front of the FIRST keyFrame else if (this->first->position > position) { newKey->next = this->first; newKey->prev = this->first->prev; newKey->prev->next = newKey; newKey->next->prev = newKey; this->first = newKey; // the new Key becomes the FIRST. } // if the KeyFrame is at the End of the Animation else if (this->first->prev->position < position) { newKey->next = this->first; newKey->prev = this->first->prev; newKey->prev->next = newKey; newKey->next->prev = newKey; } // if the Key is between two frames. else { this->current = this->first; do { if (this->current->position < position && this->current->next->position > position) break; // if it is the same as an already existing keyframe else if (this->current->position == position) { this->current->value = value; delete newKey; return; } this->current = this->current->next; } while (this->current != this->first); newKey->next = this->current->next; newKey->prev = this->current; newKey->next->prev = newKey; newKey->prev->next = newKey; } this->current = this->first; ++this->count; } /** * changes an entry in the region of position * @param position the Position of an existing keyframe * @param region a deviation of the existing keyframe (like a delta in witch to search for * @param value the new Value if the Entry at the in the region of the specified position is found, it will be changed. Otherwise a new KeyFrame will be created with value at position. @todo rimplement */ void QuickAnimation::changeEntry(float position, float value, float region) { if ((this->first->position > position + region) || this->first->prev->position < position - region || this->count == 0) this->addEntry(position, value); else { this->current = this->first; do { if (this->current->position > position + region) { this->addEntry(position, value); return; } if (this->current->position < position+region && this->current->position > position-region) { this->current->value = value; return; } this->current = this->current->next; } while (this->current != this->first); } } /** * removes a KeyFrame from the List. * @param position * @return */ void QuickAnimation::removeEntry(float position) { this->current = this->first; if (this->count <= 0) { this->current->value = 0.0; this->current->position = 0.0; count = 0; return; } else { do { if (this->current->position == position) { if (this->current == this->first) this->first = this->first->next; this->current->next->prev = this->current->prev; this->current->prev->next = this->current->next; delete this->current; break; } this->current = this->current->next; } while (this->current != this->first); count --; this->current = this->first; } } /** * returns the value of the animation at a certain position * @param position the position to get the value from :) */ float QuickAnimation::getValue(float position) { while (true) { // if we have a match if (likely(this->current->position <= position && this->current->next->position >= position)) return this->current->value + (this->current->next->value - this->current->value) * ((position-this->current->position) / (this->current->next->position -this->current->position)); else if (unlikely(this->first->prev->position < position)) return this->first->prev->value; else if (unlikely(this->first->position > position)) return this->first->value; else if(likely(this->current->next->position < position)) this->current = this->current->next; else if (likely(this->current->position > position)) this->current = this->current->prev; } } /** * outputs some nice information about this class */ void QuickAnimation::debug() { this->current = this->first; PRINT(0)("QuickAnim(entries:%d)::(position, value)", this->count); do { PRINT(0)("->(%f, %f)", this->current->position, this->current->value); this->current = this->current->next; } while(this->current != this->first); PRINT(0)("\n"); this->current = this->first; }