Stencil brush + HeightMap optimizations

This commit is contained in:
Jesse Boyd 2017-03-07 23:42:21 +11:00
parent b595ec2f2d
commit 50d80b3d1c
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
5 changed files with 95 additions and 135 deletions

View File

@ -472,11 +472,6 @@ public class Fawe {
// BlockData
BlockData.inject(); // Temporary fix for 1.9.4
BundledBlockData.inject(); // Add custom rotation
try {
BundledBlockData.getInstance().loadFromResource();
} catch (IOException e) {
MainUtil.handleError(e);
}
File jar = MainUtil.getJarFile();
File extraBlocks = MainUtil.copyFile(jar, "extrablocks.json", null);
if (extraBlocks != null && extraBlocks.exists()) {

View File

@ -16,6 +16,7 @@ import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.blocks.ImmutableBlock;
import com.sk89q.worldedit.blocks.ImmutableDatalessBlock;
import com.sk89q.worldedit.world.biome.BaseBiome;
@ -51,16 +52,8 @@ public class FaweCache {
*/
public final static byte[][] CACHE_Z = new byte[16][4096];
/**
* [ combined ] => id
* (combined >> 4) = id
*/
public final static short[] CACHE_ID = new short[65535];
/**
* [ combined ] => data
* (combined & 0xF) = data
*/
public final static byte[] CACHE_DATA = new byte[65535];
public final static boolean[] CACHE_PASSTHROUGH = new boolean[65535];
public final static boolean[] CACHE_TRANSLUSCENT = new boolean[65535];
/**
* Immutable biome cache
@ -162,13 +155,24 @@ public class FaweCache {
}
}
}
for (int i = 0; i < 65535; i++) {
final int j = i >> 4;
final int k = i & 0xF;
CACHE_ID[i] = (short) j;
CACHE_DATA[i] = (byte) k;
}
try {
BundledBlockData bundled = BundledBlockData.getInstance();
bundled.loadFromResource();
for (int i = 0; i < Character.MAX_VALUE; i++) {
int id = i >> 4;
int data = i & 0xf;
CACHE_TRANSLUSCENT[i] = BlockType.isTranslucent(id);
CACHE_PASSTHROUGH[i] = BlockType.canPassThrough(id, data);
BundledBlockData.BlockEntry blockEntry = bundled.findById(id);
if (blockEntry != null) {
BundledBlockData.FaweBlockMaterial material = blockEntry.material;
if (material != null) {
CACHE_TRANSLUSCENT[i] = !material.isOpaque();
CACHE_PASSTHROUGH[i] = !material.isMovementBlocker();
}
}
}
} catch (Throwable ignore) {}
for (int i = 0; i < Character.MAX_VALUE; i++) {
int id = i >> 4;
int data = i & 0xf;
@ -266,6 +270,14 @@ public class FaweCache {
CACHE_COLOR[getCombined(35, 15)] = new Color(0, 0, 0); // Black
}
public static boolean canPassThrough(int id, int data) {
return CACHE_PASSTHROUGH[FaweCache.getCombined(id, data)];
}
public static boolean isTranslucent(int id, int data) {
return CACHE_TRANSLUSCENT[FaweCache.getCombined(id, data)];
}
public static boolean isLiquidOrGas(int id) {
switch (id) {
case 0:

View File

@ -1,11 +1,12 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.object.PseudoRandom;
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.ExistingBlockMask;
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;
@ -20,15 +21,15 @@ public class StencilBrush extends HeightBrush {
@Override
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
int size = (int) sizeDouble;
Mask mask = editSession.getMask();
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
mask = null;
}
Mask mask = new ExistingBlockMask(editSession);
int maxY = editSession.getMaxY();
double scale = (yscale / sizeDouble) * (maxY + 1);
heightMap.setSize(size);
int cutoff = onlyWhite ? maxY : 0;
for (int x = -size; x <= size; x++) {
int xx = position.getBlockX() + x;
for (int z = -size; z <= size; z++) {
int zz = position.getBlockZ() + z;
double raise;
switch (rotation) {
default:raise = heightMap.getHeight(x, z); break;
@ -36,19 +37,16 @@ public class StencilBrush extends HeightBrush {
case 2: raise = heightMap.getHeight(-x, -z); break;
case 3: raise = heightMap.getHeight(-z, -x);break;
}
raise *= yscale;
if (raise == 0 || (onlyWhite && raise < 255)) {
int val = (int) Math.ceil(raise * scale);
if (val <= cutoff) {
continue;
}
if (val >= 255 || PseudoRandom.random.random(maxY) < val) {
int zz = position.getBlockZ() + z;
int y = editSession.getNearestSurfaceTerrainBlock(xx, zz, position.getBlockY(), 0, maxY);
editSession.setBlock(xx, y, zz, pattern);
}
}
}
int[] data = heightMap.generateHeightData(editSession, mask, position, size, rotation, yscale, true, false);
int diameter = size * 2;
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();
}
}
}

View File

@ -131,7 +131,7 @@ public class ScalableHeightMap {
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, true);
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));
@ -178,7 +178,7 @@ public class ScalableHeightMap {
raise = getHeight(-z, -x);
break;
}
int height = session.getHighestTerrainBlock(xx, zz, 0, 255, false);
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, 255);
if (height == 0) {
newData[index] = centerY;
continue;
@ -214,7 +214,7 @@ public class ScalableHeightMap {
raise = getHeight(-z, -x);
break;
}
int height = session.getHighestTerrainBlock(xx, zz, 0, maxY, false);
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY);
if (height == 0) {
newData[index] = centerY;
continue;

View File

@ -929,10 +929,14 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
*/
@Deprecated
public int getBlockType(final Vector position) {
return getBlockType(position.getBlockX(), position.getBlockY(), position.getBlockZ());
}
public int getBlockType(int x, int y, int z) {
if (!limit.MAX_CHECKS()) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
}
int combinedId4Data = queue.getCombinedId4DataDebug(position.getBlockX(), position.getBlockY(), position.getBlockZ(), 0, this);
int combinedId4Data = queue.getCombinedId4DataDebug(x, y, z, 0, this);
return combinedId4Data >> 4;
}
@ -977,6 +981,38 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
return this.getHighestTerrainBlock(x, z, minY, maxY, false);
}
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
int clearanceAbove = maxY - y;
int clearanceBelow = y - minY;
int clearance = Math.min(clearanceAbove, clearanceBelow);
BaseBlock block = getBlock(x, y, z);
boolean state = FaweCache.canPassThrough(block.getId(), block.getData());
int offset = state ? 0 : 1;
for (int d = 0; d <= clearance; d++) {
int y1 = y + d;
block = getLazyBlock(x, y1, z);
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y1 - offset;
int y2 = y - d;
block = getLazyBlock(x, y2, z);
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y2 + offset;
}
if (clearanceAbove != clearanceBelow) {
if (clearanceAbove < clearanceBelow) {
for (int layer = y - clearance - 1; layer >= minY; layer--) {
block = getLazyBlock(x, layer, z);
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer + offset;
}
} else {
for (int layer = y + clearance + 1; layer <= maxY; layer++) {
block = getLazyBlock(x, layer, z);
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer - offset;
}
}
}
return maxY;
}
/**
* Returns the highest solid 'terrain' block which can occur naturally.
*
@ -990,100 +1026,19 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
public int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, final boolean naturalOnly) {
maxY = Math.min(maxY, Math.max(0, maxY));
minY = Math.max(0, minY);
for (int y = maxY; y >= minY; --y) {
BaseBlock block = getLazyBlock(x, y, z);
final int id = block.getId();
int data;
switch (id) {
case 0: {
continue;
}
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 25:
case 30:
case 32:
case 37:
case 39:
case 40:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 51:
case 52:
case 54:
case 55:
case 56:
case 57:
case 58:
case 60:
case 61:
case 62:
case 7:
case 8:
case 9:
case 10:
case 11:
case 73:
case 74:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 84:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 117:
case 121:
case 122:
case 123:
case 124:
case 129:
case 133:
case 138:
case 137:
case 140:
case 165:
case 166:
case 169:
case 170:
case 172:
case 173:
case 174:
case 176:
case 177:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
if (naturalOnly) {
for (int y = maxY; y >= minY; --y) {
BaseBlock block = getLazyBlock(x, y, z);
if (BlockType.isNaturalTerrainBlock(block.getId(), block.getData())) {
return y;
default:
data = 0;
}
}
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) {
return y;
} else {
for (int y = maxY; y >= minY; --y) {
BaseBlock block = getLazyBlock(x, y, z);
if (!FaweCache.canPassThrough(block.getId(), block.getData())) {
return y;
}
}
}
return minY;