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. */ apply(float a)23 abstract public float apply (float a); 24 25 /** @param a Alpha value between 0 and 1. */ apply(float start, float end, float a)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 Pow(int power)130 public Pow (int power) { 131 this.power = power; 132 } 133 apply(float a)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 { PowIn(int power)141 public PowIn (int power) { 142 super(power); 143 } 144 apply(float a)145 public float apply (float a) { 146 return (float)Math.pow(a, power); 147 } 148 } 149 150 static public class PowOut extends Pow { PowOut(int power)151 public PowOut (int power) { 152 super(power); 153 } 154 apply(float a)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 Exp(float value, float power)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 apply(float a)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 { ExpIn(float value, float power)179 public ExpIn (float value, float power) { 180 super(value, power); 181 } 182 apply(float a)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 { ExpOut(float value, float power)189 public ExpOut (float value, float power) { 190 super(value, power); 191 } 192 apply(float a)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 Elastic(float value, float power, int bounces, float scale)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 apply(float a)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 { ElasticIn(float value, float power, int bounces, float scale)222 public ElasticIn (float value, float power, int bounces, float scale) { 223 super(value, power, bounces, scale); 224 } 225 apply(float a)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 { ElasticOut(float value, float power, int bounces, float scale)233 public ElasticOut (float value, float power, int bounces, float scale) { 234 super(value, power, bounces, scale); 235 } 236 apply(float a)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 { Bounce(float[] widths, float[] heights)246 public Bounce (float[] widths, float[] heights) { 247 super(widths, heights); 248 } 249 Bounce(int bounces)250 public Bounce (int bounces) { 251 super(bounces); 252 } 253 out(float a)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 apply(float a)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 BounceOut(float[] widths, float[] heights)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 BounceOut(int bounces)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 apply(float a)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 { BounceIn(float[] widths, float[] heights)336 public BounceIn (float[] widths, float[] heights) { 337 super(widths, heights); 338 } 339 BounceIn(int bounces)340 public BounceIn (int bounces) { 341 super(bounces); 342 } 343 apply(float a)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 Swing(float scale)354 public Swing (float scale) { 355 this.scale = scale * 2; 356 } 357 apply(float a)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 SwingOut(float scale)372 public SwingOut (float scale) { 373 this.scale = scale; 374 } 375 apply(float a)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 SwingIn(float scale)385 public SwingIn (float scale) { 386 this.scale = scale; 387 } 388 apply(float a)389 public float apply (float a) { 390 return a * a * ((scale + 1) * a - scale); 391 } 392 } 393 } 394