/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.client.graphics; import illarion.common.util.FastMath; import org.illarion.engine.graphic.Color; import javax.annotation.Nonnull; /** * This is a utility class that provides a few static functions that are handy * when handling animations. * * @author Martin Karing <nitram@illarion.org> */ public final class AnimationUtility { /** * The time the delta time is divided by. This result of the division is * multiplied with the difference of the values in order to slow the * animation down or speed it up based on the time since the last render * action. */ public static final int DELTA_DIV = 50; /** * The default value for the factor of the approaching functions. * * @see #approach(int, int, int, int, int) */ private static final int DEFAULT_APPROACH = 4; /** * The minimal difference value that is allowed for the the float * translation. * * @see #translate(float, float, float, int) * @see #translate(float, float, float, float, float, int) */ private static final float MIN_FLOAT_DIFF = 0.01f; /** * The minimal value of the difference that is still not compensated by the * delta time value at the approach and the translate functions. If the * difference between the value and the target value is larger the delta * value is used to reduce or increase the approaching speed. * * @see #approach(int, int, int, int, int) * @see #approach(int, int, int, int, int, int) * @see #translateAlpha(int, int, int, int) * @see #translate(int, int, int, int, int, int) * @see #translate(float, float, float, int) * @see #translate(float, float, float, float, float, int) */ private static final int MIN_INT_DIFF = 3; /** * Private constructor so no instance of this object is created. */ private AnimationUtility() { // nothing to do } /** * Approach two color values smoothly. * * @param workingColor the color that is changed * @param targetColor the target color value * @param delta the time since the last update * @return {@code true} in case the colors got changed */ public static boolean approach( @Nonnull Color workingColor, @Nonnull Color targetColor, int delta) { if (workingColor.equals(targetColor)) { return false; } workingColor.setRed(approach(workingColor.getRed(), targetColor.getRed(), 0, Color.MAX_INT_VALUE, delta)); workingColor.setGreen(approach(workingColor.getGreen(), targetColor.getGreen(), 0, Color.MAX_INT_VALUE, delta)); workingColor.setBlue(approach(workingColor.getBlue(), targetColor.getBlue(), 0, Color.MAX_INT_VALUE, delta)); workingColor.setAlpha(approach(workingColor.getAlpha(), targetColor.getAlpha(), 0, Color.MAX_INT_VALUE, delta)); return true; } /** * Let a value quickly approach a target value. This function ensures that * the value stays within the limits. * * @param value the current value that shall approach the target value * @param target the target of the approaching operation * @param min the lower border of the approaching operation, the returned * value won't be smaller then this value * @param max the upper border of the approaching operation, the returned * value won't be larger then this value * @param delta the delta time in milliseconds since the last update of the * value. This value is used to compensate the approaching speed * regarding different update speeds. In case this value is 0 the * value will change by the smallest value possible * @return the new value and so the next step of the approaching operation. * Call the function again and again with the new value until is * reaches the target value to get the full approach calculation */ public static int approach(int value, int target, int min, int max, int delta) { return approach(value, target, DEFAULT_APPROACH, min, max, delta); } /** * Let a value quickly approach a target value. This function ensures that * the value stays within the limits. * * @param value the current value that shall approach the target value * @param target the target of the approaching operation * @param factor the factor the difference between the target and the * current value is divided by. To slow down the approaching * speed, make this value larger. This value must not be 0 or * smaller * @param min the lower border of the approaching operation, the returned * value won't be smaller then this value * @param max the upper border of the approaching operation, the returned * value won't be larger then this value * @param delta the delta time in milliseconds since the last update of the * value. This value is used to compensate the approaching speed * regarding different update speeds. In case this value is 0 the * value will change by the smallest value possible * @return the new value and so the next step of the approaching operation. * Call the function again and again with the new value until is * reaches the target value to get the full approach calculation */ public static int approach( int value, int target, int factor, int min, int max, int delta) { int diff = target - value; if (diff == 0) { return value; } int dir = FastMath.sign(diff); int absDiff = FastMath.abs(diff) / factor; if (absDiff > MIN_INT_DIFF) { absDiff = FastMath.clamp((absDiff * delta) / DELTA_DIV, 1, FastMath.abs(diff)); } else { absDiff = FastMath.clamp(absDiff, 1, MIN_INT_DIFF); } int newValue = value + (absDiff * dir); return FastMath.clamp(newValue, min, max); } /** * Translate a float value linear towards a target value. * * @param value the current value that shall be translated * @param target the target value the current value shall be translated * towards * @param step the minimal step of the translation, so the maximal value the * value is changed by at one step * @param min the bottom border of the value, the value won't be smaller * then this value * @param max the top border of the value, the value won't be larger then * this value * @param delta the time in milliseconds since the last call of this * function. This value is used to compensate the change of the * value to ensure that the translation looks the same no matter * of the update speed * @return the new value that is one step closer to the translation target */ public static float translate( float value, float target, float step, float min, float max, int delta) { float diff = target - value; if (diff != 0) { int dir = (int) (diff / FastMath.abs(diff)); diff = FastMath.abs(diff); if (diff <= step) { return target; } diff = step; if (diff > MIN_FLOAT_DIFF) { diff = (diff * delta) / DELTA_DIV; if (diff < MIN_FLOAT_DIFF) { diff = MIN_FLOAT_DIFF; } } float newValue = value + (diff * dir); // clamp value against limits if (newValue > max) { return max; } else if (newValue < min) { return min; } else { return newValue; } } return value; } /** * Translate a float value linear between 0 and 1. The result value will be * always between 0 and 1. * * @param value the current value that shall be translated * @param target the target value the current value shall be translated * towards * @param step the minimal step of the translation, so the maximal value the * value is changed by at one step * @param delta the time in milliseconds since the last call of this * function. This value is used to compensate the change of the * value to ensure that the translation looks the same no matter * of the update speed * @return the new value that is one step closer to the translation target */ public static float translate(float value, float target, float step, int delta) { return translate(value, target, step, 0, 1, delta); } /** * Translate a value linear towards a target value. This function ensures * also that the value stays within the border values. * * @param value the current value that shall be translated towards the * target value * @param target the target of the translation * @param step the step value that says by how many points the current value * shall change each step * @param min the bottom border of the value. The value won't be lower then * this border value * @param max the upper border of the value. The value won't be larger then * this border value * @param delta the time in milliseconds since the last call of this * function. This value is used to compensate the change of the * value to ensure that the translation looks the same no matter * of the update speed * @return the new value that is one step closer to the translation target */ public static int translate( int value, int target, int step, int min, int max, int delta) { int diff = target - value; if (diff != 0) { int dir = FastMath.sign(diff); diff = FastMath.abs(diff); if (diff < step) { return target; } diff = step; if (diff > MIN_INT_DIFF) { diff = (diff * delta) / DELTA_DIV; if (diff == 0) { diff = 1; } } int newValue = value + (diff * dir); // clamp value against limits if ((dir == 1) && (newValue > target)) { return target; } else if ((dir == -1) && (newValue < target)) { return target; } else if (newValue > max) { return max; } else if (newValue < min) { return min; } else { return newValue; } } return value; } /** * Translate a value linear optimized for alpha values and colors. The * borders of this animation are the minimal and maximal integer values for * colors set by sprite color. * * @param value the current value that shall be translated towards the * target value * @param target the target of the translation * @param step the step value that says by how many points the current value * shall change each step * @param delta the time in milliseconds since the last call of this * function. This value is used to compensate the change of the * value to ensure that the translation looks the same no matter * of the update speed * @return the new value that is one step closer to the translation target */ public static int translateAlpha(int value, int target, int step, int delta) { return translate(value, target, step, 0, 255, delta); } }