2010-02-27 8 views
5

Hey, ich bin Text in openGL ein seltsames Problem mit der Freetype 2 Bibliothek geladen mit Zeichnung. Hier ist ein Screenshot von dem, was ich sehe.Ausgabe mit Freetype und OpenGL

example http://img203.imageshack.us/img203/3316/freetypeweird.png

Hier sind meine Codebits zum Laden und meinen Text-Rendering.

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; 
    } 
}; 

Die entsprechenden Glyphe Informationen (Breite, Höhe, Puffer) wird in der folgenden Struktur

struct Glyph { 
    GLubyte* buffer; 
    Uint width; 
    Uint height; 
}; 

Und schließlich gespeichert, es zu machen, ich habe diese Klasse genannt 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; 
}; 

Kann jemand etwas seltsames hier sehen, das den verstümmelten Text verursachen würde? Es ist seltsam, denn wenn ich die Schriftgröße oder die DPI ändere, werden einige der Buchstaben, die korrekt angezeigt werden, verstümmelt, und andere Buchstaben, die vorher verstümmelt wurden, werden korrekt angezeigt.

Antwort

7

Ich bin mit Freetype nicht vertraut, aber aus dem Bild sieht es aus wie die Breite der Zeichen nicht direkt auf die Größe der Puffer verwendet (dh. Glyph-> Puffer zu einem Punkt nicht Array von Glyph-> Breite * Glyth-> Höhe Bytes).

Als eine Annahme, würde ich sagen, dass alle Zeichen eine einzige Breite im Speicher haben (im Gegensatz zu der Größe, die sie auf dem Bildschirm verwenden), wahrscheinlich die größte aller Breiten der Glyphen, aber Sie laden sie mit eine pro-char Breite statt der richtigen. Daher sind nur die Glyphen korrekt, die die volle Breite verwenden.

+0

Das war das Problem. Ich kopierte alles in einen neuen Puffer, der eine festgelegte Größe hatte, füllte es mit leeren Pixeln auf und alles funktionierte einwandfrei. Vielen Dank! – Morgan

1

Sind Sie sicher, dass die FT_Glyph tatsächlich ein Bitmap Glyphe ist? Stellen Sie sicher, dass Sie zuerst FT_Glyph_To_Bitmap verwenden.

Alternativ kann, da Sie die FT_Glyph s nicht zu brauchen, scheinen um danach zu speichern, können Sie einfach tun:

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 

Siehe here für die Dokumentation auf FT_Bitmap. Beachten Sie, dass beim nächsten Aufruf von FT_Load_Char die Daten in bitmap nicht mehr gültig sind.

Sie haben auch eine Reihe von Problemen mit der Speicherverwaltung.

  1. Sie verwenden new Glyph Ihre Glyphen zuzuteilen, aber nie delete. nennen Da Sie nur vorübergehend eine Glyphe machen müssen, um die Textur und Anzeigeliste zu generieren, sollten Sie eine std::auto_ptr<Glyph> verwenden.

  2. Sie rufen nie FT_Glyph_Done, so dass alle diese FT_Glyph s zugewiesen werden nie freigegeben werden.

+0

Danke für den Tipp über die Speicherverwaltung. Ich habe diesen ganzen Code nur zu Testzwecken entfernt, um sicherzustellen, dass meine Daten nicht zufällig aus Versehen gelöscht wurden, wenn es nicht sein sollte. – Morgan

-1

"16" sollte die Größe der Schrift in Punkten sein. Während der Übersetzung sollten Sie stattdessen glyph-> width statt "16" verwenden. Darüber hinaus können einige Buchstaben Kerning für am besten aussehende Texte erfordern. Zum Beispiel kann "AV" wie "A V" ohne Kerning-Verwendung aussehen.

2

Verwendung:

glPixelStorei(GL_PACK_ALIGNMENT, 1);<br> 
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 

Das ärgerte den Mist auch aus mir, aber Sie müssen opengl sagen, den Abstand geben Sie es zu benutzen, nicht die normalen 32-Bit-Grenzen, es erwartet. Die Tonhöhe der Bilder ändert sich, aber OpenGL weiß nicht, dass kleinere Packungsausrichtungen ohne diese Aufrufe vor der Texturerstellung verwendet werden.

ich es wie folgt tun:

// 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; 
    } 

Ich könnte wahrscheinlich die 255 (weiß) in die String Initialisierungsfunktion bewegen dann nur die Werte für meine Alpha-Werte in FreeType verwenden, aber auf diese Weise scheint eher deskriptiv und Geschwindigkeit ist kein Problem in meiner Verwendung.

Die Adresse & Daten [0] jetzt ein GL_LUMINANCE_ALPHA external-Format enthält, mit Typ GL_UNSIGNED_CHAR und Größe _Width*_Height. Das sollte jeden, der das Zeug macht, leichter machen.