| 1 | /* | 
|---|
| 2 |    orxonox - the future of 3D-vertical-scrollers | 
|---|
| 3 |  | 
|---|
| 4 |    Copyright (C) 2004 orx | 
|---|
| 5 |  | 
|---|
| 6 |    This program is free software; you can redistribute it and/or modify | 
|---|
| 7 |    it under the terms of the GNU General Public License as published by | 
|---|
| 8 |    the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 9 |    any later version. | 
|---|
| 10 |  | 
|---|
| 11 |    ### File Specific: | 
|---|
| 12 |    main-programmer: ... | 
|---|
| 13 |    co-programmer: ... | 
|---|
| 14 | */ | 
|---|
| 15 |  | 
|---|
| 16 | //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ | 
|---|
| 17 |  | 
|---|
| 18 | #include "quick_animation.h" | 
|---|
| 19 |  | 
|---|
| 20 | #include <algorithm> | 
|---|
| 21 |  | 
|---|
| 22 |  | 
|---|
| 23 |  | 
|---|
| 24 | /** | 
|---|
| 25 |  * @brief standard constructor | 
|---|
| 26 |  * @param resolution the Resolution of the LookupTable | 
|---|
| 27 |  */ | 
|---|
| 28 | QuickAnimation::QuickAnimation (unsigned int resolution) | 
|---|
| 29 | { | 
|---|
| 30 |   this->lookupValues.resize(resolution, 0.0f); | 
|---|
| 31 | } | 
|---|
| 32 |  | 
|---|
| 33 | /** | 
|---|
| 34 |  * @brief deletes all the deconstructor stuff | 
|---|
| 35 |  */ | 
|---|
| 36 | QuickAnimation::~QuickAnimation () | 
|---|
| 37 | { } | 
|---|
| 38 |  | 
|---|
| 39 | /** | 
|---|
| 40 |  * @brief adds a new entry to the list of keyframes | 
|---|
| 41 |  * @param position the position to add the key to | 
|---|
| 42 |  * @param value the Value to set for the position | 
|---|
| 43 |  * @returns false if the key existed already for a given position | 
|---|
| 44 |  */ | 
|---|
| 45 | bool QuickAnimation::addKey(float position, float value) | 
|---|
| 46 | { | 
|---|
| 47 |   if (position > 1.0f || position < 0.0f) | 
|---|
| 48 |   { | 
|---|
| 49 |     printf("QuickAnimation::Position MUST BE between 0.0f and 1.0f\n"); | 
|---|
| 50 |     return false; | 
|---|
| 51 |   } | 
|---|
| 52 |   if(std::find(this->keyFrames.begin(), this->keyFrames.end(), position) != this->keyFrames.end()) | 
|---|
| 53 |   { | 
|---|
| 54 |     printf("QuickAnimation:: key at position %f already added. Use changeValue instead\n", position); | 
|---|
| 55 |     return false; | 
|---|
| 56 |   } | 
|---|
| 57 |   this->keyFrames.push_back(QuickKeyFrame(position, value)); | 
|---|
| 58 |  | 
|---|
| 59 |   this->rebuild(); | 
|---|
| 60 |   return true; | 
|---|
| 61 | } | 
|---|
| 62 |  | 
|---|
| 63 |  | 
|---|
| 64 | /** | 
|---|
| 65 |  * @brief changes an entry in the region of position | 
|---|
| 66 |  * @param position the Position of an existing keyframe | 
|---|
| 67 |  * @param region a deviation of the existing keyframe (like a delta in witch to search for) | 
|---|
| 68 |  * @param value the new Value | 
|---|
| 69 |  */ | 
|---|
| 70 | bool QuickAnimation::changeValueKey(unsigned int keyFrameNumber, float newValue) | 
|---|
| 71 | { | 
|---|
| 72 |   if (keyFrameNumber < this->keyFrames.size()) | 
|---|
| 73 |   { | 
|---|
| 74 |     this->keyFrames[keyFrameNumber].value = newValue; | 
|---|
| 75 |     this->rebuild(); | 
|---|
| 76 |     return true; | 
|---|
| 77 |   } | 
|---|
| 78 |   else | 
|---|
| 79 |     return false; | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|
| 82 | /** | 
|---|
| 83 |  * @brief changes an entry in the region of position | 
|---|
| 84 |  * @param position the Position of an existing keyframe | 
|---|
| 85 |  * @param region a deviation of the existing keyframe (like a delta in witch to search for) | 
|---|
| 86 |  * @param value the new Value | 
|---|
| 87 |  * | 
|---|
| 88 |  * This Function adds a new KeyFrame at position with newValue, if none was found in region of position. | 
|---|
| 89 |  */ | 
|---|
| 90 | bool QuickAnimation::changeValue(float position, float newValue, float region) | 
|---|
| 91 | { | 
|---|
| 92 |   int keyFrame = this->getKeyAt(position, region); | 
|---|
| 93 |   if (keyFrame == -1) | 
|---|
| 94 |     return this->addKey(position, newValue); | 
|---|
| 95 |   else | 
|---|
| 96 |     return this->changeValueKey(keyFrame, newValue); | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 |  | 
|---|
| 100 | /** | 
|---|
| 101 |  * @brief removes the keyFrameNumber'th entry. | 
|---|
| 102 |  * @param keyFrameNumber the n'th Keyframe to remove. | 
|---|
| 103 |  * @returns true on success, false if keyFrameNumber did not exist. | 
|---|
| 104 |  */ | 
|---|
| 105 | bool QuickAnimation::removeKey(unsigned int keyFrameNumber) | 
|---|
| 106 | { | 
|---|
| 107 |   if (keyFrameNumber < this->keyFrames.size()) | 
|---|
| 108 |   { | 
|---|
| 109 |     this->keyFrames.erase(this->keyFrames.begin() + keyFrameNumber); | 
|---|
| 110 |     this->rebuild(); | 
|---|
| 111 |     return true; | 
|---|
| 112 |   } | 
|---|
| 113 |   else | 
|---|
| 114 |     return false; | 
|---|
| 115 | } | 
|---|
| 116 |  | 
|---|
| 117 |  | 
|---|
| 118 | /** | 
|---|
| 119 |  * @brief removes a KeyFrame from the List. | 
|---|
| 120 |  * @param position the Keyframe at position position will be erased. | 
|---|
| 121 |  * @param region a deviation of the existing keyframe (like a delta in witch to search for) | 
|---|
| 122 |  * @returns true on success, false if no KeyFrame was found. | 
|---|
| 123 |  */ | 
|---|
| 124 | bool QuickAnimation::remove(float position, float region) | 
|---|
| 125 | { | 
|---|
| 126 |   int keyFrame = this->getKeyAt(position, region); | 
|---|
| 127 |   if (keyFrame == -1) | 
|---|
| 128 |     return false; | 
|---|
| 129 |   else | 
|---|
| 130 |     return this->removeKey(keyFrame); | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | /** | 
|---|
| 134 |  * @brief moves the keyFrame keyFrameNumber to newPosition/newValue. | 
|---|
| 135 |  * @param keyFrameNumber the n'th KeyFrame to move. | 
|---|
| 136 |  * @param newPosition the new Position for the KeyFrame. | 
|---|
| 137 |  * @param newValue the new Value for the KeyFrame. | 
|---|
| 138 |  * @returns true on success, false if the KeyFrame did not exist. | 
|---|
| 139 |  */ | 
|---|
| 140 | bool QuickAnimation::moveKey(unsigned int keyFrameNumber, float newPosition, float newValue) | 
|---|
| 141 | { | 
|---|
| 142 |   if (keyFrameNumber < this->keyFrames.size()) | 
|---|
| 143 |   { | 
|---|
| 144 |     this->keyFrames[keyFrameNumber].position = newPosition; | 
|---|
| 145 |     this->keyFrames[keyFrameNumber].value = newValue; | 
|---|
| 146 |     this->rebuild(); | 
|---|
| 147 |     return true; | 
|---|
| 148 |   } | 
|---|
| 149 |   else | 
|---|
| 150 |     return false; | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | /** | 
|---|
| 154 |  * @brief moves the keyFrame keyFrameNumber to newPosition/value. | 
|---|
| 155 |  * @param keyFrameNumber the n'th KeyFrame to move. | 
|---|
| 156 |  * @param newPosition the new Position for the KeyFrame. | 
|---|
| 157 |  * @returns true on success, false if the KeyFrame did not exist. | 
|---|
| 158 |  */ | 
|---|
| 159 | bool QuickAnimation::moveKey(unsigned int keyFrameNumber, float newPosition) | 
|---|
| 160 | { | 
|---|
| 161 |   if (keyFrameNumber < this->keyFrames.size()) | 
|---|
| 162 |   { | 
|---|
| 163 |     this->keyFrames[keyFrameNumber].position = newPosition; | 
|---|
| 164 |     this->rebuild(); | 
|---|
| 165 |     return true; | 
|---|
| 166 |   } | 
|---|
| 167 |   else | 
|---|
| 168 |     return false; | 
|---|
| 169 | } | 
|---|
| 170 |  | 
|---|
| 171 | /** | 
|---|
| 172 |  * @brief moves the keyFrame in the region of oldPosition to newPosition/newValue. | 
|---|
| 173 |  * @param oldPosition the old Position for the KeyFrame. | 
|---|
| 174 |  * @param newPosition the new Position for the KeyFrame. | 
|---|
| 175 |  * @param newValue the new Value for the KeyFrame. | 
|---|
| 176 |  * @param region the region around oldPosition to search for the KeyFrame. | 
|---|
| 177 |  * @returns true on success, false if the KeyFrame was not found within the region of oldPosition. | 
|---|
| 178 |  */ | 
|---|
| 179 | bool QuickAnimation::move(float oldPosition, float newPosition, float newValue, float region) | 
|---|
| 180 | { | 
|---|
| 181 |   int keyFrame = this->getKeyAt(oldPosition, region); | 
|---|
| 182 |   if (keyFrame == -1) | 
|---|
| 183 |     return false; | 
|---|
| 184 |   else | 
|---|
| 185 |     return this->moveKey(keyFrame, newPosition, newValue); | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | /** | 
|---|
| 189 |  * @brief moves the keyFrame in the region of oldPosition to newPosition/Value. | 
|---|
| 190 |  * @param oldPosition the old Position for the KeyFrame. | 
|---|
| 191 |  * @param newPosition the new Position for the KeyFrame. | 
|---|
| 192 |  * @param region the region around oldPosition to search for the KeyFrame. | 
|---|
| 193 |  * @returns true on success, false if the KeyFrame was not found within the region of oldPosition. | 
|---|
| 194 |  */ | 
|---|
| 195 | bool QuickAnimation::move(float oldPosition, float newPosition, float region) | 
|---|
| 196 | { | 
|---|
| 197 |   int keyFrame = this->getKeyAt(oldPosition, region); | 
|---|
| 198 |   if (keyFrame == -1) | 
|---|
| 199 |     return false; | 
|---|
| 200 |   else | 
|---|
| 201 |     return this->moveKey(keyFrame, newPosition); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 |  | 
|---|
| 205 | /** | 
|---|
| 206 |  * @brief searches for a Keyframe in the region of position | 
|---|
| 207 |  * @param position the Keyframe at position position will searched for. | 
|---|
| 208 |  * @param region a deviation of the existing keyframe (like a delta in witch to search for) | 
|---|
| 209 |  * @returns the keyFrame on success, -1 on fault. | 
|---|
| 210 |  */ | 
|---|
| 211 | int QuickAnimation::getKeyAt(float position, float region) | 
|---|
| 212 | { | 
|---|
| 213 |   for (unsigned int i = 0; i < this->keyFrames.size(); i++) | 
|---|
| 214 |   { | 
|---|
| 215 |     if (this->keyFrames[i].position + region/2.0 > position && this->keyFrames[i].position - region/2.0 < position) | 
|---|
| 216 |       return i; | 
|---|
| 217 |   } | 
|---|
| 218 |   return -1; | 
|---|
| 219 | } | 
|---|
| 220 |  | 
|---|
| 221 |  | 
|---|
| 222 | /** | 
|---|
| 223 |  * @brief rebuilds the QuickAnimation. | 
|---|
| 224 |  */ | 
|---|
| 225 | void QuickAnimation::rebuild() | 
|---|
| 226 | { | 
|---|
| 227 |   // if we do not have any KeyFrames | 
|---|
| 228 |   if (this->keyFrames.empty()) | 
|---|
| 229 |   { | 
|---|
| 230 |     for (unsigned int i = 0; i < this->lookupValues.size(); i++) | 
|---|
| 231 |       this->lookupValues[i] = 0.0f; | 
|---|
| 232 |     return; | 
|---|
| 233 |   } | 
|---|
| 234 |  | 
|---|
| 235 |   // Sort the List. | 
|---|
| 236 |   std::sort(this->keyFrames.begin(), this->keyFrames.end(), QuickKeyFrame::sortPositionPredicate); | 
|---|
| 237 |  | 
|---|
| 238 |   // rebuild the lookup-table | 
|---|
| 239 |   float sliceSize = 1.0f / this->lookupValues.size(); | 
|---|
| 240 |   unsigned int key = 0; | 
|---|
| 241 |   float preVal = this->keyFrames[0].value; | 
|---|
| 242 |   float prePos = this->keyFrames[0].position; | 
|---|
| 243 |  | 
|---|
| 244 |   float postVal = preVal; | 
|---|
| 245 |   float postPos = 1.0; | 
|---|
| 246 |  | 
|---|
| 247 |   if (this->keyFrames.size() > 1) | 
|---|
| 248 |   { | 
|---|
| 249 |     postVal = this->keyFrames[1].value; | 
|---|
| 250 |     postPos = this->keyFrames[1].position; | 
|---|
| 251 |   } | 
|---|
| 252 |  | 
|---|
| 253 |  | 
|---|
| 254 |   for (unsigned int i = 0; i < this->lookupValues.size(); i++) | 
|---|
| 255 |   { | 
|---|
| 256 |     float position = (float)i * sliceSize; | 
|---|
| 257 |  | 
|---|
| 258 |     // if we reach the Next KeyFrame | 
|---|
| 259 |     if (position > postPos) | 
|---|
| 260 |     { | 
|---|
| 261 |       // if we have more KeyFrames. | 
|---|
| 262 |       if (this->keyFrames.size() > ++key + 1) | 
|---|
| 263 |       { | 
|---|
| 264 |         preVal = this->keyFrames[key].value; | 
|---|
| 265 |         prePos = this->keyFrames[key].position; | 
|---|
| 266 |         postVal = this->keyFrames[key+1].value; | 
|---|
| 267 |         postPos = this->keyFrames[key+1].position; | 
|---|
| 268 |       } | 
|---|
| 269 |       // otherwise we reached the last KeyFrame | 
|---|
| 270 |       else | 
|---|
| 271 |       { | 
|---|
| 272 |         preVal = postVal; | 
|---|
| 273 |         prePos = postPos; | 
|---|
| 274 |         postPos = 1.0; | 
|---|
| 275 |       } | 
|---|
| 276 |     } | 
|---|
| 277 |     this->lookupValues[i] = preVal + ( postVal - preVal) / (postPos - prePos) * (position - prePos); | 
|---|
| 278 |   } | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | /** | 
|---|
| 282 |  * @brief outputs some nice information about this class | 
|---|
| 283 |  */ | 
|---|
| 284 | void QuickAnimation::debug() const | 
|---|
| 285 | { | 
|---|
| 286 |   printf("QuickAnim(KeyFrames:%d, Resolution:%d)::(position, value) ", this->keyFrames.size(), this->lookupValues.size()); | 
|---|
| 287 |  | 
|---|
| 288 |   for (unsigned int i = 0; i < this->keyFrames.size(); i++) | 
|---|
| 289 |     printf("(%0.2f, %0.2f)->", this->keyFrames[i].position, this->keyFrames[i].value); | 
|---|
| 290 |   printf("\n"); | 
|---|
| 291 | } | 
|---|
| 292 |  | 
|---|
| 293 |  | 
|---|
| 294 |  | 
|---|
| 295 | /** | 
|---|
| 296 |  * @brief compares two QuickKeyFrames with their positions. | 
|---|
| 297 |  * @param key1 the first keyframe | 
|---|
| 298 |  * @param key2 the second keyframe | 
|---|
| 299 |  * @returns true, if the key1.position < key2.position. | 
|---|
| 300 |  */ | 
|---|
| 301 | bool QuickAnimation::QuickKeyFrame::sortPositionPredicate(const QuickKeyFrame& key1, const QuickKeyFrame& key2) | 
|---|
| 302 | { | 
|---|
| 303 |   return (key1.position < key2.position); | 
|---|
| 304 | } | 
|---|
| 305 |  | 
|---|
| 306 | /** | 
|---|
| 307 |  * @brief compares two QuickKeyFrames with their values. | 
|---|
| 308 |  * @param key1 the first keyframe | 
|---|
| 309 |  * @param key2 the second keyframe | 
|---|
| 310 |  * @returns true, if the key1.value < key2.value. | 
|---|
| 311 |  */ | 
|---|
| 312 | bool QuickAnimation::QuickKeyFrame::sortValuePredicate(const QuickKeyFrame& key1, const QuickKeyFrame& key2) | 
|---|
| 313 | { | 
|---|
| 314 |   return (key1.value < key2.value); | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|