Эй, у меня есть странная проблема с рисованием текста в openGL, загруженном библиотекой Freetype 2. Вот снимок экрана того, что я вижу.
пример http://img203.imageshack.us/img203/3316/freetypeweird.png
Вот мои биты кода для загрузки и рендеринга моего текста.
class Font
{
Font(const String& filename)
{
if (FT_New_Face(Font::ftLibrary, "arial.ttf", 0, &mFace)) {
cout << "UH OH!" << endl;
}
FT_Set_Char_Size(mFace, 16 * 64, 16 * 64, 72, 72);
}
Glyph* GetGlyph(const unsigned char ch)
{
if(FT_Load_Char(mFace, ch, FT_LOAD_RENDER))
cout << "OUCH" << endl;
FT_Glyph glyph;
if(FT_Get_Glyph( mFace->glyph, &glyph ))
cout << "OUCH" << endl;
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
Glyph* thisGlyph = new Glyph;
thisGlyph->buffer = bitmap_glyph->bitmap.buffer;
thisGlyph->width = bitmap_glyph->bitmap.width;
thisGlyph->height = bitmap_glyph->bitmap.rows;
return thisGlyph;
}
};
Соответствующая информация глифа (ширина, высота, буфер) хранится в следующей структуре
struct Glyph {
GLubyte* buffer;
Uint width;
Uint height;
};
И наконец, для рендеринга его у меня есть этот класс под названием RenderFont.
class RenderFont
{
RenderFont(Font* font)
{
mTextureIds = new GLuint[128];
mFirstDisplayListId=glGenLists(128);
glGenTextures( 128, mTextureIds );
for(unsigned char i=0;i<128;i++)
{
MakeDisplayList(font, i);
}
}
void MakeDisplayList(Font* font, unsigned char ch)
{
Glyph* glyph = font->GetGlyph(ch);
glBindTexture( GL_TEXTURE_2D, mTextureIds[ch]);
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_RGBA,
glyph->width,
glyph->height,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
glyph->buffer);
glNewList(mFirstDisplayListId+ch,GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, mTextureIds[ch]);
glBegin(GL_QUADS);
glTexCoord2d(0,1); glVertex2f(0,glyph->height);
glTexCoord2d(0,0); glVertex2f(0,0);
glTexCoord2d(1,0); glVertex2f(glyph->width,0);
glTexCoord2d(1,1); glVertex2f(glyph->width,glyph->height);
glEnd();
glTranslatef(16, 0, 0);
glEndList();
}
void Draw(const String& text, Uint size, const TransformComponent* transform, const Color32* color)
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTranslatef(100, 250, 0.0f);
glListBase(mFirstDisplayListId);
glCallLists(text.length(), GL_UNSIGNED_BYTE, text.c_str());
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glLoadIdentity();
}
private:
GLuint mFirstDisplayListId;
GLuint* mTextureIds;
};
Кто-либо может видеть что-нибудь странное продолжение здесь, которое вызвало бы искаженный текст? Это странно, потому что, если я изменяю размер шрифта или DPI, затем некоторые буквы, которые отображаются правильно, становятся искаженными, и другими буквами, которые были искажены к тому времени дисплей правильно.
Я не знаком с FreeType, но, судя по рисунку, похоже, что ширина символов не связана напрямую с размером буферов (то есть глиф-> буфер не указывает на массив глифов- > ширина * символ-> высота байтов).
В качестве предположения я бы сказал, что все символы имеют одну ширину в памяти (в отличие от размера, который они используют на экране), вероятно, самую большую из всех значений ширины глифов, но вы загружаете их с помощью по ширине символа вместо правильной. Таким образом, правильными являются только глифы, которые используют полную ширину.
Вы уверены, что FT_Glyph
на самом деле является глифом растрового изображения? Убедитесь, что вы сначала используете FT_Glyph_To_Bitmap
.
В качестве альтернативы, поскольку вам, похоже, не нужно впоследствии хранить FT_Glyph
, вы можете просто сделать:
int error = FT_Load_Char(face, ch, FT_LOAD_RENDER);
if(error)
return error;
FT_GlyphSlot slot = face->glyph;
FT_Bitmap bitmap = slot->bitmap;
// do stuff with this FT_Bitmap
См. здесь для документации по FT_Bitmap
. Просто обратите внимание, что в следующий раз, когда вы вызовете FT_Load_Char
, данные в битовой карте
больше не будут действительны.
У вас также есть ряд проблем с управлением памятью.
Вы используете новый символ
для размещения ваших глифов, но никогда не вызываете delete.
Поскольку вам просто нужно временно создать глиф для генерации текстуры и списка отображения, вы должны использовать std :: auto_ptr
.
Вы никогда не вызываете FT_Glyph_Done
, поэтому все выделенные вами FT_Glyph
никогда не освобождаются.
«16» должно быть размером шрифта в пунктах. Итак, при переводе вы должны использовать glyph-> width вместо «16». Более того, для некоторых букв может потребоваться кернинг, чтобы текст выглядел лучше. Например, «AV» может выглядеть как «AV» без использования кернинга.