package com.sun.scenario.animation.shared;
import com.sun.javafx.animation.KeyValueHelper;
import javafx.animation.Interpolator;
import javafx.animation.KeyValue;
import javafx.beans.value.WritableBooleanValue;
import javafx.beans.value.WritableDoubleValue;
import javafx.beans.value.WritableFloatValue;
import javafx.beans.value.WritableIntegerValue;
import javafx.beans.value.WritableLongValue;
import javafx.beans.value.WritableValue;
import com.sun.scenario.animation.NumberTangentInterpolator;
public abstract class InterpolationInterval {
protected final long ticks;
protected final Interpolator rightInterpolator;
protected InterpolationInterval(long ticks,
Interpolator rightInterpolator) {
this.ticks = ticks;
this.rightInterpolator = rightInterpolator;
}
public abstract void interpolate(double frac);
public abstract void recalculateStartValue();
public static InterpolationInterval create(KeyValue rightKeyValue,
long ticks, KeyValue leftKeyValue, long duration) {
switch (KeyValueHelper.getType(rightKeyValue)) {
case BOOLEAN:
return new BooleanInterpolationInterval(rightKeyValue, ticks,
leftKeyValue.getEndValue());
case DOUBLE:
return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
.getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentDoubleInterpolationInterval(
rightKeyValue, ticks, leftKeyValue, duration)
: new DoubleInterpolationInterval(rightKeyValue,
ticks, leftKeyValue.getEndValue());
case FLOAT:
return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
.getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentFloatInterpolationInterval(
rightKeyValue, ticks, leftKeyValue, duration)
: new FloatInterpolationInterval(rightKeyValue, ticks,
leftKeyValue.getEndValue());
case INTEGER:
return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
.getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentIntegerInterpolationInterval(
rightKeyValue, ticks, leftKeyValue, duration)
: new IntegerInterpolationInterval(rightKeyValue,
ticks, leftKeyValue.getEndValue());
case LONG:
return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
.getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentLongInterpolationInterval(
rightKeyValue, ticks, leftKeyValue, duration)
: new LongInterpolationInterval(rightKeyValue, ticks,
leftKeyValue.getEndValue());
case OBJECT:
return new ObjectInterpolationInterval(rightKeyValue, ticks,
leftKeyValue.getEndValue());
}
throw new RuntimeException("Should not reach here");
}
public static InterpolationInterval create(KeyValue rightKeyValue,
long ticks) {
switch (KeyValueHelper.getType(rightKeyValue)) {
case BOOLEAN:
return new BooleanInterpolationInterval(rightKeyValue, ticks);
case DOUBLE:
return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentDoubleInterpolationInterval(
rightKeyValue, ticks)
: new DoubleInterpolationInterval(rightKeyValue, ticks);
case FLOAT:
return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentFloatInterpolationInterval(
rightKeyValue, ticks)
: new FloatInterpolationInterval(rightKeyValue, ticks);
case INTEGER:
return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentIntegerInterpolationInterval(
rightKeyValue, ticks)
: new IntegerInterpolationInterval(rightKeyValue,
ticks);
case LONG:
return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentLongInterpolationInterval(
rightKeyValue, ticks) : new LongInterpolationInterval(
rightKeyValue, ticks);
case OBJECT:
return new ObjectInterpolationInterval(rightKeyValue, ticks);
}
throw new RuntimeException("Should not reach here");
}
private static abstract class TangentInterpolationInterval extends
InterpolationInterval {
private final double duration;
private final double p2;
protected final double p3;
private final NumberTangentInterpolator leftInterpolator;
protected double p0;
private double p1;
private TangentInterpolationInterval(KeyValue rightKeyValue,
long ticks, KeyValue leftKeyValue, long duration) {
super(ticks, rightKeyValue.getInterpolator());
assert (rightKeyValue.getEndValue() instanceof Number)
&& (leftKeyValue.getEndValue() instanceof Number);
this.duration = duration;
final Interpolator rawLeftInterpolator = leftKeyValue
.getInterpolator();
leftInterpolator = (rawLeftInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rawLeftInterpolator
: null;
recalculateStartValue(((Number) leftKeyValue.getEndValue())
.doubleValue());
final NumberTangentInterpolator interpolator = (rightInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rightInterpolator
: null;
p3 = ((Number) rightKeyValue.getEndValue()).doubleValue();
final double p2Delta = (interpolator == null) ? 0 : (interpolator
.getInValue() - p3)
* duration
/ interpolator.getInTicks()
/ 3;
p2 = p3 + p2Delta;
}
private TangentInterpolationInterval(KeyValue rightKeyValue,
long ticks) {
super(ticks, rightKeyValue.getInterpolator());
assert rightKeyValue.getEndValue() instanceof Number;
this.duration = ticks;
leftInterpolator = null;
final NumberTangentInterpolator interpolator = (rightInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rightInterpolator
: null;
p3 = ((Number) rightKeyValue.getEndValue()).doubleValue();
final double p2Delta = (interpolator == null) ? 0 : (interpolator
.getInValue() - p3)
* duration
/ interpolator.getInTicks()
/ 3;
p2 = p3 + p2Delta;
}
protected double calculate(double t) {
final double oneMinusT = 1.0 - t;
final double tSquared = t * t;
final double oneMinusTSquared = oneMinusT * oneMinusT;
return oneMinusTSquared * oneMinusT * p0 + 3 * oneMinusTSquared * t
* p1 + 3 * oneMinusT * tSquared * p2 + tSquared * t * p3;
}
protected final void recalculateStartValue(double leftValue) {
p0 = leftValue;
final double p1Delta = (leftInterpolator == null) ? 0
: (leftInterpolator.getOutValue() - p0) * duration
/ leftInterpolator.getOutTicks() / 3;
p1 = p0 + p1Delta;
}
}
private static class BooleanInterpolationInterval extends
InterpolationInterval {
private final WritableBooleanValue target;
private boolean leftValue;
private final boolean rightValue;
private BooleanInterpolationInterval(KeyValue keyValue, long ticks,
Object leftValue) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableBooleanValue)
&& (keyValue.getEndValue() instanceof Boolean)
&& (leftValue instanceof Boolean);
this.target = (WritableBooleanValue) keyValue.getTarget();
this.rightValue = (Boolean) keyValue.getEndValue();
this.leftValue = (Boolean) leftValue;
}
private BooleanInterpolationInterval(KeyValue keyValue, long ticks) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableBooleanValue)
&& (keyValue.getEndValue() instanceof Boolean);
this.target = (WritableBooleanValue) keyValue.getTarget();
this.rightValue = (Boolean) keyValue.getEndValue();
this.leftValue = target.get();
}
@Override
public void interpolate(double frac) {
final boolean value = rightInterpolator.interpolate(leftValue,
rightValue, frac);
target.set(value);
}
@Override
public void recalculateStartValue() {
leftValue = target.get();
}
}
private static class DoubleInterpolationInterval extends
InterpolationInterval {
private final WritableDoubleValue target;
private double leftValue;
private final double rightValue;
private DoubleInterpolationInterval(KeyValue keyValue, long ticks,
Object leftValue) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableDoubleValue)
&& (keyValue.getEndValue() instanceof Number)
&& (leftValue instanceof Number);
this.target = (WritableDoubleValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).doubleValue();
this.leftValue = ((Number) leftValue).doubleValue();
}
private DoubleInterpolationInterval(KeyValue keyValue, long ticks) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableDoubleValue)
&& (keyValue.getEndValue() instanceof Number);
this.target = (WritableDoubleValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).doubleValue();
this.leftValue = target.get();
}
@Override
public void interpolate(double frac) {
final double value = rightInterpolator.interpolate(leftValue,
rightValue, frac);
target.set(value);
}
@Override
public void recalculateStartValue() {
leftValue = target.get();
}
}
private static class TangentDoubleInterpolationInterval extends
TangentInterpolationInterval {
private final WritableDoubleValue target;
private TangentDoubleInterpolationInterval(KeyValue rightKeyValue,
long ticks, KeyValue leftKeyValue, long duration) {
super(rightKeyValue, ticks, leftKeyValue, duration);
assert rightKeyValue.getTarget() instanceof WritableDoubleValue;
this.target = (WritableDoubleValue) rightKeyValue.getTarget();
}
private TangentDoubleInterpolationInterval(KeyValue rightKeyValue,
long ticks) {
super(rightKeyValue, ticks);
assert rightKeyValue.getTarget() instanceof WritableDoubleValue;
this.target = (WritableDoubleValue) rightKeyValue.getTarget();
recalculateStartValue(target.get());
}
@Override
public void interpolate(double frac) {
target.set(calculate(frac));
}
@Override
public void recalculateStartValue() {
recalculateStartValue(target.get());
}
}
private static class FloatInterpolationInterval extends
InterpolationInterval {
private final WritableFloatValue target;
private float leftValue;
private final float rightValue;
private FloatInterpolationInterval(KeyValue keyValue, long ticks,
Object leftValue) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableFloatValue)
&& (keyValue.getEndValue() instanceof Number)
&& (leftValue instanceof Number);
this.target = (WritableFloatValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).floatValue();
this.leftValue = ((Number) leftValue).floatValue();
}
private FloatInterpolationInterval(KeyValue keyValue, long ticks) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableFloatValue)
&& (keyValue.getEndValue() instanceof Number);
this.target = (WritableFloatValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).floatValue();
this.leftValue = target.get();
}
@Override
public void interpolate(double frac) {
final float value = (float) rightInterpolator.interpolate(
leftValue, rightValue, frac);
target.set(value);
}
@Override
public void recalculateStartValue() {
leftValue = target.get();
}
}
private static class TangentFloatInterpolationInterval extends
TangentInterpolationInterval {
private final WritableFloatValue target;
private TangentFloatInterpolationInterval(KeyValue rightKeyValue,
long ticks, KeyValue leftKeyValue, long duration) {
super(rightKeyValue, ticks, leftKeyValue, duration);
assert rightKeyValue.getTarget() instanceof WritableFloatValue;
this.target = (WritableFloatValue) rightKeyValue.getTarget();
}
private TangentFloatInterpolationInterval(KeyValue rightKeyValue,
long ticks) {
super(rightKeyValue, ticks);
assert rightKeyValue.getTarget() instanceof WritableFloatValue;
this.target = (WritableFloatValue) rightKeyValue.getTarget();
recalculateStartValue(target.get());
}
@Override
public void interpolate(double frac) {
target.set((float) calculate(frac));
}
@Override
public void recalculateStartValue() {
recalculateStartValue(target.get());
}
}
private static class IntegerInterpolationInterval extends
InterpolationInterval {
private final WritableIntegerValue target;
private int leftValue;
private final int rightValue;
private IntegerInterpolationInterval(KeyValue keyValue, long ticks,
Object leftValue) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableIntegerValue)
&& (keyValue.getEndValue() instanceof Number)
&& (leftValue instanceof Number);
this.target = (WritableIntegerValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).intValue();
this.leftValue = ((Number) leftValue).intValue();
}
private IntegerInterpolationInterval(KeyValue keyValue, long ticks) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableIntegerValue)
&& (keyValue.getEndValue() instanceof Number);
this.target = (WritableIntegerValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).intValue();
this.leftValue = target.get();
}
@Override
public void interpolate(double frac) {
final int value = rightInterpolator.interpolate(leftValue,
rightValue, frac);
target.set(value);
}
@Override
public void recalculateStartValue() {
leftValue = target.get();
}
}
private static class TangentIntegerInterpolationInterval extends
TangentInterpolationInterval {
private final WritableIntegerValue target;
private TangentIntegerInterpolationInterval(KeyValue rightKeyValue,
long ticks, KeyValue leftKeyValue, long duration) {
super(rightKeyValue, ticks, leftKeyValue, duration);
assert rightKeyValue.getTarget() instanceof WritableIntegerValue;
this.target = (WritableIntegerValue) rightKeyValue.getTarget();
}
private TangentIntegerInterpolationInterval(KeyValue rightKeyValue,
long ticks) {
super(rightKeyValue, ticks);
assert rightKeyValue.getTarget() instanceof WritableIntegerValue;
this.target = (WritableIntegerValue) rightKeyValue.getTarget();
recalculateStartValue(target.get());
}
@Override
public void interpolate(double frac) {
target.set((int) Math.round(calculate(frac)));
}
@Override
public void recalculateStartValue() {
recalculateStartValue(target.get());
}
}
private static class LongInterpolationInterval extends
InterpolationInterval {
private final WritableLongValue target;
private long leftValue;
private final long rightValue;
private LongInterpolationInterval(KeyValue keyValue, long ticks,
Object leftValue) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableLongValue)
&& (keyValue.getEndValue() instanceof Number)
&& (leftValue instanceof Number);
this.target = (WritableLongValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).longValue();
this.leftValue = ((Number) leftValue).longValue();
}
private LongInterpolationInterval(KeyValue keyValue, long ticks) {
super(ticks, keyValue.getInterpolator());
assert (keyValue.getTarget() instanceof WritableLongValue)
&& (keyValue.getEndValue() instanceof Number);
this.target = (WritableLongValue) keyValue.getTarget();
this.rightValue = ((Number) keyValue.getEndValue()).longValue();
this.leftValue = target.get();
}
@Override
public void interpolate(double frac) {
final long value = rightInterpolator.interpolate(leftValue,
rightValue, frac);
target.set(value);
}
@Override
public void recalculateStartValue() {
leftValue = target.get();
}
}
private static class TangentLongInterpolationInterval extends
TangentInterpolationInterval {
private final WritableLongValue target;
private TangentLongInterpolationInterval(KeyValue rightKeyValue,
long ticks, KeyValue leftKeyValue, long duration) {
super(rightKeyValue, ticks, leftKeyValue, duration);
assert rightKeyValue.getTarget() instanceof WritableLongValue;
this.target = (WritableLongValue) rightKeyValue.getTarget();
}
private TangentLongInterpolationInterval(KeyValue rightKeyValue,
long ticks) {
super(rightKeyValue, ticks);
assert rightKeyValue.getTarget() instanceof WritableLongValue;
this.target = (WritableLongValue) rightKeyValue.getTarget();
recalculateStartValue(target.get());
}
@Override
public void interpolate(double frac) {
target.set(Math.round(calculate(frac)));
}
@Override
public void recalculateStartValue() {
recalculateStartValue(target.get());
}
}
private static class ObjectInterpolationInterval extends
InterpolationInterval {
@SuppressWarnings("rawtypes")
private final WritableValue target;
private Object leftValue;
private final Object rightValue;
private ObjectInterpolationInterval(KeyValue keyValue, long ticks,
Object leftValue) {
super(ticks, keyValue.getInterpolator());
this.target = keyValue.getTarget();
this.rightValue = keyValue.getEndValue();
this.leftValue = leftValue;
}
private ObjectInterpolationInterval(KeyValue keyValue, long ticks) {
super(ticks, keyValue.getInterpolator());
this.target = keyValue.getTarget();
this.rightValue = keyValue.getEndValue();
this.leftValue = target.getValue();
}
@SuppressWarnings("unchecked")
@Override
public void interpolate(double frac) {
final Object value = rightInterpolator.interpolate(leftValue,
rightValue, frac);
target.setValue(value);
}
@Override
public void recalculateStartValue() {
leftValue = target.getValue();
}
}
}