aboutsummaryrefslogtreecommitdiff
path: root/java/api
diff options
context:
space:
mode:
Diffstat (limited to 'java/api')
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine.gwt.xml4
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/BaseTween.java543
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/Pool.java55
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/Timeline.java363
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/Tween.java923
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenAccessor.java82
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenCallback.java45
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenEquation.java28
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenEquations.java52
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenManager.java237
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenPath.java22
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenPaths.java14
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/TweenUtils.java53
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Back.java59
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Bounce.java55
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Circ.java47
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Cubic.java47
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Elastic.java86
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Expo.java49
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Linear.java22
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Quad.java47
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Quart.java47
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Quint.java47
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/equations/Sine.java48
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/paths/CatmullRom.java39
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/paths/Linear.java19
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/primitives/MutableFloat.java34
-rwxr-xr-xjava/api/src/aurelienribon/tweenengine/primitives/MutableInteger.java34
28 files changed, 3101 insertions, 0 deletions
diff --git a/java/api/src/aurelienribon/tweenengine.gwt.xml b/java/api/src/aurelienribon/tweenengine.gwt.xml
new file mode 100755
index 0000000..3b4e623
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine.gwt.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<module rename-to="aurelienribon.tweenengine">
+ <source path="tweenengine" />
+</module> \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/BaseTween.java b/java/api/src/aurelienribon/tweenengine/BaseTween.java
new file mode 100755
index 0000000..d8cf0e6
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/BaseTween.java
@@ -0,0 +1,543 @@
+package aurelienribon.tweenengine;
+
+/**
+ * BaseTween is the base class of Tween and Timeline. It defines the
+ * iteration engine used to play animations for any number of times, and in
+ * any direction, at any speed.
+ * <p/>
+ *
+ * It is responsible for calling the different callbacks at the right moments,
+ * and for making sure that every callbacks are triggered, even if the update
+ * engine gets a big delta time at once.
+ *
+ * @see Tween
+ * @see Timeline
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class BaseTween<T> {
+ // General
+ private int step;
+ private int repeatCnt;
+ private boolean isIterationStep;
+ private boolean isYoyo;
+
+ // Timings
+ protected float delay;
+ protected float duration;
+ private float repeatDelay;
+ private float currentTime;
+ private float deltaTime;
+ private boolean isStarted; // true when the object is started
+ private boolean isInitialized; // true after the delay
+ private boolean isFinished; // true when all repetitions are done
+ private boolean isKilled; // true if kill() was called
+ private boolean isPaused; // true if pause() was called
+
+ // Misc
+ private TweenCallback callback;
+ private int callbackTriggers;
+ private Object userData;
+
+ // Package access
+ boolean isAutoRemoveEnabled;
+ boolean isAutoStartEnabled;
+
+ // -------------------------------------------------------------------------
+
+ protected void reset() {
+ step = -2;
+ repeatCnt = 0;
+ isIterationStep = isYoyo = false;
+
+ delay = duration = repeatDelay = currentTime = deltaTime = 0;
+ isStarted = isInitialized = isFinished = isKilled = isPaused = false;
+
+ callback = null;
+ callbackTriggers = TweenCallback.COMPLETE;
+ userData = null;
+
+ isAutoRemoveEnabled = isAutoStartEnabled = true;
+ }
+
+ // -------------------------------------------------------------------------
+ // Public API
+ // -------------------------------------------------------------------------
+
+ /**
+ * Builds and validates the object. Only needed if you want to finalize a
+ * tween or timeline without starting it, since a call to ".start()" also
+ * calls this method.
+ *
+ * @return The current object, for chaining instructions.
+ */
+ public T build() {
+ return (T) this;
+ }
+
+ /**
+ * Starts or restarts the object unmanaged. You will need to take care of
+ * its life-cycle. If you want the tween to be managed for you, use a
+ * {@link TweenManager}.
+ *
+ * @return The current object, for chaining instructions.
+ */
+ public T start() {
+ build();
+ currentTime = 0;
+ isStarted = true;
+ return (T) this;
+ }
+
+ /**
+ * Convenience method to add an object to a manager. Its life-cycle will be
+ * handled for you. Relax and enjoy the animation.
+ *
+ * @return The current object, for chaining instructions.
+ */
+ public T start(TweenManager manager) {
+ manager.add(this);
+ return (T) this;
+ }
+
+ /**
+ * Adds a delay to the tween or timeline.
+ *
+ * @param delay A duration.
+ * @return The current object, for chaining instructions.
+ */
+ public T delay(float delay) {
+ this.delay += delay;
+ return (T) this;
+ }
+
+ /**
+ * Kills the tween or timeline. If you are using a TweenManager, this object
+ * will be removed automatically.
+ */
+ public void kill() {
+ isKilled = true;
+ }
+
+ /**
+ * Stops and resets the tween or timeline, and sends it to its pool, for
++ * later reuse. Note that if you use a {@link TweenManager}, this method
++ * is automatically called once the animation is finished.
+ */
+ public void free() {
+ }
+
+ /**
+ * Pauses the tween or timeline. Further update calls won't have any effect.
+ */
+ public void pause() {
+ isPaused = true;
+ }
+
+ /**
+ * Resumes the tween or timeline. Has no effect is it was no already paused.
+ */
+ public void resume() {
+ isPaused = false;
+ }
+
+ /**
+ * Repeats the tween or timeline for a given number of times.
+ * @param count The number of repetitions. For infinite repetition,
+ * use Tween.INFINITY, or a negative number.
+ *
+ * @param delay A delay between each iteration.
+ * @return The current tween or timeline, for chaining instructions.
+ */
+ public T repeat(int count, float delay) {
+ if (isStarted) throw new RuntimeException("You can't change the repetitions of a tween or timeline once it is started");
+ repeatCnt = count;
+ repeatDelay = delay >= 0 ? delay : 0;
+ isYoyo = false;
+ return (T) this;
+ }
+
+ /**
+ * Repeats the tween or timeline for a given number of times.
+ * Every two iterations, it will be played backwards.
+ *
+ * @param count The number of repetitions. For infinite repetition,
+ * use Tween.INFINITY, or '-1'.
+ * @param delay A delay before each repetition.
+ * @return The current tween or timeline, for chaining instructions.
+ */
+ public T repeatYoyo(int count, float delay) {
+ if (isStarted) throw new RuntimeException("You can't change the repetitions of a tween or timeline once it is started");
+ repeatCnt = count;
+ repeatDelay = delay >= 0 ? delay : 0;
+ isYoyo = true;
+ return (T) this;
+ }
+
+ /**
+ * Sets the callback. By default, it will be fired at the completion of the
+ * tween or timeline (event COMPLETE). If you want to change this behavior
+ * and add more triggers, use the {@link setCallbackTriggers()} method.
+ *
+ * @see TweenCallback
+ */
+ public T setCallback(TweenCallback callback) {
+ this.callback = callback;
+ return (T) this;
+ }
+
+ /**
+ * Changes the triggers of the callback. The available triggers, listed as
+ * members of the {@link TweenCallback} interface, are:
+ * <p/>
+ *
+ * <b>BEGIN</b>: right after the delay (if any)<br/>
+ * <b>START</b>: at each iteration beginning<br/>
+ * <b>END</b>: at each iteration ending, before the repeat delay<br/>
+ * <b>COMPLETE</b>: at last END event<br/>
+ * <b>BACK_BEGIN</b>: at the beginning of the first backward iteration<br/>
+ * <b>BACK_START</b>: at each backward iteration beginning, after the repeat delay<br/>
+ * <b>BACK_END</b>: at each backward iteration ending<br/>
+ * <b>BACK_COMPLETE</b>: at last BACK_END event
+ * <p/>
+ *
+ * <pre> {@code
+ * forward : BEGIN COMPLETE
+ * forward : START END START END START END
+ * |--------------[XXXXXXXXXX]------[XXXXXXXXXX]------[XXXXXXXXXX]
+ * backward: bEND bSTART bEND bSTART bEND bSTART
+ * backward: bCOMPLETE bBEGIN
+ * }</pre>
+ *
+ * @param flags one or more triggers, separated by the '|' operator.
+ * @see TweenCallback
+ */
+ public T setCallbackTriggers(int flags) {
+ this.callbackTriggers = flags;
+ return (T) this;
+ }
+
+ /**
+ * Attaches an object to this tween or timeline. It can be useful in order
+ * to retrieve some data from a TweenCallback.
+ *
+ * @param data Any kind of object.
+ * @return The current tween or timeline, for chaining instructions.
+ */
+ public T setUserData(Object data) {
+ userData = data;
+ return (T) this;
+ }
+
+ // -------------------------------------------------------------------------
+ // Getters
+ // -------------------------------------------------------------------------
+
+ /**
+ * Gets the delay of the tween or timeline. Nothing will happen before
+ * this delay.
+ */
+ public float getDelay() {
+ return delay;
+ }
+
+ /**
+ * Gets the duration of a single iteration.
+ */
+ public float getDuration() {
+ return duration;
+ }
+
+ /**
+ * Gets the number of iterations that will be played.
+ */
+ public int getRepeatCount() {
+ return repeatCnt;
+ }
+
+ /**
+ * Gets the delay occuring between two iterations.
+ */
+ public float getRepeatDelay() {
+ return repeatDelay;
+ }
+
+ /**
+ * Returns the complete duration, including initial delay and repetitions.
+ * The formula is as follows:
+ * <pre>
+ * fullDuration = delay + duration + (repeatDelay + duration) * repeatCnt
+ * </pre>
+ */
+ public float getFullDuration() {
+ if (repeatCnt < 0) return -1;
+ return delay + duration + (repeatDelay + duration) * repeatCnt;
+ }
+
+ /**
+ * Gets the attached data, or null if none.
+ */
+ public Object getUserData() {
+ return userData;
+ }
+
+ /**
+ * Gets the id of the current step. Values are as follows:<br/>
+ * <ul>
+ * <li>even numbers mean that an iteration is playing,<br/>
+ * <li>odd numbers mean that we are between two iterations,<br/>
+ * <li>-2 means that the initial delay has not ended,<br/>
+ * <li>-1 means that we are before the first iteration,<br/>
+ * <li>repeatCount*2 + 1 means that we are after the last iteration
+ */
+ public int getStep() {
+ return step;
+ }
+
+ /**
+ * Gets the local time.
+ */
+ public float getCurrentTime() {
+ return currentTime;
+ }
+
+ /**
+ * Returns true if the tween or timeline has been started.
+ */
+ public boolean isStarted() {
+ return isStarted;
+ }
+
+ /**
+ * Returns true if the tween or timeline has been initialized. Starting
+ * values for tweens are stored at initialization time. This initialization
+ * takes place right after the initial delay, if any.
+ */
+ public boolean isInitialized() {
+ return isInitialized;
+ }
+
+ /**
+ * Returns true if the tween is finished (i.e. if the tween has reached
+ * its end or has been killed). If you don't use a TweenManager, you may
+ * want to call {@link free()} to reuse the object later.
+ */
+ public boolean isFinished() {
+ return isFinished || isKilled;
+ }
+
+ /**
+ * Returns true if the iterations are played as yoyo. Yoyo means that
+ * every two iterations, the animation will be played backwards.
+ */
+ public boolean isYoyo() {
+ return isYoyo;
+ }
+
+ /**
+ * Returns true if the tween or timeline is currently paused.
+ */
+ public boolean isPaused() {
+ return isPaused;
+ }
+
+ // -------------------------------------------------------------------------
+ // Abstract API
+ // -------------------------------------------------------------------------
+
+ protected abstract void forceStartValues();
+ protected abstract void forceEndValues();
+
+ protected abstract boolean containsTarget(Object target);
+ protected abstract boolean containsTarget(Object target, int tweenType);
+
+ // -------------------------------------------------------------------------
+ // Protected API
+ // -------------------------------------------------------------------------
+
+ protected void initializeOverride() {
+ }
+
+ protected void updateOverride(int step, int lastStep, boolean isIterationStep, float delta) {
+ }
+
+ protected void forceToStart() {
+ currentTime = -delay;
+ step = -1;
+ isIterationStep = false;
+ if (isReverse(0)) forceEndValues();
+ else forceStartValues();
+ }
+
+ protected void forceToEnd(float time) {
+ currentTime = time - getFullDuration();
+ step = repeatCnt*2 + 1;
+ isIterationStep = false;
+ if (isReverse(repeatCnt*2)) forceStartValues();
+ else forceEndValues();
+ }
+
+ protected void callCallback(int type) {
+ if (callback != null && (callbackTriggers & type) > 0) callback.onEvent(type, this);
+ }
+
+ protected boolean isReverse(int step) {
+ return isYoyo && Math.abs(step%4) == 2;
+ }
+
+ protected boolean isValid(int step) {
+ return (step >= 0 && step <= repeatCnt*2) || repeatCnt < 0;
+ }
+
+ protected void killTarget(Object target) {
+ if (containsTarget(target)) kill();
+ }
+
+ protected void killTarget(Object target, int tweenType) {
+ if (containsTarget(target, tweenType)) kill();
+ }
+
+ // -------------------------------------------------------------------------
+ // Update engine
+ // -------------------------------------------------------------------------
+
+ /**
+ * Updates the tween or timeline state. <b>You may want to use a
+ * TweenManager to update objects for you.</b>
+ *
+ * Slow motion, fast motion and backward play can be easily achieved by
+ * tweaking this delta time. Multiply it by -1 to play the animation
+ * backward, or by 0.5 to play it twice slower than its normal speed.
+ *
+ * @param delta A delta time between now and the last call.
+ */
+ public void update(float delta) {
+ if (!isStarted || isPaused || isKilled) return;
+
+ deltaTime = delta;
+
+ if (!isInitialized) {
+ initialize();
+ }
+
+ if (isInitialized) {
+ testRelaunch();
+ updateStep();
+ testCompletion();
+ }
+
+ currentTime += deltaTime;
+ deltaTime = 0;
+ }
+
+ private void initialize() {
+ if (currentTime+deltaTime >= delay) {
+ initializeOverride();
+ isInitialized = true;
+ isIterationStep = true;
+ step = 0;
+ deltaTime -= delay-currentTime;
+ currentTime = 0;
+ callCallback(TweenCallback.BEGIN);
+ callCallback(TweenCallback.START);
+ }
+ }
+
+ private void testRelaunch() {
+ if (!isIterationStep && repeatCnt >= 0 && step < 0 && currentTime+deltaTime >= 0) {
+ assert step == -1;
+ isIterationStep = true;
+ step = 0;
+ float delta = 0-currentTime;
+ deltaTime -= delta;
+ currentTime = 0;
+ callCallback(TweenCallback.BEGIN);
+ callCallback(TweenCallback.START);
+ updateOverride(step, step-1, isIterationStep, delta);
+
+ } else if (!isIterationStep && repeatCnt >= 0 && step > repeatCnt*2 && currentTime+deltaTime < 0) {
+ assert step == repeatCnt*2 + 1;
+ isIterationStep = true;
+ step = repeatCnt*2;
+ float delta = 0-currentTime;
+ deltaTime -= delta;
+ currentTime = duration;
+ callCallback(TweenCallback.BACK_BEGIN);
+ callCallback(TweenCallback.BACK_START);
+ updateOverride(step, step+1, isIterationStep, delta);
+ }
+ }
+
+ private void updateStep() {
+ while (isValid(step)) {
+ if (!isIterationStep && currentTime+deltaTime <= 0) {
+ isIterationStep = true;
+ step -= 1;
+
+ float delta = 0-currentTime;
+ deltaTime -= delta;
+ currentTime = duration;
+
+ if (isReverse(step)) forceStartValues(); else forceEndValues();
+ callCallback(TweenCallback.BACK_START);
+ updateOverride(step, step+1, isIterationStep, delta);
+
+ } else if (!isIterationStep && currentTime+deltaTime >= repeatDelay) {
+ isIterationStep = true;
+ step += 1;
+
+ float delta = repeatDelay-currentTime;
+ deltaTime -= delta;
+ currentTime = 0;
+
+ if (isReverse(step)) forceEndValues(); else forceStartValues();
+ callCallback(TweenCallback.START);
+ updateOverride(step, step-1, isIterationStep, delta);
+
+ } else if (isIterationStep && currentTime+deltaTime < 0) {
+ isIterationStep = false;
+ step -= 1;
+
+ float delta = 0-currentTime;
+ deltaTime -= delta;
+ currentTime = 0;
+
+ updateOverride(step, step+1, isIterationStep, delta);
+ callCallback(TweenCallback.BACK_END);
+
+ if (step < 0 && repeatCnt >= 0) callCallback(TweenCallback.BACK_COMPLETE);
+ else currentTime = repeatDelay;
+
+ } else if (isIterationStep && currentTime+deltaTime > duration) {
+ isIterationStep = false;
+ step += 1;
+
+ float delta = duration-currentTime;
+ deltaTime -= delta;
+ currentTime = duration;
+
+ updateOverride(step, step-1, isIterationStep, delta);
+ callCallback(TweenCallback.END);
+
+ if (step > repeatCnt*2 && repeatCnt >= 0) callCallback(TweenCallback.COMPLETE);
+ currentTime = 0;
+
+ } else if (isIterationStep) {
+ float delta = deltaTime;
+ deltaTime -= delta;
+ currentTime += delta;
+ updateOverride(step, step, isIterationStep, delta);
+ break;
+
+ } else {
+ float delta = deltaTime;
+ deltaTime -= delta;
+ currentTime += delta;
+ break;
+ }
+ }
+ }
+
+ private void testCompletion() {
+ isFinished = repeatCnt >= 0 && (step > repeatCnt*2 || step < 0);
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/Pool.java b/java/api/src/aurelienribon/tweenengine/Pool.java
new file mode 100755
index 0000000..0b7b2fc
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/Pool.java
@@ -0,0 +1,55 @@
+package aurelienribon.tweenengine;
+
+import java.util.ArrayList;
+
+/**
+ * A light pool of objects that can be resused to avoid allocation.
+ * Based on Nathan Sweet pool implementation
+ */
+abstract class Pool<T> {
+ private final ArrayList<T> objects;
+ private final Callback<T> callback;
+
+ protected abstract T create();
+
+ public Pool(int initCapacity, Callback<T> callback) {
+ this.objects = new ArrayList<T>(initCapacity);
+ this.callback = callback;
+ }
+
+ public T get() {
+ T obj = null;
+ try {
+ obj = objects.isEmpty() ? create() : objects.remove(0);
+ } catch (Exception e) {}
+ if (obj == null) obj = create();
+ if (callback != null) callback.onUnPool(obj);
+ return obj;
+ }
+
+ public void free(T obj) {
+ if (obj == null) return;
+
+ if (!objects.contains(obj)) {
+ if (callback != null) callback.onPool(obj);
+ objects.add(obj);
+ }
+ }
+
+ public void clear() {
+ objects.clear();
+ }
+
+ public int size() {
+ return objects.size();
+ }
+
+ public void ensureCapacity(int minCapacity) {
+ objects.ensureCapacity(minCapacity);
+ }
+
+ public interface Callback<T> {
+ public void onPool(T obj);
+ public void onUnPool(T obj);
+ }
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/Timeline.java b/java/api/src/aurelienribon/tweenengine/Timeline.java
new file mode 100755
index 0000000..5e1f765
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/Timeline.java
@@ -0,0 +1,363 @@
+package aurelienribon.tweenengine;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A Timeline can be used to create complex animations made of sequences and
+ * parallel sets of Tweens.
+ * <p/>
+ *
+ * The following example will create an animation sequence composed of 5 parts:
+ * <p/>
+ *
+ * 1. First, opacity and scale are set to 0 (with Tween.set() calls).<br/>
+ * 2. Then, opacity and scale are animated in parallel.<br/>
+ * 3. Then, the animation is paused for 1s.<br/>
+ * 4. Then, position is animated to x=100.<br/>
+ * 5. Then, rotation is animated to 360°.
+ * <p/>
+ *
+ * This animation will be repeated 5 times, with a 500ms delay between each
+ * iteration:
+ * <br/><br/>
+ *
+ * <pre> {@code
+ * Timeline.createSequence()
+ * .push(Tween.set(myObject, OPACITY).target(0))
+ * .push(Tween.set(myObject, SCALE).target(0, 0))
+ * .beginParallel()
+ * .push(Tween.to(myObject, OPACITY, 0.5f).target(1).ease(Quad.INOUT))
+ * .push(Tween.to(myObject, SCALE, 0.5f).target(1, 1).ease(Quad.INOUT))
+ * .end()
+ * .pushPause(1.0f)
+ * .push(Tween.to(myObject, POSITION_X, 0.5f).target(100).ease(Quad.INOUT))
+ * .push(Tween.to(myObject, ROTATION, 0.5f).target(360).ease(Quad.INOUT))
+ * .repeat(5, 0.5f)
+ * .start(myManager);
+ * }</pre>
+ *
+ * @see Tween
+ * @see TweenManager
+ * @see TweenCallback
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public final class Timeline extends BaseTween<Timeline> {
+ // -------------------------------------------------------------------------
+ // Static -- pool
+ // -------------------------------------------------------------------------
+
+ private static final Pool.Callback<Timeline> poolCallback = new Pool.Callback<Timeline>() {
+ @Override public void onPool(Timeline obj) {obj.reset();}
+ @Override public void onUnPool(Timeline obj) {obj.reset();}
+ };
+
+ static final Pool<Timeline> pool = new Pool<Timeline>(10, poolCallback) {
+ @Override protected Timeline create() {return new Timeline();}
+ };
+
+ /**
+ * Used for debug purpose. Gets the current number of empty timelines that
+ * are waiting in the Timeline pool.
+ */
+ public static int getPoolSize() {
+ return pool.size();
+ }
+
+ /**
+ * Increases the minimum capacity of the pool. Capacity defaults to 10.
+ */
+ public static void ensurePoolCapacity(int minCapacity) {
+ pool.ensureCapacity(minCapacity);
+ }
+
+ // -------------------------------------------------------------------------
+ // Static -- factories
+ // -------------------------------------------------------------------------
+
+ /**
+ * Creates a new timeline with a 'sequence' behavior. Its children will
+ * be delayed so that they are triggered one after the other.
+ */
+ public static Timeline createSequence() {
+ Timeline tl = pool.get();
+ tl.setup(Modes.SEQUENCE);
+ return tl;
+ }
+
+ /**
+ * Creates a new timeline with a 'parallel' behavior. Its children will be
+ * triggered all at once.
+ */
+ public static Timeline createParallel() {
+ Timeline tl = pool.get();
+ tl.setup(Modes.PARALLEL);
+ return tl;
+ }
+
+ // -------------------------------------------------------------------------
+ // Attributes
+ // -------------------------------------------------------------------------
+
+ private enum Modes {SEQUENCE, PARALLEL}
+
+ private final List<BaseTween<?>> children = new ArrayList<BaseTween<?>>(10);
+ private Timeline current;
+ private Timeline parent;
+ private Modes mode;
+ private boolean isBuilt;
+
+ // -------------------------------------------------------------------------
+ // Setup
+ // -------------------------------------------------------------------------
+
+ private Timeline() {
+ reset();
+ }
+
+ @Override
+ protected void reset() {
+ super.reset();
+
+ children.clear();
+ current = parent = null;
+
+ isBuilt = false;
+ }
+
+ private void setup(Modes mode) {
+ this.mode = mode;
+ this.current = this;
+ }
+
+ // -------------------------------------------------------------------------
+ // Public API
+ // -------------------------------------------------------------------------
+
+ /**
+ * Adds a Tween to the current timeline.
+ *
+ * @return The current timeline, for chaining instructions.
+ */
+ public Timeline push(Tween tween) {
+ if (isBuilt) throw new RuntimeException("You can't push anything to a timeline once it is started");
+ current.children.add(tween);
+ return this;
+ }
+
+ /**
+ * Nests a Timeline in the current one.
+ *
+ * @return The current timeline, for chaining instructions.
+ */
+ public Timeline push(Timeline timeline) {
+ if (isBuilt) throw new RuntimeException("You can't push anything to a timeline once it is started");
+ if (timeline.current != timeline) throw new RuntimeException("You forgot to call a few 'end()' statements in your pushed timeline");
+ timeline.parent = current;
+ current.children.add(timeline);
+ return this;
+ }
+
+ /**
+ * Adds a pause to the timeline. The pause may be negative if you want to
+ * overlap the preceding and following children.
+ *
+ * @param time A positive or negative duration.
+ * @return The current timeline, for chaining instructions.
+ */
+ public Timeline pushPause(float time) {
+ if (isBuilt) throw new RuntimeException("You can't push anything to a timeline once it is started");
+ current.children.add(Tween.mark().delay(time));
+ return this;
+ }
+
+ /**
+ * Starts a nested timeline with a 'sequence' behavior. Don't forget to
+ * call {@link end()} to close this nested timeline.
+ *
+ * @return The current timeline, for chaining instructions.
+ */
+ public Timeline beginSequence() {
+ if (isBuilt) throw new RuntimeException("You can't push anything to a timeline once it is started");
+ Timeline tl = pool.get();
+ tl.parent = current;
+ tl.mode = Modes.SEQUENCE;
+ current.children.add(tl);
+ current = tl;
+ return this;
+ }
+
+ /**
+ * Starts a nested timeline with a 'parallel' behavior. Don't forget to
+ * call {@link end()} to close this nested timeline.
+ *
+ * @return The current timeline, for chaining instructions.
+ */
+ public Timeline beginParallel() {
+ if (isBuilt) throw new RuntimeException("You can't push anything to a timeline once it is started");
+ Timeline tl = pool.get();
+ tl.parent = current;
+ tl.mode = Modes.PARALLEL;
+ current.children.add(tl);
+ current = tl;
+ return this;
+ }
+
+ /**
+ * Closes the last nested timeline.
+ *
+ * @return The current timeline, for chaining instructions.
+ */
+ public Timeline end() {
+ if (isBuilt) throw new RuntimeException("You can't push anything to a timeline once it is started");
+ if (current == this) throw new RuntimeException("Nothing to end...");
+ current = current.parent;
+ return this;
+ }
+
+ /**
+ * Gets a list of the timeline children. If the timeline is started, the
+ * list will be immutable.
+ */
+ public List<BaseTween<?>> getChildren() {
+ if (isBuilt) return Collections.unmodifiableList(current.children);
+ else return current.children;
+ }
+
+ // -------------------------------------------------------------------------
+ // Overrides
+ // -------------------------------------------------------------------------
+
+ @Override
+ public Timeline build() {
+ if (isBuilt) return this;
+
+ duration = 0;
+
+ for (int i=0; i<children.size(); i++) {
+ BaseTween<?> obj = children.get(i);
+
+ if (obj.getRepeatCount() < 0) throw new RuntimeException("You can't push an object with infinite repetitions in a timeline");
+ obj.build();
+
+ switch (mode) {
+ case SEQUENCE:
+ float tDelay = duration;
+ duration += obj.getFullDuration();
+ obj.delay += tDelay;
+ break;
+
+ case PARALLEL:
+ duration = Math.max(duration, obj.getFullDuration());
+ break;
+ }
+ }
+
+ isBuilt = true;
+ return this;
+ }
+
+ @Override
+ public Timeline start() {
+ super.start();
+
+ for (int i=0; i<children.size(); i++) {
+ BaseTween<?> obj = children.get(i);
+ obj.start();
+ }
+
+ return this;
+ }
+
+ @Override
+ public void free() {
+ for (int i=children.size()-1; i>=0; i--) {
+ BaseTween<?> obj = children.remove(i);
+ obj.free();
+ }
+
+ pool.free(this);
+ }
+
+ @Override
+ protected void updateOverride(int step, int lastStep, boolean isIterationStep, float delta) {
+ if (!isIterationStep && step > lastStep) {
+ assert delta >= 0;
+ float dt = isReverse(lastStep) ? -delta-1 : delta+1;
+ for (int i=0, n=children.size(); i<n; i++) children.get(i).update(dt);
+ return;
+ }
+
+ if (!isIterationStep && step < lastStep) {
+ assert delta <= 0;
+ float dt = isReverse(lastStep) ? -delta-1 : delta+1;
+ for (int i=children.size()-1; i>=0; i--) children.get(i).update(dt);
+ return;
+ }
+
+ assert isIterationStep;
+
+ if (step > lastStep) {
+ if (isReverse(step)) {
+ forceEndValues();
+ for (int i=0, n=children.size(); i<n; i++) children.get(i).update(delta);
+ } else {
+ forceStartValues();
+ for (int i=0, n=children.size(); i<n; i++) children.get(i).update(delta);
+ }
+
+ } else if (step < lastStep) {
+ if (isReverse(step)) {
+ forceStartValues();
+ for (int i=children.size()-1; i>=0; i--) children.get(i).update(delta);
+ } else {
+ forceEndValues();
+ for (int i=children.size()-1; i>=0; i--) children.get(i).update(delta);
+ }
+
+ } else {
+ float dt = isReverse(step) ? -delta : delta;
+ if (delta >= 0) for (int i=0, n=children.size(); i<n; i++) children.get(i).update(dt);
+ else for (int i=children.size()-1; i>=0; i--) children.get(i).update(dt);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // BaseTween impl.
+ // -------------------------------------------------------------------------
+
+ @Override
+ protected void forceStartValues() {
+ for (int i=children.size()-1; i>=0; i--) {
+ BaseTween<?> obj = children.get(i);
+ obj.forceToStart();
+ }
+ }
+
+ @Override
+ protected void forceEndValues() {
+ for (int i=0, n=children.size(); i<n; i++) {
+ BaseTween<?> obj = children.get(i);
+ obj.forceToEnd(duration);
+ }
+ }
+
+ @Override
+ protected boolean containsTarget(Object target) {
+ for (int i=0, n=children.size(); i<n; i++) {
+ BaseTween<?> obj = children.get(i);
+ if (obj.containsTarget(target)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean containsTarget(Object target, int tweenType) {
+ for (int i=0, n=children.size(); i<n; i++) {
+ BaseTween<?> obj = children.get(i);
+ if (obj.containsTarget(target, tweenType)) return true;
+ }
+ return false;
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/Tween.java b/java/api/src/aurelienribon/tweenengine/Tween.java
new file mode 100755
index 0000000..911182e
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/Tween.java
@@ -0,0 +1,923 @@
+package aurelienribon.tweenengine;
+
+import aurelienribon.tweenengine.equations.Quad;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Core class of the Tween Engine. A Tween is basically an interpolation
+ * between two values of an object attribute. However, the main interest of a
+ * Tween is that you can apply an easing formula on this interpolation, in
+ * order to smooth the transitions or to achieve cool effects like springs or
+ * bounces.
+ * <p/>
+ *
+ * The Universal Tween Engine is called "universal" because it is able to apply
+ * interpolations on every attribute from every possible object. Therefore,
+ * every object in your application can be animated with cool effects: it does
+ * not matter if your application is a game, a desktop interface or even a
+ * console program! If it makes sense to animate something, then it can be
+ * animated through this engine.
+ * <p/>
+ *
+ * This class contains many static factory methods to create and instantiate
+ * new interpolations easily. The common way to create a Tween is by using one
+ * of these factories:
+ * <p/>
+ *
+ * - Tween.to(...)<br/>
+ * - Tween.from(...)<br/>
+ * - Tween.set(...)<br/>
+ * - Tween.call(...)
+ * <p/>
+ *
+ * <h2>Example - firing a Tween</h2>
+ *
+ * The following example will move the target horizontal position from its
+ * current value to x=200 and y=300, during 500ms, but only after a delay of
+ * 1000ms. The animation will also be repeated 2 times (the starting position
+ * is registered at the end of the delay, so the animation will automatically
+ * restart from this registered position).
+ * <p/>
+ *
+ * <pre> {@code
+ * Tween.to(myObject, POSITION_XY, 0.5f)
+ * .target(200, 300)
+ * .ease(Quad.INOUT)
+ * .delay(1.0f)
+ * .repeat(2, 0.2f)
+ * .start(myManager);
+ * }</pre>
+ *
+ * Tween life-cycles can be automatically managed for you, thanks to the
+ * {@link TweenManager} class. If you choose to manage your tween when you start
+ * it, then you don't need to care about it anymore. <b>Tweens are
+ * <i>fire-and-forget</i>: don't think about them anymore once you started
+ * them (if they are managed of course).</b>
+ * <p/>
+ *
+ * You need to periodicaly update the tween engine, in order to compute the new
+ * values. If your tweens are managed, only update the manager; else you need
+ * to call {@link #update()} on your tweens periodically.
+ * <p/>
+ *
+ * <h2>Example - setting up the engine</h2>
+ *
+ * The engine cannot directly change your objects attributes, since it doesn't
+ * know them. Therefore, you need to tell him how to get and set the different
+ * attributes of your objects: <b>you need to implement the {@link
+ * TweenAccessor} interface for each object class you will animate</b>. Once
+ * done, don't forget to register these implementations, using the static method
+ * {@link registerAccessor()}, when you start your application.
+ *
+ * @see TweenAccessor
+ * @see TweenManager
+ * @see TweenEquation
+ * @see Timeline
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public final class Tween extends BaseTween<Tween> {
+ // -------------------------------------------------------------------------
+ // Static -- misc
+ // -------------------------------------------------------------------------
+
+ /**
+ * Used as parameter in {@link #repeat(int, float)} and
+ * {@link #repeatYoyo(int, float)} methods.
+ */
+ public static final int INFINITY = -1;
+
+ private static int combinedAttrsLimit = 3;
+ private static int waypointsLimit = 0;
+
+ /**
+ * Changes the limit for combined attributes. Defaults to 3 to reduce
+ * memory footprint.
+ */
+ public static void setCombinedAttributesLimit(int limit) {
+ Tween.combinedAttrsLimit = limit;
+ }
+
+ /**
+ * Changes the limit of allowed waypoints for each tween. Defaults to 0 to
+ * reduce memory footprint.
+ */
+ public static void setWaypointsLimit(int limit) {
+ Tween.waypointsLimit = limit;
+ }
+
+ /**
+ * Gets the version number of the library.
+ */
+ public static String getVersion() {
+ return "6.3.3";
+ }
+
+ // -------------------------------------------------------------------------
+ // Static -- pool
+ // -------------------------------------------------------------------------
+
+ private static final Pool.Callback<Tween> poolCallback = new Pool.Callback<Tween>() {
+ @Override public void onPool(Tween obj) {obj.reset();}
+ @Override public void onUnPool(Tween obj) {obj.reset();}
+ };
+
+ private static final Pool<Tween> pool = new Pool<Tween>(20, poolCallback) {
+ @Override protected Tween create() {return new Tween();}
+ };
+
+ /**
+ * Used for debug purpose. Gets the current number of objects that are
+ * waiting in the Tween pool.
+ */
+ public static int getPoolSize() {
+ return pool.size();
+ }
+
+ /**
+ * Increases the minimum capacity of the pool. Capacity defaults to 20.
+ */
+ public static void ensurePoolCapacity(int minCapacity) {
+ pool.ensureCapacity(minCapacity);
+ }
+
+ // -------------------------------------------------------------------------
+ // Static -- tween accessors
+ // -------------------------------------------------------------------------
+
+ private static final Map<Class<?>, TweenAccessor<?>> registeredAccessors = new HashMap<Class<?>, TweenAccessor<?>>();
+
+ /**
+ * Registers an accessor with the class of an object. This accessor will be
+ * used by tweens applied to every objects implementing the registered
+ * class, or inheriting from it.
+ *
+ * @param someClass An object class.
+ * @param defaultAccessor The accessor that will be used to tween any
+ * object of class "someClass".
+ */
+ public static void registerAccessor(Class<?> someClass, TweenAccessor<?> defaultAccessor) {
+ registeredAccessors.put(someClass, defaultAccessor);
+ }
+
+ /**
+ * Gets the registered TweenAccessor associated with the given object class.
+ *
+ * @param someClass An object class.
+ */
+ public static TweenAccessor<?> getRegisteredAccessor(Class<?> someClass) {
+ return registeredAccessors.get(someClass);
+ }
+
+ // -------------------------------------------------------------------------
+ // Static -- factories
+ // -------------------------------------------------------------------------
+
+ /**
+ * Factory creating a new standard interpolation. This is the most common
+ * type of interpolation. The starting values are retrieved automatically
+ * after the delay (if any).
+ * <br/><br/>
+ *
+ * <b>You need to set the target values of the interpolation by using one
+ * of the target() methods</b>. The interpolation will run from the
+ * starting values to these target values.
+ * <br/><br/>
+ *
+ * The common use of Tweens is "fire-and-forget": you do not need to care
+ * for tweens once you added them to a TweenManager, they will be updated
+ * automatically, and cleaned once finished. Common call:
+ * <br/><br/>
+ *
+ * <pre> {@code
+ * Tween.to(myObject, POSITION, 1.0f)
+ * .target(50, 70)
+ * .ease(Quad.INOUT)
+ * .start(myManager);
+ * }</pre>
+ *
+ * Several options such as delay, repetitions and callbacks can be added to
+ * the tween.
+ *
+ * @param target The target object of the interpolation.
+ * @param tweenType The desired type of interpolation.
+ * @param duration The duration of the interpolation, in milliseconds.
+ * @return The generated Tween.
+ */
+ public static Tween to(Object target, int tweenType, float duration) {
+ Tween tween = pool.get();
+ tween.setup(target, tweenType, duration);
+ tween.ease(Quad.INOUT);
+ tween.path(TweenPaths.catmullRom);
+ return tween;
+ }
+
+ /**
+ * Factory creating a new reversed interpolation. The ending values are
+ * retrieved automatically after the delay (if any).
+ * <br/><br/>
+ *
+ * <b>You need to set the starting values of the interpolation by using one
+ * of the target() methods</b>. The interpolation will run from the
+ * starting values to these target values.
+ * <br/><br/>
+ *
+ * The common use of Tweens is "fire-and-forget": you do not need to care
+ * for tweens once you added them to a TweenManager, they will be updated
+ * automatically, and cleaned once finished. Common call:
+ * <br/><br/>
+ *
+ * <pre> {@code
+ * Tween.from(myObject, POSITION, 1.0f)
+ * .target(0, 0)
+ * .ease(Quad.INOUT)
+ * .start(myManager);
+ * }</pre>
+ *
+ * Several options such as delay, repetitions and callbacks can be added to
+ * the tween.
+ *
+ * @param target The target object of the interpolation.
+ * @param tweenType The desired type of interpolation.
+ * @param duration The duration of the interpolation, in milliseconds.
+ * @return The generated Tween.
+ */
+ public static Tween from(Object target, int tweenType, float duration) {
+ Tween tween = pool.get();
+ tween.setup(target, tweenType, duration);
+ tween.ease(Quad.INOUT);
+ tween.path(TweenPaths.catmullRom);
+ tween.isFrom = true;
+ return tween;
+ }
+
+ /**
+ * Factory creating a new instantaneous interpolation (thus this is not
+ * really an interpolation).
+ * <br/><br/>
+ *
+ * <b>You need to set the target values of the interpolation by using one
+ * of the target() methods</b>. The interpolation will set the target
+ * attribute to these values after the delay (if any).
+ * <br/><br/>
+ *
+ * The common use of Tweens is "fire-and-forget": you do not need to care
+ * for tweens once you added them to a TweenManager, they will be updated
+ * automatically, and cleaned once finished. Common call:
+ * <br/><br/>
+ *
+ * <pre> {@code
+ * Tween.set(myObject, POSITION)
+ * .target(50, 70)
+ * .delay(1.0f)
+ * .start(myManager);
+ * }</pre>
+ *
+ * Several options such as delay, repetitions and callbacks can be added to
+ * the tween.
+ *
+ * @param target The target object of the interpolation.
+ * @param tweenType The desired type of interpolation.
+ * @return The generated Tween.
+ */
+ public static Tween set(Object target, int tweenType) {
+ Tween tween = pool.get();
+ tween.setup(target, tweenType, 0);
+ tween.ease(Quad.INOUT);
+ return tween;
+ }
+
+ /**
+ * Factory creating a new timer. The given callback will be triggered on
+ * each iteration start, after the delay.
+ * <br/><br/>
+ *
+ * The common use of Tweens is "fire-and-forget": you do not need to care
+ * for tweens once you added them to a TweenManager, they will be updated
+ * automatically, and cleaned once finished. Common call:
+ * <br/><br/>
+ *
+ * <pre> {@code
+ * Tween.call(myCallback)
+ * .delay(1.0f)
+ * .repeat(10, 1000)
+ * .start(myManager);
+ * }</pre>
+ *
+ * @param callback The callback that will be triggered on each iteration
+ * start.
+ * @return The generated Tween.
+ * @see TweenCallback
+ */
+ public static Tween call(TweenCallback callback) {
+ Tween tween = pool.get();
+ tween.setup(null, -1, 0);
+ tween.setCallback(callback);
+ tween.setCallbackTriggers(TweenCallback.START);
+ return tween;
+ }
+
+ /**
+ * Convenience method to create an empty tween. Such object is only useful
+ * when placed inside animation sequences (see {@link Timeline}), in which
+ * it may act as a beacon, so you can set a callback on it in order to
+ * trigger some action at the right moment.
+ *
+ * @return The generated Tween.
+ * @see Timeline
+ */
+ public static Tween mark() {
+ Tween tween = pool.get();
+ tween.setup(null, -1, 0);
+ return tween;
+ }
+
+ // -------------------------------------------------------------------------
+ // Attributes
+ // -------------------------------------------------------------------------
+
+ // Main
+ private Object target;
+ private Class<?> targetClass;
+ private TweenAccessor<Object> accessor;
+ private int type;
+ private TweenEquation equation;
+ private TweenPath path;
+
+ // General
+ private boolean isFrom;
+ private boolean isRelative;
+ private int combinedAttrsCnt;
+ private int waypointsCnt;
+
+ // Values
+ private final float[] startValues = new float[combinedAttrsLimit];
+ private final float[] targetValues = new float[combinedAttrsLimit];
+ private final float[] waypoints = new float[waypointsLimit * combinedAttrsLimit];
+
+ // Buffers
+ private float[] accessorBuffer = new float[combinedAttrsLimit];
+ private float[] pathBuffer = new float[(2+waypointsLimit)*combinedAttrsLimit];
+
+ // -------------------------------------------------------------------------
+ // Setup
+ // -------------------------------------------------------------------------
+
+ private Tween() {
+ reset();
+ }
+
+ @Override
+ protected void reset() {
+ super.reset();
+
+ target = null;
+ targetClass = null;
+ accessor = null;
+ type = -1;
+ equation = null;
+ path = null;
+
+ isFrom = isRelative = false;
+ combinedAttrsCnt = waypointsCnt = 0;
+
+ if (accessorBuffer.length != combinedAttrsLimit) {
+ accessorBuffer = new float[combinedAttrsLimit];
+ }
+
+ if (pathBuffer.length != (2+waypointsLimit)*combinedAttrsLimit) {
+ pathBuffer = new float[(2+waypointsLimit)*combinedAttrsLimit];
+ }
+ }
+
+ private void setup(Object target, int tweenType, float duration) {
+ if (duration < 0) throw new RuntimeException("Duration can't be negative");
+
+ this.target = target;
+ this.targetClass = target != null ? findTargetClass() : null;
+ this.type = tweenType;
+ this.duration = duration;
+ }
+
+ private Class<?> findTargetClass() {
+ if (registeredAccessors.containsKey(target.getClass())) return target.getClass();
+ if (target instanceof TweenAccessor) return target.getClass();
+
+ Class<?> parentClass = target.getClass().getSuperclass();
+ while (parentClass != null && !registeredAccessors.containsKey(parentClass))
+ parentClass = parentClass.getSuperclass();
+
+ return parentClass;
+ }
+
+ // -------------------------------------------------------------------------
+ // Public API
+ // -------------------------------------------------------------------------
+
+ /**
+ * Sets the easing equation of the tween. Existing equations are located in
+ * <i>aurelienribon.tweenengine.equations</i> package, but you can of course
+ * implement your owns, see {@link TweenEquation}. You can also use the
+ * {@link TweenEquations} static instances to quickly access all the
+ * equations. Default equation is Quad.INOUT.
+ * <p/>
+ *
+ * <b>Proposed equations are:</b><br/>
+ * - Linear.INOUT,<br/>
+ * - Quad.IN | OUT | INOUT,<br/>
+ * - Cubic.IN | OUT | INOUT,<br/>
+ * - Quart.IN | OUT | INOUT,<br/>
+ * - Quint.IN | OUT | INOUT,<br/>
+ * - Circ.IN | OUT | INOUT,<br/>
+ * - Sine.IN | OUT | INOUT,<br/>
+ * - Expo.IN | OUT | INOUT,<br/>
+ * - Back.IN | OUT | INOUT,<br/>
+ * - Bounce.IN | OUT | INOUT,<br/>
+ * - Elastic.IN | OUT | INOUT
+ *
+ * @return The current tween, for chaining instructions.
+ * @see TweenEquation
+ * @see TweenEquations
+ */
+ public Tween ease(TweenEquation easeEquation) {
+ this.equation = easeEquation;
+ return this;
+ }
+
+ /**
+ * Forces the tween to use the TweenAccessor registered with the given
+ * target class. Useful if you want to use a specific accessor associated
+ * to an interface, for instance.
+ *
+ * @param targetClass A class registered with an accessor.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween cast(Class<?> targetClass) {
+ if (isStarted()) throw new RuntimeException("You can't cast the target of a tween once it is started");
+ this.targetClass = targetClass;
+ return this;
+ }
+
+ /**
+ * Sets the target value of the interpolation. The interpolation will run
+ * from the <b>value at start time (after the delay, if any)</b> to this
+ * target value.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start value: value at start time, after delay<br/>
+ * - end value: param
+ *
+ * @param targetValue The target value of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween target(float targetValue) {
+ targetValues[0] = targetValue;
+ return this;
+ }
+
+ /**
+ * Sets the target values of the interpolation. The interpolation will run
+ * from the <b>values at start time (after the delay, if any)</b> to these
+ * target values.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start values: values at start time, after delay<br/>
+ * - end values: params
+ *
+ * @param targetValue1 The 1st target value of the interpolation.
+ * @param targetValue2 The 2nd target value of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween target(float targetValue1, float targetValue2) {
+ targetValues[0] = targetValue1;
+ targetValues[1] = targetValue2;
+ return this;
+ }
+
+ /**
+ * Sets the target values of the interpolation. The interpolation will run
+ * from the <b>values at start time (after the delay, if any)</b> to these
+ * target values.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start values: values at start time, after delay<br/>
+ * - end values: params
+ *
+ * @param targetValue1 The 1st target value of the interpolation.
+ * @param targetValue2 The 2nd target value of the interpolation.
+ * @param targetValue3 The 3rd target value of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween target(float targetValue1, float targetValue2, float targetValue3) {
+ targetValues[0] = targetValue1;
+ targetValues[1] = targetValue2;
+ targetValues[2] = targetValue3;
+ return this;
+ }
+
+ /**
+ * Sets the target values of the interpolation. The interpolation will run
+ * from the <b>values at start time (after the delay, if any)</b> to these
+ * target values.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start values: values at start time, after delay<br/>
+ * - end values: params
+ *
+ * @param targetValues The target values of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween target(float... targetValues) {
+ if (targetValues.length > combinedAttrsLimit) throwCombinedAttrsLimitReached();
+ System.arraycopy(targetValues, 0, this.targetValues, 0, targetValues.length);
+ return this;
+ }
+
+ /**
+ * Sets the target value of the interpolation, relatively to the <b>value
+ * at start time (after the delay, if any)</b>.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start value: value at start time, after delay<br/>
+ * - end value: param + value at start time, after delay
+ *
+ * @param targetValue The relative target value of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween targetRelative(float targetValue) {
+ isRelative = true;
+ targetValues[0] = isInitialized() ? targetValue + startValues[0] : targetValue;
+ return this;
+ }
+
+ /**
+ * Sets the target values of the interpolation, relatively to the <b>values
+ * at start time (after the delay, if any)</b>.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start values: values at start time, after delay<br/>
+ * - end values: params + values at start time, after delay
+ *
+ * @param targetValue1 The 1st relative target value of the interpolation.
+ * @param targetValue2 The 2nd relative target value of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween targetRelative(float targetValue1, float targetValue2) {
+ isRelative = true;
+ targetValues[0] = isInitialized() ? targetValue1 + startValues[0] : targetValue1;
+ targetValues[1] = isInitialized() ? targetValue2 + startValues[1] : targetValue2;
+ return this;
+ }
+
+ /**
+ * Sets the target values of the interpolation, relatively to the <b>values
+ * at start time (after the delay, if any)</b>.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start values: values at start time, after delay<br/>
+ * - end values: params + values at start time, after delay
+ *
+ * @param targetValue1 The 1st relative target value of the interpolation.
+ * @param targetValue2 The 2nd relative target value of the interpolation.
+ * @param targetValue3 The 3rd relative target value of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween targetRelative(float targetValue1, float targetValue2, float targetValue3) {
+ isRelative = true;
+ targetValues[0] = isInitialized() ? targetValue1 + startValues[0] : targetValue1;
+ targetValues[1] = isInitialized() ? targetValue2 + startValues[1] : targetValue2;
+ targetValues[2] = isInitialized() ? targetValue3 + startValues[2] : targetValue3;
+ return this;
+ }
+
+ /**
+ * Sets the target values of the interpolation, relatively to the <b>values
+ * at start time (after the delay, if any)</b>.
+ * <p/>
+ *
+ * To sum-up:<br/>
+ * - start values: values at start time, after delay<br/>
+ * - end values: params + values at start time, after delay
+ *
+ * @param targetValues The relative target values of the interpolation.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween targetRelative(float... targetValues) {
+ if (targetValues.length > combinedAttrsLimit) throwCombinedAttrsLimitReached();
+ for (int i=0; i<targetValues.length; i++) {
+ this.targetValues[i] = isInitialized() ? targetValues[i] + startValues[i] : targetValues[i];
+ }
+
+ isRelative = true;
+ return this;
+ }
+
+ /**
+ * Adds a waypoint to the path. The default path runs from the start values
+ * to the end values linearly. If you add waypoints, the default path will
+ * use a smooth catmull-rom spline to navigate between the waypoints, but
+ * you can change this behavior by using the {@link #path(TweenPath)}
+ * method.
+ *
+ * @param targetValue The target of this waypoint.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween waypoint(float targetValue) {
+ if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
+ waypoints[waypointsCnt] = targetValue;
+ waypointsCnt += 1;
+ return this;
+ }
+
+ /**
+ * Adds a waypoint to the path. The default path runs from the start values
+ * to the end values linearly. If you add waypoints, the default path will
+ * use a smooth catmull-rom spline to navigate between the waypoints, but
+ * you can change this behavior by using the {@link #path(TweenPath)}
+ * method.
+ * <p/>
+ * Note that if you want waypoints relative to the start values, use one of
+ * the .targetRelative() methods to define your target.
+ *
+ * @param targetValue1 The 1st target of this waypoint.
+ * @param targetValue2 The 2nd target of this waypoint.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween waypoint(float targetValue1, float targetValue2) {
+ if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
+ waypoints[waypointsCnt*2] = targetValue1;
+ waypoints[waypointsCnt*2+1] = targetValue2;
+ waypointsCnt += 1;
+ return this;
+ }
+
+ /**
+ * Adds a waypoint to the path. The default path runs from the start values
+ * to the end values linearly. If you add waypoints, the default path will
+ * use a smooth catmull-rom spline to navigate between the waypoints, but
+ * you can change this behavior by using the {@link #path(TweenPath)}
+ * method.
+ * <p/>
+ * Note that if you want waypoints relative to the start values, use one of
+ * the .targetRelative() methods to define your target.
+ *
+ * @param targetValue1 The 1st target of this waypoint.
+ * @param targetValue2 The 2nd target of this waypoint.
+ * @param targetValue3 The 3rd target of this waypoint.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween waypoint(float targetValue1, float targetValue2, float targetValue3) {
+ if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
+ waypoints[waypointsCnt*3] = targetValue1;
+ waypoints[waypointsCnt*3+1] = targetValue2;
+ waypoints[waypointsCnt*3+2] = targetValue3;
+ waypointsCnt += 1;
+ return this;
+ }
+
+ /**
+ * Adds a waypoint to the path. The default path runs from the start values
+ * to the end values linearly. If you add waypoints, the default path will
+ * use a smooth catmull-rom spline to navigate between the waypoints, but
+ * you can change this behavior by using the {@link #path(TweenPath)}
+ * method.
+ * <p/>
+ * Note that if you want waypoints relative to the start values, use one of
+ * the .targetRelative() methods to define your target.
+ *
+ * @param targetValues The targets of this waypoint.
+ * @return The current tween, for chaining instructions.
+ */
+ public Tween waypoint(float... targetValues) {
+ if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached();
+ System.arraycopy(targetValues, 0, waypoints, waypointsCnt*targetValues.length, targetValues.length);
+ waypointsCnt += 1;
+ return this;
+ }
+
+ /**
+ * Sets the algorithm that will be used to navigate through the waypoints,
+ * from the start values to the end values. Default is a catmull-rom spline,
+ * but you can find other paths in the {@link TweenPaths} class.
+ *
+ * @param path A TweenPath implementation.
+ * @return The current tween, for chaining instructions.
+ * @see TweenPath
+ * @see TweenPaths
+ */
+ public Tween path(TweenPath path) {
+ this.path = path;
+ return this;
+ }
+
+ // -------------------------------------------------------------------------
+ // Getters
+ // -------------------------------------------------------------------------
+
+ /**
+ * Gets the target object.
+ */
+ public Object getTarget() {
+ return target;
+ }
+
+ /**
+ * Gets the type of the tween.
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Gets the easing equation.
+ */
+ public TweenEquation getEasing() {
+ return equation;
+ }
+
+ /**
+ * Gets the target values. The returned buffer is as long as the maximum
+ * allowed combined values. Therefore, you're surely not interested in all
+ * its content. Use {@link #getCombinedTweenCount()} to get the number of
+ * interesting slots.
+ */
+ public float[] getTargetValues() {
+ return targetValues;
+ }
+
+ /**
+ * Gets the number of combined animations.
+ */
+ public int getCombinedAttributesCount() {
+ return combinedAttrsCnt;
+ }
+
+ /**
+ * Gets the TweenAccessor used with the target.
+ */
+ public TweenAccessor<?> getAccessor() {
+ return accessor;
+ }
+
+ /**
+ * Gets the class that was used to find the associated TweenAccessor.
+ */
+ public Class<?> getTargetClass() {
+ return targetClass;
+ }
+
+ // -------------------------------------------------------------------------
+ // Overrides
+ // -------------------------------------------------------------------------
+
+ @Override
+ public Tween build() {
+ if (target == null) return this;
+
+ accessor = (TweenAccessor<Object>) registeredAccessors.get(targetClass);
+ if (accessor == null && target instanceof TweenAccessor) accessor = (TweenAccessor<Object>) target;
+ if (accessor != null) combinedAttrsCnt = accessor.getValues(target, type, accessorBuffer);
+ else throw new RuntimeException("No TweenAccessor was found for the target");
+
+ if (combinedAttrsCnt > combinedAttrsLimit) throwCombinedAttrsLimitReached();
+ return this;
+ }
+
+ @Override
+ public void free() {
+ pool.free(this);
+ }
+
+ @Override
+ protected void initializeOverride() {
+ if (target == null) return;
+
+ accessor.getValues(target, type, startValues);
+
+ for (int i=0; i<combinedAttrsCnt; i++) {
+ targetValues[i] += isRelative ? startValues[i] : 0;
+
+ for (int ii=0; ii<waypointsCnt; ii++) {
+ waypoints[ii*combinedAttrsCnt+i] += isRelative ? startValues[i] : 0;
+ }
+
+ if (isFrom) {
+ float tmp = startValues[i];
+ startValues[i] = targetValues[i];
+ targetValues[i] = tmp;
+ }
+ }
+ }
+
+ @Override
+ protected void updateOverride(int step, int lastStep, boolean isIterationStep, float delta) {
+ if (target == null || equation == null) return;
+
+ // Case iteration end has been reached
+
+ if (!isIterationStep && step > lastStep) {
+ accessor.setValues(target, type, isReverse(lastStep) ? startValues : targetValues);
+ return;
+ }
+
+ if (!isIterationStep && step < lastStep) {
+ accessor.setValues(target, type, isReverse(lastStep) ? targetValues : startValues);
+ return;
+ }
+
+ // Validation
+
+ assert isIterationStep;
+ assert getCurrentTime() >= 0;
+ assert getCurrentTime() <= duration;
+
+ // Case duration equals zero
+
+ if (duration < 0.00000000001f && delta > -0.00000000001f) {
+ accessor.setValues(target, type, isReverse(step) ? targetValues : startValues);
+ return;
+ }
+
+ if (duration < 0.00000000001f && delta < 0.00000000001f) {
+ accessor.setValues(target, type, isReverse(step) ? startValues : targetValues);
+ return;
+ }
+
+ // Normal behavior
+
+ float time = isReverse(step) ? duration - getCurrentTime() : getCurrentTime();
+ float t = equation.compute(time/duration);
+
+ if (waypointsCnt == 0 || path == null) {
+ for (int i=0; i<combinedAttrsCnt; i++) {
+ accessorBuffer[i] = startValues[i] + t * (targetValues[i] - startValues[i]);
+ }
+
+ } else {
+ for (int i=0; i<combinedAttrsCnt; i++) {
+ pathBuffer[0] = startValues[i];
+ pathBuffer[1+waypointsCnt] = targetValues[i];
+ for (int ii=0; ii<waypointsCnt; ii++) {
+ pathBuffer[ii+1] = waypoints[ii*combinedAttrsCnt+i];
+ }
+
+ accessorBuffer[i] = path.compute(t, pathBuffer, waypointsCnt+2);
+ }
+ }
+
+ accessor.setValues(target, type, accessorBuffer);
+ }
+
+ // -------------------------------------------------------------------------
+ // BaseTween impl.
+ // -------------------------------------------------------------------------
+
+ @Override
+ protected void forceStartValues() {
+ if (target == null) return;
+ accessor.setValues(target, type, startValues);
+ }
+
+ @Override
+ protected void forceEndValues() {
+ if (target == null) return;
+ accessor.setValues(target, type, targetValues);
+ }
+
+ @Override
+ protected boolean containsTarget(Object target) {
+ return this.target == target;
+ }
+
+ @Override
+ protected boolean containsTarget(Object target, int tweenType) {
+ return this.target == target && this.type == tweenType;
+ }
+
+ // -------------------------------------------------------------------------
+ // Helpers
+ // -------------------------------------------------------------------------
+
+ private void throwCombinedAttrsLimitReached() {
+ String msg = "You cannot combine more than " + combinedAttrsLimit + " "
+ + "attributes in a tween. You can raise this limit with "
+ + "Tween.setCombinedAttributesLimit(), which should be called once "
+ + "in application initialization code.";
+ throw new RuntimeException(msg);
+ }
+
+ private void throwWaypointsLimitReached() {
+ String msg = "You cannot add more than " + waypointsLimit + " "
+ + "waypoints to a tween. You can raise this limit with "
+ + "Tween.setWaypointsLimit(), which should be called once in "
+ + "application initialization code.";
+ throw new RuntimeException(msg);
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenAccessor.java b/java/api/src/aurelienribon/tweenengine/TweenAccessor.java
new file mode 100755
index 0000000..780fb3c
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenAccessor.java
@@ -0,0 +1,82 @@
+package aurelienribon.tweenengine;
+
+/**
+ * The TweenAccessor interface lets you interpolate any attribute from any
+ * object. Just implement it as you want and register it to the engine by
+ * calling {@link Tween#registerAccessor}.
+ * <p/>
+ *
+ * <h2>Example</h2>
+ *
+ * The following code snippet presents an example of implementation for tweening
+ * a Particle class. This Particle class is supposed to only define a position
+ * with an "x" and an "y" fields, and their associated getters and setters.
+ * <p/>
+ *
+ * <pre> {@code
+ * public class ParticleAccessor implements TweenAccessor<Particle> {
+ * public static final int X = 1;
+ * public static final int Y = 2;
+ * public static final int XY = 3;
+ *
+ * public int getValues(Particle target, int tweenType, float[] returnValues) {
+ * switch (tweenType) {
+ * case X: returnValues[0] = target.getX(); return 1;
+ * case Y: returnValues[0] = target.getY(); return 1;
+ * case XY:
+ * returnValues[0] = target.getX();
+ * returnValues[1] = target.getY();
+ * return 2;
+ * default: assert false; return 0;
+ * }
+ * }
+ *
+ * public void setValues(Particle target, int tweenType, float[] newValues) {
+ * switch (tweenType) {
+ * case X: target.setX(newValues[0]); break;
+ * case Y: target.setY(newValues[1]); break;
+ * case XY:
+ * target.setX(newValues[0]);
+ * target.setY(newValues[1]);
+ * break;
+ * default: assert false; break;
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * Once done, you only need to register this TweenAccessor once to be able to
+ * use it for every Particle objects in your application:
+ * <p/>
+ *
+ * <pre> {@code
+ * Tween.registerAccessor(Particle.class, new ParticleAccessor());
+ * }</pre>
+ *
+ * And that's all, the Tween Engine can no work with all your particles!
+ *
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public interface TweenAccessor<T> {
+ /**
+ * Gets one or many values from the target object associated to the
+ * given tween type. It is used by the Tween Engine to determine starting
+ * values.
+ *
+ * @param target The target object of the tween.
+ * @param tweenType An integer representing the tween type.
+ * @param returnValues An array which should be modified by this method.
+ * @return The count of modified slots from the returnValues array.
+ */
+ public int getValues(T target, int tweenType, float[] returnValues);
+
+ /**
+ * This method is called by the Tween Engine each time a running tween
+ * associated with the current target object has been updated.
+ *
+ * @param target The target object of the tween.
+ * @param tweenType An integer representing the tween type.
+ * @param newValues The new values determined by the Tween Engine.
+ */
+ public void setValues(T target, int tweenType, float[] newValues);
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenCallback.java b/java/api/src/aurelienribon/tweenengine/TweenCallback.java
new file mode 100755
index 0000000..5a733cb
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenCallback.java
@@ -0,0 +1,45 @@
+package aurelienribon.tweenengine;
+
+/**
+ * TweenCallbacks are used to trigger actions at some specific times. They are
+ * used in both Tweens and Timelines. The moment when the callback is
+ * triggered depends on its registered triggers:
+ * <p/>
+ *
+ * <b>BEGIN</b>: right after the delay (if any)<br/>
+ * <b>START</b>: at each iteration beginning<br/>
+ * <b>END</b>: at each iteration ending, before the repeat delay<br/>
+ * <b>COMPLETE</b>: at last END event<br/>
+ * <b>BACK_BEGIN</b>: at the beginning of the first backward iteration<br/>
+ * <b>BACK_START</b>: at each backward iteration beginning, after the repeat delay<br/>
+ * <b>BACK_END</b>: at each backward iteration ending<br/>
+ * <b>BACK_COMPLETE</b>: at last BACK_END event
+ * <p/>
+ *
+ * <pre> {@code
+ * forward : BEGIN COMPLETE
+ * forward : START END START END START END
+ * |--------------[XXXXXXXXXX]------[XXXXXXXXXX]------[XXXXXXXXXX]
+ * backward: bEND bSTART bEND bSTART bEND bSTART
+ * backward: bCOMPLETE bBEGIN
+ * }</pre>
+ *
+ * @see Tween
+ * @see Timeline
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public interface TweenCallback {
+ public static final int BEGIN = 0x01;
+ public static final int START = 0x02;
+ public static final int END = 0x04;
+ public static final int COMPLETE = 0x08;
+ public static final int BACK_BEGIN = 0x10;
+ public static final int BACK_START = 0x20;
+ public static final int BACK_END = 0x40;
+ public static final int BACK_COMPLETE = 0x80;
+ public static final int ANY_FORWARD = 0x0F;
+ public static final int ANY_BACKWARD = 0xF0;
+ public static final int ANY = 0xFF;
+
+ public void onEvent(int type, BaseTween<?> source);
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenEquation.java b/java/api/src/aurelienribon/tweenengine/TweenEquation.java
new file mode 100755
index 0000000..d550703
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenEquation.java
@@ -0,0 +1,28 @@
+package aurelienribon.tweenengine;
+
+/**
+ * Base class for every easing equation. You can create your own equations
+ * and directly use them in the Tween engine by inheriting from this class.
+ *
+ * @see Tween
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class TweenEquation {
+
+ /**
+ * Computes the next value of the interpolation.
+ *
+ * @param t The current time, between 0 and 1.
+ * @return The current value.
+ */
+ public abstract float compute(float t);
+
+ /**
+ * Returns true if the given string is the name of this equation (the name
+ * is returned in the toString() method, don't forget to override it).
+ * This method is usually used to save/load a tween to/from a text file.
+ */
+ public boolean isValueOf(String str) {
+ return str.equals(toString());
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenEquations.java b/java/api/src/aurelienribon/tweenengine/TweenEquations.java
new file mode 100755
index 0000000..115fc32
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenEquations.java
@@ -0,0 +1,52 @@
+package aurelienribon.tweenengine;
+
+import aurelienribon.tweenengine.equations.Back;
+import aurelienribon.tweenengine.equations.Bounce;
+import aurelienribon.tweenengine.equations.Circ;
+import aurelienribon.tweenengine.equations.Cubic;
+import aurelienribon.tweenengine.equations.Elastic;
+import aurelienribon.tweenengine.equations.Expo;
+import aurelienribon.tweenengine.equations.Linear;
+import aurelienribon.tweenengine.equations.Quad;
+import aurelienribon.tweenengine.equations.Quart;
+import aurelienribon.tweenengine.equations.Quint;
+import aurelienribon.tweenengine.equations.Sine;
+
+/**
+ * Collection of built-in easing equations
+ *
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public interface TweenEquations {
+ public static final Linear easeNone = Linear.INOUT;
+ public static final Quad easeInQuad = Quad.IN;
+ public static final Quad easeOutQuad = Quad.OUT;
+ public static final Quad easeInOutQuad = Quad.INOUT;
+ public static final Cubic easeInCubic = Cubic.IN;
+ public static final Cubic easeOutCubic = Cubic.OUT;
+ public static final Cubic easeInOutCubic = Cubic.INOUT;
+ public static final Quart easeInQuart = Quart.IN;
+ public static final Quart easeOutQuart = Quart.OUT;
+ public static final Quart easeInOutQuart = Quart.INOUT;
+ public static final Quint easeInQuint = Quint.IN;
+ public static final Quint easeOutQuint = Quint.OUT;
+ public static final Quint easeInOutQuint = Quint.INOUT;
+ public static final Circ easeInCirc = Circ.IN;
+ public static final Circ easeOutCirc = Circ.OUT;
+ public static final Circ easeInOutCirc = Circ.INOUT;
+ public static final Sine easeInSine = Sine.IN;
+ public static final Sine easeOutSine = Sine.OUT;
+ public static final Sine easeInOutSine = Sine.INOUT;
+ public static final Expo easeInExpo = Expo.IN;
+ public static final Expo easeOutExpo = Expo.OUT;
+ public static final Expo easeInOutExpo = Expo.INOUT;
+ public static final Back easeInBack = Back.IN;
+ public static final Back easeOutBack = Back.OUT;
+ public static final Back easeInOutBack = Back.INOUT;
+ public static final Bounce easeInBounce = Bounce.IN;
+ public static final Bounce easeOutBounce = Bounce.OUT;
+ public static final Bounce easeInOutBounce = Bounce.INOUT;
+ public static final Elastic easeInElastic = Elastic.IN;
+ public static final Elastic easeOutElastic = Elastic.OUT;
+ public static final Elastic easeInOutElastic = Elastic.INOUT;
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenManager.java b/java/api/src/aurelienribon/tweenengine/TweenManager.java
new file mode 100755
index 0000000..bc6ec7b
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenManager.java
@@ -0,0 +1,237 @@
+package aurelienribon.tweenengine;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A TweenManager updates all your tweens and timelines at once.
+ * Its main interest is that it handles the tween/timeline life-cycles for you,
+ * as well as the pooling constraints (if object pooling is enabled).
+ * <p/>
+ *
+ * Just give it a bunch of tweens or timelines and call update() periodically,
+ * you don't need to care for anything else! Relax and enjoy your animations.
+ *
+ * @see Tween
+ * @see Timeline
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public class TweenManager {
+ // -------------------------------------------------------------------------
+ // Static API
+ // -------------------------------------------------------------------------
+
+ /**
+ * Disables or enables the "auto remove" mode of any tween manager for a
+ * particular tween or timeline. This mode is activated by default. The
+ * interest of desactivating it is to prevent some tweens or timelines from
+ * being automatically removed from a manager once they are finished.
+ * Therefore, if you update a manager backwards, the tweens or timelines
+ * will be played again, even if they were finished.
+ */
+ public static void setAutoRemove(BaseTween<?> object, boolean value) {
+ object.isAutoRemoveEnabled = value;
+ }
+
+ /**
+ * Disables or enables the "auto start" mode of any tween manager for a
+ * particular tween or timeline. This mode is activated by default. If it
+ * is not enabled, add a tween or timeline to any manager won't start it
+ * automatically, and you'll need to call .start() manually on your object.
+ */
+ public static void setAutoStart(BaseTween<?> object, boolean value) {
+ object.isAutoStartEnabled = value;
+ }
+
+ // -------------------------------------------------------------------------
+ // Public API
+ // -------------------------------------------------------------------------
+
+ private final ArrayList<BaseTween<?>> objects = new ArrayList<BaseTween<?>>(20);
+ private boolean isPaused = false;
+
+ /**
+ * Adds a tween or timeline to the manager and starts or restarts it.
+ *
+ * @return The manager, for instruction chaining.
+ */
+ public TweenManager add(BaseTween<?> object) {
+ if (!objects.contains(object)) objects.add(object);
+ if (object.isAutoStartEnabled) object.start();
+ return this;
+ }
+
+ /**
+ * Returns true if the manager contains any valid interpolation associated
+ * to the given target object.
+ */
+ public boolean containsTarget(Object target) {
+ for (int i=0, n=objects.size(); i<n; i++) {
+ BaseTween<?> obj = objects.get(i);
+ if (obj.containsTarget(target)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the manager contains any valid interpolation associated
+ * to the given target object and to the given tween type.
+ */
+ public boolean containsTarget(Object target, int tweenType) {
+ for (int i=0, n=objects.size(); i<n; i++) {
+ BaseTween<?> obj = objects.get(i);
+ if (obj.containsTarget(target, tweenType)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Kills every managed tweens and timelines.
+ */
+ public void killAll() {
+ for (int i=0, n=objects.size(); i<n; i++) {
+ BaseTween<?> obj = objects.get(i);
+ obj.kill();
+ }
+ }
+
+ /**
+ * Kills every tweens associated to the given target. Will also kill every
+ * timelines containing a tween associated to the given target.
+ */
+ public void killTarget(Object target) {
+ for (int i=0, n=objects.size(); i<n; i++) {
+ BaseTween<?> obj = objects.get(i);
+ obj.killTarget(target);
+ }
+ }
+
+ /**
+ * Kills every tweens associated to the given target and tween type. Will
+ * also kill every timelines containing a tween associated to the given
+ * target and tween type.
+ */
+ public void killTarget(Object target, int tweenType) {
+ for (int i=0, n=objects.size(); i<n; i++) {
+ BaseTween<?> obj = objects.get(i);
+ obj.killTarget(target, tweenType);
+ }
+ }
+
+ /**
+ * Increases the minimum capacity of the manager. Defaults to 20.
+ */
+ public void ensureCapacity(int minCapacity) {
+ objects.ensureCapacity(minCapacity);
+ }
+
+ /**
+ * Pauses the manager. Further update calls won't have any effect.
+ */
+ public void pause() {
+ isPaused = true;
+ }
+
+ /**
+ * Resumes the manager, if paused.
+ */
+ public void resume() {
+ isPaused = false;
+ }
+
+ /**
+ * Updates every tweens with a delta time ang handles the tween life-cycles
+ * automatically. If a tween is finished, it will be removed from the
+ * manager. The delta time represents the elapsed time between now and the
+ * last update call. Each tween or timeline manages its local time, and adds
+ * this delta to its local time to update itself.
+ * <p/>
+ *
+ * Slow motion, fast motion and backward play can be easily achieved by
+ * tweaking this delta time. Multiply it by -1 to play the animation
+ * backward, or by 0.5 to play it twice slower than its normal speed.
+ */
+ public void update(float delta) {
+ for (int i=objects.size()-1; i>=0; i--) {
+ BaseTween<?> obj = objects.get(i);
+ if (obj.isFinished() && obj.isAutoRemoveEnabled) {
+ objects.remove(i);
+ obj.free();
+ }
+ }
+
+ if (!isPaused) {
+ if (delta >= 0) {
+ for (int i=0, n=objects.size(); i<n; i++) objects.get(i).update(delta);
+ } else {
+ for (int i=objects.size()-1; i>=0; i--) objects.get(i).update(delta);
+ }
+ }
+ }
+
+ /**
+ * Gets the number of managed objects. An object may be a tween or a
+ * timeline. Note that a timeline only counts for 1 object, since it
+ * manages its children itself.
+ * <p/>
+ * To get the count of running tweens, see {@link #getRunningTweensCount()}.
+ */
+ public int size() {
+ return objects.size();
+ }
+
+ /**
+ * Gets the number of running tweens. This number includes the tweens
+ * located inside timelines (and nested timelines).
+ * <p/>
+ * <b>Provided for debug purpose only.</b>
+ */
+ public int getRunningTweensCount() {
+ return getTweensCount(objects);
+ }
+
+ /**
+ * Gets the number of running timelines. This number includes the timelines
+ * nested inside other timelines.
+ * <p/>
+ * <b>Provided for debug purpose only.</b>
+ */
+ public int getRunningTimelinesCount() {
+ return getTimelinesCount(objects);
+ }
+
+ /**
+ * Gets an immutable list of every managed object.
+ * <p/>
+ * <b>Provided for debug purpose only.</b>
+ */
+ public List<BaseTween<?>> getObjects() {
+ return Collections.unmodifiableList(objects);
+ }
+
+ // -------------------------------------------------------------------------
+ // Helpers
+ // -------------------------------------------------------------------------
+
+ private static int getTweensCount(List<BaseTween<?>> objs) {
+ int cnt = 0;
+ for (int i=0, n=objs.size(); i<n; i++) {
+ BaseTween<?> obj = objs.get(i);
+ if (obj instanceof Tween) cnt += 1;
+ else cnt += getTweensCount(((Timeline)obj).getChildren());
+ }
+ return cnt;
+ }
+
+ private static int getTimelinesCount(List<BaseTween<?>> objs) {
+ int cnt = 0;
+ for (int i=0, n=objs.size(); i<n; i++) {
+ BaseTween<?> obj = objs.get(i);
+ if (obj instanceof Timeline) {
+ cnt += 1 + getTimelinesCount(((Timeline)obj).getChildren());
+ }
+ }
+ return cnt;
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenPath.java b/java/api/src/aurelienribon/tweenengine/TweenPath.java
new file mode 100755
index 0000000..724741b
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenPath.java
@@ -0,0 +1,22 @@
+package aurelienribon.tweenengine;
+
+/**
+ * Base class for every paths. You can create your own paths and directly use
+ * them in the Tween engine by inheriting from this class.
+ *
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public interface TweenPath {
+
+ /**
+ * Computes the next value of the interpolation, based on its waypoints and
+ * the current progress.
+ *
+ * @param t The progress of the interpolation, between 0 and 1. May be out
+ * of these bounds if the easing equation involves some kind of rebounds.
+ * @param points The waypoints of the tween, from start to target values.
+ * @param pointsCnt The number of valid points in the array.
+ * @return The next value of the interpolation.
+ */
+ public float compute(float t, float[] points, int pointsCnt);
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenPaths.java b/java/api/src/aurelienribon/tweenengine/TweenPaths.java
new file mode 100755
index 0000000..dbea075
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenPaths.java
@@ -0,0 +1,14 @@
+package aurelienribon.tweenengine;
+
+import aurelienribon.tweenengine.paths.CatmullRom;
+import aurelienribon.tweenengine.paths.Linear;
+
+/**
+ * Collection of built-in paths.
+ *
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public interface TweenPaths {
+ public static final Linear linear = new Linear();
+ public static final CatmullRom catmullRom = new CatmullRom();
+}
diff --git a/java/api/src/aurelienribon/tweenengine/TweenUtils.java b/java/api/src/aurelienribon/tweenengine/TweenUtils.java
new file mode 100755
index 0000000..6c1b12c
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/TweenUtils.java
@@ -0,0 +1,53 @@
+package aurelienribon.tweenengine;
+
+import aurelienribon.tweenengine.equations.Back;
+import aurelienribon.tweenengine.equations.Bounce;
+import aurelienribon.tweenengine.equations.Circ;
+import aurelienribon.tweenengine.equations.Cubic;
+import aurelienribon.tweenengine.equations.Elastic;
+import aurelienribon.tweenengine.equations.Expo;
+import aurelienribon.tweenengine.equations.Linear;
+import aurelienribon.tweenengine.equations.Quad;
+import aurelienribon.tweenengine.equations.Quart;
+import aurelienribon.tweenengine.equations.Quint;
+import aurelienribon.tweenengine.equations.Sine;
+
+/**
+ * Collection of miscellaneous utilities.
+ *
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public class TweenUtils {
+ private static TweenEquation[] easings;
+
+ /**
+ * Takes an easing name and gives you the corresponding TweenEquation.
+ * You probably won't need this, but tools will love that.
+ *
+ * @param easingName The name of an easing, like "Quad.INOUT".
+ * @return The parsed equation, or null if there is no match.
+ */
+ public static TweenEquation parseEasing(String easingName) {
+ if (easings == null) {
+ easings = new TweenEquation[] {Linear.INOUT,
+ Quad.IN, Quad.OUT, Quad.INOUT,
+ Cubic.IN, Cubic.OUT, Cubic.INOUT,
+ Quart.IN, Quart.OUT, Quart.INOUT,
+ Quint.IN, Quint.OUT, Quint.INOUT,
+ Circ.IN, Circ.OUT, Circ.INOUT,
+ Sine.IN, Sine.OUT, Sine.INOUT,
+ Expo.IN, Expo.OUT, Expo.INOUT,
+ Back.IN, Back.OUT, Back.INOUT,
+ Bounce.IN, Bounce.OUT, Bounce.INOUT,
+ Elastic.IN, Elastic.OUT, Elastic.INOUT
+ };
+ }
+
+ for (int i=0; i<easings.length; i++) {
+ if (easingName.equals(easings[i].toString()))
+ return easings[i];
+ }
+
+ return null;
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Back.java b/java/api/src/aurelienribon/tweenengine/equations/Back.java
new file mode 100755
index 0000000..46385ed
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Back.java
@@ -0,0 +1,59 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Back extends TweenEquation {
+ public static final Back IN = new Back() {
+ @Override
+ public final float compute(float t) {
+ float s = param_s;
+ return t*t*((s+1)*t - s);
+ }
+
+ @Override
+ public String toString() {
+ return "Back.IN";
+ }
+ };
+
+ public static final Back OUT = new Back() {
+ @Override
+ public final float compute(float t) {
+ float s = param_s;
+ return (t-=1)*t*((s+1)*t + s) + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Back.OUT";
+ }
+ };
+
+ public static final Back INOUT = new Back() {
+ @Override
+ public final float compute(float t) {
+ float s = param_s;
+ if ((t*=2) < 1) return 0.5f*(t*t*(((s*=(1.525f))+1)*t - s));
+ return 0.5f*((t-=2)*t*(((s*=(1.525f))+1)*t + s) + 2);
+ }
+
+ @Override
+ public String toString() {
+ return "Back.INOUT";
+ }
+ };
+
+ // -------------------------------------------------------------------------
+
+ protected float param_s = 1.70158f;
+
+ public Back s(float s) {
+ param_s = s;
+ return this;
+ }
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Bounce.java b/java/api/src/aurelienribon/tweenengine/equations/Bounce.java
new file mode 100755
index 0000000..3cfc4e3
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Bounce.java
@@ -0,0 +1,55 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Bounce extends TweenEquation {
+ public static final Bounce IN = new Bounce() {
+ @Override
+ public final float compute(float t) {
+ return 1 - OUT.compute(1-t);
+ }
+
+ @Override
+ public String toString() {
+ return "Bounce.IN";
+ }
+ };
+
+ public static final Bounce OUT = new Bounce() {
+ @Override
+ public final float compute(float t) {
+ if (t < (1/2.75)) {
+ return 7.5625f*t*t;
+ } else if (t < (2/2.75)) {
+ return 7.5625f*(t-=(1.5f/2.75f))*t + .75f;
+ } else if (t < (2.5/2.75)) {
+ return 7.5625f*(t-=(2.25f/2.75f))*t + .9375f;
+ } else {
+ return 7.5625f*(t-=(2.625f/2.75f))*t + .984375f;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Bounce.OUT";
+ }
+ };
+
+ public static final Bounce INOUT = new Bounce() {
+ @Override
+ public final float compute(float t) {
+ if (t < 0.5f) return IN.compute(t*2) * .5f;
+ else return OUT.compute(t*2-1) * .5f + 0.5f;
+ }
+
+ @Override
+ public String toString() {
+ return "Bounce.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Circ.java b/java/api/src/aurelienribon/tweenengine/equations/Circ.java
new file mode 100755
index 0000000..63a0145
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Circ.java
@@ -0,0 +1,47 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Circ extends TweenEquation {
+ public static final Circ IN = new Circ() {
+ @Override
+ public final float compute(float t) {
+ return (float) -Math.sqrt(1 - t*t) - 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Circ.IN";
+ }
+ };
+
+ public static final Circ OUT = new Circ() {
+ @Override
+ public final float compute(float t) {
+ return (float) Math.sqrt(1 - (t-=1)*t);
+ }
+
+ @Override
+ public String toString() {
+ return "Circ.OUT";
+ }
+ };
+
+ public static final Circ INOUT = new Circ() {
+ @Override
+ public final float compute(float t) {
+ if ((t*=2) < 1) return -0.5f * ((float)Math.sqrt(1 - t*t) - 1);
+ return 0.5f * ((float)Math.sqrt(1 - (t-=2)*t) + 1);
+ }
+
+ @Override
+ public String toString() {
+ return "Circ.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Cubic.java b/java/api/src/aurelienribon/tweenengine/equations/Cubic.java
new file mode 100755
index 0000000..9d86988
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Cubic.java
@@ -0,0 +1,47 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Cubic extends TweenEquation {
+ public static final Cubic IN = new Cubic() {
+ @Override
+ public final float compute(float t) {
+ return t*t*t;
+ }
+
+ @Override
+ public String toString() {
+ return "Cubic.IN";
+ }
+ };
+
+ public static final Cubic OUT = new Cubic() {
+ @Override
+ public final float compute(float t) {
+ return (t-=1)*t*t + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Cubic.OUT";
+ }
+ };
+
+ public static final Cubic INOUT = new Cubic() {
+ @Override
+ public final float compute(float t) {
+ if ((t*=2) < 1) return 0.5f*t*t*t;
+ return 0.5f * ((t-=2)*t*t + 2);
+ }
+
+ @Override
+ public String toString() {
+ return "Cubic.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Elastic.java b/java/api/src/aurelienribon/tweenengine/equations/Elastic.java
new file mode 100755
index 0000000..925993d
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Elastic.java
@@ -0,0 +1,86 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Elastic extends TweenEquation {
+ private static final float PI = 3.14159265f;
+
+ public static final Elastic IN = new Elastic() {
+ @Override
+ public final float compute(float t) {
+ float a = param_a;
+ float p = param_p;
+ if (t==0) return 0; if (t==1) return 1; if (!setP) p=.3f;
+ float s;
+ if (!setA || a < 1) { a=1; s=p/4; }
+ else s = p/(2*PI) * (float)Math.asin(1/a);
+ return -(a*(float)Math.pow(2,10*(t-=1)) * (float)Math.sin( (t-s)*(2*PI)/p ));
+ }
+
+ @Override
+ public String toString() {
+ return "Elastic.IN";
+ }
+ };
+
+ public static final Elastic OUT = new Elastic() {
+ @Override
+ public final float compute(float t) {
+ float a = param_a;
+ float p = param_p;
+ if (t==0) return 0; if (t==1) return 1; if (!setP) p=.3f;
+ float s;
+ if (!setA || a < 1) { a=1; s=p/4; }
+ else s = p/(2*PI) * (float)Math.asin(1/a);
+ return a*(float)Math.pow(2,-10*t) * (float)Math.sin( (t-s)*(2*PI)/p ) + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Elastic.OUT";
+ }
+ };
+
+ public static final Elastic INOUT = new Elastic() {
+ @Override
+ public final float compute(float t) {
+ float a = param_a;
+ float p = param_p;
+ if (t==0) return 0; if ((t*=2)==2) return 1; if (!setP) p=.3f*1.5f;
+ float s;
+ if (!setA || a < 1) { a=1; s=p/4; }
+ else s = p/(2*PI) * (float)Math.asin(1/a);
+ if (t < 1) return -.5f*(a*(float)Math.pow(2,10*(t-=1)) * (float)Math.sin( (t-s)*(2*PI)/p ));
+ return a*(float)Math.pow(2,-10*(t-=1)) * (float)Math.sin( (t-s)*(2*PI)/p )*.5f + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Elastic.INOUT";
+ }
+ };
+
+ // -------------------------------------------------------------------------
+
+ protected float param_a;
+ protected float param_p;
+ protected boolean setA = false;
+ protected boolean setP = false;
+
+ public Elastic a(float a) {
+ param_a = a;
+ this.setA = true;
+ return this;
+ }
+
+ public Elastic p(float p) {
+ param_p = p;
+ this.setP = true;
+ return this;
+ }
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Expo.java b/java/api/src/aurelienribon/tweenengine/equations/Expo.java
new file mode 100755
index 0000000..38a6a00
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Expo.java
@@ -0,0 +1,49 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Expo extends TweenEquation {
+ public static final Expo IN = new Expo() {
+ @Override
+ public final float compute(float t) {
+ return (t==0) ? 0 : (float) Math.pow(2, 10 * (t - 1));
+ }
+
+ @Override
+ public String toString() {
+ return "Expo.IN";
+ }
+ };
+
+ public static final Expo OUT = new Expo() {
+ @Override
+ public final float compute(float t) {
+ return (t==1) ? 1 : -(float) Math.pow(2, -10 * t) + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Expo.OUT";
+ }
+ };
+
+ public static final Expo INOUT = new Expo() {
+ @Override
+ public final float compute(float t) {
+ if (t==0) return 0;
+ if (t==1) return 1;
+ if ((t*=2) < 1) return 0.5f * (float) Math.pow(2, 10 * (t - 1));
+ return 0.5f * (-(float)Math.pow(2, -10 * --t) + 2);
+ }
+
+ @Override
+ public String toString() {
+ return "Expo.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Linear.java b/java/api/src/aurelienribon/tweenengine/equations/Linear.java
new file mode 100755
index 0000000..1f95103
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Linear.java
@@ -0,0 +1,22 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Linear extends TweenEquation {
+ public static final Linear INOUT = new Linear() {
+ @Override
+ public float compute(float t) {
+ return t;
+ }
+
+ @Override
+ public String toString() {
+ return "Linear.INOUT";
+ }
+ };
+}
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Quad.java b/java/api/src/aurelienribon/tweenengine/equations/Quad.java
new file mode 100755
index 0000000..d015112
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Quad.java
@@ -0,0 +1,47 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Quad extends TweenEquation {
+ public static final Quad IN = new Quad() {
+ @Override
+ public final float compute(float t) {
+ return t*t;
+ }
+
+ @Override
+ public String toString() {
+ return "Quad.IN";
+ }
+ };
+
+ public static final Quad OUT = new Quad() {
+ @Override
+ public final float compute(float t) {
+ return -t*(t-2);
+ }
+
+ @Override
+ public String toString() {
+ return "Quad.OUT";
+ }
+ };
+
+ public static final Quad INOUT = new Quad() {
+ @Override
+ public final float compute(float t) {
+ if ((t*=2) < 1) return 0.5f*t*t;
+ return -0.5f * ((--t)*(t-2) - 1);
+ }
+
+ @Override
+ public String toString() {
+ return "Quad.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Quart.java b/java/api/src/aurelienribon/tweenengine/equations/Quart.java
new file mode 100755
index 0000000..826eebb
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Quart.java
@@ -0,0 +1,47 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Quart extends TweenEquation {
+ public static final Quart IN = new Quart() {
+ @Override
+ public final float compute(float t) {
+ return t*t*t*t;
+ }
+
+ @Override
+ public String toString() {
+ return "Quart.IN";
+ }
+ };
+
+ public static final Quart OUT = new Quart() {
+ @Override
+ public final float compute(float t) {
+ return -((t-=1)*t*t*t - 1);
+ }
+
+ @Override
+ public String toString() {
+ return "Quart.OUT";
+ }
+ };
+
+ public static final Quart INOUT = new Quart() {
+ @Override
+ public final float compute(float t) {
+ if ((t*=2) < 1) return 0.5f*t*t*t*t;
+ return -0.5f * ((t-=2)*t*t*t - 2);
+ }
+
+ @Override
+ public String toString() {
+ return "Quart.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Quint.java b/java/api/src/aurelienribon/tweenengine/equations/Quint.java
new file mode 100755
index 0000000..80e2412
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Quint.java
@@ -0,0 +1,47 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Quint extends TweenEquation {
+ public static final Quint IN = new Quint() {
+ @Override
+ public final float compute(float t) {
+ return t*t*t*t*t;
+ }
+
+ @Override
+ public String toString() {
+ return "Quint.IN";
+ }
+ };
+
+ public static final Quint OUT = new Quint() {
+ @Override
+ public final float compute(float t) {
+ return (t-=1)*t*t*t*t + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Quint.OUT";
+ }
+ };
+
+ public static final Quint INOUT = new Quint() {
+ @Override
+ public final float compute(float t) {
+ if ((t*=2) < 1) return 0.5f*t*t*t*t*t;
+ return 0.5f*((t-=2)*t*t*t*t + 2);
+ }
+
+ @Override
+ public String toString() {
+ return "Quint.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/equations/Sine.java b/java/api/src/aurelienribon/tweenengine/equations/Sine.java
new file mode 100755
index 0000000..a4aec5c
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/equations/Sine.java
@@ -0,0 +1,48 @@
+package aurelienribon.tweenengine.equations;
+
+import aurelienribon.tweenengine.TweenEquation;
+
+/**
+ * Easing equation based on Robert Penner's work:
+ * http://robertpenner.com/easing/
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public abstract class Sine extends TweenEquation {
+ private static final float PI = 3.14159265f;
+
+ public static final Sine IN = new Sine() {
+ @Override
+ public final float compute(float t) {
+ return (float) -Math.cos(t * (PI/2)) + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "Sine.IN";
+ }
+ };
+
+ public static final Sine OUT = new Sine() {
+ @Override
+ public final float compute(float t) {
+ return (float) Math.sin(t * (PI/2));
+ }
+
+ @Override
+ public String toString() {
+ return "Sine.OUT";
+ }
+ };
+
+ public static final Sine INOUT = new Sine() {
+ @Override
+ public final float compute(float t) {
+ return -0.5f * ((float) Math.cos(PI*t) - 1);
+ }
+
+ @Override
+ public String toString() {
+ return "Sine.INOUT";
+ }
+ };
+} \ No newline at end of file
diff --git a/java/api/src/aurelienribon/tweenengine/paths/CatmullRom.java b/java/api/src/aurelienribon/tweenengine/paths/CatmullRom.java
new file mode 100755
index 0000000..5dedae4
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/paths/CatmullRom.java
@@ -0,0 +1,39 @@
+package aurelienribon.tweenengine.paths;
+
+import aurelienribon.tweenengine.TweenPath;
+
+/**
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public class CatmullRom implements TweenPath {
+ @Override
+ public float compute(float t, float[] points, int pointsCnt) {
+ int segment = (int) Math.floor((pointsCnt-1) * t);
+ segment = Math.max(segment, 0);
+ segment = Math.min(segment, pointsCnt-2);
+
+ t = t * (pointsCnt-1) - segment;
+
+ if (segment == 0) {
+ return catmullRomSpline(points[0], points[0], points[1], points[2], t);
+ }
+
+ if (segment == pointsCnt-2) {
+ return catmullRomSpline(points[pointsCnt-3], points[pointsCnt-2], points[pointsCnt-1], points[pointsCnt-1], t);
+ }
+
+ return catmullRomSpline(points[segment-1], points[segment], points[segment+1], points[segment+2], t);
+ }
+
+ private float catmullRomSpline(float a, float b, float c, float d, float t) {
+ float t1 = (c - a) * 0.5f;
+ float t2 = (d - b) * 0.5f;
+
+ float h1 = +2 * t * t * t - 3 * t * t + 1;
+ float h2 = -2 * t * t * t + 3 * t * t;
+ float h3 = t * t * t - 2 * t * t + t;
+ float h4 = t * t * t - t * t;
+
+ return b * h1 + c * h2 + t1 * h3 + t2 * h4;
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/paths/Linear.java b/java/api/src/aurelienribon/tweenengine/paths/Linear.java
new file mode 100755
index 0000000..a21b7b5
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/paths/Linear.java
@@ -0,0 +1,19 @@
+package aurelienribon.tweenengine.paths;
+
+import aurelienribon.tweenengine.TweenPath;
+
+/**
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public class Linear implements TweenPath {
+ @Override
+ public float compute(float t, float[] points, int pointsCnt) {
+ int segment = (int) Math.floor((pointsCnt-1) * t);
+ segment = Math.max(segment, 0);
+ segment = Math.min(segment, pointsCnt-2);
+
+ t = t * (pointsCnt-1) - segment;
+
+ return points[segment] + t * (points[segment+1] - points[segment]);
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/primitives/MutableFloat.java b/java/api/src/aurelienribon/tweenengine/primitives/MutableFloat.java
new file mode 100755
index 0000000..a2683b9
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/primitives/MutableFloat.java
@@ -0,0 +1,34 @@
+package aurelienribon.tweenengine.primitives;
+
+import aurelienribon.tweenengine.TweenAccessor;
+
+/**
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public class MutableFloat extends Number implements TweenAccessor<MutableFloat> {
+ private float value;
+
+ public MutableFloat(float value) {
+ this.value = value;
+ }
+
+ public void setValue(float value) {
+ this.value = value;
+ }
+
+ @Override public int intValue() {return (int) value;}
+ @Override public long longValue() {return (long) value;}
+ @Override public float floatValue() {return (float) value;}
+ @Override public double doubleValue() {return (double) value;}
+
+ @Override
+ public int getValues(MutableFloat target, int tweenType, float[] returnValues) {
+ returnValues[0] = target.value;
+ return 1;
+ }
+
+ @Override
+ public void setValues(MutableFloat target, int tweenType, float[] newValues) {
+ target.value = newValues[0];
+ }
+}
diff --git a/java/api/src/aurelienribon/tweenengine/primitives/MutableInteger.java b/java/api/src/aurelienribon/tweenengine/primitives/MutableInteger.java
new file mode 100755
index 0000000..a7ab932
--- /dev/null
+++ b/java/api/src/aurelienribon/tweenengine/primitives/MutableInteger.java
@@ -0,0 +1,34 @@
+package aurelienribon.tweenengine.primitives;
+
+import aurelienribon.tweenengine.TweenAccessor;
+
+/**
+ * @author Aurelien Ribon | http://www.aurelienribon.com/
+ */
+public class MutableInteger extends Number implements TweenAccessor<MutableInteger> {
+ private int value;
+
+ public MutableInteger(int value) {
+ this.value = value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ @Override public int intValue() {return (int) value;}
+ @Override public long longValue() {return (long) value;}
+ @Override public float floatValue() {return (float) value;}
+ @Override public double doubleValue() {return (double) value;}
+
+ @Override
+ public int getValues(MutableInteger target, int tweenType, float[] returnValues) {
+ returnValues[0] = target.value;
+ return 1;
+ }
+
+ @Override
+ public void setValues(MutableInteger target, int tweenType, float[] newValues) {
+ target.value = (int) newValues[0];
+ }
+}