2013-08-13 1 views
1

J'utilise freetype, et la seule chose qu'il me reste à faire pour rendre le texte est de convertir un ft_bitmap en quelque chose qui peut être rendu avec opengl quelqu'un peut-il expliquer comment faire cela? J'utilise glfw. Avec la façon dont je l'ai essayé de le faire, il donne juste un écran vide est le code ici que j'utilise:Rendu texte-freetype écran vide

#include <exception> 
    #include <iostream> 
    #include <string> 
    #include <glew.h> 
    #include <GL/glfw.h> 
    #include <iterator> 
    #include "../include/TextRenderer.h" 
    #include <ft2build.h> 
    #include FT_FREETYPE_H 
    #include <stdexcept> 
    #include <freetype/ftglyph.h> 


    using std::runtime_error; 
    using std::cout; 
    TextRenderer::TextRenderer(int x, int y, FT_Face Face, std::string s) 
    { 


     FT_Set_Char_Size(
      Face, /* handle to face object   */ 
      0,  /* char_width in 1/64th of points */ 
      16*64, /* char_height in 1/64th of points */ 
      0,  /* horizontal device resolution */ 
      0); /* vertical device resolution  */ 
     slot= Face->glyph; 

     text = s; 
     setsx(x); 
     setsy(y); 
     penX = x; 
     penY = y; 
     face = Face; 
     //shaders 
     GLuint v = glCreateShader(GL_VERTEX_SHADER) ; 
     const char* vs = "void main(){ gl_Position = ftransform();}"; 
     glShaderSource(v,1,&vs,NULL); 
     glCompileShader(v); 
     GLuint f = glCreateShader(GL_FRAGMENT_SHADER) ; 
     const char* fs = "uniform sampler2D texture1; void main() { gl_FragColor = texture2D(texture1, gl_TexCoord[0].st); //And that is all we need}"; 
     glShaderSource(f,1,&fs,NULL); 
     glCompileShader(f); 
     Program= glCreateProgram(); 
     glAttachShader(Program,v); 
     glAttachShader(Program,f); 
     glLinkProgram(Program); 


    } 
    void TextRenderer::render() 
    { 
     glUseProgram(Program); 
     FT_UInt glyph_index; 
     for (int n = 0; n < text.size(); n++) 
     { 
      /* retrieve glyph index from character code */ 

      glyph_index = FT_Get_Char_Index(face, text[n]); 

       /* load glyph image into the slot (erase previous one) */ 
       error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER); 

       draw(&face->glyph->bitmap,penX + slot->bitmap_left,penY - slot->bitmap_top); 

       penX += *(&face->glyph->bitmap.width)+3; 
       penY += slot->advance.y >> 6; /* not useful for now */ 
      } 
     } 
    void TextRenderer::draw(FT_Bitmap * bitmap,float x,float y) 
{ 



GLuint texture [0] ; 

    glGenTextures(1,texture); 
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); 
glTexImage2D (GL_TEXTURE_2D, 0, GL_RED , bitmap->width, bitmap->rows, 0, GL_RED , GL_UNSIGNED_BYTE, bitmap); 


// int loc = glGetUniformLocation(Program, "texture1"); 
// glUniform1i(loc, 0); 
glBindTexture(GL_TEXTURE_2D, texture[0]); 
glEnable(GL_TEXTURE_2D); 
     int height=bitmap->rows/10; 
     int width=bitmap->width/10; 
     glBegin(GL_QUADS); 
     glTexCoord2f (0.0, 0.0); 
     glVertex2f(x,y); 
     glTexCoord2f (1.0, 0.0); 
     glVertex2f(x+width,y); 
     glTexCoord2f (1.0, 1.0); 
     glVertex2f(x+width,y+height); 
     glTexCoord2f (0.0, 1.0); 
     glVertex2f(x,y+height); 
     glEnd(); 
glDisable(GL_TEXTURE_2D); 

} 

Qu'est-ce que j'utilise pour initialiser le texte renderer:

FT_Library library; 
FT_Face  arial; 
FT_Error error = FT_Init_FreeType(&library); 
    if (error) 
    { 
     throw std::runtime_error("Freetype failed"); 
    } 

    error = FT_New_Face(library, 
         "C:/Windows/Fonts/Arial.ttf", 
         0, 
         &arial); 
    if (error == FT_Err_Unknown_File_Format) 
    { 
     throw std::runtime_error("font format not available"); 
    } 
    else if (error) 
    { 
     throw std::runtime_error("Freetype font failed"); 
    } 
TextRenderer t(5,10,arial,"Hello"); 
    t.render(); 
+0

Pour commencer, vous passez un pointeur brut, non initialisée à une fonction ('glGenTextures()') qui attend un tableau * non nul * pointeur de base. Allouez une quantité appropriée de mémoire pour votre tableau de texture ou passez un tableau fixe automatique (dans votre cas, probablement le dernier, puisque vous en obtenez un seul). – WhozCraig

+0

mon mauvais mal compris que Fonction- modifié de manière appropriée, maintenant j'obtenir juste un écran vide – user2673108

Répondre

2

Il y a Beaucoup de problèmes dans votre programme qui résultent de ne pas comprendre ce que chaque appel que vous faites à OpenGL ou Freetype faire. Vous devriez vraiment lire la documentation pour les bibliothèques au lieu d'empiler des tutoriels les uns dans les autres.

Faisons celui-ci par un

Fragment Shader

const char* fs = "uniform sampler2D texture1; 
        void main() { 
         gl_FragColor = texture2D(texture1, gl_TexCoord[0].st); 
        //And that is all we need}";` 

Ce shader ne compile pas (vous devriez vraiment vérifier si elle compile avec glGetShaderiv et si elle les liens avec glGetProgramiv). Si vous indentez correctement, vous verrez que vous avez commenté la dernière } car elle se trouve sur la même ligne et après le //. Donc, vous devez supprimer le commentaire ou utiliser un \n pour terminer le commentaire.

De même, pour les versions plus récentes d'OpenGL utilisant gl_TexCoord est obsolète mais cela fonctionne si vous utilisez un profil de compatibilité.

Vertex Shader

comme le fragment shader il y a une fonctionnalité dépréciée utilisée, à savoir ftransform().

Mais le plus gros problème est que vous utilisez gl_TexCoord[0] dans le fragment shader sans le faire passer par le vertex shader. Donc, vous devez ajouter la ligne gl_TexCoord[0]=gl_MultiTexCoord0; dans votre vertex shader. (Comme vous l'avez deviné qui est aussi dépréciée)

passant Texture

Vous passez un pointeur vers bitmap-glTexImage2D mais bitmap est de type FT_Bitmap *, vous devez passer bitmap->buffer à la place.

Vous ne devez pas générer une nouvelle texture pour chaque lettre à chaque image (surtout si vous ne la supprimez pas). Vous devriez appeler glGentextures seulement une fois (vous pouvez le mettre dans votre constructeur TextRenderer puisque vous y mettez tous les autres trucs d'initialisation).

Ensuite, il ya le GLuint texture [0]; qui devrait vous donner une erreur de compilation.Si vous avez vraiment besoin d'un tableau avec un élément alors la syntaxe est GLuint texture [1];

donc votre dernier appel ressemblerait à quelque chose comme ceci:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap->width, bitmap->rows, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bitmap->buffer); 

Divers

int height=bitmap->rows/10; 
int width=bitmap->width/10; 

c'est une division entière et si vos valeurs pour bitmap->width deviennent plus petits que 10 vous obtiendrez 0 à la suite, ce qui rendrait le quad que vous essayez de tirer invi sible (hauteur ou largeur de 0). Si vous avez du mal à voir les objets, vous devriez simplement les traduire/les mettre à l'échelle. Ceci est également déconseillé, mais si vous continuez à utiliser l'autre chose, votre fenêtre aurait un système de coordonnées allant de [-100, -100] à [100,100] (bas à gauche en haut à droite).

glLoadIdentity(); 
glScalef(0.01f, 0.01f, 1.0f); 

vous manque aussi la conversion de coordonnées de FreeType à OpenGL, Freetype utilise un système de coordonnées qui commence à [0,0] dans le coin supérieur gauche et x est le décalage vers la droite tout en y est le décalage vers le bas. Donc, si vous utilisez simplement ces coordonnées dans OpenGL, tout sera à l'envers.

Si vous faites tout ce que votre résultat devrait ressembler à ceci (fond gris pour mettre en évidence où les polygones commencent et fin):

glfw Window

Quant à votre approche générale, repurposing une texture et une lettre de dessin par lettre ré-utiliser et écraser la même texture semble être une approche inefficace. Il vaudrait mieux allouer juste une texture plus grande et ensuite utiliser glTexSubImage2D pour y écrire les glyphes. Si le re-rendu des lettres de freetype est un goulot d'étranglement, vous pouvez également écrire tous les symboles dont vous avez besoin dans une texture au début (par exemple toute la gamme ASCII) et ensuite utiliser cette texture comme texture-atlas. Mon conseil général serait aussi que si vous ne voulez pas vraiment apprendre OpenGL mais que vous voulez simplement utiliser un rendu multiplateforme sans vous soucier des choses de bas niveau, je vous recommande d'utiliser un framework de rendu à la place.

+0

Merci pour responding- J'ai deux ou trois questions, d'abord dans l'image tex 2d appeler ce qui est de l'importance du changement de glred à glluminance? De plus, quand le mien rend le suivant http://imgur.com/NptMgk6 mon code peut être vu ici: http://pastebin.com/0M54fwpf J'allais avoir mon programme contenant une carte de chaque personnage, et ces caractères serait ajouté soit au début ou lors de la première utilisation - n'est-ce pas un bon moyen de s'y prendre? – user2673108

+0

@ user2673108 vous devez mettre 'glBindTexture (GL_TEXTURE_2D, texture [0]);' 'après la texture GLuint [1],' et avant de modifier les paramètres relatifs à la texture (alors mettez simplement directement après). Si vous voulez garder l'approche actuelle, je vous recommande d'ajouter 'glBindTexture (GL_TEXTURE_2D, 0),' et 'glDeleteTextures (1, texture [0];);' à la fin de la méthode. En outre, vous ne l'avez pas encore la transformation de coordonnées, de sorte que votre il est toujours à l'envers. – PeterT

+0

@ user2673108 et 'GL_RED' télécharge la texture juste sur le canal rouge, donc le texte s'affichera mais il sera en rouge alors que' GL_LUMINANCE' va copier les valeurs sur les 3 canaux (rouge, vert, bleu) et donc le faire apparaît blanc. – PeterT