c7d9c780edcf92960b14e4ee578e884b4764f4c7
[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     x_off;
8         int     y_off;
9         int     advance;
10         int     encoding;
11         int     location;
12 } glyph_t;
13
14 typedef struct {
15         glyph_t[...]    glyphs;
16         int             default_char;
17         int             ascent;
18 } font_t;
19
20 glyph_t
21 read_glyph(file f)
22 {
23         glyph_t glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 };
24
25         while (!File::end(f)) {
26                 string  l = fgets(f);
27
28                 string[*] tokens = String::split(l, " ");
29                 if (dim(tokens) == 0)
30                         continue;
31
32                 switch (tokens[0]) {
33                 case "ENCODING":
34                         glyph.encoding = atoi(tokens[1]);
35                         break;
36                 case "DWIDTH":
37                         glyph.advance = atoi(tokens[1]);
38                         break;
39                 case "BBX":
40                         glyph.width = atoi(tokens[1]);
41                         glyph.height = atoi(tokens[2]);
42                         glyph.x_off = atoi(tokens[3]);
43                         glyph.y_off = glyph.height + atoi(tokens[4]);
44                         break;
45                 case "ENDCHAR":
46                         return glyph;
47                 case "BITMAP":
48                         int byte_stride = ceil(glyph.width/8);
49                         for (int y = 0; y < glyph.height; y++) {
50                                 string l = fgets(f);
51                                 for (int x = 0; x < byte_stride; x++) {
52                                         string v = String::substr(l, x * 2, 2);
53                                         glyph.bytes[dim(glyph.bytes)] = atoi(v, 16);
54                                 }
55                         }
56                         break;
57                 }
58         }
59         return glyph;
60 }
61
62 font_t read_font(file f) {
63         font_t  font = { .glyphs = {}, .default_char = -1 };
64         bool in_head = true;
65
66         while (in_head && !File::end(f)) {
67                 string l = File::fgets(f);
68
69                 string[*] tokens = String::split(l, " ");
70                 switch (tokens[0]) {
71                 case "DEFAULT_CHAR":
72                         font.default_char = atoi(tokens[1]);
73                         break;
74                 case "FONT_ASCENT":
75                         font.ascent = atoi(tokens[1]);
76                         break;
77                 case "CHARS":
78                         in_head = false;
79                         break;
80                 }
81         }
82         while (!File::end(f)) {
83                 glyph_t glyph = read_glyph(f);
84                 if (glyph.encoding == -1)
85                         break;
86                 font.glyphs[dim(font.glyphs)] = glyph;
87         }
88         return font;
89 }
90
91 int
92 flip_byte(int x)
93 {
94         int     dest = 0;
95
96         for (int i = 0; i < 8; i++)
97                 dest |= ((x >> (7 - i)) & 1) << i;
98         return dest;
99 }
100
101 void print_font(font_t font, string font_name) {
102         int     width = font.glyphs[0].width;
103         int     height = font.glyphs[0].height;
104         int     max_width = width;
105         int     max_height = height;
106         int[256] pos = { -1 ... };
107         int[...] bytes;
108         bool fixed_size = true;
109
110         for (int i = 1; i < dim(font.glyphs); i++) {
111                 if (font.glyphs[i].width != width ||
112                    font.glyphs[i].height != height)
113                 {
114                         fixed_size = false;
115                 }
116                 max_width = max(max_width, font.glyphs[i].width);
117                 max_height = max(max_height, font.glyphs[i].height);
118         }
119
120         if (font.default_char == -1)
121                 font.default_char = font.glyphs[0].encoding;
122
123         /* build byte array */
124         for (int i = 0; i < dim(font.glyphs); i++) {
125                 pos[font.glyphs[i].encoding] = dim(bytes);
126                 for (int b = 0; b < dim(font.glyphs[i].bytes); b++)
127                         bytes[dim(bytes)] = font.glyphs[i].bytes[b];
128         }
129
130         /* Fill in default glyph */
131         for (int i = 0; i < dim(pos); i++)
132                 if (pos[i] == -1)
133                         pos[i] = pos[font.default_char];
134
135         printf("#include \"ao_draw.h\"\n");
136         printf("static const uint8_t %s_bytes[%d] = {", font_name, dim(bytes));
137         for (int b = 0; b < dim(bytes); b++) {
138                 if ((b & 15) == 0)
139                         printf("\n\t");
140                 else
141                         printf(" ");
142                 printf("0x%02x,", flip_byte(bytes[b]));
143         }
144         printf("\n};\n\n");
145
146         printf("static const uint16_t %s_pos[%d] = {", font_name, dim(pos));
147         for (int i = 0; i < dim(pos); i++) {
148                 if ((i & 7) == 0)
149                         printf("\n\t");
150                 else
151                         printf(" ");
152                 printf("%6d,", pos[i]);
153         }
154         printf("\n};\n\n");
155
156         printf("#define GLYPH_WIDTH_MAX %d\n", max_width);
157         printf("#define GLYPH_HEIGHT_MAX %d\n", max_height);
158         if (fixed_size) {
159                 printf("#define GLYPH_WIDTH %d\n", width);
160                 printf("#define GLYPH_HEIGHT %d\n", height);
161                 printf("#define GLYPH_ASCENT %d\n", font.ascent);
162         } else {
163                 printf("static const struct ao_glyph_metrics %s_metrics[%d] = {\n", font_name, dim(pos));
164                 for (int i = 0; i < dim(pos); i++) {
165                         int g = 0;
166                         for (int j = 0; j < dim(font.glyphs); j++) {
167                                 if (font.glyphs[j].encoding == i) {
168                                         g = j;
169                                         break;
170                                 }
171                         }
172                         string c;
173                         if (' ' <= i && i <= '~')
174                                 c = sprintf("%c", i);
175                         else
176                                 c = sprintf("%02x", i);
177                         printf("    { .width = %d, .height = %d, .x_off = %d, .y_off = %d, .advance = %d }, /* %s */\n",
178                                font.glyphs[g].width, font.glyphs[g].height,
179                                font.glyphs[g].x_off, font.glyphs[g].y_off, font.glyphs[g].advance, c);
180                 }
181                 printf("};\n");
182         }
183         printf("const struct ao_font %s_font = {\n", font_name);
184         printf("\t.bytes = %s_bytes,\n", font_name);
185         printf("\t.pos = %s_pos,\n", font_name);
186         if (!fixed_size)
187                 printf("\t.metrics = %s_metrics,\n", font_name);
188         printf("\t.max_width = %d,\n", max_width);
189         printf("\t.max_height = %d,\n", max_height);
190         printf("\t.ascent = %d,\n", font.ascent);
191         printf("};\n");
192 }
193
194 string
195 to_c(string a)
196 {
197         string r = "";
198         for (int i = String::rindex(a, "/") + 1; i < String::length(a); i++) {
199                 int c = a[i];
200                 if (c == '.')
201                         break;
202                 if (!(Ctype::isalnum(c) || c == '_'))
203                         c = '_';
204                 r += String::new(c);
205         }
206         if (!Ctype::isalpha(r[0]))
207                 r = "_" + r;
208         return r;
209 }
210
211 void
212 do_font(string name)
213 {
214         twixt (file f = File::open(name, "r"); File::close(f)) {
215                 font_t font = read_font(f);
216                 print_font(font, to_c(name));
217         }
218 }
219
220 do_font(argv[1]);