mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 17:27:38 +00:00
Heightmaps used for brushes etc. should be normalised to zero. (#1522)
* Heightmaps used for brushes etc. should be normalised to zero. Fixes #1508 * chars are unsigned * Add scale paramer to javadoc
This commit is contained in:
parent
9e40b972b1
commit
6a972e7b99
@ -51,14 +51,14 @@ public class HeightBrush implements Brush {
|
|||||||
this.smooth = smooth;
|
this.smooth = smooth;
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
try {
|
try {
|
||||||
heightMap = ScalableHeightMap.fromPNG(stream, minY, maxY);
|
heightMap = ScalableHeightMap.fromPNG(stream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid"));
|
throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid"));
|
||||||
}
|
}
|
||||||
} else if (clipboard != null) {
|
} else if (clipboard != null) {
|
||||||
heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY);
|
heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY);
|
||||||
} else {
|
} else {
|
||||||
heightMap = ScalableHeightMap.fromShape(shape, minY, maxY);
|
heightMap = ScalableHeightMap.fromShape(shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,27 +3,29 @@ package com.fastasyncworldedit.core.math.heightmap;
|
|||||||
public class ArrayHeightMap extends ScalableHeightMap {
|
public class ArrayHeightMap extends ScalableHeightMap {
|
||||||
|
|
||||||
// The heights
|
// The heights
|
||||||
private final byte[][] height;
|
private final char[][] height;
|
||||||
// The height map width/length
|
// The height map width/length
|
||||||
private final int width;
|
private final int width;
|
||||||
private final int length;
|
private final int length;
|
||||||
|
private final double scale;
|
||||||
// The size to width/length ratio
|
// The size to width/length ratio
|
||||||
private double rx;
|
private double rx;
|
||||||
private double rz;
|
private double rz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New height map represented by byte array[][] of values x*z to be scaled given a set size
|
* New height map represented by char array[][] of values x*z to be scaled given a set size.
|
||||||
|
* Limited 0->65535
|
||||||
*
|
*
|
||||||
* @param height array of height values
|
* @param height array of height values
|
||||||
* @param minY min y value allowed to be set. Inclusive.
|
* @param scale "scale" of the heightmap. Typically the normalised height of the world, or the maximum possible value (256
|
||||||
* @param maxY max y value allowed to be set. Inclusive.
|
* for a PNG heightmap)
|
||||||
*/
|
*/
|
||||||
public ArrayHeightMap(byte[][] height, int minY, int maxY) {
|
public ArrayHeightMap(char[][] height, double scale) {
|
||||||
super(minY, maxY);
|
|
||||||
setSize(5);
|
setSize(5);
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.width = height.length;
|
this.width = height.length;
|
||||||
this.length = height[0].length;
|
this.length = height[0].length;
|
||||||
|
this.scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -38,7 +40,7 @@ public class ArrayHeightMap extends ScalableHeightMap {
|
|||||||
public double getHeight(int x, int z) {
|
public double getHeight(int x, int z) {
|
||||||
x = (int) Math.max(0, Math.min(width - 1, (x + size) * rx));
|
x = (int) Math.max(0, Math.min(width - 1, (x + size) * rx));
|
||||||
z = (int) Math.max(0, Math.min(length - 1, (z + size) * rz));
|
z = (int) Math.max(0, Math.min(length - 1, (z + size) * rz));
|
||||||
return ((height[x][z] & 0xFF) * size) / 256d;
|
return (height[x][z] * size) / scale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,24 +2,13 @@ package com.fastasyncworldedit.core.math.heightmap;
|
|||||||
|
|
||||||
public class FlatScalableHeightMap extends ScalableHeightMap {
|
public class FlatScalableHeightMap extends ScalableHeightMap {
|
||||||
|
|
||||||
/**
|
|
||||||
* New height map where the returned height is the minmum height value if outside the size, otherwise returns height equal
|
|
||||||
* to size.
|
|
||||||
*
|
|
||||||
* @param minY min y value allowed to be set. Inclusive.
|
|
||||||
* @param maxY max y value allowed to be set. Inclusive.
|
|
||||||
*/
|
|
||||||
public FlatScalableHeightMap(int minY, int maxY) {
|
|
||||||
super(minY, maxY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getHeight(int x, int z) {
|
public double getHeight(int x, int z) {
|
||||||
int dx = Math.abs(x);
|
int dx = Math.abs(x);
|
||||||
int dz = Math.abs(z);
|
int dz = Math.abs(z);
|
||||||
int d2 = dx * dx + dz * dz;
|
int d2 = dx * dx + dz * dz;
|
||||||
if (d2 > size2) {
|
if (d2 > size2) {
|
||||||
return minY;
|
return 0;
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ public interface HeightMap {
|
|||||||
height = tmpY = session.getNearestSurfaceLayer(xx, zz, tmpY, minY, maxY);
|
height = tmpY = session.getNearestSurfaceLayer(xx, zz, tmpY, minY, maxY);
|
||||||
} else {
|
} else {
|
||||||
height = tmpY = session.getNearestSurfaceTerrainBlock(xx, zz, tmpY, minY, maxY);
|
height = tmpY = session.getNearestSurfaceTerrainBlock(xx, zz, tmpY, minY, maxY);
|
||||||
if (height == -1) {
|
if (height < minY) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,9 +129,9 @@ public interface HeightMap {
|
|||||||
double raiseScaled = diff * (raisePow * sizePowInv);
|
double raiseScaled = diff * (raisePow * sizePowInv);
|
||||||
double raiseScaledAbs = Math.abs(raiseScaled);
|
double raiseScaledAbs = Math.abs(raiseScaled);
|
||||||
int random =
|
int random =
|
||||||
ThreadLocalRandom
|
(ThreadLocalRandom
|
||||||
.current()
|
.current()
|
||||||
.nextInt(maxY + 1 - minY) - minY < (int) ((Math.ceil(raiseScaledAbs) - Math.floor(
|
.nextInt(maxY + 1 - minY) - minY) < (int) ((Math.ceil(raiseScaledAbs) - Math.floor(
|
||||||
raiseScaledAbs)) * (maxY + 1 - minY)) ? (diff > 0 ? 1 : -1) : 0;
|
raiseScaledAbs)) * (maxY + 1 - minY)) ? (diff > 0 ? 1 : -1) : 0;
|
||||||
int raiseScaledInt = (int) raiseScaled + random;
|
int raiseScaledInt = (int) raiseScaled + random;
|
||||||
newData[index] = height + raiseScaledInt;
|
newData[index] = height + raiseScaledInt;
|
||||||
@ -154,7 +154,7 @@ public interface HeightMap {
|
|||||||
height = session.getNearestSurfaceLayer(xx, zz, height, minY, maxY);
|
height = session.getNearestSurfaceLayer(xx, zz, height, minY, maxY);
|
||||||
} else {
|
} else {
|
||||||
height = session.getNearestSurfaceTerrainBlock(xx, zz, height, minY, maxY);
|
height = session.getNearestSurfaceTerrainBlock(xx, zz, height, minY, maxY);
|
||||||
if (height == minY - 1) {
|
if (height < minY) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,9 +165,9 @@ public interface HeightMap {
|
|||||||
}
|
}
|
||||||
raise = (yscale * raise);
|
raise = (yscale * raise);
|
||||||
int random =
|
int random =
|
||||||
ThreadLocalRandom
|
(ThreadLocalRandom
|
||||||
.current()
|
.current()
|
||||||
.nextInt(maxY + 1 - minY) - minY < (int) ((raise - (int) raise) * (maxY - minY + 1))
|
.nextInt(maxY + 1 - minY) - minY) < (int) ((raise - (int) raise) * (maxY - minY + 1))
|
||||||
? 1 : 0;
|
? 1 : 0;
|
||||||
int newHeight = height + (int) raise + random;
|
int newHeight = height + (int) raise + random;
|
||||||
newData[index] = newHeight;
|
newData[index] = newHeight;
|
||||||
|
@ -9,7 +9,6 @@ import com.sk89q.worldedit.math.BlockVector3;
|
|||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.Raster;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -18,8 +17,6 @@ public class ScalableHeightMap implements HeightMap {
|
|||||||
|
|
||||||
public int size2;
|
public int size2;
|
||||||
public int size;
|
public int size;
|
||||||
protected int minY;
|
|
||||||
protected int maxY;
|
|
||||||
|
|
||||||
public enum Shape {
|
public enum Shape {
|
||||||
CONE,
|
CONE,
|
||||||
@ -27,14 +24,9 @@ public class ScalableHeightMap implements HeightMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New height map.
|
* New height map. "Normalised" to a min Y of zero.
|
||||||
*
|
|
||||||
* @param minY min y value allowed to be set. Inclusive.
|
|
||||||
* @param maxY max y value allowed to be set. Inclusive.
|
|
||||||
*/
|
*/
|
||||||
public ScalableHeightMap(final int minY, final int maxY) {
|
public ScalableHeightMap() {
|
||||||
this.minY = minY;
|
|
||||||
this.maxY = maxY;
|
|
||||||
setSize(5);
|
setSize(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,21 +42,21 @@ public class ScalableHeightMap implements HeightMap {
|
|||||||
int dz = Math.abs(z);
|
int dz = Math.abs(z);
|
||||||
int d2 = dx * dx + dz * dz;
|
int d2 = dx * dx + dz * dz;
|
||||||
if (d2 > size2) {
|
if (d2 > size2) {
|
||||||
return minY;
|
return 0;
|
||||||
}
|
}
|
||||||
return Math.max(minY, size - MathMan.sqrtApprox(d2));
|
return Math.max(0, size - MathMan.sqrtApprox(d2));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalableHeightMap fromShape(Shape shape, int minY, int maxY) {
|
public static ScalableHeightMap fromShape(Shape shape) {
|
||||||
return switch (shape) {
|
return switch (shape) {
|
||||||
case CONE -> new ScalableHeightMap(minY, maxY);
|
case CONE -> new ScalableHeightMap();
|
||||||
case CYLINDER -> new FlatScalableHeightMap(minY, maxY);
|
case CYLINDER -> new FlatScalableHeightMap();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalableHeightMap fromClipboard(Clipboard clipboard, int minY, int maxY) {
|
public static ScalableHeightMap fromClipboard(Clipboard clipboard, int minY, int maxY) {
|
||||||
BlockVector3 dim = clipboard.getDimensions();
|
BlockVector3 dim = clipboard.getDimensions();
|
||||||
byte[][] heightArray = new byte[dim.getBlockX()][dim.getBlockZ()];
|
char[][] heightArray = new char[dim.getBlockX()][dim.getBlockZ()];
|
||||||
int clipMinX = clipboard.getMinimumPoint().getBlockX();
|
int clipMinX = clipboard.getMinimumPoint().getBlockX();
|
||||||
int clipMinZ = clipboard.getMinimumPoint().getBlockZ();
|
int clipMinZ = clipboard.getMinimumPoint().getBlockZ();
|
||||||
int clipMinY = clipboard.getMinimumPoint().getBlockY();
|
int clipMinY = clipboard.getMinimumPoint().getBlockY();
|
||||||
@ -89,20 +81,18 @@ public class ScalableHeightMap implements HeightMap {
|
|||||||
highestY = y + 1;
|
highestY = y + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int pointHeight = Math.min(clipMaxY, ((maxY - minY + 1) * (highestY - clipMinY)) / clipHeight);
|
|
||||||
int x = xx - clipMinX;
|
int x = xx - clipMinX;
|
||||||
int z = zz - clipMinZ;
|
int z = zz - clipMinZ;
|
||||||
heightArray[x][z] = (byte) pointHeight;
|
heightArray[x][z] = (char) Math.min(clipMaxY, ((maxY - minY + 1) * (highestY - clipMinY)) / clipHeight);
|
||||||
}
|
}
|
||||||
return new ArrayHeightMap(heightArray, minY, maxY);
|
return new ArrayHeightMap(heightArray, maxY - minY + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalableHeightMap fromPNG(InputStream stream, int minY, int maxY) throws IOException {
|
public static ScalableHeightMap fromPNG(InputStream stream) throws IOException {
|
||||||
BufferedImage heightFile = MainUtil.readImage(stream);
|
BufferedImage heightFile = MainUtil.readImage(stream);
|
||||||
int width = heightFile.getWidth();
|
int width = heightFile.getWidth();
|
||||||
int length = heightFile.getHeight();
|
int length = heightFile.getHeight();
|
||||||
Raster data = heightFile.getData();
|
char[][] array = new char[width][length];
|
||||||
byte[][] array = new byte[width][length];
|
|
||||||
double third = 1 / 3.0;
|
double third = 1 / 3.0;
|
||||||
double alphaInverse = 1 / 255.0;
|
double alphaInverse = 1 / 255.0;
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
@ -110,13 +100,12 @@ public class ScalableHeightMap implements HeightMap {
|
|||||||
int pixel = heightFile.getRGB(x, z);
|
int pixel = heightFile.getRGB(x, z);
|
||||||
int red = pixel >> 16 & 0xFF;
|
int red = pixel >> 16 & 0xFF;
|
||||||
int green = pixel >> 8 & 0xFF;
|
int green = pixel >> 8 & 0xFF;
|
||||||
int blue = pixel >> 0 & 0xFF;
|
int blue = pixel & 0xFF;
|
||||||
int alpha = pixel >> 24 & 0xFF;
|
int alpha = pixel >> 24 & 0xFF;
|
||||||
int intensity = (int) (alpha * ((red + green + blue) * third) * alphaInverse);
|
array[x][z] = (char) (alpha * ((red + green + blue) * third) * alphaInverse);
|
||||||
array[x][z] = (byte) intensity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ArrayHeightMap(array, minY, maxY);
|
return new ArrayHeightMap(array, 256d);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user