diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index d2023649..1b55f351 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java @@ -5,6 +5,7 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.PseudoRandom; import com.boydti.fawe.util.CachedTextureUtil; import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.RandomTextureUtil; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MutableBlockVector; import com.sk89q.worldedit.Vector; @@ -238,20 +239,25 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent { } public void setColor(BufferedImage img) { - CachedTextureUtil textureUtil = new CachedTextureUtil(Fawe.get().getTextureUtil()); - if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!"); - int index = 0; - for (int y = 0; y < img.getHeight(); y++) { - for (int x = 0; x < img.getWidth(); x++) { - int color = img.getRGB(x, y); - BaseBlock block = textureUtil.getNearestBlock(color); - if (block == null) { - continue; + try { + RandomTextureUtil textureUtil = new RandomTextureUtil(Fawe.get().getTextureUtil()); + if (img.getWidth() != getWidth() || img.getHeight() != getLength()) + throw new IllegalArgumentException("Input image dimensions do not match the current height map!"); + int index = 0; + for (int y = 0; y < img.getHeight(); y++) { + for (int x = 0; x < img.getWidth(); x++) { + int color = img.getRGB(x, y); + BaseBlock block = textureUtil.getNearestBlock(color); + if (block == null) { + continue; + } + char combined = (char) block.getCombined(); + main[index] = combined; + floor[index++] = combined; } - char combined = (char) block.getCombined(); - main[index] = combined; - floor[index++] = combined; } + } catch (Throwable e) { + e.printStackTrace(); } } diff --git a/core/src/main/java/com/boydti/fawe/util/CachedTextureUtil.java b/core/src/main/java/com/boydti/fawe/util/CachedTextureUtil.java index 9f7016fd..9b36f47e 100644 --- a/core/src/main/java/com/boydti/fawe/util/CachedTextureUtil.java +++ b/core/src/main/java/com/boydti/fawe/util/CachedTextureUtil.java @@ -2,71 +2,27 @@ package com.boydti.fawe.util; import com.boydti.fawe.FaweCache; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.world.registry.BundledBlockData; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import org.json.simple.parser.ParseException; -public class CachedTextureUtil extends TextureUtil { +public class CachedTextureUtil extends DelegateTextureUtil { private final TextureUtil parent; private Int2ObjectOpenHashMap colorBlockMap; private Int2ObjectOpenHashMap colorLayerMap; - private int[] validLayerColors; - private char[][] validLayerBlocks; - public CachedTextureUtil(TextureUtil parent) { - super(parent.getFolder()); + super(parent); this.parent = parent; this.colorBlockMap = new Int2ObjectOpenHashMap<>(); this.colorLayerMap = new Int2ObjectOpenHashMap<>(); - Int2ObjectOpenHashMap colorLayerMap = new Int2ObjectOpenHashMap<>(); - for (int i = 0; i < parent.validBlockIds.length; i++) { - int color = parent.validColors[i]; - int combined = parent.validBlockIds[i]; - if (hasAlpha(color)) { - for (int j = 0; j < parent.validBlockIds.length; j++) { - int colorOther = parent.validColors[j]; - if (!hasAlpha(colorOther)) { - int combinedOther = parent.validBlockIds[j]; - int combinedColor = combine(color, colorOther); - colorLayerMap.put(combinedColor, new char[] {(char) combined, (char) combinedOther}); - } - } - } - } - this.validLayerColors = new int[colorLayerMap.size()]; - this.validLayerBlocks = new char[colorLayerMap.size()][]; - int index = 0; - for (Int2ObjectMap.Entry entry : colorLayerMap.int2ObjectEntrySet()) { - validLayerColors[index] = entry.getIntKey(); - validLayerBlocks[index++] = entry.getValue(); - } } + @Override public char[] getNearestLayer(int color) { char[] closest = colorLayerMap.get(color); if (closest != null) { return closest; } - long min = Long.MAX_VALUE; - int red1 = (color >> 16) & 0xFF; - int green1 = (color >> 8) & 0xFF; - int blue1 = (color >> 0) & 0xFF; - int alpha = (color >> 24) & 0xFF; - for (int i = 0; i < validLayerColors.length; i++) { - int other = validLayerColors[i]; - if (((other >> 24) & 0xFF) == alpha) { - long distance = colorDistance(red1, green1, blue1, other); - if (distance < min) { - min = distance; - closest = validLayerBlocks[i]; - } - } - } + closest = parent.getNearestLayer(color); if (closest != null) { colorLayerMap.put(color, closest); } @@ -85,49 +41,4 @@ public class CachedTextureUtil extends TextureUtil { } return result; } - - @Override - public BaseBlock getDarkerBlock(BaseBlock block) { - return parent.getDarkerBlock(block); - } - - @Override - public int getColor(BaseBlock block) { - return parent.getColor(block); - } - - @Override - public File getFolder() { - return parent.getFolder(); - } - - @Override - public void loadModTextures() throws IOException, ParseException { - parent.loadModTextures(); - } - - @Override - public BaseBlock getNearestBlock(BaseBlock block, boolean darker) { - return parent.getNearestBlock(block, darker); - } - - @Override - public BaseBlock getNearestBlock(int color, boolean darker) { - return parent.getNearestBlock(color, darker); - } - - @Override - public long colorDistance(int c1, int c2) { - return parent.colorDistance(c1, c2); - } - - @Override - public int getColor(BufferedImage image) { - return parent.getColor(image); - } - - @Override - public BaseBlock getLighterBlock(BaseBlock block) { - return parent.getLighterBlock(block); - } } diff --git a/core/src/main/java/com/boydti/fawe/util/DelegateTextureUtil.java b/core/src/main/java/com/boydti/fawe/util/DelegateTextureUtil.java new file mode 100644 index 00000000..cb1ed5eb --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/DelegateTextureUtil.java @@ -0,0 +1,86 @@ +package com.boydti.fawe.util; + +import com.sk89q.worldedit.blocks.BaseBlock; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import org.json.simple.parser.ParseException; + +public class DelegateTextureUtil extends TextureUtil { + private final TextureUtil parent; + + public DelegateTextureUtil(TextureUtil parent) { + super(parent.getFolder()); + this.parent = parent; + } + + @Override + public BaseBlock getNearestBlock(int color) { + return parent.getNearestBlock(color); + } + + @Override + public char[] getNearestLayer(int color) { + return parent.getNearestLayer(color); + } + + @Override + public BaseBlock getLighterBlock(BaseBlock block) { + return parent.getLighterBlock(block); + } + + @Override + public BaseBlock getDarkerBlock(BaseBlock block) { + return parent.getDarkerBlock(block); + } + + @Override + public int getColor(BaseBlock block) { + return parent.getColor(block); + } + + @Override + public File getFolder() { + return parent.getFolder(); + } + + @Override + public int combineTransparency(int top, int bottom) { + return parent.combineTransparency(top, bottom); + } + + @Override + public void loadModTextures() throws IOException, ParseException { + parent.loadModTextures(); + } + + @Override + public BaseBlock getNearestBlock(BaseBlock block, boolean darker) { + return parent.getNearestBlock(block, darker); + } + + @Override + public BaseBlock getNearestBlock(int color, boolean darker) { + return parent.getNearestBlock(color, darker); + } + + @Override + public boolean hasAlpha(int color) { + return parent.hasAlpha(color); + } + + @Override + public long colorDistance(int c1, int c2) { + return parent.colorDistance(c1, c2); + } + + @Override + public long colorDistance(int red1, int green1, int blue1, int c2) { + return parent.colorDistance(red1, green1, blue1, c2); + } + + @Override + public int getColor(BufferedImage image) { + return parent.getColor(image); + } +} diff --git a/core/src/main/java/com/boydti/fawe/util/MathMan.java b/core/src/main/java/com/boydti/fawe/util/MathMan.java index 351528fa..aefc29b6 100644 --- a/core/src/main/java/com/boydti/fawe/util/MathMan.java +++ b/core/src/main/java/com/boydti/fawe/util/MathMan.java @@ -82,7 +82,7 @@ public class MathMan { } public static int clamp(int check, int min, int max) { - return check > max?max:(check < min?min:check); + return check > max ? max : (check < min ? min : check); } static { diff --git a/core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java b/core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java new file mode 100644 index 00000000..7cff4948 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java @@ -0,0 +1,55 @@ +package com.boydti.fawe.util; + +import com.boydti.fawe.object.PseudoRandom; +import com.sk89q.worldedit.blocks.BaseBlock; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public class RandomTextureUtil extends CachedTextureUtil { + + public RandomTextureUtil(TextureUtil parent) { + super(parent); + } + + private Int2ObjectOpenHashMap offsets = new Int2ObjectOpenHashMap<>(); + + protected int addRandomColor(int c1, int c2) { + int red1 = (c1 >> 16) & 0xFF; + int green1 = (c1 >> 8) & 0xFF; + int blue1 = (c1 >> 0) & 0xFF; + byte red2 = (byte) ((c2 >> 16)); + byte green2 = (byte) ((c2 >> 8)); + byte blue2 = (byte) ((c2 >> 0)); + int red = MathMan.clamp(red1 + random(red2), 0, 255); + int green = MathMan.clamp(green1 + random(green2), 0, 255); + int blue = MathMan.clamp(blue1 + random(blue2), 0, 255); + return (red << 16) + (green << 8) + (blue << 0) + (255 << 24); + } + + + private int random(int i) { + if (i < 0) { + return -PseudoRandom.random.nextInt(-i); + } else { + return PseudoRandom.random.nextInt(i); + } + } + + @Override + public BaseBlock getNearestBlock(int color) { + int offsetColor = offsets.getOrDefault(color, 0); + if (offsetColor != 0) { + offsetColor = addRandomColor(color, offsetColor); + } else { + offsetColor = color; + } + BaseBlock res = super.getNearestBlock(offsetColor); + int newColor = getColor(res); + { + byte dr = (byte) (((color >> 16) & 0xFF) - ((newColor >> 16) & 0xFF)); + byte dg = (byte) (((color >> 8) & 0xFF) - ((newColor >> 8) & 0xFF)); + byte db = (byte) (((color >> 0) & 0xFF) - ((newColor >> 0) & 0xFF)); + offsets.put(color, (Integer) ((dr << 16) + (dg << 8) + (db << 0))); + } + return res; + } +} diff --git a/core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 168c6641..01e828c2 100644 --- a/core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -37,6 +37,8 @@ public class TextureUtil { protected int[] blockColors = new int[Character.MAX_VALUE + 1]; protected int[] validColors; protected char[] validBlockIds; + protected int[] validLayerColors; + protected char[][] validLayerBlocks; public TextureUtil() { this(MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.TEXTURES)); @@ -67,6 +69,31 @@ public class TextureUtil { return FaweCache.CACHE_BLOCK[closest]; } + /** + * Returns the block combined ids as an array + * @param color + * @return + */ + public char[] getNearestLayer(int color) { + char[] closest = null; + long min = Long.MAX_VALUE; + int red1 = (color >> 16) & 0xFF; + int green1 = (color >> 8) & 0xFF; + int blue1 = (color >> 0) & 0xFF; + int alpha = (color >> 24) & 0xFF; + for (int i = 0; i < validLayerColors.length; i++) { + int other = validLayerColors[i]; + if (((other >> 24) & 0xFF) == alpha) { + long distance = colorDistance(red1, green1, blue1, other); + if (distance < min) { + min = distance; + closest = validLayerBlocks[i]; + } + } + } + return closest; + } + public BaseBlock getLighterBlock(BaseBlock block) { return getNearestBlock(block, false); } @@ -83,7 +110,10 @@ public class TextureUtil { return folder; } - protected int combine(int top, int bottom) { + /** + * Assumes the top layer is a transparent color and the bottom is opaque + */ + protected int combineTransparency(int top, int bottom) { int alpha1 = (top >> 24) & 0xFF; int alpha2 = 255 - alpha1; int red1 = (top >> 16) & 0xFF; @@ -98,6 +128,31 @@ public class TextureUtil { return (red << 16) + (green << 8) + (blue << 0) + (255 << 24); } + private void calculateLayerArrays() { + Int2ObjectOpenHashMap colorLayerMap = new Int2ObjectOpenHashMap<>(); + for (int i = 0; i < validBlockIds.length; i++) { + int color = validColors[i]; + int combined = validBlockIds[i]; + if (hasAlpha(color)) { + for (int j = 0; j < validBlockIds.length; j++) { + int colorOther = validColors[j]; + if (!hasAlpha(colorOther)) { + int combinedOther = validBlockIds[j]; + int combinedColor = combineTransparency(color, colorOther); + colorLayerMap.put(combinedColor, new char[] {(char) combined, (char) combinedOther}); + } + } + } + } + this.validLayerColors = new int[colorLayerMap.size()]; + this.validLayerBlocks = new char[colorLayerMap.size()][]; + int index = 0; + for (Int2ObjectMap.Entry entry : colorLayerMap.int2ObjectEntrySet()) { + validLayerColors[index] = entry.getIntKey(); + validLayerBlocks[index++] = entry.getValue(); + } + } + public void loadModTextures() throws IOException, ParseException { Int2ObjectOpenHashMap colorMap = new Int2ObjectOpenHashMap<>(); if (folder.exists()) { @@ -243,6 +298,7 @@ public class TextureUtil { validColors[index] = color; index++; } + calculateLayerArrays(); } protected BaseBlock getNearestBlock(BaseBlock block, boolean darker) { diff --git a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 9c46336f..259b311e 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -401,26 +401,26 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return contains(position.getBlockX(), position.getBlockY(), position.getBlockZ()); } - private int ly = Integer.MIN_VALUE; - private int lz = Integer.MIN_VALUE; - private boolean lr, lry, lrz; +// private int ly = Integer.MIN_VALUE; +// private int lz = Integer.MIN_VALUE; +// private boolean lr, lry, lrz; public boolean contains(int x, int y, int z) { -// return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ && y >= this.minY && y <= this.maxY; - if (z != lz) { - lz = z; - lrz = z >= this.minZ && z <= this.maxZ; - if (y != ly) { - ly = y; - lry = y >= this.minY && y <= this.maxY; - } - lr = lrz && lry; - } else if (y != ly) { - ly = y; - lry = y >= this.minY && y <= this.maxY; - lr = lrz && lry; - } - return lr && (x >= this.minX && x <= this.maxX); + return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ && y >= this.minY && y <= this.maxY; +// if (z != lz) { +// lz = z; +// lrz = z >= this.minZ && z <= this.maxZ; +// if (y != ly) { +// ly = y; +// lry = y >= this.minY && y <= this.maxY; +// } +// lr = lrz && lry; +// } else if (y != ly) { +// ly = y; +// lry = y >= this.minY && y <= this.maxY; +// lr = lrz && lry; +// } +// return lr && (x >= this.minX && x <= this.maxX); } @Override