diff --git a/src/main/java/dev/latvian/mods/kmath/util/Easing.java b/src/main/java/dev/latvian/mods/kmath/util/Easing.java index a82ff83..fe7e9ea 100644 --- a/src/main/java/dev/latvian/mods/kmath/util/Easing.java +++ b/src/main/java/dev/latvian/mods/kmath/util/Easing.java @@ -4,69 +4,63 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import net.minecraft.util.math.Vec3d; -@FunctionalInterface -public interface Easing extends Double2DoubleFunction { - double ease(double x); - - default double easeClamped(double x) { - return ease(KMath.clamp(x, 0D, 1D)); +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Source + */ +public final class Easing { + public static final Map FUNCTIONS = new LinkedHashMap<>(); + + public static Easing add(String id, Double2DoubleFunction function) { + var easing = add(id, function); + FUNCTIONS.put(id, easing); + return easing; } - @Override - default double get(double x) { - return ease(x); - } + public static final Easing LINEAR = add("linear", x -> x); + public static final Easing SMOOTHSTEP = add("smoothstep", KMath::smoothstep); + public static final Easing ISMOOTHSTEP = add("ismoothstep", KMath::ismoothstep); + public static final Easing SMOOTHERSTEP = add("smootherstep", KMath::smootherstep); - default double lerp(double t, double a, double b) { - return a + get(t) * (b - a); - } - - default Vec3d lerp(double t, Vec3d a, Vec3d b) { - return new Vec3d(lerp(t, a.x, b.x), lerp(t, a.y, b.y), lerp(t, a.z, b.z)); - } + public static final Easing SINE_IN = add("sine_in", x -> 1 - Math.cos((x - Math.PI) / 2)); + public static final Easing SINE_OUT = add("sine_out", x -> Math.sin((x * Math.PI) / 2)); + public static final Easing SINE_IN_OUT = add("sine_in_out", x -> -(Math.cos(Math.PI * x) - 1) / 2); - Easing LINEAR = x -> x; - Easing SMOOTHSTEP = KMath::smoothstep; - Easing ISMOOTHSTEP = KMath::ismoothstep; - Easing SMOOTHERSTEP = KMath::smootherstep; + public static final Easing QUAD_IN = add("quad_in", x -> x * x); + public static final Easing QUAD_OUT = add("quad_out", x -> 1 - (1 - x) * (1 - x)); + public static final Easing QUAD_IN_OUT = add("quad_in_out", x -> x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2); - Easing SINE_IN = x -> 1 - Math.cos((x - Math.PI) / 2); - Easing SINE_OUT = x -> Math.sin((x * Math.PI) / 2); - Easing SINE_IN_OUT = x -> -(Math.cos(Math.PI * x) - 1) / 2; + public static final Easing CUBIC_IN = add("cubic_in", x -> x * x * x); + public static final Easing CUBIC_OUT = add("cubic_out", x -> 1 - Math.pow(1 - x, 3)); + public static final Easing CUBIC_IN_OUT = add("cubic_in_out", x -> x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2D); - Easing QUAD_IN = x -> x * x; - Easing QUAD_OUT = x -> 1 - (1 - x) * (1 - x); - Easing QUAD_IN_OUT = x -> x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2; + public static final Easing QUART_IN = add("quart_in", x -> x * x * x * x); + public static final Easing QUART_OUT = add("quart_out", x -> 1 - Math.pow(1 - x, 4)); + public static final Easing QUART_IN_OUT = add("quart_in_out", x -> x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2D); - Easing CUBIC_IN = x -> x * x * x; - Easing CUBIC_OUT = x -> 1 - Math.pow(1 - x, 3); - Easing CUBIC_IN_OUT = x -> x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2D; + public static final Easing QUINT_IN = add("quint_in", x -> x * x * x * x * x); + public static final Easing QUINT_OUT = add("quint_out", x -> 1 - Math.pow(1 - x, 5)); + public static final Easing QUINT_IN_OUT = add("quint_in_out", x -> x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2D); - Easing QUART_IN = x -> x * x * x * x; - Easing QUART_OUT = x -> 1 - Math.pow(1 - x, 4); - Easing QUART_IN_OUT = x -> x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2D; + public static final Easing EXPO_IN = add("expo_in", x -> x == 0 ? 0 : Math.pow(2, 10 * x - 10)); + public static final Easing EXPO_OUT = add("expo_out", x -> x == 1 ? 1 : 1 - Math.pow(2, -10 * x)); + public static final Easing EXPO_IN_OUT = add("expo_in_out", x -> x == 0 ? 0 : x == 1 ? 1 : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2); - Easing QUINT_IN = x -> x * x * x * x * x; - Easing QUINT_OUT = x -> 1 - Math.pow(1 - x, 5); - Easing QUINT_IN_OUT = x -> x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2D; + public static final Easing CIRC_IN = add("circ_in", x -> 1 - Math.sqrt(1 - x * x)); + public static final Easing CIRC_OUT = add("circ_out", x -> Math.sqrt(1 - (x - 1) * (x - 1))); + public static final Easing CIRC_IN_OUT = add("circ_in_out", x -> x < 0.5 ? (1 - Math.sqrt(1 - 4 * x * x)) / 2 : (Math.sqrt(1 - (-2 * x + 2) * (-2 * x + 2)) + 1) / 2); - Easing EXPO_IN = x -> x == 0 ? 0 : Math.pow(2, 10 * x - 10); - Easing EXPO_OUT = x -> x == 1 ? 1 : 1 - Math.pow(2, -10 * x); - Easing EXPO_IN_OUT = x -> x == 0 ? 0 : x == 1 ? 1 : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2; + public static final Easing BACK_IN = add("back_in", x -> x * x * (2.70158 * x - 1.70158)); + public static final Easing BACK_OUT = add("back_out", x -> 1 - (1 - x) * (1 - x) * (2.70158 * (1 - x) - 1.70158)); + public static final Easing BACK_IN_OUT = add("back_in_out", x -> x < 0.5 ? Math.pow(2 * x, 2) * ((2.5949095 + 1) * 2 * x - 2.5949095) / 2 : (Math.pow(2 * x - 2, 2) * ((2.5949095 + 1) * (x * 2 - 2) + 2.5949095) + 2) / 2); - Easing CIRC_IN = x -> 1 - Math.sqrt(1 - x * x); - Easing CIRC_OUT = x -> Math.sqrt(1 - (x - 1) * (x - 1)); - Easing CIRC_IN_OUT = x -> x < 0.5 ? (1 - Math.sqrt(1 - 4 * x * x)) / 2 : (Math.sqrt(1 - (-2 * x + 2) * (-2 * x + 2)) + 1) / 2; + public static final Easing ELASTIC_IN = add("elastic_in", x -> Math.sin(13 * Math.PI / 2 * x) * Math.pow(2, 10 * x - 10)); + public static final Easing ELASTIC_OUT = add("elastic_out", x -> Math.sin(-13 * Math.PI / 2 * (x + 1)) * Math.pow(2, -10 * x) + 1); + public static final Easing ELASTIC_IN_OUT = add("elastic_in_out", x -> x < 0.5 ? Math.sin(13 * Math.PI / 2 * (2 * x)) * Math.pow(2, 10 * (2 * x) - 10) / 2 : Math.sin(-13 * Math.PI / 2 * (2 * x - 1)) * Math.pow(2, -10 * (2 * x - 1)) / 2 + 1); - Easing BACK_IN = x -> x * x * (2.70158 * x - 1.70158); - Easing BACK_OUT = x -> 1 - (1 - x) * (1 - x) * (2.70158 * (1 - x) - 1.70158); - Easing BACK_IN_OUT = x -> x < 0.5 ? Math.pow(2 * x, 2) * ((2.5949095 + 1) * 2 * x - 2.5949095) / 2 : (Math.pow(2 * x - 2, 2) * ((2.5949095 + 1) * (x * 2 - 2) + 2.5949095) + 2) / 2; - - Easing ELASTIC_IN = x -> Math.sin(13 * Math.PI / 2 * x) * Math.pow(2, 10 * x - 10); - Easing ELASTIC_OUT = x -> Math.sin(-13 * Math.PI / 2 * (x + 1)) * Math.pow(2, -10 * x) + 1; - Easing ELASTIC_IN_OUT = x -> x < 0.5 ? Math.sin(13 * Math.PI / 2 * (2 * x)) * Math.pow(2, 10 * (2 * x) - 10) / 2 : Math.sin(-13 * Math.PI / 2 * (2 * x - 1)) * Math.pow(2, -10 * (2 * x - 1)) / 2 + 1; - - Easing BOUNCE_OUT = x -> { + public static final Easing BOUNCE_OUT = add("bounce_out", x -> { if (x < 1 / 2.75) { return 7.5625 * x * x; } else if (x < 2 / 2.75) { @@ -76,8 +70,33 @@ default Vec3d lerp(double t, Vec3d a, Vec3d b) { } else { return 7.5625 * (x -= 2.625 / 2.75) * x + 0.984375; } - }; + }); + + public static final Easing BOUNCE_IN = add("bounce_in", x -> 1 - BOUNCE_OUT.ease(1 - x)); + public static final Easing BOUNCE_IN_OUT = add("bounce_in_out", x -> x < 0.5 ? BOUNCE_IN.ease(x * 2) / 2 : BOUNCE_OUT.ease(x * 2 - 1) / 2 + 0.5); + + public final String id; + public final Double2DoubleFunction function; - Easing BOUNCE_IN = x -> 1 - BOUNCE_OUT.ease(1 - x); - Easing BOUNCE_IN_OUT = x -> x < 0.5 ? BOUNCE_IN.ease(x * 2) / 2 : BOUNCE_OUT.ease(x * 2 - 1) / 2 + 0.5; + private Easing(String id, Double2DoubleFunction function) { + this.id = id; + this.function = function; + } + + public double ease(double x) { + return function.get(x); + } + + public double easeClamped(double x) { + return function.get(KMath.clamp(x, 0D, 1D)); + } + + public double lerp(double t, double a, double b) { + return KMath.lerp(function.get(t), a, b); + } + + public Vec3d lerp(double t, Vec3d a, Vec3d b) { + var e = function.get(t); + return new Vec3d(KMath.lerp(e, a.x, b.x), KMath.lerp(e, a.y, b.y), KMath.lerp(e, a.z, b.z)); + } } diff --git a/src/main/java/dev/latvian/mods/kmath/util/EasingGroup.java b/src/main/java/dev/latvian/mods/kmath/util/EasingGroup.java index a20d252..82b7eab 100644 --- a/src/main/java/dev/latvian/mods/kmath/util/EasingGroup.java +++ b/src/main/java/dev/latvian/mods/kmath/util/EasingGroup.java @@ -3,56 +3,43 @@ import java.util.LinkedHashMap; import java.util.Map; -/** - * Source - */ -public enum EasingGroup { - LINEAR("linear", Easing.LINEAR), - SMOOTHSTEP("smoothstep", Easing.SMOOTHSTEP), - ISMOOTHSTEP("ismoothstep", Easing.ISMOOTHSTEP), - SMOOTHERSTEP("smootherstep", Easing.SMOOTHERSTEP), - SINE("sine", Easing.SINE_IN, Easing.SINE_OUT, Easing.SINE_IN_OUT), - QUAD("quad", Easing.QUAD_IN, Easing.QUAD_OUT, Easing.QUAD_IN_OUT), - CUBIC("cubic", Easing.CUBIC_IN, Easing.CUBIC_OUT, Easing.CUBIC_IN_OUT), - QUART("quart", Easing.QUART_IN, Easing.QUART_OUT, Easing.QUART_IN_OUT), - QUINT("quint", Easing.QUINT_IN, Easing.QUINT_OUT, Easing.QUINT_IN_OUT), - EXPO("expo", Easing.EXPO_IN, Easing.EXPO_OUT, Easing.EXPO_IN_OUT), - CIRC("circ", Easing.CIRC_IN, Easing.CIRC_OUT, Easing.CIRC_IN_OUT), - BACK("back", Easing.BACK_IN, Easing.BACK_OUT, Easing.BACK_IN_OUT), - ELASTIC("elastic", Easing.ELASTIC_IN, Easing.ELASTIC_OUT, Easing.ELASTIC_IN_OUT), - BOUNCE("bounce", Easing.BOUNCE_IN, Easing.BOUNCE_OUT, Easing.BOUNCE_IN_OUT); - - public static final EasingGroup[] VALUES = values(); +public class EasingGroup { public static final Map GROUPS = new LinkedHashMap<>(); - public static final Map FUNCTIONS = new LinkedHashMap<>(); - static { - for (var group : VALUES) { - GROUPS.put(group.id, group); + public static EasingGroup add(String id, Easing in, Easing out, Easing inOut) { + var group = new EasingGroup(id, in, out, inOut); + GROUPS.put(id, group); + return group; + } - if (group.in == group.out && group.in == group.inOut) { - FUNCTIONS.put(group.id, group.in); - } else { - FUNCTIONS.put(group.id + "_in", group.in); - FUNCTIONS.put(group.id + "_out", group.out); - FUNCTIONS.put(group.id + "_in_out", group.inOut); - } - } + public static EasingGroup add(String id, Easing easing) { + return add(id, easing, easing, easing); } + public static final EasingGroup LINEAR = add("linear", Easing.LINEAR); + public static final EasingGroup SMOOTHSTEP = add("smoothstep", Easing.SMOOTHSTEP); + public static final EasingGroup ISMOOTHSTEP = add("ismoothstep", Easing.ISMOOTHSTEP); + public static final EasingGroup SMOOTHERSTEP = add("smootherstep", Easing.SMOOTHERSTEP); + public static final EasingGroup SINE = add("sine", Easing.SINE_IN, Easing.SINE_OUT, Easing.SINE_IN_OUT); + public static final EasingGroup QUAD = add("quad", Easing.QUAD_IN, Easing.QUAD_OUT, Easing.QUAD_IN_OUT); + public static final EasingGroup CUBIC = add("cubic", Easing.CUBIC_IN, Easing.CUBIC_OUT, Easing.CUBIC_IN_OUT); + public static final EasingGroup QUART = add("quart", Easing.QUART_IN, Easing.QUART_OUT, Easing.QUART_IN_OUT); + public static final EasingGroup QUINT = add("quint", Easing.QUINT_IN, Easing.QUINT_OUT, Easing.QUINT_IN_OUT); + public static final EasingGroup EXPO = add("expo", Easing.EXPO_IN, Easing.EXPO_OUT, Easing.EXPO_IN_OUT); + public static final EasingGroup CIRC = add("circ", Easing.CIRC_IN, Easing.CIRC_OUT, Easing.CIRC_IN_OUT); + public static final EasingGroup BACK = add("back", Easing.BACK_IN, Easing.BACK_OUT, Easing.BACK_IN_OUT); + public static final EasingGroup ELASTIC = add("elastic", Easing.ELASTIC_IN, Easing.ELASTIC_OUT, Easing.ELASTIC_IN_OUT); + public static final EasingGroup BOUNCE = add("bounce", Easing.BOUNCE_IN, Easing.BOUNCE_OUT, Easing.BOUNCE_IN_OUT); + public final String id; public final Easing in; public final Easing out; public final Easing inOut; - EasingGroup(String id, Easing in, Easing out, Easing inOut) { + private EasingGroup(String id, Easing in, Easing out, Easing inOut) { this.id = id; this.in = in; this.out = out; this.inOut = inOut; } - - EasingGroup(String id, Easing common) { - this(id, common, common, common); - } }