2016-11-15 2 views
1

J'essaye d'utiliser OpenGL et SDL, en utilisant SDL_ttf pour rendre le texte à une texture, mais le code rend le garbage.SDL_TTF rendre les ordures à la texture

Mon "rendu au code de texture":

GLuint textToTexture(std::string & text, TTF_Font* font, glm::vec4 textColour, glm::vec4 bgColour) 
{ 
    if (!TTF_WasInit()) 
    { 
     if (TTF_Init() == -1) 
      exit(6); 
    } 
    SDL_Color colour = { (Uint8)(textColour.r*255), (Uint8)(textColour.g*255), (Uint8)(textColour.b*255), (Uint8)(textColour.a*255) }; 
    SDL_Color bg = { (Uint8)(bgColour.r*255), (Uint8)(bgColour.g*255), (Uint8)(bgColour.b*255), (Uint8)(bgColour.a*255) }; 

    SDL_Surface *stringImage = NULL; 
    stringImage = TTF_RenderText_Blended(font, text.c_str(), colour); 

    if (stringImage == NULL) 
    { 
     exit(5); 
    } 

    GLuint trueH = powerofTwo(stringImage->h); 
    GLuint trueW = powerofTwo(stringImage->w); 
    unsigned char* pixels = NULL; 
    GLuint w = stringImage->w; 
    GLuint h = stringImage->h; 
    GLuint colours = stringImage->format->BytesPerPixel; 
    pixels = padTexture((unsigned char*)stringImage->pixels, w, h, pixels, trueW, trueH, colours); 
    GLuint format, internalFormat; 
    if (colours == 4) { 

     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGBA; 
     else 
      format = GL_BGRA; 
    } 
    else {  

     // no alpha 
     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGB; 
     else 
      format = GL_BGR; 
    } 
    internalFormat = (colours == 4) ? GL_RGBA : GL_RGB; 


    GLuint texId = 0; 
    //GLuint texture; 

    glGenTextures(1, &texId); 

    glBindTexture(GL_TEXTURE_2D, texId); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
    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, internalFormat, trueW, trueH, 0,format, GL_UNSIGNED_BYTE, pixels); 

    // SDL surface was used to generate the texture but is no longer 
    // required. Release it to free memory 
    SDL_FreeSurface(stringImage); 
    free(pixels) 
    return texId; 
} 

Le code de calcul des dimensions correctes pour le rembourrage:

int powerofTwo(int num) 
{ 
    if (num != 0) 
    { 
     num--; 
     num |= num >> 1; // Divide by 2^k for consecutive doublings of k up to 32, 
     num |= num >> 2; // and then or the results. 
     num |= num >> 4; 
     num |= num >> 8; 
     num |= num >> 16; 
     num++; 
    } 
    return num; 
} 

et enfin, le code qui copie les octets à une texture de la dimensions correctes:

unsigned char* padTexture(unsigned char * src, int srcW, int srcH, unsigned char * dest, int width, int height, int bpp) 
{ 
    dest = (unsigned char*)calloc(1, width*height*bpp); 
    for (int i = 0; i < srcH; i++) 
    { 
     memcpy(dest + (width*i*bpp),src + (srcW*i*bpp), srcW*bpp); 
    } 
    return dest; 
} 

Le résultat de ce code est le suivant: [! [Garbled Texture] [1 ]] [1]

J'ai vérifié et vérifié l'erreur que SDL_TTF est correctement initialisé ailleurs dans la base de code, et que la police est également en cours de chargement. J'ai testé avec trois polices différentes ttf, avec les mêmes résultats.

Aussi, si j'utilise toute autre fonction TTF_rendering (ombrée, etc solide), est rendu un quad solide, et la variable « couleurs » dans la fonction textToTexture se termine également comme 1.

supplémentaires:

Comme je l'ai

déjà dit, j'ai testé avec trois polices TTF: MavenPro-Regular,

HelveticaNeueLTStd-Th

et un autre je trouve sur internet. J'essayais de rendre la chaîne "Select Scenario".

Les dimensions de l'image pré-rembourrée sont de 138x25 pixels.

Les dimensions de l'image après remplissage sont de 256 x 32 pixels.

Mise à jour 1:

Après avoir résolu la question BPP la nouvelle texture est la suivante:

New garbled

Cette image change à chaque fois que je lance le programme.

Mise à jour 2: Après avoir corrigé les erreurs tachetées supplémentaires avec rembourrage de l'image et la définition des données de pixels à la texture elle-même, quand je l'utilise TTF_RenderText_Blended tout ce que je reçois est un quad noir, et quand je l'utilise TTF_RenderText_Shaded je reçois:

enter image description here

Mise à jour 3:

J'utilisé SDL_SaveBMP immedietly avant d'appeler le code GL et après avoir appelé SDL_RenderText_Blended, le résultat était une image complètement blanche, (étant donné la couleur de texte).

Lorsque je fais la même chose en utilisant TTF_RenderText_Solid, l'image enregistrée est comme elle devrait l'être, mais elle est rendue par opengl comme les images que vous voyez ci-dessus.

SDL_TTF initialisé correctement, les polices se chargent sans erreur, et le rendu du texte ne renvoie aucune erreur, donc je ne peux pas penser à quoi faire ensuite.

Mise à jour 4:

J'ai depuis refondus tout le code TTF en une seule fonction et supprimé le code de remplissage (comme opengl moderne ne semble pas se soucier à ce sujet). Cependant, malgré tous les paramètres du projet et le code étant identique à un projet de test connu pour fonctionner sur le même matériel, le problème persiste.

GLuint textToTexture(const char * text, const char * font, glm::vec4 textColour, glm::vec4 bgColour, unsigned int & texID) 
{ 
    if (!TTF_WasInit()) { 
     if (TTF_Init() == -1) 
      exit(6); 
    } 
    SDL_Color colour = { (Uint8)(textColour.r * 255), (Uint8)(textColour.g * 255), (Uint8)(textColour.b * 255),(Uint8)(textColour.a * 255) }; 
    SDL_Color bg = { (Uint8)(bgColour.r * 255), (Uint8)(bgColour.g * 255), (Uint8)(bgColour.b * 255),255 }; 
    TTF_Font* fontObj = TTF_OpenFont(font, 24); 
    if (!fontObj) 
    { 
     SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 
      "Texture Error", 
      "Cannot load font to create texture.", 
      NULL); 
     return 0; 
    } 
    SDL_Surface *image = NULL; 
    image = TTF_RenderText_Blended(fontObj, text, colour); 
    if (image == NULL) 
    { 
     exit(5); 
     //exitFatalError("String surface not created."); 
     std::cout << "String surface not created." << std::endl; 

    } 
    unsigned char* pixels = NULL; 
    GLuint w = image->w; 
    GLuint h = image->h; 
    GLuint colours = image->format->BytesPerPixel; 
    GLuint externalFormat, internalFormat; 
    SDL_PixelFormat *format = image->format; 
    if (colours == 4) { 

     if (image->format->Rmask == 0x000000ff) 
      externalFormat = GL_RGBA; 
     else 
      externalFormat = GL_BGRA; 
    } 
    else { 

     // no alpha 
     if (image->format->Rmask == 0x000000ff) 
      externalFormat = GL_RGB; 
     else 
      externalFormat = GL_BGR; 
    } 
    internalFormat = (colours == 4) ? GL_RGBA : GL_RGB; 


    GLuint texId = 0; 
    //GLuint texture; 

    glGenTextures(1, &texID); 

    glBindTexture(GL_TEXTURE_2D, texID); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
    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, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, image->pixels); 
    //glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0, externalFormat, GL_UNSIGNED_BYTE, pixels); 
    glGenerateMipmap(GL_TEXTURE_2D); 

    //// SDL surface was used to generate the texture but is no longer 
    //// required. Release it to free memory 
    SDL_FreeSurface(image); 
    TTF_CloseFont(fontObj); 
    return texID; 
} 

J'ai une solution qui sauve l'image à bmp, et puis recharge crée une texture, mais seulement quand j'utiliser TTF_RenderText_Shaded. Si j'utilise TTF_RenderText_Blended, j'obtiens une image couleur unique qui correspond à la couleur du texte.

+0

'src + (srcW * i)' - vous devez multiplier par BPP trop (même pour dst). De plus, vous ne libérez jamais votre tampon de pixels, mais cela n'a aucun rapport avec votre problème actuel. – keltar

+0

Ok, j'ai corrigé cette erreur (joliment repérée btw), mais cela n'a pas amélioré la texture résultante, donc est-il possible qu'il y ait un autre problème? –

+0

Techniquement, vous devez aligner les lignes, mais avec bpp = 4 elles le sont déjà. Mettez à jour la question avec les modifications que vous avez apportées et les résultats que vous obtenez. Il peut également être utile de connaître les valeurs réelles de largeur et de hauteur de la surface d'origine, quelle police a été utilisée et quel texte est rendu. – keltar

Répondre

2
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueH, trueW, 0,format, GL_UNSIGNED_BYTE, pixels); 

trueH et trueW ordre est inversé

memcpy(src + (srcW*i*bpp), dest + (width*i*bpp), srcW*bpp); 

ordre de source et la destination inversée.

dest = (unsigned char*)calloc(0, width*height*bpp); 

0 éléments de taille width*height*bpp attribués, qui est 0 octet. Devrait être 1 au lieu de 0.

Voici un exemple complet:

#include <SDL2/SDL.h> 
#include <GL/gl.h> 
#include <SDL2/SDL_ttf.h> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

static unsigned char* padTexture(unsigned char * src, int srcW, int srcH, unsigned char * dest, int width, int height, int bpp, const SDL_Palette *palette) 
{ 
    int dst_bpp = (bpp == 1) ? 4 : bpp; 
    dest = (unsigned char*)calloc(1, width*height*dst_bpp); 
    if(bpp != 1) { 
     for (int i = 0; i < srcH; i++) 
     { 
      memcpy(dest + (width*i*bpp), src + (srcW*i*bpp), srcW*bpp); 
     } 
    } else { 
     /* indexed - read colours from palette */ 
     for(int i = 0; i < srcH; i++) { 
      for(int j = 0; j < srcW; j++) { 
       memcpy(dest + (width*i+j)*dst_bpp, 
         &palette->colors[src[srcW*i+j]], sizeof(SDL_Color)); 
      } 
     } 
    } 
    return dest; 
} 

static int powerofTwo(int num) { 
    if (num != 0) 
    { 
     num--; 
     num |= num >> 1; // Divide by 2^k for consecutive doublings of k up to 32, 
     num |= num >> 2; // and then or the results. 
     num |= num >> 4; 
     num |= num >> 8; 
     num |= num >> 16; 
     num++; 
    } 
    return num; 
} 

static GLuint textToTexture(const char *text, TTF_Font* font) { 
    if (!TTF_WasInit()) { 
     if (TTF_Init() == -1) 
      exit(6); 
    } 
    SDL_Color colour = { 255, 255, 255, 255 }; 
    SDL_Color bg = { 0, 0, 0, 255 }; 

    SDL_Surface *stringImage = NULL; 
// stringImage = TTF_RenderText_Blended(font, text, colour); 
    stringImage = TTF_RenderText_Shaded(font, text, colour, bg); 

    if (stringImage == NULL) { 
     exit(5); 
    } 

    GLuint trueH = powerofTwo(stringImage->h); 
    GLuint trueW = powerofTwo(stringImage->w); 
    unsigned char* pixels = NULL; 
    GLuint w = stringImage->w; 
    GLuint h = stringImage->h; 
    GLuint colours = stringImage->format->BytesPerPixel; 
    pixels = padTexture((unsigned char*)stringImage->pixels, w, h, pixels, trueW, trueH, 
      colours, stringImage->format->palette); 
    GLuint format, internalFormat; 

    /* If indexed, want resulting image to be 32bit */ 
    if(colours == 1) { 
     colours = 4; 
    } 

    if (colours == 4) { 

     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGBA; 
     else 
      format = GL_BGRA; 
    } 
    else {  

     // no alpha 
     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGB; 
     else 
      format = GL_BGR; 
    } 
    internalFormat = (colours == 4) ? GL_RGBA : GL_RGB; 


    GLuint texId = 0; 
    //GLuint texture; 

    glGenTextures(1, &texId); 

    glBindTexture(GL_TEXTURE_2D, texId); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
    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, internalFormat, trueW, trueH, 0,format, GL_UNSIGNED_BYTE, pixels); 

    // SDL surface was used to generate the texture but is no longer 
    // required. Release it to free memory 
    SDL_FreeSurface(stringImage); 
    free(pixels); 
    return texId; 
} 

int main(int argc, char* argv[]) 
{ 
    SDL_Init(SDL_INIT_VIDEO); 
    TTF_Init(); 

    SDL_Window *window = SDL_CreateWindow("SDL2 Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 600, 400, SDL_WINDOW_OPENGL); 
    SDL_GLContext gl_ctx = SDL_GL_CreateContext(window); 

    TTF_Font *font = TTF_OpenFont(".fonts/tahoma.ttf", 16); 
    if(font) { 
     printf("font loaded\n"); 
     textToTexture("Select Scenario", font); 
     TTF_CloseFont(font); 
    } 

    int quit = 0; 
    while(!quit) { 
     SDL_Event ev; 
     while(SDL_PollEvent(&ev)) { 
      if(ev.type == SDL_QUIT || ev.type == SDL_KEYUP) { 
       quit = 1; 
      } 
     } 

     glClearColor(0.1f, 0.1f, 0.1f, 1.0f); 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

     glLoadIdentity(); 
     glEnable(GL_BLEND); 
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
     glEnable(GL_TEXTURE_2D); 
     glColor3f(1.0f, 1.0f, 1.0f); 
     glBegin(GL_QUADS); 
      glTexCoord2f(0, 1); 
      glVertex2f(-0.5, -0.5); 
      glTexCoord2f(0, 0); 
      glVertex2f(-0.5, 0.5); 
      glTexCoord2f(1, 0); 
      glVertex2f(0.5, 0.5); 
      glTexCoord2f(1, 1); 
      glVertex2f(0.5, -0.5); 
     glEnd(); 

     glFlush(); 
     SDL_GL_SwapWindow(window); 
    } 

    SDL_GL_DeleteContext(gl_ctx); 
    SDL_DestroyWindow(window); 

    TTF_Quit(); 
    SDL_Quit(); 

    return 0; 
} 
+0

Bien repéré. Corrigé ces erreurs mais aucune amélioration perceptible, j'ai donc mis à jour la question avec le nouveau code. –

+1

Fonctionne bien pour moi. Faites un exemple complet alors. – keltar

+0

J'ai vérifié sur les données stockées dans le RAM GPU et l'image est également tronquée, donc je suppose que le problème est soit avec SDL_TTF lui-même, ou avec la copie des données au GPU. Quelle version de SDL_TTF utilisez-vous? –