2010-10-27 19 views
8

Ho cercato di sviluppare un semplice motore di gioco 2D e ho bisogno di essere in grado di disegnare testo, così ho deciso di utilizzare la famosa libreria freetype. Il mio obiettivo attuale è quello di rendere ogni carattere da 0 a 255, e memorizzare le informazioni appropriate in un oggetto glifo, le posizioni superiore e sinistra del carattere, la larghezza e l'altezza e una trama OpenGL. (In futuro desidero rimuovere una texture per glifo, ma prima di iniziare a lavorarci ho bisogno che i miei caratteri siano visualizzati correttamente). Prima ho ottenuto caratteri confusi, ma poi ho controllato this question e ho capito che dovevo copiare il buffer bitmap in uno nuovo con dimensioni di trama richieste OpenGL (vale a dire una potenza di due per larghezza e altezza). Da quel momento in poi, ogni personaggio sembrava fantastico, quindi ho provato diverse dimensioni dei caratteri per vedere se tutto andava bene, indovina un po '... non era, su caratteri piccoli (ad esempio < 30) ogni carattere con una larghezza ridotta ('l', 'i', ';', ':') si presentarono confusi.Problema di rendering dei caratteri con Freetype e OpenGL

http://img17.imageshack.us/img17/2963/helloworld.png

caratteri distorti Tutto aveva una larghezza di 1, che è uscito per due, perché questa è la prima potenza di due, ecco il codice per il rendering ogni personaggio.

bool Font::Render(int PixelSize) 
{ 
    if(FT_Set_Pixel_Sizes(mFace, 0, PixelSize) != 0) 
     return false; 

    for(int i = 0; i < 256; ++i) 
    { 
     FT_UInt GlyphIndex; 

     GlyphIndex = FT_Get_Char_Index(mFace, i); 

     if(FT_Load_Glyph(mFace, GlyphIndex, FT_LOAD_RENDER) != 0) 
      return false; 


     int BitmapWidth = mFace->glyph->bitmap.width; 
     int BitmapHeight = mFace->glyph->bitmap.rows; 

     int TextureWidth = NextP2(BitmapWidth); 
     int TextureHeight= NextP2(BitmapHeight); 

     printf("Glyph is %c, BW: %i, BH: %i, TW: %i, TH: %i\n", i, BitmapWidth, BitmapHeight, TextureWidth, TextureHeight); 

     mGlyphs[i].SetAdvance(mFace->glyph->advance.x >> 6); 
     mGlyphs[i].SetLeftTop(mFace->glyph->bitmap_left, mFace->glyph->bitmap_top); 

     GLubyte * TextureBuffer = new GLubyte[ TextureWidth * TextureHeight ]; 

     for(int j = 0; j < TextureHeight; ++j) 
     { 
      for(int i = 0; i < TextureWidth; ++i) 
      { 
       TextureBuffer[ j*TextureWidth + i ] = (j >= BitmapHeight || i >= BitmapWidth ? 0 : mFace->glyph->bitmap.buffer[ j*BitmapWidth + i ]); 
      } 
     } 

     for(int k = 0; k < TextureWidth * TextureHeight; ++k) 
      printf("Buffer is %i\n", TextureBuffer[k]); 

     Texture GlyphTexture; 

     GLuint Handle; 
     glGenTextures(1, &Handle); 

     GlyphTexture.SetHandle(Handle); 
     GlyphTexture.SetWidth(TextureWidth); 
     GlyphTexture.SetHeight(TextureHeight); 

     glBindTexture(GL_TEXTURE_2D, Handle); 

     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 

     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 

     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, TextureWidth, TextureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, TextureBuffer); 

     mGlyphs[i].SetTexture(GlyphTexture); 

     delete [] TextureBuffer; 
    } 

    return true; 
} 

L'unica soluzione che ho trovato è stato un po 'if, cambiando il TextureWidth a 4 se ha il valore di 2, e in questo modo il testo guarda bene in ogni dimensione del carattere. Ma questo non ha senso per me, perché OpenGL rifiuta la larghezza di 2 trame? Oh, e ho determinato che il problema non risiede nel buffer, l'ho stampato e sembra perfetto.

Riesci a pensare a qualche motivo per cui questo sta accadendo?

Ecco il resto del codice (estremamente) disordinato, nel caso in cui il problema non risieda nella funzione Render.

int NextP2(int Val) 
{ 
    int RVal = 2; 

while(RVal < Val) RVal <<= 1; 

return RVal; 
} 

class Texture 
{ 
    public: 
     void Free() { glDeleteTextures(1, &mHandle); } 

     void SetHandle(GLuint Handle) { mHandle = Handle; } 
     void SetWidth(int Width) { mWidth = Width; } 
     void SetHeight(int Height) { mHeight = Height; } 

     inline GLuint Handle() const { return mHandle; } 
     inline int Width() const { return mWidth; } 
     inline int Height() const { return mHeight; } 
    private: 
     GLuint mHandle; 
     int mWidth; 
     int mHeight; 
}; 

class Glyph 
{ 
    public: 

     void SetAdvance(int Advance) { mAdvance = Advance; } 
     void SetLeftTop(int Left, int Top) { mLeft = Left; mTop = Top; } 
     void SetTexture(Texture texture) { mTexture = texture; } 

     Texture & GetTexture() { return mTexture; } 
     int GetAdvance() const { return mAdvance; } 
     int GetLeft() const { return mLeft; } 
     int GetTop() const { return mTop; } 

    private: 
     int mAdvance; 
     int mLeft; 
     int mTop; 
     Texture mTexture; 

}; 

class Font 
{ 
    public: 
     ~Font() { for(int i = 0; i < 256; ++i) mGlyphs[i].GetTexture().Free(); } 
     bool Load(const std::string & File); 
     bool Render(int PixelSize); 

     Glyph & GetGlyph(unsigned char CharCode) { return mGlyphs[CharCode]; } 

    private: 
     FT_Face mFace; 
     Glyph mGlyphs[256]; 

}; 

Penso che sia tutto, per favore fatemi sapere se avete trovato il problema.

Cordiali saluti e grazie in anticipo,

+0

Hai provato a farlo su un altro computer? Potrebbe essere un problema di driver. –

+0

No, non l'ho fatto, ci proverò e posteremo più tardi. Grazie per l'idea! :) – Carlos

risposta

0

Probabilmente sono imbattuto in un problema di consistenza-wrapping.

I pixel resi su un bordo della trama "sanguinano" sull'altro lato in OpenGls tentano di affiancare la trama. correttamente. se non sbaglio, cambiando si avvolgendo i parametri per

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

dovrebbe rendere OpenGL morsetto la texture ai bordi, e disegnare in modo corretto le piccole texture.

Aggiornamento

Ho trovato qualcosa su un tutorial page:

Se bitmap di un piccolo di carattere non sono allineati con i pixel dello schermo, interpolazione bilineare causerà artefatti. Una semplice soluzione per questo è cambiare il metodo di interpolazione da GL_LINEAR a GL_NEAREST, anche se questo può portare a ulteriori artefatti in il caso di testo ruotato.(Se la rotazione testo è importante per voi, si consiglia provare dicendo OpenGL a Super campione da bitmap dei caratteri più grandi.)

+0

Ho paura che non ha funzionato. Tutto rimane uguale. Hai controllato la schermata di stampa? A me non sembra affatto una tessitura piastrellata. Sembrano valori di pixel casuali e non ho idea del motivo per cui vengono visualizzati lì, perché nemmeno il buffer dovrebbe essere così grande. Questo è davvero frustrante ... semplicemente non ha alcun senso! Perché i caratteri di larghezza ridotta falliscono mentre altri non hanno alcun problema? Ho passato il mio codice più e più volte, e niente sembra sbagliato, la bitmap è stata renderizzata correttamente e così è il mio TextureBuffer ... Qualche altro pensiero? – Carlos

+0

In realtà, mi sono imbattuto in quel tutorial mentre cercavo una soluzione a questo problema, la modifica a GL_NEAREST non ha fatto nulla ... ma grazie per il tuo tempo :) – Carlos

0

Preparatevi a sostegno> 256 caratteri (Che è la storia) ea destra flusso di testo da sinistra a sinistra e da sinistra a destra e flusso di topdown.

Solo un argomento diverso per gli utenti di lingua inglese.

+0

Grazie, ma non sto puntando al supporto Unicode al momento. Questo dovrebbe essere un piccolo progetto fatto in casa, non una libreria di rendering di testi generici. :) – Carlos

15

Scommetto che mi sono imbattuto esattamente nello stesso problema con freetype e OpenGL la scorsa settimana.

L'impostazione predefinita di OpenGL è che le righe dei dati di trama siano allineate su 4 byte. Ciò causa problemi quando la larghezza della trama diventa 2 o 1, che sono dimensioni di potenza valide di 2.

L'impostazione dell'allineamento di riga su 1 limite di byte risolve il problema? Utilizzando

glPixelStore(GL_UNPACK_ALIGNMENT, 1) 

HTH

+0

Ha funzionato perfettamente! Grazie mille! – Carlos

+8

Per non lasciare questa domanda "senza risposta" dovresti forse "accettare" questa risposta :) – rotoglup

0

Usa Freetype con ICU. Freetype da solo non può rendere correttamente i glifi. Usa ICU per quello.

Problemi correlati