mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-18 07:05:39 +00:00
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:
parent
11f774e019
commit
df897c0b5a
134
src/Font.cpp
134
src/Font.cpp
|
@ -283,12 +283,6 @@ void Font::renderTextCache(TextCache* cache)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cache->sourceFont != this)
|
|
||||||
{
|
|
||||||
LOG(LogError) << "Attempted to draw TextCache with font other than its source!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
@ -314,17 +308,34 @@ void Font::renderTextCache(TextCache* cache)
|
||||||
|
|
||||||
Eigen::Vector2f Font::sizeText(std::string text) const
|
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++)
|
for(unsigned int i = 0; i < text.length(); i++)
|
||||||
{
|
{
|
||||||
unsigned char letter = text[i];
|
unsigned char letter = text[i];
|
||||||
|
|
||||||
|
if(letter == '\n')
|
||||||
|
{
|
||||||
|
if(lineWidth > highestWidth)
|
||||||
|
highestWidth = lineWidth;
|
||||||
|
|
||||||
|
lineWidth = 0.0f;
|
||||||
|
y += getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
if(letter < 32 || letter >= 128)
|
if(letter < 32 || letter >= 128)
|
||||||
letter = 127;
|
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
|
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)
|
void Font::drawCenteredText(std::string text, float xOffset, float y, unsigned int color)
|
||||||
{
|
{
|
||||||
Eigen::Vector2f pos = sizeText(text);
|
Eigen::Vector2f pos = sizeText(text);
|
||||||
|
@ -350,19 +359,27 @@ void Font::drawCenteredText(std::string text, float xOffset, float y, unsigned i
|
||||||
//draws text and ensures it's never longer than xLen
|
//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)
|
void Font::drawWrappedText(std::string text, const Eigen::Vector2f& offset, float xLen, unsigned int color)
|
||||||
{
|
{
|
||||||
float y = offset.y();
|
text = wrapText(text, xLen);
|
||||||
|
drawText(text, offset, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
//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
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
|
||||||
std::string line, word, temp;
|
std::string line, word, temp;
|
||||||
Eigen::Vector2f textSize;
|
|
||||||
size_t space, newline;
|
size_t space, newline;
|
||||||
|
|
||||||
|
Eigen::Vector2f textSize;
|
||||||
|
|
||||||
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
|
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
|
||||||
{
|
{
|
||||||
space = text.find(' ', 0);
|
space = text.find(' ', 0);
|
||||||
if(space == std::string::npos)
|
if(space == std::string::npos)
|
||||||
space = text.length() - 1;
|
space = text.length() - 1;
|
||||||
|
|
||||||
|
|
||||||
word = text.substr(0, space + 1);
|
word = text.substr(0, space + 1);
|
||||||
|
|
||||||
//check if the next word contains a newline
|
//check if the next word contains a newline
|
||||||
|
@ -386,16 +403,12 @@ void Font::drawWrappedText(std::string text, const Eigen::Vector2f& offset, floa
|
||||||
word = "";
|
word = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//if the next line will be too long or we're on the last of the text, render it
|
//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)
|
if(textSize.x() > xLen || text.length() == 0 || newline != std::string::npos)
|
||||||
{
|
{
|
||||||
//render line now
|
//output line now
|
||||||
if(textSize.x() > 0) //make sure it's not blank
|
if(textSize.x() > 0) //make sure it's not blank
|
||||||
drawText(line, Eigen::Vector2f(offset.x(), y), color);
|
out += line + '\n';
|
||||||
|
|
||||||
//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
|
//move the word we skipped to the next line
|
||||||
line = word;
|
line = word;
|
||||||
|
@ -403,75 +416,19 @@ void Font::drawWrappedText(std::string text, const Eigen::Vector2f& offset, floa
|
||||||
//there's still space, continue building the line
|
//there's still space, continue building the line
|
||||||
line = temp;
|
line = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen) const
|
if(!out.empty()) //chop off the last newline
|
||||||
{
|
out.erase(out.length() - 1, 1);
|
||||||
Eigen::Vector2f out(0, 0);
|
|
||||||
|
|
||||||
float y = 0;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
//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;
|
|
||||||
|
|
||||||
//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;
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen) const
|
||||||
|
{
|
||||||
|
text = wrapText(text, xLen);
|
||||||
|
return sizeText(text);
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================================================
|
//=============================================================================================================
|
||||||
//TextCache
|
//TextCache
|
||||||
|
@ -502,6 +459,13 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of
|
||||||
{
|
{
|
||||||
unsigned char letter = text[charNum];
|
unsigned char letter = text[charNum];
|
||||||
|
|
||||||
|
if(letter == '\n')
|
||||||
|
{
|
||||||
|
y += (float)getHeight();
|
||||||
|
x = offsetX;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(letter < 32 || letter >= 128)
|
if(letter < 32 || letter >= 128)
|
||||||
letter = 127; //print [X] if character is not standard ASCII
|
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;
|
x += charData[letter].advX * fontScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextCache* cache = new TextCache(vertCount, vert, colors, this);
|
TextCache* cache = new TextCache(vertCount, vert, colors);
|
||||||
if(color != 0x00000000)
|
if(color != 0x00000000)
|
||||||
cache->setColor(color);
|
cache->setColor(color);
|
||||||
|
|
||||||
return cache;
|
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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/Font.h
11
src/Font.h
|
@ -53,6 +53,8 @@ public:
|
||||||
void drawText(std::string text, const Eigen::Vector2f& offset, unsigned int color);
|
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.
|
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);
|
void drawWrappedText(std::string text, const Eigen::Vector2f& offset, float xLen, unsigned int color);
|
||||||
Eigen::Vector2f sizeWrappedText(std::string text, float xLen) const;
|
Eigen::Vector2f sizeWrappedText(std::string text, float xLen) const;
|
||||||
|
|
||||||
|
@ -102,13 +104,12 @@ public:
|
||||||
|
|
||||||
void setColor(unsigned int color);
|
void setColor(unsigned int color);
|
||||||
|
|
||||||
TextCache(int verts, Vertex* v, GLubyte* c, Font* f);
|
TextCache(int verts, Vertex* v, GLubyte* c);
|
||||||
~TextCache();
|
~TextCache();
|
||||||
|
|
||||||
const int vertCount;
|
int vertCount;
|
||||||
const Vertex* verts;
|
Vertex* verts;
|
||||||
const GLubyte* colors;
|
GLubyte* colors;
|
||||||
const Font* sourceFont;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,27 +20,26 @@ TextComponent::TextComponent(Window* window, const std::string& text, std::share
|
||||||
void TextComponent::onSizeChanged()
|
void TextComponent::onSizeChanged()
|
||||||
{
|
{
|
||||||
mAutoCalcExtent << (getSize().x() == 0), (getSize().y() == 0);
|
mAutoCalcExtent << (getSize().x() == 0), (getSize().y() == 0);
|
||||||
calculateExtent();
|
onTextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextComponent::setFont(std::shared_ptr<Font> font)
|
void TextComponent::setFont(std::shared_ptr<Font> font)
|
||||||
{
|
{
|
||||||
mFont = font;
|
mFont = font;
|
||||||
|
onTextChanged();
|
||||||
calculateExtent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextComponent::setColor(unsigned int color)
|
void TextComponent::setColor(unsigned int color)
|
||||||
{
|
{
|
||||||
mColor = color;
|
mColor = color;
|
||||||
mOpacity = mColor & 0x000000FF;
|
mOpacity = mColor & 0x000000FF;
|
||||||
|
onTextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextComponent::setText(const std::string& text)
|
void TextComponent::setText(const std::string& text)
|
||||||
{
|
{
|
||||||
mText = text;
|
mText = text;
|
||||||
|
onTextChanged();
|
||||||
calculateExtent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextComponent::setCentered(bool center)
|
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 textSize = font->sizeWrappedText(mText, getSize().x());
|
||||||
Eigen::Vector2f pos((getSize().x() - textSize.x()) / 2, 0);
|
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{
|
}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)
|
void TextComponent::setValue(const std::string& value)
|
||||||
{
|
{
|
||||||
setText(value);
|
setText(value);
|
||||||
|
|
|
@ -26,10 +26,13 @@ private:
|
||||||
|
|
||||||
void calculateExtent();
|
void calculateExtent();
|
||||||
|
|
||||||
|
void onTextChanged();
|
||||||
|
|
||||||
unsigned int mColor;
|
unsigned int mColor;
|
||||||
std::shared_ptr<Font> mFont;
|
std::shared_ptr<Font> mFont;
|
||||||
Eigen::Matrix<bool, 1, 2> mAutoCalcExtent;
|
Eigen::Matrix<bool, 1, 2> mAutoCalcExtent;
|
||||||
std::string mText;
|
std::string mText;
|
||||||
|
std::unique_ptr<TextCache> mTextCache;
|
||||||
bool mCentered;
|
bool mCentered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -69,11 +69,16 @@ void TextEditComponent::textInput(const char* text)
|
||||||
|
|
||||||
void TextEditComponent::onTextChanged()
|
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)
|
if(mAllowResize)
|
||||||
{
|
{
|
||||||
float y = getFont()->sizeWrappedText(mText, mSize.x()).y();
|
float y = f->sizeText(wrappedText).y();
|
||||||
if(y == 0)
|
if(y == 0)
|
||||||
y = (float)getFont()->getHeight();
|
y = (float)f->getHeight();
|
||||||
|
|
||||||
setSize(mSize.x(), y);
|
setSize(mSize.x(), y);
|
||||||
}
|
}
|
||||||
|
@ -96,8 +101,11 @@ void TextEditComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
|
|
||||||
Renderer::setMatrix(trans);
|
Renderer::setMatrix(trans);
|
||||||
|
|
||||||
|
if(mTextCache != NULL)
|
||||||
|
{
|
||||||
std::shared_ptr<Font> f = getFont();
|
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()
|
std::shared_ptr<Font> TextEditComponent::getFont()
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "GuiBox.h"
|
#include "GuiBox.h"
|
||||||
|
|
||||||
class Font;
|
class Font;
|
||||||
|
class TextCache;
|
||||||
|
|
||||||
class TextEditComponent : public GuiComponent
|
class TextEditComponent : public GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -33,4 +34,6 @@ private:
|
||||||
std::shared_ptr<Font> getFont();
|
std::shared_ptr<Font> getFont();
|
||||||
|
|
||||||
GuiBox mBox;
|
GuiBox mBox;
|
||||||
|
|
||||||
|
std::unique_ptr<TextCache> mTextCache;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue