// Bake a given set of ranges of chars int TTFFontAsset::BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) float pixel_height, // height of font in pixels unsigned char *pixels, int pw, int ph, // bitmap to be filled in const GlyphRanges& ranges, // characters to bake BakedChar *chardata) { stbtt_fontinfo f; stbtt_InitFont(&f, data, offset); STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels int x = 1, y = 1; int bottom_y = 1; glyphMap.clear(); float scale = stbtt_ScaleForPixelHeight(&f, pixel_height); int bakedIdx = 0; for (GlyphRanges::const_iterator iter = ranges.begin(); iter != ranges.end(); ++iter) { const Range<int>& range = *iter; int numItemsInRange = range.high - range.low; for (int i = 0; i <= numItemsInRange; i++, bakedIdx++) { int unicodeCodepoint = i + range.low; glyphMap.insert(std::make_pair(unicodeCodepoint, bakedIdx)); int advance, lsb, x0,y0,x1,y1,gw,gh; int g = stbtt_FindGlyphIndex(&f, unicodeCodepoint); stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); gw = x1-x0; gh = y1-y0; if (x + gw + 1 >= pw) y = bottom_y, x = 1; // advance to next row if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row return -i; STBTT_assert(x+gw < pw); STBTT_assert(y+gh < ph); stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); chardata[bakedIdx].x0 = (stbtt_int16) x; chardata[bakedIdx].y0 = (stbtt_int16) y; chardata[bakedIdx].x1 = (stbtt_int16) (x + gw); chardata[bakedIdx].y1 = (stbtt_int16) (y + gh); chardata[bakedIdx].xadvance = scale * advance; chardata[bakedIdx].xoff = (float) x0; chardata[bakedIdx].yoff = (float) y0; x = x + gw + 2; if (y+gh+2 > bottom_y) bottom_y = y+gh+2; } } return bottom_y; }
void GlFont::InitialiseFont(const unsigned char* ttf_buffer, float pixel_height, int tex_w, int tex_h) { font_height_px = pixel_height; this->tex_w = tex_w; this->tex_h = tex_h; font_bitmap = new unsigned char[tex_w*tex_h]; const int offset = 0; stbtt_fontinfo f; if (!stbtt_InitFont(&f, ttf_buffer, offset)) { throw std::runtime_error("Unable to initialise font"); } float scale = stbtt_ScaleForPixelHeight(&f, pixel_height); STBTT_memset(font_bitmap, 0, tex_w*tex_h); int x = 1; int y = 1; int bottom_y = 1; // Generate bitmap and char indices for (int i=0; i < NUM_CHARS; ++i) { int advance, lsb, x0,y0,x1,y1,gw,gh; int g = stbtt_FindGlyphIndex(&f, FIRST_CHAR + i); stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); gw = x1-x0; gh = y1-y0; if (x + gw + 1 >= tex_w) y = bottom_y, x = 1; // advance to next row if (y + gh + 1 >= tex_h) // check if it fits vertically AFTER potentially moving to next row throw std::runtime_error("Unable to initialise font"); STBTT_assert(x+gw < tex_w); STBTT_assert(y+gh < tex_h); stbtt_MakeGlyphBitmap(&f, font_bitmap+x+y*tex_w, gw,gh,tex_w, scale,scale, g); // Adjust offset for edges of pixels chardata[i] = GlChar(tex_w,tex_h, x, y, gw, gh, scale*advance, x0 -0.5, -y0 -0.5); x = x + gw + 1; if (y+gh+1 > bottom_y) bottom_y = y+gh+1; } // Generate kern table for (int i=0; i < NUM_CHARS; ++i) { for (int j=0; j < NUM_CHARS; ++j) { kern_table[i*NUM_CHARS+j] = scale * stbtt_GetCodepointKernAdvance(&f,i,j); } } }