paulo@0: #define USE_CONSOLE paulo@0: #include paulo@0: #include paulo@0: paulo@0: const RGB fontPalette[6] = { paulo@0: {63, 0,63}, paulo@0: {63,63,63}, paulo@0: {42,42,42}, paulo@0: { 0, 0, 0}, paulo@0: {63, 0, 0}, paulo@0: {63,63, 0} paulo@0: }; paulo@0: paulo@0: typedef struct Rect { paulo@0: signed short l, t, r, b; paulo@0: } Rect; paulo@0: paulo@0: paulo@0: BITMAP *fontImg; paulo@0: const int cellHeight = 12; paulo@0: Rect glyphs[256]; paulo@0: unsigned short glyphDataOffsets[256]; paulo@0: paulo@0: #define MIN_GLYPH 0 paulo@0: #define N_GLYPHS 256 paulo@0: paulo@0: char fontdata[65536]; paulo@0: size_t fontdata_len = 0; paulo@0: size_t fontdata_shift = 0; paulo@0: paulo@0: // stats paulo@0: size_t eols = 0; paulo@0: size_t xparents = 0; paulo@0: size_t opaques = 0; paulo@0: size_t xlucents = 0; paulo@0: paulo@0: void collectStats(int c) { paulo@0: for (int y = glyphs[c].t; y < glyphs[c].b; ++y) { paulo@0: paulo@0: // Find right side of each row of glyph paulo@0: int right = glyphs[c].l; paulo@0: for (int x = glyphs[c].l; x < glyphs[c].r; ++x) { paulo@0: int c = getpixel(fontImg, x, y); paulo@0: if (c == 2 || c == 3) { paulo@0: right = x + 1; paulo@0: } paulo@0: } paulo@0: paulo@0: // Count transparent, semitransparent, and opaque paulo@0: // pixels within row paulo@0: for (int x = glyphs[c].l; x < right; ++x) { paulo@0: switch (getpixel(fontImg, x, y)) { paulo@0: case 1: paulo@0: ++xparents; paulo@0: break; paulo@0: case 2: paulo@0: ++xlucents; paulo@0: break; paulo@0: case 3: paulo@0: ++opaques; paulo@0: break; paulo@0: } paulo@0: } paulo@0: ++eols; paulo@0: } paulo@0: } paulo@0: paulo@0: paulo@0: void drawChar(int c) { paulo@0: int left = glyphs[c].l; paulo@0: int top = glyphs[c].t; paulo@0: int right = glyphs[c].r; paulo@0: int bottom = glyphs[c].b; paulo@0: if ((c & 0x1F) == 0) { paulo@0: rectfill(screen, paulo@0: 0, 288, SCREEN_W - 1, 288 + 32 * 4, paulo@0: 5); paulo@0: } paulo@0: paulo@0: int x = (c & 0x07) * (SCREEN_W / 8); paulo@0: int y = 288 + 32 * ((c & 0x18) >> 3); paulo@0: paulo@0: textprintf_ex(screen, font, x, y + bottom - top - 4, 3, -1, paulo@0: "%c=", c); paulo@0: stretch_blit(fontImg, screen, paulo@0: left, top, right - left, bottom - top, paulo@0: x + 16, y, (right - left) * 2, (bottom - top) * 2); paulo@0: if ((c & 0x1F) == 0x1F) { paulo@0: readkey(); paulo@0: } paulo@0: } paulo@0: paulo@0: // color 0: border around kernbox paulo@0: // color 1: background paulo@0: // color 2: mix bg+fg paulo@0: // color 3: foreground paulo@0: void findCharacters(void) { paulo@0: int curChar = MIN_GLYPH; paulo@0: int x = 0; paulo@0: int y = 12; paulo@0: paulo@0: for(y = 0; y < fontImg->h; y += cellHeight) { paulo@0: for (x = 0; x < fontImg->w; ++x) { paulo@0: // Skip if border pixel paulo@0: if (getpixel(fontImg, x, y) != 0) { paulo@0: paulo@0: // find left and right extents paulo@0: int left = x; paulo@0: int right; paulo@0: for (right = x; paulo@0: right < fontImg->w && getpixel(fontImg, right, y) != 0; paulo@0: ++right) { paulo@0: } paulo@0: paulo@0: // record them paulo@0: glyphs[curChar].l = left; paulo@0: glyphs[curChar].t = y; paulo@0: glyphs[curChar].r = right; paulo@0: glyphs[curChar].b = y + cellHeight; paulo@0: x = right; paulo@0: ++curChar; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: #if 0 paulo@0: int maxChar = curChar; paulo@0: for (curChar = MIN_GLYPH; curChar < maxChar; ++curChar) { paulo@0: collectStats(curChar); paulo@0: drawChar(curChar); paulo@0: } paulo@0: #endif paulo@0: } paulo@0: paulo@0: void displayStats(void) { paulo@0: rectfill(screen, 0, 288, 255, 479, 5); paulo@0: textprintf_ex(screen, font, 4, 298, 3, -1, paulo@0: "xparents: %d", xparents); paulo@0: textprintf_ex(screen, font, 4, 308, 3, -1, paulo@0: "xlucents: %d", xlucents); paulo@0: textprintf_ex(screen, font, 4, 318, 3, -1, paulo@0: "opaques: %d", opaques); paulo@0: textprintf_ex(screen, font, 4, 328, 3, -1, paulo@0: "end of lines: %d", eols); paulo@0: textprintf_ex(screen, font, 4, 338, 3, -1, paulo@0: "total number of bits: %d", paulo@0: (xparents + xlucents + opaques + eols + 3) * 2); paulo@0: } paulo@0: paulo@0: /* Details of the font encoding paulo@0: paulo@0: Header: paulo@0: u8 offsetToEncodingTable; paulo@0: u8 minGlyph; paulo@0: u8 nGlyphs; paulo@0: u8 fontHeight; paulo@0: paulo@0: First the encoding table (nglyphs/2 bytes): paulo@0: u16 offsetToGlyphData; paulo@0: u8 glyphWidth; paulo@0: u8 reserved; paulo@0: paulo@0: Each glyph data element consists of a stream of bytes. paulo@0: Each byte contains four 2-bit values packed little-endian: paulo@0: 0: Move pen to start of next line paulo@0: 1: Move pen to right paulo@0: 2: Draw pixel using 50% opacity and move pen to right paulo@0: 3: Draw pixel using 100% opacity and move pen to right paulo@0: The glyph data is done when "Move pen to start of next line" paulo@0: has run fontHeight times. paulo@0: paulo@0: */ paulo@0: void compressPadByte(void) { paulo@0: if (fontdata_shift > 0) { paulo@0: fontdata_shift = 0; paulo@0: ++fontdata_len; paulo@0: } paulo@0: } paulo@0: paulo@0: void compressWriteCode(unsigned int code) { paulo@0: fontdata[fontdata_len] |= code << fontdata_shift; paulo@0: fontdata_shift += 2; paulo@0: if (fontdata_shift >= 8) { paulo@0: compressPadByte(); paulo@0: } paulo@0: } paulo@0: paulo@0: void compressGlyph(unsigned int c) { paulo@0: glyphDataOffsets[c] = fontdata_len; paulo@0: for (int y = glyphs[c].t; y < glyphs[c].b; ++y) { paulo@0: paulo@0: // Find right side of each row of glyph paulo@0: int right = glyphs[c].l; paulo@0: for (int x = glyphs[c].l; x < glyphs[c].r; ++x) { paulo@0: int c = getpixel(fontImg, x, y); paulo@0: if (c == 2 || c == 3) { paulo@0: right = x + 1; paulo@0: } paulo@0: } paulo@0: paulo@0: // Write transparent, semitransparent, and opaque paulo@0: // pixels within row paulo@0: for (int x = glyphs[c].l; x < right; ++x) { paulo@0: int code = getpixel(fontImg, x, y) & 3; paulo@0: if (code == 0) { paulo@0: code = 1; paulo@0: } paulo@0: compressWriteCode(code); paulo@0: } paulo@0: paulo@0: // Signal eol paulo@0: compressWriteCode(0); paulo@0: } paulo@0: compressPadByte(); paulo@0: } paulo@0: paulo@0: void compressFont(void) { paulo@0: unsigned int minGlyph = MIN_GLYPH; paulo@0: size_t nGlyphs = N_GLYPHS; paulo@0: for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) { paulo@0: compressGlyph(i); paulo@0: } paulo@0: } paulo@0: paulo@0: int writeFont(const char *dstName) { paulo@0: FILE *dst = fopen(dstName, "wb"); paulo@0: unsigned int minGlyph = MIN_GLYPH; paulo@0: size_t nGlyphs = N_GLYPHS; paulo@0: size_t headerLen = 4; paulo@0: size_t glyphDataBase = nGlyphs * 4 + headerLen; paulo@0: paulo@0: if (!dst) { paulo@0: return EXIT_FAILURE; paulo@0: } paulo@0: fputc(4, dst); // offset to encoding table paulo@0: fputc(minGlyph, dst); paulo@0: fputc(nGlyphs, dst); paulo@0: fputc(cellHeight, dst); paulo@0: paulo@0: for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) { paulo@0: size_t glyphDataOffset = glyphDataBase + glyphDataOffsets[i]; paulo@0: fputc(glyphDataOffset & 0xFF, dst); paulo@0: fputc((glyphDataOffset >> 8) & 0xFF, dst); paulo@0: fputc(glyphs[i].r - glyphs[i].l, dst); paulo@0: fputc(0, dst); paulo@0: } paulo@0: fwrite(fontdata, fontdata_len, 1, dst); paulo@0: fclose(dst); paulo@0: return 0; paulo@0: } paulo@0: paulo@0: #define WATCHING 0 paulo@0: paulo@0: int main(int argc, const char *const *argv) { paulo@0: paulo@0: if (argc != 3) { paulo@0: fputs("syntax: fontconv fontbitmapname outname\n", stderr); paulo@0: return EXIT_FAILURE; paulo@0: } paulo@0: paulo@0: allegro_init(); paulo@0: install_timer(); paulo@0: paulo@0: set_color_depth(8); paulo@0: #if WATCHING paulo@0: if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 256, 480, 0, 0) < 0) { paulo@0: allegro_message("Could not open a dual screen sized window.\n"); paulo@0: return EXIT_FAILURE; paulo@0: } paulo@0: set_palette_range(fontPalette, paulo@0: 0, sizeof(fontPalette)/sizeof(fontPalette[0]) - 1, paulo@0: 1); paulo@0: clear_bitmap(screen); paulo@0: rectfill(screen, 0, 192, 255, 287, 2); paulo@0: rectfill(screen, 0, 288, 255, 479, 5); paulo@0: install_keyboard(); paulo@0: #endif paulo@0: paulo@0: fontImg = load_bitmap(argv[1], NULL); paulo@0: if (!fontImg) { paulo@0: allegro_exit(); paulo@0: fprintf(stderr, "fontconv could not load %s\n", paulo@0: argv[1]); paulo@0: return EXIT_FAILURE; paulo@0: } paulo@0: findCharacters(); paulo@0: #if WATCHING paulo@0: blit(fontImg, screen, 0, 0, 0, 0, fontImg->w, fontImg->h); paulo@0: readkey(); paulo@0: displayStats(); paulo@0: readkey(); paulo@0: #endif paulo@0: compressFont(); paulo@0: return writeFont(argv[2]); paulo@0: } END_OF_MAIN(); paulo@0: