| [4597] | 1 | /* | 
|---|
| [1853] | 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. | 
|---|
| [1855] | 10 |  | 
|---|
 | 11 |    ### File Specific: | 
|---|
 | 12 |    main-programmer: ... | 
|---|
 | 13 |    co-programmer: ... | 
|---|
| [1853] | 14 | */ | 
|---|
 | 15 |  | 
|---|
| [3955] | 16 | //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ | 
|---|
| [1853] | 17 |  | 
|---|
| [4415] | 18 | #include "quick_animation.h" | 
|---|
| [1853] | 19 |  | 
|---|
| [7333] | 20 | #include <algorithm> | 
|---|
| [4415] | 21 |  | 
|---|
| [1853] | 22 |  | 
|---|
| [9406] | 23 |  | 
|---|
| [3245] | 24 | /** | 
|---|
| [7333] | 25 |  * @brief standard constructor | 
|---|
 | 26 |  * @param resolution the Resolution of the LookupTable | 
|---|
 | 27 |  */ | 
|---|
 | 28 | QuickAnimation::QuickAnimation (unsigned int resolution) | 
|---|
| [3365] | 29 | { | 
|---|
| [7333] | 30 |   this->lookupValues.resize(resolution, 0.0f); | 
|---|
| [3365] | 31 | } | 
|---|
| [1853] | 32 |  | 
|---|
| [3245] | 33 | /** | 
|---|
| [7333] | 34 |  * @brief deletes all the deconstructor stuff | 
|---|
 | 35 |  */ | 
|---|
| [4746] | 36 | QuickAnimation::~QuickAnimation () | 
|---|
| [7333] | 37 | { } | 
|---|
| [4597] | 38 |  | 
|---|
| [4421] | 39 | /** | 
|---|
| [7333] | 40 |  * @brief adds a new entry to the list of keyframes | 
|---|
| [4836] | 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 | 
|---|
| [7333] | 44 |  */ | 
|---|
 | 45 | bool QuickAnimation::addKey(float position, float value) | 
|---|
| [4415] | 46 | { | 
|---|
| [7333] | 47 |   if (position > 1.0f || position < 0.0f) | 
|---|
| [4654] | 48 |   { | 
|---|
| [7333] | 49 |     printf("QuickAnimation::Position MUST BE between 0.0f and 1.0f\n"); | 
|---|
 | 50 |     return false; | 
|---|
| [4654] | 51 |   } | 
|---|
| [7335] | 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 |   } | 
|---|
| [7333] | 57 |   this->keyFrames.push_back(QuickKeyFrame(position, value)); | 
|---|
| [4654] | 58 |  | 
|---|
| [7333] | 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()) | 
|---|
| [4654] | 73 |   { | 
|---|
| [7333] | 74 |     this->keyFrames[keyFrameNumber].value = newValue; | 
|---|
 | 75 |     this->rebuild(); | 
|---|
 | 76 |     return true; | 
|---|
| [4654] | 77 |   } | 
|---|
 | 78 |   else | 
|---|
| [7333] | 79 |     return false; | 
|---|
| [4415] | 80 | } | 
|---|
 | 81 |  | 
|---|
| [4421] | 82 | /** | 
|---|
| [7333] | 83 |  * @brief changes an entry in the region of position | 
|---|
| [4836] | 84 |  * @param position the Position of an existing keyframe | 
|---|
| [7333] | 85 |  * @param region a deviation of the existing keyframe (like a delta in witch to search for) | 
|---|
| [4836] | 86 |  * @param value the new Value | 
|---|
| [7333] | 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 | } | 
|---|
| [4654] | 98 |  | 
|---|
| [7333] | 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) | 
|---|
| [4425] | 106 | { | 
|---|
| [7333] | 107 |   if (keyFrameNumber < this->keyFrames.size()) | 
|---|
| [4656] | 108 |   { | 
|---|
| [7333] | 109 |     this->keyFrames.erase(this->keyFrames.begin() + keyFrameNumber); | 
|---|
 | 110 |     this->rebuild(); | 
|---|
 | 111 |     return true; | 
|---|
| [4656] | 112 |   } | 
|---|
| [7333] | 113 |   else | 
|---|
 | 114 |     return false; | 
|---|
| [4425] | 115 | } | 
|---|
 | 116 |  | 
|---|
| [4597] | 117 |  | 
|---|
| [4657] | 118 | /** | 
|---|
| [7333] | 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. | 
|---|
| [4657] | 123 |  */ | 
|---|
| [7333] | 124 | bool QuickAnimation::remove(float position, float region) | 
|---|
| [4657] | 125 | { | 
|---|
| [7333] | 126 |   int keyFrame = this->getKeyAt(position, region); | 
|---|
 | 127 |   if (keyFrame == -1) | 
|---|
 | 128 |     return false; | 
|---|
 | 129 |   else | 
|---|
 | 130 |     return this->removeKey(keyFrame); | 
|---|
 | 131 | } | 
|---|
| [4597] | 132 |  | 
|---|
| [7333] | 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()) | 
|---|
| [4425] | 143 |   { | 
|---|
| [7333] | 144 |     this->keyFrames[keyFrameNumber].position = newPosition; | 
|---|
 | 145 |     this->keyFrames[keyFrameNumber].value = newValue; | 
|---|
 | 146 |     this->rebuild(); | 
|---|
 | 147 |     return true; | 
|---|
| [4657] | 148 |   } | 
|---|
 | 149 |   else | 
|---|
| [7333] | 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()) | 
|---|
| [4425] | 162 |   { | 
|---|
| [7333] | 163 |     this->keyFrames[keyFrameNumber].position = newPosition; | 
|---|
 | 164 |     this->rebuild(); | 
|---|
 | 165 |     return true; | 
|---|
 | 166 |   } | 
|---|
 | 167 |   else | 
|---|
 | 168 |     return false; | 
|---|
 | 169 | } | 
|---|
| [4597] | 170 |  | 
|---|
| [7333] | 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; | 
|---|
| [4425] | 217 |   } | 
|---|
| [7333] | 218 |   return -1; | 
|---|
| [4657] | 219 | } | 
|---|
| [4425] | 220 |  | 
|---|
| [4657] | 221 |  | 
|---|
| [4425] | 222 | /** | 
|---|
| [7333] | 223 |  * @brief rebuilds the QuickAnimation. | 
|---|
 | 224 |  */ | 
|---|
 | 225 | void QuickAnimation::rebuild() | 
|---|
| [4415] | 226 | { | 
|---|
| [7333] | 227 |   // if we do not have any KeyFrames | 
|---|
 | 228 |   if (this->keyFrames.empty()) | 
|---|
| [4654] | 229 |   { | 
|---|
| [7333] | 230 |     for (unsigned int i = 0; i < this->lookupValues.size(); i++) | 
|---|
 | 231 |       this->lookupValues[i] = 0.0f; | 
|---|
 | 232 |     return; | 
|---|
 | 233 |   } | 
|---|
| [4654] | 234 |  | 
|---|
| [7333] | 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; | 
|---|
| [4654] | 251 |   } | 
|---|
| [7333] | 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 |   } | 
|---|
| [4415] | 279 | } | 
|---|
 | 280 |  | 
|---|
| [4479] | 281 | /** | 
|---|
| [7333] | 282 |  * @brief outputs some nice information about this class | 
|---|
 | 283 |  */ | 
|---|
 | 284 | void QuickAnimation::debug() const | 
|---|
| [4421] | 285 | { | 
|---|
| [7333] | 286 |   printf("QuickAnim(KeyFrames:%d, Resolution:%d)::(position, value) ", this->keyFrames.size(), this->lookupValues.size()); | 
|---|
| [4421] | 287 |  | 
|---|
| [7333] | 288 |   for (unsigned int i = 0; i < this->keyFrames.size(); i++) | 
|---|
 | 289 |     printf("(%f, %f)->", this->keyFrames[i].position, this->keyFrames[i].value); | 
|---|
 | 290 |   printf("\n"); | 
|---|
 | 291 | } | 
|---|
| [4421] | 292 |  | 
|---|
| [7333] | 293 |  | 
|---|
 | 294 |  | 
|---|
| [7334] | 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 |  */ | 
|---|
| [7333] | 301 | bool QuickAnimation::QuickKeyFrame::sortPositionPredicate(const QuickKeyFrame& key1, const QuickKeyFrame& key2) | 
|---|
 | 302 | { | 
|---|
 | 303 |   return (key1.position < key2.position); | 
|---|
| [4421] | 304 | } | 
|---|
| [7333] | 305 |  | 
|---|
| [7334] | 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 |  */ | 
|---|
| [7333] | 312 | bool QuickAnimation::QuickKeyFrame::sortValuePredicate(const QuickKeyFrame& key1, const QuickKeyFrame& key2) | 
|---|
 | 313 | { | 
|---|
 | 314 |   return (key1.value < key2.value); | 
|---|
 | 315 | } | 
|---|
 | 316 |  | 
|---|