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