diff --git a/core/src/main/java/com/boydti/fawe/util/ColorUtil.java b/core/src/main/java/com/boydti/fawe/util/ColorUtil.java new file mode 100644 index 00000000..eecf0ef2 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/ColorUtil.java @@ -0,0 +1,146 @@ +package com.boydti.fawe.util; + +import java.awt.Color; +import java.lang.reflect.Field; +import java.util.Locale; + +public class ColorUtil { + private static final int PARSE_COMPONENT = 0; // percent, or clamped to [0,255] => [0,1] + private static final int PARSE_PERCENT = 1; // clamped to [0,100]% => [0,1] + private static final int PARSE_ANGLE = 2; // clamped to [0,360] + private static final int PARSE_ALPHA = 3; // clamped to [0f,1f] + + private static float parseComponent(String color, int off, int end, int type) { + color = color.substring(off, end).trim(); + if (color.endsWith("%")) { + if (type > PARSE_PERCENT) { + throw new IllegalArgumentException("Invalid color specification"); + } + type = PARSE_PERCENT; + color = color.substring(0, color.length()-1).trim(); + } else if (type == PARSE_PERCENT) { + throw new IllegalArgumentException("Invalid color specification"); + } + float c = ((type == PARSE_COMPONENT) + ? Integer.parseInt(color) + : Float.parseFloat(color)); + switch (type) { + case PARSE_ALPHA: + return (c < 0f) ? 0f : ((c > 1f) ? 1f : c); + case PARSE_PERCENT: + return (c <= 0f) ? 0f : ((c >= 100f) ? 1f : (c / 100f)); + case PARSE_COMPONENT: + return (c <= 0f) ? 0f : ((c >= 255f) ? 1f : (c / 255f)); + case PARSE_ANGLE: + return ((c < 0f) + ? ((c % 360f) + 360f) + : ((c > 360f) + ? (c % 360f) + : c)); + } + + throw new IllegalArgumentException("Invalid color specification"); + } + + private static Color parseRGBColor(String color, int roff) + { + try { + int rend = color.indexOf(',', roff); + int gend = rend < 0 ? -1 : color.indexOf(',', rend+1); + int bend = gend < 0 ? -1 : color.indexOf(gend+1); + float r = parseComponent(color, roff, rend, PARSE_COMPONENT); + float g = parseComponent(color, rend+1, gend, PARSE_COMPONENT); + float b = parseComponent(color, gend+1, bend, PARSE_COMPONENT); + return new Color(r, g, b); + } catch (NumberFormatException nfe) {} + + throw new IllegalArgumentException("Invalid color specification"); + } + + private static Color parseHSLColor(String color, int hoff) + { + try { + int hend = color.indexOf(',', hoff); + int send = hend < 0 ? -1 : color.indexOf(',', hend+1); + int lend = send < 0 ? -1 : color.indexOf(send+1); + float h = parseComponent(color, hoff, hend, PARSE_ANGLE); + float s = parseComponent(color, hend+1, send, PARSE_PERCENT); + float l = parseComponent(color, send+1, lend, PARSE_PERCENT); + return Color.getHSBColor(h, s, l); + } catch (NumberFormatException nfe) {} + + throw new IllegalArgumentException("Invalid color specification"); + } + + public static Color parseColor(String colorString) { + if (colorString == null) { + throw new NullPointerException( + "The color components or name must be specified"); + } + if (colorString.isEmpty()) { + throw new IllegalArgumentException("Invalid color specification"); + } + + String color = colorString.toLowerCase(Locale.ROOT); + + if (color.startsWith("#")) { + color = color.substring(1); + } else if (color.startsWith("0x")) { + color = color.substring(2); + } else if (color.startsWith("rgb")) { + if (color.startsWith("(", 3)) { + return parseRGBColor(color, 4); + } else if (color.startsWith("a(", 3)) { + return parseRGBColor(color, 5); + } + } else if (color.startsWith("hsl")) { + if (color.startsWith("(", 3)) { + return parseHSLColor(color, 4); + } else if (color.startsWith("a(", 3)) { + return parseHSLColor(color, 5); + } + } else { + Color col = null; + try { + Field field = java.awt.Color.class.getField(color.toLowerCase()); + col = (Color) field.get(null); + } catch (Throwable ignore) {} + if (col != null) { + return col; + } + } + + int len = color.length(); + + try { + int r; + int g; + int b; + int a; + + if (len == 3) { + r = Integer.parseInt(color.substring(0, 1), 16); + g = Integer.parseInt(color.substring(1, 2), 16); + b = Integer.parseInt(color.substring(2, 3), 16); + return new Color(r / 15f, g / 15f, b / 15f); + } else if (len == 4) { + r = Integer.parseInt(color.substring(0, 1), 16); + g = Integer.parseInt(color.substring(1, 2), 16); + b = Integer.parseInt(color.substring(2, 3), 16); + return new Color(r / 15f, g / 15f, b / 15f); + } else if (len == 6) { + r = Integer.parseInt(color.substring(0, 2), 16); + g = Integer.parseInt(color.substring(2, 4), 16); + b = Integer.parseInt(color.substring(4, 6), 16); + return new Color(r, g, b); + } else if (len == 8) { + r = Integer.parseInt(color.substring(0, 2), 16); + g = Integer.parseInt(color.substring(2, 4), 16); + b = Integer.parseInt(color.substring(4, 6), 16); + return new Color(r, g, b); + } + } catch (NumberFormatException nfe) {} + + throw new IllegalArgumentException("Invalid color specification"); + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 4d6c98cc..77e26fc4 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -49,6 +49,7 @@ import com.boydti.fawe.object.brush.SurfaceSphereBrush; import com.boydti.fawe.object.brush.SurfaceSpline; import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap; import com.boydti.fawe.object.mask.IdMask; +import com.boydti.fawe.util.ColorUtil; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandLocals; @@ -85,6 +86,7 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.InvalidUsageException; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; +import java.awt.Color; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -95,7 +97,6 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.ArrayList; import java.util.List; -import javafx.scene.paint.Color; /** * Commands to set brush shape. @@ -447,9 +448,8 @@ public class BrushCommands extends MethodCommands { throw new InvalidUsageException(getCallable()); } try { - Color color = Color.web(args.getString(1)); - java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity()); - char[] glassLayers = Fawe.get().getTextureUtil().getNearestLayer(awtColor.getRGB()); + Color color = ColorUtil.parseColor(args.getString(1)); + char[] glassLayers = Fawe.get().getTextureUtil().getNearestLayer(color.getRGB()); for (char layer : glassLayers) { blocks.add(FaweCache.CACHE_BLOCK[layer]); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index f77965e3..1497d9ad 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -32,6 +32,7 @@ import com.boydti.fawe.object.pattern.ShadePattern; import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern; import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern; import com.boydti.fawe.object.random.SimplexRandom; +import com.boydti.fawe.util.ColorUtil; import com.boydti.fawe.util.TextureUtil; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.worldedit.EmptyClipboardException; @@ -54,12 +55,18 @@ import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.biome.BaseBiome; +import java.awt.Color; import java.io.IOException; import java.util.Set; -import javafx.scene.paint.Color; @Command(aliases = {"patterns"}, - desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)" + desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)", + help = "Patterns determine what blocks are placed\n" + + " - Use [brackets] for arguments\n" + + " - Use , to OR multiple\n" + + "e.g. #surfacespread[10][#existing],andesite\n" + + "More Info: https://git.io/vSPmA" + ) public class PatternCommands extends MethodCommands { public PatternCommands(WorldEdit worldEdit) { @@ -106,9 +113,8 @@ public class PatternCommands extends MethodCommands { max = 1 ) public Pattern color(String arg) { - Color color = Color.web(arg); - java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity()); - return Fawe.get().getTextureUtil().getNearestBlock(awtColor.getRGB()); + Color color = ColorUtil.parseColor(arg); + return Fawe.get().getTextureUtil().getNearestBlock(color.getRGB()); } @Command( @@ -140,9 +146,8 @@ public class PatternCommands extends MethodCommands { ) public Pattern saturate(Extent extent, String arg, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) { TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity); - Color color = Color.web(arg); - java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity()); - return new SaturatePattern(extent, awtColor.getRGB(), (int) maxComplexity, randomize); + Color color = ColorUtil.parseColor(arg); + return new SaturatePattern(extent, color.getRGB(), (int) maxComplexity, randomize); } @Command( @@ -154,9 +159,8 @@ public class PatternCommands extends MethodCommands { ) public Pattern averagecolor(Extent extent, String arg, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) { TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity); - Color color = Color.web(arg); - java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity()); - return new AverageColorPattern(extent, awtColor.getRGB(), (int) maxComplexity, randomize); + Color color = ColorUtil.parseColor(arg); + return new AverageColorPattern(extent, color.getRGB(), (int) maxComplexity, randomize); } @Command(