/** * Copyright 2008 - 2012 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.3.3 */ package loon.utils; public class Easing { public static enum EasingMode { InQuad, OutQuad, InOutQuad, InCubic, OutCubic, InOutCubic, InQuart, OutQuart, InOutQuart, InQuint, OutQuint, InOutQuint, InSine, OutSine, InOutSine, InExp, OutExp, InOutExp, InCirc, OutCirc, InOutCirc, InBack, OutBack, InOutBack, OutBounce, InBounce, InOutBounce, Linear; } public static EasingMode toEasingMode(String name) { String key = name == null ? "Linear" : name.trim(); if ("InQuad".equals(key)) { return EasingMode.InQuad; } else if ("OutQuad".equals(key)) { return EasingMode.OutQuad; } else if ("InOutQuad".equals(key)) { return EasingMode.InOutQuad; } else if ("InCubic".equals(key)) { return EasingMode.InCubic; } else if ("OutCubic".equals(key)) { return EasingMode.OutCubic; } else if ("InOutCubic".equals(key)) { return EasingMode.InOutCubic; } else if ("InQuart".equals(key)) { return EasingMode.InQuart; } else if ("OutQuart".equals(key)) { return EasingMode.OutQuart; } else if ("InOutQuart".equals(key)) { return EasingMode.InOutQuart; } else if ("InQuint".equals(key)) { return EasingMode.InQuint; } else if ("OutQuint".equals(key)) { return EasingMode.OutQuint; } else if ("InOutQuint".equals(key)) { return EasingMode.InOutQuint; } else if ("InSine".equals(key)) { return EasingMode.InSine; } else if ("OutSine".equals(key)) { return EasingMode.OutSine; } else if ("InOutSine".equals(key)) { return EasingMode.InOutSine; } else if ("InExp".equals(key)) { return EasingMode.InExp; } else if ("OutExp".equals(key)) { return EasingMode.OutExp; } else if ("InOutExp".equals(key)) { return EasingMode.InOutExp; } else if ("InCirc".equals(key)) { return EasingMode.InCirc; } else if ("OutCirc".equals(key)) { return EasingMode.OutCirc; } else if ("InOutCirc".equals(key)) { return EasingMode.InOutCirc; } else if ("InBack".equals(key)) { return EasingMode.InBack; } else if ("OutBack".equals(key)) { return EasingMode.OutBack; } else if ("InOutBack".equals(key)) { return EasingMode.InOutBack; } else if ("OutBounce".equals(key)) { return EasingMode.OutBounce; } else if ("InBounce".equals(key)) { return EasingMode.InBounce; } else if ("InOutBounce".equals(key)) { return EasingMode.InOutBounce; } else { return EasingMode.Linear; } } private static final int TYPE_IN = 0; private static final int TYPE_OUT = 1; private static final int TYPE_IN_OUT = 2; private static final int TYPE_TIME = 3; private static final int FUNCTION_LINEAR = 0; private static final int FUNCTION_QUADRADIC = 1; private static final int FUNCTION_IN = 2; private static final int FUNCTION_QUARTIC = 3; private static final int FUNCTION_QUINTIC = 4; private static final int FUNCTION_BACK = 5; private static final int FUNCTION_ELASTIC = 6; private static final int FUNCTION_NONE = 7; private static final int FUNCTION_OUT = 8; private static final int FUNCTION_INOUT = 9; private static final int FUNCTION_IN_BACK = 10; private static final int FUNCTION_OUT_BACK = 11; private static final int FUNCTION_BOUNCE_OUT = 12; private static final int FUNCTION_OUT_ELASTIC = 13; public static final Easing NONE = new Easing("NONE", TYPE_IN, FUNCTION_LINEAR); public static final Easing ELASTIC_INOUT = new Easing("ELASTIC_INOUT", TYPE_IN_OUT, FUNCTION_ELASTIC); public static final Easing QUAD_INOUT = new Easing("QUAD_INOUT", TYPE_IN_OUT, FUNCTION_LINEAR); public static final Easing REGULAR_IN = new Easing("REGULAR_IN", TYPE_IN, FUNCTION_QUADRADIC); public static final Easing REGULAR_OUT = new Easing("REGULAR_OUT", TYPE_OUT, FUNCTION_QUADRADIC); public static final Easing REGULAR_IN_OUT = new Easing("REGULAR_IN_OUT", TYPE_IN_OUT, FUNCTION_QUADRADIC); public static final Easing STRONG_IN = new Easing("STRONG_IN", TYPE_IN, FUNCTION_QUINTIC); public static final Easing STRONG_OUT = new Easing("STRONG_OUT", TYPE_OUT, FUNCTION_QUINTIC); public static final Easing STRONG_IN_OUT = new Easing("STRONG_IN_OUT", TYPE_IN_OUT, FUNCTION_QUINTIC); public static final Easing BACK_IN = new Easing("BACK_IN", TYPE_IN, FUNCTION_BACK); public static final Easing BACK_OUT = new Easing("BACK_OUT", TYPE_OUT, FUNCTION_BACK); public static final Easing CUBIC_IN = new Easing("CUBIC_IN", TYPE_IN, FUNCTION_IN); public static final Easing CUBIC_OUT = new Easing("CUBIC_OUT", TYPE_OUT, FUNCTION_OUT); public static final Easing CUBIC_INOUT = new Easing("CUBIC_INOUT", TYPE_OUT, FUNCTION_INOUT); public static final Easing BOUNCE_IN = new Easing("BOUNCE_IN", TYPE_OUT, FUNCTION_BOUNCE_OUT); public static final Easing BOUNCE_INOUT = new Easing("BOUNCE_INOUT", TYPE_IN_OUT, FUNCTION_BOUNCE_OUT); public static final Easing BACK_IN_OUT = new Easing("BACK_IN_OUT", TYPE_IN_OUT, FUNCTION_BACK); public static final Easing ELASTIC_IN = new Easing("ELASTIC_IN", TYPE_IN, FUNCTION_ELASTIC); public static final Easing ELASTIC_OUT = new Easing("ELASTIC_OUT", TYPE_OUT, FUNCTION_ELASTIC); public static final Easing ELASTIC_IN_OUT = new Easing("ELASTIC_IN_OUT", TYPE_IN_OUT, FUNCTION_ELASTIC); public static final Easing TIME_NONE = new Easing("TIME_NONE", TYPE_TIME, FUNCTION_NONE); public static final Easing TIME_LINEAR = new Easing("TIME_LINEAR", TYPE_TIME, FUNCTION_LINEAR); public static final Easing TIME_EASE_IN = new Easing("TIME_EASE_IN", TYPE_TIME, FUNCTION_IN); public static final Easing TIME_EASE_OUT = new Easing("TIME_EASE_OUT", TYPE_TIME, FUNCTION_OUT); public static final Easing TIME_EASE_INOUT = new Easing("TIME_EASE_INOUT", TYPE_TIME, FUNCTION_INOUT); public static final Easing TIME_EASE_IN_BACK = new Easing( "TIME_EASE_IN_BACK", TYPE_TIME, FUNCTION_IN_BACK); public static final Easing TIME_EASE_OUT_BACK = new Easing( "TIME_EASE_OUT_BACK", TYPE_TIME, FUNCTION_OUT_BACK); public static final Easing TIME_BOUNCE_OUT = new Easing("TIME_BOUNCE_OUT", TYPE_TIME, FUNCTION_BOUNCE_OUT); public static final Easing TIME_EASE_OUT_ELASTIC = new Easing( "TIME_EASE_OUT_ELASTIC", TYPE_TIME, FUNCTION_OUT_ELASTIC); private final int type; private final int function; private final float strength; private final String name; protected Easing() { this("NONE"); } protected Easing(String name) { this(name, TYPE_IN, FUNCTION_LINEAR); } protected Easing(String name, int type) { this(name, type, FUNCTION_LINEAR); } private Easing(String name, int type, int function) { this(name, type, function, 1); } private Easing(String name, int type, int function, float stength) { this.name = name; this.type = type; this.function = function; this.strength = stength; } public Easing(Easing easing, float strength) { this(easing.name, easing.type, easing.function, strength); } public final float apply(float time, float duration) { return apply(time, duration, true); } public final float apply(float time, float duration, boolean mul) { if (TYPE_TIME == type) { return call(function, duration / time); } if (time <= 0 || duration <= 0) { return 0; } else if (time >= duration) { return duration; } final float t = time / duration; float easedT; switch (type) { default: easedT = t; break; case TYPE_IN: easedT = call(function, t); break; case TYPE_OUT: easedT = 1 - call(function, 1 - t); break; case TYPE_IN_OUT: if (t < 0.5) { easedT = call(function, 2 * t) / 2; } else { easedT = 1 - call(function, 2 - 2 * t) / 2; } break; } if (strength != 1) { easedT = strength * easedT + (1 - strength) * t; } if (mul) { return (easedT * duration); } return easedT; } public float applyClamp(float time, float duration) { return apply((time < 0) ? 0 : (time > 1 ? 1 : time), duration); } public float apply(float start, float range, float time, float duration) { float pos = (duration == 0) ? 1 : apply(time, duration); return start + range * pos; } public float applyClamp(float start, float range, float time, float duration) { return apply(start, range, duration, MathUtils.clamp(time, 0, duration)); } protected static float call(int fun, float t) { float t2; float t3; switch (fun) { default: case FUNCTION_LINEAR: return t; case FUNCTION_QUADRADIC: return t * t; case FUNCTION_IN: return t * t * t; case FUNCTION_QUARTIC: t2 = t * t; return t2 * t2; case FUNCTION_QUINTIC: t2 = t * t; return t2 * t2 * t; case FUNCTION_BACK: t2 = t * t; t3 = t2 * t; return t3 + t2 - t; case FUNCTION_ELASTIC: t2 = t * t; t3 = t2 * t; float scale = t2 * (2 * t3 + t2 - 4 * t + 2); float wave = -MathUtils.sin(t * 3.5f * MathUtils.PI); return scale * wave; case FUNCTION_NONE: return 0; case FUNCTION_OUT: t2 = t - 1; return (1 + t2 * t2 * t2); case FUNCTION_INOUT: t2 = 2 * t; if (t2 < 1) { return (t2 * t2 * t2) / 2; } t3 = t2 - 2; return (2 + t3 * t3 * t3) / 2; case FUNCTION_IN_BACK: t2 = 1.70158f; return t * t * ((t2 + 1) * t - t2); case FUNCTION_OUT_BACK: t2 = 1.70158f; t3 = t - 1; return (t3 * t3 * ((t2 + 1) * t3 + t2) + 1); case FUNCTION_BOUNCE_OUT: if (t < (1 / 2.75f)) { return 7.5625f * t * t; } else if (t < (2 / 2.75f)) { t2 = t - (1.5f / 2.75f); return 7.5625f * t2 * t2 + 0.75f; } else if (t < (2.5 / 2.75)) { t2 = t - (2.25f / 2.75f); return 7.5625f * t2 * t2 + 0.9375f; } else { t2 = t - (2.625f / 2.75f); return 7.5625f * t2 * t2 + 0.984375f; } case FUNCTION_OUT_ELASTIC: t2 = 0.3f / 4; t3 = (float) (2 * MathUtils.PI / 0.3); return MathUtils.pow(2, -10 * t) * MathUtils.sin((t - t2) * t3) + 1; } } public static float inQuad(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; return max * t * t + min; } public static float outQuad(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; return -max * t * (t - 2.0f) + min; } public static float inOutQuad(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; if (t / 2.0f < 1.0f) { return max / 2.0f * t * t + min; } t -= 1.0f; return -max * (t * (t - 2.0f) - 1.0f) + min; } public static float inCubic(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; return max * t * t * t + min; } public static float outCubic(float t, float totaltime, float max, float min) { max -= min; t = t / totaltime - 1.0f; return max * (t * t * t + 1.0f) + min; } public static float inOutCubic(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; if (t / 2.0f < 1.0f) { return max / 2.0f * t * t * t + min; } t -= 2.0f; return max / 2.0f * (t * t * t + 2.0f) + min; } public static float inQuart(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; return max * t * t * t * t + min; } public static float outQuart(float t, float totaltime, float max, float min) { max -= min; t = t / totaltime - 1.0f; return -max * (t * t * t * t - 1.0f) + min; } public static float inOutQuart(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; if (t / 2.0f < 1.0f) { return max / 2.0f * t * t * t * t + min; } t -= 2.0f; return -max / 2.0f * (t * t * t * t - 2.0f) + min; } public static float inQuint(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; return max * t * t * t * t * t + min; } public static float outQuint(float t, float totaltime, float max, float min) { max -= min; t = t / totaltime - 1.0f; return max * (t * t * t * t * t + 1.0f) + min; } public static float inOutQuint(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; if (t / 2.0f < 1.0f) { return max / 2.0f * t * t * t * t * t + min; } t -= 2.0f; return max / 2.0f * (t * t * t * t * t + 2.0f) + min; } public static float inSine(float t, float totaltime, float max, float min) { max -= min; return -max * MathUtils.cos(t * 1.570796326794897f / totaltime) + max + min; } public static float outSine(float t, float totaltime, float max, float min) { max -= min; return max * MathUtils.sin(t * 1.570796326794897f / totaltime) + min; } public static float inOutSine(float t, float totaltime, float max, float min) { max -= min; return -max / 2.0f * (MathUtils.cos(t * 3.141592653589793f / totaltime) - 1.0f) + min; } public static float inExp(float t, float totaltime, float max, float min) { max -= min; return t == 0.0f ? min : max * MathUtils.pow(2.0f, 10.0f * (t / totaltime - 1.0f)) + min; } public static float outExp(float t, float totaltime, float max, float min) { max -= min; return t == totaltime ? max + min : max * (-MathUtils.pow(2.0f, -10.0f * t / totaltime) + 1.0f) + min; } public static float inOutExp(float t, float totaltime, float max, float min) { if (t == 0f) { return min; } if (t == totaltime) { return max; } max -= min; t /= totaltime; if (t / 2.0f < 1.0f) { return max / 2.0f * MathUtils.pow(2.0f, 10.0f * (t - 1.0f)) + min; } t -= 1.0f; return max / 2.0f * (-MathUtils.pow(2.0f, -10.0f * t) + 2.0f) + min; } public static float inCirc(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; return -max * (MathUtils.sqrt(1.0f - t * t) - 1.0f) + min; } public static float outCirc(float t, float totaltime, float max, float min) { max -= min; t = t / totaltime - 1.0f; return max * MathUtils.sqrt(1.0f - t * t) + min; } public static float inOutCirc(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; if (t / 2.0f < 1.0f) { return -max / 2.0f * (MathUtils.sqrt(1.0f - t * t) - 1.0f) + min; } t -= 2.0f; return max / 2.0f * (MathUtils.sqrt(1.0f - t * t) + 1.0f) + min; } public static float inBack(float t, float totaltime, float max, float min, float s) { max -= min; t /= totaltime; return max * t * t * ((s + 1.0f) * t - s) + min; } public static float outBack(float t, float totaltime, float max, float min, float s) { max -= min; t = t / totaltime - 1.0f; return max * (t * t * ((s + 1.0f) * t * s) + 1.0f) + min; } public static float inOutBack(float t, float totaltime, float max, float min, float s) { max -= min; s *= 1.525f; if (t / 2.0f < 1.0f) { return max * (t * t * ((s + 1.0f) * t - s)) + min; } t -= 2.0f; return max / 2.0f * (t * t * ((s + 1.0f) * t + s) + 2.0f) + min; } public static float outBounce(float t, float totaltime, float max, float min) { max -= min; t /= totaltime; if (t < 0.3636363636363637f) { return max * (7.5625f * t * t) + min; } if (t < 0.7272727272727273f) { t -= 0.5454545454545454f; return max * (7.5625f * t * t + 0.75f) + min; } if (t < 0.9090909090909091f) { t -= 0.8181818181818182f; return max * (7.5625f * t * t + 0.9375f) + min; } t -= 0.9545454545454546f; return max * (7.5625f * t * t + 0.984375f) + min; } public static float inBounce(float t, float totaltime, float max, float min) { return max - outBounce(totaltime - t, totaltime, max - min, 0.0f) + min; } public static float inOutBounce(float t, float totaltime, float max, float min) { if (t < totaltime / 2.0f) { return inBounce(t * 2.0f, totaltime, max - min, max) * 0.5f + min; } return outBounce(t * 2.0f - totaltime, totaltime, max - min, 0.0f) * 0.5f + min + (max - min) * 0.5f; } public static float linear(float t, float totaltime, float max, float min) { return (max - min) * t / totaltime + min; } }