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 }