view tools/fontconv.c @ 3:17286938e22a

change DS alt. rotate key to rotate twice
author paulo@localhost
date Wed, 08 Apr 2009 21:50:13 -0700
parents
children
line source
1 #define USE_CONSOLE
2 #include <allegro.h>
3 #include <stdio.h>
5 const RGB fontPalette[6] = {
6 {63, 0,63},
7 {63,63,63},
8 {42,42,42},
9 { 0, 0, 0},
10 {63, 0, 0},
11 {63,63, 0}
12 };
14 typedef struct Rect {
15 signed short l, t, r, b;
16 } Rect;
19 BITMAP *fontImg;
20 const int cellHeight = 12;
21 Rect glyphs[256];
22 unsigned short glyphDataOffsets[256];
24 #define MIN_GLYPH 0
25 #define N_GLYPHS 256
27 char fontdata[65536];
28 size_t fontdata_len = 0;
29 size_t fontdata_shift = 0;
31 // stats
32 size_t eols = 0;
33 size_t xparents = 0;
34 size_t opaques = 0;
35 size_t xlucents = 0;
37 void collectStats(int c) {
38 for (int y = glyphs[c].t; y < glyphs[c].b; ++y) {
40 // Find right side of each row of glyph
41 int right = glyphs[c].l;
42 for (int x = glyphs[c].l; x < glyphs[c].r; ++x) {
43 int c = getpixel(fontImg, x, y);
44 if (c == 2 || c == 3) {
45 right = x + 1;
46 }
47 }
49 // Count transparent, semitransparent, and opaque
50 // pixels within row
51 for (int x = glyphs[c].l; x < right; ++x) {
52 switch (getpixel(fontImg, x, y)) {
53 case 1:
54 ++xparents;
55 break;
56 case 2:
57 ++xlucents;
58 break;
59 case 3:
60 ++opaques;
61 break;
62 }
63 }
64 ++eols;
65 }
66 }
69 void drawChar(int c) {
70 int left = glyphs[c].l;
71 int top = glyphs[c].t;
72 int right = glyphs[c].r;
73 int bottom = glyphs[c].b;
74 if ((c & 0x1F) == 0) {
75 rectfill(screen,
76 0, 288, SCREEN_W - 1, 288 + 32 * 4,
77 5);
78 }
80 int x = (c & 0x07) * (SCREEN_W / 8);
81 int y = 288 + 32 * ((c & 0x18) >> 3);
83 textprintf_ex(screen, font, x, y + bottom - top - 4, 3, -1,
84 "%c=", c);
85 stretch_blit(fontImg, screen,
86 left, top, right - left, bottom - top,
87 x + 16, y, (right - left) * 2, (bottom - top) * 2);
88 if ((c & 0x1F) == 0x1F) {
89 readkey();
90 }
91 }
93 // color 0: border around kernbox
94 // color 1: background
95 // color 2: mix bg+fg
96 // color 3: foreground
97 void findCharacters(void) {
98 int curChar = MIN_GLYPH;
99 int x = 0;
100 int y = 12;
102 for(y = 0; y < fontImg->h; y += cellHeight) {
103 for (x = 0; x < fontImg->w; ++x) {
104 // Skip if border pixel
105 if (getpixel(fontImg, x, y) != 0) {
107 // find left and right extents
108 int left = x;
109 int right;
110 for (right = x;
111 right < fontImg->w && getpixel(fontImg, right, y) != 0;
112 ++right) {
113 }
115 // record them
116 glyphs[curChar].l = left;
117 glyphs[curChar].t = y;
118 glyphs[curChar].r = right;
119 glyphs[curChar].b = y + cellHeight;
120 x = right;
121 ++curChar;
122 }
123 }
124 }
126 #if 0
127 int maxChar = curChar;
128 for (curChar = MIN_GLYPH; curChar < maxChar; ++curChar) {
129 collectStats(curChar);
130 drawChar(curChar);
131 }
132 #endif
133 }
135 void displayStats(void) {
136 rectfill(screen, 0, 288, 255, 479, 5);
137 textprintf_ex(screen, font, 4, 298, 3, -1,
138 "xparents: %d", xparents);
139 textprintf_ex(screen, font, 4, 308, 3, -1,
140 "xlucents: %d", xlucents);
141 textprintf_ex(screen, font, 4, 318, 3, -1,
142 "opaques: %d", opaques);
143 textprintf_ex(screen, font, 4, 328, 3, -1,
144 "end of lines: %d", eols);
145 textprintf_ex(screen, font, 4, 338, 3, -1,
146 "total number of bits: %d",
147 (xparents + xlucents + opaques + eols + 3) * 2);
148 }
150 /* Details of the font encoding
152 Header:
153 u8 offsetToEncodingTable;
154 u8 minGlyph;
155 u8 nGlyphs;
156 u8 fontHeight;
158 First the encoding table (nglyphs/2 bytes):
159 u16 offsetToGlyphData;
160 u8 glyphWidth;
161 u8 reserved;
163 Each glyph data element consists of a stream of bytes.
164 Each byte contains four 2-bit values packed little-endian:
165 0: Move pen to start of next line
166 1: Move pen to right
167 2: Draw pixel using 50% opacity and move pen to right
168 3: Draw pixel using 100% opacity and move pen to right
169 The glyph data is done when "Move pen to start of next line"
170 has run fontHeight times.
172 */
173 void compressPadByte(void) {
174 if (fontdata_shift > 0) {
175 fontdata_shift = 0;
176 ++fontdata_len;
177 }
178 }
180 void compressWriteCode(unsigned int code) {
181 fontdata[fontdata_len] |= code << fontdata_shift;
182 fontdata_shift += 2;
183 if (fontdata_shift >= 8) {
184 compressPadByte();
185 }
186 }
188 void compressGlyph(unsigned int c) {
189 glyphDataOffsets[c] = fontdata_len;
190 for (int y = glyphs[c].t; y < glyphs[c].b; ++y) {
192 // Find right side of each row of glyph
193 int right = glyphs[c].l;
194 for (int x = glyphs[c].l; x < glyphs[c].r; ++x) {
195 int c = getpixel(fontImg, x, y);
196 if (c == 2 || c == 3) {
197 right = x + 1;
198 }
199 }
201 // Write transparent, semitransparent, and opaque
202 // pixels within row
203 for (int x = glyphs[c].l; x < right; ++x) {
204 int code = getpixel(fontImg, x, y) & 3;
205 if (code == 0) {
206 code = 1;
207 }
208 compressWriteCode(code);
209 }
211 // Signal eol
212 compressWriteCode(0);
213 }
214 compressPadByte();
215 }
217 void compressFont(void) {
218 unsigned int minGlyph = MIN_GLYPH;
219 size_t nGlyphs = N_GLYPHS;
220 for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) {
221 compressGlyph(i);
222 }
223 }
225 int writeFont(const char *dstName) {
226 FILE *dst = fopen(dstName, "wb");
227 unsigned int minGlyph = MIN_GLYPH;
228 size_t nGlyphs = N_GLYPHS;
229 size_t headerLen = 4;
230 size_t glyphDataBase = nGlyphs * 4 + headerLen;
232 if (!dst) {
233 return EXIT_FAILURE;
234 }
235 fputc(4, dst); // offset to encoding table
236 fputc(minGlyph, dst);
237 fputc(nGlyphs, dst);
238 fputc(cellHeight, dst);
240 for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) {
241 size_t glyphDataOffset = glyphDataBase + glyphDataOffsets[i];
242 fputc(glyphDataOffset & 0xFF, dst);
243 fputc((glyphDataOffset >> 8) & 0xFF, dst);
244 fputc(glyphs[i].r - glyphs[i].l, dst);
245 fputc(0, dst);
246 }
247 fwrite(fontdata, fontdata_len, 1, dst);
248 fclose(dst);
249 return 0;
250 }
252 #define WATCHING 0
254 int main(int argc, const char *const *argv) {
256 if (argc != 3) {
257 fputs("syntax: fontconv fontbitmapname outname\n", stderr);
258 return EXIT_FAILURE;
259 }
261 allegro_init();
262 install_timer();
264 set_color_depth(8);
265 #if WATCHING
266 if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 256, 480, 0, 0) < 0) {
267 allegro_message("Could not open a dual screen sized window.\n");
268 return EXIT_FAILURE;
269 }
270 set_palette_range(fontPalette,
271 0, sizeof(fontPalette)/sizeof(fontPalette[0]) - 1,
272 1);
273 clear_bitmap(screen);
274 rectfill(screen, 0, 192, 255, 287, 2);
275 rectfill(screen, 0, 288, 255, 479, 5);
276 install_keyboard();
277 #endif
279 fontImg = load_bitmap(argv[1], NULL);
280 if (!fontImg) {
281 allegro_exit();
282 fprintf(stderr, "fontconv could not load %s\n",
283 argv[1]);
284 return EXIT_FAILURE;
285 }
286 findCharacters();
287 #if WATCHING
288 blit(fontImg, screen, 0, 0, 0, 0, fontImg->w, fontImg->h);
289 readkey();
290 displayStats();
291 readkey();
292 #endif
293 compressFont();
294 return writeFont(argv[2]);
295 } END_OF_MAIN();