嘿,我在装载Freetype 2库的openGL中绘制文本时遇到了一个奇怪的问题。这是我所看到的截图。
example 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,那么正确显示的一些字母会变成乱码,而其他字母在出现之前会出现乱码。
答案 0 :(得分:8)
我不熟悉FreeType,但是从图片中可以看出,字符的宽度与缓冲区的大小没有直接关系(即。glyph-&gt;缓冲区不指向字形数组 - &gt; width * glyth-&gt; height bytes)。
作为一个猜测,我会说所有的字符在内存中都有一个宽度(与它们在屏幕上使用的大小相反),可能是字形宽度的最大值,但是你加载了它们每个字符宽度而不是正确的宽度。因此,只有使用全宽的字形才是正确的。
答案 1 :(得分:2)
使用:
glPixelStorei(GL_PACK_ALIGNMENT, 1);<br>
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
这也让我感到恼火,但是你需要告诉opengl使用你给它的间距,而不是它预期的正常32位边界。图像的间距会发生变化,但OpenGL
不知道在纹理创建之前没有这些调用就会使用较小的打包对齐。
我这样做:
// Convert the glyph to a bitmap.
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, true);
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
// This reference will make accessing the bitmap easier
FT_Bitmap& bitmap = bitmap_glyph->bitmap;
int _Left = abs(bitmap_glyph->left);
int _Top = abs(bitmap_glyph->top);
int _Height = abs(bitmap.rows);
int _Width = _Left+abs(bitmap.width);
// If it's not a glyph or spacing, go to the next one
if ((_Width == 0 || _Height == 0) && !isspace(i))
return;
advances[i] = max(_Width, face->glyph->advance.x >> 6);
vector<unsigned char> Data(_Height*_Width*2, 0);
for (int32 h=0; h < abs(bitmap.rows); ++h)
for (int32 w=0; w < abs(bitmap.width); ++w)
{
int32 luminance = bitmap.buffer[h*bitmap.pitch + w];
Data[(h*_Width + w + _Left)*2 + 0] = 255;
Data[(h*_Width + w + _Left)*2 + 1] = luminance;
}
我可能会将255(白色)移动到String初始化函数中,然后只使用FreeType
中的值作为我的alpha值,但这种方式似乎更具描述性,速度在我的使用中不是问题。
地址和数据[0]现在包含GL_LUMINANCE_ALPHA external
格式,类型为GL_UNSIGNED_CHAR
,大小为_Width*_Height
。这应该让那些做这些事情的人更容易。
答案 2 :(得分:1)
您确定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
的文档,请参阅here。请注意,下次拨打FT_Load_Char
时,bitmap
中的数据将不再有效。
内存管理也存在许多问题。
您使用new Glyph
分配字形,但从不调用delete.
因为您只需要临时制作字形以生成纹理和显示列表,所以应使用{{1 }}
您永远不会致电std::auto_ptr<Glyph>
,因此您分配的所有FT_Glyph_Done
都不会被释放。
答案 3 :(得分:-1)
“16”应该是以磅为单位的字体大小。因此,在翻译时,您应该使用glyph-&gt; width而不是“16”。此外,某些字母可能需要字距调整以获得最佳文本。例如,“AV”可能看起来像“A V”而没有使用字距调整。