blob: 911182ebf049cc5432b663b9a2731bf3d30c3229 [file] [log] [blame]
Jorim Jaggi8f2ef8f2016-06-13 16:08:20 -07001package aurelienribon.tweenengine;
2
3import aurelienribon.tweenengine.equations.Quad;
4import java.util.HashMap;
5import 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 */
79public 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 */
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 */
105 public static void setWaypointsLimit(int limit) {
106 Tween.waypointsLimit = limit;
107 }
108
109 /**
110 * Gets the version number of the library.
111 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
366 private Tween() {
367 reset();
368 }
369
370 @Override
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
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
727 public Object getTarget() {
728 return target;
729 }
730
731 /**
732 * Gets the type of the tween.
733 */
734 public int getType() {
735 return type;
736 }
737
738 /**
739 * Gets the easing equation.
740 */
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 */
751 public float[] getTargetValues() {
752 return targetValues;
753 }
754
755 /**
756 * Gets the number of combined animations.
757 */
758 public int getCombinedAttributesCount() {
759 return combinedAttrsCnt;
760 }
761
762 /**
763 * Gets the TweenAccessor used with the target.
764 */
765 public TweenAccessor<?> getAccessor() {
766 return accessor;
767 }
768
769 /**
770 * Gets the class that was used to find the associated TweenAccessor.
771 */
772 public Class<?> getTargetClass() {
773 return targetClass;
774 }
775
776 // -------------------------------------------------------------------------
777 // Overrides
778 // -------------------------------------------------------------------------
779
780 @Override
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
794 public void free() {
795 pool.free(this);
796 }
797
798 @Override
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
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
883 protected void forceStartValues() {
884 if (target == null) return;
885 accessor.setValues(target, type, startValues);
886 }
887
888 @Override
889 protected void forceEndValues() {
890 if (target == null) return;
891 accessor.setValues(target, type, targetValues);
892 }
893
894 @Override
895 protected boolean containsTarget(Object target) {
896 return this.target == target;
897 }
898
899 @Override
900 protected boolean containsTarget(Object target, int tweenType) {
901 return this.target == target && this.type == tweenType;
902 }
903
904 // -------------------------------------------------------------------------
905 // Helpers
906 // -------------------------------------------------------------------------
907
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
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}