diff --git a/src/main/java/com/volmit/iris/core/loader/ImageResourceLoader.java b/src/main/java/com/volmit/iris/core/loader/ImageResourceLoader.java new file mode 100644 index 000000000..e525e4ffe --- /dev/null +++ b/src/main/java/com/volmit/iris/core/loader/ImageResourceLoader.java @@ -0,0 +1,150 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * 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 com.volmit.iris.core.loader; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.engine.object.IrisImage; +import com.volmit.iris.engine.object.IrisObject; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.data.KCache; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; + +public class ImageResourceLoader extends ResourceLoader { + public ImageResourceLoader(File root, IrisData idm, String folderName, String resourceTypeName) { + super(root, idm, folderName, resourceTypeName, IrisImage.class); + loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getObjectLoaderCacheSize()); + } + + public boolean supportsSchemas() { + return false; + } + + public long getSize() { + return loadCache.getSize(); + } + + public long getTotalStorage() { + return getSize(); + } + + protected IrisImage loadFile(File j, String name) { + try { + PrecisionStopwatch p = PrecisionStopwatch.start(); + BufferedImage bu = ImageIO.read(j); + IrisImage img = new IrisImage(bu); + img.setLoadFile(j); + img.setLoader(manager); + img.setLoadKey(name); + logLoad(j, img); + tlt.addAndGet(p.getMilliseconds()); + return img; + } catch (Throwable e) { + Iris.reportError(e); + Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage()); + return null; + } + } + + public String[] getPossibleKeys() { + if (possibleKeys != null) { + return possibleKeys; + } + + Iris.debug("Building " + resourceTypeName + " Possibility Lists"); + KSet m = new KSet<>(); + + for (File i : getFolders()) { + for (File j : i.listFiles()) { + if (j.isFile() && j.getName().endsWith(".png")) { + m.add(j.getName().replaceAll("\\Q.png\\E", "")); + } else if (j.isDirectory()) { + for (File k : j.listFiles()) { + if (k.isFile() && k.getName().endsWith(".png")) { + m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.png\\E", "")); + } else if (k.isDirectory()) { + for (File l : k.listFiles()) { + if (l.isFile() && l.getName().endsWith(".png")) { + m.add(j.getName() + "/" + k.getName() + "/" + l.getName().replaceAll("\\Q.png\\E", "")); + } + } + } + } + } + } + } + + KList v = new KList<>(m); + possibleKeys = v.toArray(new String[0]); + return possibleKeys; + } + + public File findFile(String name) { + for (File i : getFolders(name)) { + for (File j : i.listFiles()) { + if (j.isFile() && j.getName().endsWith(".png") && j.getName().split("\\Q.\\E")[0].equals(name)) { + return j; + } + } + + File file = new File(i, name + ".png"); + + if (file.exists()) { + return file; + } + } + + Iris.warn("Couldn't find " + resourceTypeName + ": " + name); + + return null; + } + + public IrisImage load(String name) { + return load(name, true); + } + + private IrisImage loadRaw(String name) { + for (File i : getFolders(name)) { + for (File j : i.listFiles()) { + if (j.isFile() && j.getName().endsWith(".png") && j.getName().split("\\Q.\\E")[0].equals(name)) { + return loadFile(j, name); + } + } + + File file = new File(i, name + ".png"); + + if (file.exists()) { + return loadFile(file, name); + } + } + + Iris.warn("Couldn't find " + resourceTypeName + ": " + name); + + return null; + } + + public IrisImage load(String name, boolean warn) { + return loadCache.get(name); + } +} diff --git a/src/main/java/com/volmit/iris/core/loader/IrisData.java b/src/main/java/com/volmit/iris/core/loader/IrisData.java index 79ff87dae..c29196199 100644 --- a/src/main/java/com/volmit/iris/core/loader/IrisData.java +++ b/src/main/java/com/volmit/iris/core/loader/IrisData.java @@ -38,6 +38,7 @@ import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisEntity; import com.volmit.iris.engine.object.IrisExpression; import com.volmit.iris.engine.object.IrisGenerator; +import com.volmit.iris.engine.object.IrisImage; import com.volmit.iris.engine.object.IrisJigsawPiece; import com.volmit.iris.engine.object.IrisJigsawPool; import com.volmit.iris.engine.object.IrisJigsawStructure; @@ -86,6 +87,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { private ResourceLoader blockLoader; private ResourceLoader expressionLoader; private ResourceLoader objectLoader; + private ResourceLoader imageLoader; private ResourceLoader scriptLoader; private ResourceLoader caveLoader; private ResourceLoader ravineLoader; @@ -186,6 +188,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false)); } + public static IrisImage loadAnyImage(String key) { + return loadAny(key, (dm) -> dm.getImageLoader().load(key, false)); + } + public static IrisDimension loadAnyDimension(String key) { return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false)); } @@ -336,6 +342,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { this.blockLoader = registerLoader(IrisBlockData.class); this.expressionLoader = registerLoader(IrisExpression.class); this.objectLoader = registerLoader(IrisObject.class); + this.imageLoader = registerLoader(IrisImage.class); this.scriptLoader = registerLoader(IrisScript.class); gson = builder.create(); } diff --git a/src/main/java/com/volmit/iris/engine/object/IrisImage.java b/src/main/java/com/volmit/iris/engine/object/IrisImage.java new file mode 100644 index 000000000..f09d1488a --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/object/IrisImage.java @@ -0,0 +1,116 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * 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 com.volmit.iris.engine.object; + +import com.volmit.iris.core.loader.IrisRegistrant; +import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.plugin.VolmitSender; + +import java.awt.Color; +import java.awt.image.BufferedImage; + +public class IrisImage extends IrisRegistrant { + private BufferedImage image; + + public int getRawValue(int x, int z) + { + if(x >= w || z >= h || x < 0 || z < 0) + { + return 0; + } + + return image.getRGB(x, z); + } + + public double getValue(IrisImageChannel channel, int x, int z) + { + int color = getRawValue(x + (image.getWidth()/2), z + (image.getHeight()/2)); + + switch(channel) + { + case RED -> { + return ((color >> 16) & 0xFF) / 255D; + } + case GREEN -> { + return ((color >> 8) & 0xFF) / 255D; + } + case BLUE -> { + return ((color >> 0) & 0xFF) / 255D; + } + case SATURATION -> { + return Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color >> 0) & 0xFF, null)[1]; + } + case HUE -> { + return Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color >> 0) & 0xFF, null)[0]; + } + case BRIGHTNESS -> { + return Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color >> 0) & 0xFF, null)[2]; + } + case COMPOSITE_ADD_RGB -> { + return ((((color >> 16) & 0xFF) / 255D) + (((color >> 8) & 0xFF) / 255D) + (((color >> 0) & 0xFF) / 255D)) / 3D; + } + case COMPOSITE_MUL_RGB -> { + return (((color >> 16) & 0xFF) / 255D) * (((color >> 8) & 0xFF) / 255D) * (((color >> 0) & 0xFF) / 255D); + } + case COMPOSITE_MAX_RGB -> { + return Math.max(Math.max((((color >> 16) & 0xFF) / 255D), (((color >> 8) & 0xFF) / 255D)), (((color >> 0) & 0xFF) / 255D)); + } + case COMPOSITE_ADD_HSB -> { + float[] hsb = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color >> 0) & 0xFF, null); + return (hsb[0] + hsb[1] + hsb[2]) / 3D; + } + case COMPOSITE_MUL_HSB -> { + float[] hsb = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color >> 0) & 0xFF, null); + return hsb[0] * hsb[1] * hsb[2]; + } + case COMPOSITE_MAX_HSB -> { + float[] hsb = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color >> 0) & 0xFF, null); + return Math.max(hsb[0], Math.max(hsb[1], hsb[2])); + } + case RAW -> { + return color; + } + } + } + + public IrisImage() + { + this(new BufferedImage(4, 4, BufferedImage.TYPE_INT_RGB)); + } + + public IrisImage(BufferedImage image) + { + this.image = image; + } + + @Override + public String getFolderName() { + return "images"; + } + + @Override + public String getTypeName() { + return "Image"; + } + + @Override + public void scanForErrors(JSONObject p, VolmitSender sender) { + + } +}