I want to render an anti-aliased string on an SDL_Surface
with a given alpha channel.
I figured out it is possible to render:
Blended
variant of the string render method (ie: TTR_RenderText_Blended
). But then I can't make it transparent.Shaded
method. But then there is a solid background. The background and the drawn string can be made transparent, but then the solid background is still there. Passing it a transparent background color is also not possible.Solid
variant. But it is not anti-aliased.Thanks
I know I'm a bit late on this one :/
According to SDL documentation on SDL_SetAlpha
:
Note that per-pixel and per-surface alpha cannot be combined; the per-pixel alpha is always used if available.
So regular SDL_BlitSurface
/SDL_SetAlpha
won't work here. But it can be done:
The only ways I can think of alpha-blending TTF_RenderText_Blended
output are to use OpenGL, or adjust the alpha values of each pixel in the surface.
You can do this by scaling the per-pixel alpha values from [0, 255]
to a new range [0, alpha]
:
// Changes a surface's alpha value, by altering per-pixel alpha if necessary.
void SetSurfaceAlpha (SDL_Surface *surface, Uint8 alpha)
{
SDL_PixelFormat* fmt = surface->format;
// If surface has no alpha channel, just set the surface alpha.
if( fmt->Amask == 0 ) {
SDL_SetAlpha( surface, SDL_SRCALPHA, alpha );
}
// Else change the alpha of each pixel.
else {
unsigned bpp = fmt->BytesPerPixel;
// Scaling factor to clamp alpha to [0, alpha].
float scale = alpha / 255.0f;
SDL_LockSurface(surface);
for (int y = 0; y < surface->h; ++y)
for (int x = 0; x < surface->w; ++x) {
// Get a pointer to the current pixel.
Uint32* pixel_ptr = (Uint32 *)(
(Uint8 *)surface->pixels
+ y * surface->pitch
+ x * bpp
);
// Get the old pixel components.
Uint8 r, g, b, a;
SDL_GetRGBA( *pixel_ptr, fmt, &r, &g, &b, &a );
// Set the pixel with the new alpha.
*pixel_ptr = SDL_MapRGBA( fmt, r, g, b, scale * a );
}
SDL_UnlockSurface(surface);
}
}
I know it looks scary, but it's pretty straight-forward. The key line is here:
*pixel_ptr = SDL_MapRGBA( fmt, r, g, b, scale * a );
You can use it like this:
text_surface = TTF_RenderText_Blended( font, "Hello World!", color );
SetSurfaceAlpha( text_surface, 128 );
If using OpenGL, things are lot easier. Assuming you convert the SDL_Surface
from TTF_RenderText_Blended
to a GL texture, you can just use:
glColor4f( 1.0, 1.0, 1.0, Alpha );
before you render it on a textured quad.
But don't forget to enable alpha blending first!
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
All you have to do is call SDL_SetAlpha
on your SDL_Surface
after creating the sprite on which the text is rendered, but before calling SDL_DisplayFormatAlpha
on that sprite.
// Make the sprite with the text on it
SDL_Surface *swSprite = TTF_RenderText_Solid( font, text, textColor ) ;
// CALL SET ALPHA NOW
SDL_SetAlpha( swSprite, SDL_SRCALPHA, 128 ) ; // 50% opacity
// OK, NOW you can convert it to display format. I'm presuming
// you called `SDL_SetVideoMode` with the `SDL_HWSURFACE` flag set previously
SDL_Surface* hwSprite = SDL_DisplayFormatAlpha( swSprite ) ;
// If you invert the above 2 steps, it won't work.
// We don't need the software sprite anymore
SDL_FreeSurface( swSprite ) ;
// Now draw the hwSprite as normal
SDL_BlitSurface( hwSprite, NULL, screen, &spriteLocation );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With