Mercurial > hg > index.fcgi > lj > lj046-2players
diff tools/fontconv.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/fontconv.c Fri Mar 13 00:39:12 2009 -0700 1.3 @@ -0,0 +1,296 @@ 1.4 +#define USE_CONSOLE 1.5 +#include <allegro.h> 1.6 +#include <stdio.h> 1.7 + 1.8 +const RGB fontPalette[6] = { 1.9 + {63, 0,63}, 1.10 + {63,63,63}, 1.11 + {42,42,42}, 1.12 + { 0, 0, 0}, 1.13 + {63, 0, 0}, 1.14 + {63,63, 0} 1.15 +}; 1.16 + 1.17 +typedef struct Rect { 1.18 + signed short l, t, r, b; 1.19 +} Rect; 1.20 + 1.21 + 1.22 +BITMAP *fontImg; 1.23 +const int cellHeight = 12; 1.24 +Rect glyphs[256]; 1.25 +unsigned short glyphDataOffsets[256]; 1.26 + 1.27 +#define MIN_GLYPH 0 1.28 +#define N_GLYPHS 256 1.29 + 1.30 +char fontdata[65536]; 1.31 +size_t fontdata_len = 0; 1.32 +size_t fontdata_shift = 0; 1.33 + 1.34 +// stats 1.35 +size_t eols = 0; 1.36 +size_t xparents = 0; 1.37 +size_t opaques = 0; 1.38 +size_t xlucents = 0; 1.39 + 1.40 +void collectStats(int c) { 1.41 + for (int y = glyphs[c].t; y < glyphs[c].b; ++y) { 1.42 + 1.43 + // Find right side of each row of glyph 1.44 + int right = glyphs[c].l; 1.45 + for (int x = glyphs[c].l; x < glyphs[c].r; ++x) { 1.46 + int c = getpixel(fontImg, x, y); 1.47 + if (c == 2 || c == 3) { 1.48 + right = x + 1; 1.49 + } 1.50 + } 1.51 + 1.52 + // Count transparent, semitransparent, and opaque 1.53 + // pixels within row 1.54 + for (int x = glyphs[c].l; x < right; ++x) { 1.55 + switch (getpixel(fontImg, x, y)) { 1.56 + case 1: 1.57 + ++xparents; 1.58 + break; 1.59 + case 2: 1.60 + ++xlucents; 1.61 + break; 1.62 + case 3: 1.63 + ++opaques; 1.64 + break; 1.65 + } 1.66 + } 1.67 + ++eols; 1.68 + } 1.69 +} 1.70 + 1.71 + 1.72 +void drawChar(int c) { 1.73 + int left = glyphs[c].l; 1.74 + int top = glyphs[c].t; 1.75 + int right = glyphs[c].r; 1.76 + int bottom = glyphs[c].b; 1.77 + if ((c & 0x1F) == 0) { 1.78 + rectfill(screen, 1.79 + 0, 288, SCREEN_W - 1, 288 + 32 * 4, 1.80 + 5); 1.81 + } 1.82 + 1.83 + int x = (c & 0x07) * (SCREEN_W / 8); 1.84 + int y = 288 + 32 * ((c & 0x18) >> 3); 1.85 + 1.86 + textprintf_ex(screen, font, x, y + bottom - top - 4, 3, -1, 1.87 + "%c=", c); 1.88 + stretch_blit(fontImg, screen, 1.89 + left, top, right - left, bottom - top, 1.90 + x + 16, y, (right - left) * 2, (bottom - top) * 2); 1.91 + if ((c & 0x1F) == 0x1F) { 1.92 + readkey(); 1.93 + } 1.94 +} 1.95 + 1.96 +// color 0: border around kernbox 1.97 +// color 1: background 1.98 +// color 2: mix bg+fg 1.99 +// color 3: foreground 1.100 +void findCharacters(void) { 1.101 + int curChar = MIN_GLYPH; 1.102 + int x = 0; 1.103 + int y = 12; 1.104 + 1.105 + for(y = 0; y < fontImg->h; y += cellHeight) { 1.106 + for (x = 0; x < fontImg->w; ++x) { 1.107 + // Skip if border pixel 1.108 + if (getpixel(fontImg, x, y) != 0) { 1.109 + 1.110 + // find left and right extents 1.111 + int left = x; 1.112 + int right; 1.113 + for (right = x; 1.114 + right < fontImg->w && getpixel(fontImg, right, y) != 0; 1.115 + ++right) { 1.116 + } 1.117 + 1.118 + // record them 1.119 + glyphs[curChar].l = left; 1.120 + glyphs[curChar].t = y; 1.121 + glyphs[curChar].r = right; 1.122 + glyphs[curChar].b = y + cellHeight; 1.123 + x = right; 1.124 + ++curChar; 1.125 + } 1.126 + } 1.127 + } 1.128 + 1.129 +#if 0 1.130 + int maxChar = curChar; 1.131 + for (curChar = MIN_GLYPH; curChar < maxChar; ++curChar) { 1.132 + collectStats(curChar); 1.133 + drawChar(curChar); 1.134 + } 1.135 +#endif 1.136 +} 1.137 + 1.138 +void displayStats(void) { 1.139 + rectfill(screen, 0, 288, 255, 479, 5); 1.140 + textprintf_ex(screen, font, 4, 298, 3, -1, 1.141 + "xparents: %d", xparents); 1.142 + textprintf_ex(screen, font, 4, 308, 3, -1, 1.143 + "xlucents: %d", xlucents); 1.144 + textprintf_ex(screen, font, 4, 318, 3, -1, 1.145 + "opaques: %d", opaques); 1.146 + textprintf_ex(screen, font, 4, 328, 3, -1, 1.147 + "end of lines: %d", eols); 1.148 + textprintf_ex(screen, font, 4, 338, 3, -1, 1.149 + "total number of bits: %d", 1.150 + (xparents + xlucents + opaques + eols + 3) * 2); 1.151 +} 1.152 + 1.153 +/* Details of the font encoding 1.154 + 1.155 +Header: 1.156 +u8 offsetToEncodingTable; 1.157 +u8 minGlyph; 1.158 +u8 nGlyphs; 1.159 +u8 fontHeight; 1.160 + 1.161 +First the encoding table (nglyphs/2 bytes): 1.162 +u16 offsetToGlyphData; 1.163 +u8 glyphWidth; 1.164 +u8 reserved; 1.165 + 1.166 +Each glyph data element consists of a stream of bytes. 1.167 +Each byte contains four 2-bit values packed little-endian: 1.168 +0: Move pen to start of next line 1.169 +1: Move pen to right 1.170 +2: Draw pixel using 50% opacity and move pen to right 1.171 +3: Draw pixel using 100% opacity and move pen to right 1.172 +The glyph data is done when "Move pen to start of next line" 1.173 +has run fontHeight times. 1.174 + 1.175 +*/ 1.176 +void compressPadByte(void) { 1.177 + if (fontdata_shift > 0) { 1.178 + fontdata_shift = 0; 1.179 + ++fontdata_len; 1.180 + } 1.181 +} 1.182 + 1.183 +void compressWriteCode(unsigned int code) { 1.184 + fontdata[fontdata_len] |= code << fontdata_shift; 1.185 + fontdata_shift += 2; 1.186 + if (fontdata_shift >= 8) { 1.187 + compressPadByte(); 1.188 + } 1.189 +} 1.190 + 1.191 +void compressGlyph(unsigned int c) { 1.192 + glyphDataOffsets[c] = fontdata_len; 1.193 + for (int y = glyphs[c].t; y < glyphs[c].b; ++y) { 1.194 + 1.195 + // Find right side of each row of glyph 1.196 + int right = glyphs[c].l; 1.197 + for (int x = glyphs[c].l; x < glyphs[c].r; ++x) { 1.198 + int c = getpixel(fontImg, x, y); 1.199 + if (c == 2 || c == 3) { 1.200 + right = x + 1; 1.201 + } 1.202 + } 1.203 + 1.204 + // Write transparent, semitransparent, and opaque 1.205 + // pixels within row 1.206 + for (int x = glyphs[c].l; x < right; ++x) { 1.207 + int code = getpixel(fontImg, x, y) & 3; 1.208 + if (code == 0) { 1.209 + code = 1; 1.210 + } 1.211 + compressWriteCode(code); 1.212 + } 1.213 + 1.214 + // Signal eol 1.215 + compressWriteCode(0); 1.216 + } 1.217 + compressPadByte(); 1.218 +} 1.219 + 1.220 +void compressFont(void) { 1.221 + unsigned int minGlyph = MIN_GLYPH; 1.222 + size_t nGlyphs = N_GLYPHS; 1.223 + for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) { 1.224 + compressGlyph(i); 1.225 + } 1.226 +} 1.227 + 1.228 +int writeFont(const char *dstName) { 1.229 + FILE *dst = fopen(dstName, "wb"); 1.230 + unsigned int minGlyph = MIN_GLYPH; 1.231 + size_t nGlyphs = N_GLYPHS; 1.232 + size_t headerLen = 4; 1.233 + size_t glyphDataBase = nGlyphs * 4 + headerLen; 1.234 + 1.235 + if (!dst) { 1.236 + return EXIT_FAILURE; 1.237 + } 1.238 + fputc(4, dst); // offset to encoding table 1.239 + fputc(minGlyph, dst); 1.240 + fputc(nGlyphs, dst); 1.241 + fputc(cellHeight, dst); 1.242 + 1.243 + for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) { 1.244 + size_t glyphDataOffset = glyphDataBase + glyphDataOffsets[i]; 1.245 + fputc(glyphDataOffset & 0xFF, dst); 1.246 + fputc((glyphDataOffset >> 8) & 0xFF, dst); 1.247 + fputc(glyphs[i].r - glyphs[i].l, dst); 1.248 + fputc(0, dst); 1.249 + } 1.250 + fwrite(fontdata, fontdata_len, 1, dst); 1.251 + fclose(dst); 1.252 + return 0; 1.253 +} 1.254 + 1.255 +#define WATCHING 0 1.256 + 1.257 +int main(int argc, const char *const *argv) { 1.258 + 1.259 + if (argc != 3) { 1.260 + fputs("syntax: fontconv fontbitmapname outname\n", stderr); 1.261 + return EXIT_FAILURE; 1.262 + } 1.263 + 1.264 + allegro_init(); 1.265 + install_timer(); 1.266 + 1.267 + set_color_depth(8); 1.268 +#if WATCHING 1.269 + if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 256, 480, 0, 0) < 0) { 1.270 + allegro_message("Could not open a dual screen sized window.\n"); 1.271 + return EXIT_FAILURE; 1.272 + } 1.273 + set_palette_range(fontPalette, 1.274 + 0, sizeof(fontPalette)/sizeof(fontPalette[0]) - 1, 1.275 + 1); 1.276 + clear_bitmap(screen); 1.277 + rectfill(screen, 0, 192, 255, 287, 2); 1.278 + rectfill(screen, 0, 288, 255, 479, 5); 1.279 + install_keyboard(); 1.280 +#endif 1.281 + 1.282 + fontImg = load_bitmap(argv[1], NULL); 1.283 + if (!fontImg) { 1.284 + allegro_exit(); 1.285 + fprintf(stderr, "fontconv could not load %s\n", 1.286 + argv[1]); 1.287 + return EXIT_FAILURE; 1.288 + } 1.289 + findCharacters(); 1.290 +#if WATCHING 1.291 + blit(fontImg, screen, 0, 0, 0, 0, fontImg->w, fontImg->h); 1.292 + readkey(); 1.293 + displayStats(); 1.294 + readkey(); 1.295 +#endif 1.296 + compressFont(); 1.297 + return writeFont(argv[2]); 1.298 +} END_OF_MAIN(); 1.299 +