//----------------------------------------------------------- ofTexture ofTrueTypeFont::getStringTexture(const std::string& str, bool vflip) const{ vector<glyph> glyphs; vector<ofVec2f> glyphPositions; int x = 0; int y = 0; long height = 0; uint32_t prevC = 0; for(auto c: ofUTF8Iterator(str)){ try{ 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())); } 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; }
//----------------------------------------------------------- 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}; } } }
vector<SplitTextBlock> ofxFontStash2::splitWords( const vector<StyledText> & blocks){ std::locale loc = std::locale(""); vector<SplitTextBlock> wordBlocks; std::string currentWord; for(int i = 0; i < blocks.size(); i++){ const StyledText & block = blocks[i]; string blockText = block.text; for(auto c: ofUTF8Iterator(blockText)){ bool isSpace = std::isspace<wchar_t>(c,loc); bool isPunct = std::ispunct<wchar_t>(c,loc); if(isSpace || isPunct){ if(currentWord.size()){ SplitTextBlock word = SplitTextBlock(BLOCK_WORD, currentWord, block.style); currentWord.clear(); wordBlocks.push_back(word); } string separatorText; utf8::append(c, back_inserter(separatorText)); SplitTextBlock separator = SplitTextBlock(isPunct?SEPARATOR:SEPARATOR_INVISIBLE, separatorText, block.style); wordBlocks.push_back(separator); }else{ utf8::append(c, back_inserter(currentWord)); } } if(currentWord.size()){ //add last word SplitTextBlock word = SplitTextBlock(BLOCK_WORD, currentWord, block.style); currentWord.clear(); wordBlocks.push_back(word); } } return wordBlocks; }
void ofTrueTypeFont::iterateString(const string & str, float x, float y, bool vFlipped, std::function<void(uint32_t, ofVec2f)> f) const { ofVec2f pos(x,y); int newLineDirection = 1; if(!vFlipped) { // this would align multiline texts to the last line when vflip is disabled //int lines = ofStringTimesInString(c,"\n"); //Y = lines*lineHeight; newLineDirection = -1; } int directionX = settings.direction == ofTtfSettings::LeftToRight?1:-1; uint32_t prevC = 0; for(auto c: ofUTF8Iterator(str)) { try { if (c == '\n') { pos.y += lineHeight*newLineDirection; pos.x = x ; //reset X Pos back to zero prevC = 0; } if (c == '\t') { pos.x += getGlyphProperties(' ').advance * letterSpacing * 4 * directionX; prevC = c; } else if(isValidGlyph(c)) { const auto & props = getGlyphProperties(c); if(prevC>0) { pos.x += getKerning(c,prevC);// * directionX; } f(c,pos); pos.x += props.advance * letterSpacing * directionX; prevC = c; } } catch(...) { break; } } }
//------------------------------------------------------------------ ofUTF8Iterator ofUTF8::end(const ofUTF8String& input) { return ofUTF8Iterator(endPtr(input),beginPtr(input),endPtr(input)); }