Mercurial > hg > index.fcgi > lj > lj046-2players
comparison tools/fontconv.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d6ee2c16cd14 |
---|---|
1 #define USE_CONSOLE | |
2 #include <allegro.h> | |
3 #include <stdio.h> | |
4 | |
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 }; | |
13 | |
14 typedef struct Rect { | |
15 signed short l, t, r, b; | |
16 } Rect; | |
17 | |
18 | |
19 BITMAP *fontImg; | |
20 const int cellHeight = 12; | |
21 Rect glyphs[256]; | |
22 unsigned short glyphDataOffsets[256]; | |
23 | |
24 #define MIN_GLYPH 0 | |
25 #define N_GLYPHS 256 | |
26 | |
27 char fontdata[65536]; | |
28 size_t fontdata_len = 0; | |
29 size_t fontdata_shift = 0; | |
30 | |
31 // stats | |
32 size_t eols = 0; | |
33 size_t xparents = 0; | |
34 size_t opaques = 0; | |
35 size_t xlucents = 0; | |
36 | |
37 void collectStats(int c) { | |
38 for (int y = glyphs[c].t; y < glyphs[c].b; ++y) { | |
39 | |
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 } | |
48 | |
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 } | |
67 | |
68 | |
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 } | |
79 | |
80 int x = (c & 0x07) * (SCREEN_W / 8); | |
81 int y = 288 + 32 * ((c & 0x18) >> 3); | |
82 | |
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 } | |
92 | |
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; | |
101 | |
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) { | |
106 | |
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 } | |
114 | |
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 } | |
125 | |
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 } | |
134 | |
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 } | |
149 | |
150 /* Details of the font encoding | |
151 | |
152 Header: | |
153 u8 offsetToEncodingTable; | |
154 u8 minGlyph; | |
155 u8 nGlyphs; | |
156 u8 fontHeight; | |
157 | |
158 First the encoding table (nglyphs/2 bytes): | |
159 u16 offsetToGlyphData; | |
160 u8 glyphWidth; | |
161 u8 reserved; | |
162 | |
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. | |
171 | |
172 */ | |
173 void compressPadByte(void) { | |
174 if (fontdata_shift > 0) { | |
175 fontdata_shift = 0; | |
176 ++fontdata_len; | |
177 } | |
178 } | |
179 | |
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 } | |
187 | |
188 void compressGlyph(unsigned int c) { | |
189 glyphDataOffsets[c] = fontdata_len; | |
190 for (int y = glyphs[c].t; y < glyphs[c].b; ++y) { | |
191 | |
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 } | |
200 | |
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 } | |
210 | |
211 // Signal eol | |
212 compressWriteCode(0); | |
213 } | |
214 compressPadByte(); | |
215 } | |
216 | |
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 } | |
224 | |
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; | |
231 | |
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); | |
239 | |
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 } | |
251 | |
252 #define WATCHING 0 | |
253 | |
254 int main(int argc, const char *const *argv) { | |
255 | |
256 if (argc != 3) { | |
257 fputs("syntax: fontconv fontbitmapname outname\n", stderr); | |
258 return EXIT_FAILURE; | |
259 } | |
260 | |
261 allegro_init(); | |
262 install_timer(); | |
263 | |
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 | |
278 | |
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(); | |
296 |