//go:build ignore

// fontgen.go is the source of truth for CaptureStudio's embedded bitmap font.
//
// It holds one hand-drawn 5x8 glyph per printable ASCII code point as plain
// ASCII art ('#' = ink, '.' = paper) and packs each row into the low five bits
// of a byte, most significant bit = leftmost pixel. The packed table is written
// to font.go, which is what actually ships and compiles in. Nothing is loaded
// at run time and there is no font file anywhere.
//
// Rows 0-6 are cap height with the baseline on row 6. Row 7 is the descender
// row, used only by g j p q y , ; and _ , which is why glyph() takes seven
// rows and pads, while glyph8() takes all eight.
//
//	go run fontgen.go > font.go && gofmt -w font.go
package main

import (
	"fmt"
	"os"
	"strings"
)

// g records one glyph. The strings are the pixel rows, top first.
type g struct {
	r    rune
	rows [8]string
}

func glyph(r rune, r0, r1, r2, r3, r4, r5, r6 string) g {
	return g{r, [8]string{r0, r1, r2, r3, r4, r5, r6, "....."}}
}

func glyph8(r rune, r0, r1, r2, r3, r4, r5, r6, r7 string) g {
	return g{r, [8]string{r0, r1, r2, r3, r4, r5, r6, r7}}
}

var glyphs = []g{
	glyph(' ',
		".....",
		".....",
		".....",
		".....",
		".....",
		".....",
		"....."),
	glyph('!',
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		".....",
		"..#.."),
	glyph('"',
		".#.#.",
		".#.#.",
		".....",
		".....",
		".....",
		".....",
		"....."),
	glyph('#',
		".#.#.",
		".#.#.",
		"#####",
		".#.#.",
		"#####",
		".#.#.",
		".#.#."),
	glyph('$',
		"..#..",
		".####",
		"#.#..",
		".###.",
		"..#.#",
		"####.",
		"..#.."),
	glyph('%',
		"##..#",
		"##..#",
		"...#.",
		"..#..",
		".#...",
		"#..##",
		"#..##"),
	glyph('&',
		".##..",
		"#..#.",
		"#.#..",
		".#...",
		"#.#.#",
		"#..#.",
		".##.#"),
	glyph('\'',
		"..#..",
		"..#..",
		".....",
		".....",
		".....",
		".....",
		"....."),
	glyph('(',
		"...#.",
		"..#..",
		".#...",
		".#...",
		".#...",
		"..#..",
		"...#."),
	glyph(')',
		".#...",
		"..#..",
		"...#.",
		"...#.",
		"...#.",
		"..#..",
		".#..."),
	glyph('*',
		".....",
		"#.#.#",
		".###.",
		"#####",
		".###.",
		"#.#.#",
		"....."),
	glyph('+',
		".....",
		"..#..",
		"..#..",
		"#####",
		"..#..",
		"..#..",
		"....."),
	glyph8(',',
		".....",
		".....",
		".....",
		".....",
		".....",
		"..##.",
		"..#..",
		".#..."),
	glyph('-',
		".....",
		".....",
		".....",
		"#####",
		".....",
		".....",
		"....."),
	glyph('.',
		".....",
		".....",
		".....",
		".....",
		".....",
		".##..",
		".##.."),
	glyph('/',
		"....#",
		"...#.",
		"...#.",
		"..#..",
		".#...",
		".#...",
		"#...."),
	glyph('0',
		".###.",
		"#...#",
		"#..##",
		"#.#.#",
		"##..#",
		"#...#",
		".###."),
	glyph('1',
		"..#..",
		".##..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		".###."),
	glyph('2',
		".###.",
		"#...#",
		"....#",
		"...#.",
		"..#..",
		".#...",
		"#####"),
	glyph('3',
		"#####",
		"...#.",
		"..#..",
		"...#.",
		"....#",
		"#...#",
		".###."),
	glyph('4',
		"...#.",
		"..##.",
		".#.#.",
		"#..#.",
		"#####",
		"...#.",
		"...#."),
	glyph('5',
		"#####",
		"#....",
		"####.",
		"....#",
		"....#",
		"#...#",
		".###."),
	glyph('6',
		"..##.",
		".#...",
		"#....",
		"####.",
		"#...#",
		"#...#",
		".###."),
	glyph('7',
		"#####",
		"....#",
		"...#.",
		"..#..",
		".#...",
		".#...",
		".#..."),
	glyph('8',
		".###.",
		"#...#",
		"#...#",
		".###.",
		"#...#",
		"#...#",
		".###."),
	glyph('9',
		".###.",
		"#...#",
		"#...#",
		".####",
		"....#",
		"...#.",
		".##.."),
	glyph(':',
		".....",
		".##..",
		".##..",
		".....",
		".##..",
		".##..",
		"....."),
	glyph8(';',
		".....",
		".##..",
		".##..",
		".....",
		".##..",
		".##..",
		"..#..",
		".#..."),
	glyph('<',
		"...#.",
		"..#..",
		".#...",
		"#....",
		".#...",
		"..#..",
		"...#."),
	glyph('=',
		".....",
		".....",
		"#####",
		".....",
		"#####",
		".....",
		"....."),
	glyph('>',
		".#...",
		"..#..",
		"...#.",
		"....#",
		"...#.",
		"..#..",
		".#..."),
	glyph('?',
		".###.",
		"#...#",
		"....#",
		"...#.",
		"..#..",
		".....",
		"..#.."),
	glyph('@',
		".###.",
		"#...#",
		"....#",
		"#.###",
		"#.#.#",
		"#.###",
		".###."),
	glyph('A',
		"..#..",
		".#.#.",
		"#...#",
		"#...#",
		"#####",
		"#...#",
		"#...#"),
	glyph('B',
		"####.",
		"#...#",
		"#...#",
		"####.",
		"#...#",
		"#...#",
		"####."),
	glyph('C',
		".###.",
		"#...#",
		"#....",
		"#....",
		"#....",
		"#...#",
		".###."),
	glyph('D',
		"###..",
		"#..#.",
		"#...#",
		"#...#",
		"#...#",
		"#..#.",
		"###.."),
	glyph('E',
		"#####",
		"#....",
		"#....",
		"####.",
		"#....",
		"#....",
		"#####"),
	glyph('F',
		"#####",
		"#....",
		"#....",
		"####.",
		"#....",
		"#....",
		"#...."),
	glyph('G',
		".###.",
		"#...#",
		"#....",
		"#..##",
		"#...#",
		"#...#",
		".####"),
	glyph('H',
		"#...#",
		"#...#",
		"#...#",
		"#####",
		"#...#",
		"#...#",
		"#...#"),
	glyph('I',
		".###.",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		".###."),
	glyph('J',
		"..###",
		"...#.",
		"...#.",
		"...#.",
		"...#.",
		"#..#.",
		".##.."),
	glyph('K',
		"#...#",
		"#..#.",
		"#.#..",
		"##...",
		"#.#..",
		"#..#.",
		"#...#"),
	glyph('L',
		"#....",
		"#....",
		"#....",
		"#....",
		"#....",
		"#....",
		"#####"),
	glyph('M',
		"#...#",
		"##.##",
		"#.#.#",
		"#.#.#",
		"#...#",
		"#...#",
		"#...#"),
	glyph('N',
		"#...#",
		"#...#",
		"##..#",
		"#.#.#",
		"#..##",
		"#...#",
		"#...#"),
	glyph('O',
		".###.",
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		".###."),
	glyph('P',
		"####.",
		"#...#",
		"#...#",
		"####.",
		"#....",
		"#....",
		"#...."),
	glyph('Q',
		".###.",
		"#...#",
		"#...#",
		"#...#",
		"#.#.#",
		"#..#.",
		".##.#"),
	glyph('R',
		"####.",
		"#...#",
		"#...#",
		"####.",
		"#.#..",
		"#..#.",
		"#...#"),
	glyph('S',
		".####",
		"#....",
		"#....",
		".###.",
		"....#",
		"....#",
		"####."),
	glyph('T',
		"#####",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#.."),
	glyph('U',
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		".###."),
	glyph('V',
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		"#...#",
		".#.#.",
		"..#.."),
	glyph('W',
		"#...#",
		"#...#",
		"#...#",
		"#.#.#",
		"#.#.#",
		"##.##",
		"#...#"),
	glyph('X',
		"#...#",
		"#...#",
		".#.#.",
		"..#..",
		".#.#.",
		"#...#",
		"#...#"),
	glyph('Y',
		"#...#",
		"#...#",
		".#.#.",
		"..#..",
		"..#..",
		"..#..",
		"..#.."),
	glyph('Z',
		"#####",
		"....#",
		"...#.",
		"..#..",
		".#...",
		"#....",
		"#####"),
	glyph('[',
		".###.",
		".#...",
		".#...",
		".#...",
		".#...",
		".#...",
		".###."),
	glyph('\\',
		"#....",
		".#...",
		".#...",
		"..#..",
		"...#.",
		"...#.",
		"....#"),
	glyph(']',
		".###.",
		"...#.",
		"...#.",
		"...#.",
		"...#.",
		"...#.",
		".###."),
	glyph('^',
		"..#..",
		".#.#.",
		"#...#",
		".....",
		".....",
		".....",
		"....."),
	glyph8('_',
		".....",
		".....",
		".....",
		".....",
		".....",
		".....",
		".....",
		"#####"),
	glyph('`',
		".#...",
		"..#..",
		".....",
		".....",
		".....",
		".....",
		"....."),
	glyph('a',
		".....",
		".....",
		".###.",
		"....#",
		".####",
		"#...#",
		".####"),
	glyph('b',
		"#....",
		"#....",
		"####.",
		"#...#",
		"#...#",
		"#...#",
		"####."),
	glyph('c',
		".....",
		".....",
		".###.",
		"#....",
		"#....",
		"#....",
		".###."),
	glyph('d',
		"....#",
		"....#",
		".####",
		"#...#",
		"#...#",
		"#...#",
		".####"),
	glyph('e',
		".....",
		".....",
		".###.",
		"#...#",
		"#####",
		"#....",
		".###."),
	glyph('f',
		"..##.",
		".#..#",
		".#...",
		"####.",
		".#...",
		".#...",
		".#..."),
	glyph8('g',
		".....",
		".....",
		".####",
		"#...#",
		"#...#",
		".####",
		"....#",
		".###."),
	glyph('h',
		"#....",
		"#....",
		"####.",
		"#...#",
		"#...#",
		"#...#",
		"#...#"),
	glyph('i',
		"..#..",
		".....",
		".##..",
		"..#..",
		"..#..",
		"..#..",
		".###."),
	glyph8('j',
		"...#.",
		".....",
		"..##.",
		"...#.",
		"...#.",
		"...#.",
		"#..#.",
		".##.."),
	glyph('k',
		"#....",
		"#....",
		"#..#.",
		"#.#..",
		"##...",
		"#.#..",
		"#..#."),
	glyph('l',
		".##..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		".###."),
	glyph('m',
		".....",
		".....",
		"##.#.",
		"#.#.#",
		"#.#.#",
		"#...#",
		"#...#"),
	glyph('n',
		".....",
		".....",
		"####.",
		"#...#",
		"#...#",
		"#...#",
		"#...#"),
	glyph('o',
		".....",
		".....",
		".###.",
		"#...#",
		"#...#",
		"#...#",
		".###."),
	glyph8('p',
		".....",
		".....",
		"####.",
		"#...#",
		"#...#",
		"####.",
		"#....",
		"#...."),
	glyph8('q',
		".....",
		".....",
		".####",
		"#...#",
		"#...#",
		".####",
		"....#",
		"....#"),
	glyph('r',
		".....",
		".....",
		"#.##.",
		"##..#",
		"#....",
		"#....",
		"#...."),
	glyph('s',
		".....",
		".....",
		".####",
		"#....",
		".###.",
		"....#",
		"####."),
	glyph('t',
		".#...",
		".#...",
		"####.",
		".#...",
		".#...",
		".#..#",
		"..##."),
	glyph('u',
		".....",
		".....",
		"#...#",
		"#...#",
		"#...#",
		"#..##",
		".##.#"),
	glyph('v',
		".....",
		".....",
		"#...#",
		"#...#",
		"#...#",
		".#.#.",
		"..#.."),
	glyph('w',
		".....",
		".....",
		"#...#",
		"#...#",
		"#.#.#",
		"#.#.#",
		".#.#."),
	glyph('x',
		".....",
		".....",
		"#...#",
		".#.#.",
		"..#..",
		".#.#.",
		"#...#"),
	glyph8('y',
		".....",
		".....",
		"#...#",
		"#...#",
		"#...#",
		".####",
		"....#",
		".###."),
	glyph('z',
		".....",
		".....",
		"#####",
		"...#.",
		"..#..",
		".#...",
		"#####"),
	glyph('{',
		"...##",
		"..#..",
		"..#..",
		".##..",
		"..#..",
		"..#..",
		"...##"),
	glyph('|',
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#..",
		"..#.."),
	glyph('}',
		"##...",
		"..#..",
		"..#..",
		"..##.",
		"..#..",
		"..#..",
		"##..."),
	glyph('~',
		".....",
		".#...",
		"#.#.#",
		"...#.",
		".....",
		".....",
		"....."),
}

// fallback is drawn for any rune the font does not cover (everything outside
// printable ASCII). A hollow box is the conventional "missing glyph".
var fallback = [8]string{
	".....",
	".....",
	"####.",
	"#..#.",
	"#..#.",
	"#..#.",
	"####.",
	".....",
}

func pack(rows [8]string) [8]uint8 {
	var out [8]uint8
	for y, row := range rows {
		if len(row) != 5 {
			fmt.Fprintf(os.Stderr, "row %q is not 5 columns wide\n", row)
			os.Exit(1)
		}
		var b uint8
		for x := 0; x < 5; x++ {
			if row[x] == '#' {
				b |= 1 << uint(4-x)
			} else if row[x] != '.' {
				fmt.Fprintf(os.Stderr, "row %q has a character that is neither # nor .\n", row)
				os.Exit(1)
			}
		}
		out[y] = b
	}
	return out
}

func main() {
	if len(glyphs) != 95 {
		fmt.Fprintf(os.Stderr, "expected 95 glyphs, have %d\n", len(glyphs))
		os.Exit(1)
	}
	for i, gl := range glyphs {
		if want := rune(0x20 + i); gl.r != want {
			fmt.Fprintf(os.Stderr, "glyph %d is %q, expected %q\n", i, gl.r, want)
			os.Exit(1)
		}
	}

	var b strings.Builder
	b.WriteString("// Code generated by \"go run fontgen.go\"; DO NOT EDIT.\n")
	b.WriteString("// The glyph artwork lives in fontgen.go.\n\n")
	b.WriteString("package main\n\n")
	b.WriteString("// Bitmap font geometry. Each glyph is glyphW x glyphH pixels, drawn into a\n")
	b.WriteString("// cellW x cellH character cell with the glyph offset by (glyphX, glyphY).\n")
	b.WriteString("const (\n")
	b.WriteString("\tglyphW = 5\n")
	b.WriteString("\tglyphH = 8\n")
	b.WriteString("\tcellW  = 6\n")
	b.WriteString("\tcellH  = 11\n")
	b.WriteString("\tglyphX = 0\n")
	b.WriteString("\tglyphY = 1\n")
	b.WriteString(")\n\n")
	b.WriteString("// fontBits holds one packed row per scan line for U+0020..U+007E in order.\n")
	b.WriteString("// Bit 4 is the leftmost pixel, bit 0 the rightmost; bits 5-7 are always zero.\n")
	b.WriteString("var fontBits = [95][8]uint8{\n")
	for _, gl := range glyphs {
		p := pack(gl.rows)
		name := string(gl.r)
		if gl.r == '\\' {
			name = "\\\\"
		}
		fmt.Fprintf(&b, "\t{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}, // %q\n",
			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], name)
	}
	b.WriteString("}\n\n")
	b.WriteString("// fontFallback is drawn for every rune outside printable ASCII.\n")
	p := pack(fallback)
	fmt.Fprintf(&b, "var fontFallback = [8]uint8{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}\n",
		p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7])

	fmt.Print(b.String())
}
