mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-17 22:55:38 +00:00
Some refactoring to the Font class.
This commit is contained in:
parent
b2193c3bf5
commit
4cf206d3eb
|
@ -7,11 +7,7 @@
|
||||||
#include "../Log.h"
|
#include "../Log.h"
|
||||||
#include "../Util.h"
|
#include "../Util.h"
|
||||||
|
|
||||||
FT_Library Font::sLibrary;
|
FT_Library Font::sLibrary = NULL;
|
||||||
bool Font::libraryInitialized = false;
|
|
||||||
|
|
||||||
int Font::getDpiX() { return 96; }
|
|
||||||
int Font::getDpiY() { return 96; }
|
|
||||||
|
|
||||||
int Font::getSize() const { return mSize; }
|
int Font::getSize() const { return mSize; }
|
||||||
|
|
||||||
|
@ -19,20 +15,20 @@ std::map< std::pair<std::string, int>, std::weak_ptr<Font> > Font::sFontMap;
|
||||||
|
|
||||||
void Font::initLibrary()
|
void Font::initLibrary()
|
||||||
{
|
{
|
||||||
|
assert(sLibrary == NULL);
|
||||||
if(FT_Init_FreeType(&sLibrary))
|
if(FT_Init_FreeType(&sLibrary))
|
||||||
{
|
{
|
||||||
|
sLibrary = NULL;
|
||||||
LOG(LogError) << "Error initializing FreeType!";
|
LOG(LogError) << "Error initializing FreeType!";
|
||||||
}else{
|
|
||||||
libraryInitialized = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Font::getMemUsage() const
|
size_t Font::getMemUsage() const
|
||||||
{
|
{
|
||||||
if(!textureID)
|
if(!mTextureID)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return textureWidth * textureHeight * 4;
|
return mTextureWidth * mTextureHeight * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Font::getTotalMemUsage()
|
size_t Font::getTotalMemUsage()
|
||||||
|
@ -55,7 +51,7 @@ size_t Font::getTotalMemUsage()
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(int size, const std::string& path) : fontScale(1.0f), mSize(size), mPath(path)
|
Font::Font(int size, const std::string& path) : mFontScale(1.0f), mSize(size), mPath(path), mTextureID(0)
|
||||||
{
|
{
|
||||||
reload(ResourceManager::getInstance());
|
reload(ResourceManager::getInstance());
|
||||||
}
|
}
|
||||||
|
@ -93,9 +89,11 @@ std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
||||||
|
|
||||||
void Font::init(ResourceData data)
|
void Font::init(ResourceData data)
|
||||||
{
|
{
|
||||||
if(!libraryInitialized)
|
if(sLibrary == NULL)
|
||||||
initLibrary();
|
initLibrary();
|
||||||
|
|
||||||
|
deinit();
|
||||||
|
|
||||||
mMaxGlyphHeight = 0;
|
mMaxGlyphHeight = 0;
|
||||||
|
|
||||||
buildAtlas(data);
|
buildAtlas(data);
|
||||||
|
@ -103,51 +101,33 @@ void Font::init(ResourceData data)
|
||||||
|
|
||||||
void Font::deinit()
|
void Font::deinit()
|
||||||
{
|
{
|
||||||
if(textureID)
|
if(mTextureID)
|
||||||
{
|
{
|
||||||
glDeleteTextures(1, &textureID);
|
glDeleteTextures(1, &mTextureID);
|
||||||
textureID = 0;
|
mTextureID = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::buildAtlas(ResourceData data)
|
void Font::buildAtlas(ResourceData data)
|
||||||
{
|
{
|
||||||
|
assert(mSize > 0);
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
if(FT_New_Memory_Face(sLibrary, data.ptr.get(), data.length, 0, &face))
|
if(FT_New_Memory_Face(sLibrary, data.ptr.get(), data.length, 0, &face))
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Error creating font face! (mPath: " << mPath << ", data.length: " << data.length << ")";
|
LOG(LogError) << "Error creating font face! (mPath: " << mPath << ", data.length: " << data.length << ")";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FT_Set_Char_Size(face, 0, size * 64, getDpiX(), getDpiY());
|
|
||||||
FT_Set_Pixel_Sizes(face, 0, mSize);
|
FT_Set_Pixel_Sizes(face, 0, mSize);
|
||||||
|
|
||||||
//find the size we should use
|
// hardcoded texture size right now
|
||||||
FT_GlyphSlot g = face->glyph;
|
mTextureWidth = 2048;
|
||||||
int w = 0;
|
mTextureHeight = 512;
|
||||||
int h = 0;
|
|
||||||
|
|
||||||
/*for(int i = 32; i < 128; i++)
|
// create the texture
|
||||||
{
|
glGenTextures(1, &mTextureID);
|
||||||
if(FT_Load_Char(face, i, FT_LOAD_RENDER))
|
glBindTexture(GL_TEXTURE_2D, mTextureID);
|
||||||
{
|
|
||||||
fprintf(stderr, "Loading character %c failed!\n", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
w += g->bitmap.width;
|
|
||||||
h = std::max(h, g->bitmap.rows);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//the max size (GL_MAX_TEXTURE_SIZE) is like 3300
|
|
||||||
w = 2048;
|
|
||||||
h = 512;
|
|
||||||
|
|
||||||
textureWidth = w;
|
|
||||||
textureHeight = h;
|
|
||||||
|
|
||||||
//create the texture
|
|
||||||
glGenTextures(1, &textureID);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
|
||||||
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
@ -158,33 +138,19 @@ void Font::buildAtlas(ResourceData data)
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mTextureWidth, mTextureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
//copy the glyphs into the texture
|
//copy the glyphs into the texture
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
int maxHeight = 0;
|
int maxHeight = 0;
|
||||||
|
FT_GlyphSlot g = face->glyph;
|
||||||
for(int i = 32; i < 128; i++)
|
for(int i = 32; i < 128; i++)
|
||||||
{
|
{
|
||||||
if(FT_Load_Char(face, i, FT_LOAD_RENDER))
|
if(FT_Load_Char(face, i, FT_LOAD_RENDER))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//prints rendered texture to the console
|
if(x + g->bitmap.width >= mTextureWidth)
|
||||||
/*std::cout << "uploading at x: " << x << ", w: " << g->bitmap.width << " h: " << g->bitmap.rows << "\n";
|
|
||||||
|
|
||||||
for(int k = 0; k < g->bitmap.rows; k++)
|
|
||||||
{
|
|
||||||
for(int j = 0; j < g->bitmap.width; j++)
|
|
||||||
{
|
|
||||||
if(g->bitmap.buffer[g->bitmap.width * k + j])
|
|
||||||
std::cout << ".";
|
|
||||||
else
|
|
||||||
std::cout << " ";
|
|
||||||
}
|
|
||||||
std::cout << "\n";
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(x + g->bitmap.width >= textureWidth)
|
|
||||||
{
|
{
|
||||||
x = 0;
|
x = 0;
|
||||||
y += maxHeight + 1; //leave one pixel of space between glyphs
|
y += maxHeight + 1; //leave one pixel of space between glyphs
|
||||||
|
@ -197,17 +163,17 @@ void Font::buildAtlas(ResourceData data)
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||||
|
|
||||||
|
|
||||||
charData[i].texX = x;
|
mCharData[i].texX = x;
|
||||||
charData[i].texY = y;
|
mCharData[i].texY = y;
|
||||||
charData[i].texW = g->bitmap.width;
|
mCharData[i].texW = g->bitmap.width;
|
||||||
charData[i].texH = g->bitmap.rows;
|
mCharData[i].texH = g->bitmap.rows;
|
||||||
charData[i].advX = (float)g->metrics.horiAdvance / 64.0f;
|
mCharData[i].advX = (float)g->metrics.horiAdvance / 64.0f;
|
||||||
charData[i].advY = (float)g->metrics.vertAdvance / 64.0f;
|
mCharData[i].advY = (float)g->metrics.vertAdvance / 64.0f;
|
||||||
charData[i].bearingX = (float)g->metrics.horiBearingX / 64.0f;
|
mCharData[i].bearingX = (float)g->metrics.horiBearingX / 64.0f;
|
||||||
charData[i].bearingY = (float)g->metrics.horiBearingY / 64.0f;
|
mCharData[i].bearingY = (float)g->metrics.horiBearingY / 64.0f;
|
||||||
|
|
||||||
if(charData[i].texH > mMaxGlyphHeight)
|
if(mCharData[i].texH > mMaxGlyphHeight)
|
||||||
mMaxGlyphHeight = charData[i].texH;
|
mMaxGlyphHeight = mCharData[i].texH;
|
||||||
|
|
||||||
x += g->bitmap.width + 1; //leave one pixel of space between glyphs
|
x += g->bitmap.width + 1; //leave one pixel of space between glyphs
|
||||||
}
|
}
|
||||||
|
@ -216,13 +182,13 @@ void Font::buildAtlas(ResourceData data)
|
||||||
|
|
||||||
FT_Done_Face(face);
|
FT_Done_Face(face);
|
||||||
|
|
||||||
if((y + maxHeight) >= textureHeight)
|
if((y + maxHeight) >= mTextureHeight)
|
||||||
{
|
{
|
||||||
//failed to create a proper font texture
|
//failed to create a proper font texture
|
||||||
LOG(LogWarning) << "Font \"" << mPath << "\" with size " << mSize << " exceeded max texture size! Trying again...";
|
LOG(LogWarning) << "Font \"" << mPath << "\" with size " << mSize << " exceeded max texture size! Trying again...";
|
||||||
//try a 3/4th smaller size and redo initialization
|
//try a 3/4th smaller size and redo initialization
|
||||||
fontScale *= 1.25f;
|
mFontScale *= 1.25f;
|
||||||
mSize = (int)(mSize * (1.0f / fontScale));
|
mSize = (int)(mSize * (1.0f / mFontScale));
|
||||||
deinit();
|
deinit();
|
||||||
init(data);
|
init(data);
|
||||||
}
|
}
|
||||||
|
@ -230,7 +196,7 @@ void Font::buildAtlas(ResourceData data)
|
||||||
|
|
||||||
void Font::renderTextCache(TextCache* cache)
|
void Font::renderTextCache(TextCache* cache)
|
||||||
{
|
{
|
||||||
if(!textureID)
|
if(!mTextureID)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Error - tried to draw with Font that has no texture loaded!";
|
LOG(LogError) << "Error - tried to draw with Font that has no texture loaded!";
|
||||||
return;
|
return;
|
||||||
|
@ -242,7 +208,7 @@ void Font::renderTextCache(TextCache* cache)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
glBindTexture(GL_TEXTURE_2D, mTextureID);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
@ -265,12 +231,12 @@ void Font::renderTextCache(TextCache* cache)
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
Eigen::Vector2f Font::sizeText(std::string text) const
|
Eigen::Vector2f Font::sizeText(std::string text, float lineSpacing) const
|
||||||
{
|
{
|
||||||
float lineWidth = 0.0f;
|
float lineWidth = 0.0f;
|
||||||
float highestWidth = 0.0f;
|
float highestWidth = 0.0f;
|
||||||
|
|
||||||
float y = getHeight();
|
float y = getHeight(lineSpacing);
|
||||||
|
|
||||||
for(unsigned int i = 0; i < text.length(); i++)
|
for(unsigned int i = 0; i < text.length(); i++)
|
||||||
{
|
{
|
||||||
|
@ -282,13 +248,13 @@ Eigen::Vector2f Font::sizeText(std::string text) const
|
||||||
highestWidth = lineWidth;
|
highestWidth = lineWidth;
|
||||||
|
|
||||||
lineWidth = 0.0f;
|
lineWidth = 0.0f;
|
||||||
y += getHeight();
|
y += getHeight(lineSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(letter < 32 || letter >= 128)
|
if(letter < 32 || letter >= 128)
|
||||||
letter = 127;
|
letter = 127;
|
||||||
|
|
||||||
lineWidth += charData[letter].advX * fontScale;
|
lineWidth += mCharData[letter].advX * mFontScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lineWidth > highestWidth)
|
if(lineWidth > highestWidth)
|
||||||
|
@ -297,14 +263,14 @@ Eigen::Vector2f Font::sizeText(std::string text) const
|
||||||
return Eigen::Vector2f(highestWidth, y);
|
return Eigen::Vector2f(highestWidth, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Font::getHeight() const
|
float Font::getHeight(float lineSpacing) const
|
||||||
{
|
{
|
||||||
return mMaxGlyphHeight * 1.5f * fontScale;
|
return mMaxGlyphHeight * lineSpacing * mFontScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Font::getLetterHeight() const
|
float Font::getLetterHeight() const
|
||||||
{
|
{
|
||||||
return charData['S'].texH * fontScale;
|
return mCharData['S'].texH * mFontScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
//the worst algorithm ever written
|
//the worst algorithm ever written
|
||||||
|
@ -368,13 +334,13 @@ std::string Font::wrapText(std::string text, float xLen) const
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen) const
|
Eigen::Vector2f Font::sizeWrappedText(std::string text, float xLen, float lineSpacing) const
|
||||||
{
|
{
|
||||||
text = wrapText(text, xLen);
|
text = wrapText(text, xLen);
|
||||||
return sizeText(text);
|
return sizeText(text, lineSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
Eigen::Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, int cursor) const
|
Eigen::Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, int cursor, float lineSpacing) const
|
||||||
{
|
{
|
||||||
std::string wrappedText = wrapText(text, xLen);
|
std::string wrappedText = wrapText(text, xLen);
|
||||||
|
|
||||||
|
@ -393,7 +359,7 @@ Eigen::Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, i
|
||||||
//this is where the wordwrap inserted a newline
|
//this is where the wordwrap inserted a newline
|
||||||
//reset lineWidth and increment y, but don't consume a cursor character
|
//reset lineWidth and increment y, but don't consume a cursor character
|
||||||
lineWidth = 0.0f;
|
lineWidth = 0.0f;
|
||||||
y += getHeight();
|
y += getHeight(lineSpacing);
|
||||||
|
|
||||||
wrapOffset++;
|
wrapOffset++;
|
||||||
i--;
|
i--;
|
||||||
|
@ -403,14 +369,14 @@ Eigen::Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, i
|
||||||
if(letter == '\n')
|
if(letter == '\n')
|
||||||
{
|
{
|
||||||
lineWidth = 0.0f;
|
lineWidth = 0.0f;
|
||||||
y += getHeight();
|
y += getHeight(lineSpacing);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(letter < 32 || letter >= 128)
|
if(letter < 32 || letter >= 128)
|
||||||
letter = 127;
|
letter = 127;
|
||||||
|
|
||||||
lineWidth += charData[letter].advX * fontScale;
|
lineWidth += mCharData[letter].advX * mFontScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Eigen::Vector2f(lineWidth, y);
|
return Eigen::Vector2f(lineWidth, y);
|
||||||
|
@ -420,9 +386,9 @@ Eigen::Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, i
|
||||||
//TextCache
|
//TextCache
|
||||||
//=============================================================================================================
|
//=============================================================================================================
|
||||||
|
|
||||||
TextCache* Font::buildWrappedTextCache(const std::string& text, const Eigen::Vector2f& offset, float xLen, Alignment alignment, unsigned int color)
|
TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset, unsigned int color, float xLen, Alignment alignment, float lineSpacing)
|
||||||
{
|
{
|
||||||
if(!textureID)
|
if(!mTextureID)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Error - tried to build TextCache with Font that has no texture loaded!";
|
LOG(LogError) << "Error - tried to build TextCache with Font that has no texture loaded!";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -430,12 +396,14 @@ TextCache* Font::buildWrappedTextCache(const std::string& text, const Eigen::Vec
|
||||||
|
|
||||||
// todo
|
// todo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextCache* Font::buildTextCache(const std::string& text, float offsetX, float offsetY, unsigned int color)
|
TextCache* Font::buildTextCache(const std::string& text, float offsetX, float offsetY, unsigned int color)
|
||||||
{
|
{
|
||||||
if(!textureID)
|
if(!mTextureID)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Error - tried to build TextCache with Font that has no texture loaded!";
|
LOG(LogError) << "Error - tried to build TextCache with Font that has no texture loaded!";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -446,13 +414,18 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of
|
||||||
TextCache::Vertex* vert = new TextCache::Vertex[vertCount];
|
TextCache::Vertex* vert = new TextCache::Vertex[vertCount];
|
||||||
GLubyte* colors = new GLubyte[vertCount * 4];
|
GLubyte* colors = new GLubyte[vertCount * 4];
|
||||||
|
|
||||||
|
// all glyph sizes/texture offsets are in pixels,
|
||||||
|
// so the only rounding we have to worry about is the offset
|
||||||
|
offsetX = round(offsetX);
|
||||||
|
offsetY = round(offsetY);
|
||||||
|
|
||||||
//texture atlas width/height
|
//texture atlas width/height
|
||||||
float tw = (float)textureWidth;
|
float tw = (float)mTextureWidth;
|
||||||
float th = (float)textureHeight;
|
float th = (float)mTextureHeight;
|
||||||
|
|
||||||
float x = offsetX;
|
float x = offsetX;
|
||||||
|
|
||||||
float yTop = charData['S'].bearingY * fontScale;
|
float yTop = mCharData['S'].bearingY * mFontScale;
|
||||||
float yBot = getHeight();
|
float yBot = getHeight();
|
||||||
float y = offsetY + (yBot + yTop)/2.0f;
|
float y = offsetY + (yBot + yTop)/2.0f;
|
||||||
|
|
||||||
|
@ -473,14 +446,14 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of
|
||||||
letter = 127; //print [X] if character is not standard ASCII
|
letter = 127; //print [X] if character is not standard ASCII
|
||||||
|
|
||||||
//the glyph might not start at the cursor position, but needs to be shifted a bit
|
//the glyph might not start at the cursor position, but needs to be shifted a bit
|
||||||
const float glyphStartX = x + charData[letter].bearingX * fontScale;
|
const float glyphStartX = x + mCharData[letter].bearingX * mFontScale;
|
||||||
//order is bottom left, top right, top left
|
//order is bottom left, top right, top left
|
||||||
vert[i + 0].pos << glyphStartX, y + (charData[letter].texH - charData[letter].bearingY) * fontScale;
|
vert[i + 0].pos << glyphStartX, y + (mCharData[letter].texH - mCharData[letter].bearingY) * mFontScale;
|
||||||
vert[i + 1].pos << glyphStartX + charData[letter].texW * fontScale, y - charData[letter].bearingY * fontScale;
|
vert[i + 1].pos << glyphStartX + mCharData[letter].texW * mFontScale, y - mCharData[letter].bearingY * mFontScale;
|
||||||
vert[i + 2].pos << glyphStartX, vert[i + 1].pos.y();
|
vert[i + 2].pos << glyphStartX, vert[i + 1].pos.y();
|
||||||
|
|
||||||
Eigen::Vector2i charTexCoord(charData[letter].texX, charData[letter].texY);
|
Eigen::Vector2i charTexCoord(mCharData[letter].texX, mCharData[letter].texY);
|
||||||
Eigen::Vector2i charTexSize(charData[letter].texW, charData[letter].texH);
|
Eigen::Vector2i charTexSize(mCharData[letter].texW, mCharData[letter].texH);
|
||||||
|
|
||||||
vert[i + 0].tex << charTexCoord.x() / tw, (charTexCoord.y() + charTexSize.y()) / th;
|
vert[i + 0].tex << charTexCoord.x() / tw, (charTexCoord.y() + charTexSize.y()) / th;
|
||||||
vert[i + 1].tex << (charTexCoord.x() + charTexSize.x()) / tw, charTexCoord.y() / th;
|
vert[i + 1].tex << (charTexCoord.x() + charTexSize.x()) / tw, charTexCoord.y() / th;
|
||||||
|
@ -497,13 +470,7 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of
|
||||||
vert[i + 5].tex[0] = vert[i + 1].tex.x();
|
vert[i + 5].tex[0] = vert[i + 1].tex.x();
|
||||||
vert[i + 5].tex[1] = vert[i + 0].tex.y();
|
vert[i + 5].tex[1] = vert[i + 0].tex.y();
|
||||||
|
|
||||||
// round
|
x += mCharData[letter].advX * mFontScale;
|
||||||
for(int j = 0; j < 6; j++)
|
|
||||||
{
|
|
||||||
vert[i + j].pos = roundVector(vert[i + j].pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
x += charData[letter].advX * fontScale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextCache::CacheMetrics metrics = { sizeText(text) };
|
TextCache::CacheMetrics metrics = { sizeText(text) };
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#ifndef _FONT_H_
|
#pragma once
|
||||||
#define _FONT_H_
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../platform.h"
|
#include "../platform.h"
|
||||||
|
@ -35,38 +34,18 @@ public:
|
||||||
|
|
||||||
static std::shared_ptr<Font> get(int size, const std::string& path = getDefaultPath());
|
static std::shared_ptr<Font> get(int size, const std::string& path = getDefaultPath());
|
||||||
|
|
||||||
~Font();
|
virtual ~Font();
|
||||||
|
|
||||||
FT_Face face;
|
Eigen::Vector2f sizeText(std::string text, float lineSpacing = 1.5f) const; // Returns the expected size of a string when rendered. Extra spacing is applied to the Y axis.
|
||||||
|
|
||||||
//contains sizing information for every glyph.
|
|
||||||
struct charPosData {
|
|
||||||
int texX;
|
|
||||||
int texY;
|
|
||||||
int texW;
|
|
||||||
int texH;
|
|
||||||
|
|
||||||
float advX; //!<The horizontal distance to advance to the next character after this one
|
|
||||||
float advY; //!<The vertical distance to advance to the next character after this one
|
|
||||||
|
|
||||||
float bearingX; //!<The horizontal distance from the cursor to the start of the character
|
|
||||||
float bearingY; //!<The vertical distance from the cursor to the start of the character
|
|
||||||
};
|
|
||||||
|
|
||||||
charPosData charData[128];
|
|
||||||
|
|
||||||
GLuint textureID;
|
|
||||||
|
|
||||||
Eigen::Vector2f sizeText(std::string text) const; // Returns the expected size of a string when rendered. Extra spacing is applied to the Y axis.
|
|
||||||
TextCache* buildTextCache(const std::string& text, float offsetX, float offsetY, unsigned int color);
|
TextCache* buildTextCache(const std::string& text, float offsetX, float offsetY, unsigned int color);
|
||||||
TextCache* buildWrappedTextCache(const std::string& text, const Eigen::Vector2f& offset, float xLen, Alignment alignment, unsigned int color);
|
TextCache* buildTextCache(const std::string& text, Eigen::Vector2f offset, unsigned int color, float xLen, Alignment alignment = ALIGN_LEFT, float lineSpacing = 1.5f);
|
||||||
void renderTextCache(TextCache* cache);
|
void renderTextCache(TextCache* cache);
|
||||||
|
|
||||||
std::string wrapText(std::string text, float xLen) const; // Inserts newlines into text to make it wrap properly.
|
std::string wrapText(std::string text, float xLen) const; // Inserts newlines into text to make it wrap properly.
|
||||||
Eigen::Vector2f sizeWrappedText(std::string text, float xLen) const; // Returns the expected size of a string after wrapping is applied.
|
Eigen::Vector2f sizeWrappedText(std::string text, float xLen, float lineSpacing = 1.5f) const; // Returns the expected size of a string after wrapping is applied.
|
||||||
Eigen::Vector2f getWrappedTextCursorOffset(std::string text, float xLen, int cursor) const; // Returns the position of of the cursor after moving "cursor" characters.
|
Eigen::Vector2f getWrappedTextCursorOffset(std::string text, float xLen, int cursor, float lineSpacing = 1.5f) const; // Returns the position of of the cursor after moving "cursor" characters.
|
||||||
|
|
||||||
float getHeight() const;
|
float getHeight(float lineSpacing = 1.5f) const;
|
||||||
float getLetterHeight() const;
|
float getLetterHeight() const;
|
||||||
|
|
||||||
void unload(std::shared_ptr<ResourceManager>& rm) override;
|
void unload(std::shared_ptr<ResourceManager>& rm) override;
|
||||||
|
@ -83,12 +62,7 @@ public:
|
||||||
static size_t getTotalMemUsage(); // returns an approximation of total VRAM used by font textures (in bytes)
|
static size_t getTotalMemUsage(); // returns an approximation of total VRAM used by font textures (in bytes)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int getDpiX();
|
|
||||||
static int getDpiY();
|
|
||||||
|
|
||||||
static FT_Library sLibrary;
|
static FT_Library sLibrary;
|
||||||
static bool libraryInitialized;
|
|
||||||
|
|
||||||
static std::map< std::pair<std::string, int>, std::weak_ptr<Font> > sFontMap;
|
static std::map< std::pair<std::string, int>, std::weak_ptr<Font> > sFontMap;
|
||||||
|
|
||||||
Font(int size, const std::string& path);
|
Font(int size, const std::string& path);
|
||||||
|
@ -98,18 +72,39 @@ private:
|
||||||
|
|
||||||
void buildAtlas(ResourceData data); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128.
|
void buildAtlas(ResourceData data); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128.
|
||||||
|
|
||||||
int textureWidth; //OpenGL texture width
|
//contains sizing information for every glyph.
|
||||||
int textureHeight; //OpenGL texture height
|
struct CharData
|
||||||
|
{
|
||||||
|
int texX;
|
||||||
|
int texY;
|
||||||
|
int texW;
|
||||||
|
int texH;
|
||||||
|
|
||||||
|
float advX; //!<The horizontal distance to advance to the next character after this one
|
||||||
|
float advY; //!<The vertical distance to advance to the next character after this one
|
||||||
|
|
||||||
|
float bearingX; //!<The horizontal distance from the cursor to the start of the character
|
||||||
|
float bearingY; //!<The vertical distance from the cursor to the start of the character
|
||||||
|
};
|
||||||
|
|
||||||
|
CharData mCharData[128];
|
||||||
|
|
||||||
|
GLuint mTextureID;
|
||||||
|
|
||||||
|
int mTextureWidth; //OpenGL texture width
|
||||||
|
int mTextureHeight; //OpenGL texture height
|
||||||
int mMaxGlyphHeight;
|
int mMaxGlyphHeight;
|
||||||
float fontScale; //!<Font scale factor. It is > 1.0 if the font would be to big for the texture
|
float mFontScale; //!<Font scale factor. It is > 1.0 if the font would be to big for the texture
|
||||||
|
|
||||||
int mSize;
|
int mSize;
|
||||||
const std::string mPath;
|
const std::string mPath;
|
||||||
|
|
||||||
|
friend TextCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used to store a sort of "pre-rendered" string.
|
// Used to store a sort of "pre-rendered" string.
|
||||||
// When a TextCache is constructed (Font::buildTextCache()), the vertices and texture coordinates of the string are calculated and stored in the TextCache object.
|
// When a TextCache is constructed (Font::buildTextCache()), the vertices and texture coordinates of the string are calculated and stored in the TextCache object.
|
||||||
// Rendering a TextCache (Font::renderTextCache) every frame is MUCH faster than calling Font::drawText() and its variants.
|
// Rendering a previously constructed TextCache (Font::renderTextCache) every frame is MUCH faster than rebuilding one every frame.
|
||||||
// Keep in mind you still need the Font object to render a TextCache (as the Font holds the OpenGL texture), and if a Font changes your TextCache may become invalid.
|
// Keep in mind you still need the Font object to render a TextCache (as the Font holds the OpenGL texture), and if a Font changes your TextCache may become invalid.
|
||||||
class TextCache
|
class TextCache
|
||||||
{
|
{
|
||||||
|
@ -134,5 +129,3 @@ public:
|
||||||
Vertex* verts;
|
Vertex* verts;
|
||||||
GLubyte* colors;
|
GLubyte* colors;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue