Joymaker
Joymaker

Reputation: 1418

SDL_ttf with transparent background?

I would like to use SDL_ttf to draw lettering over a potentially complex image, such that the lettering is opaque but no background box is drawn; the background is transparent. Is this possible? Here's my attempt; I had hoped that by making bgColor transparent I might achieve this result. But no, my lettering still appears surrounded by black boxes.

(I am aware of this answer but at 14 years old it looks radically out of date. Have things been made better in SDL2?)

void DrawText(int x, int y, const char* text, SDL_Color textColor, TTF_Font *font) {
    int width, height;

    SDL_Color bgColor = { 0, 0, 0, 0};
    SDL_Surface* textSurface =
        TTF_RenderText_Shaded(font, text, textColor, bgColor);
    if( textSurface == NULL )
        printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
    else {
        //Create texture from surface pixels
        SDL_Texture *mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
        if( mTexture == NULL )  printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
        else {
            //Get image dimensions
            width = textSurface->w;
            height = textSurface->h;
        }
        //Get rid of old surface
        SDL_FreeSurface( textSurface );

        //Render to screen
        int descent = TTF_FontDescent(gFont);
        SDL_Rect renderQuad = { x, y-height-descent, width, height };
        SDL_RenderCopy( gRenderer, mTexture, NULL, &renderQuad);
        SDL_DestroyTexture(mTexture);
    }
}

Upvotes: 0

Views: 58

Answers (1)

Joymaker
Joymaker

Reputation: 1418

The answer turned out to be quite simple. Copying some old example, I was drawing my text with TTF_RenderText_Shaded, which produces an 8-bit surface with a palette to represent the colors. This technique, which was important when we had fewer bits, seems to me archaic and seldom useful at present. And it required an explicit background color, which when blitted overwrote whatever was there before.

TTF_RenderText_Blended does exactly what I want. It generates an ARGB surface with the background completely transparent, so that when it is blitted onto a target it draws only the lettering and nothing else. Minus the set up stuff, here's my working code:

void DrawText(int x, int y, const char* text, SDL_Color fg) {
    int width, height;

    if (strlen(text) == 0) return;
    
    SDL_Color bgColor = { 0xff, 0xff, 0xff, 0xff};
    SDL_Surface* textSurface = TTF_RenderText_Blended(gFont, text, fg);
    if( textSurface == NULL )
        printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
    else {
        //Create texture from surface pixels
        SDL_Texture *mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
        if( mTexture == NULL ) {
            printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
        } else {
            //Get image dimensions
            width = textSurface->w;
            height = textSurface->h;
        }
        //Get rid of old surface
        SDL_FreeSurface( textSurface );

        //Render to screen
        int descent = TTF_FontDescent(gFont);
        printf("height: %d  descent:%d\n", height, descent);
        SDL_Rect renderQuad = { x, y-height-descent, width, height };
        SDL_RenderCopy( gRenderer, mTexture, NULL, &renderQuad);
        SDL_DestroyTexture(mTexture);
    }
}

void TextTest() {
    SDL_Color c1 = {0xff, 0xff, 0x00, 0x00};
    SDL_Color c2 = {0xff, 0x00, 0xff, 0x00};
    DrawText(50, 50, "hello", c1);
    DrawText(60, 55, "goodbye", c2);
}

And its output:

enter image description here

Upvotes: 0

Related Questions