void getBounds(Font font, const T* str, float& xmin, float& ymin, float& xmax, float& ymax) { # undef min # undef max xmin=ymin=xmax=ymax=0; if (!font) return; if ((NULL!=str) && ('\0'!=*str)) { float advance = 0; unsigned int left =FT_Get_Char_Index(font->ftFace, *str); unsigned int right = FT_Get_Char_Index(font->ftFace, *++str); if (GlyphData* glyph = getGlyphData(font, left)) { xmin = glyph->xmin; ymin = glyph->ymin; xmax = glyph->xmax; ymax = glyph->ymax; float xadvance, yadvance; kernAdvance(font, left, right, xadvance, yadvance); advance = xadvance+glyph->xadvance; } left = right; while (*str++) { right = FT_Get_Char_Index(font->ftFace, *str); if (GlyphData* glyph = getGlyphData(font, left)) { xmin = std::min(xmin, glyph->xmin+advance); ymin = std::min(ymin, glyph->ymin); xmax = std::max(xmax, glyph->xmax+advance); ymax = std::max(ymax, glyph->ymax); float xadvance, yadvance; kernAdvance(font, left, right, xadvance, yadvance); advance += xadvance+glyph->xadvance; } left = right; } xmax = std::max(xmax, advance); } }
//----------------------------------------------------------------------------// float Font::drawText(GeometryBuffer& buffer, const String& text, const Vector2f& position, const Rectf* clip_rect, const ColourRect& colours, const float space_extra, const float x_scale, const float y_scale) const { const float base_y = position.d_y + getBaseline(y_scale); Vector2f glyph_pos(position); for (size_t c = 0; c < text.length(); ++c) { const FontGlyph* glyph; if ((glyph = getGlyphData(text[c]))) // NB: assignment { const Image* const img = glyph->getImage(); glyph_pos.d_y = base_y - (img->getRenderedOffset().d_y - img->getRenderedOffset().d_y * y_scale); img->render(buffer, glyph_pos, glyph->getSize(x_scale, y_scale), clip_rect, colours); glyph_pos.d_x += glyph->getAdvance(x_scale); // apply extra spacing to space chars if (text[c] == ' ') glyph_pos.d_x += space_extra; } } return glyph_pos.d_x; }
//----------------------------------------------------------------------------// size_t Font::getCharAtPixel(const String& text, size_t start_char, float pixel, float x_scale) const { const FontGlyph* glyph; float cur_extent = 0; size_t char_count = text.length(); // handle simple cases if ((pixel <= 0) || (char_count <= start_char)) return start_char; for (size_t c = start_char; c < char_count; ++c) { glyph = getGlyphData(text[c]); if (glyph) { cur_extent += glyph->getAdvance(x_scale); if (pixel < cur_extent) return c; } } return char_count; }
float getTextHExtent(Font font, const T* str) { if (!font) return 0; float advance = 0; if ((NULL!=str) && ('\0'!=*str)) { unsigned int left =FT_Get_Char_Index(font->ftFace, *str); while (*str++) { unsigned int right = FT_Get_Char_Index(font->ftFace, *str); if (GlyphData* glyph = getGlyphData(font, left)) { float xadvance, yadvance; kernAdvance(font, left, right, xadvance, yadvance); advance += xadvance+glyph->xadvance; } left = right; } } return advance; }
int font_data::width(const std::string& text) const { typedef std::vector<std::string> linesType; linesType lines; boost::split(lines, text, boost::is_any_of("\n\r")); int maximumWidth(0); for (linesType::const_iterator line(lines.begin()), end(lines.end()); line != end; ++line) { int currentWidth(0); const char* lineBegin = line->c_str(); const char* lineEnd = lineBegin + line->length(); try { for (utf8::iterator<const char*> itr(lineBegin, lineBegin, lineEnd), itrEnd(lineEnd, lineBegin, lineEnd); itr != itrEnd; ++itr) { currentWidth += getGlyphData(*itr).width(); } } catch (const utf8::invalid_utf8& e) { LogError << "Invalid UTF8 in string \"" << *line << "(" << &e << ")\"" << std::endl; } maximumWidth = std::max(maximumWidth, currentWidth); } return maximumWidth; }
//----------------------------------------------------------------------------// float Font::getTextAdvance(const String& text, float x_scale) const { float advance = 0.0f; for (size_t c = 0; c < text.length(); ++c) { if (const FontGlyph* glyph = getGlyphData(text[c])) advance += glyph->getAdvance(x_scale); } return advance; }
void font_data::print(float x, float y, const std::string& text, float colorR, float colorG, float colorB) const { float height(h / 0.90f); typedef std::vector<std::string> linesType; linesType lines; boost::split(lines, text, boost::is_any_of("\n\r")); glColor3f(colorR, colorG, colorB); glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT); glMatrixMode(GL_MODELVIEW); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); int verticalPosition((int)y); for (linesType::const_iterator line(lines.begin()), end(lines.end()); line != end; ++line) { glPushMatrix(); glTranslatef(x, (float)verticalPosition, 0.0f); const char* lineBegin = line->c_str(); const char* lineEnd = lineBegin + line->length(); try { for (utf8::iterator<const char*> itr(lineBegin, lineBegin, lineEnd), itrEnd(lineEnd, lineBegin, lineEnd); itr != itrEnd; ++itr) { getGlyphData(*itr).render(); } } catch (const utf8::invalid_utf8& e) { LogError << "Invalid UTF8 in string \"" << *line << "(" << &e << ")\"" << std::endl; } verticalPosition += (int)height; glPopMatrix(); } glPopAttrib(); }
/************************************************************************* Draw a line of text. No formatting is applied. *************************************************************************/ void Font::drawTextLine(const String& text, const Vector3& position, const Rect& clip_rect, const ColourRect& colours, float x_scale, float y_scale) { Vector3 cur_pos(position); const FontGlyph* glyph; float base_y = position.d_y; for (size_t c = 0; c < text.length(); ++c) { glyph = getGlyphData(text[c]); if (glyph) { const Image* img = glyph->getImage(); cur_pos.d_y = base_y - (img->getOffsetY() - img->getOffsetY() * y_scale); img->draw(cur_pos, glyph->getSize(x_scale, y_scale), clip_rect, colours); cur_pos.d_x += glyph->getAdvance(x_scale); } } }
/************************************************************************* Draw a justified line of text. *************************************************************************/ void Font::drawTextLineJustified (const String& text, const Rect& draw_area, const Vector3& position, const Rect& clip_rect, const ColourRect& colours, float x_scale, float y_scale) { Vector3 cur_pos(position); const FontGlyph* glyph; float base_y = position.d_y; size_t char_count = text.length(); // Calculate the length difference between the justified text and the same text, left aligned // This space has to be shared between the space characters of the line float lost_space = getFormattedTextExtent(text, draw_area, Justified, x_scale) - getTextExtent(text, x_scale); // The number of spaces and tabs in the current line uint space_count = 0; size_t c; for (c = 0; c < char_count; ++c) if ((text[c] == ' ') || (text[c] == '\t')) ++space_count; // The width that must be added to each space character in order to transform the left aligned text in justified text float shared_lost_space = 0.0; if (space_count > 0) shared_lost_space = lost_space / (float)space_count; for (c = 0; c < char_count; ++c) { glyph = getGlyphData(text[c]); if (glyph) { const Image* img = glyph->getImage(); cur_pos.d_y = base_y - (img->getOffsetY() - img->getOffsetY() * y_scale); img->draw(cur_pos, glyph->getSize(x_scale, y_scale), clip_rect, colours); cur_pos.d_x += glyph->getAdvance(x_scale); // That's where we adjust the size of each space character if ((text[c] == ' ') || (text[c] == '\t')) cur_pos.d_x += shared_lost_space; } } }
//----------------------------------------------------------------------------// float Font::getTextExtent(const String& text, float x_scale) const { const FontGlyph* glyph; float cur_extent = 0, adv_extent = 0, width; for (size_t c = 0; c < text.length(); ++c) { glyph = getGlyphData(text[c]); if (glyph) { width = glyph->getRenderedAdvance(x_scale); if (adv_extent + width > cur_extent) cur_extent = adv_extent + width; adv_extent += glyph->getAdvance(x_scale); } } return ceguimax(adv_extent, cur_extent); }
void drawString(Font font, float x, float y, const T* str, size_t len) { if (!font) return; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE font->activeTextureID = 0; unsigned int left = FT_Get_Char_Index(font->ftFace, *str); unsigned int right; while (len--) { ++str; right = FT_Get_Char_Index(font->ftFace, *str); if (GlyphData* glyph = getGlyphData(font, left)) { float xkern, ykern; kernAdvance(font, left, right, xkern, ykern); if (font->activeTextureID != glyph->glTextureID) { glBindTexture( GL_TEXTURE_2D, (GLuint)glyph->glTextureID); font->activeTextureID = glyph->glTextureID; } float u0 = glyph->u0, v0 = glyph->v0, u1 = glyph->u1, v1 = glyph->v1; float px = x+glyph->xoffset, py = y-glyph->yoffset, w = (float)glyph->width, h = (float)glyph->height; glBegin(GL_QUADS); glTexCoord2f(u0, v0); glVertex2f(px, py); glTexCoord2f(u0, v1); glVertex2f(px, py+h); glTexCoord2f(u1, v1); glVertex2f(w+px, py+h); glTexCoord2f(u1, v0); glVertex2f(w+px, py); glEnd(); x += xkern+glyph->xadvance; y += ykern+glyph->yadvance; } left = right; } glPopAttrib(); }