Home | History | Annotate | Download | only in math
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.math;
     18 
     19 /** Takes a linear value in the range of 0-1 and outputs a (usually) non-linear, interpolated value.
     20  * @author Nathan Sweet */
     21 public abstract class Interpolation {
     22 	/** @param a Alpha value between 0 and 1. */
     23 	abstract public float apply (float a);
     24 
     25 	/** @param a Alpha value between 0 and 1. */
     26 	public float apply (float start, float end, float a) {
     27 		return start + (end - start) * apply(a);
     28 	}
     29 
     30 	//
     31 
     32 	static public final Interpolation linear = new Interpolation() {
     33 		public float apply (float a) {
     34 			return a;
     35 		}
     36 	};
     37 
     38 	static public final Interpolation fade = new Interpolation() {
     39 		public float apply (float a) {
     40 			return MathUtils.clamp(a * a * a * (a * (a * 6 - 15) + 10), 0, 1);
     41 		}
     42 	};
     43 
     44 	static public final Pow pow2 = new Pow(2);
     45 	/** Slow, then fast. */
     46 	static public final PowIn pow2In = new PowIn(2);
     47 	/** Fast, then slow. */
     48 	static public final PowOut pow2Out = new PowOut(2);
     49 
     50 	static public final Pow pow3 = new Pow(3);
     51 	static public final PowIn pow3In = new PowIn(3);
     52 	static public final PowOut pow3Out = new PowOut(3);
     53 
     54 	static public final Pow pow4 = new Pow(4);
     55 	static public final PowIn pow4In = new PowIn(4);
     56 	static public final PowOut pow4Out = new PowOut(4);
     57 
     58 	static public final Pow pow5 = new Pow(5);
     59 	static public final PowIn pow5In = new PowIn(5);
     60 	static public final PowOut pow5Out = new PowOut(5);
     61 
     62 	static public final Interpolation sine = new Interpolation() {
     63 		public float apply (float a) {
     64 			return (1 - MathUtils.cos(a * MathUtils.PI)) / 2;
     65 		}
     66 	};
     67 
     68 	static public final Interpolation sineIn = new Interpolation() {
     69 		public float apply (float a) {
     70 			return 1 - MathUtils.cos(a * MathUtils.PI / 2);
     71 		}
     72 	};
     73 
     74 	static public final Interpolation sineOut = new Interpolation() {
     75 		public float apply (float a) {
     76 			return MathUtils.sin(a * MathUtils.PI / 2);
     77 		}
     78 	};
     79 
     80 	static public final Exp exp10 = new Exp(2, 10);
     81 	static public final ExpIn exp10In = new ExpIn(2, 10);
     82 	static public final ExpOut exp10Out = new ExpOut(2, 10);
     83 
     84 	static public final Exp exp5 = new Exp(2, 5);
     85 	static public final ExpIn exp5In = new ExpIn(2, 5);
     86 	static public final ExpOut exp5Out = new ExpOut(2, 5);
     87 
     88 	static public final Interpolation circle = new Interpolation() {
     89 		public float apply (float a) {
     90 			if (a <= 0.5f) {
     91 				a *= 2;
     92 				return (1 - (float)Math.sqrt(1 - a * a)) / 2;
     93 			}
     94 			a--;
     95 			a *= 2;
     96 			return ((float)Math.sqrt(1 - a * a) + 1) / 2;
     97 		}
     98 	};
     99 
    100 	static public final Interpolation circleIn = new Interpolation() {
    101 		public float apply (float a) {
    102 			return 1 - (float)Math.sqrt(1 - a * a);
    103 		}
    104 	};
    105 
    106 	static public final Interpolation circleOut = new Interpolation() {
    107 		public float apply (float a) {
    108 			a--;
    109 			return (float)Math.sqrt(1 - a * a);
    110 		}
    111 	};
    112 
    113 	static public final Elastic elastic = new Elastic(2, 10, 7, 1);
    114 	static public final ElasticIn elasticIn = new ElasticIn(2, 10, 6, 1);
    115 	static public final ElasticOut elasticOut = new ElasticOut(2, 10, 7, 1);
    116 
    117 	static public final Swing swing = new Swing(1.5f);
    118 	static public final SwingIn swingIn = new SwingIn(2f);
    119 	static public final SwingOut swingOut = new SwingOut(2f);
    120 
    121 	static public final Bounce bounce = new Bounce(4);
    122 	static public final BounceIn bounceIn = new BounceIn(4);
    123 	static public final BounceOut bounceOut = new BounceOut(4);
    124 
    125 	//
    126 
    127 	static public class Pow extends Interpolation {
    128 		final int power;
    129 
    130 		public Pow (int power) {
    131 			this.power = power;
    132 		}
    133 
    134 		public float apply (float a) {
    135 			if (a <= 0.5f) return (float)Math.pow(a * 2, power) / 2;
    136 			return (float)Math.pow((a - 1) * 2, power) / (power % 2 == 0 ? -2 : 2) + 1;
    137 		}
    138 	}
    139 
    140 	static public class PowIn extends Pow {
    141 		public PowIn (int power) {
    142 			super(power);
    143 		}
    144 
    145 		public float apply (float a) {
    146 			return (float)Math.pow(a, power);
    147 		}
    148 	}
    149 
    150 	static public class PowOut extends Pow {
    151 		public PowOut (int power) {
    152 			super(power);
    153 		}
    154 
    155 		public float apply (float a) {
    156 			return (float)Math.pow(a - 1, power) * (power % 2 == 0 ? -1 : 1) + 1;
    157 		}
    158 	}
    159 
    160 	//
    161 
    162 	static public class Exp extends Interpolation {
    163 		final float value, power, min, scale;
    164 
    165 		public Exp (float value, float power) {
    166 			this.value = value;
    167 			this.power = power;
    168 			min = (float)Math.pow(value, -power);
    169 			scale = 1 / (1 - min);
    170 		}
    171 
    172 		public float apply (float a) {
    173 			if (a <= 0.5f) return ((float)Math.pow(value, power * (a * 2 - 1)) - min) * scale / 2;
    174 			return (2 - ((float)Math.pow(value, -power * (a * 2 - 1)) - min) * scale) / 2;
    175 		}
    176 	};
    177 
    178 	static public class ExpIn extends Exp {
    179 		public ExpIn (float value, float power) {
    180 			super(value, power);
    181 		}
    182 
    183 		public float apply (float a) {
    184 			return ((float)Math.pow(value, power * (a - 1)) - min) * scale;
    185 		}
    186 	}
    187 
    188 	static public class ExpOut extends Exp {
    189 		public ExpOut (float value, float power) {
    190 			super(value, power);
    191 		}
    192 
    193 		public float apply (float a) {
    194 			return 1 - ((float)Math.pow(value, -power * a) - min) * scale;
    195 		}
    196 	}
    197 
    198 	//
    199 
    200 	static public class Elastic extends Interpolation {
    201 		final float value, power, scale, bounces;
    202 
    203 		public Elastic (float value, float power, int bounces, float scale) {
    204 			this.value = value;
    205 			this.power = power;
    206 			this.scale = scale;
    207 			this.bounces = bounces * MathUtils.PI * (bounces % 2 == 0 ? 1 : -1);
    208 		}
    209 
    210 		public float apply (float a) {
    211 			if (a <= 0.5f) {
    212 				a *= 2;
    213 				return (float)Math.pow(value, power * (a - 1)) * MathUtils.sin(a * bounces) * scale / 2;
    214 			}
    215 			a = 1 - a;
    216 			a *= 2;
    217 			return 1 - (float)Math.pow(value, power * (a - 1)) * MathUtils.sin((a) * bounces) * scale / 2;
    218 		}
    219 	}
    220 
    221 	static public class ElasticIn extends Elastic {
    222 		public ElasticIn (float value, float power, int bounces, float scale) {
    223 			super(value, power, bounces, scale);
    224 		}
    225 
    226 		public float apply (float a) {
    227 			if (a >= 0.99) return 1;
    228 			return (float)Math.pow(value, power * (a - 1)) * MathUtils.sin(a * bounces) * scale;
    229 		}
    230 	}
    231 
    232 	static public class ElasticOut extends Elastic {
    233 		public ElasticOut (float value, float power, int bounces, float scale) {
    234 			super(value, power, bounces, scale);
    235 		}
    236 
    237 		public float apply (float a) {
    238 			a = 1 - a;
    239 			return (1 - (float)Math.pow(value, power * (a - 1)) * MathUtils.sin(a * bounces) * scale);
    240 		}
    241 	}
    242 
    243 	//
    244 
    245 	static public class Bounce extends BounceOut {
    246 		public Bounce (float[] widths, float[] heights) {
    247 			super(widths, heights);
    248 		}
    249 
    250 		public Bounce (int bounces) {
    251 			super(bounces);
    252 		}
    253 
    254 		private float out (float a) {
    255 			float test = a + widths[0] / 2;
    256 			if (test < widths[0]) return test / (widths[0] / 2) - 1;
    257 			return super.apply(a);
    258 		}
    259 
    260 		public float apply (float a) {
    261 			if (a <= 0.5f) return (1 - out(1 - a * 2)) / 2;
    262 			return out(a * 2 - 1) / 2 + 0.5f;
    263 		}
    264 	}
    265 
    266 	static public class BounceOut extends Interpolation {
    267 		final float[] widths, heights;
    268 
    269 		public BounceOut (float[] widths, float[] heights) {
    270 			if (widths.length != heights.length)
    271 				throw new IllegalArgumentException("Must be the same number of widths and heights.");
    272 			this.widths = widths;
    273 			this.heights = heights;
    274 		}
    275 
    276 		public BounceOut (int bounces) {
    277 			if (bounces < 2 || bounces > 5) throw new IllegalArgumentException("bounces cannot be < 2 or > 5: " + bounces);
    278 			widths = new float[bounces];
    279 			heights = new float[bounces];
    280 			heights[0] = 1;
    281 			switch (bounces) {
    282 			case 2:
    283 				widths[0] = 0.6f;
    284 				widths[1] = 0.4f;
    285 				heights[1] = 0.33f;
    286 				break;
    287 			case 3:
    288 				widths[0] = 0.4f;
    289 				widths[1] = 0.4f;
    290 				widths[2] = 0.2f;
    291 				heights[1] = 0.33f;
    292 				heights[2] = 0.1f;
    293 				break;
    294 			case 4:
    295 				widths[0] = 0.34f;
    296 				widths[1] = 0.34f;
    297 				widths[2] = 0.2f;
    298 				widths[3] = 0.15f;
    299 				heights[1] = 0.26f;
    300 				heights[2] = 0.11f;
    301 				heights[3] = 0.03f;
    302 				break;
    303 			case 5:
    304 				widths[0] = 0.3f;
    305 				widths[1] = 0.3f;
    306 				widths[2] = 0.2f;
    307 				widths[3] = 0.1f;
    308 				widths[4] = 0.1f;
    309 				heights[1] = 0.45f;
    310 				heights[2] = 0.3f;
    311 				heights[3] = 0.15f;
    312 				heights[4] = 0.06f;
    313 				break;
    314 			}
    315 			widths[0] *= 2;
    316 		}
    317 
    318 		public float apply (float a) {
    319 			a += widths[0] / 2;
    320 			float width = 0, height = 0;
    321 			for (int i = 0, n = widths.length; i < n; i++) {
    322 				width = widths[i];
    323 				if (a <= width) {
    324 					height = heights[i];
    325 					break;
    326 				}
    327 				a -= width;
    328 			}
    329 			a /= width;
    330 			float z = 4 / width * height * a;
    331 			return 1 - (z - z * a) * width;
    332 		}
    333 	}
    334 
    335 	static public class BounceIn extends BounceOut {
    336 		public BounceIn (float[] widths, float[] heights) {
    337 			super(widths, heights);
    338 		}
    339 
    340 		public BounceIn (int bounces) {
    341 			super(bounces);
    342 		}
    343 
    344 		public float apply (float a) {
    345 			return 1 - super.apply(1 - a);
    346 		}
    347 	}
    348 
    349 	//
    350 
    351 	static public class Swing extends Interpolation {
    352 		private final float scale;
    353 
    354 		public Swing (float scale) {
    355 			this.scale = scale * 2;
    356 		}
    357 
    358 		public float apply (float a) {
    359 			if (a <= 0.5f) {
    360 				a *= 2;
    361 				return a * a * ((scale + 1) * a - scale) / 2;
    362 			}
    363 			a--;
    364 			a *= 2;
    365 			return a * a * ((scale + 1) * a + scale) / 2 + 1;
    366 		}
    367 	}
    368 
    369 	static public class SwingOut extends Interpolation {
    370 		private final float scale;
    371 
    372 		public SwingOut (float scale) {
    373 			this.scale = scale;
    374 		}
    375 
    376 		public float apply (float a) {
    377 			a--;
    378 			return a * a * ((scale + 1) * a + scale) + 1;
    379 		}
    380 	}
    381 
    382 	static public class SwingIn extends Interpolation {
    383 		private final float scale;
    384 
    385 		public SwingIn (float scale) {
    386 			this.scale = scale;
    387 		}
    388 
    389 		public float apply (float a) {
    390 			return a * a * ((scale + 1) * a - scale);
    391 		}
    392 	}
    393 }
    394