openglsdlsdl-ttf

OpenGL, SDL_ttf


I have trouble with display text in OpenGL through SDL_ttf. I have written LoadFont() function which loads font and makes OpenGL texture.

int LoadFont( char *name, GLubyte r, GLubyte g, GLubyte b, char *text, int ptsize)
{
SDL_Color color = {r, g, b, 0};
TTF_Font *font = TTF_OpenFont(name, ptsize);

Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
#else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
#endif

SDL_Surface *msg = TTF_RenderText_Blended(font, text, color);

SDL_SetAlpha(msg, 0, 0);

if(!msg) {
    printf("Unable to Render text\n");
    return -1;
}

SDL_Surface *tmp = SDL_CreateRGBSurface(0, msg->w, msg->h, 32, rmask, gmask, bmask, amask);

SDL_BlitSurface(msg, NULL, tmp, NULL);


glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, msg->w, msg->h, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, msg->pixels);


return 1;
}

And i use this function in initGL():

int initGL( GLvoid )
{
glViewport(0, 0, SCREEN_WIDHT, SCREEN_HEIGHT);
LoadFont("THWACK.TTF", 255, 255, 255, "Hello!", 14);
glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(45.0f, (GLfloat)SCREEN_WIDHT/(GLfloat)SCREEN_HEIGHT, 0.1f, 100.0f);

glMatrixMode(GL_MODELVIEW);

return TRUE;
}

Further i try display this text on polygon:

int drawGLScene( GLvoid )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

glTranslatef(0.0f, 0.0f, -5.0f);

glBindTexture(GL_TEXTURE_2D, texture[0]);

glEnable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
    glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, -1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);

SDL_GL_SwapBuffers();

return TRUE;
}

But text doesnt display, only white polygon.


Solution

  • GL_TEXTURE_MIN_FILTER defaults to GL_NEAREST_MIPMAP_LINEAR.

    If you request mipmapping and don't upload a complete mipmap you'll get white textures.

    You have this:

    // disable mipmapping on default texture
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    // create new texture, with default filtering state (==mipmapping on)
    glGenTextures(1, &texture[0]);
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, msg->w, msg->h, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, msg->pixels);
    

    Try this sequence instead:

    // create new texture, with default filtering state (==mipmapping on)
    glGenTextures(1, &texture[0]);
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    
    // disable mipmapping on the new texture
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, msg->w, msg->h, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, msg->pixels);
    

    The texture filtering state belongs to the texture object and not the texture unit, hence the glTexParameterf() after the glBindTexture():

    OpenGL 2.1 spec, Section 3.8.11 (page 180) and section 3.8.12 (page 182):

    3.8.11: ...Next, there are the two sets of texture properties; each consists of the selected minification and magnification filters...

    3.8.12: ...The resulting texture object is a new state vector, comprising all the state values listed in section 3.8.11, set to the same initial values...


    EDIT: You also have to enable blending before your render if you want to use TTF_Render*_Blended():

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    
    glColor3ub( 255, 255, 255 );
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, stringTex );
    glBegin(GL_QUADS);
    // ...
    

    Example:

    #include <SDL.h>
    #include <SDL_ttf.h>
    #include <SDL_opengl.h>
    
    GLuint TextToTexture( TTF_Font* font, GLubyte r, GLubyte g, GLubyte b, const char* text, int ptsize )
    {
        SDL_Color color = { r, g, b };
        SDL_Surface* msg = TTF_RenderText_Blended( font, text, color );
    
        // create new texture, with default filtering state (==mipmapping on)
        GLuint tex;
        glGenTextures( 1, &tex );
        glBindTexture( GL_TEXTURE_2D, tex );
    
        // disable mipmapping on the new texture
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, msg->w, msg->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, msg->pixels );
    
        SDL_FreeSurface( msg );
        return tex;
    }
    
    GLuint stringTex = 0;
    void drawGLScene( int winWidth, int winHeight )
    {
        glViewport(0, 0, winWidth, winHeight );
    
        glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
        glClearDepth(1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0f, winWidth / (float)winHeight, 0.1f, 100.0f);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0f, 0.0f, -5.0f);
    
        // this is where the magic happens
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    
        glColor3ub( 255, 255, 255 );
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, stringTex );
        glBegin(GL_QUADS);
            glTexCoord2f( 0.0f, 0.0f ); glVertex2f( -1.0f, -1.0f );
            glTexCoord2f( 1.0f, 0.0f ); glVertex2f(  1.0f, -1.0f );
            glTexCoord2f( 1.0f, 1.0f ); glVertex2f(  1.0f,  1.0f );
            glTexCoord2f( 0.0f, 1.0f ); glVertex2f( -1.0f,  1.0f );
        glEnd();
        glDisable(GL_TEXTURE_2D);
    }
    
    int main( int argc, char *argv[] )
    { 
        SDL_Init( SDL_INIT_EVERYTHING );
        SDL_Surface* display = SDL_SetVideoMode( 640, 480, 32, SDL_OPENGL );
    
        if( -1 == TTF_Init() )
            return -1;
    
        // http://unifoundry.com/unifont.html
        TTF_Font *font = TTF_OpenFont( "unifont.ttf", 14 );
        stringTex = TextToTexture( font, 255, 255, 255, "Hello!", 14 );
    
        glDepthFunc(GL_LESS);
        glEnable(GL_DEPTH_TEST);
        glShadeModel(GL_SMOOTH);
    
        bool running = true;
        while( running )
        {
            SDL_Event event;
            while( SDL_PollEvent( &event ) )
            {
                if( event.type == SDL_QUIT )
                {
                    running = false;
                    break;
                }
            }
    
            drawGLScene( display->w, display->h );
            SDL_GL_SwapBuffers();
            SDL_Delay( 16 );
        }
    
        TTF_CloseFont(font);
    
        TTF_Quit();
        SDL_Quit();
        return 0;
    }