void DynamicFontData::set_font_data(const DVector<uint8_t>& p_font) { //clear caches and stuff ERR_FAIL_COND(font_data.size()) ; font_data=p_font; lock(); if (valid) { stbtt_GetFontVMetrics(&info, &ascent, &descent, &linegap); descent=-descent + linegap; for(int i=32;i<1024;i++) { for(int j=32;j<1024;j++) { int kern = stbtt_GetCodepointKernAdvance(&info, i,j); if (kern!=0) { KerningPairKey kpk; kpk.A=i; kpk.B=j; kerning_map[kpk]=kern; } } } } unlock(); //clear existing stuff ERR_FAIL_COND(!valid); }
int __stdcall get_length(char *text, char *buffer, int height, int max_len) { stbtt_fontinfo font; int i,j,ascent,baseline,ch,xpos=0; float scale=0; baseline=10; if (buffer==-1) {stbtt_InitFont(&font, pdf_font_DroidSans,stbtt_GetFontOffsetForIndex(pdf_font_DroidSans,0) );} else {stbtt_InitFont(&font, buffer,stbtt_GetFontOffsetForIndex(buffer,0) );kol_board_puts("Font loaded..\n");} //kol_board_puts("Engine init..\n"); //kol_board_puti(&screen); scale = stbtt_ScaleForPixelHeight(&font, height*3/4); while (dos2utf(text[ch])) { // kol_board_puts("new symbol...\n"); int advance,lsb; stbtt_GetCodepointHMetrics(&font, dos2utf(text[ch]), &advance, &lsb); xpos += (advance * scale); if ((int)xpos>max_len) return ch; if (text[ch+1]) xpos += scale*stbtt_GetCodepointKernAdvance(&font, dos2utf(text[ch]),dos2utf(text[ch+1])); ++ch; } return ch; }
float TruetypeFont::kerningOffset(uint32_t previousChar, uint32_t currentChar) { float result = 0.0f; if(_fontinfo->kern) { result = stbtt_GetCodepointKernAdvance(_fontinfo, previousChar, currentChar); result *= _vscale; } return result; }
JNIEXPORT jint JNICALL Java_com_badlogic_gdx_graphics_g2d_stbtt_StbTrueType_getCodepointKernAdvance(JNIEnv* env, jclass clazz, jlong info, jint char1, jint char2) { //@line:75 return stbtt_GetCodepointKernAdvance((stbtt_fontinfo*)info, char1, char2); }
void Font::measureText(const std::wstring str, int& width, int& height, int max_width) { if(!isLoaded()) { return NULL; } Image char_render; std::vector<unsigned char> char_raster; int bx, by, bw, bh; int ascent, descent, lineGap; int sx = 0, sy = 0; stbtt_GetFontVMetrics(&m_info, &ascent, &descent, &lineGap); ascent *= m_scale; descent *= m_scale; lineGap *= m_scale; width = 0; height = 0; for(int i = 0; i < str.length(); i++) { if(str[i] == L'\n') { sy += ascent - descent + lineGap; sx = 0; continue; } stbtt_GetCodepointBitmapBox(&m_info, str[i], m_scale, m_scale, &bx, &by, &bw, &bh); int cwidth = bw - bx; int cheight = bh - by; int oy = ascent + by; if(max_width > 0 && sx + cwidth > max_width) { sy += ascent - descent + lineGap; sx = 0; } int advance; stbtt_GetCodepointHMetrics(&m_info, str[i], &advance, 0); if(sy + oy + cheight > height) { height = sy + oy + cheight; } if(sx + cwidth > width) { width = sx + cwidth; } sx += advance * m_scale; int kerning = stbtt_GetCodepointKernAdvance(&m_info, str[i], str[i + 1]); sx += kerning * m_scale; } }
int __stdcall picture(char *text, char *buffer, char *screen1, int width, int height) { //unsigned char *screen; //screen=zmalloc(20*78); //kol_board_puts(screen); //kol_board_puts("It was text\n"); stbtt_fontinfo font; int i,j,ascent,baseline,descent,ch=0; float scale, xpos=0; //baseline=10; kol_board_puts("Font address:\n"); //kol_board_puti(buffer); if (buffer==-1) {stbtt_InitFont(&font, pdf_font_DroidSans,stbtt_GetFontOffsetForIndex(pdf_font_DroidSans,0) );kol_board_puts("default font\n");} else {stbtt_InitFont(&font, buffer,stbtt_GetFontOffsetForIndex(buffer,0) );kol_board_puts("Font loaded..\n");} //kol_board_puti(&screen); scale = stbtt_ScaleForPixelHeight(&font, height*3/4); //stbtt_GetFontVMetrics(&font, &ascent,0,0); stbtt_GetFontVMetrics(&font, &ascent,&descent,0); //lev //baseline = (int) (ascent*scale); baseline = (int) ((ascent-descent)*scale); //lev //kol_board_puts("Text render:\n"); while (dos2utf(text[ch])) { //kol_board_puts("new symbol...\n"); int advance,lsb,x0,y0,x1,y1; //float x_shift = xpos - (float) i_floor(xpos); // kol_board_puts("floor called!\n"); stbtt_GetCodepointHMetrics(&font, dos2utf(text[ch]), &advance, &lsb); stbtt_GetCodepointBitmapBoxSubpixel(&font, dos2utf(text[ch]), scale,scale,0,0, &x0,&y0,&x1,&y1); //10= y0, 20=y1-y0 or so stbtt_MakeCodepointBitmapSubpixel(&font, &screen1[(baseline + y0)*width+ (int)xpos + x0], x1-x0,y1-y0, width, scale,scale,0,0, dos2utf(text[ch])); // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong // because this API is really for baking character bitmaps into textures. if you want to do this, // you need to render the bitmap to a temp buffer, then\n\t"alpha blend" that into the working buffer xpos += (advance * scale); if (text[ch+1]) xpos += scale*stbtt_GetCodepointKernAdvance(&font, dos2utf(text[ch]),dos2utf(text[ch+1])); ++ch; } //zmemcpy(screen1,bitmap,20*20); //kol_board_puts("finished...\n"); return 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); } } }
void Font::drawStringUnicode(int x, int y, const std::wstring& str, Color color, bool top_screen, bool side) { if(!isLoaded()) { return; } Image char_render; std::vector<unsigned char> char_raster; int bx, by, bw, bh; int ascent, descent, lineGap; int sx = 0, sy = 0; stbtt_GetFontVMetrics(&m_info, &ascent, &descent, &lineGap); ascent *= m_scale; descent *= m_scale; for (unsigned int i = 0; i < str.length(); i++) { if(str[i + 1] == L'\n') { sy += lineGap * m_scale; sx = 0; continue; } stbtt_GetCodepointBitmapBox(&m_info, str[i], m_scale, m_scale, &bx, &by, &bw, &bh); int width = bw - bx; int height = bh - by; int oy = ascent + by; char_raster.resize(width * height); stbtt_MakeCodepointBitmap(&m_info, &char_raster[0], width, height, width, m_scale, m_scale, str[i]); char_render.create(width, height, Color(0, 0, 0, 0)); for (int ix = 0; ix < width; ix++) { for (int iy = 0; iy < height; iy++) { if (char_raster[ix + iy * width] != 0) char_render.putPixel(ix, iy, Color(color.r, color.g, color.b, char_raster[ix + iy * width])); } } char_render.draw(sx + x, sy + y + oy, top_screen, side); int advance; stbtt_GetCodepointHMetrics(&m_info, str[i], &advance, 0); sx += advance * m_scale; int kerning = stbtt_GetCodepointKernAdvance(&m_info, str[i], str[i + 1]); sx += kerning * m_scale; } }
void TruetypeFont::Render(const std::string &In, const Vec2 &Position, const Mat4 &Transform) { const char* Text = In.c_str(); int Line = 0; glm::vec3 vOffs(Position.x, Position.y + scale, 0); if (!IsValid) return; UpdateWindowScale(); SetBlendingMode(BLEND_ALPHA); SetShaderParameters(false, false, false, false, false, true); WindowFrame.SetUniform(U_COLOR, Red, Green, Blue, Alpha); SetPrimitiveQuadVBO(); try { utf8::iterator<const char*> it(Text, Text, Text + In.length()); utf8::iterator<const char*> itend(Text + In.length(), Text, Text + In.length()); for (; it != itend; ++it) { CheckCodepoint(*it); // Force a regeneration of this if necessary codepdata &cp = GetTexFromCodepoint(*it); unsigned char* tx = cp.tex; glm::vec3 trans = vOffs + glm::vec3(cp.xofs, cp.yofs, 0); glm::mat4 dx; if (*it == 10) // utf-32 line feed { Line++; vOffs.x = Position.x; vOffs.y = Position.y + scale * (Line + 1); continue; } dx = Transform * glm::translate(Mat4(), trans) * glm::scale(Mat4(), glm::vec3(cp.w, cp.h, 1)); // do the actual draw? if (cp.gltx == 0) { glGenTextures(1, &cp.gltx); glBindTexture(GL_TEXTURE_2D, cp.gltx); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, cp.tw, cp.th, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tx); } else glBindTexture(GL_TEXTURE_2D, cp.gltx); WindowFrame.SetUniform(U_MVP, &(dx[0][0])); DoQuadDraw(); utf8::iterator<const char*> next = it; next++; if (next != itend) { float aW = stbtt_GetCodepointKernAdvance(info.get(), *it, *next); int bW; stbtt_GetCodepointHMetrics(info.get(), *it, &bW, NULL); vOffs.x += aW * virtualscale + bW * virtualscale; } } } #ifndef NDEBUG catch (utf8::exception &ex) { Utility::DebugBreak(); Log::Logf("Invalid UTF-8 string %s was passed. Error type: %s\n", ex.what()); } #else catch (...) { // nothing } #endif FinalizeDraw(); Image::ForceRebind(); }
int FontRenderer::getKerning(const fm::Uint32 &leftCodePoint,const fm::Uint32 &rightCodePoint) const { if (!m_fileContent) return 0; return stbtt_ScaleForMappingEmToPixels((stbtt_fontinfo*)m_stbFontInfo, m_currentSize) * stbtt_GetCodepointKernAdvance((stbtt_fontinfo*)m_stbFontInfo, leftCodePoint,rightCodePoint); }
void Text::setText(const char* text) { int length = strlen(text); if(length > 255) length = 255; memset(pTextBuffer, 0x00, 256); memcpy(pTextBuffer, text, length); const char* p; int width=0,height=0; /* calculate font scaling */ LOCK_ACQUIRE(gFtLock); //float scale = stbtt_ScaleForPixelHeight(gFontInfo, pPixelSize); float scale = stbtt_ScaleForMappingEmToPixels(gFontInfo, pPixelSize); int ascent, descent, lineGap; stbtt_GetFontVMetrics(gFontInfo, &ascent, &descent, &lineGap); ascent *= scale; descent *= scale; height = ascent; // calculate bitmap size for (p = pTextBuffer; *p; p++) { /* how wide is this character */ int ax; stbtt_GetCodepointHMetrics(gFontInfo, p[0], &ax, 0); width += ax * scale; /* add kerning */ int kern; kern = stbtt_GetCodepointKernAdvance(gFontInfo, p[0], p[1]); width += kern * scale; } //check if old bitmap exists, and delete it uint8_t* oldBitmap = pBitmap; pBitmap = (uint8_t*)malloc(width*height); if(oldBitmap) { free(oldBitmap); } memset(pBitmap,0,width*height); pBitmapWidth = width; pBitmapHeight = height; setSizeN( 2.f*((float)pBitmapWidth)/GetCore()->screen_width, 2.f*((float)pBitmapHeight)/GetCore()->screen_width ); int x=0,y=0; // render text to buffer for (p = pTextBuffer; *p; p++) { /* get bounding box for character (may be offset to account for chars that dip above or below the line */ int c_x1, c_y1, c_x2, c_y2; stbtt_GetCodepointBitmapBox(gFontInfo, p[0], scale, scale, &c_x1, &c_y1, &c_x2, &c_y2); /* compute y (different characters have different heights */ y = ascent + c_y1; /* render character (stride and offset is important here) */ int byteOffset = x + (y * width); stbtt_MakeCodepointBitmap(gFontInfo, pBitmap + byteOffset, c_x2 - c_x1, c_y2 - c_y1, width, scale, scale, p[0]); /* how wide is this character */ int ax; stbtt_GetCodepointHMetrics(gFontInfo, p[0], &ax, 0); x += ax * scale; /* add kerning */ int kern; kern = stbtt_GetCodepointKernAdvance(gFontInfo, p[0], p[1]); x += kern * scale; } LOCK_RELEASE(gFtLock); updateBitmap = true; }
Bytes& StbFontRenderer::RenderText( const FontPtr& data, const FontProperties& properties, cstring text, Bytes& output, Size& imageSize) { using irect = rect<int>; auto stb_data = &data->info; auto scale = properties.scale; Bytes stringData = Bytes::CreateString(text); szptr bit_w = 0; int x = 0; /* We use this to find kerning character */ auto shadowChar = stringData.begin(); for(auto c : stringData) { irect bbox = {}; stbtt_GetCodepointBitmapBox( stb_data, c, scale, scale, &bbox.x, &bbox.y, &bbox.w, &bbox.h); int y = properties.ascent + bbox.y, ax = 0, kern = 0; stbtt_GetCodepointHMetrics(stb_data, c, &ax, nullptr); kern = stbtt_GetCodepointKernAdvance(stb_data, c, *shadowChar); x += scale * (ax + kern); imageSize.w = CMath::max<u32>(imageSize.w, x + (bbox.w - bbox.x)); imageSize.h = CMath::max<u32>(imageSize.h, y + (bbox.h - bbox.y)); } bit_w = C_FCAST<szptr>(imageSize.w); output = Bytes::Alloc(imageSize.area()); shadowChar = stringData.begin(); x = 0; for(auto c : stringData) { ++shadowChar; irect bbox = {}; stbtt_GetCodepointBitmapBox( stb_data, c, scale, scale, &bbox.x, &bbox.y, &bbox.w, &bbox.h); int y = properties.ascent + bbox.y, ax = 0, kern = 0; szptr offset = C_FCAST<szptr>(x + y * bit_w); stbtt_MakeCodepointBitmap( stb_data, &output[offset], (bbox.w - bbox.x), (bbox.h - bbox.y), bit_w, scale, scale, c); stbtt_GetCodepointHMetrics(stb_data, c, &ax, nullptr); kern = stbtt_GetCodepointKernAdvance(stb_data, c, *shadowChar); x += scale * (ax + kern); } return output; }