Biome mixing tweaks to texture util

This commit is contained in:
Jesse Boyd 2017-08-25 15:02:26 +10:00
parent d14b267cfd
commit 0dbb3b2844
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
5 changed files with 152 additions and 26 deletions

View File

@ -468,20 +468,18 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
int widthIndex = img.getWidth() - 1;
int heightIndex = img.getHeight() - 1;
int maxIndex = biomes.length - 1;
int[] buffer = new int[2];
for (int y = 0; y < img.getHeight(); y++) {
boolean yBiome = y > 0 && y < heightIndex;
for (int x = 0; x < img.getWidth(); x++) {
for (int x = 0; x < img.getWidth(); x++, index++) {
int color = img.getRGB(x, y);
BaseBlock block = textureUtil.getNearestBlock(color);
TextureUtil.BiomeColor biome = textureUtil.getNearestBiome(color);
int blockColor = textureUtil.getColor(block);
biomes[index] = (byte) biome.id;
if (textureUtil.colorDistance(biome.grass, color) - biomePriority > textureUtil.colorDistance(blockColor, color)) {
char combined = (char) block.getCombined();
if (textureUtil.getIsBlockCloserThanBiome(buffer, color, biomePriority)) {
char combined = (char) buffer[0];
main[index] = combined;
floor[index] = combined;
}
index++;
biomes[index] = (byte) buffer[1];
}
}
}

View File

@ -118,4 +118,4 @@ public class CopyPastaBrush implements Brush, ResettableTool {
editSession.flushQueue();
}
}
}
}

View File

@ -49,6 +49,16 @@ public class DelegateTextureUtil extends TextureUtil {
return parent.getColor(block);
}
@Override
public boolean getIsBlockCloserThanBiome(int[] blockAndBiomeIdOutput, int color, int biomePriority) {
return parent.getIsBlockCloserThanBiome(blockAndBiomeIdOutput, color, biomePriority);
}
@Override
public int getBiomeMix(int[] biomeIdsOutput, int color) {
return parent.getBiomeMix(biomeIdsOutput, color);
}
@Override
public BiomeColor getBiome(int biome) {
return parent.getBiome(biome);

View File

@ -16,8 +16,10 @@ public class RandomTextureUtil extends CachedTextureUtil {
this.grassColor = parent.getColor(FaweCache.getBlock(BlockID.GRASS, 0));
}
private int index;
private int[] biomeMixBuffer = new int[3];
private Int2ObjectOpenHashMap<Integer> offsets = new Int2ObjectOpenHashMap<>();
private Int2ObjectOpenHashMap<Integer> biomeOffsets = new Int2ObjectOpenHashMap<>();
private Int2ObjectOpenHashMap<int[]> biomeMixes = new Int2ObjectOpenHashMap<>();
protected int addRandomColor(int c1, int c2) {
int red1 = (c1 >> 16) & 0xFF;
@ -38,26 +40,45 @@ public class RandomTextureUtil extends CachedTextureUtil {
} else {
return PseudoRandom.random.nextInt(i);
}
// return i;
}
@Override
public boolean getIsBlockCloserThanBiome(int[] blockAndBiomeIdOutput, int color, int biomePriority) {
BaseBlock block = getNearestBlock(color);
int[] mix = biomeMixes.getOrDefault(color, null);
if (mix == null) {
int average = getBiomeMix(biomeMixBuffer, color);
mix = new int[4];
System.arraycopy(biomeMixBuffer, 0, mix, 0, 3);
mix[3] = average;
biomeMixes.put(color, mix);
}
if (++index > 2) index = 0;
int biomeId = mix[index];
int biomeAvColor = mix[3];
int blockColor = getColor(block);
blockAndBiomeIdOutput[0] = block.getCombined();
blockAndBiomeIdOutput[1] = biomeId;
if (colorDistance(biomeAvColor, color) - biomePriority > colorDistance(blockColor, color)) {
return true;
}
return false;
}
@Override
public BiomeColor getNearestBiome(int color) {
int offsetColor = biomeOffsets.getOrDefault(color, 0);
if (offsetColor != 0) {
offsetColor = addRandomColor(color, offsetColor);
} else {
offsetColor = color;
int[] mix = biomeMixes.getOrDefault(color, null);
if (mix == null) {
int average = getBiomeMix(biomeMixBuffer, color);
mix = new int[4];
System.arraycopy(biomeMixBuffer, 0, mix, 0, 3);
mix[3] = average;
biomeMixes.put(color, mix);
}
BiomeColor res = super.getNearestBiome(offsetColor);
int newColor = res.grass;
{
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));
biomeOffsets.put(color, (Integer) ((dr << 16) + (dg << 8) + (db << 0)));
}
return res;
if (++index > 2) index = 0;
int biomeId = mix[index];
return getBiome(biomeId);
}
@Override

View File

@ -11,6 +11,8 @@ import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
@ -50,9 +52,13 @@ public class TextureUtil {
protected long[] distances;
protected int[] validColors;
protected char[] validBlockIds;
protected int[] validLayerColors;
protected char[][] validLayerBlocks;
protected int[] validMixBiomeColors;
protected long[] validMixBiomeIds;
/**
* https://github.com/erich666/Mineways/blob/master/Win/biomes.cpp
@ -420,6 +426,43 @@ public class TextureUtil {
return biomes[biome];
}
public boolean getIsBlockCloserThanBiome(int[] blockAndBiomeIdOutput, int color, int biomePriority) {
BaseBlock block = getNearestBlock(color);
TextureUtil.BiomeColor biome = getNearestBiome(color);
int blockColor = getColor(block);
blockAndBiomeIdOutput[0] = block.getCombined();
blockAndBiomeIdOutput[1] = biome.id;
if (colorDistance(biome.grass, color) - biomePriority > colorDistance(blockColor, color)) {
return true;
}
return false;
}
public int getBiomeMix(int[] biomeIdsOutput, int color) {
long closest = Long.MAX_VALUE;
int closestAverage = Integer.MAX_VALUE;
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 < validMixBiomeColors.length; i++) {
int other = validMixBiomeColors[i];
if (((other >> 24) & 0xFF) == alpha) {
long distance = colorDistance(red1, green1, blue1, other);
if (distance < min) {
min = distance;
closest = validMixBiomeIds[i];
closestAverage = other;
}
}
}
biomeIdsOutput[0] = (int) ((closest >> 0) & 0xFF);
biomeIdsOutput[1] = (int) ((closest >> 8) & 0xFF);
biomeIdsOutput[2] = (int) ((closest >> 16) & 0xFF);
return closestAverage;
}
public BiomeColor getNearestBiome(int color) {
int grass = blockColors[2 << 4];
if (grass == 0) {
@ -633,12 +676,47 @@ public class TextureUtil {
List<BiomeColor> valid = new ArrayList<>();
for (int i = 0; i < biomes.length; i++) {
BiomeColor biome = biomes[i];
biome.grass = multiplyColor(biome.grass, grass);
// biome.grass = multiplyColor(biome.grass, grass);
if (biome.grass != 0 && !biome.name.equalsIgnoreCase("Unknown Biome")) {
valid.add(biome);
}
}
this.validBiomes = valid.toArray(new BiomeColor[valid.size()]);
{
ArrayList<BiomeColor> uniqueColors = new ArrayList<>();
Set<Integer> uniqueBiomesColors = new IntArraySet();
for (BiomeColor color : validBiomes) {
if (uniqueBiomesColors.add(color.grass)) {
uniqueColors.add(color);
}
}
int count = 0;
int count2 = 0;
uniqueBiomesColors.clear();
LongArrayList layerIds = new LongArrayList();
LongArrayList layerColors = new LongArrayList();
for (int i = 0; i < uniqueColors.size(); i++) {
for (int j = i; j < uniqueColors.size(); j++) {
for (int k = j; k < uniqueColors.size(); k++) {
BiomeColor c1 = uniqueColors.get(i);
BiomeColor c2 = uniqueColors.get(j);
BiomeColor c3 = uniqueColors.get(k);
int average = averageColor(c1.grass, c2.grass, c3.grass);
if (uniqueBiomesColors.add(average)) {
count++;
layerColors.add((long) average);
layerIds.add((long) ((c1.id) + (c2.id << 8) + (c3.id << 16)));
}
}
}
}
validMixBiomeColors = new int[layerColors.size()];
for (int i = 0; i < layerColors.size(); i++) validMixBiomeColors[i] = (int) layerColors.getLong(i);
validMixBiomeIds = layerIds.toLongArray();
}
}
}
@ -703,6 +781,25 @@ public class TextureUtil {
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
}
public int averageColor(int... colors) {
int alpha = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int c : colors) {
alpha += (c >> 24) & 0xFF;
red += (c >> 16) & 0xFF;
green += (c >> 8) & 0xFF;
blue += (c >> 0) & 0xFF;
}
int num = colors.length;
alpha /= num;
red /= num;
green /= num;
blue /= num;
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
}
/**
* Assumes the top layer is a transparent color and the bottom is opaque
*/