void TextureFont::MeasureString(const char *str, float &w, float &h) { w = h = 0.0f; float line_width = 0.0f; int i = 0; while (str[i]) { if (str[i] == '\n') { if (line_width > w) w = line_width; line_width = 0.0f; h += GetHeight(); i++; } else { Uint32 chr; int n = utf8_decode_char(&chr, &str[i]); assert(n); i += n; const glfglyph_t &glyph = m_glyphs[chr]; line_width += glyph.advx; if (str[i]) { Uint32 chr2; n = utf8_decode_char(&chr2, &str[i]); assert(n); FT_UInt a = FT_Get_Char_Index(m_face, chr); FT_UInt b = FT_Get_Char_Index(m_face, chr2); FT_Vector kern; FT_Get_Kerning(m_face, a, b, FT_KERNING_UNFITTED, &kern); line_width += float(kern.x) / 64.0; } } } if (line_width > w) w = line_width; h += GetHeight() + GetDescender(); }
void CglFont::glPrintTable(float x, float y, float s, const int options, const std::string& text) { std::vector<std::string> coltext; coltext.push_back(""); std::vector<SColor> colColor; SColor defaultcolor(0,0,0); defaultcolor[0] = ColorCodeIndicator; for (int i = 0; i < 3; ++i) defaultcolor[i+1] = (unsigned char)(textColor[i] * 255.0f); colColor.push_back(defaultcolor); SColor curcolor(defaultcolor); int col = 0; int row = 0; for (int pos = 0; pos < text.length(); pos++) { const unsigned char& c = text[pos]; switch(c) { // inline colorcodes case ColorCodeIndicator: for (int i = 0; i < 4 && pos < text.length(); ++i, ++pos) { coltext[col] += text[pos]; curcolor[i] = text[pos]; } colColor[col] = curcolor; --pos; break; // column separator is `\t`==`horizontal tab` case '\t': ++col; if (col >= coltext.size()) { coltext.push_back(""); for(int i = 0; i < row; ++i) coltext[col] += 0x0a; colColor.push_back(defaultcolor); } if (colColor[col] != curcolor) { for(int i = 0; i < 4; ++i) coltext[col] += curcolor[i]; colColor[col] = curcolor; } break; // newline case 0x0d: // CR+LF if (pos+1 < text.length() && text[pos + 1] == 0x0a) pos++; case 0x0a: // LF for (int i = 0; i < coltext.size(); ++i) coltext[i] += 0x0a; if (colColor[0] != curcolor) { for(int i = 0; i < 4; ++i) coltext[0] += curcolor[i]; colColor[0] = curcolor; } col = 0; ++row; break; // printable char default: coltext[col] += c; } } float totalWidth = 0.0f; float maxHeight = 0.0f; float minDescender = 0.0f; std::vector<float> colWidths(coltext.size(), 0.0f); for (int i = 0; i < coltext.size(); ++i) { float colwidth = GetTextWidth(coltext[i]); colWidths[i] = colwidth; totalWidth += colwidth; float textDescender; float textHeight = GetTextHeight(coltext[i], &textDescender); if (textHeight > maxHeight) maxHeight = textHeight; if (textDescender < minDescender) minDescender = textDescender; } // s := scale or absolute size? float ss = s; if (options & FONT_SCALE) { ss *= fontSize; } float sizeX = ss, sizeY = ss; // render in normalized coords (0..1) instead of screencoords (0..~1024) if (options & FONT_NORM) { sizeX *= globalRendering->pixelX; sizeY *= globalRendering->pixelY; } // horizontal alignment (FONT_LEFT is default) if (options & FONT_CENTER) { x -= sizeX * 0.5f * totalWidth; } else if (options & FONT_RIGHT) { x -= sizeX * totalWidth; } // vertical alignment if (options & FONT_BASELINE) { // nothing } else if (options & FONT_DESCENDER) { y -= sizeY * GetDescender(); } else if (options & FONT_VCENTER) { y -= sizeY * 0.5f * maxHeight; y -= sizeY * 0.5f * minDescender; } else if (options & FONT_TOP) { y -= sizeY * maxHeight; } else if (options & FONT_ASCENDER) { y -= sizeY * GetDescender(); y -= sizeY; } else if (options & FONT_BOTTOM) { y -= sizeY * minDescender; } for (int i = 0; i < coltext.size(); ++i) { glPrint(x, y, s, (options | FONT_BASELINE) & ~(FONT_RIGHT | FONT_CENTER), coltext[i]); x += sizeX * colWidths[i]; } }
void CglFont::glPrint(float x, float y, float s, const int options, const std::string& text) { // s := scale or absolute size? if (options & FONT_SCALE) { s *= fontSize; } float sizeX = s, sizeY = s; // render in normalized coords (0..1) instead of screencoords (0..~1024) if (options & FONT_NORM) { sizeX *= globalRendering->pixelX; sizeY *= globalRendering->pixelY; } // horizontal alignment (FONT_LEFT is default) if (options & FONT_CENTER) { x -= sizeX * 0.5f * GetTextWidth(text); } else if (options & FONT_RIGHT) { x -= sizeX * GetTextWidth(text); } // vertical alignment y += sizeY * GetDescender(); // move to baseline (note: descender is negative) if (options & FONT_BASELINE) { // nothing } else if (options & FONT_DESCENDER) { y -= sizeY * GetDescender(); } else if (options & FONT_VCENTER) { float textDescender; y -= sizeY * 0.5f * GetTextHeight(text,&textDescender); y -= sizeY * 0.5f * textDescender; } else if (options & FONT_TOP) { y -= sizeY * GetTextHeight(text); } else if (options & FONT_ASCENDER) { y -= sizeY * GetDescender(); y -= sizeY; } else if (options & FONT_BOTTOM) { float textDescender; GetTextHeight(text,&textDescender); y -= sizeY * textDescender; } if (options & FONT_NEAREST) { x = (int)x; y = (int)y; } // backup text & outline colors (also ::ColorResetIndicator will reset to those) baseTextColor = textColor; baseOutlineColor = outlineColor; // immediate mode? const bool immediate = !inBeginEnd; if (immediate) { Begin(!(options & (FONT_OUTLINE | FONT_SHADOW))); } // select correct decoration RenderString function if (options & FONT_OUTLINE) { RenderStringOutlined(x, y, sizeX, sizeY, text); } else if (options & FONT_SHADOW) { RenderStringShadow(x, y, sizeX, sizeY, text); } else { RenderString(x, y, sizeX, sizeY, text); } // immediate mode? if (immediate) { End(); } // reset text & outline colors (if changed via in text colorcodes) SetColors(&baseTextColor,&baseOutlineColor); }