From cf556dd0fdf2d5bf142fdff0c39d3711232d67e3 Mon Sep 17 00:00:00 2001 From: Juuxel <6596629+Juuxel@users.noreply.github.com> Date: Thu, 23 Jan 2020 22:13:53 +0200 Subject: Add support for loading nine-patch metadata from resource packs --- .../cotton/gui/client/BackgroundPainter.java | 60 +++++++++----- .../cottonmc/cotton/gui/client/LibGuiClient.java | 4 + .../cotton/gui/client/NinePatchMetadataLoader.java | 91 ++++++++++++++++++++++ 3 files changed, 136 insertions(+), 19 deletions(-) create mode 100644 src/main/java/io/github/cottonmc/cotton/gui/client/NinePatchMetadataLoader.java (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java b/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java index 65cf95f..24cf6ab 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java @@ -5,6 +5,8 @@ import io.github.cottonmc.cotton.gui.widget.WWidget; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; +import javax.annotation.Nullable; + /** * Background painters are used to paint the background of a widget. * The background painter instance of a widget can be changed to customize the look of a widget. @@ -128,11 +130,30 @@ public interface BackgroundPainter { * *

Nine-patch textures are separated into nine sections: four corners, four edges and a center part. * The edges and the center are either tiled or stretched, depending on the {@linkplain BackgroundPainter.NinePatch.Mode mode}, - * to fill the area between the corners. The default mode is {@link BackgroundPainter.NinePatch.Mode#TILING}. + * to fill the area between the corners. By default, the texture mode is loaded from the texture metadata. + * The default mode for that is {@link BackgroundPainter.NinePatch.Mode#STRETCHING}. * *

{@code NinePatch} painters have a customizable padding that can be applied. * For example, a GUI panel for a container block might have a padding of 8 pixels, like {@link BackgroundPainter#VANILLA}. * You can set the padding using {@link NinePatch#setPadding(int)}. + * + *

Nine-patch metadata

+ * You can specify metadata for a nine-patch texture in a resource pack by creating a metadata file. + * Metadata files can currently specify the filling mode of the painter that paints the texture. + *

The metadata file for a texture has to be placed in the same directory as the texture. + * The file name must be {@code X.9patch} where X is the texture file name (including .png). + *

Metadata files use {@linkplain java.util.Properties .properties format} with the following keys: + * + * + * + * + * + * + * + * + * + * + *
Properties
KeyValue
{@code mode}{@link Mode#STRETCHING stretching} | {@link Mode#TILING tiling}
*/ public static class NinePatch implements BackgroundPainter { private final Identifier texture; @@ -142,7 +163,7 @@ public interface BackgroundPainter { private int leftPadding = 0; private int bottomPadding = 0; private int rightPadding = 0; - private Mode mode = Mode.STRETCHING; + private Mode mode = null; /** * Creates a nine-patch background painter with 4 px corners and a 0.25 cornerUv (corner fraction of whole texture). @@ -234,28 +255,18 @@ public interface BackgroundPainter { return cornerUv; } + @Nullable public Mode getMode() { return mode; } - public NinePatch setMode(Mode mode) { - this.mode = mode; - return this; - } - - /** - * Sets the {@linkplain Mode mode} of this painter to {@link Mode#STRETCHING}. - */ - public NinePatch stretch() { - this.mode = Mode.STRETCHING; - return this; - } - /** - * Sets the {@linkplain Mode mode} of this painter to {@link Mode#TILING}. + * Sets the {@linkplain Mode mode} of this painter to the specified mode. + *

If the {@code mode} is not null, it will override the one specified in the texture metadata. + * A null mode uses the texture metadata. */ - public NinePatch tile() { - this.mode = Mode.TILING; + public NinePatch setMode(@Nullable Mode mode) { + this.mode = mode; return this; } @@ -271,6 +282,7 @@ public interface BackgroundPainter { int y2 = top + height - cornerSize; float uv1 = cornerUv; float uv2 = 1.0f - cornerUv; + Mode mode = this.mode != null ? this.mode : NinePatchMetadataLoader.INSTANCE.getProperties(texture).getMode(); ScreenDrawing.texturedRect(left, top, cornerSize, cornerSize, texture, 0, 0, uv1, uv1, 0xFF_FFFFFF); ScreenDrawing.texturedRect(x2, top, cornerSize, cornerSize, texture, uv2, 0, 1, uv1, 0xFF_FFFFFF); @@ -322,14 +334,24 @@ public interface BackgroundPainter { public enum Mode { /** * The texture is stretched to fill the edges and the center. + * This is the default mode. */ STRETCHING, /** * The texture is tiled to fill the edges and the center. - * This is the default mode. */ TILING; + + @Nullable + static Mode fromString(String str) { + if (str == null) return null; + + if (str.equalsIgnoreCase("stretching")) return STRETCHING; + if (str.equalsIgnoreCase("tiling")) return TILING; + + return null; + } } } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiClient.java b/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiClient.java index b06369a..d457e50 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiClient.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiClient.java @@ -5,8 +5,10 @@ import blue.endless.jankson.JsonElement; import blue.endless.jankson.JsonObject; import io.github.cottonmc.jankson.JanksonFactory; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.resource.ResourceType; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -24,6 +26,8 @@ public class LibGuiClient implements ClientModInitializer { @Override public void onInitializeClient() { config = loadConfig(); + + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(NinePatchMetadataLoader.INSTANCE); } public static LibGuiConfig loadConfig() { diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatchMetadataLoader.java b/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatchMetadataLoader.java new file mode 100644 index 0000000..daa1b45 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatchMetadataLoader.java @@ -0,0 +1,91 @@ +package io.github.cottonmc.cotton.gui.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.SinglePreparationResourceReloadListener; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; + +import java.io.InputStream; +import java.util.*; + +@Environment(EnvType.CLIENT) +public class NinePatchMetadataLoader extends SinglePreparationResourceReloadListener> implements IdentifiableResourceReloadListener { + public static final NinePatchMetadataLoader INSTANCE = new NinePatchMetadataLoader(); + + private static final Identifier ID = new Identifier("libgui", "9patch_metadata"); + private static final String SUFFIX = ".9patch"; + + private Map properties = Collections.emptyMap(); + + public TextureProperties getProperties(Identifier texture) { + return properties.getOrDefault(texture, TextureProperties.DEFAULT); + } + + @Override + public Identifier getFabricId() { + return ID; + } + + @Override + protected Map prepare(ResourceManager manager, Profiler profiler) { + Collection ids = manager.findResources("textures", s -> s.endsWith(SUFFIX)); + Map result = new HashMap<>(); + + for (Identifier input : ids) { + try (Resource resource = manager.getResource(input); + InputStream stream = resource.getInputStream()) { + Properties props = new Properties(); + props.load(stream); + Identifier textureId = new Identifier(input.getNamespace(), input.getPath().substring(0, input.getPath().length() - SUFFIX.length())); + result.put(textureId, props); + } catch (Exception e) { + LibGuiClient.logger.error("Error while loading metadata file {}, skipping...", input, e); + } + } + + return result; + } + + @Override + protected void apply(Map meta, ResourceManager manager, Profiler profiler) { + properties = new HashMap<>(); + for (Map.Entry entry : meta.entrySet()) { + Identifier id = entry.getKey(); + Properties props = entry.getValue(); + + if (!props.containsKey("mode")) { + LibGuiClient.logger.error("Metadata file for nine-patch texture {} is missing required key 'mode'", id); + continue; + } + + String modeStr = props.getProperty("mode"); + BackgroundPainter.NinePatch.Mode mode = BackgroundPainter.NinePatch.Mode.fromString(modeStr); + + if (mode == null) { + LibGuiClient.logger.error("Invalid mode '{}' in nine-patch metadata file for texture {}", modeStr, id); + continue; + } + + TextureProperties texProperties = new TextureProperties(mode); + properties.put(id, texProperties); + } + } + + public static class TextureProperties { + public static final TextureProperties DEFAULT = new TextureProperties(BackgroundPainter.NinePatch.Mode.STRETCHING); + + private final BackgroundPainter.NinePatch.Mode mode; + + public TextureProperties(BackgroundPainter.NinePatch.Mode mode) { + this.mode = mode; + } + + public BackgroundPainter.NinePatch.Mode getMode() { + return mode; + } + } +} -- cgit