Finally implemented TextCaches for TextComponent and TextEditComponent.

Huge boost in performance with rendering game descriptions.
(It's About Damn Time (TM))
This commit is contained in:
Aloshi 2013-08-21 20:08:36 -05:00
parent 11f774e019
commit df897c0b5a
6 changed files with 90 additions and 100 deletions

View file

@ -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)
{
}

View file

@ -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

View file

@ -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> 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<Font> f = getFont();
mTextCache = std::unique_ptr<TextCache>(f->buildTextCache(f->wrapText(mText, mSize.x()), 0, 0, (mColor >> 8 << 8) | mOpacity));
}
void TextComponent::setValue(const std::string& value)
{
setText(value);

View file

@ -26,10 +26,13 @@ private:
void calculateExtent();
void onTextChanged();
unsigned int mColor;
std::shared_ptr<Font> mFont;
Eigen::Matrix<bool, 1, 2> mAutoCalcExtent;
std::string mText;
std::unique_ptr<TextCache> mTextCache;
bool mCentered;
};

View file

@ -69,11 +69,16 @@ void TextEditComponent::textInput(const char* text)
void TextEditComponent::onTextChanged()
{
std::shared_ptr<Font> f = getFont();
std::string wrappedText = f->wrapText(mText, mSize.x());
mTextCache = std::unique_ptr<TextCache>(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);
if(mTextCache != NULL)
{
std::shared_ptr<Font> f = getFont();
f->drawWrappedText(mText, Eigen::Vector2f(0, 0), mSize.x(), 0x000000 | getOpacity());
f->renderTextCache(mTextCache.get());
}
}
std::shared_ptr<Font> TextEditComponent::getFont()

View file

@ -4,6 +4,7 @@
#include "GuiBox.h"
class Font;
class TextCache;
class TextEditComponent : public GuiComponent
{
@ -33,4 +34,6 @@ private:
std::shared_ptr<Font> getFont();
GuiBox mBox;
std::unique_ptr<TextCache> mTextCache;
};