#include #include // For memset #include "FTGLTextureFont.h" #include "FTTextureGlyph.h" inline GLuint NextPowerOf2( GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } FTGLTextureFont::FTGLTextureFont( const char* fontFilePath) : FTFont( fontFilePath), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { remGlyphs = numGlyphs = face.GlyphCount(); } FTGLTextureFont::FTGLTextureFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool _hinting) : FTFont( pBufferBytes, bufferSizeInBytes), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0), hinting( _hinting ) { remGlyphs = numGlyphs = face.GlyphCount(); } FTGLTextureFont::~FTGLTextureFont() { glDeleteTextures( textureIDList.size(), (const GLuint*)&textureIDList[0]); } FTGlyph* FTGLTextureFont::MakeGlyph( unsigned int glyphIndex) { FT_GlyphSlot ftGlyph = face.Glyph( glyphIndex, hinting ? 0 : FT_LOAD_NO_HINTING ); if( ftGlyph) { glyphHeight = static_cast( charSize.Height()); glyphWidth = static_cast( charSize.Width()); if( textureIDList.empty()) { textureIDList.push_back( CreateTexture()); xOffset = yOffset = padding; } if( xOffset > ( textureWidth - glyphWidth)) { xOffset = padding; yOffset += glyphHeight; if( yOffset > ( textureHeight - glyphHeight)) { textureIDList.push_back( CreateTexture()); yOffset = padding; } } FTTextureGlyph* tempGlyph = new FTTextureGlyph( ftGlyph, textureIDList[textureIDList.size() - 1], xOffset, yOffset, textureWidth, textureHeight); xOffset += static_cast( tempGlyph->BBox().upperX - tempGlyph->BBox().lowerX + padding); --remGlyphs; return tempGlyph; } err = face.Error(); return NULL; } void FTGLTextureFont::CalculateTextureSize() { if( !maximumGLTextureSize) { glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize); assert(maximumGLTextureSize); // If you hit this then you have an invalid OpenGL context. } textureWidth = NextPowerOf2( (remGlyphs * glyphWidth) + ( padding * 2)); textureWidth = textureWidth > maximumGLTextureSize ? maximumGLTextureSize : textureWidth; int h = static_cast( (textureWidth - ( padding * 2)) / glyphWidth); textureHeight = NextPowerOf2( (( numGlyphs / h) + 1) * glyphHeight); textureHeight = textureHeight > maximumGLTextureSize ? maximumGLTextureSize : textureHeight; } GLuint FTGLTextureFont::CreateTexture() { CalculateTextureSize(); int totalMemory = textureWidth * textureHeight; unsigned char* textureMemory = new unsigned char[totalMemory]; memset( textureMemory, 0, totalMemory); GLuint textID; glGenTextures( 1, (GLuint*)&textID); glBindTexture( GL_TEXTURE_2D, textID); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, textureMemory); delete [] textureMemory; return textID; } bool FTGLTextureFont::FaceSize( const unsigned int size, const unsigned int res) { if( !textureIDList.empty()) { glDeleteTextures( textureIDList.size(), (const GLuint*)&textureIDList[0]); textureIDList.clear(); remGlyphs = numGlyphs = face.GlyphCount(); } return FTFont::FaceSize( size, res); } void FTGLTextureFont::Render( const char* string) { glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE FTTextureGlyph::ResetActiveTexture(); FTFont::Render( string); glPopAttrib(); } void FTGLTextureFont::Render( const wchar_t* string) { glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE FTTextureGlyph::ResetActiveTexture(); FTFont::Render( string); glPopAttrib(); }