Heightmap rotation
This commit is contained in:
parent
cf0bd96308
commit
fb76ff4ea0
@ -28,7 +28,7 @@ ext {
|
|||||||
date = git.head().date.format("yy.MM.dd")
|
date = git.head().date.format("yy.MM.dd")
|
||||||
revision = "-${git.head().abbreviatedId}"
|
revision = "-${git.head().abbreviatedId}"
|
||||||
parents = git.head().parentIds;
|
parents = git.head().parentIds;
|
||||||
index = -87; // Offset to mach CI
|
index = -88; // Offset to mach CI
|
||||||
int major, minor, patch;
|
int major, minor, patch;
|
||||||
major = minor = patch = 0;
|
major = minor = patch = 0;
|
||||||
for (;parents != null && !parents.isEmpty();index++) {
|
for (;parents != null && !parents.isEmpty();index++) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.boydti.fawe.object.brush;
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.brush.heightmap.HeightMap;
|
||||||
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
@ -23,7 +24,8 @@ public class FlattenBrush extends HeightBrush {
|
|||||||
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
|
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
|
||||||
mask = null;
|
mask = null;
|
||||||
}
|
}
|
||||||
heightMap.setSize(size);
|
HeightMap map = getHeightMap();
|
||||||
heightMap.perform(editSession, mask, position, size, rotation, yscale, true, true);
|
map.setSize(size);
|
||||||
|
map.perform(editSession, mask, position, size, rotation, yscale, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.boydti.fawe.object.brush;
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.PseudoRandom;
|
||||||
|
import com.boydti.fawe.object.brush.heightmap.HeightMap;
|
||||||
|
import com.boydti.fawe.object.brush.heightmap.RotatableHeightMap;
|
||||||
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
@ -16,7 +19,8 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
public class HeightBrush implements Brush {
|
public class HeightBrush implements Brush {
|
||||||
|
|
||||||
public final ScalableHeightMap heightMap;
|
private HeightMap heightMap;
|
||||||
|
private boolean randomRotate;
|
||||||
public final int rotation;
|
public final int rotation;
|
||||||
public final double yscale;
|
public final double yscale;
|
||||||
|
|
||||||
@ -40,6 +44,21 @@ public class HeightBrush implements Brush {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HeightMap getHeightMap() {
|
||||||
|
if (randomRotate) {
|
||||||
|
if (!(heightMap instanceof RotatableHeightMap)) {
|
||||||
|
heightMap = new RotatableHeightMap(heightMap);
|
||||||
|
}
|
||||||
|
RotatableHeightMap rotatable = (RotatableHeightMap) heightMap;
|
||||||
|
rotatable.rotate(PseudoRandom.random.nextInt(360));
|
||||||
|
}
|
||||||
|
return heightMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRandomRotate(boolean randomRotate) {
|
||||||
|
this.randomRotate = randomRotate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
|
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
|
||||||
int size = (int) sizeDouble;
|
int size = (int) sizeDouble;
|
||||||
@ -47,7 +66,8 @@ public class HeightBrush implements Brush {
|
|||||||
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
|
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
|
||||||
mask = null;
|
mask = null;
|
||||||
}
|
}
|
||||||
heightMap.setSize(size);
|
HeightMap map = getHeightMap();
|
||||||
heightMap.perform(editSession, mask, position, size, rotation, yscale, true, false);
|
map.setSize(size);
|
||||||
|
map.perform(editSession, mask, position, size, rotation, yscale, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.boydti.fawe.object.brush;
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
import com.boydti.fawe.object.PseudoRandom;
|
import com.boydti.fawe.object.PseudoRandom;
|
||||||
|
import com.boydti.fawe.object.brush.heightmap.HeightMap;
|
||||||
import com.boydti.fawe.object.mask.AdjacentAnyMask;
|
import com.boydti.fawe.object.mask.AdjacentAnyMask;
|
||||||
import com.boydti.fawe.object.mask.RadiusMask;
|
import com.boydti.fawe.object.mask.RadiusMask;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
@ -11,10 +12,12 @@ import com.sk89q.worldedit.blocks.BaseBlock;
|
|||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.function.RegionFunction;
|
import com.sk89q.worldedit.function.RegionFunction;
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.function.mask.RegionMask;
|
||||||
import com.sk89q.worldedit.function.mask.SolidBlockMask;
|
import com.sk89q.worldedit.function.mask.SolidBlockMask;
|
||||||
import com.sk89q.worldedit.function.operation.Operations;
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@ -35,21 +38,23 @@ public class StencilBrush extends HeightBrush {
|
|||||||
|
|
||||||
int maxY = editSession.getMaxY();
|
int maxY = editSession.getMaxY();
|
||||||
double scale = (yscale / sizeDouble) * (maxY + 1);
|
double scale = (yscale / sizeDouble) * (maxY + 1);
|
||||||
heightMap.setSize(size);
|
final HeightMap map = getHeightMap();
|
||||||
|
map.setSize(size);
|
||||||
int cutoff = onlyWhite ? maxY : 0;
|
int cutoff = onlyWhite ? maxY : 0;
|
||||||
|
|
||||||
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
|
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
|
||||||
final SolidBlockMask solid = new SolidBlockMask(editSession);
|
final SolidBlockMask solid = new SolidBlockMask(editSession);
|
||||||
|
RegionMask region = new RegionMask(new CuboidRegion(position.subtract(size, size, size), position.add(size, size, size)));
|
||||||
final RadiusMask radius = new RadiusMask(0, size);
|
final RadiusMask radius = new RadiusMask(0, size);
|
||||||
RecursiveVisitor visitor = new RecursiveVisitor(new Mask() {
|
RecursiveVisitor visitor = new RecursiveVisitor(new Mask() {
|
||||||
@Override
|
@Override
|
||||||
public boolean test(Vector vector) {
|
public boolean test(Vector vector) {
|
||||||
if (solid.test(vector) && radius.test(vector)) {
|
if (solid.test(vector) && radius.test(vector)) {
|
||||||
|
int dx = vector.getBlockX() - cx;
|
||||||
|
int dy = vector.getBlockY() - cy;
|
||||||
|
int dz = vector.getBlockZ() - cz;
|
||||||
Vector dir = adjacent.direction(vector);
|
Vector dir = adjacent.direction(vector);
|
||||||
if (dir != null) {
|
if (dir != null) {
|
||||||
int dx = vector.getBlockX() - cx;
|
|
||||||
int dy = vector.getBlockY() - cy;
|
|
||||||
int dz = vector.getBlockZ() - cz;
|
|
||||||
if (dy != 0) {
|
if (dy != 0) {
|
||||||
if (dir.getBlockX() != 0) {
|
if (dir.getBlockX() != 0) {
|
||||||
dx += dir.getBlockX() * dy;
|
dx += dir.getBlockX() * dy;
|
||||||
@ -57,7 +62,7 @@ public class StencilBrush extends HeightBrush {
|
|||||||
dz += dir.getBlockZ() * dy;
|
dz += dir.getBlockZ() * dy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double raise = heightMap.getHeight(dx, dz);
|
double raise = map.getHeight(dx, dz);
|
||||||
int val = (int) Math.ceil(raise * scale);
|
int val = (int) Math.ceil(raise * scale);
|
||||||
if (val <= cutoff) {
|
if (val <= cutoff) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.boydti.fawe.object.brush.heightmap;
|
||||||
|
|
||||||
|
public class AbstractDelegateHeightMap implements HeightMap {
|
||||||
|
|
||||||
|
private final HeightMap parent;
|
||||||
|
|
||||||
|
public AbstractDelegateHeightMap(HeightMap parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getHeight(int x, int z) {
|
||||||
|
return parent.getHeight(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSize(int size) {
|
||||||
|
parent.setSize(size);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package com.boydti.fawe.object.brush.heightmap;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.PseudoRandom;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.WorldVector;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.internal.LocalWorldAdapter;
|
||||||
|
import com.sk89q.worldedit.math.convolution.GaussianKernel;
|
||||||
|
import com.sk89q.worldedit.math.convolution.HeightMapFilter;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
import com.sk89q.worldedit.regions.Region;
|
||||||
|
|
||||||
|
public interface HeightMap {
|
||||||
|
public double getHeight(int x, int z);
|
||||||
|
|
||||||
|
public void setSize(int size);
|
||||||
|
|
||||||
|
|
||||||
|
default void perform(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
||||||
|
int[] data = generateHeightData(session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
||||||
|
applyHeightMapData(data, session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void applyHeightMapData(int[] data, EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
||||||
|
Vector top = session.getMaximumPoint();
|
||||||
|
int maxY = top.getBlockY();
|
||||||
|
int diameter = 2 * size + 1;
|
||||||
|
int iterations = 1;
|
||||||
|
WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, maxY, size));
|
||||||
|
Vector max = pos.add(size, maxY, size);
|
||||||
|
Region region = new CuboidRegion(session.getWorld(), min, max);
|
||||||
|
com.sk89q.worldedit.math.convolution.HeightMap heightMap = new com.sk89q.worldedit.math.convolution.HeightMap(session, region, false);
|
||||||
|
if (smooth) {
|
||||||
|
try {
|
||||||
|
HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1));
|
||||||
|
data = filter.filter(data, diameter, diameter);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
heightMap.apply(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
default int[] generateHeightData(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) {
|
||||||
|
Vector top = session.getMaximumPoint();
|
||||||
|
int maxY = top.getBlockY();
|
||||||
|
int diameter = 2 * size + 1;
|
||||||
|
int centerX = pos.getBlockX();
|
||||||
|
int centerZ = pos.getBlockZ();
|
||||||
|
int centerY = pos.getBlockY();
|
||||||
|
int endY = pos.getBlockY() + size;
|
||||||
|
int startY = pos.getBlockY() - size;
|
||||||
|
int[] newData = new int[diameter * diameter];
|
||||||
|
Vector mutablePos = new Vector(0, 0, 0);
|
||||||
|
if (towards) {
|
||||||
|
double sizePow = Math.pow(size, yscale);
|
||||||
|
int targetY = pos.getBlockY();
|
||||||
|
for (int x = -size; x <= size; x++) {
|
||||||
|
int xx = centerX + x;
|
||||||
|
mutablePos.mutX(xx);
|
||||||
|
for (int z = -size; z <= size; z++) {
|
||||||
|
int index = (z + size) * diameter + (x + size);
|
||||||
|
int zz = centerZ + z;
|
||||||
|
double raise;
|
||||||
|
switch (rotationMode) {
|
||||||
|
default:
|
||||||
|
raise = getHeight(x, z);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
raise = getHeight(z, x);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
raise = getHeight(-x, -z);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
raise = getHeight(-z, -x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, 255);
|
||||||
|
if (height == 0) {
|
||||||
|
newData[index] = centerY;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double raisePow = Math.pow(raise, yscale);
|
||||||
|
int diff = targetY - height;
|
||||||
|
double raiseScaled = diff * (raisePow / sizePow);
|
||||||
|
double raiseScaledAbs = Math.abs(raiseScaled);
|
||||||
|
int random = PseudoRandom.random.random(256) < (int) ((Math.ceil(raiseScaledAbs) - Math.floor(raiseScaledAbs)) * 256) ? (diff > 0 ? 1 : -1) : 0;
|
||||||
|
int raiseScaledInt = (int) raiseScaled + random;
|
||||||
|
newData[index] = height + raiseScaledInt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int x = -size; x <= size; x++) {
|
||||||
|
int xx = centerX + x;
|
||||||
|
mutablePos.mutX(xx);
|
||||||
|
for (int z = -size; z <= size; z++) {
|
||||||
|
int index = (z + size) * diameter + (x + size);
|
||||||
|
int zz = centerZ + z;
|
||||||
|
double raise;
|
||||||
|
switch (rotationMode) {
|
||||||
|
default:
|
||||||
|
raise = getHeight(x, z);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
raise = getHeight(z, x);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
raise = getHeight(-x, -z);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
raise = getHeight(-z, -x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY);
|
||||||
|
if (height == 0) {
|
||||||
|
newData[index] = centerY;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
raise = (yscale * raise);
|
||||||
|
int random = PseudoRandom.random.random(maxY + 1) < (int) ((raise - (int) raise) * (maxY + 1)) ? 1 : 0;
|
||||||
|
int newHeight = height + (int) raise + random;
|
||||||
|
newData[index] = newHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.boydti.fawe.object.brush.heightmap;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.MutableBlockVector;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
|
||||||
|
public class RotatableHeightMap extends AbstractDelegateHeightMap {
|
||||||
|
private AffineTransform transform;
|
||||||
|
private MutableBlockVector mutable;
|
||||||
|
|
||||||
|
public RotatableHeightMap(HeightMap parent) {
|
||||||
|
super(parent);
|
||||||
|
mutable = new MutableBlockVector();
|
||||||
|
this.transform = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate(double angle) {
|
||||||
|
this.transform = transform.rotateY(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getHeight(int x, int z) {
|
||||||
|
mutable.mutX(x);
|
||||||
|
mutable.mutZ(z);
|
||||||
|
Vector pos = transform.apply(mutable.setComponents(x, 0, z));
|
||||||
|
return super.getHeight(pos.getBlockX(), pos.getBlockZ());
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,11 @@
|
|||||||
package com.boydti.fawe.object.brush.heightmap;
|
package com.boydti.fawe.object.brush.heightmap;
|
||||||
|
|
||||||
import com.boydti.fawe.object.IntegerPair;
|
import com.boydti.fawe.object.IntegerPair;
|
||||||
import com.boydti.fawe.object.PseudoRandom;
|
|
||||||
import com.boydti.fawe.util.MainUtil;
|
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.WorldVector;
|
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
|
||||||
import com.sk89q.worldedit.internal.LocalWorldAdapter;
|
|
||||||
import com.sk89q.worldedit.math.convolution.GaussianKernel;
|
|
||||||
import com.sk89q.worldedit.math.convolution.HeightMap;
|
|
||||||
import com.sk89q.worldedit.math.convolution.HeightMapFilter;
|
|
||||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.Raster;
|
import java.awt.image.Raster;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -24,7 +13,7 @@ import java.io.InputStream;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
public class ScalableHeightMap {
|
public class ScalableHeightMap implements com.boydti.fawe.object.brush.heightmap.HeightMap{
|
||||||
public int size2;
|
public int size2;
|
||||||
public int size;
|
public int size;
|
||||||
|
|
||||||
@ -41,11 +30,13 @@ public class ScalableHeightMap {
|
|||||||
setSize(size);
|
setSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setSize(int size) {
|
public void setSize(int size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.size2 = size * size;
|
this.size2 = size * size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
@ -117,115 +108,4 @@ public class ScalableHeightMap {
|
|||||||
}
|
}
|
||||||
return new ArrayHeightMap(array);
|
return new ArrayHeightMap(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void perform(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
|
||||||
int[] data = generateHeightData(session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
|
||||||
applyHeightMapData(data, session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyHeightMapData(int[] data, EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
|
||||||
Vector top = session.getMaximumPoint();
|
|
||||||
int maxY = top.getBlockY();
|
|
||||||
int diameter = 2 * size + 1;
|
|
||||||
int iterations = 1;
|
|
||||||
WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, maxY, size));
|
|
||||||
Vector max = pos.add(size, maxY, size);
|
|
||||||
Region region = new CuboidRegion(session.getWorld(), min, max);
|
|
||||||
HeightMap heightMap = new HeightMap(session, region, false);
|
|
||||||
if (smooth) {
|
|
||||||
try {
|
|
||||||
HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1));
|
|
||||||
data = filter.filter(data, diameter, diameter);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
MainUtil.handleError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
heightMap.apply(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] generateHeightData(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) {
|
|
||||||
Vector top = session.getMaximumPoint();
|
|
||||||
int maxY = top.getBlockY();
|
|
||||||
int diameter = 2 * size + 1;
|
|
||||||
int centerX = pos.getBlockX();
|
|
||||||
int centerZ = pos.getBlockZ();
|
|
||||||
int centerY = pos.getBlockY();
|
|
||||||
int endY = pos.getBlockY() + size;
|
|
||||||
int startY = pos.getBlockY() - size;
|
|
||||||
int[] newData = new int[diameter * diameter];
|
|
||||||
Vector mutablePos = new Vector(0, 0, 0);
|
|
||||||
if (towards) {
|
|
||||||
double sizePow = Math.pow(size, yscale);
|
|
||||||
int targetY = pos.getBlockY();
|
|
||||||
for (int x = -size; x <= size; x++) {
|
|
||||||
int xx = centerX + x;
|
|
||||||
mutablePos.mutX(xx);
|
|
||||||
for (int z = -size; z <= size; z++) {
|
|
||||||
int index = (z + size) * diameter + (x + size);
|
|
||||||
int zz = centerZ + z;
|
|
||||||
double raise;
|
|
||||||
switch (rotationMode) {
|
|
||||||
default:
|
|
||||||
raise = getHeight(x, z);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
raise = getHeight(z, x);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
raise = getHeight(-x, -z);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
raise = getHeight(-z, -x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, 255);
|
|
||||||
if (height == 0) {
|
|
||||||
newData[index] = centerY;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
double raisePow = Math.pow(raise, yscale);
|
|
||||||
int diff = targetY - height;
|
|
||||||
double raiseScaled = diff * (raisePow / sizePow);
|
|
||||||
double raiseScaledAbs = Math.abs(raiseScaled);
|
|
||||||
int random = PseudoRandom.random.random(256) < (int) ((Math.ceil(raiseScaledAbs) - Math.floor(raiseScaledAbs)) * 256) ? (diff > 0 ? 1 : -1) : 0;
|
|
||||||
int raiseScaledInt = (int) raiseScaled + random;
|
|
||||||
newData[index] = height + raiseScaledInt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int x = -size; x <= size; x++) {
|
|
||||||
int xx = centerX + x;
|
|
||||||
mutablePos.mutX(xx);
|
|
||||||
for (int z = -size; z <= size; z++) {
|
|
||||||
int index = (z + size) * diameter + (x + size);
|
|
||||||
int zz = centerZ + z;
|
|
||||||
double raise;
|
|
||||||
switch (rotationMode) {
|
|
||||||
default:
|
|
||||||
raise = getHeight(x, z);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
raise = getHeight(z, x);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
raise = getHeight(-x, -z);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
raise = getHeight(-z, -x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY);
|
|
||||||
if (height == 0) {
|
|
||||||
newData[index] = centerY;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
raise = (yscale * raise);
|
|
||||||
int random = PseudoRandom.random.random(maxY + 1) < (int) ((raise - (int) raise) * (maxY + 1)) ? 1 : 0;
|
|
||||||
int newHeight = height + (int) raise + random;
|
|
||||||
newData[index] = newHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.boydti.fawe.object.extent;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
|
|
||||||
|
public class OffsetExtent extends ResettableExtent {
|
||||||
|
private final int dx, dy, dz;
|
||||||
|
|
||||||
|
public OffsetExtent(Extent parent, int dx, int dy, int dz) {
|
||||||
|
super(parent);
|
||||||
|
this.dx = dx;
|
||||||
|
this.dy = dy;
|
||||||
|
this.dz = dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||||
|
return super.setBiome(new Vector2D(position.getBlockX() + dx, position.getBlockZ() + dz), biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||||
|
return super.setBlock(location.getBlockX() + dx, location.getBlockY() + dy, location.getBlockZ() + dz, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||||
|
return super.setBlock(x + dx, y + dy, z + dz, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResettableExtent setExtent(Extent extent) {
|
||||||
|
return super.setExtent(extent);
|
||||||
|
}
|
||||||
|
}
|
@ -1453,7 +1453,65 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
checkArgument(depth >= 1, "depth >= 1");
|
checkArgument(depth >= 1, "depth >= 1");
|
||||||
|
|
||||||
final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), new BoundedHeightMask(Math.max(
|
final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), new BoundedHeightMask(Math.max(
|
||||||
(origin.getBlockY() - depth) + 1, 0), Math.min(EditSession.this.getMaximumPoint().getBlockY(), origin.getBlockY())), Masks.negate(new ExistingBlockMask(EditSession.this)));
|
(origin.getBlockY() - depth) + 1, 0), Math.min(EditSession.this.getMaximumPoint().getBlockY(), origin.getBlockY())), Masks.negate(new ExistingBlockMask(EditSession.this)));
|
||||||
|
|
||||||
|
// Want to replace blocks
|
||||||
|
final BlockReplace replace = new BlockReplace(EditSession.this, Patterns.wrap(pattern));
|
||||||
|
|
||||||
|
// Pick how we're going to visit blocks
|
||||||
|
RecursiveVisitor visitor;
|
||||||
|
if (recursive) {
|
||||||
|
visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
|
||||||
|
} else {
|
||||||
|
visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start at the origin
|
||||||
|
visitor.visit(origin);
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
Operations.completeBlindly(visitor);
|
||||||
|
return this.changes = visitor.getAffected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fillDirection(final Vector origin, PlayerDirection direction, final Pattern pattern, final double radius, final int depth, final boolean recursive) throws MaxChangedBlocksException {
|
||||||
|
checkNotNull(origin);
|
||||||
|
checkNotNull(pattern);
|
||||||
|
checkArgument(radius >= 0, "radius >= 0");
|
||||||
|
checkArgument(depth >= 1, "depth >= 1");
|
||||||
|
|
||||||
|
Vector dirVec = direction.vector();
|
||||||
|
BlockVector min = origin.toBlockVector();
|
||||||
|
BlockVector max = origin.toBlockVector();
|
||||||
|
|
||||||
|
CuboidRegion cuboid = new CuboidRegion(new Vector(), new Vector());
|
||||||
|
switch (direction) {
|
||||||
|
case NORTH:
|
||||||
|
break;
|
||||||
|
case NORTH_EAST:
|
||||||
|
break;
|
||||||
|
case EAST:
|
||||||
|
break;
|
||||||
|
case SOUTH_EAST:
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
break;
|
||||||
|
case SOUTH_WEST:
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
break;
|
||||||
|
case NORTH_WEST:
|
||||||
|
break;
|
||||||
|
case UP:
|
||||||
|
break;
|
||||||
|
case DOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), new BoundedHeightMask(Math.max(
|
||||||
|
(origin.getBlockY() - depth) + 1, 0), Math.min(EditSession.this.getMaximumPoint().getBlockY(), origin.getBlockY())), Masks.negate(new ExistingBlockMask(EditSession.this)));
|
||||||
|
|
||||||
// Want to replace blocks
|
// Want to replace blocks
|
||||||
final BlockReplace replace = new BlockReplace(EditSession.this, Patterns.wrap(pattern));
|
final BlockReplace replace = new BlockReplace(EditSession.this, Patterns.wrap(pattern));
|
||||||
|
@ -542,18 +542,22 @@ public class BrushCommands {
|
|||||||
max = -1
|
max = -1
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.brush.stencil")
|
@CommandPermissions("worldedit.brush.stencil")
|
||||||
public void stencilBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('w') boolean onlyWhite) throws WorldEditException {
|
public void stencilBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('w') boolean onlyWhite, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||||
worldEdit.checkMaxBrushRadius(radius);
|
worldEdit.checkMaxBrushRadius(radius);
|
||||||
BrushTool tool = session.getBrushTool(player);
|
BrushTool tool = session.getBrushTool(player);
|
||||||
InputStream stream = getHeightmapStream(filename);
|
InputStream stream = getHeightmapStream(filename);
|
||||||
tool.setFill(fill);
|
tool.setFill(fill);
|
||||||
tool.setSize(radius);
|
tool.setSize(radius);
|
||||||
|
HeightBrush brush;
|
||||||
try {
|
try {
|
||||||
tool.setBrush(new StencilBrush(stream, rotation, yscale, onlyWhite, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height", player);
|
brush = new StencilBrush(stream, rotation, yscale, onlyWhite, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null);
|
||||||
} catch (EmptyClipboardException ignore) {
|
} catch (EmptyClipboardException ignore) {
|
||||||
tool.setBrush(new StencilBrush(stream, rotation, yscale, onlyWhite, null), "worldedit.brush.height", player);
|
brush = new StencilBrush(stream, rotation, yscale, onlyWhite, null);
|
||||||
|
}
|
||||||
|
tool.setBrush(brush, "worldedit.brush.height", player);
|
||||||
|
if (randomRotate) {
|
||||||
|
brush.setRandomRotate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.print(BBC.getPrefix() + BBC.BRUSH_STENCIL.f(radius));
|
player.print(BBC.getPrefix() + BBC.BRUSH_STENCIL.f(radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,8 +699,8 @@ public class BrushCommands {
|
|||||||
max = 4
|
max = 4
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.brush.height")
|
@CommandPermissions("worldedit.brush.height")
|
||||||
public void heightBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale) throws WorldEditException {
|
public void heightBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||||
terrainBrush(player, session, radius, filename, rotation, yscale, false, ScalableHeightMap.Shape.CONE);
|
terrainBrush(player, session, radius, filename, rotation, yscale, false, randomRotate, ScalableHeightMap.Shape.CONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -710,8 +714,8 @@ public class BrushCommands {
|
|||||||
max = 4
|
max = 4
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.brush.height")
|
@CommandPermissions("worldedit.brush.height")
|
||||||
public void cliffBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale) throws WorldEditException {
|
public void cliffBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, ScalableHeightMap.Shape.CYLINDER);
|
terrainBrush(player, session, radius, filename, rotation, yscale, true, randomRotate, ScalableHeightMap.Shape.CYLINDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -725,8 +729,8 @@ public class BrushCommands {
|
|||||||
max = 4
|
max = 4
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.brush.height")
|
@CommandPermissions("worldedit.brush.height")
|
||||||
public void flattenBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale) throws WorldEditException {
|
public void flattenBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, ScalableHeightMap.Shape.CONE);
|
terrainBrush(player, session, radius, filename, rotation, yscale, true, randomRotate, ScalableHeightMap.Shape.CONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getHeightmapStream(String filename) {
|
private InputStream getHeightmapStream(String filename) {
|
||||||
@ -760,24 +764,29 @@ public class BrushCommands {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void terrainBrush(Player player, LocalSession session, double radius, String filename, int rotation, double yscale, boolean flat, ScalableHeightMap.Shape shape) throws WorldEditException {
|
private void terrainBrush(Player player, LocalSession session, double radius, String filename, int rotation, double yscale, boolean flat, boolean randomRotate, ScalableHeightMap.Shape shape) throws WorldEditException {
|
||||||
worldEdit.checkMaxBrushRadius(radius);
|
worldEdit.checkMaxBrushRadius(radius);
|
||||||
InputStream stream = getHeightmapStream(filename);
|
InputStream stream = getHeightmapStream(filename);
|
||||||
BrushTool tool = session.getBrushTool(player);
|
BrushTool tool = session.getBrushTool(player);
|
||||||
tool.setSize(radius);
|
tool.setSize(radius);
|
||||||
|
HeightBrush brush;
|
||||||
if (flat) {
|
if (flat) {
|
||||||
try {
|
try {
|
||||||
tool.setBrush(new FlattenBrush(stream, rotation, yscale, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null, shape), "worldedit.brush.height", player);
|
brush = new FlattenBrush(stream, rotation, yscale, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null, shape);
|
||||||
} catch (EmptyClipboardException ignore) {
|
} catch (EmptyClipboardException ignore) {
|
||||||
tool.setBrush(new FlattenBrush(stream, rotation, yscale, null, shape), "worldedit.brush.height", player);
|
brush = new FlattenBrush(stream, rotation, yscale, null, shape);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
tool.setBrush(new HeightBrush(stream, rotation, yscale, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height", player);
|
brush = new HeightBrush(stream, rotation, yscale, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null);
|
||||||
} catch (EmptyClipboardException ignore) {
|
} catch (EmptyClipboardException ignore) {
|
||||||
tool.setBrush(new HeightBrush(stream, rotation, yscale, null), "worldedit.brush.height", player);
|
brush = new HeightBrush(stream, rotation, yscale, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tool.setBrush(brush, "worldedit.brush.height", player);
|
||||||
|
if (randomRotate) {
|
||||||
|
brush.setRandomRotate(true);
|
||||||
|
}
|
||||||
player.print(BBC.getPrefix() + BBC.BRUSH_HEIGHT.f(radius));
|
player.print(BBC.getPrefix() + BBC.BRUSH_HEIGHT.f(radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user