Changed the text shaping function to return the segment vector

This commit is contained in:
Leon Styhre 2024-08-02 23:31:47 +02:00
parent 9e7b02291b
commit b3ac8b6320
2 changed files with 23 additions and 29 deletions

View file

@ -24,7 +24,6 @@ Font::Font(float size, const std::string& path)
, mFontSize {size} , mFontSize {size}
, mLetterHeight {0.0f} , mLetterHeight {0.0f}
, mMaxGlyphHeight {static_cast<int>(std::round(size))} , mMaxGlyphHeight {static_cast<int>(std::round(size))}
, mTextHash {0}
{ {
if (mFontSize < 3.0f) { if (mFontSize < 3.0f) {
mFontSize = 3.0f; mFontSize = 3.0f;
@ -96,14 +95,17 @@ std::shared_ptr<Font> Font::get(float size, const std::string& path)
glm::vec2 Font::sizeText(std::string text, float lineSpacing) glm::vec2 Font::sizeText(std::string text, float lineSpacing)
{ {
if (text == "")
return glm::vec2 {0.0f, getHeight(lineSpacing)};
const float lineHeight {getHeight(lineSpacing)}; const float lineHeight {getHeight(lineSpacing)};
float lineWidth {0.0f}; float lineWidth {0.0f};
float highestWidth {0.0f}; float highestWidth {0.0f};
float y {lineHeight}; float y {lineHeight};
shapeText(text); std::vector<ShapeSegment> segmentsHB {std::move(shapeText(text))};
for (auto& segment : mSegmentsHB) { for (auto& segment : segmentsHB) {
for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) { for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) {
const unsigned int character {segment.glyphIndexes[i]}; const unsigned int character {segment.glyphIndexes[i]};
Glyph* glyph {nullptr}; Glyph* glyph {nullptr};
@ -141,9 +143,9 @@ int Font::loadGlyphs(const std::string& text)
{ {
mMaxGlyphHeight = static_cast<int>(std::round(mFontSize)); mMaxGlyphHeight = static_cast<int>(std::round(mFontSize));
shapeText(text); std::vector<ShapeSegment> segmentsHB {std::move(shapeText(text))};
for (auto& segment : mSegmentsHB) { for (auto& segment : segmentsHB) {
for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) { for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) {
const unsigned int character {segment.glyphIndexes[i]}; const unsigned int character {segment.glyphIndexes[i]};
Glyph* glyph {nullptr}; Glyph* glyph {nullptr};
@ -202,9 +204,9 @@ TextCache* Font::buildTextCache(const std::string& text,
// Vertices by texture. // Vertices by texture.
std::map<FontTexture*, std::vector<Renderer::Vertex>> vertMap; std::map<FontTexture*, std::vector<Renderer::Vertex>> vertMap;
shapeText(text); std::vector<ShapeSegment> segmentsHB {std::move(shapeText(text))};
for (auto& segment : mSegmentsHB) { for (auto& segment : segmentsHB) {
for (size_t cursor {0}; cursor < segment.glyphIndexes.size(); ++cursor) { for (size_t cursor {0}; cursor < segment.glyphIndexes.size(); ++cursor) {
const unsigned int character {segment.glyphIndexes[cursor]}; const unsigned int character {segment.glyphIndexes[cursor]};
Glyph* glyph {nullptr}; Glyph* glyph {nullptr};
@ -338,13 +340,13 @@ std::string Font::wrapText(const std::string& text,
// There are also many instances where this hack will not lead to correct results. // There are also many instances where this hack will not lead to correct results.
float totalWidth {0.0f}; float totalWidth {0.0f};
bool skipAbbreviation {false}; bool skipAbbreviation {false};
shapeText(text); std::vector<ShapeSegment> segmentsHB {std::move(shapeText(text))};
for (auto& segment : mSegmentsHB) for (auto& segment : segmentsHB)
totalWidth += segment.glyphsWidth; totalWidth += segment.glyphsWidth;
if (totalWidth <= maxLength || if (totalWidth <= maxLength ||
(mSegmentsHB.size() == 1 && mSegmentsHB.front().glyphsWidth <= maxLength)) (segmentsHB.size() == 1 && segmentsHB.front().glyphsWidth <= maxLength))
skipAbbreviation = true; skipAbbreviation = true;
for (size_t i {0}; i < text.length(); ++i) { for (size_t i {0}; i < text.length(); ++i) {
@ -469,10 +471,10 @@ glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
size_t cursor {0}; size_t cursor {0};
// TEMPORARY - enable this code when shaped text is properly wrapped in wrapText(). // TEMPORARY - enable this code when shaped text is properly wrapped in wrapText().
// shapeText(wrappedText); // std::vector<ShapeSegment> segmentsHB {std::move(shapeText(wrappedText))};
// size_t totalPos {0}; // size_t totalPos {0};
// for (auto& segment : mSegmentsHB) { // for (auto& segment : segmentsHB) {
// if (totalPos > stop) // if (totalPos > stop)
// break; // break;
// for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) { // for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) {
@ -740,17 +742,9 @@ void Font::initLibrary()
} }
} }
void Font::shapeText(const std::string& text) std::vector<Font::ShapeSegment> Font::shapeText(const std::string& text)
{ {
// Calculate the hash value for the string to make sure we're not shaping the same std::vector<ShapeSegment> segmentsHB;
// text repeatedly.
const size_t hashValue {std::hash<std::string> {}(text)};
if (hashValue == mTextHash)
return;
mTextHash = hashValue;
mSegmentsHB.clear();
hb_font_t* lastFont {nullptr}; hb_font_t* lastFont {nullptr};
unsigned int lastCursor {0}; unsigned int lastCursor {0};
unsigned int byteLength {0}; unsigned int byteLength {0};
@ -809,15 +803,15 @@ void Font::shapeText(const std::string& text)
if (!shapeSegment) if (!shapeSegment)
segment.substring = text.substr(lastFlushPos, textCursor - lastFlushPos); segment.substring = text.substr(lastFlushPos, textCursor - lastFlushPos);
mSegmentsHB.emplace_back(std::move(segment)); segmentsHB.emplace_back(std::move(segment));
lastFlushPos = textCursor; lastFlushPos = textCursor;
} }
lastFont = currGlyph->fontHB; lastFont = currGlyph->fontHB;
} }
if (mSegmentsHB.empty()) if (segmentsHB.empty())
return; return segmentsHB;
size_t cursor {0}; size_t cursor {0};
size_t length {0}; size_t length {0};
@ -827,7 +821,7 @@ void Font::shapeText(const std::string& text)
// Step 2, shape text. // Step 2, shape text.
for (auto& segment : mSegmentsHB) { for (auto& segment : segmentsHB) {
cursor = 0; cursor = 0;
length = 0; length = 0;
segment.glyphIndexes.clear(); segment.glyphIndexes.clear();
@ -868,6 +862,8 @@ void Font::shapeText(const std::string& text)
segment.glyphIndexes.emplace_back(character); segment.glyphIndexes.emplace_back(character);
} }
} }
return segmentsHB;
} }
void Font::rebuildTextures() void Font::rebuildTextures()

View file

@ -208,7 +208,7 @@ private:
}; };
// Shape text using HarfBuzz. // Shape text using HarfBuzz.
void shapeText(const std::string& text); std::vector<ShapeSegment> shapeText(const std::string& text);
// Completely recreate the texture data for all textures based on mGlyphs information. // Completely recreate the texture data for all textures based on mGlyphs information.
void rebuildTextures(); void rebuildTextures();
@ -238,7 +238,6 @@ private:
std::vector<std::unique_ptr<FontTexture>> mTextures; std::vector<std::unique_ptr<FontTexture>> mTextures;
std::map<unsigned int, Glyph> mGlyphMap; std::map<unsigned int, Glyph> mGlyphMap;
std::map<std::pair<unsigned int, hb_font_t*>, Glyph> mGlyphMapByIndex; std::map<std::pair<unsigned int, hb_font_t*>, Glyph> mGlyphMapByIndex;
std::vector<ShapeSegment> mSegmentsHB;
const std::string mPath; const std::string mPath;
hb_font_t* mFontHB; hb_font_t* mFontHB;
@ -248,7 +247,6 @@ private:
float mFontSize; float mFontSize;
float mLetterHeight; float mLetterHeight;
int mMaxGlyphHeight; int mMaxGlyphHeight;
size_t mTextHash;
}; };
// Used to store a sort of "pre-rendered" string. // Used to store a sort of "pre-rendered" string.