public void RebuildBlockSkyLight() { IBoundedLitBlockCollection[,] chunkMap = LocalBlockLightMap(); int[,] heightMap = LocalHeightMap(chunkMap); int xdim = _xdim; int ydim = _ydim; int zdim = _zdim; // 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++) { int xi = x + xdim; int zi = z + zdim; 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++) { _blockset.SetSkyLight(x, y, z, BlockInfo.MAX_LUMINANCE); } //QueueRelight(new BlockKey(x, h, z)); SpreadSkyLight(chunkMap, heightMap, x, h, z); } } }
private void SpreadSkyLight(IBoundedLitBlockCollection[,] chunkMap, int[,] heightMap, int lx, int ly, int lz) { BlockInfo primary = _blockset.GetInfo(lx, ly, lz); int primaryLight = _blockset.GetSkyLight(lx, ly, lz); int priLum = Math.Max(BlockInfo.MAX_LUMINANCE - primary.Opacity, 0); if (primaryLight < priLum) { _blockset.SetSkyLight(lx, ly, lz, priLum); } if (primaryLight > BlockInfo.MAX_LUMINANCE - 1 || !primary.TransmitsLight) { return; } Queue <LightRecord> spread = new Queue <LightRecord>(); int xdim = _xdim; int ydim = _ydim; int zdim = _zdim; int lxi = lx + xdim; int lzi = lz + zdim; int strength = (primary.Opacity > 0) ? priLum : priLum - 1; if (ly > 0) { if (heightMap[lxi, lzi] > ly - 1) { spread.Enqueue(new LightRecord(lx, ly - 1, lz, strength)); } else { spread.Enqueue(new LightRecord(lx, ly - 1, lz, priLum)); } } if (ly < ydim - 1) { if (heightMap[lxi, lzi] > ly + 1) { spread.Enqueue(new LightRecord(lx, ly + 1, lz, strength)); } } if (heightMap[lxi - 1, lzi] > ly) { spread.Enqueue(new LightRecord(lx - 1, ly, lz, strength)); } if (heightMap[lxi + 1, lzi] > ly) { spread.Enqueue(new LightRecord(lx + 1, ly, lz, strength)); } if (heightMap[lxi, lzi - 1] > ly) { spread.Enqueue(new LightRecord(lx, ly, lz - 1, strength)); } if (heightMap[lxi, lzi + 1] > ly) { spread.Enqueue(new LightRecord(lx, ly, lz + 1, strength)); } while (spread.Count > 0) { LightRecord rec = spread.Dequeue(); int xi = rec.x + xdim; int zi = rec.z + zdim; IBoundedLitBlockCollection cc = chunkMap[xi / xdim, zi / zdim]; if (cc == null) { continue; } int x = xi % xdim; int y = rec.y; int z = zi % zdim; BlockInfo info = cc.GetInfo(x, y, z); int light = cc.GetSkyLight(x, y, z); int dimStr = Math.Max(rec.str - info.Opacity, 0); if (dimStr > light) { cc.SetSkyLight(x, y, z, dimStr); if (info.TransmitsLight) { strength = (info.Opacity > 0) ? dimStr : dimStr - 1; if (rec.y > 0) { if (heightMap[xi, zi] > rec.y - 1) { spread.Enqueue(new LightRecord(rec.x, rec.y - 1, rec.z, strength)); } else { spread.Enqueue(new LightRecord(rec.x, rec.y - 1, rec.z, dimStr)); } } if (rec.y < ydim - 1) { if (heightMap[xi, zi] > rec.y + 1) { spread.Enqueue(new LightRecord(rec.x, rec.y + 1, rec.z, strength)); } } if (heightMap[xi - 1, zi] > rec.y) { spread.Enqueue(new LightRecord(rec.x - 1, rec.y, rec.z, strength)); } if (heightMap[xi + 1, zi] > rec.y) { spread.Enqueue(new LightRecord(rec.x + 1, rec.y, rec.z, strength)); } if (heightMap[xi, zi - 1] > rec.y) { spread.Enqueue(new LightRecord(rec.x, rec.y, rec.z - 1, strength)); } if (heightMap[xi, zi + 1] > rec.y) { spread.Enqueue(new LightRecord(rec.x, rec.y, rec.z + 1, strength)); } } } } }
private void UpdateBlockSkyLight() { IBoundedLitBlockCollection[,] chunkMap = LocalBlockLightMap(); int xdim = _xdim; int ydim = _ydim; int zdim = _zdim; while (_update.Count > 0) { BlockKey k = _update.Dequeue(); int index = LightBitmapIndex(k); _lightbit[index] = false; int xi = k.x + xdim; int zi = k.z + zdim; IBoundedLitBlockCollection cc = chunkMap[xi / xdim, zi / zdim]; if (cc == null) { continue; } int x = xi % xdim; int y = k.y; int z = zi % zdim; int lightval = cc.GetSkyLight(x, y, z); BlockInfo info = cc.GetInfo(x, y, z); int light = BlockInfo.MIN_LUMINANCE; if (cc.GetHeight(x, z) <= y) { light = BlockInfo.MAX_LUMINANCE; } else { int lle = NeighborSkyLight(chunkMap, k.x, k.y, k.z - 1); int lln = NeighborSkyLight(chunkMap, k.x - 1, k.y, k.z); int lls = NeighborSkyLight(chunkMap, k.x, k.y, k.z + 1); int llw = NeighborSkyLight(chunkMap, k.x + 1, k.y, k.z); int lld = NeighborSkyLight(chunkMap, k.x, k.y - 1, k.z); int llu = NeighborSkyLight(chunkMap, k.x, k.y + 1, k.z); light = Math.Max(light, lle); light = Math.Max(light, lln); light = Math.Max(light, lls); light = Math.Max(light, llw); light = Math.Max(light, lld); light = Math.Max(light, llu); } light = Math.Max(light - info.Opacity, 0); if (light != lightval) { //Console.WriteLine("Block SkyLight: ({0},{1},{2}) " + lightval + " -> " + light, k.x, k.y, k.z); cc.SetSkyLight(x, y, z, light); if (info.TransmitsLight) { if (k.y > 0) { QueueRelight(new BlockKey(k.x, k.y - 1, k.z)); } if (k.y < ydim - 1) { QueueRelight(new BlockKey(k.x, k.y + 1, k.z)); } QueueRelight(new BlockKey(k.x - 1, k.y, k.z)); QueueRelight(new BlockKey(k.x + 1, k.y, k.z)); QueueRelight(new BlockKey(k.x, k.y, k.z - 1)); QueueRelight(new BlockKey(k.x, k.y, k.z + 1)); } } } }