Initial automatic relighting support for blocklight (not skylight) via chunkref manipulations. There is also untested code for recalculating an entire chunk's light. Relighting still not present in blockmanager.

This commit is contained in:
Justin Aquadro 2011-04-11 06:13:33 +00:00
parent f1cc8f13f1
commit 2adf6ced99
4 changed files with 219 additions and 5 deletions

View file

@ -6,9 +6,9 @@ namespace Substrate
{ {
public struct BlockKey : IEquatable<BlockKey> public struct BlockKey : IEquatable<BlockKey>
{ {
readonly int x; public readonly int x;
readonly int y; public readonly int y;
readonly int z; public readonly int z;
public BlockKey (int _x, int _y, int _z) public BlockKey (int _x, int _y, int _z)
{ {

View file

@ -374,6 +374,10 @@ namespace Substrate
} }
} }
// Light consistency
return true; return true;
} }
@ -729,5 +733,67 @@ namespace Substrate
} }
#endregion #endregion
public void ResetBlockLight ()
{
for (int i = 0; i < _blocks.Length; i++) {
BlockInfo info = BlockInfo.BlockTable[_blocks[i]];
if (info == null) {
_blockLight[i] = 0;
}
else {
_blockLight[i] = info.Luminance;
}
}
}
public void StepBlockLight (IChunk east, IChunk north, IChunk south, IChunk west)
{
for (int x = 0; x < XDim; x++) {
for (int z = 0; z < ZDim; z++) {
for (int y = 0; y < YDim; y++) {
int lle = NeighborLight(x, y, z - 1, east);
int lln = NeighborLight(x - 1, y, z, north);
int lls = NeighborLight(x, y, z + 1, south);
int llw = NeighborLight(x + 1, y, z, west);
int lld = NeighborLight(x, y - 1, z, null);
int llu = NeighborLight(x, y + 1, z, null);
int light = GetBlockLight(x, y, z);
light = Math.Max(light, lle - 1);
light = Math.Max(light, lln - 1);
light = Math.Max(light, lls - 1);
light = Math.Max(light, llw - 1);
light = Math.Max(light, lld - 1);
light = Math.Max(light, llu - 1);
SetBlockLight(x, y, z, light);
}
}
}
}
private int NeighborLight (int x, int y, int z, IChunk n)
{
if (y < 0 || y >= YDim) {
return 0;
}
IChunk src = this;
if (x < 0 || x >= XDim || z < 0 || z >= ZDim) {
src = n;
x = (x + XDim) % XDim;
z = (z + ZDim) % ZDim;
}
if (src == null) {
return 0;
}
BlockInfo info = src.GetBlockInfo(x, y, z);
int light = src.GetBlockLight(x, y, z);
return Math.Max(light - info.Opacity, 0);
}
} }
} }

View file

@ -6,6 +6,7 @@ using System.IO;
namespace Substrate namespace Substrate
{ {
using NBT; using NBT;
using System.Collections;
public class ChunkRef : IChunk public class ChunkRef : IChunk
{ {
@ -86,6 +87,9 @@ namespace Substrate
{ {
if (_chunk == null) { if (_chunk == null) {
_chunk = _container.GetChunk(_cx, _cz); _chunk = _container.GetChunk(_cx, _cz);
_lightbit = new BitArray(XDim * 3 * ZDim * 3 * YDim);
_update = new Queue<BlockKey>();
} }
return _chunk; return _chunk;
} }
@ -96,8 +100,9 @@ namespace Substrate
return false; return false;
} }
_dirty = true;
_cache.MarkChunkDirty(this); _cache.MarkChunkDirty(this);
_dirty = true;
return true; return true;
} }
@ -259,8 +264,16 @@ namespace Substrate
public bool SetBlockID (int lx, int ly, int lz, int id) public bool SetBlockID (int lx, int ly, int lz, int id)
{ {
BlockInfo info1 = GetChunk().GetBlockInfo(lx, ly, lz);
if (GetChunk().SetBlockID(lx, ly, lz, id)) { if (GetChunk().SetBlockID(lx, ly, lz, id)) {
MarkDirty(); MarkDirty();
BlockInfo info2 = GetChunk().GetBlockInfo(lx, ly, lz);
if (info1.Luminance != info2.Luminance || info1.Opacity != info2.Opacity) {
_update.Enqueue(new BlockKey(lx, ly, lz));
UpdateBlockLight();
}
return true; return true;
} }
return false; return false;
@ -297,7 +310,7 @@ namespace Substrate
public int GetBlockLight (int lx, int ly, int lz) public int GetBlockLight (int lx, int ly, int lz)
{ {
return GetChunk().GetBlockSkyLight(lx, ly, lz); return GetChunk().GetBlockLight(lx, ly, lz);
} }
public int GetBlockSkyLight (int lx, int ly, int lz) public int GetBlockSkyLight (int lx, int ly, int lz)
@ -409,6 +422,137 @@ namespace Substrate
} }
#endregion #endregion
private BitArray _lightbit;
private Queue<BlockKey> _update;
private void UpdateBlockLight ()
{
while (_update.Count > 0) {
BlockKey k = _update.Dequeue();
int index = LightBitmapIndex(k);
_lightbit[index] = false;
ChunkRef cc = LocalChunk(k.x, k.y, k.z);
if (cc == null) {
continue;
}
int lle = NeighborLight(k.x, k.y, k.z - 1);
int lln = NeighborLight(k.x - 1, k.y, k.z);
int lls = NeighborLight(k.x, k.y, k.z + 1);
int llw = NeighborLight(k.x + 1, k.y, k.z);
int lld = NeighborLight(k.x, k.y - 1, k.z);
int llu = NeighborLight(k.x, k.y + 1, k.z);
int x = (k.x + XDim) % XDim;
int y = k.y;
int z = (k.z + ZDim) % ZDim;
int lightval = cc.GetBlockLight(x, y, z);
BlockInfo info = cc.GetBlockInfo(x, y, z);
int light = Math.Max(info.Luminance, 0);
light = Math.Max(light, lle - 1);
light = Math.Max(light, lln - 1);
light = Math.Max(light, lls - 1);
light = Math.Max(light, llw - 1);
light = Math.Max(light, lld - 1);
light = Math.Max(light, llu - 1);
light = Math.Max(light - info.Opacity, 0);
if (light != lightval) {
//Console.WriteLine("Block Light: ({0},{1},{2}) " + lightval + " -> " + light, k.x, k.y, k.z);
cc.SetBlockLight(x, y, z, light);
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 - 1, k.z));
QueueRelight(new BlockKey(k.x, k.y + 1, k.z));
QueueRelight(new BlockKey(k.x, k.y, k.z - 1));
QueueRelight(new BlockKey(k.x, k.y, k.z + 1));
}
}
}
private int LightBitmapIndex (BlockKey key)
{
int x = key.x + XDim;
int y = key.y;
int z = key.z + ZDim;
int zstride = YDim;
int xstride = ZDim * 3 * zstride;
return (x * xstride) + (z * zstride) + y;
}
private void QueueRelight (BlockKey key)
{
if (key.x < -15 || key.x >= 31 || key.z < -15 || key.z >= 31) {
return;
}
int index = LightBitmapIndex(key);
if (!_lightbit[index]) {
_lightbit[index] = true;
_update.Enqueue(key);
}
}
private ChunkRef LocalChunk (int lx, int ly, int lz)
{
if (lx < 0) {
if (lz < 0) {
return _container.GetChunkRef(_cx - 1, _cz - 1);
}
else if (lz >= ZDim) {
return _container.GetChunkRef(_cx - 1, _cz + 1);
}
return _container.GetChunkRef(_cx - 1, _cz);
}
else if (lx >= XDim) {
if (lz < 0) {
return _container.GetChunkRef(_cx + 1, _cz - 1);
}
else if (lz >= ZDim) {
return _container.GetChunkRef(_cx + 1, _cz + 1);
}
return _container.GetChunkRef(_cx + 1, _cz);
}
else {
if (lz < 0) {
return _container.GetChunkRef(_cx, _cz - 1);
}
else if (lz >= ZDim) {
return _container.GetChunkRef(_cx, _cz + 1);
}
return this;
}
}
private int NeighborLight (int x, int y, int z)
{
if (y < 0 || y >= YDim) {
return 0;
}
ChunkRef src = LocalChunk(x, y, z);
if (src == null) {
return 0;
}
x = (x + XDim) % XDim;
z = (z + ZDim) % ZDim;
BlockInfo info = src.GetBlockInfo(x, y, z);
int light = src.GetBlockLight(x, y, z);
return Math.Max(light, info.Luminance);
}
} }
} }

View file

@ -271,6 +271,10 @@ namespace Substrate
public bool ChunkExists (int lcx, int lcz) public bool ChunkExists (int lcx, int lcz)
{ {
if (lcx < 0 || lcx >= 32 || lcz < 0 || lcz >= 32) {
return false;
}
RegionFile rf = GetRegionFile(); RegionFile rf = GetRegionFile();
return rf.HasChunk(lcx, lcz); return rf.HasChunk(lcx, lcz);
} }