com.brashmonkey.spriter.Curve.java Source code

Java tutorial

Introduction

Here is the source code for com.brashmonkey.spriter.Curve.java

Source

/**************************************************************************
 * Copyright 2014 by Trixt0r
 * (https://github.com/Trixt0r, Heinrich Reich, e-mail: trixter16@web.de)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ***************************************************************************/

package com.brashmonkey.spriter;

import static com.brashmonkey.spriter.Calculator.NO_SOLUTION;
import static com.brashmonkey.spriter.Calculator.solveCubic;
import static com.brashmonkey.spriter.Interpolator.bezier;
import static com.brashmonkey.spriter.Interpolator.cubic;
import static com.brashmonkey.spriter.Interpolator.cubicAngle;
import static com.brashmonkey.spriter.Interpolator.linear;
import static com.brashmonkey.spriter.Interpolator.linearAngle;
import static com.brashmonkey.spriter.Interpolator.quadratic;
import static com.brashmonkey.spriter.Interpolator.quadraticAngle;
import static com.brashmonkey.spriter.Interpolator.quartic;
import static com.brashmonkey.spriter.Interpolator.quarticAngle;
import static com.brashmonkey.spriter.Interpolator.quintic;
import static com.brashmonkey.spriter.Interpolator.quinticAngle;

import com.badlogic.gdx.math.Vector2;

/** 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) {
        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 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 == NO_SOLUTION)
                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(Vector2 a, Vector2 b, float t, Vector2 target) {
        target.set(tween(a.x, b.x, t), tween(a.y, b.y, t));
    }

    private float tweenSub(float a, float b, float t) {
        if (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);
    }

    /** @see {@link #tween(float, float, float)} */
    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 == NO_SOLUTION)
                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) {
            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 + "]";
        }
    }
}