DaoxGlyph* DaoxFont_LoadGlyph( DaoxFont *self, size_t codepoint ) { DaoxGlyph *glyph = DaoxGlyph_New(); stbtt_vertex *vertices = NULL; int id = stbtt_FindGlyphIndex( & self->info, codepoint ); int i, num_verts = stbtt_GetGlyphShape( & self->info, id, & vertices ); stbtt_GetGlyphHMetrics( & self->info, id, & glyph->advanceWidth, & glyph->leftSideBearing ); DMap_Insert( self->glyphs, (void*) codepoint, glyph ); DaoxPath_SetRelativeMode( glyph->shape, 0 ); for(i=0; i<num_verts; ++i){ stbtt_vertex_type x = vertices[i].x; stbtt_vertex_type y = vertices[i].y; stbtt_vertex_type cx = vertices[i].cx; stbtt_vertex_type cy = vertices[i].cy; switch( vertices[i].type ){ case STBTT_vmove : if( i ) DaoxPath_Close( glyph->shape ); DaoxPath_MoveTo( glyph->shape, x, y ); break; case STBTT_vline : DaoxPath_LineTo( glyph->shape, x, y ); break; case STBTT_vcurve : DaoxPath_QuadTo( glyph->shape, cx, cy, x, y ); break; } } if( i ) DaoxPath_Close( glyph->shape ); stbtt_FreeShape( & self->info, vertices ); return glyph; }
// 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); } } }
struct TEXT_FONT_GLYPH *textRenderGlyph(struct TEXT_FONT_CACHE *index, unsigned int glyph, int glyph_index, TEXT_FONT *font) { int pos_x, pos_y, w, h, x1, x2, y1, y2, ad, sb; unsigned char *data; struct TEXT_FONT_GLYPH *next, *alloc; float skipf; if ((alloc = malloc(sizeof(struct TEXT_FONT_GLYPH))) == NULL) return NULL; next = index->glyph; alloc->next = NULL; if (next == NULL) index->glyph = alloc; else { while (next->next != NULL) next = next->next; next->next = alloc; } x1 = y1 = x2 = y2 = 0; data = stbtt_GetGlyphBitmap(&font->face, 0, font->scale, glyph_index, &w, &h, 0, 0); textCacheGetCoordinates(index, w, h, &pos_x, &pos_y); stbtt_GetGlyphBox(&font->face, glyph_index, &x1, &y1, &x2, &y2); stbtt_GetGlyphHMetrics(&font->face, glyph_index, &ad, &sb); alloc->u1 = index->sheet_pwf * pos_x; alloc->v1 = index->sheet_phf * pos_y; alloc->u2 = index->sheet_pwf * pos_x + index->sheet_pwf * (w); alloc->v2 = index->sheet_phf * pos_y + index->sheet_phf * (h); alloc->wf = index->sheet_pwf * w; alloc->hf = index->sheet_phf * h; alloc->risei = y2 * font->scale; alloc->rise = index->ts->shgran * alloc->risei; alloc->cw = w; alloc->ch = h; alloc->adv = lrintf(font->scale * ad); alloc->advf = index->ts->swgran * alloc->adv; skipf = font->scale * sb; alloc->skip = skipf; alloc->skipf = index->ts->swgran * skipf; alloc->glyph = glyph; alloc->tex_cache = index; renderUpdateTilesheet(index->ts, pos_x, pos_y, data, w, h); stbtt_FreeBitmap(data, NULL); return alloc; }
JNIEXPORT void JNICALL Java_com_badlogic_gdx_graphics_g2d_stbtt_StbTrueType_getGlyphHMetrics(JNIEnv* env, jclass clazz, jlong info, jint glyphIndex, jintArray obj_metrics) { int* metrics = (int*)env->GetPrimitiveArrayCritical(obj_metrics, 0); //@line:90 int advanceWidth = 0; int leftSideBearing = 0; stbtt_GetGlyphHMetrics((stbtt_fontinfo*)info, glyphIndex, &advanceWidth, &leftSideBearing); metrics[0] = advanceWidth; metrics[1] = leftSideBearing; env->ReleasePrimitiveArrayCritical(obj_metrics, metrics, 0); }
static uint32_t font_renderer_stb_unicode_update_atlas( stb_unicode_font_renderer_t *self, uint32_t charcode) { int advance_width, left_side_bearing; int id, glyph_index, offset_x, offset_y; struct font_glyph *glyph = NULL; uint8_t *dst = NULL; int x0 = 0; int y1 = 0; if(charcode > 0xFFFF) return 0; if(self->uc_to_id[charcode]) return self->uc_to_id[charcode]; id = font_renderer_stb_unicode_get_slot(self); self->id_to_uc[id] = charcode; self->uc_to_id[charcode] = id; self->atlas.dirty = true; glyph = &self->glyphs[id]; glyph_index = stbtt_FindGlyphIndex(&self->info, charcode); offset_x = (id % 16) * self->max_glyph_width; offset_y = (id / 16) * self->max_glyph_height; dst = self->atlas.buffer + offset_x + offset_y * self->atlas.width; stbtt_MakeGlyphBitmap(&self->info, dst, self->max_glyph_width, self->max_glyph_height, self->atlas.width, self->scale_factor, self->scale_factor, glyph_index); stbtt_GetGlyphHMetrics(&self->info, glyph_index, &advance_width, &left_side_bearing); stbtt_GetGlyphBox(&self->info, glyph_index, &x0, NULL, NULL, &y1); glyph->advance_x = advance_width * self->scale_factor; glyph->atlas_offset_x = offset_x; glyph->atlas_offset_y = offset_y; glyph->draw_offset_x = x0 * self->scale_factor; glyph->draw_offset_y = - y1 * self->scale_factor; glyph->width = self->max_glyph_width; glyph->height = self->max_glyph_height; return id; }
static float font_width_imp(struct font *font, float scale, char *str) { int ucs, gid; int advance, kern; float w = 0.0; int left = 0; while (*str) { str += chartorune(&ucs, str); gid = stbtt_FindGlyphIndex(&font->info, ucs); stbtt_GetGlyphHMetrics(&font->info, gid, &advance, NULL); kern = stbtt_GetGlyphKernAdvance(&font->info, left, gid); w += advance * scale; w += kern * scale; left = gid; } return w; }
static struct glyph *lookup_glyph(struct font *font, float scale, int gid, int subx, int suby) { struct key key; unsigned int pos; unsigned char *data; float shift_x, shift_y; int w, h, x, y; int advance, lsb; /* Look it up in the table */ memset(&key, 0, sizeof key); key.font = font; key.size = scale * 10000; key.gid = gid; key.subx = subx; key.suby = suby; pos = lookup_table(&key); if (table[pos].key.font) return &table[pos].glyph; /* Render the bitmap */ shift_x = (float)subx / XPRECISION; shift_y = (float)suby / YPRECISION; stbtt_GetGlyphHMetrics(&font->info, gid, &advance, &lsb); data = stbtt_GetGlyphBitmapSubpixel(&font->info, scale, scale, shift_x, shift_y, gid, &w, &h, &x, &y); /* Find an empty slot in the texture */ if (table_load == (MAXGLYPHS * 3) / 4) { puts("glyph cache table full, clearing cache"); clear_glyph_cache(); pos = lookup_table(&key); } if (h + PADDING > CACHESIZE || w + PADDING > CACHESIZE) { warn("error: rendered glyph exceeds cache dimensions"); exit(1); } if (cache_row_x + w + PADDING > CACHESIZE) { cache_row_y += cache_row_h + PADDING; cache_row_x = PADDING; cache_row_h = 0; } if (cache_row_y + h + PADDING > CACHESIZE) { puts("glyph cache texture full, clearing cache"); clear_glyph_cache(); pos = lookup_table(&key); } /* Copy the bitmap into our texture */ memcpy(&table[pos].key, &key, sizeof(struct key)); table[pos].glyph.w = w; table[pos].glyph.h = h; table[pos].glyph.x = x; table[pos].glyph.y = y; table[pos].glyph.s = cache_row_x; table[pos].glyph.t = cache_row_y; table[pos].glyph.advance = advance * scale; table_load ++; if (data && w && h) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ROW_LENGTH, w); glTexSubImage2D(GL_TEXTURE_2D, 0, cache_row_x, cache_row_y, w, h, GL_RED, GL_UNSIGNED_BYTE, data); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } free(data); cache_row_x += w + PADDING; if (cache_row_h < h + PADDING) cache_row_h = h + PADDING; return &table[pos].glyph; }
stash::sth_glyph* stash::sth_font::get_glyph(unsigned int codepoint, short isize) { // Find code point and size. std::pair<unsigned int,int> key(codepoint, isize); if (glyphs.find( key ) != glyphs.end() ) return &glyphs.find( key )->second; // Could not find glyph, create it. int advance,lsb,x0,y0,x1,y1; int g = stbtt_FindGlyphIndex(&font, codepoint); float scale = stbtt_ScaleForPixelHeight(&font, isize/10.0f); stbtt_GetGlyphHMetrics(&font, g, &advance, &lsb); stbtt_GetGlyphBitmapBox(&font, g, scale,scale, &x0,&y0,&x1,&y1); int gw = x1-x0; int gh = y1-y0; // Find row where the glyph can be fit (vertically first, then horizontally) sth_row* br = 0; int rh = (gh+7) & ~7; for (size_t i = 0; i < rows->size() && !br; ++i) { if (rows->at(i).h == rh && rows->at(i).x+gw+1 <= tw) br = &rows->at(i); } // If no row found, add new. if (br == NULL) { short py = 0; // Check that there is enough space. if (rows->size()) { py = rows->back().y + rows->back().h+1; if (py+rh > th) return 0; } // Init and add row rows->push_back( sth_row(0,py,rh) ); br = &rows->back(); } // Init glyph. sth_glyph glyph; glyph.codepoint = codepoint; glyph.size = isize; glyph.x0 = br->x; glyph.y0 = br->y; glyph.x1 = glyph.x0+gw; glyph.y1 = glyph.y0+gh; glyph.xadv = scale * advance; glyph.xoff = (float)x0; glyph.yoff = (float)y0; // glyphs[ key ] = glyphs[ key ]; glyphs[ key ] = glyph; // Advance row location. br->x += gw+1; // Rasterize std::vector< unsigned char > bmp(gw*gh); if( bmp.size() ) { stbtt_MakeGlyphBitmap(&font, &bmp[0], gw,gh,gw, scale,scale, g); // Update texture glBindTexture(GL_TEXTURE_2D, tex); glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexSubImage2D(GL_TEXTURE_2D, 0, glyph.x0,glyph.y0, gw,gh, GL_ALPHA,GL_UNSIGNED_BYTE,&bmp[0]); } return &glyphs[ key ]; }
float Face::advance(int index, float scale) const { int advance; stbtt_GetGlyphHMetrics(m_info, index, &advance, nullptr); return advance * scale; }