// 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;
 }
Example #2
0
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);
        }
    }
}