diff --git a/src/gpufont/font.hpp b/src/gpufont/font.hpp index d036427..98b63c1 100644 --- a/src/gpufont/font.hpp +++ b/src/gpufont/font.hpp @@ -4,6 +4,7 @@ // but it is still compiled in the "main.cpp" translation unit, // because both files have mostly the same dependencies (OpenGL, GLM, FreeType). #include "ofMain.h" +#include "ofUtils.h" #include #include @@ -57,12 +58,12 @@ class Font { float x0, y0, x1, y1, x2, y2; }; - struct BufferVertex { - float x, y, u, v; - int32_t bufferIndex; - }; - public: + struct BufferVertex { + float x, y, u, v; + int32_t bufferIndex; + }; + /// A structure to model a given axis of a variable font. struct FontVariationAxisParameters { /// The name of the variation axis. @@ -700,6 +701,97 @@ class Font { } + void collectVerticesAndIndices(const glm::vec3 & position, + const std::string & text, + std::vector & vertices, + std::vector & indices, + const bool vFlip = false, + const float fontSize_px = 42){ + float x = position.x; + float y = position.y; + float originalX = x; + + FT_UInt previous = 0; + for(const char * textIt = text.c_str(); *textIt != '\0';){ + float letterFontSize_px = fontSize_px; // can be individual + uint32_t charcode = decodeCharcode(&textIt); + + if(charcode == '\r'){ + continue; + } + + if(charcode == '\n'){ + x = originalX; + y -= (float)face->height / (float)face->units_per_EM * worldSize; + if(hinting){ + y = std::round(y); + } + continue; + } + + auto glyphIt = glyphs.find(charcode); + Glyph & glyph = (glyphIt == glyphs.end()) ? glyphs[0] : glyphIt->second; + + if(previous != 0 && glyph.index != 0){ + FT_Vector kerning; + FT_Error error = FT_Get_Kerning(face, previous, glyph.index, kerningMode, &kerning); + if(!error){ + x += (float)kerning.x / emSize * worldSize; + } + } + + // 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 x0 = x + u0 * worldSize * letterFontSize_px; + float y0 = y + v0 * worldSize * letterFontSize_px; + float x1 = x + u1 * worldSize * letterFontSize_px; + float y1 = y + v1 * worldSize * letterFontSize_px; + + if(vFlip){ + float _v = v0; + v0 = v1; + v1 = _v; + + y0 = y - v0 * worldSize * letterFontSize_px; + y1 = y - v1 * worldSize * letterFontSize_px; + } + + int32_t base = static_cast (vertices.size()); + vertices.push_back(BufferVertex{x0, y0, u0, v0, glyph.bufferIndex}); + vertices.push_back(BufferVertex{x1, y0, u1, v0, glyph.bufferIndex}); + vertices.push_back(BufferVertex{x1, y1, u1, v1, glyph.bufferIndex}); + vertices.push_back(BufferVertex{x0, y1, u0, v1, glyph.bufferIndex}); + + indices.insert(indices.end(), {base, base + 1, base + 2, base + 2, base + 3, base}); + } + + x += ((float)glyph.advance * letterFontSize_px) / emSize * worldSize; + previous = glyph.index; + } + } + + void draw(const std::vector & vertices, + const std::vector & indices){ + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(BufferVertex) * vertices.size(), vertices.data(), GL_STREAM_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * indices.size(), indices.data(), GL_STREAM_DRAW); + + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + } + void draw(float x, float y, float z, const std::string & text, bool vFlip = false, float fontSize_px = 42){ float originalX = x;