altos/telelco-v2.0: A bit fancier with the drag-mode LED show
[fw/altos] / src / draw / font-convert
1 #!/usr/bin/nickle
2
3 typedef struct {
4         int[]   bytes;
5         int     width;
6         int     height;
7         int     encoding;
8         int     location;
9 } glyph_t;
10
11 typedef struct {
12         glyph_t[...]    glyphs;
13         int             default_char;
14         int             ascent;
15 } font_t;
16
17 glyph_t
18 read_glyph(file f)
19 {
20         glyph_t glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 };
21
22         while (!File::end(f)) {
23                 string  l = fgets(f);
24
25                 string[*] tokens = String::split(l, " ");
26                 if (dim(tokens) == 0)
27                         continue;
28
29                 switch (tokens[0]) {
30                 case "ENCODING":
31                         glyph.encoding = atoi(tokens[1]);
32                         break;
33                 case "DWIDTH":
34                         glyph.width = atoi(tokens[1]);
35                         break;
36                 case "BBX":
37                         glyph.height = atoi(tokens[2]);
38                         break;
39                 case "ENDCHAR":
40                         return glyph;
41                 case "BITMAP":
42                         while (!File::end(f)) {
43                                 string l = fgets(f);
44                                 if (l == "ENDCHAR")
45                                         return glyph;
46                                 glyph.bytes[dim(glyph.bytes)] = atoi(l, 16);
47                         }
48                         break;
49                 }
50         }
51         return glyph;
52 }
53
54 font_t read_font(file f) {
55         font_t  font = { .glyphs = {}, .default_char = -1 };
56         bool in_head = true;
57
58         while (in_head && !File::end(f)) {
59                 string l = File::fgets(f);
60
61                 string[*] tokens = String::split(l, " ");
62                 switch (tokens[0]) {
63                 case "DEFAULT_CHAR":
64                         font.default_char = atoi(tokens[1]);
65                         break;
66                 case "FONT_ASCENT":
67                         font.ascent = atoi(tokens[1]);
68                         break;
69                 case "CHARS":
70                         in_head = false;
71                         break;
72                 }
73         }
74         while (!File::end(f)) {
75                 glyph_t glyph = read_glyph(f);
76                 if (glyph.encoding == -1)
77                         break;
78                 font.glyphs[dim(font.glyphs)] = glyph;
79         }
80         return font;
81 }
82
83 int
84 flip_byte(int x)
85 {
86         int     dest = 0;
87
88         for (int i = 0; i < 8; i++)
89                 dest |= ((x >> (7 - i)) & 1) << i;
90         return dest;
91 }
92
93 void print_font(font_t font) {
94         int     width = font.glyphs[0].width;
95         int     height = font.glyphs[0].height;
96         int[256] pos = { -1 ... };
97         int[...] bytes;
98
99         if (false) {
100         for (int i = 1; i < dim(font.glyphs); i++) {
101                 if (font.glyphs[i].width != width ||
102                    font.glyphs[i].height != height)
103                 {
104                         File::fprintf(stderr, "font not constant size, glyph %d is %dx%d\n",
105                                       font.glyphs[i].encoding, font.glyphs[i].width, font.glyphs[i].height);
106                         exit(1);
107                 }
108         }
109         }
110
111         if (font.default_char == -1)
112                 font.default_char = font.glyphs[0].encoding;
113
114         /* build byte array */
115         for (int i = 0; i < dim(font.glyphs); i++) {
116                 pos[font.glyphs[i].encoding] = dim(bytes);
117                 for (int b = 0; b < dim(font.glyphs[i].bytes); b++)
118                         bytes[dim(bytes)] = font.glyphs[i].bytes[b];
119         }
120
121         /* Fill in default glyph */
122         for (int i = 0; i < dim(pos); i++)
123                 if (pos[i] == -1)
124                         pos[i] = pos[font.default_char];
125
126         printf("static const uint8_t glyph_bytes[%d] = {", dim(bytes));
127         for (int b = 0; b < dim(bytes); b++) {
128                 if ((b & 15) == 0)
129                         printf("\n\t");
130                 printf("0x%02x, ", flip_byte(bytes[b]));
131         }
132         printf("\n};\n\n");
133
134         printf("static const uint16_t glyph_pos[%d] = {", dim(pos));
135         for (int i = 0; i < dim(pos); i++) {
136                 if ((i & 7) == 0)
137                         printf("\n\t");
138                 printf("%4d, ", pos[i]);
139         }
140         printf("\n};\n\n");
141
142         printf("#define GLYPH_WIDTH %d\n", width);
143         printf("#define GLYPH_HEIGHT %d\n", height);
144         printf("#define GLYPH_ASCENT %d\n", font.ascent);
145 }
146
147 twixt (file f = File::open(argv[1], "r"); File::close(f)) {
148        font_t font = read_font(f);
149        print_font(font);
150 }