Home | History | Annotate | Download | only in tweenengine
      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 	 */
     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 }
    924