1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.scenario.animation.shared; 27 28 import com.sun.javafx.animation.KeyValueHelper; 29 import javafx.animation.Interpolator; 30 import javafx.animation.KeyValue; 31 import javafx.beans.value.WritableBooleanValue; 32 import javafx.beans.value.WritableDoubleValue; 33 import javafx.beans.value.WritableFloatValue; 34 import javafx.beans.value.WritableIntegerValue; 35 import javafx.beans.value.WritableLongValue; 36 import javafx.beans.value.WritableValue; 37 38 import com.sun.scenario.animation.NumberTangentInterpolator; 39 40 public abstract class InterpolationInterval { 41 42 protected final long ticks; 43 protected final Interpolator rightInterpolator; 44 45 protected InterpolationInterval(long ticks, 46 Interpolator rightInterpolator) { 47 this.ticks = ticks; 48 this.rightInterpolator = rightInterpolator; 49 } 50 51 public abstract void interpolate(double frac); 52 53 public abstract void recalculateStartValue(); 54 55 public static InterpolationInterval create(KeyValue rightKeyValue, 56 long ticks, KeyValue leftKeyValue, long duration) { 57 switch (KeyValueHelper.getType(rightKeyValue)) { 58 case BOOLEAN: 59 return new BooleanInterpolationInterval(rightKeyValue, ticks, 60 leftKeyValue.getEndValue()); 61 case DOUBLE: 62 return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue 63 .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentDoubleInterpolationInterval( 64 rightKeyValue, ticks, leftKeyValue, duration) 65 : new DoubleInterpolationInterval(rightKeyValue, 66 ticks, leftKeyValue.getEndValue()); 67 case FLOAT: 68 return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue 69 .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentFloatInterpolationInterval( 70 rightKeyValue, ticks, leftKeyValue, duration) 71 : new FloatInterpolationInterval(rightKeyValue, ticks, 72 leftKeyValue.getEndValue()); 73 case INTEGER: 74 return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue 75 .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentIntegerInterpolationInterval( 76 rightKeyValue, ticks, leftKeyValue, duration) 77 : new IntegerInterpolationInterval(rightKeyValue, 78 ticks, leftKeyValue.getEndValue()); 79 case LONG: 80 return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue 81 .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentLongInterpolationInterval( 82 rightKeyValue, ticks, leftKeyValue, duration) 83 : new LongInterpolationInterval(rightKeyValue, ticks, 84 leftKeyValue.getEndValue()); 85 case OBJECT: 86 return new ObjectInterpolationInterval(rightKeyValue, ticks, 87 leftKeyValue.getEndValue()); 88 } 89 throw new RuntimeException("Should not reach here"); 90 } 91 92 public static InterpolationInterval create(KeyValue rightKeyValue, 93 long ticks) { 94 switch (KeyValueHelper.getType(rightKeyValue)) { 95 case BOOLEAN: 96 return new BooleanInterpolationInterval(rightKeyValue, ticks); 97 case DOUBLE: 98 return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentDoubleInterpolationInterval( 99 rightKeyValue, ticks) 100 : new DoubleInterpolationInterval(rightKeyValue, ticks); 101 case FLOAT: 102 return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentFloatInterpolationInterval( 103 rightKeyValue, ticks) 104 : new FloatInterpolationInterval(rightKeyValue, ticks); 105 case INTEGER: 106 return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentIntegerInterpolationInterval( 107 rightKeyValue, ticks) 108 : new IntegerInterpolationInterval(rightKeyValue, 109 ticks); 110 case LONG: 111 return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentLongInterpolationInterval( 112 rightKeyValue, ticks) : new LongInterpolationInterval( 113 rightKeyValue, ticks); 114 case OBJECT: 115 return new ObjectInterpolationInterval(rightKeyValue, ticks); 116 } 117 throw new RuntimeException("Should not reach here"); 118 } 119 120 private static abstract class TangentInterpolationInterval extends 121 InterpolationInterval { 122 123 private final double duration; 124 private final double p2; 125 protected final double p3; 126 private final NumberTangentInterpolator leftInterpolator; 127 128 protected double p0; 129 private double p1; 130 131 private TangentInterpolationInterval(KeyValue rightKeyValue, 132 long ticks, KeyValue leftKeyValue, long duration) { 133 super(ticks, rightKeyValue.getInterpolator()); 134 assert (rightKeyValue.getEndValue() instanceof Number) 135 && (leftKeyValue.getEndValue() instanceof Number); 136 137 this.duration = duration; 138 final Interpolator rawLeftInterpolator = leftKeyValue 139 .getInterpolator(); 140 leftInterpolator = (rawLeftInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rawLeftInterpolator 141 : null; 142 recalculateStartValue(((Number) leftKeyValue.getEndValue()) 143 .doubleValue()); 144 145 final NumberTangentInterpolator interpolator = (rightInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rightInterpolator 146 : null; 147 p3 = ((Number) rightKeyValue.getEndValue()).doubleValue(); 148 final double p2Delta = (interpolator == null) ? 0 : (interpolator 149 .getInValue() - p3) 150 * duration 151 / interpolator.getInTicks() 152 / 3; 153 p2 = p3 + p2Delta; 154 } 155 156 private TangentInterpolationInterval(KeyValue rightKeyValue, 157 long ticks) { 158 super(ticks, rightKeyValue.getInterpolator()); 159 assert rightKeyValue.getEndValue() instanceof Number; 160 161 this.duration = ticks; 162 leftInterpolator = null; 163 164 final NumberTangentInterpolator interpolator = (rightInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rightInterpolator 165 : null; 166 p3 = ((Number) rightKeyValue.getEndValue()).doubleValue(); 167 final double p2Delta = (interpolator == null) ? 0 : (interpolator 168 .getInValue() - p3) 169 * duration 170 / interpolator.getInTicks() 171 / 3; 172 p2 = p3 + p2Delta; 173 } 174 175 protected double calculate(double t) { 176 final double oneMinusT = 1.0 - t; 177 final double tSquared = t * t; 178 final double oneMinusTSquared = oneMinusT * oneMinusT; 179 180 return oneMinusTSquared * oneMinusT * p0 + 3 * oneMinusTSquared * t 181 * p1 + 3 * oneMinusT * tSquared * p2 + tSquared * t * p3; 182 } 183 184 protected final void recalculateStartValue(double leftValue) { 185 p0 = leftValue; 186 final double p1Delta = (leftInterpolator == null) ? 0 187 : (leftInterpolator.getOutValue() - p0) * duration 188 / leftInterpolator.getOutTicks() / 3; 189 p1 = p0 + p1Delta; 190 } 191 } 192 193 private static class BooleanInterpolationInterval extends 194 InterpolationInterval { 195 196 private final WritableBooleanValue target; 197 private boolean leftValue; 198 private final boolean rightValue; 199 200 private BooleanInterpolationInterval(KeyValue keyValue, long ticks, 201 Object leftValue) { 202 super(ticks, keyValue.getInterpolator()); 203 assert (keyValue.getTarget() instanceof WritableBooleanValue) 204 && (keyValue.getEndValue() instanceof Boolean) 205 && (leftValue instanceof Boolean); 206 this.target = (WritableBooleanValue) keyValue.getTarget(); 207 this.rightValue = (Boolean) keyValue.getEndValue(); 208 this.leftValue = (Boolean) leftValue; 209 } 210 211 private BooleanInterpolationInterval(KeyValue keyValue, long ticks) { 212 super(ticks, keyValue.getInterpolator()); 213 assert (keyValue.getTarget() instanceof WritableBooleanValue) 214 && (keyValue.getEndValue() instanceof Boolean); 215 this.target = (WritableBooleanValue) keyValue.getTarget(); 216 this.rightValue = (Boolean) keyValue.getEndValue(); 217 this.leftValue = target.get(); 218 } 219 220 @Override 221 public void interpolate(double frac) { 222 final boolean value = rightInterpolator.interpolate(leftValue, 223 rightValue, frac); 224 target.set(value); 225 } 226 227 @Override 228 public void recalculateStartValue() { 229 leftValue = target.get(); 230 } 231 } 232 233 private static class DoubleInterpolationInterval extends 234 InterpolationInterval { 235 236 private final WritableDoubleValue target; 237 private double leftValue; 238 private final double rightValue; 239 240 private DoubleInterpolationInterval(KeyValue keyValue, long ticks, 241 Object leftValue) { 242 super(ticks, keyValue.getInterpolator()); 243 assert (keyValue.getTarget() instanceof WritableDoubleValue) 244 && (keyValue.getEndValue() instanceof Number) 245 && (leftValue instanceof Number); 246 this.target = (WritableDoubleValue) keyValue.getTarget(); 247 this.rightValue = ((Number) keyValue.getEndValue()).doubleValue(); 248 this.leftValue = ((Number) leftValue).doubleValue(); 249 } 250 251 private DoubleInterpolationInterval(KeyValue keyValue, long ticks) { 252 super(ticks, keyValue.getInterpolator()); 253 assert (keyValue.getTarget() instanceof WritableDoubleValue) 254 && (keyValue.getEndValue() instanceof Number); 255 this.target = (WritableDoubleValue) keyValue.getTarget(); 256 this.rightValue = ((Number) keyValue.getEndValue()).doubleValue(); 257 this.leftValue = target.get(); 258 } 259 260 @Override 261 public void interpolate(double frac) { 262 final double value = rightInterpolator.interpolate(leftValue, 263 rightValue, frac); 264 target.set(value); 265 } 266 267 @Override 268 public void recalculateStartValue() { 269 leftValue = target.get(); 270 } 271 } 272 273 private static class TangentDoubleInterpolationInterval extends 274 TangentInterpolationInterval { 275 276 private final WritableDoubleValue target; 277 278 private TangentDoubleInterpolationInterval(KeyValue rightKeyValue, 279 long ticks, KeyValue leftKeyValue, long duration) { 280 super(rightKeyValue, ticks, leftKeyValue, duration); 281 assert rightKeyValue.getTarget() instanceof WritableDoubleValue; 282 this.target = (WritableDoubleValue) rightKeyValue.getTarget(); 283 } 284 285 private TangentDoubleInterpolationInterval(KeyValue rightKeyValue, 286 long ticks) { 287 super(rightKeyValue, ticks); 288 assert rightKeyValue.getTarget() instanceof WritableDoubleValue; 289 this.target = (WritableDoubleValue) rightKeyValue.getTarget(); 290 recalculateStartValue(target.get()); 291 } 292 293 @Override 294 public void interpolate(double frac) { 295 target.set(calculate(frac)); 296 } 297 298 @Override 299 public void recalculateStartValue() { 300 recalculateStartValue(target.get()); 301 } 302 } 303 304 private static class FloatInterpolationInterval extends 305 InterpolationInterval { 306 307 private final WritableFloatValue target; 308 private float leftValue; 309 private final float rightValue; 310 311 private FloatInterpolationInterval(KeyValue keyValue, long ticks, 312 Object leftValue) { 313 super(ticks, keyValue.getInterpolator()); 314 assert (keyValue.getTarget() instanceof WritableFloatValue) 315 && (keyValue.getEndValue() instanceof Number) 316 && (leftValue instanceof Number); 317 this.target = (WritableFloatValue) keyValue.getTarget(); 318 this.rightValue = ((Number) keyValue.getEndValue()).floatValue(); 319 this.leftValue = ((Number) leftValue).floatValue(); 320 } 321 322 private FloatInterpolationInterval(KeyValue keyValue, long ticks) { 323 super(ticks, keyValue.getInterpolator()); 324 assert (keyValue.getTarget() instanceof WritableFloatValue) 325 && (keyValue.getEndValue() instanceof Number); 326 this.target = (WritableFloatValue) keyValue.getTarget(); 327 this.rightValue = ((Number) keyValue.getEndValue()).floatValue(); 328 this.leftValue = target.get(); 329 } 330 331 @Override 332 public void interpolate(double frac) { 333 final float value = (float) rightInterpolator.interpolate( 334 leftValue, rightValue, frac); 335 target.set(value); 336 } 337 338 @Override 339 public void recalculateStartValue() { 340 leftValue = target.get(); 341 } 342 } 343 344 private static class TangentFloatInterpolationInterval extends 345 TangentInterpolationInterval { 346 347 private final WritableFloatValue target; 348 349 private TangentFloatInterpolationInterval(KeyValue rightKeyValue, 350 long ticks, KeyValue leftKeyValue, long duration) { 351 super(rightKeyValue, ticks, leftKeyValue, duration); 352 assert rightKeyValue.getTarget() instanceof WritableFloatValue; 353 this.target = (WritableFloatValue) rightKeyValue.getTarget(); 354 } 355 356 private TangentFloatInterpolationInterval(KeyValue rightKeyValue, 357 long ticks) { 358 super(rightKeyValue, ticks); 359 assert rightKeyValue.getTarget() instanceof WritableFloatValue; 360 this.target = (WritableFloatValue) rightKeyValue.getTarget(); 361 recalculateStartValue(target.get()); 362 } 363 364 @Override 365 public void interpolate(double frac) { 366 target.set((float) calculate(frac)); 367 } 368 369 @Override 370 public void recalculateStartValue() { 371 recalculateStartValue(target.get()); 372 } 373 } 374 375 private static class IntegerInterpolationInterval extends 376 InterpolationInterval { 377 378 private final WritableIntegerValue target; 379 private int leftValue; 380 private final int rightValue; 381 382 private IntegerInterpolationInterval(KeyValue keyValue, long ticks, 383 Object leftValue) { 384 super(ticks, keyValue.getInterpolator()); 385 assert (keyValue.getTarget() instanceof WritableIntegerValue) 386 && (keyValue.getEndValue() instanceof Number) 387 && (leftValue instanceof Number); 388 this.target = (WritableIntegerValue) keyValue.getTarget(); 389 this.rightValue = ((Number) keyValue.getEndValue()).intValue(); 390 this.leftValue = ((Number) leftValue).intValue(); 391 } 392 393 private IntegerInterpolationInterval(KeyValue keyValue, long ticks) { 394 super(ticks, keyValue.getInterpolator()); 395 assert (keyValue.getTarget() instanceof WritableIntegerValue) 396 && (keyValue.getEndValue() instanceof Number); 397 this.target = (WritableIntegerValue) keyValue.getTarget(); 398 this.rightValue = ((Number) keyValue.getEndValue()).intValue(); 399 this.leftValue = target.get(); 400 } 401 402 @Override 403 public void interpolate(double frac) { 404 final int value = rightInterpolator.interpolate(leftValue, 405 rightValue, frac); 406 target.set(value); 407 } 408 409 @Override 410 public void recalculateStartValue() { 411 leftValue = target.get(); 412 } 413 } 414 415 private static class TangentIntegerInterpolationInterval extends 416 TangentInterpolationInterval { 417 418 private final WritableIntegerValue target; 419 420 private TangentIntegerInterpolationInterval(KeyValue rightKeyValue, 421 long ticks, KeyValue leftKeyValue, long duration) { 422 super(rightKeyValue, ticks, leftKeyValue, duration); 423 assert rightKeyValue.getTarget() instanceof WritableIntegerValue; 424 this.target = (WritableIntegerValue) rightKeyValue.getTarget(); 425 } 426 427 private TangentIntegerInterpolationInterval(KeyValue rightKeyValue, 428 long ticks) { 429 super(rightKeyValue, ticks); 430 assert rightKeyValue.getTarget() instanceof WritableIntegerValue; 431 this.target = (WritableIntegerValue) rightKeyValue.getTarget(); 432 recalculateStartValue(target.get()); 433 } 434 435 @Override 436 public void interpolate(double frac) { 437 target.set((int) Math.round(calculate(frac))); 438 } 439 440 @Override 441 public void recalculateStartValue() { 442 recalculateStartValue(target.get()); 443 } 444 } 445 446 private static class LongInterpolationInterval extends 447 InterpolationInterval { 448 449 private final WritableLongValue target; 450 private long leftValue; 451 private final long rightValue; 452 453 private LongInterpolationInterval(KeyValue keyValue, long ticks, 454 Object leftValue) { 455 super(ticks, keyValue.getInterpolator()); 456 assert (keyValue.getTarget() instanceof WritableLongValue) 457 && (keyValue.getEndValue() instanceof Number) 458 && (leftValue instanceof Number); 459 this.target = (WritableLongValue) keyValue.getTarget(); 460 this.rightValue = ((Number) keyValue.getEndValue()).longValue(); 461 this.leftValue = ((Number) leftValue).longValue(); 462 } 463 464 private LongInterpolationInterval(KeyValue keyValue, long ticks) { 465 super(ticks, keyValue.getInterpolator()); 466 assert (keyValue.getTarget() instanceof WritableLongValue) 467 && (keyValue.getEndValue() instanceof Number); 468 this.target = (WritableLongValue) keyValue.getTarget(); 469 this.rightValue = ((Number) keyValue.getEndValue()).longValue(); 470 this.leftValue = target.get(); 471 } 472 473 @Override 474 public void interpolate(double frac) { 475 final long value = rightInterpolator.interpolate(leftValue, 476 rightValue, frac); 477 target.set(value); 478 } 479 480 @Override 481 public void recalculateStartValue() { 482 leftValue = target.get(); 483 } 484 } 485 486 private static class TangentLongInterpolationInterval extends 487 TangentInterpolationInterval { 488 489 private final WritableLongValue target; 490 491 private TangentLongInterpolationInterval(KeyValue rightKeyValue, 492 long ticks, KeyValue leftKeyValue, long duration) { 493 super(rightKeyValue, ticks, leftKeyValue, duration); 494 assert rightKeyValue.getTarget() instanceof WritableLongValue; 495 this.target = (WritableLongValue) rightKeyValue.getTarget(); 496 } 497 498 private TangentLongInterpolationInterval(KeyValue rightKeyValue, 499 long ticks) { 500 super(rightKeyValue, ticks); 501 assert rightKeyValue.getTarget() instanceof WritableLongValue; 502 this.target = (WritableLongValue) rightKeyValue.getTarget(); 503 recalculateStartValue(target.get()); 504 } 505 506 @Override 507 public void interpolate(double frac) { 508 target.set(Math.round(calculate(frac))); 509 } 510 511 @Override 512 public void recalculateStartValue() { 513 recalculateStartValue(target.get()); 514 } 515 } 516 517 private static class ObjectInterpolationInterval extends 518 InterpolationInterval { 519 520 @SuppressWarnings("rawtypes") 521 private final WritableValue target; 522 private Object leftValue; 523 private final Object rightValue; 524 525 private ObjectInterpolationInterval(KeyValue keyValue, long ticks, 526 Object leftValue) { 527 super(ticks, keyValue.getInterpolator()); 528 this.target = keyValue.getTarget(); 529 this.rightValue = keyValue.getEndValue(); 530 this.leftValue = leftValue; 531 } 532 533 private ObjectInterpolationInterval(KeyValue keyValue, long ticks) { 534 super(ticks, keyValue.getInterpolator()); 535 this.target = keyValue.getTarget(); 536 this.rightValue = keyValue.getEndValue(); 537 this.leftValue = target.getValue(); 538 } 539 540 @SuppressWarnings("unchecked") 541 @Override 542 public void interpolate(double frac) { 543 final Object value = rightInterpolator.interpolate(leftValue, 544 rightValue, frac); 545 target.setValue(value); 546 } 547 548 @Override 549 public void recalculateStartValue() { 550 leftValue = target.getValue(); 551 } 552 } 553 554 }