Skip to content

Commit

Permalink
Improve ArbitraryShape caching
Browse files Browse the repository at this point in the history
Every point is now only evaluated once.
  • Loading branch information
TomyLobo authored and me4502 committed Jun 18, 2023
1 parent faf4d7c commit 28ca9e5
Showing 1 changed file with 69 additions and 79 deletions.
Expand Up @@ -31,27 +31,33 @@
* {@link #getMaterial} method.
*/
public abstract class ArbitraryShape {
/**
* This Object instance is used for cache entries that are known to be outside the shape.
*/
private static final Object OUTSIDE = new Object();

protected final Region extent;

private final int cacheOffsetX;
private final int cacheOffsetY;
private final int cacheOffsetZ;
@SuppressWarnings("FieldCanBeLocal")
private final int cacheSizeX;
private final int cacheSizeY;
private final int cacheSizeZ;

/**
* Cache for expression results.
*
* <p>
* Cache entries:
* 0 = unknown
* -1 = outside
* 1 = inside
* </p>
* <p>Possible cache entries:
* <ul>
* <li>null = unknown</li>
* <li>ArbitraryShape.OUTSIDE = outside</li>
* <li>any BaseBlock = inside</li>
* <li>anything else = (invalid, not used)</li>
* </ul>
*/
private final byte[] cache;
private final Object[] cache;

public ArbitraryShape(Region extent) {
this.extent = extent;
Expand All @@ -67,7 +73,7 @@ public ArbitraryShape(Region extent) {
cacheSizeY = max.getY() - cacheOffsetY + 2;
cacheSizeZ = max.getZ() - cacheOffsetZ + 2;

cache = new byte[cacheSizeX * cacheSizeY * cacheSizeZ];
cache = new Object[cacheSizeX * cacheSizeY * cacheSizeZ];
}

protected Region getExtent() {
Expand Down Expand Up @@ -98,87 +104,71 @@ public int generate(EditSession editSession, Pattern pattern, boolean hollow) th
int affected = 0;

for (BlockVector3 position : getExtent()) {
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();

if (!hollow) {
BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position));
if (material != null && editSession.setBlock(position, material)) {
++affected;
}

continue;
}

BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position));
if (material == null) {
final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
cache[index] = -1;
continue;
}
final BaseBlock material = getMaterial(position, pattern, hollow);

boolean draw = false;
do {
if (!isInsideCached(x + 1, y, z, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x - 1, y, z, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y, z + 1, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y, z - 1, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y + 1, z, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y - 1, z, pattern)) {
draw = true;
break;
}
} while (false);

if (!draw) {
continue;
}

if (editSession.setBlock(position, material)) {
if (material != null && editSession.setBlock(position, material)) {
++affected;
}
}

return affected;
}

private boolean isInsideCached(int x, int y, int z, Pattern pattern) {
final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
private BaseBlock getMaterial(BlockVector3 position, Pattern pattern, boolean hollow) {
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();

final BaseBlock defaultMaterial = pattern.applyBlock(position);

if (!hollow) {
return getMaterial(x, y, z, defaultMaterial);
}

final Object cacheEntry = getMaterialCached(x, y, z, defaultMaterial);
if (cacheEntry == OUTSIDE) {
return null;
}

final BaseBlock material = (BaseBlock) cacheEntry;

switch (cache[index]) {
case 0:
BaseBlock mat = getMaterial(x, y, z, pattern.applyBlock(BlockVector3.at(x, y, z)));
if (mat == null) {
cache[index] = -1;
return false;
}
cache[index] = 1;
return true;

case -1:
// outside
return false;

default:
// inside
return true;
if (isOutsideCached(x + 1, y, z, pattern)) {
return material;
}
if (isOutsideCached(x - 1, y, z, pattern)) {
return material;
}
if (isOutsideCached(x, y, z + 1, pattern)) {
return material;
}
if (isOutsideCached(x, y, z - 1, pattern)) {
return material;
}
if (isOutsideCached(x, y + 1, z, pattern)) {
return material;
}
if (isOutsideCached(x, y - 1, z, pattern)) {
return material;
}

return null;
}

private boolean isOutsideCached(int x, int y, int z, Pattern pattern) {
return getMaterialCached(x, y, z, pattern.applyBlock(BlockVector3.at(x, y, z))) == OUTSIDE;
}

private Object getMaterialCached(int x, int y, int z, BaseBlock defaultMaterial) {
final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
final Object cacheEntry = cache[index];
if (cacheEntry == null) {
final BaseBlock material = getMaterial(x, y, z, defaultMaterial);
if (material == null) {
return cache[index] = OUTSIDE;
} else {
return cache[index] = material;
}
}
return cacheEntry;
}
}

0 comments on commit 28ca9e5

Please sign in to comment.