From 2f506000ab8a19a198699016bc9cfb04432adb92 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Wed, 19 Apr 2023 16:52:56 +0200 Subject: [PATCH] glyph appearance and color --- src/gpufont/font.hpp | 208 ++++++++++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 83 deletions(-) diff --git a/src/gpufont/font.hpp b/src/gpufont/font.hpp index 2a6287b..f90b17c 100644 --- a/src/gpufont/font.hpp +++ b/src/gpufont/font.hpp @@ -143,6 +143,12 @@ struct GlyphIdentity { return this->charcode == other.charcode && this->coords == other.coords; } }; + +struct GlyphAppearance { + uint32_t charcode; + glm::vec4 color; + float fontSize_px; +}; } // create hash for GlyphIdentity, so we can use it in our unordered_map as key namespace std { @@ -919,6 +925,7 @@ class Font { } void collectBoundingBoxes(const std::vector & variationText, + const std::vector & variationTextAppearance, BoundingBox & boundingBox, std::vector & boundingBoxes, float & advanceY, @@ -932,18 +939,21 @@ class Font { float minY = FLT_MAX; float maxX = -FLT_MAX; float maxY = -FLT_MAX; + int i = 0; for(const GlyphIdentity & glyphIdentity : variationText){ + const GlyphAppearance & glyphAppearance = variationTextAppearance[i]; if(glyphIdentity.charcode == '\0'){ break; } - float letterFontSize_px = fontSize_px; // can be individual + float letterFontSize_px = glyphAppearance.fontSize_px; // can be individual const uint32_t & charcode = glyphIdentity.charcode; if(charcode == '\r'){ + i++; continue; } - if(charcode == '\n' || charcode == 'n'){ + if(charcode == '\n'){ advanceX = 0; advanceY += getLineHeight(fontSize_px); if(!vFlip){ @@ -952,6 +962,7 @@ class Font { if(hinting){ advanceY = std::round(advanceY); } + i++; continue; } @@ -963,7 +974,7 @@ class Font { FT_Vector kerning; FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning); if(!error){ - advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize; + advanceX += ((float)kerning.x * letterFontSize_px) / emSize * worldSize; } } @@ -1009,6 +1020,7 @@ class Font { advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize; previous = glyph.index; + i++; } boundingBox.p0 = glm::vec4(minX, minY, 0, 1); boundingBox.p1 = glm::vec4(maxX, minY, 0, 1); @@ -1024,114 +1036,144 @@ class Font { } void collectVerticesAndIndices(const ofNode & node, + const std::vector & variationTextAppearance, std::vector & boundingBoxes, std::vector & vertices, - std::vector & indices, - const glm::vec4 & color = glm::vec4(1), - const float fontSize_px = 42){ + std::vector & indices){ + int i = 0; for(BoundingBox & bb : boundingBoxes){ + bool hasGoodCharacter = false; + while(!hasGoodCharacter && i < variationTextAppearance.size() - 1){ + if(variationTextAppearance[i].charcode == '\0' + || variationTextAppearance[i].charcode == '\r' + || variationTextAppearance[i].charcode == '\n'){ + i++; + }else{ + hasGoodCharacter = true; + } + } bb.multiply(node.getGlobalTransformMatrix()); int32_t base = static_cast (vertices.size()); - vertices.push_back(BufferVertex{bb.p0.x, bb.p0.y, bb.u0, bb.v0, bb.bufferIndex, color.r, color.g, color.b, color.a}); - vertices.push_back(BufferVertex{bb.p1.x, bb.p1.y, bb.u1, bb.v0, bb.bufferIndex, color.r, color.g, color.b, color.a}); - vertices.push_back(BufferVertex{bb.p2.x, bb.p2.y, bb.u1, bb.v1, bb.bufferIndex, color.r, color.g, color.b, color.a}); - vertices.push_back(BufferVertex{bb.p3.x, bb.p3.y, bb.u0, bb.v1, bb.bufferIndex, color.r, color.g, color.b, color.a}); + const glm::vec4 & color = variationTextAppearance[i].color; + vertices.push_back(BufferVertex{bb.p0.x, bb.p0.y, bb.u0, bb.v0, bb.bufferIndex, + color.r, + color.g, + color.b, + color.a}); + vertices.push_back(BufferVertex{bb.p1.x, bb.p1.y, bb.u1, bb.v0, bb.bufferIndex, + color.r, + color.g, + color.b, + color.a}); + vertices.push_back(BufferVertex{bb.p2.x, bb.p2.y, bb.u1, bb.v1, bb.bufferIndex, + color.r, + color.g, + color.b, + color.a}); + vertices.push_back(BufferVertex{bb.p3.x, bb.p3.y, bb.u0, bb.v1, bb.bufferIndex, + color.r, + color.g, + color.b, + color.a}); indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base}); + i++; } } - void collectVerticesAndIndices(const ofNode & node, - const std::vector & variationText, - std::vector & vertices, - std::vector & indices, - const glm::vec4 & color = glm::vec4(1), - const bool vFlip = false, - const float fontSize_px = 42){ - float advanceX = 0; - float advanceY = 0; + // NOTE: following only exists for nostalgic reason + // + //void collectVerticesAndIndices(const ofNode & node, + //const std::vector & variationText, + //std::vector & vertices, + //std::vector & indices, + //const glm::vec4 & color = glm::vec4(1), + //const bool vFlip = false, + //const float fontSize_px = 42){ + //float advanceX = 0; + //float advanceY = 0; - FT_UInt previous = 0; - for(const GlyphIdentity & glyphIdentity : variationText){ - if(glyphIdentity.charcode == '\0'){ - break; - } - float letterFontSize_px = fontSize_px; // can be individual - const uint32_t & charcode = glyphIdentity.charcode; + //FT_UInt previous = 0; + //for(const GlyphIdentity & glyphIdentity : variationText){ + //if(glyphIdentity.charcode == '\0'){ + //break; + //} + //float letterFontSize_px = fontSize_px; // can be individual + //const uint32_t & charcode = glyphIdentity.charcode; - if(charcode == '\r'){ - continue; - } + //if(charcode == '\r'){ + //continue; + //} - if(charcode == '\n' || charcode == 'n'){ - advanceX = 0; - advanceY += ((float)face->height * fontSize_px) / (float)face->units_per_EM * worldSize; - if(!vFlip){ - advanceY *= -1; - } - if(hinting){ - advanceY = std::round(advanceY); - } - continue; - } + //if(charcode == '\n' || charcode == 'n'){ + //advanceX = 0; + //advanceY += ((float)face->height * fontSize_px) / (float)face->units_per_EM * worldSize; + //if(!vFlip){ + //advanceY *= -1; + //} + //if(hinting){ + //advanceY = std::round(advanceY); + //} + //continue; + //} - auto glyphIt = glyphs.find(glyphIdentity); - Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs.begin()->second : glyphIt->second; // in case we have no glyph, draw first one? - // NOTE: should we do this? + //auto glyphIt = glyphs.find(glyphIdentity); + //Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs.begin()->second : glyphIt->second; // in case we have no glyph, draw first one? + //// NOTE: should we do this? - if(previous != 0 && glyph.index != 0){ - FT_Vector kerning; - FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning); - if(!error){ - advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize; - } - } + //if(previous != 0 && glyph.index != 0){ + //FT_Vector kerning; + //FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning); + //if(!error){ + //advanceX += ((float)kerning.x * fontSize_px) / emSize * worldSize; + //} + //} - // Do not emit quad for empty glyphs (whitespace). - if(glyph.curveCount){ - FT_Pos d = (FT_Pos)(emSize * dilation); + //// Do not emit quad for empty glyphs (whitespace). + //if(glyph.curveCount){ + //FT_Pos d = (FT_Pos)(emSize * dilation); - float u0 = (float)(glyph.bearingX - d) / emSize; - float v0 = (float)(glyph.bearingY - glyph.height - d) / emSize; - float u1 = (float)(glyph.bearingX + glyph.width + d) / emSize; - float v1 = (float)(glyph.bearingY + d) / emSize; + //float u0 = (float)(glyph.bearingX - d) / emSize; + //float v0 = (float)(glyph.bearingY - glyph.height - d) / emSize; + //float u1 = (float)(glyph.bearingX + glyph.width + d) / emSize; + //float v1 = (float)(glyph.bearingY + d) / emSize; - float x0 = advanceX + u0 * worldSize * letterFontSize_px; - float y0 = v0 * worldSize * letterFontSize_px; - float x1 = advanceX + u1 * worldSize * letterFontSize_px; - float y1 = v1 * worldSize * letterFontSize_px; + //float x0 = advanceX + u0 * worldSize * letterFontSize_px; + //float y0 = v0 * worldSize * letterFontSize_px; + //float x1 = advanceX + u1 * worldSize * letterFontSize_px; + //float y1 = v1 * worldSize * letterFontSize_px; - if(vFlip){ - float _v = v0; - v0 = v1; - v1 = _v; + //if(vFlip){ + //float _v = v0; + //v0 = v1; + //v1 = _v; - y0 = -v0 * worldSize * letterFontSize_px; - y1 = -v1 * worldSize * letterFontSize_px; - } + //y0 = -v0 * worldSize * letterFontSize_px; + //y1 = -v1 * worldSize * letterFontSize_px; + //} - glm::vec4 p0 = node.getGlobalTransformMatrix() * glm::vec4(x0, y0 + advanceY, 0, 1); - glm::vec4 p1 = node.getGlobalTransformMatrix() * glm::vec4(x1, y0 + advanceY, 0, 1); - glm::vec4 p2 = node.getGlobalTransformMatrix() * glm::vec4(x1, y1 + advanceY, 0, 1); - glm::vec4 p3 = node.getGlobalTransformMatrix() * glm::vec4(x0, y1 + advanceY, 0, 1); + //glm::vec4 p0 = node.getGlobalTransformMatrix() * glm::vec4(x0, y0 + advanceY, 0, 1); + //glm::vec4 p1 = node.getGlobalTransformMatrix() * glm::vec4(x1, y0 + advanceY, 0, 1); + //glm::vec4 p2 = node.getGlobalTransformMatrix() * glm::vec4(x1, y1 + advanceY, 0, 1); + //glm::vec4 p3 = node.getGlobalTransformMatrix() * glm::vec4(x0, y1 + advanceY, 0, 1); - int32_t base = static_cast (vertices.size()); - vertices.push_back(BufferVertex{p0.x, p0.y, u0, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a}); - vertices.push_back(BufferVertex{p1.x, p1.y, u1, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a}); - vertices.push_back(BufferVertex{p2.x, p2.y, u1, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a}); - vertices.push_back(BufferVertex{p3.x, p3.y, u0, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a}); + //int32_t base = static_cast (vertices.size()); + //vertices.push_back(BufferVertex{p0.x, p0.y, u0, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a}); + //vertices.push_back(BufferVertex{p1.x, p1.y, u1, v0, glyph.bufferIndex, color.r, color.g, color.b, color.a}); + //vertices.push_back(BufferVertex{p2.x, p2.y, u1, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a}); + //vertices.push_back(BufferVertex{p3.x, p3.y, u0, v1, glyph.bufferIndex, color.r, color.g, color.b, color.a}); - indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base}); - } + //indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base}); + //} - advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize; - previous = glyph.index; - } - } + //advanceX += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize; + //previous = glyph.index; + //} + //} void draw(const std::vector & vertices, const std::vector & indices){