Random coloring

This commit is contained in:
Jesse Boyd 2017-04-28 15:16:12 +10:00
parent cdbe396ae6
commit fb779a8daa
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
7 changed files with 239 additions and 125 deletions

View File

@ -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();
}
}

View File

@ -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<Integer> colorBlockMap;
private Int2ObjectOpenHashMap<char[]> 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<char[]> 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<char[]> 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);
}
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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<Integer> 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;
}
}

View File

@ -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<char[]> 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<char[]> entry : colorLayerMap.int2ObjectEntrySet()) {
validLayerColors[index] = entry.getIntKey();
validLayerBlocks[index++] = entry.getValue();
}
}
public void loadModTextures() throws IOException, ParseException {
Int2ObjectOpenHashMap<Integer> 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) {

View File

@ -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