diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java index 6fe36da84..11eeb0302 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java @@ -74,7 +74,7 @@ public class EmbeddedEnvironment extends AtomicReferenceCounted implements Envir @Override public void invalidateLight() { - lightVolume.delete(); + lightVolume.clear(); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java index 0d6a9773d..d2300e4d1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java @@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.engine.embed; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.backend.util.BoxSet; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import net.minecraft.core.BlockPos; @@ -13,20 +12,28 @@ import net.minecraft.world.level.LightLayer; public class EmbeddedLightVolume { public static final long STRIDE = Short.BYTES; - private final BoxSet wantedCoords = new BoxSet(); + private int minX; + private int minY; + private int minZ; + private int maxX; + private int maxY; + private int maxZ; private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos(); @Nullable protected MemoryBlock memoryBlock; + protected boolean empty = true; public boolean empty() { - return memoryBlock == null; + return empty; } public void collect(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) { maybeExpandForBox(minX, minY, minZ, sizeX, sizeY, sizeZ); + empty = false; + for (int z = minZ; z < minZ + sizeZ; z++) { for (int y = minY; y < minY + sizeY; y++) { for (int x = minX; x < minX + sizeX; x++) { @@ -46,47 +53,85 @@ public class EmbeddedLightVolume { MemoryUtil.memPutShort(ptr, (short) ((block << 4) | sky << 12)); } - private void maybeExpandForBox(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) { - int oldMinX = wantedCoords.minX(); - int oldMinY = wantedCoords.minY(); - int oldMinZ = wantedCoords.minZ(); - int oldSizeX = wantedCoords.sizeX(); - int oldSizeY = wantedCoords.sizeY(); - int oldSizeZ = wantedCoords.sizeZ(); + private void maybeExpandForBox(int x, int y, int z, int sizeX, int sizeY, int sizeZ) { + if (empty || memoryBlock == null) { + // We're either brand new or recently #clear'd, + // so none of the previous min/max values have any meaning. + this.minX = x; + this.minY = y; + this.minZ = z; + this.maxX = x + sizeX; + this.maxY = y + sizeY; + this.maxZ = z + sizeZ; - var grew = wantedCoords.add(minX, minY, minZ, sizeX, sizeY, sizeZ); - - if (memoryBlock == null) { int volume = sizeX * sizeY * sizeZ; + long neededSize = volume * STRIDE; - memoryBlock = MemoryBlock.malloc(volume * STRIDE); + if (memoryBlock == null) { + memoryBlock = MemoryBlock.malloc(neededSize); + } else if (memoryBlock.size() < neededSize) { + // There's some memory left over from before the last #clear, + // but not enough to hold this initial box. Need to grow the block. + memoryBlock.realloc(neededSize); + } + // else: we have enough memory left over to hold this box, nothing to do! return; } - if (!grew) { + int oldMinX = this.minX; + int oldMinY = this.minY; + int oldMinZ = this.minZ; + int oldSizeX = this.sizeX(); + int oldSizeY = this.sizeY(); + int oldSizeZ = this.sizeZ(); + boolean changed = false; + + if (x < this.minX) { + this.minX = x; + changed = true; + } + if (y < this.minY) { + this.minY = y; + changed = true; + } + if (z < this.minZ) { + this.minZ = z; + changed = true; + } + if (x + sizeX > this.maxX) { + this.maxX = x + sizeX; + changed = true; + } + if (y + sizeY > this.maxY) { + this.maxY = y + sizeY; + changed = true; + } + if (z + sizeZ > this.maxZ) { + this.maxZ = z + sizeZ; + changed = true; + } + + if (!changed) { return; } - int newVolume = wantedCoords.volume(); + int volume = volume(); - MemoryBlock newBlock = MemoryBlock.malloc(newVolume * STRIDE); + memoryBlock = memoryBlock.realloc(volume * STRIDE); - int xOff = oldMinX - wantedCoords.minX(); - int yOff = oldMinY - wantedCoords.minY(); - int zOff = oldMinZ - wantedCoords.minZ(); + int xOff = oldMinX - minX; + int yOff = oldMinY - minY; + int zOff = oldMinZ - minZ; - blit(memoryBlock, 0, 0, 0, oldSizeX, oldSizeY, newBlock, xOff, yOff, zOff, wantedCoords.sizeX(), wantedCoords.sizeY(), oldSizeX, oldSizeY, oldSizeZ); - - memoryBlock.free(); - memoryBlock = newBlock; + blit(memoryBlock.ptr(), 0, 0, 0, oldSizeX, oldSizeY, memoryBlock.ptr(), xOff, yOff, zOff, sizeX(), sizeY(), oldSizeX, oldSizeY, oldSizeZ); } - public static void blit(MemoryBlock src, int srcX, int srcY, int srcZ, int srcSizeX, int srcSizeY, MemoryBlock dst, int dstX, int dstY, int dstZ, int dstSizeX, int dstSizeY, int sizeX, int sizeY, int sizeZ) { + public static void blit(long src, int srcX, int srcY, int srcZ, int srcSizeX, int srcSizeY, long dst, int dstX, int dstY, int dstZ, int dstSizeX, int dstSizeY, int sizeX, int sizeY, int sizeZ) { for (int z = 0; z < sizeZ; z++) { for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { - long srcPtr = src.ptr() + offset(x + srcX, y + srcY, z + srcZ, srcSizeX, srcSizeY); - long dstPtr = dst.ptr() + offset(x + dstX, y + dstY, z + dstZ, dstSizeX, dstSizeY); + long srcPtr = src + offset(x + srcX, y + srcY, z + srcZ, srcSizeX, srcSizeY); + long dstPtr = dst + offset(x + dstX, y + dstY, z + dstZ, dstSizeX, dstSizeY); MemoryUtil.memPutShort(dstPtr, MemoryUtil.memGetShort(srcPtr)); } @@ -95,7 +140,11 @@ public class EmbeddedLightVolume { } public static long offset(int x, int y, int z, int sizeX, int sizeY) { - return (x + sizeX * (y + z * sizeY)) * STRIDE; + return (x + sizeX * (y + sizeY * z)) * STRIDE; + } + + public void clear() { + empty = true; } public void delete() { @@ -110,26 +159,30 @@ public class EmbeddedLightVolume { } public int x() { - return wantedCoords.minX(); + return minX; } public int y() { - return wantedCoords.minY(); + return minY; } public int z() { - return wantedCoords.minZ(); + return minZ; } public int sizeX() { - return wantedCoords.sizeX(); + return maxX - minX; } public int sizeY() { - return wantedCoords.sizeY(); + return maxY - minY; } public int sizeZ() { - return wantedCoords.sizeZ(); + return maxZ - minZ; + } + + public int volume() { + return sizeX() * sizeY() * sizeZ(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/util/BoxSet.java b/src/main/java/com/jozufozu/flywheel/backend/util/BoxSet.java deleted file mode 100644 index 13209e008..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/util/BoxSet.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.jozufozu.flywheel.backend.util; - -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongSet; -import net.minecraft.core.BlockPos; - -public class BoxSet { - private final LongSet occupied = new LongOpenHashSet(); - - private int minX; - private int minY; - private int minZ; - private int maxX; - private int maxY; - private int maxZ; - - /** - * Add a box to the set. - * - * @return {@code true} if the position or size of the set changed. - */ - public boolean add(int x, int y, int z, int sizeX, int sizeY, int sizeZ) { - boolean wasEmpty = occupied.isEmpty(); - for (int i = x; i < x + sizeX; i++) { - for (int j = y; j < y + sizeY; j++) { - for (int k = z; k < z + sizeZ; k++) { - occupied.add(BlockPos.asLong(i, j, k)); - } - } - } - - if (wasEmpty) { - this.minX = x; - this.minY = y; - this.minZ = z; - this.maxX = x + sizeX; - this.maxY = y + sizeY; - this.maxZ = z + sizeZ; - return true; - } else { - boolean changed = false; - if (x < minX) { - minX = x; - changed = true; - } - if (y < minY) { - minY = y; - changed = true; - } - if (z < minZ) { - minZ = z; - changed = true; - } - if (x + sizeX > maxX) { - maxX = x + sizeX; - changed = true; - } - if (y + sizeY > maxY) { - maxY = y + sizeY; - changed = true; - } - if (z + sizeZ > maxZ) { - maxZ = z + sizeZ; - changed = true; - } - return changed; - } - } - - /** - * Remove a box from the set. - * - * @return {@code true} if the position or size of the set changed. - */ - public boolean clear(int x, int y, int z, int sizeX, int sizeY, int sizeZ) { - for (int i = x; i < x + sizeX; i++) { - for (int j = y; j < y + sizeY; j++) { - for (int k = z; k < z + sizeZ; k++) { - occupied.remove(BlockPos.asLong(i, j, k)); - } - } - } - - if (occupied.isEmpty()) { - minX = 0; - minY = 0; - minZ = 0; - maxX = 0; - maxY = 0; - maxZ = 0; - return true; - } else { - ExtremaFinder finder = new ExtremaFinder(); - occupied.forEach(finder::accept); - - if (finder.volume() != volume()) { - minX = finder.minX; - minY = finder.minY; - minZ = finder.minZ; - maxX = finder.maxX; - maxY = finder.maxY; - maxZ = finder.maxZ; - return true; - } else { - return false; - } - } - } - - public int minX() { - return minX; - } - - public int minY() { - return minY; - } - - public int minZ() { - return minZ; - } - - public int sizeX() { - return maxX - minX; - } - - public int sizeY() { - return maxY - minY; - } - - public int sizeZ() { - return maxZ - minZ; - } - - public int volume() { - return sizeX() * sizeY() * sizeZ(); - } - - private static class ExtremaFinder { - int minX = Integer.MAX_VALUE; - int minY = Integer.MAX_VALUE; - int minZ = Integer.MAX_VALUE; - int maxX = Integer.MIN_VALUE; - int maxY = Integer.MIN_VALUE; - int maxZ = Integer.MIN_VALUE; - - public void accept(long l) { - int x = BlockPos.getX(l); - int y = BlockPos.getY(l); - int z = BlockPos.getZ(l); - if (x < minX) { - minX = x; - } - if (y < minY) { - minY = y; - } - if (z < minZ) { - minZ = z; - } - if (x > maxX) { - maxX = x; - } - if (y > maxY) { - maxY = y; - } - if (z > maxZ) { - maxZ = z; - } - } - - public int volume() { - return (maxX - minX) * (maxY - minY) * (maxZ - minZ); - } - } -}