diff --git a/lib/libtesla/include/tesla.hpp b/lib/libtesla/include/tesla.hpp index 329c00a4..e1efcf08 100644 --- a/lib/libtesla/include/tesla.hpp +++ b/lib/libtesla/include/tesla.hpp @@ -552,6 +552,15 @@ namespace tsl { s32 x, y, w, h; }; + struct Glyph { + stbtt_fontinfo* currFont; + float currFontSize; + int bounds[4]; + int xAdvance; + u8* glyphBmp; + int width, height; + }; + /** * @brief Manages the Tesla layer and draws raw data to the screen */ @@ -787,6 +796,41 @@ namespace tsl { this->fillScreen({ 0x00, 0x00, 0x00, 0x00 }); } + Glyph* getGlyph(u32 character, float fontSize, bool monospace) + { + static std::unordered_map s_glyphCache; + Glyph* glyph = nullptr; + u64 key = (static_cast(character) << 32) | static_cast(monospace) << 31 | static_cast(std::bit_cast(fontSize)); + + auto it = s_glyphCache.find(key); + if (it == s_glyphCache.end()) { + /* Cache glyph */ + glyph = &s_glyphCache.emplace(key, Glyph()).first->second; + + if (stbtt_FindGlyphIndex(&this->m_extFont, character)) + glyph->currFont = &this->m_extFont; + else if (this->m_hasLocalFont && stbtt_FindGlyphIndex(&this->m_stdFont, character) == 0) + glyph->currFont = &this->m_localFont; + else + glyph->currFont = &this->m_stdFont; + + glyph->currFontSize = stbtt_ScaleForPixelHeight(glyph->currFont, fontSize); + + stbtt_GetCodepointBitmapBoxSubpixel(glyph->currFont, character, glyph->currFontSize, glyph->currFontSize, + 0, 0, &glyph->bounds[0], &glyph->bounds[1], &glyph->bounds[2], &glyph->bounds[3]); + + int yAdvance = 0; + stbtt_GetCodepointHMetrics(glyph->currFont, monospace ? 'W' : character, &glyph->xAdvance, &yAdvance); + + glyph->glyphBmp = stbtt_GetCodepointBitmap(glyph->currFont, glyph->currFontSize, glyph->currFontSize, character, &glyph->width, &glyph->height, nullptr, nullptr); + } else { + /* Use cached glyph */ + glyph = &it->second; + } + + return glyph; + } + /** * @brief Draws a string * @@ -803,15 +847,6 @@ namespace tsl { s32 currX = x; s32 currY = y; - struct Glyph { - stbtt_fontinfo *currFont; - float currFontSize; - int bounds[4]; - int xAdvance; - u8 *glyphBmp; - int width, height; - }; - static std::unordered_map s_glyphCache; do { @@ -835,35 +870,7 @@ namespace tsl { continue; } - u64 key = (static_cast(currCharacter) << 32) | static_cast(monospace) << 31 | static_cast(std::bit_cast(fontSize)); - - Glyph *glyph = nullptr; - - auto it = s_glyphCache.find(key); - if (it == s_glyphCache.end()) { - /* Cache glyph */ - glyph = &s_glyphCache.emplace(key, Glyph()).first->second; - - if (stbtt_FindGlyphIndex(&this->m_extFont, currCharacter)) - glyph->currFont = &this->m_extFont; - else if(this->m_hasLocalFont && stbtt_FindGlyphIndex(&this->m_stdFont, currCharacter)==0) - glyph->currFont = &this->m_localFont; - else - glyph->currFont = &this->m_stdFont; - - glyph->currFontSize = stbtt_ScaleForPixelHeight(glyph->currFont, fontSize); - - stbtt_GetCodepointBitmapBoxSubpixel(glyph->currFont, currCharacter, glyph->currFontSize, glyph->currFontSize, - 0, 0, &glyph->bounds[0], &glyph->bounds[1], &glyph->bounds[2], &glyph->bounds[3]); - - int yAdvance = 0; - stbtt_GetCodepointHMetrics(glyph->currFont, monospace ? 'W' : currCharacter, &glyph->xAdvance, &yAdvance); - - glyph->glyphBmp = stbtt_GetCodepointBitmap(glyph->currFont, glyph->currFontSize, glyph->currFontSize, currCharacter, &glyph->width, &glyph->height, nullptr, nullptr); - } else { - /* Use cached glyph */ - glyph = &it->second; - } + Glyph* glyph = this->getGlyph(currCharacter, fontSize, monospace); if (glyph->glyphBmp != nullptr && !std::iswspace(currCharacter) && fontSize > 0 && color.a != 0x0) { @@ -940,20 +947,21 @@ namespace tsl { return string; } - private: - Renderer() {} - /** * @brief Gets the renderer instance * * @return Renderer */ - static Renderer& get() { + static Renderer& get() + { static Renderer renderer; return renderer; } + private: + Renderer() { } + /** * @brief Sets the opacity of the layer * diff --git a/source/text_funcs.hpp b/source/text_funcs.hpp index 89377070..335759b0 100644 --- a/source/text_funcs.hpp +++ b/source/text_funcs.hpp @@ -1,25 +1,38 @@ #pragma once +#include "tesla.hpp" + #include #include #include #include +size_t lineWidth(const std::string& line, const int fontSize = 19, const bool monospace = false) +{ + size_t width = 0; + for (const auto character : line) { + auto glyph = tsl::gfx::Renderer::get().getGlyph(character, fontSize, monospace); + width += static_cast(glyph->xAdvance * glyph->currFontSize); + } + return width; +} + std::pair readTextFromFile(const std::string& filePath) { // log("Entered readTextFromFile"); - std::string lines; + std::stringstream lines; std::string currentLine; std::ifstream file(filePath); std::vector words; int lineCount = 0; - size_t maxRowLength = 35; + const size_t maxRowWidth = 363; // magic number. width of a tesla List drawing area + const size_t whitespaceWidth = lineWidth(" "); std::string line; while (std::getline(file, line)) { if (line == "\r" || line.empty()) { - lines += "\n"; // Preserve empty lines + lines << std::endl; // Preserve empty lines lineCount++; continue; } @@ -27,27 +40,31 @@ std::pair readTextFromFile(const std::string& filePath) std::istringstream lineStream(line); std::string word; std::string currentLine; + size_t currentLineWidth = 0; while (lineStream >> word) { if (currentLine.empty()) { currentLine = word; - } else if (currentLine.length() + 1 + word.length() <= maxRowLength) { + currentLineWidth = lineWidth(currentLine); + } else if (const auto wordWidth = lineWidth(word); currentLineWidth + whitespaceWidth + wordWidth <= maxRowWidth) { currentLine += " " + word; + currentLineWidth = currentLineWidth + whitespaceWidth + wordWidth; } else { - lines += currentLine + "\n"; + lines << currentLine << std::endl; currentLine = word; + currentLineWidth = lineWidth(currentLine); lineCount++; } } if (!currentLine.empty()) { - lines += currentLine + "\n"; + lines << currentLine << std::endl; lineCount++; } } file.close(); - return std::make_pair(lines, lineCount); + return std::make_pair(lines.str(), lineCount); } bool write_to_file(const std::string& file_path, const std::string& line)