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