/** * Word wrap to width */ void FontEngine::render(string text, int x, int y, int justify, SDL_Surface *target, int width, int color) { cursor_y = y; string segment; string fulltext; string builder = ""; string builder_prev = ""; char space = 32; fulltext = text + " "; segment = eatFirstString(fulltext, space); while(segment != "" || fulltext.length() > 0) { // don't exit early on double spaces builder = builder + segment; if (calc_length(builder) > width) { render(builder_prev, x, cursor_y, justify, target, color); cursor_y += getLineHeight(); builder_prev = ""; builder = segment + " "; } else { builder = builder + " "; builder_prev = builder; } segment = eatFirstString(fulltext, space); } render(builder, x, cursor_y, justify, target, color); cursor_y += getLineHeight(); }
/** * Using the given wrap width, calculate the width and height necessary to display this text */ Point FontEngine::calc_size(string text_with_newlines, int width) { char newline = 10; string text = text_with_newlines; // if this contains newlines, recurse int check_newline = text.find_first_of(newline); if (check_newline > -1) { Point p1 = calc_size(text.substr(0, check_newline), width); Point p2 = calc_size(text.substr(check_newline+1, text.length()), width); Point p3; if (p1.x > p2.x) p3.x = p1.x; else p3.x = p2.x; p3.y = p1.y + p2.y; return p3; } int height = 0; int max_width = 0; string segment; string fulltext; string builder = ""; string builder_prev = ""; char space = 32; fulltext = text + " "; segment = eatFirstString(fulltext, space); while(segment != "" || fulltext.length() > 0) { // don't exit early on double spaces builder = builder + segment; if (calc_length(builder) > width) { height = height + getLineHeight(); if (calc_length(builder_prev) > max_width) max_width = calc_length(builder_prev); builder_prev = ""; builder = segment + " "; } else { builder = builder + " "; builder_prev = builder; } segment = eatFirstString(fulltext, space); } height = height + getLineHeight(); builder = trim(builder, ' '); //removes whitespace that shouldn't be included in the size if (calc_length(builder) > max_width) max_width = calc_length(builder); Point size; size.x = max_width; size.y = height; return size; }
//----------------------------------------------------------- ofTexture ofTrueTypeFont::getStringTexture(const std::string& str, bool vflip) const{ string str_valid; utf8::replace_invalid(str.begin(),str.end(),back_inserter(str_valid)); vector<glyph> glyphs; vector<ofVec2f> glyphPositions; utf8::iterator<const char*> it(&str_valid.front(), &str_valid.front(), (&str_valid.back())+1); utf8::iterator<const char*> end((&str_valid.back())+1, &str_valid.front(), (&str_valid.back())+1); int x = 0; int y = 0; long height = 0; uint32_t prevC = 0; while(it != end){ try{ auto c = *it; if (c == '\n') { y += lineHeight; x = 0 ; //reset X Pos back to zero prevC = 0; } else { glyphs.push_back(loadGlyph(c)); if(prevC>0){ x += getKerning(c,prevC); }else if(settings.direction == ofTtfSettings::RightToLeft){ x += glyphs.back().props.width; } glyphPositions.emplace_back(static_cast<float>(x), static_cast<float>(y)); x += glyphs.back().props.advance * letterSpacing; height = max(height, glyphs.back().props.ymax + y + long(getLineHeight())); } ++it; prevC = c; }catch(...){ break; } } ofTexture tex; ofPixels totalPixels; totalPixels.allocate(x, height, OF_PIXELS_GRAY_ALPHA); //-------------------------------- clear data: totalPixels.set(0,255); // every luminance pixel = 255 totalPixels.set(1,0); size_t i = 0; for(auto & g: glyphs){ if(settings.direction == ofTtfSettings::LeftToRight){ g.pixels.blendInto(totalPixels, glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() ); }else{ g.pixels.blendInto(totalPixels, x-glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() ); } i++; if(i==glyphPositions.size()){ break; } } tex.allocate(totalPixels); return tex; }
void IFont::renderTextLinesCenter(SDL_Surface * surface, const std::vector<std::string> & data, const SDL_Color & color, const Point & pos) const { Point currPos = pos; currPos.y -= data.size() * getLineHeight()/2; for(const std::string & line : data) { renderTextCenter(surface, line, color, currPos); currPos.y += getLineHeight(); } }
Math::Rectangle<int> Font::computeRectangle(const UTF8String & text) const { UCodePoint codePoint; Math::Rectangle<int> rectangle(0, this -> getLineHeight(), 0, 0); float currentPosX = 0.0f; for ( auto it = text.getBegin(); text.iterate(&it, &codePoint); ) { if ( codePoint == '\n' ) { rectangle.setTop(rectangle.getTop() + getLineHeight()); rectangle.setRight(Math::max<int>(rectangle.getRight(), currentPosX)); currentPosX = 0; } else if (codePoint == ' '){ currentPosX += getWordSpace(); } else { const FreeTypeChar * c = this -> operator [](codePoint); if ( c ) { rectangle.setBottom(Math::min<int>(rectangle.getBottom(), -c -> getHoriOffsetY())); currentPosX += c -> getHoriAdvance(); } } } rectangle.setRight(Math::max<int>(rectangle.getRight(), currentPosX)); return rectangle; }
QRect KTextEditorHelpers::getItemBoundingRect(const KTextEditor::View* view, const KTextEditor::Range& itemRange) { QPoint startPoint = view->mapToGlobal(view->cursorToCoordinate(itemRange.start())); QPoint endPoint = view->mapToGlobal(view->cursorToCoordinate(itemRange.end())); endPoint.ry() += getLineHeight(view, itemRange.start().line()); return QRect(startPoint, endPoint); }
Vec2 Text::measureString(const std::string& str) { float x = 0.0f; float y = 0.0f; Uint32 currentChar; Font::Character character; for (auto& c : str) { if (c == '\t') { incrementX(x, y, _font._base * 4.0f); continue; } else if (c == '\n') { y += getLineHeight(); x = 0.0f; continue; } currentChar = Uint32(c); auto charIt = _font._characters.find(currentChar); if (charIt != _font._characters.end()) { character = charIt->second; } else { incrementX(x, y, (float)_font._base); continue; } if (_lineWidth > 0 && x + character.xadvance >= _lineWidth) { x = 0.0f; y += getLineHeight(); } x += character.xadvance; } return Vec2(x, y + getLineHeight()); }
void IFont::renderTextLinesLeft(SDL_Surface * surface, const std::vector<std::string> & data, const SDL_Color & color, const Point & pos) const { Point currPos = pos; BOOST_FOREACH(const std::string & line, data) { renderTextLeft(surface, line, color, currPos); currPos.y += getLineHeight(); }
float ofxTextAlign::getHeight(const char *str, bool single_line) { const char *ptr = str; if(*ptr=='\0') { return 0; } float ret = getLineHeight(); if(single_line) { return ret; } while(*ptr != '\0') { if(*ptr == '\n' && *(ptr+1) != '\0') { ret += getLineHeight(); } ++ptr; } return ret; }
//----------------------------------------------------------- ofVec2f ofTrueTypeFont::getFirstGlyphPosForTexture(const std::string & str, bool vflip) const { if(!str.empty()) { try { auto c = *ofUTF8Iterator(str).begin(); if (c == '\n') { return {0.f, 0.f}; } else { auto g = loadGlyph(c); if(settings.direction == ofTtfSettings::LeftToRight) { return {-float(g.props.xmin), getLineHeight() + g.props.ymin + getDescenderHeight()}; } else { return {-float(g.props.xmin), getLineHeight() + g.props.ymin + getDescenderHeight()}; } } } catch(...) { return {0.f, 0.f}; } } }
void ofxTextAlign::draw(string str, float x, float y, unsigned int flags) { const char *ptr = str.c_str(); float cursor_y = y+getOffsetY(ptr, flags, false); int line_count = getLineCount(ptr); float y_interval = line_count>1?(getDrawHeight(ptr, false)-getLineHeight())/(float)(line_count-1):0; while(*ptr != '\0') { float cursor_x = x+getOffsetX(ptr, flags, true); ptr = drawLine(ptr, cursor_x, cursor_y); cursor_y += y_interval; } }
void MacText::recalcDims() { int y = 0; _textMaxWidth = 0; for (uint i = 0; i < _textLines.size(); i++) { _textLines[i].y = y; y += getLineHeight(i) + _interLinear; _textMaxWidth = MAX(_textMaxWidth, getLineWidth(i, true)); } _textMaxHeight = y - _interLinear; }
//----------------------------------------------------------- ofTexture ofTrueTypeFont::getStringTexture(const std::string& str, bool vflip) const { vector<glyph> glyphs; vector<ofVec2f> glyphPositions; long height = 0; int width = 0; int lineWidth = 0; uint32_t prevC = 0; iterateString(str, 0, 0, vflip, [&](uint32_t c, ofVec2f pos) { try { if (c != '\n') { auto g = loadGlyph(c); glyphs.push_back(g); int x = pos.x + g.props.xmin; int y = g.props.ymax + pos.y; glyphPositions.emplace_back(x, y); lineWidth += glyphs.back().props.advance * letterSpacing; width = max(width, lineWidth); height = max(height, y + long(getLineHeight())); } else { lineWidth = 0; } } catch(...) { } }); ofTexture tex; ofPixels totalPixels; totalPixels.allocate(width, height, OF_PIXELS_GRAY_ALPHA); //-------------------------------- clear data: totalPixels.set(0,255); // every luminance pixel = 255 totalPixels.set(1,0); size_t i = 0; for(auto & g: glyphs) { if(settings.direction == ofTtfSettings::LeftToRight) { g.pixels.blendInto(totalPixels, glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() ); } else { g.pixels.blendInto(totalPixels, width-glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() ); } i++; if(i==glyphPositions.size()) { break; } } tex.allocate(totalPixels); return tex; }
void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_TEXT, getText()); APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor()); APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, getFaceCamera()); }
float ofxTextAlign::getOffsetY(const char *str, unsigned int flags, bool single_line) { unsigned int flag = flags&VERTICAL_ALIGN_MASK; if(VERTICAL_ALIGN_TOP == flag) { return getAscenderHeight(); } else if(!single_line && getLineCount(str) < 2) { float height = getLineHeight(); switch(flag) { case VERTICAL_ALIGN_MIDDLE: return getAscenderHeight()-height/2.f; case VERTICAL_ALIGN_BOTTOM: return getAscenderHeight()-height; } } else { float height = getDrawHeight(str, single_line); switch(flag) { case VERTICAL_ALIGN_MIDDLE: return getAscenderHeight()-height/2.f; case VERTICAL_ALIGN_BOTTOM: return getAscenderHeight()-height; } } return 0; }
void ofxTextBox::draw() { int lineWidth; int xOffset = 0; int yOffset = rBounds.height-((lines.size()-1)*int(getLineHeight())); // set yOffset if(vAlign == "center") { yOffset = (yOffset )/2; } else if(vAlign == "top") { yOffset = 0; } for(int i = 0; i < lines.size(); ++i) { lineWidth = ofTrueTypeFont::getStringBoundingBox(lines[i], 0, 0).width; xOffset = (rBounds.width - lineWidth); // reset. if(hAlign == "center") { xOffset = (rBounds.width - lineWidth) / 2; } else if (hAlign == "top") { xOffset = 0; } //ofTrueTypeFont::drawStringAsShapes(lines[i], rBounds.x+centerOffset, rBounds.y+((i+1)*int(getLineHeight()))); ofTrueTypeFont::drawString(lines[i], rBounds.x+xOffset, rBounds.y+yOffset+((i+1)*int(getLineHeight()))); } if(bDebug) { ofNoFill(); ofSetColor(255,0,0,127); ofRect(rBounds); ofFill(); } //OF_EXIT_APP(0); }
void Font::write(float x, float y, float z, const char *text, int count, Alignment alignment) { if (count <= 0) count = getTextLength(text); // Get first line int pos = 0; int len = findTextChar(text, pos, count, '\n'); if (len == -1) len = count; beginRender(); while (pos < count) { float cx = x; if (alignment == Alignment::CENTER) { float w = getTextWidth(&text[pos], len); cx -= w / 2; } else if (alignment == Alignment::RIGHT) { float w = getTextWidth(&text[pos], len); cx -= w; } writeInternal(cx, y, z, &text[pos], len); y -= getLineHeight(); // Get next line pos += len; int ch = getTextChar(text, pos, &pos); if (ch == '\n') { len = findTextChar(text, pos, count, '\n'); if (len == -1) len = count - pos; else len = len - pos; } } endRender(); }
void IFont::renderTextCenter(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const { Point size(getStringWidth(data), getLineHeight()); renderText(surface, data, color, pos - size / 2); }
void Text::updateCharacters() { for (auto& character : _characters) { removeChild(character.get()); } _characters.clear(); int previousChar = 0; float x = 0.0f; float y = 0.0f; Uint32 currentChar; Font::Character character; for (Uint32 i = 0; i < _str.length(); ++i) { if (_str[i] == '\t') { incrementX(x, y, _font._base * 4.0f); continue; } else if (_str[i] == '\n') { y += getLineHeight(); x = 0.0f; continue; } currentChar = Uint32(_str[i]); auto charIt = _font._characters.find(currentChar); if (charIt != _font._characters.end()) { character = charIt->second; } else { incrementX(x, y, (float)_font._base); continue; } auto& page = _font._pages[character.page]; int kerning = 0; auto kernIt = character.kernings.find(previousChar); if (kernIt != character.kernings.end()) { kerning = kernIt->second; } if (_lineWidth > 0 && x + character.xadvance >= _lineWidth) { x = 0.0f; y += getLineHeight(); } float px = x + character.xoffset; float py = y + character.yoffset; if (_useKerning) { px += kerning; } auto charSprite = std::make_shared<Sprite>(); charSprite->getTexture() = *page; charSprite->setTextureRect((float)character.x, (float)character.y, (float)character.width, (float)character.height); charSprite->setPosition(px, py); charSprite->setColor(_color); charSprite->setTag(i); addChild(charSprite); _characters.push_back(charSprite); x += character.xadvance; previousChar = currentChar; } }
void CHexWidget::paintEvent(QPaintEvent *) { QBrush white(Qt::white); QBrush black(Qt::black); QPainter painter(this); QFont font = getFont(); QFontMetrics metrics(font); painter.setBackground(white); painter.setBrush(white); painter.setFont(font); painter.drawRect(0, 0, this->width(), this->height()); painter.setBrush(black); painter.drawLine(0, getLineHeight(), this->width(), getLineHeight()); painter.drawText(10, getLineHeight() - 4, "Address"); painter.drawText(80, getLineHeight() - 4, "Data"); int y = 2*getLineHeight(); this->setMinimumHeight(y + lineToYCoord(m_currentFile.getLineCount())); painter.drawLine(75, 0, 75, this->height()); int maxWidth = 0; unsigned int lineCnt = m_currentFile.getLineCount(); if(lineCnt == 0) { maxWidth = 120; } else { for(unsigned int i=0; i<lineCnt; i++) { y = lineToYCoord(i); QString addr = m_currentFile.getLine(i).getAddressString(); painter.drawText(10, y, addr); if(m_uiCurrentLine == i) { QString lineStr = m_currentFile.getLine(i).getDataString(); int markerW = metrics.charWidth(lineStr, m_uiCurrentByte); int markerX = metrics.width(lineStr, m_uiCurrentByte); unsigned int x = 80; unsigned int h = getLineHeight(); painter.fillRect(markerX+x, y-h+2, markerW, h+2, Qt::gray); } painter.drawText(80, y, m_currentFile.getLine(i).getDataString()); if(80 + metrics.width(m_currentFile.getLine(i).getDataString()) > maxWidth) maxWidth = 80 + metrics.width(m_currentFile.getLine(i).getDataString()); } for(unsigned int i=0; i<lineCnt; i++) { y = lineToYCoord(i); QString checksum = this->m_currentFile.getLine(i).getChecksumString(); painter.drawText(maxWidth + 25, y, checksum); } } this->setMinimumWidth(maxWidth+100); painter.drawLine(maxWidth + 20, 0, maxWidth + 20, this->height()); painter.drawText(maxWidth + 25, metrics.height() + 1, "Checksum"); }
void Font::drawText(const ICommandBuffersSP& cmdBuffer, const glm::mat4& viewProjection, const glm::vec2& translate, const std::string& text, const glm::vec4& color) const { if (!cmdBuffer.get()) { return; } // const VkBuffer buffers[1] = {vertexBuffer->getBuffer()->getBuffer()}; VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(cmdBuffer->getCommandBuffer(), 0, 1, buffers, offsets); // glm::vec2 cursor = translate; const Char* lastCharacter = nullptr; for (auto c : text) { // Line break. if (c == '\n') { cursor.x = translate.x; cursor.y += getLineHeight(); lastCharacter = nullptr; continue; } auto currentCharacter = allCharacters.find((int32_t)c); if (currentCharacter == allCharacters.end()) { // Character not found. lastCharacter = nullptr; continue; } // // Advance, depending on kerning of current and last character. // if (lastCharacter) { cursor.x += lastCharacter->getKerning(currentCharacter->second.getId()); } // // Get bottom left corner of the character texture. // glm::vec2 origin = cursor; origin.y += getBase(); origin.x -= currentCharacter->second.getXoffset(); // Draw Character. glm::mat4 transformVertex = viewProjection * translateMat4(origin.x, origin.y, 0.0f); vkCmdPushConstants(cmdBuffer->getCommandBuffer(), graphicsPipeline->getLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 16, glm::value_ptr(transformVertex)); glm::mat3 translateTexCoord = translateMat3(currentCharacter->second.getX() / getScaleWidth(), (getScaleHeight() - currentCharacter->second.getY() - currentCharacter->second.getHeight()) / getScaleHeight()); glm::mat3 scaleTexCoord = scaleMat3(currentCharacter->second.getWidth() / getScaleWidth(), currentCharacter->second.getHeight() / getScaleHeight(), 1.0f); glm::mat3 transformTexCoord = translateTexCoord * scaleTexCoord; vkCmdPushConstants(cmdBuffer->getCommandBuffer(), graphicsPipeline->getLayout(), VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 16, sizeof(float) * 9, glm::value_ptr(transformTexCoord)); vkCmdPushConstants(cmdBuffer->getCommandBuffer(), graphicsPipeline->getLayout(), VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 16 + sizeof(float) * 12, sizeof(float) * 4, glm::value_ptr(color)); // Expecting triangle strip as primitive topology. vkCmdDraw(cmdBuffer->getCommandBuffer(), 4, 1, 0, 0); // // Advance, as character has been drawn. // cursor.x += currentCharacter->second.getXadvance(); lastCharacter = ¤tCharacter->second; } }
int CHexWidget::lineToYCoord(int lineNr) { QFontMetrics metrics(getFont()); int h = getLineHeight(); return (2*h + lineNr*h); }
int BaseFontTT::getLetterHeight() { return (int)getLineHeight(); }
void Window::refreshHeaderHeightAndPadding() { headerHeight_ = getLineHeight() + 6; // Padding. padding_ = Border(borderSize_ + headerHeight_, borderSize_, borderSize_, borderSize_); }
void MacText::render(int from, int to) { reallocSurface(); from = MAX<int>(0, from); to = MIN<int>(to, _textLines.size() - 1); // Clear the screen _surface->fillRect(Common::Rect(0, _textLines[from].y, _surface->w, _textLines[to].y + getLineHeight(to)), _bgcolor); for (int i = from; i <= to; i++) { int xOffset = 0; if (_textAlignment == kTextAlignRight) xOffset = _textMaxWidth - getLineWidth(i); else if (_textAlignment == kTextAlignCenter) xOffset = (_textMaxWidth / 2) - (getLineWidth(i) / 2); // TODO: _textMaxWidth, when -1, was not rendering ANY text. for (uint j = 0; j < _textLines[i].chunks.size(); j++) { if (_textLines[i].chunks[j].text.empty()) continue; _textLines[i].chunks[j].getFont()->drawString(_surface, _textLines[i].chunks[j].text, xOffset, _textLines[i].y, _maxWidth, _fgcolor); xOffset += _textLines[i].chunks[j].getFont()->getStringWidth(_textLines[i].chunks[j].text); } } for (uint i = 0; i < _textLines.size(); i++) { debugN(4, "%2d ", i); for (uint j = 0; j < _textLines[i].chunks.size(); j++) debugN(4, "[%d (%d)] \"%s\" ", _textLines[i].chunks[j].fontId, _textLines[i].chunks[j].textSlant, _textLines[i].chunks[j].text.c_str()); debug(4, "%s", ""); } }
void Font::writeBox(float x, float y, float z, float width, const char *text, int count, Alignment alignment) { if (count <= 0) count = getTextLength(text); float currWidth = 0, wordWidth; int lineS = 0, lineE = 0, wordS = 0, wordE = 0; int wordCount = 0; const char *s = " "; float spaceWidth = getTextWidth(s, 1); bool softBreak = false; beginRender(); for (; lineS < count;) { // Determine the extent of the line for (;;) { // Determine the number of characters in the word while (wordE < count && getTextChar(text, wordE) != ' ' && getTextChar(text, wordE) != '\n') // Advance the cursor to the next character getTextChar(text, wordE, &wordE); // Determine the width of the word if (wordE > wordS) { wordCount++; wordWidth = getTextWidth(&text[wordS], wordE - wordS); } else wordWidth = 0; // Does the word fit on the line? The first word is always accepted. if (wordCount == 1 || currWidth + (wordCount > 1 ? spaceWidth : 0) + wordWidth <= width) { // Increase the line extent to the end of the word lineE = wordE; currWidth += (wordCount > 1 ? spaceWidth : 0) + wordWidth; // Did we reach the end of the line? if (wordE == count || getTextChar(text, wordE) == '\n') { softBreak = false; // Skip the newline character if (wordE < count) // Advance the cursor to the next character getTextChar(text, wordE, &wordE); break; } // Skip the trailing space if (wordE < count && getTextChar(text, wordE) == ' ') // Advance the cursor to the next character getTextChar(text, wordE, &wordE); // Move to next word wordS = wordE; } else { softBreak = true; // Skip the trailing space if (wordE < count && getTextChar(text, wordE) == ' ') // Advance the cursor to the next character getTextChar(text, wordE, &wordE); break; } } // Write the line if (alignment == Alignment::JUSTIFY) { float spacing = 0; if (softBreak) { if (wordCount > 2) spacing = (width - currWidth) / (wordCount - 2); else spacing = (width - currWidth); } writeInternal(x, y, z, &text[lineS], lineE - lineS, spacing); } else { float cx = x; if (alignment == Alignment::RIGHT) cx = x + width - currWidth; else if (alignment == Alignment::CENTER) cx = x + 0.5f*(width - currWidth); writeInternal(cx, y, z, &text[lineS], lineE - lineS); } if (softBreak) { // Skip the trailing space if (lineE < count && getTextChar(text, lineE) == ' ') // Advance the cursor to the next character getTextChar(text, lineE, &lineE); // We've already counted the first word on the next line currWidth = wordWidth; wordCount = 1; } else { // Skip the line break if (lineE < count && getTextChar(text, lineE) == '\n') // Advance the cursor to the next character getTextChar(text, lineE, &lineE); currWidth = 0; wordCount = 0; } // Move to next line lineS = lineE; wordS = wordE; y -= getLineHeight(); } endRender(); }
void Font::printString(const std::string &s, float x, float y, float scale, Align align) { if (s.empty()) { return; } std::istringstream manystr; manystr.str(s); glPushMatrix(); glTranslatef(x, y, 0); glScalef(scale, scale, 1); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); std::string onestr; float cur_y = 0; while (getline(manystr, onestr)) { float cur_x = 0; switch (align) { case ALIGN_CENTER: cur_x -= getStringWidth(onestr) / 2; break; case ALIGN_RIGHT: cur_x -= getStringWidth(onestr); break; default: break; } // Print one string std::string::const_iterator i = onestr.begin(); uint32_t prev = 0; while (i != onestr.end()) { uint32_t c = get_unicode_char(i); if (unicode2glyph.find(c) != unicode2glyph.end()) { Glyph *g = unicode2glyph.find(c)->second; // shortcut //if (kerning.find(std::make_pair(prev, c)) != kerning.end()) { // cur_x += kerning[std::make_pair(prev, c)]; //} float left = cur_x + g->bearingX; float right = left + g->width; float top = cur_y + g->bearingY; float bottom = top - g->height; glTexCoord2f(g->tex_left, g->tex_top); glVertex2f(left, top); glTexCoord2f(g->tex_right, g->tex_top); glVertex2f(right, top); glTexCoord2f(g->tex_right, g->tex_bottom); glVertex2f(right, bottom); glTexCoord2f(g->tex_left, g->tex_bottom); glVertex2f(left, bottom); cur_x += g->advance; prev = c; } //i++; } // Advance down cur_y -= getLineHeight(); } glEnd(); glDisable(GL_BLEND); glPopMatrix(); }