• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package aurelienribon.tweenengine;
2 
3 import aurelienribon.tweenengine.equations.Quad;
4 import java.util.HashMap;
5 import java.util.Map;
6 
7 /**
8  * Core class of the Tween Engine. A Tween is basically an interpolation
9  * between two values of an object attribute. However, the main interest of a
10  * Tween is that you can apply an easing formula on this interpolation, in
11  * order to smooth the transitions or to achieve cool effects like springs or
12  * bounces.
13  * <p/>
14  *
15  * The Universal Tween Engine is called "universal" because it is able to apply
16  * interpolations on every attribute from every possible object. Therefore,
17  * every object in your application can be animated with cool effects: it does
18  * not matter if your application is a game, a desktop interface or even a
19  * console program! If it makes sense to animate something, then it can be
20  * animated through this engine.
21  * <p/>
22  *
23  * This class contains many static factory methods to create and instantiate
24  * new interpolations easily. The common way to create a Tween is by using one
25  * of these factories:
26  * <p/>
27  *
28  * - Tween.to(...)<br/>
29  * - Tween.from(...)<br/>
30  * - Tween.set(...)<br/>
31  * - Tween.call(...)
32  * <p/>
33  *
34  * <h2>Example - firing a Tween</h2>
35  *
36  * The following example will move the target horizontal position from its
37  * current value to x=200 and y=300, during 500ms, but only after a delay of
38  * 1000ms. The animation will also be repeated 2 times (the starting position
39  * is registered at the end of the delay, so the animation will automatically
40  * restart from this registered position).
41  * <p/>
42  *
43  * <pre> {@code
44  * Tween.to(myObject, POSITION_XY, 0.5f)
45  *      .target(200, 300)
46  *      .ease(Quad.INOUT)
47  *      .delay(1.0f)
48  *      .repeat(2, 0.2f)
49  *      .start(myManager);
50  * }</pre>
51  *
52  * Tween life-cycles can be automatically managed for you, thanks to the
53  * {@link TweenManager} class. If you choose to manage your tween when you start
54  * it, then you don't need to care about it anymore. <b>Tweens are
55  * <i>fire-and-forget</i>: don't think about them anymore once you started
56  * them (if they are managed of course).</b>
57  * <p/>
58  *
59  * You need to periodicaly update the tween engine, in order to compute the new
60  * values. If your tweens are managed, only update the manager; else you need
61  * to call {@link #update()} on your tweens periodically.
62  * <p/>
63  *
64  * <h2>Example - setting up the engine</h2>
65  *
66  * The engine cannot directly change your objects attributes, since it doesn't
67  * know them. Therefore, you need to tell him how to get and set the different
68  * attributes of your objects: <b>you need to implement the {@link
69  * TweenAccessor} interface for each object class you will animate</b>. Once
70  * done, don't forget to register these implementations, using the static method
71  * {@link registerAccessor()}, when you start your application.
72  *
73  * @see TweenAccessor
74  * @see TweenManager
75  * @see TweenEquation
76  * @see Timeline
77  * @author Aurelien Ribon | http://www.aurelienribon.com/
78  */
79 public final class Tween extends BaseTween<Tween> {
80 	// -------------------------------------------------------------------------
81 	// Static -- misc
82 	// -------------------------------------------------------------------------
83 
84 	/**
85 	 * Used as parameter in {@link #repeat(int, float)} and
86 	 * {@link #repeatYoyo(int, float)} methods.
87 	 */
88 	public static final int INFINITY = -1;
89 
90 	private static int combinedAttrsLimit = 3;
91 	private static int waypointsLimit = 0;
92 
93 	/**
94 	 * Changes the limit for combined attributes. Defaults to 3 to reduce
95 	 * memory footprint.
96 	 */
setCombinedAttributesLimit(int limit)97 	public static void setCombinedAttributesLimit(int limit) {
98 		Tween.combinedAttrsLimit = limit;
99 	}
100 
101 	/**
102 	 * Changes the limit of allowed waypoints for each tween. Defaults to 0 to
103 	 * reduce memory footprint.
104 	 */
setWaypointsLimit(int limit)105 	public static void setWaypointsLimit(int limit) {
106 		Tween.waypointsLimit = limit;
107 	}
108 
109 	/**
110 	 * Gets the version number of the library.
111 	 */
getVersion()112 	public static String getVersion() {
113 		return "6.3.3";
114 	}
115 
116 	// -------------------------------------------------------------------------
117 	// Static -- pool
118 	// -------------------------------------------------------------------------
119 
120 	private static final Pool.Callback<Tween> poolCallback = new Pool.Callback<Tween>() {
121 		@Override public void onPool(Tween obj) {obj.reset();}
122 		@Override public void onUnPool(Tween obj) {obj.reset();}
123 	};
124 
125 	private static final Pool<Tween> pool = new Pool<Tween>(20, poolCallback) {
126 		@Override protected Tween create() {return new Tween();}
127 	};
128 
129 	/**
130 	 * Used for debug purpose. Gets the current number of objects that are
131 	 * waiting in the Tween pool.
132 	 */
getPoolSize()133 	public static int getPoolSize() {
134 		return pool.size();
135 	}
136 
137 	/**
138 	 * Increases the minimum capacity of the pool. Capacity defaults to 20.
139 	 */
ensurePoolCapacity(int minCapacity)140 	public static void ensurePoolCapacity(int minCapacity) {
141 		pool.ensureCapacity(minCapacity);
142 	}
143 
144 	// -------------------------------------------------------------------------
145 	// Static -- tween accessors
146 	// -------------------------------------------------------------------------
147 
148 	private static final Map<Class<?>, TweenAccessor<?>> registeredAccessors = new HashMap<Class<?>, TweenAccessor<?>>();
149 
150 	/**
151 	 * Registers an accessor with the class of an object. This accessor will be
152 	 * used by tweens applied to every objects implementing the registered
153 	 * class, or inheriting from it.
154 	 *
155 	 * @param someClass An object class.
156 	 * @param defaultAccessor The accessor that will be used to tween any
157 	 * object of class "someClass".
158 	 */
registerAccessor(Class<?> someClass, TweenAccessor<?> defaultAccessor)159 	public static void registerAccessor(Class<?> someClass, TweenAccessor<?> defaultAccessor) {
160 		registeredAccessors.put(someClass, defaultAccessor);
161 	}
162 
163 	/**
164 	 * Gets the registered TweenAccessor associated with the given object class.
165 	 *
166 	 * @param someClass An object class.
167 	 */
getRegisteredAccessor(Class<?> someClass)168 	public static TweenAccessor<?> getRegisteredAccessor(Class<?> someClass) {
169 		return registeredAccessors.get(someClass);
170 	}
171 
172 	// -------------------------------------------------------------------------
173 	// Static -- factories
174 	// -------------------------------------------------------------------------
175 
176 	/**
177 	 * Factory creating a new standard interpolation. This is the most common
178 	 * type of interpolation. The starting values are retrieved automatically
179 	 * after the delay (if any).
180 	 * <br/><br/>
181 	 *
182 	 * <b>You need to set the target values of the interpolation by using one
183 	 * of the target() methods</b>. The interpolation will run from the
184 	 * starting values to these target values.
185 	 * <br/><br/>
186 	 *
187 	 * The common use of Tweens is "fire-and-forget": you do not need to care
188 	 * for tweens once you added them to a TweenManager, they will be updated
189 	 * automatically, and cleaned once finished. Common call:
190 	 * <br/><br/>
191 	 *
192 	 * <pre> {@code
193 	 * Tween.to(myObject, POSITION, 1.0f)
194 	 *      .target(50, 70)
195 	 *      .ease(Quad.INOUT)
196 	 *      .start(myManager);
197 	 * }</pre>
198 	 *
199 	 * Several options such as delay, repetitions and callbacks can be added to
200 	 * the tween.
201 	 *
202 	 * @param target The target object of the interpolation.
203 	 * @param tweenType The desired type of interpolation.
204 	 * @param duration The duration of the interpolation, in milliseconds.
205 	 * @return The generated Tween.
206 	 */
to(Object target, int tweenType, float duration)207 	public static Tween to(Object target, int tweenType, float duration) {
208 		Tween tween = pool.get();
209 		tween.setup(target, tweenType, duration);
210 		tween.ease(Quad.INOUT);
211 		tween.path(TweenPaths.catmullRom);
212 		return tween;
213 	}
214 
215 	/**
216 	 * Factory creating a new reversed interpolation. The ending values are
217 	 * retrieved automatically after the delay (if any).
218 	 * <br/><br/>
219 	 *
220 	 * <b>You need to set the starting values of the interpolation by using one
221 	 * of the target() methods</b>. The interpolation will run from the
222 	 * starting values to these target values.
223 	 * <br/><br/>
224 	 *
225 	 * The common use of Tweens is "fire-and-forget": you do not need to care
226 	 * for tweens once you added them to a TweenManager, they will be updated
227 	 * automatically, and cleaned once finished. Common call:
228 	 * <br/><br/>
229 	 *
230 	 * <pre> {@code
231 	 * Tween.from(myObject, POSITION, 1.0f)
232 	 *      .target(0, 0)
233 	 *      .ease(Quad.INOUT)
234 	 *      .start(myManager);
235 	 * }</pre>
236 	 *
237 	 * Several options such as delay, repetitions and callbacks can be added to
238 	 * the tween.
239 	 *
240 	 * @param target The target object of the interpolation.
241 	 * @param tweenType The desired type of interpolation.
242 	 * @param duration The duration of the interpolation, in milliseconds.
243 	 * @return The generated Tween.
244 	 */
from(Object target, int tweenType, float duration)245 	public static Tween from(Object target, int tweenType, float duration) {
246 		Tween tween = pool.get();
247 		tween.setup(target, tweenType, duration);
248 		tween.ease(Quad.INOUT);
249 		tween.path(TweenPaths.catmullRom);
250 		tween.isFrom = true;
251 		return tween;
252 	}
253 
254 	/**
255 	 * Factory creating a new instantaneous interpolation (thus this is not
256 	 * really an interpolation).
257 	 * <br/><br/>
258 	 *
259 	 * <b>You need to set the target values of the interpolation by using one
260 	 * of the target() methods</b>. The interpolation will set the target
261 	 * attribute to these values after the delay (if any).
262 	 * <br/><br/>
263 	 *
264 	 * The common use of Tweens is "fire-and-forget": you do not need to care
265 	 * for tweens once you added them to a TweenManager, they will be updated
266 	 * automatically, and cleaned once finished. Common call:
267 	 * <br/><br/>
268 	 *
269 	 * <pre> {@code
270 	 * Tween.set(myObject, POSITION)
271 	 *      .target(50, 70)
272 	 *      .delay(1.0f)
273 	 *      .start(myManager);
274 	 * }</pre>
275 	 *
276 	 * Several options such as delay, repetitions and callbacks can be added to
277 	 * the tween.
278 	 *
279 	 * @param target The target object of the interpolation.
280 	 * @param tweenType The desired type of interpolation.
281 	 * @return The generated Tween.
282 	 */
set(Object target, int tweenType)283 	public static Tween set(Object target, int tweenType) {
284 		Tween tween = pool.get();
285 		tween.setup(target, tweenType, 0);
286 		tween.ease(Quad.INOUT);
287 		return tween;
288 	}
289 
290 	/**
291 	 * Factory creating a new timer. The given callback will be triggered on
292 	 * each iteration start, after the delay.
293 	 * <br/><br/>
294 	 *
295 	 * The common use of Tweens is "fire-and-forget": you do not need to care
296 	 * for tweens once you added them to a TweenManager, they will be updated
297 	 * automatically, and cleaned once finished. Common call:
298 	 * <br/><br/>
299 	 *
300 	 * <pre> {@code
301 	 * Tween.call(myCallback)
302 	 *      .delay(1.0f)
303 	 *      .repeat(10, 1000)
304 	 *      .start(myManager);
305 	 * }</pre>
306 	 *
307 	 * @param callback The callback that will be triggered on each iteration
308 	 * start.
309 	 * @return The generated Tween.
310 	 * @see TweenCallback
311 	 */
call(TweenCallback callback)312 	public static Tween call(TweenCallback callback) {
313 		Tween tween = pool.get();
314 		tween.setup(null, -1, 0);
315 		tween.setCallback(callback);
316 		tween.setCallbackTriggers(TweenCallback.START);
317 		return tween;
318 	}
319 
320 	/**
321 	 * Convenience method to create an empty tween. Such object is only useful
322 	 * when placed inside animation sequences (see {@link Timeline}), in which
323 	 * it may act as a beacon, so you can set a callback on it in order to
324 	 * trigger some action at the right moment.
325 	 *
326 	 * @return The generated Tween.
327 	 * @see Timeline
328 	 */
mark()329 	public static Tween mark() {
330 		Tween tween = pool.get();
331 		tween.setup(null, -1, 0);
332 		return tween;
333 	}
334 
335 	// -------------------------------------------------------------------------
336 	// Attributes
337 	// -------------------------------------------------------------------------
338 
339 	// Main
340 	private Object target;
341 	private Class<?> targetClass;
342 	private TweenAccessor<Object> accessor;
343 	private int type;
344 	private TweenEquation equation;
345 	private TweenPath path;
346 
347 	// General
348 	private boolean isFrom;
349 	private boolean isRelative;
350 	private int combinedAttrsCnt;
351 	private int waypointsCnt;
352 
353 	// Values
354 	private final float[] startValues = new float[combinedAttrsLimit];
355 	private final float[] targetValues = new float[combinedAttrsLimit];
356 	private final float[] waypoints = new float[waypointsLimit * combinedAttrsLimit];
357 
358 	// Buffers
359 	private float[] accessorBuffer = new float[combinedAttrsLimit];
360 	private float[] pathBuffer = new float[(2+waypointsLimit)*combinedAttrsLimit];
361 
362 	// -------------------------------------------------------------------------
363 	// Setup
364 	// -------------------------------------------------------------------------
365 
Tween()366 	private Tween() {
367 		reset();
368 	}
369 
370 	@Override
reset()371 	protected void reset() {
372 		super.reset();
373 
374 		target = null;
375 		targetClass = null;
376 		accessor = null;
377 		type = -1;
378 		equation = null;
379 		path = null;
380 
381 		isFrom = isRelative = false;
382 		combinedAttrsCnt = waypointsCnt = 0;
383 
384 		if (accessorBuffer.length != combinedAttrsLimit) {
385 			accessorBuffer = new float[combinedAttrsLimit];
386 		}
387 
388 		if (pathBuffer.length != (2+waypointsLimit)*combinedAttrsLimit) {
389 			pathBuffer = new float[(2+waypointsLimit)*combinedAttrsLimit];
390 		}
391 	}
392 
setup(Object target, int tweenType, float duration)393 	private void setup(Object target, int tweenType, float duration) {
394 		if (duration < 0) throw new RuntimeException("Duration can't be negative");
395 
396 		this.target = target;
397 		this.targetClass = target != null ? findTargetClass() : null;
398 		this.type = tweenType;
399 		this.duration = duration;
400 	}
401 
findTargetClass()402 	private Class<?> findTargetClass() {
403 		if (registeredAccessors.containsKey(target.getClass())) return target.getClass();
404 		if (target instanceof TweenAccessor) return target.getClass();
405 
406 		Class<?> parentClass = target.getClass().getSuperclass();
407 		while (parentClass != null && !registeredAccessors.containsKey(parentClass))
408 			parentClass = parentClass.getSuperclass();
409 
410 		return parentClass;
411 	}
412 
413 	// -------------------------------------------------------------------------
414 	// Public API
415 	// -------------------------------------------------------------------------
416 
417 	/**
418 	 * Sets the easing equation of the tween. Existing equations are located in
419 	 * <i>aurelienribon.tweenengine.equations</i> package, but you can of course
420 	 * implement your owns, see {@link TweenEquation}. You can also use the
421 	 * {@link TweenEquations} static instances to quickly access all the
422 	 * equations. Default equation is Quad.INOUT.
423 	 * <p/>
424 	 *
425 	 * <b>Proposed equations are:</b><br/>
426 	 * - Linear.INOUT,<br/>
427 	 * - Quad.IN | OUT | INOUT,<br/>
428 	 * - Cubic.IN | OUT | INOUT,<br/>
429 	 * - Quart.IN | OUT | INOUT,<br/>
430 	 * - Quint.IN | OUT | INOUT,<br/>
431 	 * - Circ.IN | OUT | INOUT,<br/>
432 	 * - Sine.IN | OUT | INOUT,<br/>
433 	 * - Expo.IN | OUT | INOUT,<br/>
434 	 * - Back.IN | OUT | INOUT,<br/>
435 	 * - Bounce.IN | OUT | INOUT,<br/>
436 	 * - Elastic.IN | OUT | INOUT
437 	 *
438 	 * @return The current tween, for chaining instructions.
439 	 * @see TweenEquation
440 	 * @see TweenEquations
441 	 */
ease(TweenEquation easeEquation)442 	public Tween ease(TweenEquation easeEquation) {
443 		this.equation = easeEquation;
444 		return this;
445 	}
446 
447 	/**
448 	 * Forces the tween to use the TweenAccessor registered with the given
449 	 * target class. Useful if you want to use a specific accessor associated
450 	 * to an interface, for instance.
451 	 *
452 	 * @param targetClass A class registered with an accessor.
453 	 * @return The current tween, for chaining instructions.
454 	 */
cast(Class<?> targetClass)455 	public Tween cast(Class<?> targetClass) {
456 		if (isStarted()) throw new RuntimeException("You can't cast the target of a tween once it is started");
457 		this.targetClass = targetClass;
458 		return this;
459 	}
460 
461 	/**
462 	 * Sets the target value of the interpolation. The interpolation will run
463 	 * from the <b>value at start time (after the delay, if any)</b> to this
464 	 * target value.
465 	 * <p/>
466 	 *
467 	 * To sum-up:<br/>
468 	 * - start value: value at start time, after delay<br/>
469 	 * - end value: param
470 	 *
471 	 * @param targetValue The target value of the interpolation.
472 	 * @return The current tween, for chaining instructions.
473 	 */
target(float targetValue)474 	public Tween target(float targetValue) {
475 		targetValues[0] = targetValue;
476 		return this;
477 	}
478 
479 	/**
480 	 * Sets the target values of the interpolation. The interpolation will run
481 	 * from the <b>values at start time (after the delay, if any)</b> to these
482 	 * target values.
483 	 * <p/>
484 	 *
485 	 * To sum-up:<br/>
486 	 * - start values: values at start time, after delay<br/>
487 	 * - end values: params
488 	 *
489 	 * @param targetValue1 The 1st target value of the interpolation.
490 	 * @param targetValue2 The 2nd target value of the interpolation.
491 	 * @return The current tween, for chaining instructions.
492 	 */
target(float targetValue1, float targetValue2)493 	public Tween target(float targetValue1, float targetValue2) {
494 		targetValues[0] = targetValue1;
495 		targetValues[1] = targetValue2;
496 		return this;
497 	}
498 
499 	/**
500 	 * Sets the target values of the interpolation. The interpolation will run
501 	 * from the <b>values at start time (after the delay, if any)</b> to these
502 	 * target values.
503 	 * <p/>
504 	 *
505 	 * To sum-up:<br/>
506 	 * - start values: values at start time, after delay<br/>
507 	 * - end values: params
508 	 *
509 	 * @param targetValue1 The 1st target value of the interpolation.
510 	 * @param targetValue2 The 2nd target value of the interpolation.
511 	 * @param targetValue3 The 3rd target value of the interpolation.
512 	 * @return The current tween, for chaining instructions.
513 	 */
target(float targetValue1, float targetValue2, float targetValue3)514 	public Tween target(float targetValue1, float targetValue2, float targetValue3) {
515 		targetValues[0] = targetValue1;
516 		targetValues[1] = targetValue2;
517 		targetValues[2] = targetValue3;
518 		return this;
519 	}
520 
521 	/**
522 	 * Sets the target values of the interpolation. The interpolation will run
523 	 * from the <b>values at start time (after the delay, if any)</b> to these
524 	 * target values.
525 	 * <p/>
526 	 *
527 	 * To sum-up:<br/>
528 	 * - start values: values at start time, after delay<br/>
529 	 * - end values: params
530 	 *
531 	 * @param targetValues The target values of the interpolation.
532 	 * @return The current tween, for chaining instructions.
533 	 */
target(float... targetValues)534 	public Tween target(float... targetValues) {
535 		if (targetValues.length > combinedAttrsLimit) throwCombinedAttrsLimitReached();
536 		System.arraycopy(targetValues, 0, this.targetValues, 0, targetValues.length);
537 		return this;
538 	}
539 
540 	/**
541 	 * Sets the target value of the interpolation, relatively to the <b>value
542 	 * at start time (after the delay, if any)</b>.
543 	 * <p/>
544 	 *
545 	 * To sum-up:<br/>
546 	 * - start value: value at start time, after delay<br/>
547 	 * - end value: param + value at start time, after delay
548 	 *
549 	 * @param targetValue The relative target value of the interpolation.
550 	 * @return The current tween, for chaining instructions.
551 	 */
targetRelative(float targetValue)552 	public Tween targetRelative(float targetValue) {
553 		isRelative = true;
554 		targetValues[0] = isInitialized() ? targetValue + startValues[0] : targetValue;
555 		return this;
556 	}
557 
558 	/**
559 	 * Sets the target values of the interpolation, relatively to the <b>values
560 	 * at start time (after the delay, if any)</b>.
561 	 * <p/>
562 	 *
563 	 * To sum-up:<br/>
564 	 * - start values: values at start time, after delay<br/>
565 	 * - end values: params + values at start time, after delay
566 	 *
567 	 * @param targetValue1 The 1st relative target value of the interpolation.
568 	 * @param targetValue2 The 2nd relative target value of the interpolation.
569 	 * @return The current tween, for chaining instructions.
570 	 */
targetRelative(float targetValue1, float targetValue2)571 	public Tween targetRelative(float targetValue1, float targetValue2) {
572 		isRelative = true;
573 		targetValues[0] = isInitialized() ? targetValue1 + startValues[0] : targetValue1;
574 		targetValues[1] = isInitialized() ? targetValue2 + startValues[1] : targetValue2;
575 		return this;
576 	}
577 
578 	/**
579 	 * Sets the target values of the interpolation, relatively to the <b>values
580 	 * at start time (after the delay, if any)</b>.
581 	 * <p/>
582 	 *
583 	 * To sum-up:<br/>
584 	 * - start values: values at start time, after delay<br/>
585 	 * - end values: params + values at start time, after delay
586 	 *
587 	 * @param targetValue1 The 1st relative target value of the interpolation.
588 	 * @param targetValue2 The 2nd relative target value of the interpolation.
589 	 * @param targetValue3 The 3rd relative target value of the interpolation.
590 	 * @return The current tween, for chaining instructions.
591 	 */
targetRelative(float targetValue1, float targetValue2, float targetValue3)592 	public Tween targetRelative(float targetValue1, float targetValue2, float targetValue3) {
593 		isRelative = true;
594 		targetValues[0] = isInitialized() ? targetValue1 + startValues[0] : targetValue1;
595 		targetValues[1] = isInitialized() ? targetValue2 + startValues[1] : targetValue2;
596 		targetValues[2] = isInitialized() ? targetValue3 + startValues[2] : targetValue3;
597 		return this;
598 	}
599 
600 	/**
601 	 * Sets the target values of the interpolation, relatively to the <b>values
602 	 * at start time (after the delay, if any)</b>.
603 	 * <p/>
604 	 *
605 	 * To sum-up:<br/>
606 	 * - start values: values at start time, after delay<br/>
607 	 * - end values: params + values at start time, after delay
608 	 *
609 	 * @param targetValues The relative target values of the interpolation.
610 	 * @return The current tween, for chaining instructions.
611 	 */
targetRelative(float... targetValues)612 	public Tween targetRelative(float... targetValues) {
613 		if (targetValues.length > combinedAttrsLimit) throwCombinedAttrsLimitReached();
614 		for (int i=0; i<targetValues.length; i++) {
615 			this.targetValues[i] = isInitialized() ? targetValues[i] + startValues[i] : targetValues[i];
616 		}
617 
618 		isRelative = true;
619 		return this;
620 	}
621 
622 	/**
623 	 * Adds a waypoint to the path. The default path runs from the start values
624 	 * to the end values linearly. If you add waypoints, the default path will
625 	 * use a smooth catmull-rom spline to navigate between the waypoints, but
626 	 * you can change this behavior by using the {@link #path(TweenPath)}
627 	 * method.
628 	 *
629 	 * @param targetValue The target of this waypoint.
630 	 * @return The current tween, for chaining instructions.
631 	 */
waypoint(float targetValue)632 	public Tween waypoint(float targetValue) {
633 		if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
634 		waypoints[waypointsCnt] = targetValue;
635 		waypointsCnt += 1;
636 		return this;
637 	}
638 
639 	/**
640 	 * Adds a waypoint to the path. The default path runs from the start values
641 	 * to the end values linearly. If you add waypoints, the default path will
642 	 * use a smooth catmull-rom spline to navigate between the waypoints, but
643 	 * you can change this behavior by using the {@link #path(TweenPath)}
644 	 * method.
645 	 * <p/>
646 	 * Note that if you want waypoints relative to the start values, use one of
647 	 * the .targetRelative() methods to define your target.
648 	 *
649 	 * @param targetValue1 The 1st target of this waypoint.
650 	 * @param targetValue2 The 2nd target of this waypoint.
651 	 * @return The current tween, for chaining instructions.
652 	 */
waypoint(float targetValue1, float targetValue2)653 	public Tween waypoint(float targetValue1, float targetValue2) {
654 		if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
655 		waypoints[waypointsCnt*2] = targetValue1;
656 		waypoints[waypointsCnt*2+1] = targetValue2;
657 		waypointsCnt += 1;
658 		return this;
659 	}
660 
661 	/**
662 	 * Adds a waypoint to the path. The default path runs from the start values
663 	 * to the end values linearly. If you add waypoints, the default path will
664 	 * use a smooth catmull-rom spline to navigate between the waypoints, but
665 	 * you can change this behavior by using the {@link #path(TweenPath)}
666 	 * method.
667 	 * <p/>
668 	 * Note that if you want waypoints relative to the start values, use one of
669 	 * the .targetRelative() methods to define your target.
670 	 *
671 	 * @param targetValue1 The 1st target of this waypoint.
672 	 * @param targetValue2 The 2nd target of this waypoint.
673 	 * @param targetValue3 The 3rd target of this waypoint.
674 	 * @return The current tween, for chaining instructions.
675 	 */
waypoint(float targetValue1, float targetValue2, float targetValue3)676 	public Tween waypoint(float targetValue1, float targetValue2, float targetValue3) {
677 		if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
678 		waypoints[waypointsCnt*3] = targetValue1;
679 		waypoints[waypointsCnt*3+1] = targetValue2;
680 		waypoints[waypointsCnt*3+2] = targetValue3;
681 		waypointsCnt += 1;
682 		return this;
683 	}
684 
685 	/**
686 	 * Adds a waypoint to the path. The default path runs from the start values
687 	 * to the end values linearly. If you add waypoints, the default path will
688 	 * use a smooth catmull-rom spline to navigate between the waypoints, but
689 	 * you can change this behavior by using the {@link #path(TweenPath)}
690 	 * method.
691 	 * <p/>
692 	 * Note that if you want waypoints relative to the start values, use one of
693 	 * the .targetRelative() methods to define your target.
694 	 *
695 	 * @param targetValues The targets of this waypoint.
696 	 * @return The current tween, for chaining instructions.
697 	 */
waypoint(float... targetValues)698 	public Tween waypoint(float... targetValues) {
699 		if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
700 		System.arraycopy(targetValues, 0, waypoints, waypointsCnt*targetValues.length, targetValues.length);
701 		waypointsCnt += 1;
702 		return this;
703 	}
704 
705 	/**
706 	 * Sets the algorithm that will be used to navigate through the waypoints,
707 	 * from the start values to the end values. Default is a catmull-rom spline,
708 	 * but you can find other paths in the {@link TweenPaths} class.
709 	 *
710 	 * @param path A TweenPath implementation.
711 	 * @return The current tween, for chaining instructions.
712 	 * @see TweenPath
713 	 * @see TweenPaths
714 	 */
path(TweenPath path)715 	public Tween path(TweenPath path) {
716 		this.path = path;
717 		return this;
718 	}
719 
720 	// -------------------------------------------------------------------------
721 	// Getters
722 	// -------------------------------------------------------------------------
723 
724 	/**
725 	 * Gets the target object.
726 	 */
getTarget()727 	public Object getTarget() {
728 		return target;
729 	}
730 
731 	/**
732 	 * Gets the type of the tween.
733 	 */
getType()734 	public int getType() {
735 		return type;
736 	}
737 
738 	/**
739 	 * Gets the easing equation.
740 	 */
getEasing()741 	public TweenEquation getEasing() {
742 		return equation;
743 	}
744 
745 	/**
746 	 * Gets the target values. The returned buffer is as long as the maximum
747 	 * allowed combined values. Therefore, you're surely not interested in all
748 	 * its content. Use {@link #getCombinedTweenCount()} to get the number of
749 	 * interesting slots.
750 	 */
getTargetValues()751 	public float[] getTargetValues() {
752 		return targetValues;
753 	}
754 
755 	/**
756 	 * Gets the number of combined animations.
757 	 */
getCombinedAttributesCount()758 	public int getCombinedAttributesCount() {
759 		return combinedAttrsCnt;
760 	}
761 
762 	/**
763 	 * Gets the TweenAccessor used with the target.
764 	 */
getAccessor()765 	public TweenAccessor<?> getAccessor() {
766 		return accessor;
767 	}
768 
769 	/**
770 	 * Gets the class that was used to find the associated TweenAccessor.
771 	 */
getTargetClass()772 	public Class<?> getTargetClass() {
773 		return targetClass;
774 	}
775 
776 	// -------------------------------------------------------------------------
777 	// Overrides
778 	// -------------------------------------------------------------------------
779 
780 	@Override
build()781 	public Tween build() {
782 		if (target == null) return this;
783 
784 		accessor = (TweenAccessor<Object>) registeredAccessors.get(targetClass);
785 		if (accessor == null && target instanceof TweenAccessor) accessor = (TweenAccessor<Object>) target;
786 		if (accessor != null) combinedAttrsCnt = accessor.getValues(target, type, accessorBuffer);
787 		else throw new RuntimeException("No TweenAccessor was found for the target");
788 
789 		if (combinedAttrsCnt > combinedAttrsLimit) throwCombinedAttrsLimitReached();
790 		return this;
791 	}
792 
793 	@Override
free()794 	public void free() {
795 		pool.free(this);
796 	}
797 
798 	@Override
initializeOverride()799 	protected void initializeOverride() {
800 		if (target == null) return;
801 
802 		accessor.getValues(target, type, startValues);
803 
804 		for (int i=0; i<combinedAttrsCnt; i++) {
805 			targetValues[i] += isRelative ? startValues[i] : 0;
806 
807 			for (int ii=0; ii<waypointsCnt; ii++) {
808 				waypoints[ii*combinedAttrsCnt+i] += isRelative ? startValues[i] : 0;
809 			}
810 
811 			if (isFrom) {
812 				float tmp = startValues[i];
813 				startValues[i] = targetValues[i];
814 				targetValues[i] = tmp;
815 			}
816 		}
817 	}
818 
819 	@Override
updateOverride(int step, int lastStep, boolean isIterationStep, float delta)820 	protected void updateOverride(int step, int lastStep, boolean isIterationStep, float delta) {
821 		if (target == null || equation == null) return;
822 
823 		// Case iteration end has been reached
824 
825 		if (!isIterationStep && step > lastStep) {
826 			accessor.setValues(target, type, isReverse(lastStep) ? startValues : targetValues);
827 			return;
828 		}
829 
830 		if (!isIterationStep && step < lastStep) {
831 			accessor.setValues(target, type, isReverse(lastStep) ? targetValues : startValues);
832 			return;
833 		}
834 
835 		// Validation
836 
837 		assert isIterationStep;
838 		assert getCurrentTime() >= 0;
839 		assert getCurrentTime() <= duration;
840 
841 		// Case duration equals zero
842 
843 		if (duration < 0.00000000001f && delta > -0.00000000001f) {
844 			accessor.setValues(target, type, isReverse(step) ? targetValues : startValues);
845 			return;
846 		}
847 
848 		if (duration < 0.00000000001f && delta < 0.00000000001f) {
849 			accessor.setValues(target, type, isReverse(step) ? startValues : targetValues);
850 			return;
851 		}
852 
853 		// Normal behavior
854 
855 		float time = isReverse(step) ? duration - getCurrentTime() : getCurrentTime();
856 		float t = equation.compute(time/duration);
857 
858 		if (waypointsCnt == 0 || path == null) {
859 			for (int i=0; i<combinedAttrsCnt; i++) {
860 				accessorBuffer[i] = startValues[i] + t * (targetValues[i] - startValues[i]);
861 			}
862 
863 		} else {
864 			for (int i=0; i<combinedAttrsCnt; i++) {
865 				pathBuffer[0] = startValues[i];
866 				pathBuffer[1+waypointsCnt] = targetValues[i];
867 				for (int ii=0; ii<waypointsCnt; ii++) {
868 					pathBuffer[ii+1] = waypoints[ii*combinedAttrsCnt+i];
869 				}
870 
871 				accessorBuffer[i] = path.compute(t, pathBuffer, waypointsCnt+2);
872 			}
873 		}
874 
875 		accessor.setValues(target, type, accessorBuffer);
876 	}
877 
878 	// -------------------------------------------------------------------------
879 	// BaseTween impl.
880 	// -------------------------------------------------------------------------
881 
882 	@Override
forceStartValues()883 	protected void forceStartValues() {
884 		if (target == null) return;
885 		accessor.setValues(target, type, startValues);
886 	}
887 
888 	@Override
forceEndValues()889 	protected void forceEndValues() {
890 		if (target == null) return;
891 		accessor.setValues(target, type, targetValues);
892 	}
893 
894 	@Override
containsTarget(Object target)895 	protected boolean containsTarget(Object target) {
896 		return this.target == target;
897 	}
898 
899 	@Override
containsTarget(Object target, int tweenType)900 	protected boolean containsTarget(Object target, int tweenType) {
901 		return this.target == target && this.type == tweenType;
902 	}
903 
904 	// -------------------------------------------------------------------------
905 	// Helpers
906 	// -------------------------------------------------------------------------
907 
throwCombinedAttrsLimitReached()908 	private void throwCombinedAttrsLimitReached() {
909 		String msg = "You cannot combine more than " + combinedAttrsLimit + " "
910 			+ "attributes in a tween. You can raise this limit with "
911 			+ "Tween.setCombinedAttributesLimit(), which should be called once "
912 			+ "in application initialization code.";
913 		throw new RuntimeException(msg);
914 	}
915 
throwWaypointsLimitReached()916 	private void throwWaypointsLimitReached() {
917 		String msg = "You cannot add more than " + waypointsLimit + " "
918 			+ "waypoints to a tween. You can raise this limit with "
919 			+ "Tween.setWaypointsLimit(), which should be called once in "
920 			+ "application initialization code.";
921 		throw new RuntimeException(msg);
922 	}
923 }
924