void addGlyphsToTexture(const std::vector<char32_t>& codepoints) override { if(codepoints.empty()) { LOG_WARN("stb_impl::addGlyphsToTexture: no codepoints."); return; } int old_size = packed_char_.size(); auto ttf_buffer = reinterpret_cast<const unsigned char*>(font_data_.c_str()); if(font_size_ < 20.0f) { stbtt_PackSetOversampling(&pc_, 2, 2); } std::vector<stbtt_pack_range> ranges; char32_t last_cp = codepoints.front(); char32_t first_cp = codepoints.front(); int num_chars = 1; for(auto it = codepoints.begin() + 1; it != codepoints.end(); ++it) { char32_t cp = *it; if(cp == last_cp+1) { ++num_chars; } else { auto& packed_data = packed_char_[UnicodeRange(first_cp, first_cp+num_chars-1)]; packed_data.resize(num_chars); stbtt_pack_range range; range.num_chars_in_range = num_chars; range.chardata_for_range = packed_data.data(); range.font_size = font_size_; range.first_unicode_char_in_range = first_cp; ranges.emplace_back(range); num_chars = 1; first_cp = cp; } last_cp = cp; } auto& packed_data = packed_char_[UnicodeRange(first_cp, first_cp+num_chars-1)]; packed_data.resize(num_chars); stbtt_pack_range range; range.num_chars_in_range = num_chars; range.chardata_for_range = packed_data.data(); range.font_size = font_size_; range.first_unicode_char_in_range = first_cp; ranges.emplace_back(range); stbtt_PackFontRanges(&pc_, ttf_buffer, 0, ranges.data(), ranges.size()); font_texture_->update2D(0, 0, 0, surface_width, surface_height, surface_width, pixels_.data()); }
Array<Dynamic> pack_font_ranges(const char *filename, int font_index, Array<Dynamic> ranges) { int i; int num_ranges = ranges.__length(); int num_chars = 0; stbtt_pack_range *pr = new stbtt_pack_range[num_ranges]; for(i = 0; i < num_ranges; i++) { hx::Anon range = (hx::Anon) ranges[i]; Array<int> array_of_unicode_codepoints = range->__Field(HX_CSTRING("array_of_unicode_codepoints"), HX_PROP_NEVER); if(array_of_unicode_codepoints != null()) { pr[i].array_of_unicode_codepoints = (int*) array_of_unicode_codepoints->GetBase(); pr[i].num_chars = array_of_unicode_codepoints.__length(); } else { pr[i].first_unicode_codepoint_in_range = range->__Field(HX_CSTRING("first_unicode_codepoint_in_range"), HX_PROP_NEVER); pr[i].num_chars = range->__Field(HX_CSTRING("num_chars"), HX_PROP_NEVER); pr[i].array_of_unicode_codepoints = 0; } pr[i].font_size = range->__Field(HX_CSTRING("font_size"), HX_PROP_NEVER); num_chars += pr[i].num_chars; } stbtt_packedchar *packed_char_data = new stbtt_packedchar[num_chars]; int pdata_index = 0; for(i = 0; i < num_ranges; i++) { pr[i].chardata_for_range = packed_char_data + pdata_index; pdata_index += pr[i].num_chars; } fread(ttf_buffer, 1, 1<<25, fopen(filename, "rb")); stbtt_PackFontRanges(spc, ttf_buffer, font_index, pr, num_ranges); return to_packed_char_data(packed_char_data, num_chars); }
FontAtlas::FontAtlas(int bitmapSize, FontRangeMap &map, unsigned char *fontData) : bitmapSize(bitmapSize), fontRangeMap(std::move(map)) { ASSERT(bitmapSize > 0, "Invalid bitmap size"); UPtr<unsigned char[]> bitmap(new unsigned char[bitmapSize * bitmapSize]); stbtt_pack_context packContext; int res = stbtt_PackBegin(&packContext, bitmap.get(), bitmapSize, bitmapSize, 0, 1, nullptr); ASSERT(res, "stbtt_PackBegin failed"); std::vector<stbtt_pack_range> packRanges; for (std::pair<const FontType, FontRange> &item : fontRangeMap) { FontRange &fontRange = item.second; stbtt_pack_range packRange; fontRange.charData.resize(fontRange.numGlyphs); packRange.font_size = fontRange.fontSize; packRange.first_unicode_char_in_range = fontRange.firstGlyph; packRange.num_chars_in_range = fontRange.numGlyphs; packRange.chardata_for_range = fontRange.charData.data(); packRanges.push_back(packRange); } res = stbtt_PackFontRanges(&packContext, fontData, 0, packRanges.data(), packRanges.size()); ASSERT(res, "stbtt_PackFontRanges failed"); stbtt_PackEnd(&packContext); texture = std::make_shared<Texture>(GL_TEXTURE_2D); texture->bind(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, bitmapSize, bitmapSize, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap.get()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); texture->unbind(); }
int main(int argc, char **argv) { stbtt_fontinfo font; unsigned char *bitmap; int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 34807), s = (argc > 2 ? atoi(argv[2]) : 32); //debug(); // @TODO: why is minglui.ttc failing? fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb")); //fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/x/DroidSansMono.ttf", "rb")); { static stbtt_pack_context pc; static stbtt_packedchar cd[256]; static unsigned char atlas[1024*1024]; stbtt_PackBegin(&pc, atlas, 1024,1024,1024,1,NULL); stbtt_PackFontRange(&pc, ttf_buffer, 0, 32.0, 0, 256, cd); stbtt_PackEnd(&pc); } #if 0 stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); { stbtt_pack_context pc; stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 32, 95, pdata); stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 0xa0, 0x100-0xa0, pdata); stbtt_PackEnd(&pc); stbi_write_png("fonttest2.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); } { stbtt_pack_context pc; stbtt_pack_range pr[2]; stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); pr[0].chardata_for_range = pdata; pr[0].first_unicode_char_in_range = 32; pr[0].num_chars_in_range = 95; pr[0].font_size = 20.0f; pr[1].chardata_for_range = pdata+256; pr[1].first_unicode_char_in_range = 0xa0; pr[1].num_chars_in_range = 0x100 - 0xa0; pr[1].font_size = 20.0f; stbtt_PackSetOversampling(&pc, 2, 2); stbtt_PackFontRanges(&pc, ttf_buffer, 0, pr, 2); stbtt_PackEnd(&pc); stbi_write_png("fonttest3.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); } return 0; #endif stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, (float)s), c, &w, &h, 0,0); for (j=0; j < h; ++j) { for (i=0; i < w; ++i) putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); putchar('\n'); } return 0; }