/* 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 /** * @brief standard constructor * @param resolution the Resolution of the LookupTable */ QuickAnimation::QuickAnimation (unsigned int resolution) { this->lookupValues.resize(resolution, 0.0f); } /** * @brief deletes all the deconstructor stuff */ QuickAnimation::~QuickAnimation () { } /** * @brief 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 */ bool QuickAnimation::addKey(float position, float value) { if (position > 1.0f || position < 0.0f) { printf("QuickAnimation::Position MUST BE between 0.0f and 1.0f\n"); return false; } if(std::find(this->keyFrames.begin(), this->keyFrames.end(), position) != this->keyFrames.end()) { printf("QuickAnimation:: key at position %f already added. Use changeValue instead\n", position); return false; } this->keyFrames.push_back(QuickKeyFrame(position, value)); this->rebuild(); return true; } /** * @brief 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 */ bool QuickAnimation::changeValueKey(unsigned int keyFrameNumber, float newValue) { if (keyFrameNumber < this->keyFrames.size()) { this->keyFrames[keyFrameNumber].value = newValue; this->rebuild(); return true; } else return false; } /** * @brief 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 * * This Function adds a new KeyFrame at position with newValue, if none was found in region of position. */ bool QuickAnimation::changeValue(float position, float newValue, float region) { int keyFrame = this->getKeyAt(position, region); if (keyFrame == -1) return this->addKey(position, newValue); else return this->changeValueKey(keyFrame, newValue); } /** * @brief removes the keyFrameNumber'th entry. * @param keyFrameNumber the n'th Keyframe to remove. * @returns true on success, false if keyFrameNumber did not exist. */ bool QuickAnimation::removeKey(unsigned int keyFrameNumber) { if (keyFrameNumber < this->keyFrames.size()) { this->keyFrames.erase(this->keyFrames.begin() + keyFrameNumber); this->rebuild(); return true; } else return false; } /** * @brief removes a KeyFrame from the List. * @param position the Keyframe at position position will be erased. * @param region a deviation of the existing keyframe (like a delta in witch to search for) * @returns true on success, false if no KeyFrame was found. */ bool QuickAnimation::remove(float position, float region) { int keyFrame = this->getKeyAt(position, region); if (keyFrame == -1) return false; else return this->removeKey(keyFrame); } /** * @brief moves the keyFrame keyFrameNumber to newPosition/newValue. * @param keyFrameNumber the n'th KeyFrame to move. * @param newPosition the new Position for the KeyFrame. * @param newValue the new Value for the KeyFrame. * @returns true on success, false if the KeyFrame did not exist. */ bool QuickAnimation::moveKey(unsigned int keyFrameNumber, float newPosition, float newValue) { if (keyFrameNumber < this->keyFrames.size()) { this->keyFrames[keyFrameNumber].position = newPosition; this->keyFrames[keyFrameNumber].value = newValue; this->rebuild(); return true; } else return false; } /** * @brief moves the keyFrame keyFrameNumber to newPosition/value. * @param keyFrameNumber the n'th KeyFrame to move. * @param newPosition the new Position for the KeyFrame. * @returns true on success, false if the KeyFrame did not exist. */ bool QuickAnimation::moveKey(unsigned int keyFrameNumber, float newPosition) { if (keyFrameNumber < this->keyFrames.size()) { this->keyFrames[keyFrameNumber].position = newPosition; this->rebuild(); return true; } else return false; } /** * @brief moves the keyFrame in the region of oldPosition to newPosition/newValue. * @param oldPosition the old Position for the KeyFrame. * @param newPosition the new Position for the KeyFrame. * @param newValue the new Value for the KeyFrame. * @param region the region around oldPosition to search for the KeyFrame. * @returns true on success, false if the KeyFrame was not found within the region of oldPosition. */ bool QuickAnimation::move(float oldPosition, float newPosition, float newValue, float region) { int keyFrame = this->getKeyAt(oldPosition, region); if (keyFrame == -1) return false; else return this->moveKey(keyFrame, newPosition, newValue); } /** * @brief moves the keyFrame in the region of oldPosition to newPosition/Value. * @param oldPosition the old Position for the KeyFrame. * @param newPosition the new Position for the KeyFrame. * @param region the region around oldPosition to search for the KeyFrame. * @returns true on success, false if the KeyFrame was not found within the region of oldPosition. */ bool QuickAnimation::move(float oldPosition, float newPosition, float region) { int keyFrame = this->getKeyAt(oldPosition, region); if (keyFrame == -1) return false; else return this->moveKey(keyFrame, newPosition); } /** * @brief searches for a Keyframe in the region of position * @param position the Keyframe at position position will searched for. * @param region a deviation of the existing keyframe (like a delta in witch to search for) * @returns the keyFrame on success, -1 on fault. */ int QuickAnimation::getKeyAt(float position, float region) { for (unsigned int i = 0; i < this->keyFrames.size(); i++) { if (this->keyFrames[i].position + region/2.0 > position && this->keyFrames[i].position - region/2.0 < position) return i; } return -1; } /** * @brief rebuilds the QuickAnimation. */ void QuickAnimation::rebuild() { // if we do not have any KeyFrames if (this->keyFrames.empty()) { for (unsigned int i = 0; i < this->lookupValues.size(); i++) this->lookupValues[i] = 0.0f; return; } // Sort the List. std::sort(this->keyFrames.begin(), this->keyFrames.end(), QuickKeyFrame::sortPositionPredicate); // rebuild the lookup-table float sliceSize = 1.0f / this->lookupValues.size(); unsigned int key = 0; float preVal = this->keyFrames[0].value; float prePos = this->keyFrames[0].position; float postVal = preVal; float postPos = 1.0; if (this->keyFrames.size() > 1) { postVal = this->keyFrames[1].value; postPos = this->keyFrames[1].position; } for (unsigned int i = 0; i < this->lookupValues.size(); i++) { float position = (float)i * sliceSize; // if we reach the Next KeyFrame if (position > postPos) { // if we have more KeyFrames. if (this->keyFrames.size() > ++key + 1) { preVal = this->keyFrames[key].value; prePos = this->keyFrames[key].position; postVal = this->keyFrames[key+1].value; postPos = this->keyFrames[key+1].position; } // otherwise we reached the last KeyFrame else { preVal = postVal; prePos = postPos; postPos = 1.0; } } this->lookupValues[i] = preVal + ( postVal - preVal) / (postPos - prePos) * (position - prePos); } } /** * @brief outputs some nice information about this class */ void QuickAnimation::debug() const { printf("QuickAnim(KeyFrames:%d, Resolution:%d)::(position, value) ", this->keyFrames.size(), this->lookupValues.size()); for (unsigned int i = 0; i < this->keyFrames.size(); i++) printf("(%0.2f, %0.2f)->", this->keyFrames[i].position, this->keyFrames[i].value); printf("\n"); } /** * @brief compares two QuickKeyFrames with their positions. * @param key1 the first keyframe * @param key2 the second keyframe * @returns true, if the key1.position < key2.position. */ bool QuickAnimation::QuickKeyFrame::sortPositionPredicate(const QuickKeyFrame& key1, const QuickKeyFrame& key2) { return (key1.position < key2.position); } /** * @brief compares two QuickKeyFrames with their values. * @param key1 the first keyframe * @param key2 the second keyframe * @returns true, if the key1.value < key2.value. */ bool QuickAnimation::QuickKeyFrame::sortValuePredicate(const QuickKeyFrame& key1, const QuickKeyFrame& key2) { return (key1.value < key2.value); }