forked from mirrors/NBTExplorer
Thanks to caching, rebuilding the skylight is now half the cost. I'm sure the algorithm can still be fundamentally improved, however.
This commit is contained in:
parent
e78f28b25f
commit
0b2db7934d
1 changed files with 85 additions and 34 deletions
|
@ -483,34 +483,27 @@ namespace Substrate
|
|||
{
|
||||
GetChunk();
|
||||
|
||||
ChunkRef[,] chunkMap = LocalChunkMap();
|
||||
int[,] heightMap = LocalHeightMap(chunkMap);
|
||||
|
||||
// Optimization - only need to queue at level of highest neighbor's height
|
||||
for (int x = 0; x < XDim; x++) {
|
||||
for (int z = 0; z < ZDim; z++) {
|
||||
ChunkRef ce = LocalChunk(x, 0, z - 1);
|
||||
ChunkRef cn = LocalChunk(x - 1, 0, z);
|
||||
ChunkRef cs = LocalChunk(x + 1, 0, z);
|
||||
ChunkRef cw = LocalChunk(x, 0, z + 1);
|
||||
int xi = x + XDim;
|
||||
int zi = z + ZDim;
|
||||
|
||||
int h = GetHeight(x, z);
|
||||
if (ce != null) {
|
||||
h = Math.Max(h, ce.GetHeight(x, ZDim - 1));
|
||||
}
|
||||
if (cn != null) {
|
||||
h = Math.Max(h, cn.GetHeight(XDim - 1, z));
|
||||
}
|
||||
if (cs != null) {
|
||||
h = Math.Max(h, cs.GetHeight(0, z));
|
||||
}
|
||||
if (cw != null) {
|
||||
h = Math.Max(h, cw.GetHeight(x, 0));
|
||||
}
|
||||
int h = heightMap[xi, zi];
|
||||
h = Math.Max(h, heightMap[xi, zi - 1]);
|
||||
h = Math.Max(h, heightMap[xi - 1, zi]);
|
||||
h = Math.Max(h, heightMap[xi + 1, zi]);
|
||||
h = Math.Max(h, heightMap[xi, zi + 1]);
|
||||
|
||||
for (int y = h + 1; y < YDim; y++) {
|
||||
SetBlockSkyLight(x, y, z, BlockInfo.MAX_LUMINANCE);
|
||||
}
|
||||
|
||||
//QueueRelight(new BlockKey(x, h, z));
|
||||
SpreadSkyLight(x, h, z);
|
||||
SpreadSkyLight(chunkMap, heightMap, x, h, z);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,7 +579,7 @@ namespace Substrate
|
|||
}
|
||||
}
|
||||
|
||||
private void SpreadSkyLight (int lx, int ly, int lz)
|
||||
private void SpreadSkyLight (ChunkRef[,] chunkMap, int[,] heightMap, int lx, int ly, int lz)
|
||||
{
|
||||
BlockInfo primary = GetBlockInfo(lx, ly, lz);
|
||||
int primaryLight = GetBlockSkyLight(lx, ly, lz);
|
||||
|
@ -602,30 +595,46 @@ namespace Substrate
|
|||
|
||||
Queue<LightRecord> spread = new Queue<LightRecord>();
|
||||
|
||||
if (GetHeight(lx, lz) > ly - 1) {
|
||||
int lxi = lx + XDim;
|
||||
int lzi = lz + ZDim;
|
||||
|
||||
if (heightMap[lxi, lzi] > ly - 1) {
|
||||
spread.Enqueue(new LightRecord(lx, ly - 1, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
}
|
||||
else {
|
||||
spread.Enqueue(new LightRecord(lx, ly - 1, lz, BlockInfo.MAX_LUMINANCE));
|
||||
}
|
||||
|
||||
spread.Enqueue(new LightRecord(lx - 1, ly, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
spread.Enqueue(new LightRecord(lx + 1, ly, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
spread.Enqueue(new LightRecord(lx, ly + 1, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
spread.Enqueue(new LightRecord(lx, ly, lz - 1, BlockInfo.MAX_LUMINANCE - 1));
|
||||
spread.Enqueue(new LightRecord(lx, ly, lz + 1, BlockInfo.MAX_LUMINANCE - 1));
|
||||
if (heightMap[lxi - 1, lzi] > ly) {
|
||||
spread.Enqueue(new LightRecord(lx - 1, ly, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
}
|
||||
if (heightMap[lxi + 1, lzi] > ly) {
|
||||
spread.Enqueue(new LightRecord(lx + 1, ly, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
}
|
||||
if (heightMap[lxi, lzi] > ly + 1) {
|
||||
spread.Enqueue(new LightRecord(lx, ly + 1, lz, BlockInfo.MAX_LUMINANCE - 1));
|
||||
}
|
||||
if (heightMap[lxi, lzi] > ly) {
|
||||
spread.Enqueue(new LightRecord(lx, ly, lz - 1, BlockInfo.MAX_LUMINANCE - 1));
|
||||
}
|
||||
if (heightMap[lxi, lzi + 1] > ly) {
|
||||
spread.Enqueue(new LightRecord(lx, ly, lz + 1, BlockInfo.MAX_LUMINANCE - 1));
|
||||
}
|
||||
|
||||
while (spread.Count > 0) {
|
||||
LightRecord rec = spread.Dequeue();
|
||||
|
||||
ChunkRef cc = LocalChunk(rec.x, rec.y, rec.z);
|
||||
int xi = rec.x + XDim;
|
||||
int zi = rec.z + ZDim;
|
||||
|
||||
ChunkRef cc = chunkMap[xi / XDim, zi / ZDim];
|
||||
if (cc == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int x = (rec.x + XDim) % XDim;
|
||||
int x = xi % XDim;
|
||||
int y = rec.y;
|
||||
int z = (rec.z + ZDim) % ZDim;
|
||||
int z = zi % ZDim;
|
||||
|
||||
BlockInfo info = cc.GetBlockInfo(x, y, z);
|
||||
int light = cc.GetBlockSkyLight(x, y, z);
|
||||
|
@ -642,26 +651,26 @@ namespace Substrate
|
|||
spread.Enqueue(new LightRecord(rec.x, rec.y, rec.z - 1, dimStr - 1));
|
||||
spread.Enqueue(new LightRecord(rec.x, rec.y, rec.z + 1, dimStr - 1));
|
||||
|
||||
if (cc.GetHeight(x, z) > rec.y - 1) {
|
||||
if (heightMap[xi, zi] > rec.y - 1) {
|
||||
spread.Enqueue(new LightRecord(rec.x, rec.y - 1, rec.z, dimStr - 1));
|
||||
}
|
||||
else {
|
||||
spread.Enqueue(new LightRecord(rec.x, rec.y - 1, rec.z, dimStr));
|
||||
}
|
||||
|
||||
if (NeighborHeight(rec.x - 1, rec.z) > rec.y) {
|
||||
if (heightMap[xi - 1, zi] > rec.y) {
|
||||
spread.Enqueue(new LightRecord(rec.x - 1, rec.y, rec.z, dimStr - 1));
|
||||
}
|
||||
if (NeighborHeight(rec.x + 1, rec.z) > rec.y) {
|
||||
if (heightMap[xi + 1, zi] > rec.y) {
|
||||
spread.Enqueue(new LightRecord(rec.x + 1, rec.y, rec.z, dimStr - 1));
|
||||
}
|
||||
if (cc.GetHeight(x, z) > rec.y + 1) {
|
||||
if (heightMap[xi, zi] > rec.y + 1) {
|
||||
spread.Enqueue(new LightRecord(rec.x, rec.y + 1, rec.z, dimStr - 1));
|
||||
}
|
||||
if (NeighborHeight(rec.x, rec.z - 1) > rec.y) {
|
||||
if (heightMap[xi, zi] > rec.y) {
|
||||
spread.Enqueue(new LightRecord(rec.x, rec.y, rec.z - 1, dimStr - 1));
|
||||
}
|
||||
if (NeighborHeight(rec.x, rec.z + 1) > rec.y) {
|
||||
if (heightMap[xi, zi + 1] > rec.y) {
|
||||
spread.Enqueue(new LightRecord(rec.x, rec.y, rec.z + 1, dimStr - 1));
|
||||
}
|
||||
}
|
||||
|
@ -1040,6 +1049,48 @@ namespace Substrate
|
|||
QueueRelight(new BlockKey(x1, y1, z1));
|
||||
}
|
||||
}
|
||||
|
||||
private ChunkRef[,] LocalChunkMap ()
|
||||
{
|
||||
ChunkRef[,] map = new ChunkRef[3, 3];
|
||||
|
||||
map[0,0] = _container.GetChunkRef(_cx - 1, _cz - 1);
|
||||
map[0,1] = _container.GetChunkRef(_cx - 1, _cz);
|
||||
map[0,2] = _container.GetChunkRef(_cx - 1, _cz + 1);
|
||||
map[1,0] = _container.GetChunkRef(_cx, _cz - 1);
|
||||
map[1,1] = this;
|
||||
map[1,2] = _container.GetChunkRef(_cx, _cz + 1);
|
||||
map[2,0] = _container.GetChunkRef(_cx + 1, _cz - 1);
|
||||
map[2,1] = _container.GetChunkRef(_cx + 1, _cz);
|
||||
map[2,2] = _container.GetChunkRef(_cx + 1, _cz + 1);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private int[,] LocalHeightMap (ChunkRef[,] chunkMap)
|
||||
{
|
||||
int[,] map = new int[3 * XDim, 3 * ZDim];
|
||||
|
||||
for (int xi = 0; xi < 3; xi++) {
|
||||
int xoff = xi * XDim;
|
||||
for (int zi = 0; zi < 3; zi++) {
|
||||
int zoff = zi * ZDim;
|
||||
if (chunkMap[xi, zi] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int x = 0; x < XDim; x++) {
|
||||
int xx = xoff + x;
|
||||
for (int z = 0; z < ZDim; z++) {
|
||||
int zz = zoff + z;
|
||||
map[xx, zz] = chunkMap[xi, zi].GetHeight(x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue