mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-17 22:55:38 +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
130
src/Font.cpp
130
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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
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);
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue