diff options
| author | hazel <hazel@hazelthats.me> | 2026-01-26 22:04:39 +0100 |
|---|---|---|
| committer | hazel <hazel@hazelthats.me> | 2026-01-26 22:04:39 +0100 |
| commit | 567c422f8cd42eba2437f9a8c2522716a1649be7 (patch) | |
| tree | 93c5b296f3b7c14b626d0aadf5cad37764c41c74 /source/graphics/lighting/LightMap.cs | |
| download | celesteia-567c422f8cd42eba2437f9a8c2522716a1649be7.tar.gz celesteia-567c422f8cd42eba2437f9a8c2522716a1649be7.tar.bz2 celesteia-567c422f8cd42eba2437f9a8c2522716a1649be7.zip | |
celesteia archive, last updated april 9th 2024
Signed-off-by: hazel <hazel@hazelthats.me>
Diffstat (limited to 'source/graphics/lighting/LightMap.cs')
| -rw-r--r-- | source/graphics/lighting/LightMap.cs | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/source/graphics/lighting/LightMap.cs b/source/graphics/lighting/LightMap.cs new file mode 100644 index 0000000..4fb3b9d --- /dev/null +++ b/source/graphics/lighting/LightMap.cs @@ -0,0 +1,139 @@ +using System; +using Celesteia.Resources.Types; +using Microsoft.Xna.Framework; + +namespace Celesteia.Graphics.Lighting { + public class LightMap { + private bool[,] _emit; + private LightColor[,] _lightColors; + private int[,] _propagation; + + public readonly int Width; + public readonly int Height; + + public LightMap(int width, int height) { + Width = width; + Height = height; + + _emit = new bool[width, height]; + _lightColors = new LightColor[width, height]; + _propagation = new int[width, height]; + } + + public bool AddForeground(int x, int y, BlockLightProperties blockLight) { + if (blockLight.Emits) AddLight(x, y, blockLight.Emits, blockLight.Color, blockLight.Propagation); + else if (blockLight.Occludes) AddDarkness(x, y); + + return blockLight.Emits || blockLight.Occludes; + } + + public bool AddBackground(int x, int y, BlockLightProperties blockLight) { + if (blockLight.Occludes) { + if (blockLight.Emits) AddLight(x, y, blockLight.Emits, blockLight.Color, blockLight.Propagation); + else AddDarkness(x, y); + } + + return blockLight.Occludes; + } + + public void AddLight(int x, int y, bool emit, LightColor color, int propagation) { + if (!InMap(x, y)) return; + + _emit[x, y] = emit; + _lightColors[x, y] = color; + _propagation[x, y] = propagation; + } + + public void AddDarkness(int x, int y) => AddLight(x, y, false, LightColor.black, 0); + + public void Propagate() { + for (int x = 0; x < Width; x++) + for (int y = 0; y < Height; y++) + if (_emit[x, y]) + PropagateFrom(x, y, _lightColors[x, y], _propagation[x, y]); + } + + public bool InMap(int x, int y) => !(x < 0 || x >= Width || y < 0 || y >= Height); + + private float _normalDropoff = 0.7f; + private float _diagonalDropoff => _normalDropoff * _normalDropoff; + private int lookX; + private int lookY; + private LightColor _target; + private int distance; + private void PropagateFrom(int x, int y, LightColor color, int propagation) { + for (int i = -propagation; i <= propagation; i++) { + lookX = x + i; + for (int j = -propagation; j <= propagation; j++) { + lookY = y + j; + + if (!InMap(lookX, lookY)) continue; + if (_emit[lookX, lookY]) continue; + + distance = Math.Max(Math.Abs(i), Math.Abs(j)); + + _target = color * (float)(distance > propagation - 3 ? Math.Pow((i != 0 && j != 0) ? _diagonalDropoff : _normalDropoff, distance - (propagation - 3)) : 1); + + if (!_lightColors[lookX, lookY].Equals(LightColor.black)) + { + _target.R = MathF.Max(_target.R, _lightColors[lookX, lookY].R); + _target.G = MathF.Max(_target.G, _lightColors[lookX, lookY].G); + _target.B = MathF.Max(_target.B, _lightColors[lookX, lookY].B); + } + + _lightColors[lookX, lookY] = _target; + } + } + } + + private Color[] _colorMap; + public void CreateColorMap() { + _colorMap = new Color[Width * Height]; + + for (int y = 0; y < Height; y++) + for (int x = 0; x < Width; x++) + _colorMap[y * Width + x] = _lightColors[x, y].Color; + } + + public Color[] GetColors() => _colorMap; + public int GetColorCount() => _colorMap.Length; + } + + public struct LightColor { + public static LightColor black = new LightColor(0, 0, 0); + public static LightColor white = new LightColor(255f, 255f, 255f); + public static LightColor ambient = new LightColor(255f, 255f, 255f); + public static LightColor cave = new LightColor(40f, 40f, 40f); + + public float R; + public float G; + public float B; + + public Color Color => new Color(R / 255f, G / 255f, B / 255f); + + public LightColor(float r, float g, float b) { + R = Math.Clamp(r, 0, 255f); + G = Math.Clamp(g, 0, 255f); + B = Math.Clamp(b, 0, 255f); + } + + public bool IsCutoff(float cutoff) => R > cutoff || G > cutoff || B > cutoff; + public bool Overpowers(LightColor other) => R > other.R || G > other.G || B > other.B; + public bool Equals(LightColor other) => R == other.R && G == other.G && B == other.B; + public static LightColor FromColor(Color color) => new LightColor(color.R, color.G, color.B); + + public static LightColor operator *(LightColor a, LightColor b) { + a.R *= b.R; + a.G *= b.G; + a.B *= b.B; + return a; + } + + public static LightColor operator *(LightColor a, float multiplier) { + a.R *= multiplier; + a.G *= multiplier; + a.B *= multiplier; + return a; + } + } +}
\ No newline at end of file |
