package com.brashmonkey.spriter; import static com.brashmonkey.spriter.Calculator.*; import static com.brashmonkey.spriter.Interpolator.*; /** * Represents a curve in a Spriter SCML file. * An instance of this class is responsible for tweening given data. * The most important method of this class is {@link #tween(float, float, float)}. * Curves can be changed with sub curves {@link Curve#subCurve}. * @author Trixt0r * */ public class Curve { /** * Represents a curve type in a Spriter SCML file. * @author Trixt0r * */ public static enum Type { Instant, Linear, Quadratic, Cubic, Quartic, Quintic, Bezier; } /** * Returns a curve type based on the given curve name. * @param name the name of the curve * @return the curve type. {@link Type#Linear} is returned as a default type. */ public static Type getType(String name){ if(name.equals("instant")) return Type.Instant; else if(name.equals("quadratic")) return Type.Quadratic; else if(name.equals("cubic")) return Type.Cubic; else if(name.equals("quartic")) return Type.Quartic; else if(name.equals("quintic")) return Type.Quintic; else if(name.equals("bezier")) return Type.Bezier; else return Type.Linear; } private Type type; /** * The sub curve of this curve, which can be <code>null</code>. */ public Curve subCurve; /** * The constraints of a curve which will affect a curve of the types different from {@link Type#Linear} and {@link Type#Instant}. */ public final Constraints constraints = new Constraints(0, 0, 0, 0); /** * Creates a new linear curve. */ public Curve(){ this(Type.Linear); } /** * Creates a new curve with the given type. * @param type the curve type */ public Curve(Type type){ this(type, null); } /** * Creates a new curve with the given type and sub cuve. * @param type the curve type * @param subCurve the sub curve. Can be <code>null</code> */ public Curve(Type type, Curve subCurve){ this.setType(type); this.subCurve = subCurve; } /** * Sets the type of this curve. * @param type the curve type. * @throws SpriterException if the type is <code>null</code> */ public void setType(Type type){ if(type == null) throw new SpriterException("The type of a curve cannot be null!"); this.type = type; } /** * Returns the type of this curve. * @return the curve type */ public Type getType(){ return this.type; } private float lastCubicSolution = 0f; /** * Returns a new value based on the given values. * Tweens the weight with the set sub curve. * @param a the start value * @param b the end value * @param t the weight which lies between 0.0 and 1.0 * @return tweened value */ public float tween(float a, float b, float t){ t = tweenSub(0f,1f,t); switch(type){ case Instant: return a; case Linear: return linear(a, b, t); case Quadratic: return quadratic(a, linear(a, b, constraints.c1), b, t); case Cubic: return cubic(a, linear(a, b, constraints.c1), linear(a, b, constraints.c2), b, t); case Quartic: return quartic(a, linear(a, b, constraints.c1), linear(a, b, constraints.c2), linear(a, b, constraints.c3), b, t); case Quintic: return quintic(a, linear(a, b, constraints.c1), linear(a, b, constraints.c2), linear(a, b, constraints.c3), linear(a, b, constraints.c4), b, t); case Bezier: Float cubicSolution = solveCubic(3f*(constraints.c1-constraints.c3) + 1f, 3f*(constraints.c3-2f*constraints.c1), 3f*constraints.c1, -t); if(cubicSolution == null) cubicSolution = lastCubicSolution; else lastCubicSolution = cubicSolution; return linear(a, b, bezier(cubicSolution, 0f, constraints.c2, constraints.c4, 1f)); default: return linear(a, b, t); } } /** * Interpolates the given two points with the given weight and saves the result in the target point. * @param a the start point * @param b the end point * @param t the weight which lies between 0.0 and 1.0 * @param target the target point to save the result in */ public void tweenPoint(Point a, Point b, float t, Point target){ target.set(this.tween(a.x, b.x, t), this.tween(a.y, b.y, t)); } private float tweenSub(float a, float b, float t){ if(this.subCurve != null) return subCurve.tween(a, b, t); else return t; } /** * Returns a tweened angle based on the given angles, weight and the spin. * @param a the start angle * @param b the end angle * @param t the weight which lies between 0.0 and 1.0 * @param spin the spin, which is either 0, 1 or -1 * @return tweened angle */ public float tweenAngle(float a, float b, float t, int spin){ if(spin>0){ if(b-a < 0) b+=360; } else if(spin < 0){ if(b-a > 0) b-=360; } else return a; return tween(a, b, t); } /** * */ public float tweenAngle(float a, float b, float t){ t = tweenSub(0f,1f,t); switch(type){ case Instant: return a; case Linear: return linearAngle(a, b, t); case Quadratic: return quadraticAngle(a, linearAngle(a, b, constraints.c1), b, t); case Cubic: return cubicAngle(a, linearAngle(a, b, constraints.c1), linearAngle(a, b, constraints.c2), b, t); case Quartic: return quarticAngle(a, linearAngle(a, b, constraints.c1), linearAngle(a, b, constraints.c2), linearAngle(a, b, constraints.c3), b, t); case Quintic: return quinticAngle(a, linearAngle(a, b, constraints.c1), linearAngle(a, b, constraints.c2), linearAngle(a, b, constraints.c3), linearAngle(a, b, constraints.c4), b, t); case Bezier: Float cubicSolution = solveCubic(3f*(constraints.c1-constraints.c3) + 1f, 3f*(constraints.c3-2f*constraints.c1), 3f*constraints.c1, -t); if(cubicSolution == null) cubicSolution = lastCubicSolution; else lastCubicSolution = cubicSolution; return linearAngle(a, b, bezier(cubicSolution, 0f, constraints.c2, constraints.c4, 1f)); default: return linearAngle(a, b, t); } } public String toString(){ return getClass().getSimpleName()+"|["+type+":"+constraints+", subCurve: "+subCurve+"]"; } /** * Represents constraints for a curve. * Constraints are important for curves which have a order higher than 1. * @author Trixt0r * */ public static class Constraints{ public float c1, c2, c3, c4; public Constraints(float c1, float c2, float c3, float c4){ this.set(c1, c2, c3, c4); } public void set(float c1, float c2, float c3, float c4){ this.c1 = c1; this.c2 = c2; this.c3 = c3; this.c4 = c4; } public String toString(){ return getClass().getSimpleName()+"| [c1:"+c1+", c2:"+c2+", c3:"+c3+", c4:"+c4+"]"; } } }