Add flatten brush (needs testing)

This commit is contained in:
Jesse Boyd 2017-02-08 15:44:21 +11:00
parent 85ac3dff41
commit 49fc44bb4d
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
4 changed files with 152 additions and 40 deletions

View File

@ -0,0 +1,28 @@
package com.boydti.fawe.object.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.pattern.Pattern;
import java.io.InputStream;
public class FlattenBrush extends HeightBrush {
public FlattenBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard) {
super(stream, rotation, yscale, tool, clipboard);
}
@Override
public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
int size = (int) sizeDouble;
Mask mask = tool.getMask();
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
mask = null;
}
heightMap.setSize(size);
heightMap.apply(editSession, mask, position, size, rotation, action == DoubleActionBrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, true);
}
}

View File

@ -16,9 +16,9 @@ import java.io.InputStream;
public class HeightBrush implements DoubleActionBrush { public class HeightBrush implements DoubleActionBrush {
public final ScalableHeightMap heightMap; public final ScalableHeightMap heightMap;
private final int rotation; public final int rotation;
double yscale = 1; public final double yscale;
private final DoubleActionBrushTool tool; public final DoubleActionBrushTool tool;
public HeightBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard) { public HeightBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard) {
this.tool = tool; this.tool = tool;
@ -45,6 +45,6 @@ public class HeightBrush implements DoubleActionBrush {
mask = null; mask = null;
} }
heightMap.setSize(size); heightMap.setSize(size);
heightMap.apply(editSession, mask, position, size, rotation, action == DoubleActionBrushTool.BrushAction.PRIMARY ? yscale : -yscale, true); heightMap.apply(editSession, mask, position, size, rotation, action == DoubleActionBrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, false);
} }
} }

View File

@ -2,7 +2,6 @@ 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.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.MaxChangedBlocksException;
@ -12,9 +11,7 @@ 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.function.mask.Mask;
import com.sk89q.worldedit.internal.LocalWorldAdapter; 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.HeightMap;
import com.sk89q.worldedit.math.convolution.HeightMapFilter;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -103,7 +100,7 @@ public class ScalableHeightMap {
return new ArrayHeightMap(array); return new ArrayHeightMap(array);
} }
public void apply(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth) throws MaxChangedBlocksException { public void apply(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
Vector top = session.getMaximumPoint(); Vector top = session.getMaximumPoint();
int maxY = top.getBlockY(); int maxY = top.getBlockY();
int diameter = 2 * size + 1; int diameter = 2 * size + 1;
@ -113,31 +110,65 @@ public class ScalableHeightMap {
int startY = pos.getBlockY() - size; int startY = pos.getBlockY() - size;
int[] newData = new int[diameter * diameter]; int[] newData = new int[diameter * diameter];
Vector mutablePos = new Vector(0, 0, 0); Vector mutablePos = new Vector(0, 0, 0);
for (int x = -size; x <= size; x++) { if (towards) {
int xx = centerX + x; int targetY = pos.getBlockY();
mutablePos.mutX(xx); for (int x = -size; x <= size; x++) {
for (int z = -size; z <= size; z++) { int xx = centerX + x;
int index = (z + size) * diameter + (x + size); mutablePos.mutX(xx);
int zz = centerZ + z; for (int z = -size; z <= size; z++) {
double raise; int index = (z + size) * diameter + (x + size);
switch (rotationMode) { int zz = centerZ + z;
default: double raise;
raise = getHeight(x, z); switch (rotationMode) {
break; default:
case 1: raise = getHeight(x, z);
raise = getHeight(z, x); break;
break; case 1:
case 2: raise = getHeight(z, x);
raise = getHeight(-x, -z); break;
break; case 2:
case 3: raise = getHeight(-x, -z);
raise = getHeight(-z, -x); break;
break; case 3:
raise = getHeight(-z, -x);
break;
}
raise = (yscale * raise);
int height = session.getHighestTerrainBlock(xx, zz, 0, 255, true);
int diff = targetY - height;
double raiseScaled = 1 + diff * (raise / (double) size);
int random = PseudoRandom.random.random(maxY + 1) < (int) ((raiseScaled - (int) raiseScaled) * (maxY + 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;
}
raise = (yscale * raise);
int random = PseudoRandom.random.random(maxY + 1) < (int) ((raise - (int) raise) * (maxY + 1)) ? 1 : 0;
int height = session.getHighestTerrainBlock(xx, zz, 0, maxY, true) + (int) raise + random;
newData[index] = height;
} }
raise = (yscale * raise);
int random = PseudoRandom.random.random(maxY + 1) < (int) ((raise - (int) raise) * (maxY + 1)) ? 1 : 0;
int height = session.getHighestTerrainBlock(xx, zz, 0, maxY, true) + (int) raise + random;
newData[index] = height;
} }
} }
int iterations = 1; int iterations = 1;
@ -145,14 +176,14 @@ public class ScalableHeightMap {
Vector max = pos.add(size, maxY, size); Vector max = pos.add(size, maxY, size);
Region region = new CuboidRegion(session.getWorld(), min, max); Region region = new CuboidRegion(session.getWorld(), min, max);
HeightMap heightMap = new HeightMap(session, region, true); HeightMap heightMap = new HeightMap(session, region, true);
if (smooth) { // if (smooth) {
try { // try {
HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1)); // HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1));
newData = filter.filter(newData, diameter, diameter); // newData = filter.filter(newData, diameter, diameter);
} catch (Throwable e) { // } catch (Throwable e) {
MainUtil.handleError(e); // MainUtil.handleError(e);
} // }
} // }
heightMap.apply(newData); heightMap.apply(newData);
} }
} }

View File

@ -29,6 +29,7 @@ import com.boydti.fawe.object.brush.CommandBrush;
import com.boydti.fawe.object.brush.CopyPastaBrush; import com.boydti.fawe.object.brush.CopyPastaBrush;
import com.boydti.fawe.object.brush.DoubleActionBrushTool; import com.boydti.fawe.object.brush.DoubleActionBrushTool;
import com.boydti.fawe.object.brush.ErodeBrush; import com.boydti.fawe.object.brush.ErodeBrush;
import com.boydti.fawe.object.brush.FlattenBrush;
import com.boydti.fawe.object.brush.HeightBrush; import com.boydti.fawe.object.brush.HeightBrush;
import com.boydti.fawe.object.brush.LineBrush; import com.boydti.fawe.object.brush.LineBrush;
import com.boydti.fawe.object.brush.RecurseBrush; import com.boydti.fawe.object.brush.RecurseBrush;
@ -405,6 +406,58 @@ public class BrushCommands {
player.print(BBC.getPrefix() + BBC.BRUSH_HEIGHT.f(radius)); player.print(BBC.getPrefix() + BBC.BRUSH_HEIGHT.f(radius));
} }
@Command(
aliases = { "flatten", "flatmap", "flat" },
usage = "[radius] [file|#clipboard|null] [rotation] [yscale]",
flags = "h",
desc = "Flatten brush",
help =
"This brush raises and lowers land towards the clicked point\n",
min = 1,
max = 4
)
@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 {
worldEdit.checkMaxBrushRadius(radius);
String filenamePng = (filename.endsWith(".png") ? filename : filename + ".png");
File file = new File(Fawe.imp().getDirectory(), "heightmap" + File.separator + filenamePng);
InputStream stream = null;
if (!file.exists()) {
if (!filename.equals("#clipboard") && filename.length() >= 7) {
try {
URL url;
if (filename.startsWith("http")) {
url = new URL(filename);
if (!url.getHost().equals("i.imgur.com")) {
throw new FileNotFoundException(filename);
}
} else {
url = new URL("https://i.imgur.com/" + filenamePng);
}
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
stream = Channels.newInputStream(rbc);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} else if (!filename.equalsIgnoreCase("#clipboard")){
try {
stream = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
DoubleActionBrushTool tool = session.getDoubleActionBrushTool(player.getItemInHand());
tool.setSize(radius);
try {
tool.setBrush(new FlattenBrush(stream, rotation, yscale, tool, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height");
} catch (EmptyClipboardException ignore) {
tool.setBrush(new FlattenBrush(stream, rotation, yscale, tool, null), "worldedit.brush.height");
}
player.print(BBC.getPrefix() + BBC.BRUSH_HEIGHT.f(radius));
}
@Command( @Command(
aliases = { "copypaste", "copy", "paste", "cp", "copypasta" }, aliases = { "copypaste", "copy", "paste", "cp", "copypasta" },
usage = "[depth]", usage = "[depth]",