diff --git a/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/FunctionHelper.java b/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/FunctionHelper.java index 2ded91f13..00adec235 100644 --- a/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/FunctionHelper.java +++ b/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/FunctionHelper.java @@ -9,52 +9,59 @@ import java.util.function.Supplier; import javafx.event.Event; import javafx.event.EventHandler; -public interface FunctionHelper { - +public final class FunctionHelper { + private FunctionHelper() { + } + + @SafeVarargs public static void always(Consumer consumer, T... ts) { Arrays.asList(ts).forEach(consumer); } - + + @SafeVarargs public static void alwaysA(BiConsumer consumer, A a, B... bs) { Arrays.asList(bs).forEach(b -> consumer.accept(a, b)); } - + + @SafeVarargs public static void alwaysB(BiConsumer consumer, B b, A... as) { Arrays.asList(as).forEach(a -> consumer.accept(a, b)); } - + public static BiConsumer exchange(BiConsumer consumer) { return (b, a) -> consumer.accept(a, b); } - + + @SafeVarargs public static Consumer link(Consumer... consumers) { return t -> { for (Consumer consumer : consumers) consumer.accept(t); }; } - + + @SafeVarargs public static EventHandler link(EventHandler... handlers) { return t -> { for (EventHandler handler : handlers) handler.handle(t); }; } - + public static Consumer link1(Function function, Consumer consumer) { return a -> consumer.accept(function.apply(a)); } - + public static BiConsumer link2(Function function, BiConsumer consumer) { return (a, c) -> consumer.accept(function.apply(a), c); } - + public static Consumer link2(Supplier supplier, BiConsumer consumer) { return b -> consumer.accept(supplier.get(), b); } - + public static Supplier link1(Supplier supplier, Function function) { return () -> function.apply(supplier.get()); } - + } diff --git a/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/SkinCube.java b/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/SkinCube.java index 107b27464..40980cae8 100644 --- a/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/SkinCube.java +++ b/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/SkinCube.java @@ -4,79 +4,80 @@ import javafx.scene.image.Image; import javafx.scene.shape.Mesh; import javafx.scene.shape.MeshView; import javafx.scene.shape.TriangleMesh; +import org.jackhuang.hmcl.util.ArrayUtils; public class SkinCube extends MeshView { - + public static class Model extends TriangleMesh { - + public Model(float width, float height, float depth, float scaleX, float scaleY, float startX, float startY, boolean isSlim) { getPoints().addAll(createPoints(width, height, depth)); getTexCoords().addAll(createTexCoords(width, height, depth, scaleX, scaleY, startX, startY, isSlim)); getFaces().addAll(createFaces()); } - + public static float[] createPoints(float width, float height, float depth) { width /= 2F; height /= 2F; depth /= 2F; - + return new float[]{ - -width, -height, depth, // P0 - width, -height, depth, // P1 - -width, height, depth, // P2 - width, height, depth, // P3 - -width, -height, -depth, // P4 - width, -height, -depth, // P5 - -width, height, -depth, // P6 - width, height, -depth // P7 + -width, -height, depth, // P0 + width, -height, depth, // P1 + -width, height, depth, // P2 + width, height, depth, // P3 + -width, -height, -depth, // P4 + width, -height, -depth, // P5 + -width, height, -depth, // P6 + width, height, -depth // P7 }; } - + public static float[] createTexCoords(float width, float height, float depth, float scaleX, float scaleY, - float startX, float startY, boolean isSlim) { - float x = (width + depth) * 2, y = height + depth, half_width = width / x * scaleX, half_depth = depth / x * scaleX, + float startX, float startY, boolean isSlim) { + float x = (width + depth) * 2, y = height + depth, half_width = width / x * scaleX, half_depth = depth / x * scaleX, top_x = depth / x * scaleX + startX, top_y = startY, arm4 = isSlim ? half_depth : half_width, bottom_x = startX, middle_y = depth / y * scaleY + top_y, bottom_y = scaleY + top_y; return new float[]{ - top_x, top_y, // T0 --- - top_x + half_width, top_y, // T1 | - top_x + half_width * 2, top_y, // T2 --- - bottom_x, middle_y, // T3 --- - bottom_x + half_depth, middle_y, // T4 | - bottom_x + half_depth + half_width, middle_y, // T5 | - bottom_x + scaleX - arm4, middle_y, // T6 | - bottom_x + scaleX, middle_y, // T7 --- - bottom_x, bottom_y, // T8 --- - bottom_x + half_depth, bottom_y, // T9 | - bottom_x + half_depth + half_width, bottom_y, // T10 | - bottom_x + scaleX - arm4, bottom_y, // T11 | - bottom_x + scaleX, bottom_y // T12 --- + top_x, top_y, // T0 --- + top_x + half_width, top_y, // T1 | + top_x + half_width * 2, top_y, // T2 --- + bottom_x, middle_y, // T3 --- + bottom_x + half_depth, middle_y, // T4 | + bottom_x + half_depth + half_width, middle_y, // T5 | + bottom_x + scaleX - arm4, middle_y, // T6 | + bottom_x + scaleX, middle_y, // T7 --- + bottom_x, bottom_y, // T8 --- + bottom_x + half_depth, bottom_y, // T9 | + bottom_x + half_depth + half_width, bottom_y, // T10 | + bottom_x + scaleX - arm4, bottom_y, // T11 | + bottom_x + scaleX, bottom_y // T12 --- }; } - + public static int[] createFaces() { int faces[] = new int[]{ // TOP - 5,0, 4,1, 0,5, //P5,T0, P4,T1, P0,T5 - 5,0, 0,5, 1,4, //P5,T0, P0,T5, P1,T4 + 5, 0, 4, 1, 0, 5, //P5,T0, P4,T1, P0,T5 + 5, 0, 0, 5, 1, 4, //P5,T0, P0,T5, P1,T4 // RIGHT - 0,5, 4,6, 6,11, //P0,T4 ,P4,T3, P6,T8 - 0,5, 6,11,2,10, //P0,T4 ,P6,T8, P2,T9 + 0, 5, 4, 6, 6, 11, //P0,T4 ,P4,T3, P6,T8 + 0, 5, 6, 11, 2, 10, //P0,T4 ,P6,T8, P2,T9 // FRONT - 1,4, 0,5, 2,10, //P1,T5, P0,T4, P2,T9 - 1,4, 2,10,3,9, //P1,T5, P2,T9, P3,T10 + 1, 4, 0, 5, 2, 10, //P1,T5, P0,T4, P2,T9 + 1, 4, 2, 10, 3, 9, //P1,T5, P2,T9, P3,T10 // LEFT - 5,3, 1,4, 3,9, //P5,T6, P1,T5, P3,T10 - 5,3, 3,9, 7,8, //P5,T6, P3,T10,P7,T11 + 5, 3, 1, 4, 3, 9, //P5,T6, P1,T5, P3,T10 + 5, 3, 3, 9, 7, 8, //P5,T6, P3,T10,P7,T11 // BACK - 4,6, 5,7, 7,12, //P4,T6, P5,T7, P7,T12 - 4,6, 7,12,6,11, //P4,T6, P7,T12,P6,T11 + 4, 6, 5, 7, 7, 12, //P4,T6, P5,T7, P7,T12 + 4, 6, 7, 12, 6, 11, //P4,T6, P7,T12,P6,T11 // BOTTOM - 3,5, 2,6, 6,2, //P3,T2, P2,T1, P6,T5 - 3,5, 6,2, 7,1 //P3,T2, P6,T5, P7,T6 + 3, 5, 2, 6, 6, 2, //P3,T2, P2,T1, P6,T5 + 3, 5, 6, 2, 7, 1 //P3,T2, P6,T5, P7,T6 }; - - int copy[] = ArrayUtils.clone(faces); + + int[] copy = faces.clone(); ArrayUtils.reverse(copy); for (int i = 0; i < copy.length; i += 2) { int tmp = copy[i]; @@ -87,12 +88,12 @@ public class SkinCube extends MeshView { } } - + private double width, height, depth; private boolean isSlim; private Image skin; private Mesh model; - + public SkinCube(float width, float height, float depth, float scaleX, float scaleY, float startX, float startY, float enlarge, boolean isSlim) { this.width = width; this.height = height; @@ -104,35 +105,35 @@ public class SkinCube extends MeshView { public void setWidth(double width) { this.width = width; } - + public double getWidth() { return width; } - + public void setHeight(double height) { this.height = height; } - + public double getHeight() { return height; } - + public void setDepth(double depth) { this.depth = depth; } - + public double getDepth() { return depth; } - + public boolean isSlim() { return isSlim; } - + public Mesh getModel() { return model; } - + public void setModel(Mesh model) { this.model = model; setMesh(model); diff --git a/HMCL/src/main/java/moe/mickey/minecraft/skin/fx/SkinCanvasSupport.java b/HMCL/src/test/java/moe/mickey/minecraft/skin/fx/SkinCanvasSupport.java similarity index 100% rename from HMCL/src/main/java/moe/mickey/minecraft/skin/fx/SkinCanvasSupport.java rename to HMCL/src/test/java/moe/mickey/minecraft/skin/fx/SkinCanvasSupport.java diff --git a/HMCL/src/test/java/moe/mickey/minecraft/skin/fx/test/Test.java b/HMCL/src/test/java/moe/mickey/minecraft/skin/fx/test/Test.java new file mode 100644 index 000000000..9edb06888 --- /dev/null +++ b/HMCL/src/test/java/moe/mickey/minecraft/skin/fx/test/Test.java @@ -0,0 +1,38 @@ +package moe.mickey.minecraft.skin.fx.test; + +import java.util.function.Consumer; + +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.stage.Stage; +import moe.mickey.minecraft.skin.fx.FunctionHelper; +import moe.mickey.minecraft.skin.fx.SkinCanvas; +import moe.mickey.minecraft.skin.fx.SkinCanvasSupport; +import moe.mickey.minecraft.skin.fx.animation.SkinAniRunning; +import moe.mickey.minecraft.skin.fx.animation.SkinAniWavingArms; + +public class Test extends Application { + + public static final String TITLE = "FX - Minecraft skin preview"; + + public static SkinCanvas createSkinCanvas() { + SkinCanvas canvas = new SkinCanvas(SkinCanvas.CHOCOLATE, 400, 400, true); + canvas.getAnimationplayer().addSkinAnimation(new SkinAniWavingArms(100, 2000, 7.5, canvas), new SkinAniRunning(100, 100, 30, canvas)); + FunctionHelper.alwaysB(Consumer::accept, canvas, new SkinCanvasSupport.Mouse(.5), new SkinCanvasSupport.Drag(TITLE)); + return canvas; + } + + @Override + public void start(Stage stage) throws Exception { + stage.setTitle(TITLE); + Scene scene = new Scene(createSkinCanvas()); + stage.setScene(scene); + stage.show(); + + } + + public static void main(String... args) { + launch(args); + } + +} diff --git a/HMCLCore/build.gradle b/HMCLCore/build.gradle index 5aad792f0..27d9427c2 100644 --- a/HMCLCore/build.gradle +++ b/HMCLCore/build.gradle @@ -14,13 +14,4 @@ dependencies { api group: 'com.nqzero', name: 'permit-reflect', version: '0.3' api group: 'org.nanohttpd', name: 'nanohttpd', version: '2.3.1' compileOnlyApi group: 'org.jetbrains', name: 'annotations', version: '16.0.3' - - // compileOnlyApi group: 'org.openjfx', name: 'javafx-base', version: '15', classifier: 'win' - // compileOnlyApi group: 'org.openjfx', name: 'javafx-controls', version: '15', classifier: 'win' - // compileOnlyApi group: 'org.openjfx', name: 'javafx-fxml', version: '15', classifier: 'win' - // compileOnlyApi group: 'org.openjfx', name: 'javafx-graphics', version: '15', classifier: 'win' - // compileOnlyApi group: 'org.openjfx', name: 'javafx-media', version: '15', classifier: 'win' - // compileOnlyApi group: 'org.openjfx', name: 'javafx-swing', version: '15', classifier: 'win' - // compileOnlyApi group: 'org.openjfx', name: 'javafx-web', version: '15', classifier: 'win' - } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ArrayUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ArrayUtils.java new file mode 100644 index 000000000..1e25d65f7 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ArrayUtils.java @@ -0,0 +1,434 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.util; + +import java.lang.reflect.Array; + +/** + * Commons-lang ArrayUtils + */ +public final class ArrayUtils { + private ArrayUtils() { + } + + public static boolean[] addAll(boolean[] array1, boolean... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + boolean[] joinedArray = new boolean[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static byte[] addAll(byte[] array1, byte... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + byte[] joinedArray = new byte[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static char[] addAll(char[] array1, char... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + char[] joinedArray = new char[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static double[] addAll(double[] array1, double... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + double[] joinedArray = new double[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static float[] addAll(float[] array1, float... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + float[] joinedArray = new float[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static int[] addAll(int[] array1, int... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + int[] joinedArray = new int[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static long[] addAll(long[] array1, long... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + long[] joinedArray = new long[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + public static short[] addAll(short[] array1, short... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } else { + short[] joinedArray = new short[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + } + + @SafeVarargs + public static T[] addAll(final T[] array1, final T... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final Class type1 = array1.getClass().getComponentType(); + @SuppressWarnings("unchecked") // OK, because array is of type T + final T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length); + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + try { + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + } catch (final ArrayStoreException ase) { + // Check if problem was due to incompatible types + /* + * We do this here, rather than before the copy because: + * - it would be a wasted check most of the time + * - safer, in case check turns out to be too strict + */ + final Class type2 = array2.getClass().getComponentType(); + if (!type1.isAssignableFrom(type2)) { + throw new IllegalArgumentException("Cannot store " + type2.getName() + " in an array of " + + type1.getName(), ase); + } + throw ase; // No, so rethrow original + } + return joinedArray; + } + + public static boolean[] clone(final boolean[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static byte[] clone(final byte[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static char[] clone(final char[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static double[] clone(final double[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static float[] clone(final float[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static int[] clone(final int[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static long[] clone(final long[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static short[] clone(final short[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static T[] clone(final T[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + public static void reverse(final boolean[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final byte[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final char[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final double[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final float[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final int[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final long[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final short[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final Object[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + public static void reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + boolean tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final byte[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + byte tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final char[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + char tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final double[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + double tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final float[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + float tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final int[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + int tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final long[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + long tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final short[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + short tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + public static void reverse(final Object[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + Object tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } +} + + diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java index db4ac804f..e6731b08a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java @@ -316,6 +316,16 @@ public final class Lang { }; } + @SafeVarargs + public static Consumer compose(Consumer... consumers) { + return t -> { + for (Consumer consumer : consumers) { + consumer.accept(t); + } + }; + } + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public static Stream toStream(Optional optional) { return optional.map(Stream::of).orElseGet(Stream::empty); }