using System;
using Godot;
using IslaApocalypse.Core;
namespace IslaApocalypse.Tools
{
///
/// THE LABELED-REGIONS OVERLAY (chat2/07): the mainland one tint, EACH island component an
/// individually distinct colour, the components the speck revert removed in a dim red, the midline
/// drawn — so the developer can SEE that components are identified correctly and catch an
/// 8-connectivity mislabel (two touching blobs coloured as one, one mass coloured as two).
///
/// ⚠ A DIAGNOSTIC, NOT A MAP. It draws the region layer's id map, which is DATA. No hypsometry, no
/// hillshade — flat tints on purpose. The relief / grayscale plates stay on the provisional palette.
/// Presentation only: it is handed arrays and returns a PNG.
///
public static class RegionOverlayRenderer
{
private static readonly Color Sea = new(0.055f, 0.110f, 0.235f);
private static readonly Color Mainland = new(0.340f, 0.380f, 0.330f);
private static readonly Color Reverted = new(0.420f, 0.080f, 0.080f); // where a reverted speck WAS (now sea)
private static readonly Color Midline = new(0.700f, 0.720f, 0.760f);
private static readonly Color Ink = new(0.941f, 0.949f, 0.961f);
/// A distinct, saturated colour per island id — golden-angle hue walk, three value steps.
public static Color IslandColor(int id)
{
float hue = (id * 137.508f) % 360f / 360f;
float val = 0.70f + 0.15f * (id % 3);
float sat = 0.85f - 0.15f * ((id / 3) % 2);
return Color.FromHsv(hue, sat, val);
}
/// The finished field's labeling (post-revert).
/// The pre-revert labeling, or null — its reverted components are painted .
public static void SavePng(RegionLabels labels, RegionLabels labelsPre, int mapSize, int revertedCount, long thresholdCells,
string absolutePath)
{
var img = Image.CreateEmpty(mapSize, mapSize, false, Image.Format.Rgb8);
int n = mapSize;
for (int x = 0; x < n; x++)
{
for (int y = 0; y < n; y++)
{
int id = labels.Id[x * n + y];
Color c;
if (id == 0)
{
c = Sea;
if (labelsPre != null)
{
int pid = labelsPre.Id[x * n + y];
if (pid != 0 && pid != labelsPre.MainlandId) c = Reverted; // was land, was not mainland, is sea now
}
}
else if (id == labels.MainlandId) c = Mainland;
else c = IslandColor(id);
img.SetPixel(x, y, c);
}
}
int mid = n / 2;
for (int x = 0; x < n; x += 3) img.SetPixel(x, mid, Midline);
var (north, south) = RegionLabeling.IslandsByHemisphere(labels);
int s = n >= 4096 ? 4 : 3;
int lh = TinyFont.Height(s) + 6;
TinyFont.Draw(img, "LABELED REGIONS - CLASSIFY FIELD, LAND 8-CONNECTED", 12, 12, s, Ink);
TinyFont.Draw(img, $"GREY: MAINLAND (CENTRE COMPONENT{(labels.CentreWasLand ? "" : " - FALLBACK, CENTRE NOT LAND")}) EACH ISLAND: ITS OWN COLOUR", 12, 12 + lh, s, Ink);
TinyFont.Draw(img, $"ISLANDS: {labels.IslandCount} ({north} N / {south} S BY CENTROID) DARK RED: {revertedCount} REVERTED < {thresholdCells} CELLS", 12, 12 + lh * 2, s, Ink);
TinyFont.Draw(img, "N ABOVE THE LINE - S BELOW - Y RUNS SOUTH", 12, 12 + lh * 3, s, Ink);
Error err = img.SavePng(absolutePath);
if (err != Error.Ok) GD.PrintErr($"[RegionOverlayRenderer] SavePng failed ({err}) for {absolutePath}");
}
}
}