Skip to content

Latest commit

 

History

History
204 lines (168 loc) · 6.66 KB

README.md

File metadata and controls

204 lines (168 loc) · 6.66 KB

[<-back]

Texture Loading and Rendering

A major new addition to SDL 2 is the texture rendering API. This gives you fast, flexible hardware based rendering. In this tutorial we'll be using this new rendering technique.

Preview


Textures in SDL have their own data type intuitively called an SDL_Texture. When we deal with SDL textures you need an SDL_Renderer to render it to the screen which is why we declare a global renderer named "gRenderer".

As you can also see we have a new image loading routine with loadTexture and a globally declared texture we're going to load.

//  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;

After we create our window, we have to create a renderer for our window so we can render textures on it. Fortunately this is easily done with a call to SDL_CreateRenderer.

After creating the renderer, we want to initialize the rendering color using SDL_SetRenderDrawColor. This controls what color is used for various rendering operations.

        //  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;
                }
            }
        }

Our texture loading function looks largely the same as before only now instead of converting the loaded surface to the display format, we create a texture from the loaded surface using SDL_CreateTextureFromSurface. Like before, this function creates a new texture from an existing surface which means like before we have to free the loaded surface and then return the loaded texture.

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;
}

Since texture loading is abstracted with our image loading function, the loadMedia() function works pretty much the same as before.

In our clean up function, we have to remember to deallocate our textures using SDL_DestroyTexture.

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

    //  Load PNG texture
    gTexture = loadTexture( "./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();
}

In the main loop after the event loop, we call SDL_RenderClear. This function fills the screen with the color that was last set with SDL_SetRenderDrawColor.

With the screen cleared, we render the texture with SDL_RenderCopy. With the texture rendered, we still have to update the screen, but since we're not using SDL_Surfaces to render we can't use SDL_UpdateWindowSurface. Instead we have to use SDL_RenderPresent.

            //  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 );
            }

[<-back]