diff --git a/src/Font.cpp b/src/Font.cpp index d7b29bdf2..2147d7327 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -283,12 +283,6 @@ void Font::renderTextCache(TextCache* cache) return; } - if(cache->sourceFont != this) - { - LOG(LogError) << "Attempted to draw TextCache with font other than its source!"; - return; - } - glBindTexture(GL_TEXTURE_2D, textureID); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); @@ -314,17 +308,34 @@ void Font::renderTextCache(TextCache* cache) Eigen::Vector2f Font::sizeText(std::string text) const { - float cwidth = 0.0f; + float lineWidth = 0.0f; + float highestWidth = 0.0f; + + float y = (float)getHeight(); + for(unsigned int i = 0; i < text.length(); i++) { unsigned char letter = text[i]; + + if(letter == '\n') + { + if(lineWidth > highestWidth) + highestWidth = lineWidth; + + lineWidth = 0.0f; + y += getHeight(); + } + if(letter < 32 || letter >= 128) letter = 127; - cwidth += charData[letter].advX * fontScale; + lineWidth += charData[letter].advX * fontScale; } - return Eigen::Vector2f(cwidth, getHeight()); + if(lineWidth > highestWidth) + highestWidth = lineWidth; + + return Eigen::Vector2f(highestWidth, y); } int Font::getHeight() const @@ -333,8 +344,6 @@ int Font::getHeight() const } - - void Font::drawCenteredText(std::string text, float xOffset, float y, unsigned int color) { Eigen::Vector2f pos = sizeText(text); @@ -350,73 +359,21 @@ void Font::drawCenteredText(std::string text, float xOffset, float y, unsigned i //draws text and ensures it's never longer than xLen void Font::drawWrappedText(std::string text, const Eigen::Vector2f& offset, float xLen, unsigned int color) { - float y = offset.y(); - - std::string line, word, temp; - Eigen::Vector2f textSize; - size_t space, newline; - - while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render - { - space = text.find(' ', 0); - if(space == std::string::npos) - space = text.length() - 1; - - - word = text.substr(0, space + 1); - - //check if the next word contains a newline - newline = word.find('\n', 0); - if(newline != std::string::npos) - { - word = word.substr(0, newline); - text.erase(0, newline + 1); - }else{ - text.erase(0, space + 1); - } - - temp = line + word; - - textSize = sizeText(temp); - - //if we're on the last word and it'll fit on the line, just add it to the line - if((textSize.x() <= xLen && text.length() == 0) || newline != std::string::npos) - { - line = temp; - word = ""; - } - - - //if the next line will be too long or we're on the last of the text, render it - if(textSize.x() > xLen || text.length() == 0 || newline != std::string::npos) - { - //render line now - if(textSize.x() > 0) //make sure it's not blank - drawText(line, Eigen::Vector2f(offset.x(), y), color); - - //increment y by height and some extra padding for the next line - y += textSize.y() + 4; - - //move the word we skipped to the next line - line = word; - }else{ - //there's still space, continue building the line - line = temp; - } - - } + text = wrapText(text, xLen); + drawText(text, offset, color); } -Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen) const +//the worst algorithm ever written +//breaks up a normal string with newlines to make it fit xLen +std::string Font::wrapText(std::string text, float xLen) const { - Eigen::Vector2f out(0, 0); - - float y = 0; + std::string out; std::string line, word, temp; - Eigen::Vector2f textSize; size_t space, newline; + Eigen::Vector2f textSize; + while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render { space = text.find(' ', 0); @@ -449,29 +406,29 @@ Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen) const //if the next line will be too long or we're on the last of the text, render it if(textSize.x() > xLen || text.length() == 0 || newline != std::string::npos) { - //increment y by height and some extra padding for the next line - y += textSize.y() + 4; + //output line now + if(textSize.x() > 0) //make sure it's not blank + out += line + '\n'; //move the word we skipped to the next line line = word; - - //update our maximum known line width - if(textSize.x() > out.x()) - out[0] = textSize.x(); }else{ //there's still space, continue building the line line = temp; } - } - out[1] = y; + if(!out.empty()) //chop off the last newline + out.erase(out.length() - 1, 1); return out; } - - +Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen) const +{ + text = wrapText(text, xLen); + return sizeText(text); +} //============================================================================================================= //TextCache @@ -502,6 +459,13 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of { unsigned char letter = text[charNum]; + if(letter == '\n') + { + y += (float)getHeight(); + x = offsetX; + continue; + } + if(letter < 32 || letter >= 128) letter = 127; //print [X] if character is not standard ASCII @@ -533,14 +497,14 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of x += charData[letter].advX * fontScale; } - TextCache* cache = new TextCache(vertCount, vert, colors, this); + TextCache* cache = new TextCache(vertCount, vert, colors); if(color != 0x00000000) cache->setColor(color); return cache; } -TextCache::TextCache(int verts, Vertex* v, GLubyte* c, Font* f) : vertCount(verts), verts(v), colors(c), sourceFont(f) +TextCache::TextCache(int verts, Vertex* v, GLubyte* c) : vertCount(verts), verts(v), colors(c) { } diff --git a/src/Font.h b/src/Font.h index fedc4e9e3..6456804d9 100644 --- a/src/Font.h +++ b/src/Font.h @@ -53,6 +53,8 @@ public: void drawText(std::string text, const Eigen::Vector2f& offset, unsigned int color); Eigen::Vector2f sizeText(std::string text) const; //Sets the width and height of a given string to supplied pointers. A dimension is skipped if its pointer is NULL. + std::string wrapText(std::string text, float xLen) const; + void drawWrappedText(std::string text, const Eigen::Vector2f& offset, float xLen, unsigned int color); Eigen::Vector2f sizeWrappedText(std::string text, float xLen) const; @@ -102,13 +104,12 @@ public: void setColor(unsigned int color); - TextCache(int verts, Vertex* v, GLubyte* c, Font* f); + TextCache(int verts, Vertex* v, GLubyte* c); ~TextCache(); - const int vertCount; - const Vertex* verts; - const GLubyte* colors; - const Font* sourceFont; + int vertCount; + Vertex* verts; + GLubyte* colors; }; #endif diff --git a/src/components/TextComponent.cpp b/src/components/TextComponent.cpp index a36203c84..f3daa5ae2 100644 --- a/src/components/TextComponent.cpp +++ b/src/components/TextComponent.cpp @@ -20,27 +20,26 @@ TextComponent::TextComponent(Window* window, const std::string& text, std::share void TextComponent::onSizeChanged() { mAutoCalcExtent << (getSize().x() == 0), (getSize().y() == 0); - calculateExtent(); + onTextChanged(); } void TextComponent::setFont(std::shared_ptr font) { mFont = font; - - calculateExtent(); + onTextChanged(); } void TextComponent::setColor(unsigned int color) { mColor = color; mOpacity = mColor & 0x000000FF; + onTextChanged(); } void TextComponent::setText(const std::string& text) { mText = text; - - calculateExtent(); + onTextChanged(); } void TextComponent::setCentered(bool center) @@ -70,9 +69,13 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans) { Eigen::Vector2f textSize = font->sizeWrappedText(mText, getSize().x()); Eigen::Vector2f pos((getSize().x() - textSize.x()) / 2, 0); - font->drawWrappedText(mText, pos, getSize().x(), (mColor >> 8 << 8) | getOpacity()); + + Eigen::Affine3f centeredTrans = trans; + centeredTrans = centeredTrans.translate(Eigen::Vector3f(pos.x(), pos.y(), 0)); + Renderer::setMatrix(centeredTrans); + font->renderTextCache(mTextCache.get()); }else{ - font->drawWrappedText(mText, Eigen::Vector2f(0, 0), getSize().x(), mColor >> 8 << 8 | getOpacity()); + font->renderTextCache(mTextCache.get()); } } @@ -94,6 +97,14 @@ void TextComponent::calculateExtent() } } +void TextComponent::onTextChanged() +{ + calculateExtent(); + + std::shared_ptr f = getFont(); + mTextCache = std::unique_ptr(f->buildTextCache(f->wrapText(mText, mSize.x()), 0, 0, (mColor >> 8 << 8) | mOpacity)); +} + void TextComponent::setValue(const std::string& value) { setText(value); diff --git a/src/components/TextComponent.h b/src/components/TextComponent.h index 0cba0cacb..99892488f 100644 --- a/src/components/TextComponent.h +++ b/src/components/TextComponent.h @@ -26,10 +26,13 @@ private: void calculateExtent(); + void onTextChanged(); + unsigned int mColor; std::shared_ptr mFont; Eigen::Matrix mAutoCalcExtent; std::string mText; + std::unique_ptr mTextCache; bool mCentered; }; diff --git a/src/components/TextEditComponent.cpp b/src/components/TextEditComponent.cpp index f8c5e4475..1efed94cd 100644 --- a/src/components/TextEditComponent.cpp +++ b/src/components/TextEditComponent.cpp @@ -69,11 +69,16 @@ void TextEditComponent::textInput(const char* text) void TextEditComponent::onTextChanged() { + std::shared_ptr f = getFont(); + + std::string wrappedText = f->wrapText(mText, mSize.x()); + mTextCache = std::unique_ptr(f->buildTextCache(wrappedText, 0, 0, 0x00000000 | getOpacity())); + if(mAllowResize) { - float y = getFont()->sizeWrappedText(mText, mSize.x()).y(); + float y = f->sizeText(wrappedText).y(); if(y == 0) - y = (float)getFont()->getHeight(); + y = (float)f->getHeight(); setSize(mSize.x(), y); } @@ -96,8 +101,11 @@ void TextEditComponent::render(const Eigen::Affine3f& parentTrans) Renderer::setMatrix(trans); - std::shared_ptr f = getFont(); - f->drawWrappedText(mText, Eigen::Vector2f(0, 0), mSize.x(), 0x000000 | getOpacity()); + if(mTextCache != NULL) + { + std::shared_ptr f = getFont(); + f->renderTextCache(mTextCache.get()); + } } std::shared_ptr TextEditComponent::getFont() diff --git a/src/components/TextEditComponent.h b/src/components/TextEditComponent.h index e5eb2055f..dd35f4cd2 100644 --- a/src/components/TextEditComponent.h +++ b/src/components/TextEditComponent.h @@ -4,12 +4,13 @@ #include "GuiBox.h" class Font; +class TextCache; class TextEditComponent : public GuiComponent { public: TextEditComponent(Window* window); - + void textInput(const char* text) override; void render(const Eigen::Affine3f& parentTrans) override; @@ -33,4 +34,6 @@ private: std::shared_ptr getFont(); GuiBox mBox; + + std::unique_ptr mTextCache; };