Tutorial de SDL – Parte 7 – Carregamento e renderização de texturas

Continuando com nossa série de artigos traduzido do site lazyfoo, agora veremos como carregar e renderizar texturas.

Uma importante adição no SDL 2 é a API de renderização de texturas. Isso lhe proporcionará renderização de texturas baseada em hardware de forma rápida e flexível. Nesse artigo, estaremos usando essa nova técnica de renderização.

//Loads individual image as texture
SDL_Texture* loadTexture( std::string path );

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The window renderer
SDL_Renderer* gRenderer = NULL;

//Current displayed texture
SDL_Texture* gTexture = NULL;

Texturas em SDL possuem seu próprio tipo de dado que é intuitivamente chamado de  SDL_Texture. Quando lidamos com texturas em SDL você precisa de um SDL_Renderer para renderiza-las na tela, por isso declaramos um renderizador chamado “gRenderer”.

Como você também pode ver, temos uma nova rotina de carregamento de imagem com loadTexture e uma textura que declaramos globalmente que iremos ter que carregar.

        //Create window
        gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
        if( gWindow == NULL )
        {
            printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
            success = false;
        }
        else
        {
            //Create renderer for window
            gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
            if( gRenderer == NULL )
            {
                printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
                success = false;
            }
            else
            {
                //Initialize renderer color
                SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );

                //Initialize PNG loading
                int imgFlags = IMG_INIT_PNG;
                if( !( IMG_Init( imgFlags ) & imgFlags ) )
                {
                    printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
                    success = false;
                }
            }
        }

Depois que criamos nossa janela, temos que criar um renderizador para ela de forma que possamos renderizar as texturas nela. Felizmente, isso é feito de forma fácil com uma chamada para SDL_CreateRenderer.

Depois de criar o renderizador, precisamos inicializar a renderização de cores usando SDL_SetRenderDrawColor. Isso irá controlar quais cores são usadas por várias operações de renderização.

SDL_Texture* loadTexture( std::string path )
{
    //The final texture
    SDL_Texture* newTexture = NULL;

    //Load image at specified path
    SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
    if( loadedSurface == NULL )
    {
        printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
    }
    else
    {
        //Create texture from surface pixels
        newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
        if( newTexture == NULL )
        {
            printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
        }

        //Get rid of old loaded surface
        SDL_FreeSurface( loadedSurface );
    }

    return newTexture;
}

Nossa função de carregamento de texturas se parece muito com o que tínhamos antes, mas agora ao invés de converter a superfície carregada para o formato de exibição, criamos uma textura a partir da superfície carregada usando SDL_CreateTextureFromSurface. Como antes, essa função cria uma nova textura a partir de uma superfície existente, o que significa que como antes temos que liberar a superfície carregada e então retornar a textura carregada.

bool loadMedia()
{
    //Loading success flag
    bool success = true;

    //Load PNG texture
    gTexture = loadTexture( "07_texture_loading_and_rendering/texture.png" );
    if( gTexture == NULL )
    {
        printf( "Failed to load texture image!\n" );
        success = false;
    }

    return success;
}

void close()
{
    //Free loaded image
    SDL_DestroyTexture( gTexture );
    gTexture = NULL;

    //Destroy window
    SDL_DestroyRenderer( gRenderer );
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;
    gRenderer = NULL;

    //Quit SDL subsystems
    IMG_Quit();
    SDL_Quit();
}

Como o carregamento da textura é abstraída com nossa função de carregamento de imagem, a função loadMedia() funciona praticamente de mesma forma que antes.

Na nossa função de limpeza, temos que lembrar de desalocar nossa texturas usando SDL_DestroyTexture.

            //While application is running
            while( !quit )
            {
                //Handle events on queue
                while( SDL_PollEvent( &e ) != 0 )
                {
                    //User requests quit
                    if( e.type == SDL_QUIT )
                    {
                        quit = true;
                    }
                }

                //Clear screen
                SDL_RenderClear( gRenderer );

                //Render texture to screen
                SDL_RenderCopy( gRenderer, gTexture, NULL, NULL );

                //Update screen
                SDL_RenderPresent( gRenderer );
            }

No loop principal, após o loop de eventos, chamados SDL_RenderClear. Essa função preenche a tela com as cores que foram configuradas com SDL_SetRenderDrawColor.

Com a tela liberada, renderizamos a textura com SDL_RenderCopy. Com atextura renderizada, temos que atualizar a tela, mas como não estamos usando SDL_Surfaces para renderização não podemos usar SDL_UpdateWindowSurface. Ao invés disso, usamos SDL_RenderPresent.

Baixe o código fonte e arquivos de mídia desse artigo aqui.