mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-02-18 04:45:39 +00:00
Fixed deinitialization/reinitialization for fonts.
This commit is contained in:
parent
2b22e1fe0b
commit
9f040f4c71
|
@ -183,7 +183,9 @@ Font::Font(int size, const std::string& path) : mSize(size), mPath(path)
|
||||||
if(!sLibrary)
|
if(!sLibrary)
|
||||||
initLibrary();
|
initLibrary();
|
||||||
|
|
||||||
reload(ResourceManager::getInstance());
|
// always initialize ASCII characters
|
||||||
|
for(UnicodeChar i = 32; i < 128; i++)
|
||||||
|
getGlyph(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::~Font()
|
Font::~Font()
|
||||||
|
@ -193,12 +195,12 @@ Font::~Font()
|
||||||
|
|
||||||
void Font::reload(std::shared_ptr<ResourceManager>& rm)
|
void Font::reload(std::shared_ptr<ResourceManager>& rm)
|
||||||
{
|
{
|
||||||
reloadGlyphTextures();
|
rebuildTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::unload(std::shared_ptr<ResourceManager>& rm)
|
void Font::unload(std::shared_ptr<ResourceManager>& rm)
|
||||||
{
|
{
|
||||||
freeTextures();
|
unloadTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
||||||
|
@ -219,24 +221,25 @@ std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::reloadGlyphTextures()
|
void Font::unloadTextures()
|
||||||
{
|
|
||||||
// freeTextures(); // make sure we don't leak
|
|
||||||
|
|
||||||
for(UnicodeChar i = 32; i < 128; i++)
|
|
||||||
getGlyph(i);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void Font::freeTextures()
|
|
||||||
{
|
{
|
||||||
for(auto it = mTextures.begin(); it != mTextures.end(); it++)
|
for(auto it = mTextures.begin(); it != mTextures.end(); it++)
|
||||||
{
|
{
|
||||||
glDeleteTextures(1, &it->textureId);
|
it->deinitTexture();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mTextures.clear();
|
Font::FontTexture::FontTexture()
|
||||||
|
{
|
||||||
|
textureId = 0;
|
||||||
|
textureSize << 2048, 512;
|
||||||
|
writePos = Eigen::Vector2i::Zero();
|
||||||
|
rowHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Font::FontTexture::~FontTexture()
|
||||||
|
{
|
||||||
|
deinitTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Font::FontTexture::findEmpty(const Eigen::Vector2i& size, Eigen::Vector2i& cursor_out)
|
bool Font::FontTexture::findEmpty(const Eigen::Vector2i& size, Eigen::Vector2i& cursor_out)
|
||||||
|
@ -269,6 +272,34 @@ bool Font::FontTexture::findEmpty(const Eigen::Vector2i& size, Eigen::Vector2i&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Font::FontTexture::initTexture()
|
||||||
|
{
|
||||||
|
assert(textureId == 0);
|
||||||
|
|
||||||
|
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_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, textureSize.x(), textureSize.y(), 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::FontTexture::deinitTexture()
|
||||||
|
{
|
||||||
|
if(textureId != 0)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &textureId);
|
||||||
|
textureId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Font::getTextureForNewGlyph(const Eigen::Vector2i& glyphSize, FontTexture*& tex_out, Eigen::Vector2i& cursor_out)
|
void Font::getTextureForNewGlyph(const Eigen::Vector2i& glyphSize, FontTexture*& tex_out, Eigen::Vector2i& cursor_out)
|
||||||
{
|
{
|
||||||
if(mTextures.size())
|
if(mTextures.size())
|
||||||
|
@ -285,21 +316,8 @@ void Font::getTextureForNewGlyph(const Eigen::Vector2i& glyphSize, FontTexture*&
|
||||||
// make a new one
|
// make a new one
|
||||||
mTextures.push_back(FontTexture());
|
mTextures.push_back(FontTexture());
|
||||||
tex_out = &mTextures.back();
|
tex_out = &mTextures.back();
|
||||||
|
tex_out->initTexture();
|
||||||
glGenTextures(1, &tex_out->textureId);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, tex_out->textureId);
|
|
||||||
|
|
||||||
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_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_out->textureSize.x(), tex_out->textureSize.y(), 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
|
|
||||||
bool ok = tex_out->findEmpty(glyphSize, cursor_out);
|
bool ok = tex_out->findEmpty(glyphSize, cursor_out);
|
||||||
if(!ok)
|
if(!ok)
|
||||||
{
|
{
|
||||||
|
@ -375,6 +393,50 @@ Font::Glyph* Font::getGlyph(UnicodeChar id)
|
||||||
return &glyph;
|
return &glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// completely recreate the texture data for all textures based on mGlyphs information
|
||||||
|
void Font::rebuildTextures()
|
||||||
|
{
|
||||||
|
// recreate OpenGL textures
|
||||||
|
for(auto it = mTextures.begin(); it != mTextures.end(); it++)
|
||||||
|
{
|
||||||
|
it->initTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the font file
|
||||||
|
ResourceData data = ResourceManager::getInstance()->getFileData(mPath);
|
||||||
|
|
||||||
|
// load the font with FT
|
||||||
|
FT_Face face;
|
||||||
|
FT_New_Memory_Face(sLibrary, data.ptr.get(), data.length, 0, &face);
|
||||||
|
|
||||||
|
// set the size
|
||||||
|
FT_Set_Pixel_Sizes(face, 0, mSize);
|
||||||
|
|
||||||
|
FT_GlyphSlot glyphSlot = face->glyph;
|
||||||
|
|
||||||
|
// reupload the texture data
|
||||||
|
for(auto it = mGlyphMap.begin(); it != mGlyphMap.end(); it++)
|
||||||
|
{
|
||||||
|
// load the glyph bitmap through FT
|
||||||
|
FT_Load_Char(face, it->first, FT_LOAD_RENDER);
|
||||||
|
|
||||||
|
FontTexture* tex = it->second.texture;
|
||||||
|
|
||||||
|
// find the position/size
|
||||||
|
Eigen::Vector2i cursor(it->second.texPos.x() * tex->textureSize.x(), it->second.texPos.y() * tex->textureSize.y());
|
||||||
|
Eigen::Vector2i glyphSize(it->second.texSize.x() * tex->textureSize.x(), it->second.texSize.y() * tex->textureSize.y());
|
||||||
|
|
||||||
|
// upload to texture
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tex->textureId);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, cursor.x(), cursor.y(), glyphSize.x(), glyphSize.y(), GL_ALPHA, GL_UNSIGNED_BYTE, glyphSlot->bitmap.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
// free the FT face
|
||||||
|
FT_Done_Face(face);
|
||||||
|
}
|
||||||
|
|
||||||
void Font::renderTextCache(TextCache* cache)
|
void Font::renderTextCache(TextCache* cache)
|
||||||
{
|
{
|
||||||
if(cache == NULL)
|
if(cache == NULL)
|
||||||
|
@ -385,11 +447,11 @@ void Font::renderTextCache(TextCache* cache)
|
||||||
|
|
||||||
for(auto it = cache->vertexLists.begin(); it != cache->vertexLists.end(); it++)
|
for(auto it = cache->vertexLists.begin(); it != cache->vertexLists.end(); it++)
|
||||||
{
|
{
|
||||||
assert(it->textureId != 0);
|
assert(*it->textureIdPtr != 0);
|
||||||
|
|
||||||
auto vertexList = *it;
|
auto vertexList = *it;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, it->textureId);
|
glBindTexture(GL_TEXTURE_2D, *it->textureIdPtr);
|
||||||
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);
|
||||||
|
@ -582,7 +644,7 @@ TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset,
|
||||||
float y = offset[1] + (yBot + yTop)/2.0f;
|
float y = offset[1] + (yBot + yTop)/2.0f;
|
||||||
|
|
||||||
// vertices by texture
|
// vertices by texture
|
||||||
std::map< GLuint, std::vector<TextCache::Vertex> > vertMap;
|
std::map< FontTexture*, std::vector<TextCache::Vertex> > vertMap;
|
||||||
|
|
||||||
size_t cursor = 0;
|
size_t cursor = 0;
|
||||||
UnicodeChar character;
|
UnicodeChar character;
|
||||||
|
@ -606,7 +668,7 @@ TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset,
|
||||||
if(glyph == NULL)
|
if(glyph == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::vector<TextCache::Vertex>& verts = vertMap[glyph->texture->textureId];
|
std::vector<TextCache::Vertex>& verts = vertMap[glyph->texture];
|
||||||
size_t oldVertSize = verts.size();
|
size_t oldVertSize = verts.size();
|
||||||
verts.resize(oldVertSize + 6);
|
verts.resize(oldVertSize + 6);
|
||||||
TextCache::Vertex* tri = verts.data() + oldVertSize;
|
TextCache::Vertex* tri = verts.data() + oldVertSize;
|
||||||
|
@ -653,7 +715,7 @@ TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset,
|
||||||
{
|
{
|
||||||
TextCache::VertexList& vertList = cache->vertexLists.at(i);
|
TextCache::VertexList& vertList = cache->vertexLists.at(i);
|
||||||
|
|
||||||
vertList.textureId = it->first;
|
vertList.textureIdPtr = &it->first->textureId;
|
||||||
vertList.verts = it->second;
|
vertList.verts = it->second;
|
||||||
|
|
||||||
vertList.colors.resize(4 * it->second.size());
|
vertList.colors.resize(4 * it->second.size());
|
||||||
|
|
|
@ -75,9 +75,6 @@ private:
|
||||||
|
|
||||||
Font(int size, const std::string& path);
|
Font(int size, const std::string& path);
|
||||||
|
|
||||||
void reloadGlyphTextures();
|
|
||||||
void freeTextures();
|
|
||||||
|
|
||||||
struct FontTexture
|
struct FontTexture
|
||||||
{
|
{
|
||||||
GLuint textureId;
|
GLuint textureId;
|
||||||
|
@ -86,17 +83,18 @@ private:
|
||||||
Eigen::Vector2i writePos;
|
Eigen::Vector2i writePos;
|
||||||
int rowHeight;
|
int rowHeight;
|
||||||
|
|
||||||
FontTexture()
|
FontTexture();
|
||||||
{
|
~FontTexture();
|
||||||
textureId = 0;
|
|
||||||
textureSize << 2048, 512;
|
|
||||||
writePos = Eigen::Vector2i::Zero();
|
|
||||||
rowHeight = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool findEmpty(const Eigen::Vector2i& size, Eigen::Vector2i& cursor_out);
|
bool findEmpty(const Eigen::Vector2i& size, Eigen::Vector2i& cursor_out);
|
||||||
|
|
||||||
|
// you must call initTexture() after creating a FontTexture to get a textureId
|
||||||
|
void initTexture(); // initializes the OpenGL texture according to this FontTexture's settings, updating textureId
|
||||||
|
void deinitTexture(); // deinitializes the OpenGL texture if any exists, is automatically called in the destructor
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void rebuildTextures();
|
||||||
|
void unloadTextures();
|
||||||
|
|
||||||
std::vector<FontTexture> mTextures;
|
std::vector<FontTexture> mTextures;
|
||||||
|
|
||||||
void getTextureForNewGlyph(const Eigen::Vector2i& glyphSize, FontTexture*& tex_out, Eigen::Vector2i& cursor_out);
|
void getTextureForNewGlyph(const Eigen::Vector2i& glyphSize, FontTexture*& tex_out, Eigen::Vector2i& cursor_out);
|
||||||
|
@ -141,7 +139,7 @@ protected:
|
||||||
|
|
||||||
struct VertexList
|
struct VertexList
|
||||||
{
|
{
|
||||||
GLuint textureId;
|
GLuint* textureIdPtr; // this is a pointer because the texture ID can change during deinit/reinit (when launching a game)
|
||||||
std::vector<Vertex> verts;
|
std::vector<Vertex> verts;
|
||||||
std::vector<GLubyte> colors;
|
std::vector<GLubyte> colors;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue