mkfont.cc (4813B)
1 /* Copyright 2013 Brian Swetland <swetland@frotz.net> 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <ft2build.h> 17 #include FT_FREETYPE_H 18 #include FT_OUTLINE_H 19 #include FT_BITMAP_H 20 #include FT_GLYPH_H 21 22 #include <util.h> 23 #include <io.h> 24 25 #include <texturefont.h> 26 27 #include <algorithm> 28 29 /* from internal header... */ 30 #define FT_PIX_FLOOR(x) ((x) & ~63) 31 #define FT_PIX_CEIL(x) FT_PIX_FLOOR((x) + 63) 32 33 struct Glyph { 34 unsigned c; 35 unsigned h; 36 }; 37 38 void get_bbox(FT_Outline *outline, FT_BBox *bb) { 39 FT_Outline_Get_CBox(outline, bb); 40 /* grid fit */ 41 bb->xMin = FT_PIX_FLOOR(bb->xMin); 42 bb->yMin = FT_PIX_FLOOR(bb->yMin); 43 bb->xMax = FT_PIX_CEIL(bb->xMax); 44 bb->yMax = FT_PIX_CEIL(bb->yMax); 45 /* convert from 26.6 to pixel coords */ 46 bb->xMin >>= 6; 47 bb->yMin >>= 6; 48 bb->xMax >>= 6; 49 bb->yMax >>= 6; 50 } 51 52 bool compare_glyphs(Glyph const &left, Glyph const &right) { 53 return left.h < right.h; 54 } 55 56 #define FIRST 0x20 57 #define LAST 0x7F 58 #define MAXDIM 1024 59 60 int main(int argc, char **argv) { 61 FT_Library ftl; 62 FT_Face face; 63 FT_Bitmap *bitmap; 64 unsigned i, n; 65 void *x; 66 67 FT_BBox bb; 68 FT_Bitmap bm; 69 unsigned char data[MAXDIM * MAXDIM]; 70 int w, h, tx, ty, nx, ny, rh, max; 71 CharInfo info[128]; 72 Glyph list[LAST]; 73 char tmp[256]; 74 75 io_ignore_asset_paths(); 76 77 if (argc < 4) 78 return error("usage: mkfont <truetypefont> <height> <outputname>"); 79 80 if (FT_Init_FreeType(&ftl)) 81 return -1; 82 83 x = load_file(argv[1], &n); 84 if (x == 0) 85 return -1; 86 87 if (FT_New_Memory_Face(ftl, (FT_Byte*) x, n, 0, &face)) 88 return error("cannot load font '%s'", argv[1]); 89 90 if (FT_Set_Pixel_Sizes(face, 0, atoi(argv[2]))) 91 return error("cannot set font size to %s\n", argv[2]); 92 93 for (n = FIRST; n < LAST; n++) { 94 if (FT_Load_Char(face, n, FT_LOAD_NO_BITMAP)) { 95 error("missing glyph for %d\n", n); 96 continue; 97 } 98 get_bbox(&face->glyph->outline, &bb); 99 list[n - FIRST].c = n; 100 list[n - FIRST].h = bb.yMax - bb.yMin; 101 102 } 103 std::sort(list, list + LAST - FIRST, compare_glyphs); 104 105 max = 128; 106 retry: 107 memset(data, 0, sizeof(data)); 108 memset(info, 0, sizeof(info)); 109 110 bm.rows = max; 111 bm.width = max; 112 bm.pitch = max; 113 bm.buffer = data; 114 bm.num_grays = 256; 115 bm.pixel_mode = FT_PIXEL_MODE_GRAY; 116 bm.palette_mode = 0; 117 bm.palette = NULL; 118 119 nx = ny = 1; 120 rh = 0; 121 122 int ascent, descent; 123 int ascent_max = 0; 124 int descent_max = 0; 125 int height_max = 0; 126 127 printf("%dx%d texture...\n", max, max); 128 for (i = 0; i < (LAST - FIRST); i++) { 129 n = list[i].c; 130 if (FT_Load_Char(face, n, FT_LOAD_NO_BITMAP)) { 131 error("missing glyph for %d\n", n); 132 continue; 133 } 134 get_bbox(&face->glyph->outline, &bb); 135 w = bb.xMax - bb.xMin + 1; 136 h = bb.yMax - bb.yMin + 1; 137 tx = -bb.xMin; 138 ty = -bb.yMin; 139 if ((nx + w) >= max) { 140 nx = 1; 141 ny += rh + 1; 142 rh = 0; 143 } 144 if ((ny + h) >= max) { 145 max *= 2; 146 if (max > MAXDIM) { 147 fprintf(stderr,"oops! out of space\n"); 148 return -1; 149 } 150 goto retry; 151 } 152 info[n].x = nx; 153 info[n].y = max - ny - h + 1; 154 info[n].w = w - 1; 155 info[n].h = h - 1; 156 info[n].dx = bb.xMin; 157 info[n].dy = bb.yMin; 158 info[n].advance = face->glyph->advance.x >> 6; 159 160 if (bb.yMin < 0) { 161 descent = -bb.yMin; 162 } else { 163 descent = 0; 164 } 165 ascent = h + bb.yMin; 166 if (ascent < 0) 167 ascent = 0; 168 if (ascent > ascent_max) 169 ascent_max = ascent; 170 if (descent > descent_max) 171 descent_max = descent; 172 if ((ascent + descent) > height_max) 173 height_max = ascent + descent; 174 175 FT_Outline_Translate(&face->glyph->outline, nx * 64 + tx * 64, ny * 64 + ty * 64); 176 FT_Outline_Get_Bitmap(ftl, &face->glyph->outline, &bm); 177 nx += w; 178 if (h > rh) 179 rh = h; 180 } 181 bitmap = &bm; 182 183 sprintf(tmp, "%s.png", argv[3]); 184 save_png_gray(tmp, bitmap->buffer, bitmap->width, bitmap->rows); 185 FontInfo header; 186 memset(&header, 0, sizeof(header)); 187 header.magic = TEXTUREFONT_MAGIC; 188 header.first = FIRST; 189 header.count = LAST - FIRST; 190 header.ascent_max = ascent_max; 191 header.descent_max = descent_max; 192 header.height_max = height_max; 193 194 sprintf(tmp, "%s.dat", argv[3]); 195 FILE *fp = fopen(tmp, "wb"); 196 if (!fp) 197 return error("cannot write font data"); 198 if (fwrite(&header, sizeof(header), 1, fp) != 1) 199 return error("failed to write font header"); 200 if (fwrite(info + header.first, sizeof(FontInfo), header.count, fp) != header.count) 201 return error("failed to write character info"); 202 fclose(fp); 203 return 0; 204 }