PixFont.cs
namespace PixelPusher;

public static class PixFont
{
	public static void Draw( Color32[] buf, int bw, int bh, int x, int y, string text, Color32 color, int scale = 1 )
	{
		if ( buf is null || string.IsNullOrEmpty( text ) )
			return;
		scale = Math.Max( 1, scale );
		var cx = x;
		foreach ( var ch in text.ToUpperInvariant() )
		{
			if ( ch == '\n' )
			{
				cx = x;
				y += (5 + 1) * scale;
				continue;
			}

			if ( Glyphs.TryGetValue( ch, out var bits ) )
				Blit( buf, bw, bh, cx, y, bits, color, scale );
			cx += (3 + 1) * scale;
		}
	}

	public static int Width( string text, int scale = 1 )
	{
		if ( string.IsNullOrEmpty( text ) )
			return 0;
		var lines = text.Split( '\n' );
		var max = 0;
		foreach ( var line in lines )
			max = Math.Max( max, line.Length );
		return max * 4 * Math.Max( 1, scale );
	}

	static void Blit( Color32[] buf, int bw, int bh, int x, int y, ushort bits, Color32 color, int scale )
	{
		for ( var row = 0; row < 5; row++ )
		for ( var col = 0; col < 3; col++ )
		{
			if ( (bits & (1 << (row * 3 + col))) == 0 )
				continue;
			for ( var sy = 0; sy < scale; sy++ )
			for ( var sx = 0; sx < scale; sx++ )
			{
				var px = x + col * scale + sx;
				var py = y + row * scale + sy;
				if ( (uint)px >= (uint)bw || (uint)py >= (uint)bh )
					continue;
				buf[py * bw + px] = color;
			}
		}
	}

	static ushort Pack( string a, string b, string c, string d, string e )
	{
		ushort bits = 0;
		void Row( string s, int r )
		{
			for ( var i = 0; i < 3; i++ )
			{
				if ( i < s.Length && s[i] == '#' )
					bits |= (ushort)(1 << (r * 3 + i));
			}
		}
		Row( a, 0 );
		Row( b, 1 );
		Row( c, 2 );
		Row( d, 3 );
		Row( e, 4 );
		return bits;
	}

	static readonly Dictionary<char, ushort> Glyphs = Build();

	static Dictionary<char, ushort> Build()
	{
		var g = new Dictionary<char, ushort>
		{
			[' '] = 0,
			['0'] = Pack( "###", "# #", "# #", "# #", "###" ),
			['1'] = Pack( " # ", "## ", " # ", " # ", "###" ),
			['2'] = Pack( "###", "  #", "###", "#  ", "###" ),
			['3'] = Pack( "###", "  #", "###", "  #", "###" ),
			['4'] = Pack( "# #", "# #", "###", "  #", "  #" ),
			['5'] = Pack( "###", "#  ", "###", "  #", "###" ),
			['6'] = Pack( "###", "#  ", "###", "# #", "###" ),
			['7'] = Pack( "###", "  #", " # ", " # ", " # " ),
			['8'] = Pack( "###", "# #", "###", "# #", "###" ),
			['9'] = Pack( "###", "# #", "###", "  #", "###" ),
			['A'] = Pack( " # ", "# #", "###", "# #", "# #" ),
			['B'] = Pack( "## ", "# #", "## ", "# #", "## " ),
			['C'] = Pack( " ##", "#  ", "#  ", "#  ", " ##" ),
			['D'] = Pack( "## ", "# #", "# #", "# #", "## " ),
			['E'] = Pack( "###", "#  ", "## ", "#  ", "###" ),
			['F'] = Pack( "###", "#  ", "## ", "#  ", "#  " ),
			['G'] = Pack( " ##", "#  ", "# #", "# #", " ##" ),
			['H'] = Pack( "# #", "# #", "###", "# #", "# #" ),
			['I'] = Pack( "###", " # ", " # ", " # ", "###" ),
			['J'] = Pack( "###", "  #", "  #", "# #", " # " ),
			['K'] = Pack( "# #", "# #", "## ", "# #", "# #" ),
			['L'] = Pack( "#  ", "#  ", "#  ", "#  ", "###" ),
			['M'] = Pack( "# #", "###", "###", "# #", "# #" ),
			['N'] = Pack( "# #", "###", "###", "###", "# #" ),
			['O'] = Pack( " # ", "# #", "# #", "# #", " # " ),
			['P'] = Pack( "## ", "# #", "## ", "#  ", "#  " ),
			['Q'] = Pack( " # ", "# #", "# #", " ##", "  #" ),
			['R'] = Pack( "## ", "# #", "## ", "# #", "# #" ),
			['S'] = Pack( " ##", "#  ", " # ", "  #", "## " ),
			['T'] = Pack( "###", " # ", " # ", " # ", " # " ),
			['U'] = Pack( "# #", "# #", "# #", "# #", "###" ),
			['V'] = Pack( "# #", "# #", "# #", "# #", " # " ),
			['W'] = Pack( "# #", "# #", "###", "###", "# #" ),
			['X'] = Pack( "# #", "# #", " # ", "# #", "# #" ),
			['Y'] = Pack( "# #", "# #", " # ", " # ", " # " ),
			['Z'] = Pack( "###", "  #", " # ", "#  ", "###" ),
			['.'] = Pack( "   ", "   ", "   ", "   ", " # " ),
			[','] = Pack( "   ", "   ", "   ", " # ", "#  " ),
			[':'] = Pack( "   ", " # ", "   ", " # ", "   " ),
			['-'] = Pack( "   ", "   ", "###", "   ", "   " ),
			['+'] = Pack( "   ", " # ", "###", " # ", "   " ),
			['!'] = Pack( " # ", " # ", " # ", "   ", " # " ),
			['?'] = Pack( "## ", "  #", " # ", "   ", " # " ),
			['/'] = Pack( "  #", "  #", " # ", "#  ", "#  " ),
			['·'] = Pack( "   ", "   ", " # ", "   ", "   " ),
			['\''] = Pack( " # ", " # ", "   ", "   ", "   " )
		};
		return g;
	}
}