1 /*
2 * Project: VizKit
3 * Version: 2.3
4
5 * Date: 20090823
6 * File: VisualAnimation.cpp
7 *
8 */
9
10 /***************************************************************************
11
12 Copyright (c) 2004-2009 Heiko Wichmann (http://www.imagomat.de/vizkit)
13
14
15 This software is provided 'as-is', without any expressed or implied warranty.
16 In no event will the authors be held liable for any damages
17 arising from the use of this software.
18
19 Permission is granted to anyone to use this software for any purpose,
20 including commercial applications, and to alter it and redistribute it
21 freely, subject to the following restrictions:
22
23 1. The origin of this software must not be misrepresented;
24 you must not claim that you wrote the original software.
25 If you use this software in a product, an acknowledgment
26 in the product documentation would be appreciated
27 but is not required.
28
29 2. Altered source versions must be plainly marked as such,
30 and must not be misrepresented as being the original software.
31
32 3. This notice may not be removed or altered from any source distribution.
33
34 ***************************************************************************/
35
36 #include "VisualAnimation.h"
37 #include "VisualAsset.h"
38 #include "VisualItemIdentifier.h"
39 #include "VisualTiming.h"
40 #include "VisualTimeline.h"
41 #include "VisualErrorHandling.h"
42 #include "VisualAnimationQueue.h"
43 #include "VisualGraphics.h"
44 #include "VisualCamera.h"
45
46
47 using namespace VizKit;
48
49
50 const uint32 VisualAnimation::maxNumberOfDebugHistoryEntries = 700;
51
52
VisualAnimation(AnimatedProperty theAnimatedProperty,bool aDebugMode)53 VisualAnimation::VisualAnimation(AnimatedProperty theAnimatedProperty, bool aDebugMode) {
54 if (aDebugMode == true) {
55 writeLog("VisualAnimation::VisualAnimation");
56 }
57 theTimeline = new VisualTimeline(aDebugMode);
58 animatedProperty = theAnimatedProperty;
59 remainingNumberOfRepeats = 0;
60 animateCallback = NULL;
61 animationUserData = NULL;
62 performAnyAdditionalActionCallback = NULL;
63 performAnyAdditionalActionCallbackUserData = NULL;
64 startDelayInMilliseconds = 0;
65 status = kIsNotRunning;
66 debugMode = aDebugMode;
67 currDebugHistoryEntry = 0;
68 collectionIdentifier = NULL;
69 enclosingAsset = NULL;
70 doStartAnimationWithCurrentPropertyValue = true;
71 startValue = 0.0;
72 stopValue = 1.0;
73 speed = theTimeline->getDistance() / theTimeline->getDurationInMilliseconds();
74 setSpeed(speed);
75 if (aDebugMode == true) {
76 for (size_t i = 0; i < this->maxNumberOfDebugHistoryEntries; i++) {
77 debugHistory.push_back(0.0);
78 }
79 debugHistoryIsInitialized = true;
80 } else {
81 debugHistoryIsInitialized = false;
82 }
83 willDieCallback = NULL;
84 willDieCallbackUserData = NULL;
85 }
86
87
~VisualAnimation()88 VisualAnimation::~VisualAnimation() {
89 delete theTimeline;
90 debugHistory.clear();
91 if (collectionIdentifier != NULL) {
92 delete collectionIdentifier;
93 }
94 }
95
96
VisualAnimation(const VisualAnimation & other)97 VisualAnimation::VisualAnimation(const VisualAnimation& other) : VisualAnimationComponent(other) {
98 copy(other);
99 }
100
101
operator =(const VisualAnimation & other)102 VisualAnimation& VisualAnimation::operator=(const VisualAnimation& other) {
103
104 if (this == &other) return *this;
105
106 VisualObject::operator=(other);
107
108 delete this->theTimeline;
109 if (this->collectionIdentifier != NULL) {
110 delete this->collectionIdentifier;
111 }
112
113 this->copy(other);
114
115 return *this;
116 }
117
118
clone(void) const119 VisualAnimationComponent* VisualAnimation::clone(void) const {
120 return new VisualAnimation(*this);
121 }
122
123
copy(const VisualAnimation & other)124 void VisualAnimation::copy(const VisualAnimation& other) {
125 // deep copy
126 if (other.debugMode == true) {
127 writeLog("VisualAnimation::copy");
128 }
129 this->theTimeline = new VisualTimeline(*other.theTimeline);
130 this->animatedProperty = other.animatedProperty;
131 this->remainingNumberOfRepeats = other.remainingNumberOfRepeats;
132 this->animateCallback = other.animateCallback;
133 this->animationUserData = other.animationUserData;
134 this->performAnyAdditionalActionCallback = other.performAnyAdditionalActionCallback;
135 this->performAnyAdditionalActionCallbackUserData = other.performAnyAdditionalActionCallbackUserData;
136 this->startDelayInMilliseconds = other.startDelayInMilliseconds;
137 this->status = other.status;
138 this->debugMode = other.debugMode;
139 this->currDebugHistoryEntry = other.currDebugHistoryEntry;
140 this->debugHistory = other.debugHistory;
141 this->debugHistoryIsInitialized = other.debugHistoryIsInitialized;
142 this->doStartAnimationWithCurrentPropertyValue = other.doStartAnimationWithCurrentPropertyValue;
143 this->startValue = other.startValue;
144 this->stopValue = other.stopValue;
145 if (other.collectionIdentifier != NULL) {
146 this->collectionIdentifier = new VisualItemIdentifier(*(other.collectionIdentifier));
147 } else {
148 this->collectionIdentifier = NULL;
149 }
150 this->enclosingAsset = other.enclosingAsset;
151 this->willDieCallback = other.willDieCallback;
152 this->willDieCallbackUserData = other.willDieCallbackUserData;
153 }
154
155
setAnimateCallbackFunctionPtr(VisualAnimationAnimateCallback theCallback,void * someUserData)156 void VisualAnimation::setAnimateCallbackFunctionPtr(VisualAnimationAnimateCallback theCallback, void* someUserData) {
157 this->animateCallback = theCallback;
158 this->animationUserData = someUserData;
159 }
160
161
setIdentifierOfParentCollection(const VisualItemIdentifier & aCollectionIdentifier)162 void VisualAnimation::setIdentifierOfParentCollection(const VisualItemIdentifier& aCollectionIdentifier) {
163 if (this->collectionIdentifier != NULL) {
164 delete this->collectionIdentifier;
165 }
166 this->collectionIdentifier = new VisualItemIdentifier(aCollectionIdentifier);
167 }
168
169
handleOneCollectionItemAnimationDied()170 void VisualAnimation::handleOneCollectionItemAnimationDied() {
171 char errLog[256];
172 sprintf(errLog, "Err: VisualAnimation is unable to handle collection animations in file: %s (line: %d) [%s])", __FILE__, __LINE__, __FUNCTION__);
173 writeLog(errLog);
174 return;
175 }
176
177
getVisualAnimation(const VisualItemIdentifier & anAnimationIdentifier)178 VisualAnimationComponent* VisualAnimation::getVisualAnimation(const VisualItemIdentifier& anAnimationIdentifier) {
179 if (VisualObject::getIdentifier() == anAnimationIdentifier) {
180 return this;
181 } else {
182 return NULL;
183 }
184 }
185
186
animate()187 void VisualAnimation::animate() {
188
189 double currVal = this->theTimeline->getCurrentValue();
190
191 if (this->debugMode == true) {
192 this->debugHistory[this->currDebugHistoryEntry] = currVal;
193 VisualCamera* aCamera = VisualCamera::createDefaultCamera();
194 VisualGraphics::drawHistoryDiagram(this->debugHistory, this->currDebugHistoryEntry, 0.0, 1.0, *aCamera);
195 delete aCamera;
196 if ((this->currDebugHistoryEntry + 1) < this->maxNumberOfDebugHistoryEntries) {
197 this->currDebugHistoryEntry++;
198 } else {
199 this->currDebugHistoryEntry = 0;
200 }
201 char logStr[128];
202 sprintf(logStr, "VisualAnimation::animate currVal: %f", currVal);
203 writeLog(logStr);
204 }
205 this->animateCallback(currVal, this->animationUserData);
206 if (this->performAnyAdditionalActionCallback != NULL) {
207 this->performAnyAdditionalActionCallback(this, this->performAnyAdditionalActionCallbackUserData);
208 }
209 }
210
211
start()212 void VisualAnimation::start() {
213 if (this->startDelayInMilliseconds > 0) {
214 return;
215 }
216 if (this->remainingNumberOfRepeats == 0) {
217 this->remainingNumberOfRepeats = 1;
218 }
219 this->theTimeline->start();
220 this->status = kIsRunning;
221 this->animate();
222 }
223
224
stop()225 void VisualAnimation::stop() {
226 this->status = kIsReadyToDie;
227 if (this->collectionIdentifier != NULL) {
228 VisualAnimationComponent* animationCollection = VisualAnimationQueue::getVisualAnimation(*(this->collectionIdentifier));
229 if (animationCollection != NULL) {
230 animationCollection->handleOneCollectionItemAnimationDied();
231 } else {
232 char errLog[256];
233 sprintf(errLog, "CollectionAnimation not found in in file: %s (line: %d) [%s])", __FILE__, __LINE__, __FUNCTION__);
234 writeLog(errLog);
235 }
236
237 }
238 }
239
240
setDurationInMilliseconds(uint32 numberOfMilliseconds)241 void VisualAnimation::setDurationInMilliseconds(uint32 numberOfMilliseconds) {
242 this->theTimeline->setDurationInMilliseconds(numberOfMilliseconds);
243 this->speed = this->calcSpeed(this->theTimeline->getDistance(), this->theTimeline->getDurationInMilliseconds());
244 this->durationSpeedConstraint = kDurationBound;
245 }
246
247
getDurationInMilliseconds() const248 uint32 VisualAnimation::getDurationInMilliseconds() const {
249 return this->theTimeline->getDurationInMilliseconds();
250 }
251
252
setCurrentValue(double aCurrentValue)253 void VisualAnimation::setCurrentValue(double aCurrentValue) {
254 AnimationSpeed prevSpeed = this->getSpeed();
255 bool adjustedDistanceAndDuration = this->theTimeline->setCurrentValue(aCurrentValue);
256 if (adjustedDistanceAndDuration == true) {
257 if (this->durationSpeedConstraint == kSpeedBound) {
258 this->setSpeed(prevSpeed);
259 }
260 }
261 // aCurrentValue might be out of range of this->startValue and this->stopValue
262 double maxValue = (this->startValue > this->stopValue) ? this->startValue : this->stopValue;
263 double minValue = (this->startValue < this->stopValue) ? this->startValue : this->stopValue;
264 if ((aCurrentValue < minValue) || (aCurrentValue > maxValue)) {
265 this->startValue = aCurrentValue;
266 this->doStartAnimationWithCurrentPropertyValue = true;
267 }
268 if (this->doStartAnimationWithCurrentPropertyValue == true) {
269 // movingDirection might need to change (we want to arrive at the stop position by way of the shortest distance)
270 MovingDirection movingDirection = this->theTimeline->getMovingDirection();
271 double theCurrentValue = this->theTimeline->getCurrentValue();
272 if ((movingDirection == kAscending) && theCurrentValue > this->stopValue) {
273 this->theTimeline->toggleMovingDirection();
274 } else if ((movingDirection == kDescending) && theCurrentValue < this->stopValue) {
275 this->theTimeline->toggleMovingDirection();
276 }
277 }
278
279 }
280
281
getCurrentValue() const282 double VisualAnimation::getCurrentValue() const {
283 return this->theTimeline->getCurrentValue();
284 }
285
286
setStartValue(double aStartValue,bool startAnimationWithCurrentPropertyValue)287 void VisualAnimation::setStartValue(double aStartValue, bool startAnimationWithCurrentPropertyValue) {
288 AnimationSpeed prevSpeed = this->getSpeed();
289 this->theTimeline->setStartValue(aStartValue);
290 this->startValue = aStartValue;
291 this->doStartAnimationWithCurrentPropertyValue = startAnimationWithCurrentPropertyValue;
292 if (this->durationSpeedConstraint == kSpeedBound) {
293 this->setSpeed(prevSpeed);
294 }
295 }
296
297
setStartValue(const VisualStagePosition & aPosition,bool startAnimationWithCurrentPropertyValue)298 void VisualAnimation::setStartValue(const VisualStagePosition& aPosition, bool startAnimationWithCurrentPropertyValue) {
299 AnimationSpeed prevSpeed = this->getSpeed();
300 //this->theTimeline->setStartValue(aStartValue);
301 //this->startValue = aStartValue;
302 this->startValueVisualStagePosition = aPosition;
303 this->doStartAnimationWithCurrentPropertyValue = startAnimationWithCurrentPropertyValue;
304 if (this->durationSpeedConstraint == kSpeedBound) {
305 this->setSpeed(prevSpeed);
306 }
307 }
308
309
getStartValue() const310 double VisualAnimation::getStartValue() const {
311 return this->startValue;
312 }
313
314
setStopValue(double aStopValue)315 void VisualAnimation::setStopValue(double aStopValue) {
316 AnimationSpeed prevSpeed = this->getSpeed();
317 theTimeline->setStopValue(aStopValue);
318 this->stopValue = aStopValue;
319 if (this->durationSpeedConstraint == kSpeedBound) {
320 this->setSpeed(prevSpeed);
321 }
322 }
323
324
setStopValue(const VisualStagePosition & aPosition)325 void VisualAnimation::setStopValue(const VisualStagePosition& aPosition) {
326 AnimationSpeed prevSpeed = this->getSpeed();
327 //theTimeline->setStopValue(aStopValue);
328 //this->stopValue = aStopValue;
329 this->stopValueVisualStagePosition = aPosition;
330 if (this->durationSpeedConstraint == kSpeedBound) {
331 this->setSpeed(prevSpeed);
332 }
333 }
334
335
getStopValue() const336 double VisualAnimation::getStopValue() const {
337 return this->stopValue;
338 }
339
340
setLoopMode(LoopMode aLoopMode,sint32 requestedNumberOfLoops)341 void VisualAnimation::setLoopMode(LoopMode aLoopMode, sint32 requestedNumberOfLoops) {
342 if ((aLoopMode & kMirroredLoop) == kMirroredLoop) {
343 theTimeline->setRepeatMode(kRepeatMirrored);
344 } else if ((aLoopMode & kLoop) == kLoop) {
345 theTimeline->setRepeatMode(kRepeatFromStart);
346 }
347 this->remainingNumberOfRepeats = requestedNumberOfLoops;
348 }
349
350
setInterpolationType(InterpolationType anInterpolationType)351 void VisualAnimation::setInterpolationType(InterpolationType anInterpolationType) {
352 this->theTimeline->setInterpolationType(anInterpolationType);
353 }
354
355
getStartDelayInMilliseconds() const356 uint32 VisualAnimation::getStartDelayInMilliseconds() const {
357 return this->startDelayInMilliseconds;
358 }
359
360
setStartDelayInMilliseconds(uint32 aStartDelayInMilliseconds)361 void VisualAnimation::setStartDelayInMilliseconds(uint32 aStartDelayInMilliseconds) {
362 this->startDelayInMilliseconds = aStartDelayInMilliseconds;
363 }
364
365
setCallbackToPerformAnyAdditionalAction(VisualAnimationPerformAnyAdditionalActionCallback theCallback,void * userData)366 void VisualAnimation::setCallbackToPerformAnyAdditionalAction(VisualAnimationPerformAnyAdditionalActionCallback theCallback, void* userData) {
367 this->performAnyAdditionalActionCallback = theCallback;
368 this->performAnyAdditionalActionCallbackUserData = userData;
369 }
370
371
setCallbackToNotifyBeforeDeath(VisualAnimationWillDieCallback theCallback,void * userData)372 void VisualAnimation::setCallbackToNotifyBeforeDeath(VisualAnimationWillDieCallback theCallback, void* userData) {
373 this->willDieCallback = theCallback;
374 this->willDieCallbackUserData = userData;
375 }
376
377
notifyBeforeDeath()378 void VisualAnimation::notifyBeforeDeath() {
379 if (this->willDieCallback != NULL) {
380 this->willDieCallback(this, this->willDieCallbackUserData);
381 }
382 }
383
384
getAnimatedProperty() const385 AnimatedProperty VisualAnimation::getAnimatedProperty() const {
386 return this->animatedProperty;
387 }
388
389
getMovingDirection(void) const390 MovingDirection VisualAnimation::getMovingDirection(void) const {
391 return this->theTimeline->getMovingDirection();
392 }
393
394
getRepeatMode(void) const395 RepeatMode VisualAnimation::getRepeatMode(void) const {
396 return this->theTimeline->getRepeatMode();
397 }
398
399
update()400 void VisualAnimation::update() {
401 if (this->status == kIsNotRunning) {
402 if (this->startDelayInMilliseconds > 0) {
403 uint32 elapsedMillisecondsOfDelay = VisualTiming::getElapsedMilliSecsSinceReset(VisualObject::getIdentifier());
404 if (elapsedMillisecondsOfDelay > this->startDelayInMilliseconds) {
405 this->startDelayInMilliseconds = 0;
406 VisualTiming::resetTimestamp(VisualObject::getIdentifier());
407 this->start();
408 }
409 }
410 } else if (this->status == kIsRunning) {
411 MovingDirection movingDirection = this->theTimeline->getMovingDirection();
412 TimelineUpdateResult result = this->theTimeline->update();
413 bool animateFinalValue = false;
414 double endValue = 0.0;
415 if (movingDirection == kAscending) {
416 if (this->startValue < this->stopValue) {
417 endValue = this->stopValue;
418 } else {
419 endValue = this->startValue;
420 }
421 } else if (movingDirection == kDescending) {
422 if (this->startValue < this->stopValue) {
423 endValue = this->startValue;
424 } else {
425 endValue = this->stopValue;
426 }
427 }
428 if (result != kTimelineUpdateOK) {
429 if (this->debugMode == true) {
430 char resultStr[128];
431 VisualTimeline::convertTimelineUpdateResultToString(result, resultStr);
432 char logStr[128];
433 sprintf(logStr, "VisualAnimation::update: TimelineUpdateResult == %s", resultStr);
434 writeLog(logStr);
435 }
436 animateFinalValue = true;
437 } else {
438 if (movingDirection == kAscending) {
439 if (this->theTimeline->getCurrentValue() >= endValue) {
440 if (this->debugMode == true) {
441 writeLog("VisualAnimation::update: this->theTimeline->getCurrentValue() >= endValue");
442 }
443 animateFinalValue = true;
444 }
445 } else if (movingDirection == kDescending) {
446 if (this->theTimeline->getCurrentValue() <= endValue) {
447 if (this->debugMode == true) {
448 writeLog("VisualAnimation::update: this->theTimeline->getCurrentValue() <= endValue");
449 }
450 animateFinalValue = true;
451 }
452 }
453 }
454 if (animateFinalValue == true) {
455 this->animateCallback(endValue, this->animationUserData);
456 this->durationIsExceeded();
457 }
458 }
459 }
460
461
isRunning() const462 bool VisualAnimation::isRunning() const {
463 if (this->status == kIsRunning) {
464 return true;
465 } else {
466 return false;
467 }
468 }
469
470
isReadyToDie(void) const471 bool VisualAnimation::isReadyToDie(void) const {
472 if (this->status == kIsReadyToDie) {
473 return true;
474 } else {
475 return false;
476 }
477 }
478
479
setDebugMode(bool requestedDebugMode)480 void VisualAnimation::setDebugMode(bool requestedDebugMode) {
481 this->debugMode = requestedDebugMode;
482 this->theTimeline->setDebugMode(requestedDebugMode);
483 if (this->debugHistoryIsInitialized == false) {
484 for (size_t i = 0; i < this->maxNumberOfDebugHistoryEntries; i++) {
485 debugHistory.push_back(0.0);
486 }
487 this->debugHistoryIsInitialized = true;
488 }
489 }
490
491
durationIsExceeded()492 void VisualAnimation::durationIsExceeded() {
493 if (this->remainingNumberOfRepeats != kInfiniteRepetition) {
494 this->decrementRemainingNumberOfRepeats();
495 }
496 }
497
498
decrementRemainingNumberOfRepeats()499 void VisualAnimation::decrementRemainingNumberOfRepeats() {
500 if (this->remainingNumberOfRepeats > 1) {
501 this->remainingNumberOfRepeats--;
502 } else {
503 this->stop();
504 }
505 }
506
507
preparePriorToAddingToAsset(VisualAsset & visualAsset)508 void VisualAnimation::preparePriorToAddingToAsset(VisualAsset& visualAsset) {
509
510 VisualAnimationQueue::removeVisualAnimationsWithOwnerIdentifier(visualAsset.getIdentifier(), this->animatedProperty);
511
512 if (this->doStartAnimationWithCurrentPropertyValue == true) {
513 this->setCurrentTimelineValueToCurrentPropertyValue(visualAsset, this->animatedProperty);
514 }
515
516 if (this->animatedProperty == kAnimatedOpacity) {
517 this->setAnimateCallbackFunctionPtr(VisualAsset::animateOpacity, (void*)&visualAsset);
518 } else if (this->animatedProperty == kAnimatedRotation) {
519 this->setAnimateCallbackFunctionPtr(VisualAsset::animateRotation, (void*)&visualAsset);
520 } else if (this->animatedProperty == kAnimatedSize) {
521 this->setAnimateCallbackFunctionPtr(VisualAsset::animateScaleFactor, (void*)&visualAsset);
522 } else if (this->animatedProperty == kAnimatedLocation) {
523 visualAsset.setStartValueVisualStagePosition(this->startValueVisualStagePosition);
524 visualAsset.setStopValueVisualStagePosition(this->stopValueVisualStagePosition);
525 this->setAnimateCallbackFunctionPtr(VisualAsset::animateLocation, (void*)&visualAsset);
526 }
527
528 this->enclosingAsset = &visualAsset;
529
530 }
531
532
getEnclosingAsset(void) const533 const VisualAsset* const VisualAnimation::getEnclosingAsset(void) const {
534 return this->enclosingAsset;
535 }
536
537
setSpeed(AnimationSpeed animationSpeed)538 void VisualAnimation::setSpeed(AnimationSpeed animationSpeed) {
539 if (this->debugMode == true) {
540 char logStr[128];
541 sprintf(logStr, "VisualAnimation::setSpeed: %f", animationSpeed);
542 writeLog(logStr);
543 }
544 //double timelineStartValue = 0.0;
545 //MovingDirection movingDirection = this->theTimeline->getMovingDirection();
546 double distance = this->theTimeline->getDistance();
547 uint32 newDuration = (uint32)(distance / (double)animationSpeed);
548 if (this->debugMode == true) {
549 char logStr[128];
550 sprintf(logStr, "VisualAnimation::setSpeed: newDuration: %d (distance: %f)", newDuration, distance);
551 writeLog(logStr);
552 }
553 this->theTimeline->setDurationInMilliseconds(newDuration);
554 /*
555 if (movingDirection == kAscending) {
556 timelineStartValue = theTimeline->getMaxValue() - (this->theTimeline->getDurationInMilliseconds() * animationSpeed);
557 } else if (movingDirection == kDescending) {
558 timelineStartValue = theTimeline->getMinValue() + (this->theTimeline->getDurationInMilliseconds() * animationSpeed);
559 }
560 theTimeline->setStartValue(timelineStartValue);
561 */
562 this->speed = animationSpeed;
563 this->durationSpeedConstraint = kSpeedBound;
564 }
565
566
getSpeed(void) const567 AnimationSpeed VisualAnimation::getSpeed(void) const {
568 return this->speed;
569 }
570
571
calcSpeed(double aStartValue,double aStopValue,uint32 aDurationInMilliseconds)572 AnimationSpeed VisualAnimation::calcSpeed(double aStartValue, double aStopValue, uint32 aDurationInMilliseconds) {
573 double aDistance = 0.0;
574 if (aStartValue < aStopValue) {
575 aDistance = aStopValue - aStartValue;
576 } else {
577 aDistance = aStartValue - aStopValue;
578 }
579 return VisualAnimation::calcSpeed(aDistance, aDurationInMilliseconds);
580 }
581
582
calcSpeed(double aDistance,uint32 aDurationInMilliseconds)583 AnimationSpeed VisualAnimation::calcSpeed(double aDistance, uint32 aDurationInMilliseconds) {
584 return (aDistance / static_cast<double>(aDurationInMilliseconds));
585 }
586
587
calcDurationInMilliseconds(double aDistance,AnimationSpeed aSpeed)588 uint32 VisualAnimation::calcDurationInMilliseconds(double aDistance, AnimationSpeed aSpeed) {
589 return static_cast<uint32>(aDistance / static_cast<double>(aSpeed));
590 }
591
592
setCurrentTimelineValueToCurrentPropertyValue(const VisualAsset & visualAsset,AnimatedProperty anAnimatedProperty)593 void VisualAnimation::setCurrentTimelineValueToCurrentPropertyValue(const VisualAsset& visualAsset, AnimatedProperty anAnimatedProperty) {
594 AnimationSpeed prevSpeed = this->getSpeed();
595 bool adjustedDistanceAndDuration = false;
596 if (anAnimatedProperty == kAnimatedLocation) {
597 adjustedDistanceAndDuration = this->theTimeline->setCurrentValue(visualAsset.getCurrentAnimationValueForAnimatedLocation(this->startValueVisualStagePosition, this->stopValueVisualStagePosition));
598 } else {
599 adjustedDistanceAndDuration = this->theTimeline->setCurrentValue(visualAsset.getCurrentAnimationValueOfProperty(anAnimatedProperty));
600 }
601 // movingDirection might need to change (we want to arrive at the stop position by way of the shortest distance)
602 MovingDirection movingDirection = this->theTimeline->getMovingDirection();
603 double theCurrentValue = this->theTimeline->getCurrentValue();
604 if ((movingDirection == kAscending) && theCurrentValue > this->stopValue) {
605 this->startValue = theCurrentValue;
606 this->theTimeline->toggleMovingDirection();
607 } else if ((movingDirection == kDescending) && theCurrentValue < this->stopValue) {
608 this->startValue = theCurrentValue;
609 this->theTimeline->toggleMovingDirection();
610 }
611 if (adjustedDistanceAndDuration == true) {
612 if (this->durationSpeedConstraint == kSpeedBound) {
613 this->setSpeed(prevSpeed);
614 }
615 }
616 }
617