diff --git a/Blarg.GameFramework/Blarg.GameFramework.csproj b/Blarg.GameFramework/Blarg.GameFramework.csproj index 9125a1e..6f8b7d7 100644 --- a/Blarg.GameFramework/Blarg.GameFramework.csproj +++ b/Blarg.GameFramework/Blarg.GameFramework.csproj @@ -210,6 +210,7 @@ + diff --git a/Blarg.GameFramework/TileMap/Lighting/LightSpreadingTileMapLighter.cs b/Blarg.GameFramework/TileMap/Lighting/LightSpreadingTileMapLighter.cs new file mode 100644 index 0000000..10a8f81 --- /dev/null +++ b/Blarg.GameFramework/TileMap/Lighting/LightSpreadingTileMapLighter.cs @@ -0,0 +1,176 @@ +using System; +using Blarg.GameFramework.TileMap.Meshes; + +namespace Blarg.GameFramework.TileMap.Lighting +{ + public class LightSpreadingTileMapLighter : BaseTileMapLighter + { + bool _doSkyLight; + bool _doTileLight; + + public LightSpreadingTileMapLighter(bool doSkyLight, bool doTileLight) + { + _doSkyLight = doSkyLight; + _doTileLight = doTileLight; + } + + public LightSpreadingTileMapLighter() + : this(true, true) + { + } + + private void spreadSkyLight(int x, int y, int z, Tile tile, byte light, TileMap tileMap) + { + if (light > 0) + { + tile.SkyLight = light; + --light; + + var left = tileMap.GetSafe(x - 1, y, z); + var right = tileMap.GetSafe(x + 1, y, z); + var forward = tileMap.GetSafe(x, y, z - 1); + var backward = tileMap.GetSafe(x, y, z + 1); + var up = tileMap.GetSafe(x, y + 1, z); + var down = tileMap.GetSafe(x, y - 1, z); + + if (left != null && (left.IsEmptySpace || !tileMap.TileMeshes.Get(left).IsOpaque(TileMesh.SIDE_RIGHT)) && left.SkyLight < light) + { + byte spreadLight = light; + if (!left.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(left).Translucency); + spreadSkyLight(x - 1, y, z, left, spreadLight, tileMap); + } + if (right != null && (right.IsEmptySpace || !tileMap.TileMeshes.Get(right).IsOpaque(TileMesh.SIDE_LEFT)) && right.SkyLight < light) + { + byte spreadLight = light; + if (!right.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(right).Translucency); + spreadSkyLight(x + 1, y, z, right, spreadLight, tileMap); + } + if (forward != null && (forward.IsEmptySpace || !tileMap.TileMeshes.Get(forward).IsOpaque(TileMesh.SIDE_BACK)) && forward.SkyLight < light) + { + byte spreadLight = light; + if (!forward.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(forward).Translucency); + spreadSkyLight(x, y, z - 1, forward, spreadLight, tileMap); + } + if (backward != null && (backward.IsEmptySpace || !tileMap.TileMeshes.Get(backward).IsOpaque(TileMesh.SIDE_FRONT)) && backward.SkyLight < light) + { + byte spreadLight = light; + if (!backward.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(backward).Translucency); + spreadSkyLight(x, y, z + 1, backward, spreadLight, tileMap); + } + if (up != null && (up.IsEmptySpace || !tileMap.TileMeshes.Get(up).IsOpaque(TileMesh.SIDE_BOTTOM)) && up.SkyLight < light) + { + byte spreadLight = light; + if (!up.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(up).Translucency); + spreadSkyLight(x, y + 1, z, up, spreadLight, tileMap); + } + if (down != null && (down.IsEmptySpace || !tileMap.TileMeshes.Get(down).IsOpaque(TileMesh.SIDE_TOP)) && down.SkyLight < light) + { + byte spreadLight = light; + if (!down.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(down).Translucency); + spreadSkyLight(x, y - 1, z, down, spreadLight, tileMap); + } + } + } + + private void spreadTileLight(int x, int y, int z, Tile tile, byte light, TileMap tileMap) + { + if (light > 0) + { + tile.TileLight = light; + --light; + + Tile left = tileMap.GetSafe(x - 1, y, z); + Tile right = tileMap.GetSafe(x + 1, y, z); + Tile forward = tileMap.GetSafe(x, y, z - 1); + Tile backward = tileMap.GetSafe(x, y, z + 1); + Tile up = tileMap.GetSafe(x, y + 1, z); + Tile down = tileMap.GetSafe(x, y - 1, z); + + if (left != null && (left.IsEmptySpace || !tileMap.TileMeshes.Get(left).IsOpaque(TileMesh.SIDE_RIGHT)) && left.TileLight < light) + { + byte spreadLight = light; + if (!left.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(left).Translucency); + spreadTileLight(x - 1, y, z, left, spreadLight, tileMap); + } + if (right != null && (right.IsEmptySpace || !tileMap.TileMeshes.Get(right).IsOpaque(TileMesh.SIDE_LEFT)) && right.TileLight < light) + { + byte spreadLight = light; + if (!right.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(right).Translucency); + spreadTileLight(x + 1, y, z, right, spreadLight, tileMap); + } + if (forward != null && (forward.IsEmptySpace || !tileMap.TileMeshes.Get(forward).IsOpaque(TileMesh.SIDE_BACK)) && forward.TileLight < light) + { + byte spreadLight = light; + if (!forward.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(forward).Translucency); + spreadTileLight(x, y, z - 1, forward, spreadLight, tileMap); + } + if (backward != null && (backward.IsEmptySpace || !tileMap.TileMeshes.Get(backward).IsOpaque(TileMesh.SIDE_FRONT)) && backward.TileLight < light) + { + byte spreadLight = light; + if (!backward.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(backward).Translucency); + spreadTileLight(x, y, z + 1, backward, spreadLight, tileMap); + } + if (up != null && (up.IsEmptySpace || !tileMap.TileMeshes.Get(up).IsOpaque(TileMesh.SIDE_BOTTOM)) && up.TileLight < light) + { + byte spreadLight = light; + if (!up.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(up).Translucency); + spreadTileLight(x, y + 1, z, up, spreadLight, tileMap); + } + if (down != null && (down.IsEmptySpace || !tileMap.TileMeshes.Get(down).IsOpaque(TileMesh.SIDE_TOP)) && down.TileLight < light) + { + byte spreadLight = light; + if (!down.IsEmptySpace) + spreadLight = Tile.AdjustLightForTranslucency(spreadLight, tileMap.TileMeshes.Get(down).Translucency); + spreadTileLight(x, y - 1, z, down, spreadLight, tileMap); + } + } + } + + public override void Light(TileMap tileMap) + { + ResetLightValues(tileMap); + + if (_doSkyLight) + CastSkyLightDown(tileMap); + + // for each light source (sky or not), recursively go through and set + // appropriate lighting for each adjacent tile + for (int y = 0; y < tileMap.Height; ++y) + { + for (int z = 0; z < tileMap.Depth; ++z) + { + for (int x = 0; x < tileMap.Width; ++x) + { + Tile tile = tileMap.Get(x, y, z); + if (tile.IsEmptySpace) + { + if (_doSkyLight && tile.IsSkyLit) + spreadSkyLight(x, y, z, tile, tile.SkyLight, tileMap); + } + else + { + if (_doTileLight) + { + TileMesh mesh = tileMap.TileMeshes.Get(tile); + if (mesh.IsLightSource) + spreadTileLight(x, y, z, tile, mesh.LightValue, tileMap); + } + } + } + } + } + } + } +} +