using System.Collections.Generic;
using Godot;
namespace IslaApocalypse.Tools
{
///
/// A 5x7 bitmap font, drawn straight into a .
///
/// ═══ WHY A HAND-ROLLED FONT AND NOT GODOT'S ═══
///
/// Godot's Font renders through a CanvasItem, which means a viewport — the SubViewport
/// capture path the renderer deliberately avoids, because it awaits render frames and is why
/// `--headless` hangs. A legend is a handful of digits; paying the whole capture path for it
/// would be a poor trade, and would drag a frame-loop dependency into a tool that currently
/// needs no display at all.
///
/// So: 5x7 glyphs, integer-scaled, drawn per-pixel. Digits, a few punctuation marks and A–Z.
/// Unknown characters draw as blank rather than throwing — a legend with a missing letter is a
/// cosmetic problem, not a reason to lose the render.
///
public static class TinyFont
{
public const int GlyphW = 5;
public const int GlyphH = 7;
// Each glyph is 7 rows of 5 columns. '#' = ink. Written out rather than hex-packed so a
// reader can verify a letter by looking at it.
private static readonly Dictionary Glyphs = new()
{
[' '] = new[] { ".....", ".....", ".....", ".....", ".....", ".....", "....." },
['.'] = new[] { ".....", ".....", ".....", ".....", ".....", "..##.", "..##." },
['-'] = new[] { ".....", ".....", ".....", "#####", ".....", ".....", "....." },
[':'] = new[] { ".....", "..##.", "..##.", ".....", "..##.", "..##.", "....." },
['/'] = new[] { "....#", "...#.", "...#.", "..#..", ".#...", ".#...", "#...." },
['('] = new[] { "...#.", "..#..", ".#...", ".#...", ".#...", "..#..", "...#." },
[')'] = new[] { ".#...", "..#..", "...#.", "...#.", "...#.", "..#..", ".#..." },
['0'] = new[] { ".###.", "#...#", "#..##", "#.#.#", "##..#", "#...#", ".###." },
['1'] = new[] { "..#..", ".##..", "..#..", "..#..", "..#..", "..#..", ".###." },
['2'] = new[] { ".###.", "#...#", "....#", "...#.", "..#..", ".#...", "#####" },
['3'] = new[] { "#####", "...#.", "..#..", "...#.", "....#", "#...#", ".###." },
['4'] = new[] { "...#.", "..##.", ".#.#.", "#..#.", "#####", "...#.", "...#." },
['5'] = new[] { "#####", "#....", "####.", "....#", "....#", "#...#", ".###." },
['6'] = new[] { "..##.", ".#...", "#....", "####.", "#...#", "#...#", ".###." },
['7'] = new[] { "#####", "....#", "...#.", "..#..", ".#...", ".#...", ".#..." },
['8'] = new[] { ".###.", "#...#", "#...#", ".###.", "#...#", "#...#", ".###." },
['9'] = new[] { ".###.", "#...#", "#...#", ".####", "....#", "...#.", ".##.." },
['A'] = new[] { ".###.", "#...#", "#...#", "#####", "#...#", "#...#", "#...#" },
['B'] = new[] { "####.", "#...#", "#...#", "####.", "#...#", "#...#", "####." },
['C'] = new[] { ".###.", "#...#", "#....", "#....", "#....", "#...#", ".###." },
['D'] = new[] { "###..", "#..#.", "#...#", "#...#", "#...#", "#..#.", "###.." },
['E'] = new[] { "#####", "#....", "#....", "####.", "#....", "#....", "#####" },
['F'] = new[] { "#####", "#....", "#....", "####.", "#....", "#....", "#...." },
['G'] = new[] { ".###.", "#...#", "#....", "#.###", "#...#", "#...#", ".####" },
['H'] = new[] { "#...#", "#...#", "#...#", "#####", "#...#", "#...#", "#...#" },
['I'] = new[] { ".###.", "..#..", "..#..", "..#..", "..#..", "..#..", ".###." },
['J'] = new[] { "..###", "...#.", "...#.", "...#.", "...#.", "#..#.", ".##.." },
['K'] = new[] { "#...#", "#..#.", "#.#..", "##...", "#.#..", "#..#.", "#...#" },
['L'] = new[] { "#....", "#....", "#....", "#....", "#....", "#....", "#####" },
['M'] = new[] { "#...#", "##.##", "#.#.#", "#.#.#", "#...#", "#...#", "#...#" },
['N'] = new[] { "#...#", "##..#", "#.#.#", "#..##", "#...#", "#...#", "#...#" },
['O'] = new[] { ".###.", "#...#", "#...#", "#...#", "#...#", "#...#", ".###." },
['P'] = new[] { "####.", "#...#", "#...#", "####.", "#....", "#....", "#...." },
['Q'] = new[] { ".###.", "#...#", "#...#", "#...#", "#.#.#", "#..#.", ".##.#" },
['R'] = new[] { "####.", "#...#", "#...#", "####.", "#.#..", "#..#.", "#...#" },
['S'] = new[] { ".####", "#....", "#....", ".###.", "....#", "....#", "####." },
['T'] = new[] { "#####", "..#..", "..#..", "..#..", "..#..", "..#..", "..#.." },
['U'] = new[] { "#...#", "#...#", "#...#", "#...#", "#...#", "#...#", ".###." },
['V'] = new[] { "#...#", "#...#", "#...#", "#...#", "#...#", ".#.#.", "..#.." },
['W'] = new[] { "#...#", "#...#", "#...#", "#.#.#", "#.#.#", "##.##", "#...#" },
['X'] = new[] { "#...#", "#...#", ".#.#.", "..#..", ".#.#.", "#...#", "#...#" },
['Y'] = new[] { "#...#", "#...#", ".#.#.", "..#..", "..#..", "..#..", "..#.." },
['Z'] = new[] { "#####", "....#", "...#.", "..#..", ".#...", "#....", "#####" },
};
/// Pixel width of at the given integer scale.
public static int Width(string text, int scale) => text.Length * (GlyphW + 1) * scale;
/// Pixel height of one line at the given integer scale.
public static int Height(int scale) => GlyphH * scale;
///
/// Draw with its top-left at (x, y). Uppercases automatically —
/// the font has no lowercase, and silently dropping letters would be worse than shouting.
///
public static void Draw(Image img, string text, int x, int y, int scale, Color color)
{
int cursor = x;
foreach (char raw in text.ToUpperInvariant())
{
if (Glyphs.TryGetValue(raw, out string[] g))
{
for (int row = 0; row < GlyphH; row++)
for (int col = 0; col < GlyphW; col++)
if (g[row][col] == '#')
FillCell(img, cursor + col * scale, y + row * scale, scale, color);
}
cursor += (GlyphW + 1) * scale;
}
}
private static void FillCell(Image img, int px, int py, int scale, Color color)
{
for (int dy = 0; dy < scale; dy++)
for (int dx = 0; dx < scale; dx++)
{
int tx = px + dx, ty = py + dy;
if (tx >= 0 && ty >= 0 && tx < img.GetWidth() && ty < img.GetHeight())
img.SetPixel(tx, ty, color);
}
}
}
}