diff --git a/src/GPUFontAtlasLayerCombo.cpp b/src/GPUFontAtlasLayerCombo.cpp index 802ec90..8ea1f36 100644 --- a/src/GPUFontAtlasLayerCombo.cpp +++ b/src/GPUFontAtlasLayerCombo.cpp @@ -243,6 +243,7 @@ void GPUFontAtlasLayerCombo::draw(int width, int height){ if(layer->getProps().width > 0){ int n_wraps = wrapBoundingBoxes(bbs, layer->getVariationText(), + const_cast &>(layer->getVariationTextAppearance()), // TODO: REMOVE layer->getProps().width, lineHeight); float min_x = FLT_MAX; @@ -515,6 +516,7 @@ void GPUFontAtlasLayerCombo::draw(int width, float lineHeight = font->getLineHeight(layer->getProps().fontSize_px) * layer->getProps().lineHeight; int n_wraps = wrapBoundingBoxes(bbs, layer->getVariationText(), + const_cast &>(layer->getVariationTextAppearance()), // TODO: REMOVE layer->getProps().width, lineHeight, layer->getProps().textAlignment); @@ -787,86 +789,110 @@ void GPUFontAtlasLayerCombo::getAndApplyTransformOrigin(glm::vec4 & transformOri } int GPUFontAtlasLayerCombo::wrapBoundingBoxes(std::vector & bbs, const std::vector & _variationText, + std::vector & variationTextAppearance, int width, float advanceY, float textAlignment){ - int i = 0; - int vi = 0; - int wrapIndex = -1; int n_wraps = 0; - float collectedWrapWidth = 0; std::vector lineBreaks; std::vector goodCharacters; int lastGoodCharacter = -1; //textAlignment = ofMap(sin(ofGetElapsedTimef()), -1, 1, 0, 1); + std::vector vis; + std::vector wrapIndices; - float maxX = 0; - for(ofxGPUFont::Font::BoundingBox & bb : bbs){ - // good character means it's a drawable character - bool hasGoodCharacter = false; - while(!hasGoodCharacter && vi < variationText.size()){ - if(variationText[vi].charcode == '\0' - || variationText[vi].charcode == '\r' - || variationText[vi].charcode == '\n'){ - if(variationText[vi].charcode == '\n'){ - if(lastGoodCharacter >= 0){ - lineBreaks.push_back(lastGoodCharacter); + { // collect existing linebreaks, wrapindices and good characters + int vi = 0; + int wrapIndex = -1; + for(int i = 0; i < bbs.size(); i++){ + // good character means it's a drawable character + bool hasGoodCharacter = false; + while(!hasGoodCharacter && vi < variationText.size()){ + if(variationText[vi].charcode == '\0' + || variationText[vi].charcode == '\r' + || variationText[vi].charcode == '\n'){ + if(variationText[vi].charcode == '\n'){ + if(lastGoodCharacter >= 0){ + lineBreaks.push_back(lastGoodCharacter); + } } + wrapIndex = -1; + vi++; + }else if(variationText[vi].charcode == ' '){ // TODO: any whitespace + wrapIndex = i; + vi++; + }else{ + hasGoodCharacter = true; + goodCharacters.push_back(vi); } - wrapIndex = -1; - collectedWrapWidth = 0; - vi++; - }else if(variationText[vi].charcode == ' '){ // TODO: any whitespace + } + if(variationText[vi].charcode == '-'){ wrapIndex = i; - vi++; - }else{ - hasGoodCharacter = true; - goodCharacters.push_back(i); } - } - if(variationText[vi].charcode == '-'){ - wrapIndex = i; - } - const float insideWidth = bb.p1.x - collectedWrapWidth; - bool overhang = (insideWidth / float(width)) > (n_wraps + 1); - if(width > 0 && insideWidth > width){ - if(wrapIndex >= 0){ - float wrapWidth = bbs[wrapIndex].p0.x; - for(int w = wrapIndex; w < bbs.size(); w++){ - bbs[w].p0.x -= wrapWidth; - bbs[w].p1.x -= wrapWidth; - bbs[w].p2.x -= wrapWidth; - bbs[w].p3.x -= wrapWidth; - bbs[w].p0.y += advanceY; - bbs[w].p1.y += advanceY; - bbs[w].p2.y += advanceY; - bbs[w].p3.y += advanceY; + if(hasGoodCharacter){ + lastGoodCharacter = i; + } + wrapIndices.push_back(wrapIndex); + vi++; + } + } + { // add new linebreaks at wrapindices + int i = 0; + float wrapWidth; + int lastBrokenWrapIndex = -1; + for(ofxGPUFont::Font::BoundingBox & bb : bbs){ + int wrapIndex = wrapIndices[i]; + if(width > 0 && bb.p1.x > width){ + if(wrapIndex >= 0 && std::find(lineBreaks.begin(), lineBreaks.end(), wrapIndex - 1) == lineBreaks.end()){ + lastBrokenWrapIndex = wrapIndex; + wrapWidth = bbs[wrapIndex].p0.x; + int nextLineBreak = INT_MAX; + for(int lb = 0; lb < lineBreaks.size(); lb++){ + if(lineBreaks[lb] >= i){ + nextLineBreak = lineBreaks[lb]; + break; + } + } + for(int w = wrapIndex; w < bbs.size(); w++){ + if(w <= nextLineBreak){ + bbs[w].p0.x -= wrapWidth; + bbs[w].p1.x -= wrapWidth; + bbs[w].p2.x -= wrapWidth; + bbs[w].p3.x -= wrapWidth; + } + bbs[w].p0.y += advanceY; + bbs[w].p1.y += advanceY; + bbs[w].p2.y += advanceY; + bbs[w].p3.y += advanceY; + } + n_wraps++; + lineBreaks.push_back(wrapIndex - 1); } - n_wraps++; - lineBreaks.push_back(wrapIndex - 1); - wrapIndex = -1; } + i++; } + } - maxX = max(maxX, bbs[i].p1.x); - - if(hasGoodCharacter){ - lastGoodCharacter = i; - } - vi++; - i++; + float maxX = -1 * FLT_MAX; + for(const auto & bb : bbs){ + maxX = max(maxX, bb.p1.x); } if(textAlignment != 0){ if(lineBreaks.size() > 0){ lineBreaks.push_back(lastGoodCharacter); } - float w = width; // > 0 ? width : maxX; + //float w = width > 0 ? width : maxX; + float w = maxX; int startFromCharacter = 0; for(int lineBreak : lineBreaks){ ofxGPUFont::Font::BoundingBox & bbb = bbs[lineBreak]; + int vi = vis[lineBreak]; + int vi2 = vis[startFromCharacter]; + variationTextAppearance[vi].color[0] = 1.0; + variationTextAppearance[vi2].color[1] = 1.0; float shiftX = (w - bbb.p1.x) * textAlignment; for(int i = startFromCharacter; i <= lineBreak; i++){ auto & bb = bbs[i]; diff --git a/src/GPUFontAtlasLayerCombo.h b/src/GPUFontAtlasLayerCombo.h index a09479c..c4a654b 100644 --- a/src/GPUFontAtlasLayerCombo.h +++ b/src/GPUFontAtlasLayerCombo.h @@ -91,6 +91,7 @@ class GPUFontAtlasLayerCombo : public AtlasLayerCombo { private: int wrapBoundingBoxes(std::vector & bbs, const std::vector & _variationText, + std::vector & variationTextAppearance, int width, float advanceY, float textAlignment = 0);