Tutorial de SDL – Parte 13 – Combinação de canais Alpha

Continuando nossa série de artigos traduzidos do site lazyfoo, iremos ver agora como aproveitar a nova renderização acelerada por hardware do SDL, que faz com o uso de transparência seja muito mais rápida, e usa a modulação do canal alpha (que funciona exatamente a modulação de cores) para controlar a transparência de uma textura.

//Texture wrapper class
class LTexture
{
 public:
 //Initializes variables
 LTexture();
 //Deallocates memory
 ~LTexture();
 //Loads image at specified path
 bool loadFromFile( std::string path );
 //Deallocates texture
 void free();
 //Set color modulation
 void setColor( Uint8 red, Uint8 green, Uint8 blue );
 //Set blending
 void setBlendMode( SDL_BlendMode blending );
 //Set alpha modulation
 void setAlpha( Uint8 alpha );
 //Renders texture at given point
 void render( int x, int y, SDL_Rect* clip = NULL );
 //Gets image dimensions
 int getWidth();
 int getHeight();
 private:
 //The actual hardware texture
 SDL_Texture* mTexture;
 //Image dimensions
 int mWidth;
 int mHeight;
};

Iremos adicionar aqui duas funções para suporte da transparência alpha em uma textura. Primeiro temos setAlpha que funciona de forma similar à setColor no artigo sobre modulação de cores. Temos também setBlendMode que controlará como a textura será combinada com o canal alpha. Para que a combinação funciona de forma adequada, você deve ajustar o modo de combinação da textura. Veremos isso em detalhes mais tarde.

bool loadMedia()
{
 //Loading success flag
 bool success = true;
 //Load front alpha texture
 if( !gModulatedTexture.loadFromFile( "13_alpha_blending/fadeout.png" ) )
 {
 printf( "Failed to load front texture!\n" );
 success = false;
 }
 else
 {
 //Set standard alpha blending
 gModulatedTexture.setBlendMode( SDL_BLENDMODE_BLEND );
 }
 //Load background texture
 if( !gBackgroundTexture.loadFromFile( "13_alpha_blending/fadein.png" ) )
 {
 printf( "Failed to load background texture!\n" );
 success = false;
 }
 return success;
}

Aqui na função de carregamento da textura iremos carregar a textura frontal que iremos combinar com o canal alpha e uma textura de fundo. A medida que a textura frontal vai ficando mais transparente, seremos capazes de enxergar cada vez mais a textura do fundo. Como você pode ver no código, depois de ter carregado com sucesso a textura frontal, configuramos o BlendMode para blend para que a combinação seja ativada. Como o fundo não irá ficar transparente, não temos que ativar a combinação para ela.
Agora, como Alpha funciona? Alpha é a opacidade, e com uma opacidade menor mais podemos enxergar através da textura. Como os componentes vermelho, verde e azul da cor, o canal Alpha vai de 0 a 255 ao ser modulada. A melhor maneira de entender isso tudo é com alguns exemplos. Digamos que temos uma imagem frontal sobre um plano de fundo branco.
Aqui temos a imagem frontal em 255 (Alpha 100%):

Aqui temos a imagem frontal em 191 (Alpha 75%):

Aqui temos a imagem frontal em 127 (Alpha 50%):

Aqui temos a imagem frontal em 63 (Alpha 25%):

Aqui temos a imagem frontal em 0 (Alpha 0%):

Como você pode ver, quanto menor o valor do canal Alpha mais transparente a imagem é.

void LTexture::setBlendMode( SDL_BlendMode blending )
{
 //Set blending function
 SDL_SetTextureBlendMode( mTexture, blending );
}
void LTexture::setAlpha( Uint8 alpha )
{
 //Modulate texture alpha
 SDL_SetTextureAlphaMod( mTexture, alpha );
}

Aqui temos a funcões SDL que fazem o trabalho de verdade. SDL_SetTextureBlendMode em setBlendMode permite que ativemos a combinação e SDL_SetTextureAlphaMod permite que ajustemos o valor do canal Alpha de toda a textura.

 //Main loop flag
 bool quit = false;
 //Event handler
 SDL_Event e;
 //Modulation component
 Uint8 a = 255;
 //While application is running
 while( !quit )
 {

Assim que entramos no loop principal, declaramos uma variável para controlar o valor do canal Alpha da textura. Esse valor é inicializado em 255 de forma que a textura frontal começa completamente opaca.

 //Handle events on queue
 while( SDL_PollEvent( &e ) != 0 )
 {
 //User requests quit
 if( e.type == SDL_QUIT )
 {
 quit = true;
 }
 //Handle key presses
 else if( e.type == SDL_KEYDOWN )
 {
 //Increase alpha on w
 if( e.key.keysym.sym == SDLK_w )
 {
 //Cap if over 255
 if( a + 32 > 255 )
 {
 a = 255;
 }
 //Increment otherwise
 else
 {
 a += 32;
 }
 }
 //Decrease alpha on s
 else if( e.key.keysym.sym == SDLK_s )
 {
 //Cap if below 0
 if( a - 32 < 0 )
 {
 a = 0;
 }
 //Decrement otherwise
 else
 {
 a -= 32;
 }
 }
 }
 }

O loop de eventos encerra a aplicacão e aumenta ou diminiu o valor do canal Alpha com as teclas w e s do teclado.

 //Clear screen
 SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
 SDL_RenderClear( gRenderer );
 //Render background
 gBackgroundTexture.render( 0, 0 );
 //Render front blended
 gModulatedTexture.setAlpha( a );
 gModulatedTexture.render( 0, 0 );
 //Update screen
 SDL_RenderPresent( gRenderer );

No final do loop principal fazemos a nossa renderização. Depois de limpar a tema, primeiro renderizamos o plano de fundo e em seguida renderizamos a textura frontal, modulada, sobre ele. Antes de renderizar a textura frontal, ajustamos o valor de seu canal Alpha. Tente aumentar e diminuir esse valor para ver como a transparência afeta a renderização.
Baixe os arquivos de mídia e código fonte desse artigo aqui.