Lessons on SDL 2: Lesson 4 - Stretching PNG

    Hello! This is the fourth lesson in SDL 2. I decided to combine the two lessons into one, since in the original they are small. But they can be found here and here . Well, let's start the lesson.

    First, we will decide what we will do. Today we’ll learn how to upload images of another extension (not BMP), namely: PNG. Redo the image in a different format to speed up the work and resize the image. We will work with this image:

    image

    Installation


    So, first we learn how to download PNG. In the standard SDL 2 feature set, there is no upload of a non BMP format image. To download a different format, you need to install the extension.

    Here are the instructions:

    Windows
    You go to this page and download the ZIP or TAR.GZ archives from the Development Libraries section . Unpack and throw them into the folder with the compiler.

    Linux
    If your system uses Debian, then you need to enter these commands:

    apt-cache search libsdl2-image
    apt-get install libsdl2-image-dev
    

    If Yellowdog Updater, Modified is used, then you enter these commands:

    yum search SDL2_image-devel
    yum установить SDL2_image-devel
    


    Mac OS
    Download the DMG file and read the Readme.

    Writing a code


    After setting SDL_image, we start writing code. First, as always, we will connect the libraries, set the window sizes and create 3 global variables.

    #include 
    #include 
    #include 
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    SDL_Window *win = NULL;
    SDL_Surface *scr = NULL;
    SDL_Surface *flower = NULL;
    

    Note that I connected SDL_image.h separately, as it is a separate library.

    Next, we write 3 functions, known to us, in which we will add and change something, as usual.

    Init ()
    bool init() {
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
            std::cout << "Can't init video: " << SDL_GetError() << std::endl;
            return false;
        }
        int flags = IMG_INIT_PNG;
        if ( !( IMG_Init( flags ) & flags ) ) {
            std::cout << "Can't init image: " << IMG_GetError() << std::endl;
            return false;
        }
        win = SDL_CreateWindow("Растяжка PNG", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
        if (win == NULL) {
            std::cout << "Can't create window: " << SDL_GetError() << std::endl;
            return false;
        }
        scr = SDL_GetWindowSurface(win);
        return true;
    }
    


    Here we have added initsalizatsiyu module SDL_image . To initialize it, first we create an int variable , we have flags , and save there all the flags that you want to use for initialization.

    List of all flags
    SDL_INIT_PNG - initializes the PNG image downloader;
    SDL_INIT_JPG - initializes the JPG image downloader;
    SDL_INIT_TIF - initializes the TIF image downloader;

    Next, we write this condition:

    if ( !( IMG_Init( flags ) & flags ) )
    

    The IMG_Init () function returns the flags that it was able to initialize. If she returned the flags, but the one we wanted was missing, we return an error. Very simple. Also, note that I use IMG_GetError instead of SDL_GetError , since we are looking for an error in the function of the SDL_image module , and not SDL .

    I also want to note that I decided to use the bool type to return a - this is a more rational way.

    Let's continue writing our program, write the Load () function , in which we load a PNG image and convert it.

    Load
    bool load() {
        flower = IMG_Load("flower.png");
        if (flower == NULL) {
            std::cout << "Can't load: " << IMG_GetError() << std::endl;
            return false;
        }
        flower = SDL_ConvertSurface(flower, scr->format, NULL);
        if (flower == NULL) {
            std::cout << "Can't convert: " << SDL_GetError() << std::endl;
            return false;
        }
        return true;
    }
    


    Here we upload the image with the new IMG_Load function . Its function is the same as that of SDL_LoadBMP and the result is the same - it returns an instance of the SDL_Surface class . To find errors during loading, we also use IMG_GetError .

    It's time to convert. First, a little theory. Few people know, but when downloading an image, it is downloaded in 24bit format, and most modern displays are in 32bit format. And every time we displayed the image on the screen, it was first redone in 32bit format. For simple programs, this does not matter, but when creating some kind of large project, it will greatly affect performance, so we will take and at the stage of loading images we will remake them in the display format. The SDL_ConvertSurface function will help . It takes 3 values: The surface we want to format, the format we want to format into, and the flags. we want to format the image flower, pass it as the first parameter. The second parameter is the format of the window surface, we will not use flags. This function returns a copy of the surface, which we immediately assign to flower . To search for errors, we take the SDL_GetError () function, because we are already working with surfaces, and they are from SDL , and not from SDL_image .

    Next we write the Quit function, add just one function to it.

    Quit
    void quit() {
        SDL_FreeSurface(flower);
        SDL_FreeSurface(scr);
        SDL_DestroyWindow(win);
        SDL_Quit();
        IMG_Quit();
    }
    


    We added IMG_Quit , to razynitsializirovat module SDL_image .

    Main


    Now the simplest thing remains - the main function .

    int main (int argc, char ** args) {
        if (!init()) {
            system("pause");
            quit();
            return 1;
        }
        if (!load()) {
            system("pause");
            quit();
            return 1;
        }
    

    To get started, initialize and create everything you need and upload the necessary files. We will not stop here.

        SDL_Rect bg_flower;
        bg_flower.w = SCREEN_WIDTH;
        bg_flower.h = SCREEN_HEIGHT;
        bg_flower.x = 0;
        bg_flower.y = 0;
    

    After that, create an object of class SDL_Rect . We will need it to stretch the image. If you notice, the flower image is 4 times smaller than the window size (2 times thinner and 2 times lower), and we need to stretch it to the window size. So in the width of the rectangle bg_flower write the value of the width of the window, and in height - the height of the window. set the coordinates to 0, so that the image is displayed in the upper left corner.

    To display images with resized, there is a special function. It looks like this:

       SDL_BlitScaled(flower, NULL, scr, &bg_flower);
    

    It takes 4 meanings. The first is the image we want to display, the second is the Rectangle that we want to cut from this image (if we want to take the whole image, we write NULL), the third is the surface on which we want to display the image, and the fourth is the same rectangle, dimensions and the coordinates of which we take to stretch or compress and display the image.

    Next, just update the screen surface, set the delay, exit and return 0.

        SDL_UpdateWindowSurface(win);
        SDL_Delay(2000);
        quit();
        return 0;
    };
    

    This is where our program ends. In order to compile this miracle, you need to add -lSDL2_image, as another compilation option.

    And on this we will end for today. Here is the code we got:

    #include 
    #include 
    #include 
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    SDL_Window *win = NULL;
    SDL_Surface *scr = NULL;
    SDL_Surface *flower = NULL;
    bool init() {
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
            std::cout << "Can't init video: " << SDL_GetError() << std::endl;
            return false;
        }
        int flags = IMG_INIT_PNG;
        if ( !( IMG_Init( flags ) & flags ) ) {
            std::cout << "Can't init image: " << IMG_GetError() << std::endl;
            return false;
        }
        win = SDL_CreateWindow("Растяжка PNG", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
        if (win == NULL) {
            std::cout << "Can't create window: " << SDL_GetError() << std::endl;
            return false;
        }
        scr = SDL_GetWindowSurface(win);
        return true;
    }
    bool load() {
        flower = IMG_Load("flower.png");
        if (flower == NULL) {
            std::cout << "Can't load: " << IMG_GetError() << std::endl;
            return false;
        }
        flower = SDL_ConvertSurface(flower, scr->format, NULL);
        if (flower == NULL) {
            std::cout << "Can't convert: " << SDL_GetError() << std::endl;
            return false;
        }
        return true;
    }
    void quit() {
        SDL_FreeSurface(flower);
        SDL_FreeSurface(scr);
        SDL_DestroyWindow(win);
        SDL_Quit();
        IMG_Quit();
    }
    int main (int argc, char ** args) {
        if (!init()) {
            system("pause");
            quit();
            return 1;
        }
        if (!load()) {
            system("pause");
            quit();
            return 1;
        }
        SDL_Rect bg_flower;
        bg_flower.w = SCREEN_WIDTH;
        bg_flower.h = SCREEN_HEIGHT;
        bg_flower.x = 0;
        bg_flower.y = 0;
        SDL_BlitScaled(flower, NULL, scr, &bg_flower);
        SDL_UpdateWindowSurface(win);
        SDL_Delay(2000);
        quit();
        return 0;
    };
    

    Bye everyone!

    << Previous lesson || Next lesson >>

    Also popular now: