Inventory management focused game written in Godot / C#
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

69 lines
2.3 KiB

public partial class ReplacePalette : Node3D
{
readonly struct TextureInfo(float min, float max)
{
public float MinBrightness { get; } = min;
public float MaxBrightness { get; } = max;
}
static Shader _paletteShader;
static System.Collections.Generic.Dictionary<Texture2D, TextureInfo> _textureCache = [];
[Export] public Texture2D Palette { get; set; }
public override void _Ready()
{
_paletteShader ??= Load<Shader>("res://assets/shaders/palette_swap.gdshader");
ReplaceShaderRecursive(this, Palette);
}
static void ReplaceShaderRecursive(Node node, Texture2D palette)
{
if (node is MeshInstance3D mesh) {
var oldMaterial = (StandardMaterial3D)mesh.Mesh.SurfaceGetMaterial(0);
var texture = oldMaterial.AlbedoTexture;
var info = GetOrCreateTextureInfo(texture);
var material = new ShaderMaterial { Shader = _paletteShader };
material.SetShaderParameter("palette", palette);
material.SetShaderParameter("albedo_texture", texture);
material.SetShaderParameter("min_brightness", info.MinBrightness);
material.SetShaderParameter("max_brightness", info.MaxBrightness);
mesh.MaterialOverride = material;
}
foreach (var child in node.GetChildren())
ReplaceShaderRecursive(child, palette);
}
static TextureInfo GetOrCreateTextureInfo(Texture2D texture)
{
if (!_textureCache.TryGetValue(texture, out var info)) {
var minBrightness = 1.0f;
var maxBrightness = 0.0f;
var image = texture.GetImage();
image.Convert(Image.Format.Rgba8);
var data = image.GetData().AsSpan();
for (var i = 0; i < data.Length; i += 4) {
var rgba = data.Slice(i, 4);
if (rgba[3] <= byte.MaxValue / 2) continue;
var brightness = Max(rgba[0], Max(rgba[1], rgba[2])) / (float)byte.MaxValue;
minBrightness = Min(minBrightness, brightness);
maxBrightness = Max(maxBrightness, brightness);
}
// for (var x = 0; x < image.GetWidth(); x++)
// for (var y = 0; y < image.GetHeight(); y++) {
// var color = image.GetPixel(x, y);
// // var brightness = Max(color.R, Max(color.G, color.B));
// color.ToHsv(out _, out _, out var brightness);
// minBrightness = Min(minBrightness, brightness);
// maxBrightness = Max(maxBrightness, brightness);
// }
info = new(minBrightness, maxBrightness);
_textureCache.Add(texture, info);
}
return info;
}
}