2010-02-27 76 views
5

嘿,我有一個奇怪的問題,在用Freetype 2庫加載的openGL中繪製文本。這是我所看到的截圖。問題與Freetype和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,那麼一些顯示正確的字母會變成亂碼,其他字母在之前顯示爲亂碼,然後正確顯示。

回答

7

我不熟悉的FreeType,但是從圖像,它看起來像字符的寬度不直接相關的緩衝器的大小(即glyph->緩衝器不指向一個glyph-> width * glyth-> height字節數組)。

作爲一個猜測,我會說所有的字符在內存中都有一個寬度(與它們在屏幕上使用的大小相反),可能是字形寬度中最大的一個,但是用每個字符寬度,而不是正確的。所以,只有使用全寬的字形纔是正確的。

+0

這是問題所在。我將所有東西都複製到一個新的緩衝區中,這個緩衝區是一個填充大小的空白像素,一切正常。謝謝! – Morgan 2010-02-27 23:36:08

1

您確定FT_Glyph實際上是一個位圖字形嗎?確保你先使用FT_Glyph_To_Bitmap

或者,你似乎因爲並不需要存儲FT_Glyph S周圍之後,你可以做:

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 

hereFT_Bitmap的文檔。請注意,下次您撥打FT_Load_Char時,bitmap中的數據將不再有效。

您還有一些內存管理問題。

  1. 您使用new Glyph來分配你的字形,但從來沒有叫delete.既然你只需要暫時使字形生成的紋理和顯示列表,你應該使用一個std::auto_ptr<Glyph>

  2. 您永遠不會撥打FT_Glyph_Done,因此您分配的所有FT_Glyph都不會被釋放。

+0

感謝您關於內存管理的提示。爲了測試的目的,我將所有代碼都刪除了,以確保我的數據不會在意外情況下被意外刪除。 – Morgan 2010-02-27 23:37:18

-1

「16」應該是點的字體大小。所以,在翻譯時你應該使用glyph-> width而不是「16」。此外,有些字母可能需要查找最好看的文本。例如,「AV」可能看起來像「A V」,而沒有使用字距。

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(白)到字符串初始化函數,那麼只使用值FreeType我的alpha值,但這種方式似乎更具描述性,速度在我的使用中不是問題。

地址&數據[0]現在包含GL_LUMINANCE_ALPHA external格式,類型爲GL_UNSIGNED_CHAR,大小爲_Width*_Height。這應該使任何人做這個東西的生活更容易。