diff --git a/common/addons/biome-provider-image-v2/src/main/java/com/dfsek/terra/addons/biome/image/v2/config/converter/mapping/DefinedBiomeColorMappingTemplate.java b/common/addons/biome-provider-image-v2/src/main/java/com/dfsek/terra/addons/biome/image/v2/config/converter/mapping/DefinedBiomeColorMappingTemplate.java index 88dbb82b2..ea650d424 100644 --- a/common/addons/biome-provider-image-v2/src/main/java/com/dfsek/terra/addons/biome/image/v2/config/converter/mapping/DefinedBiomeColorMappingTemplate.java +++ b/common/addons/biome-provider-image-v2/src/main/java/com/dfsek/terra/addons/biome/image/v2/config/converter/mapping/DefinedBiomeColorMappingTemplate.java @@ -5,6 +5,7 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import java.util.Map; +import com.dfsek.terra.addons.image.config.ColorLoader.ColorString; import com.dfsek.terra.addons.image.converter.mapping.ColorMapping; import com.dfsek.terra.addons.image.util.MapUtil; import com.dfsek.terra.api.world.biome.Biome; @@ -13,11 +14,11 @@ import com.dfsek.terra.api.world.biome.Biome; public class DefinedBiomeColorMappingTemplate implements ObjectTemplate> { @Value("map") - Map map; + Map map; @Override public ColorMapping get() { - var map = MapUtil.mapKeys(this.map, Integer::decode); + var map = MapUtil.mapKeys(this.map, ColorString::getColor); return () -> map; } } diff --git a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/ImageLibraryAddon.java b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/ImageLibraryAddon.java index 20c1d462b..fdcbc701d 100644 --- a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/ImageLibraryAddon.java +++ b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/ImageLibraryAddon.java @@ -4,6 +4,8 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import java.util.function.Supplier; +import com.dfsek.terra.addons.image.config.ColorLoader; +import com.dfsek.terra.addons.image.config.ColorLoader.ColorString; import com.dfsek.terra.addons.image.config.noisesampler.ChannelNoiseSamplerTemplate; import com.dfsek.terra.addons.image.config.noisesampler.DistanceTransformNoiseSamplerTemplate; import com.dfsek.terra.addons.image.config.image.ImageTemplate; @@ -61,7 +63,8 @@ public class ImageLibraryAddon implements AddonInitializer { .applyLoader(DistanceTransform.CostFunction.class, (type, o, loader, depthTracker) -> DistanceTransform.CostFunction.valueOf((String) o)) .applyLoader(DistanceTransform.Normalization.class, - (type, o, loader, depthTracker) -> DistanceTransform.Normalization.valueOf((String) o)); + (type, o, loader, depthTracker) -> DistanceTransform.Normalization.valueOf((String) o)) + .applyLoader(ColorString.class, new ColorLoader()); CheckedRegistry>> noiseRegistry = event.getPack().getOrCreateRegistry( NOISE_SAMPLER_TOKEN); diff --git a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/ColorLoader.java b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/ColorLoader.java new file mode 100644 index 000000000..76b069c68 --- /dev/null +++ b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/ColorLoader.java @@ -0,0 +1,92 @@ +package com.dfsek.terra.addons.image.config; + +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; +import com.dfsek.tectonic.api.loader.ConfigLoader; +import com.dfsek.tectonic.api.loader.type.TypeLoader; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.AnnotatedType; + +import com.dfsek.terra.addons.image.config.ColorLoader.ColorString; +import com.dfsek.terra.addons.image.util.ColorUtil; + + +public class ColorLoader implements TypeLoader { + + @Override + public ColorString load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader, + DepthTracker depthTracker) throws LoadException { + return new ColorString((String) o); + } + + public static class ColorString { + + private final int argb; + + public ColorString(String string) throws IllegalArgumentException { + this.argb = parse(string); + } + + public int getColor() { + return argb; + } + + private static int parse(String string) throws IllegalArgumentException { + if (string.length() == 0) + throw new IllegalArgumentException("Empty string cannot be parsed as a valid color"); + + String[] split = string.split(","); + + if (split.length == 1) + return parseHex(string); + else if (split.length == 3) + return parseChannels("255", split[0], split[1], split[2]); + else if (split.length == 4) + return parseChannels(split[0], split[1], split[2], split[3]); + else + throw new IllegalArgumentException("Invalid channels provided, required format RED,GREEN,BLUE or ALPHA,RED,GREEN,BLUE"); + } + + private static int parseHex(String hex) throws IllegalArgumentException { + if (hex.startsWith("#")) + hex = hex.substring(1); + + int alpha = 255; + int red = 0; + int green = 0; + int blue = 0; + + try { + if(hex.length() == 8) { + alpha = Integer.parseInt(hex.substring(0, 2), 16); + hex = hex.substring(2); + } + + if(hex.length() != 6) + throw new IllegalArgumentException("Invalid color channels, required format AARRGGBB or RRGGBB"); + + red = Integer.parseInt(hex.substring(0, 2), 16); + green = Integer.parseInt(hex.substring(2, 4), 16); + blue = Integer.parseInt(hex.substring(4, 6), 16); + + return ColorUtil.rgbValidated(alpha, red, green, blue); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Failed to parse hex color", e); + } + } + + private static int parseChannels(String alpha, String red, String green, String blue) throws IllegalArgumentException { + try { + int a = Integer.decode(alpha); + int r = Integer.decode(red); + int g = Integer.decode(green); + int b = Integer.decode(blue); + + return ColorUtil.rgbValidated(a, r, g, b); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid channel value", e); + } + } + } +} diff --git a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/colorsampler/ConstantColorSamplerTemplate.java b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/colorsampler/ConstantColorSamplerTemplate.java index 4a07edd3f..61702340b 100644 --- a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/colorsampler/ConstantColorSamplerTemplate.java +++ b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/config/colorsampler/ConstantColorSamplerTemplate.java @@ -4,15 +4,16 @@ import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import com.dfsek.terra.addons.image.colorsampler.ColorSampler; +import com.dfsek.terra.addons.image.config.ColorLoader.ColorString; public class ConstantColorSamplerTemplate implements ObjectTemplate { @Value("color") - private int color; + private ColorString color; @Override public ColorSampler get() { - return ((x, z) -> color); + return ((x, z) -> color.argb()); } } diff --git a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/util/ColorUtil.java b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/util/ColorUtil.java index fd06a3fbd..fed9ee4ee 100644 --- a/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/util/ColorUtil.java +++ b/common/addons/library-image/src/main/java/com/dfsek/terra/addons/image/util/ColorUtil.java @@ -76,6 +76,15 @@ public class ColorUtil { return rgbAlpha(alpha) | rgbRed(red) | rgbGreen(green) | rgbBlue(blue); } + public static int rgbValidated(int alpha, int red, int green, int blue) throws IllegalArgumentException { + if (alpha < 0 || alpha > 255 || + red < 0 || red > 255 || + green < 0 || green > 255 || + blue < 0 || blue > 255 + ) throw new IllegalArgumentException("Channel values must be in range 0-255"); + return rgb(alpha, red, green, blue); + } + public static int rgbAlpha(int alpha) { return alpha << 24; } public static int rgbRed(int red) { return red << 16; }