mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-14 00:06:12 +01:00
Smart lighting
- Do not delete light volume memory when invalidated. Keep the block around, and then use it again later when we collect more light - Do not allocate fresh memory blocks when growing a light volume. Turns out self-blitting is perfectly fine since we always start from the volume's origin - Inline BoxSet back into light volume. The precise tracking it did is no longer relevant now that the embedding api has been simplified - Light volumes now directly
This commit is contained in:
parent
cfe6f3901b
commit
84515316a7
3 changed files with 88 additions and 209 deletions
|
@ -74,7 +74,7 @@ public class EmbeddedEnvironment extends AtomicReferenceCounted implements Envir
|
|||
|
||||
@Override
|
||||
public void invalidateLight() {
|
||||
lightVolume.delete();
|
||||
lightVolume.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue