Уроки по SDL 2: Урок 5 — Текстуры

    Всем привет и добро пожаловать на пятый урок по SDL 2, в котором мы разберем текстуры, упростив работу компьютеру. Все уроки на английском языке вы можете найти здесь.

    В SDL второй версии появиласть очень хорошая возможность создания текстур и их рендеринга. Аппаратный рендеринг значительно быстрее, чем отрисовка поверхностей в окне.

    У текстур есть собственный тип данных — SDL_Texture. При работе с текстурами нам потребуется рендер для отрисовки. Сейчас мы всё это объявим.

    #include <SDL2/SDL.h>
    #include <SDL2/SDL_image.h>
    #include <iostream>
    
    using namespace std;
    
    int SCREEN_WIDTH = 640;
    int SCREEN_HEIGHT = 480;
    
    SDL_Window *win = NULL;
    SDL_Renderer *ren = NULL;
    SDL_Texture *flower = NULL;
    

    Здесь мы объявили окно, рендер и этот цветок.
    Так же подключили библиотеки и задали размеры окна.

    Функцию Init тоже придется изменить.

        bool ok = true;
    
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
            cout << "Can't init: " << SDL_GetError() << endl;
            ok = false;
        }
    
        win = SDL_CreateWindow("Текстуры", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
        if (win == NULL) {
            cout << "Can't create window: " << SDL_GetError() << endl;
            ok = false;
        }
    

    Для начала создадим переменную ok, для того, чтобы не заканчивать функцию сразу, а найти все ошибки при инициализации. Далее инициализируем SDL и уже известным способом создаем окно.

    Пришло время объявить рендер.

        ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
        if (ren == NULL) {
            cout << "Can't create renderer: " << SDL_GetError() << endl;
            ok = false;
        }
        SDL_SetRenderDrawColor(ren, 0xFF, 0xFF, 0xFF, 0xFF);
    

    Рендер объявляется функцией SDL_CreateRenderer. Она принимает 3 значения: окно, для которого будет использоваться этот рендер, индекс драйвера(или -1, если мы хотим найти первый подходящий) и флаги. Я использовал флаги SDL_RENDERER_ACCELERATED и SDL_RENDERER_PRESENTVSYNC. Вот список всех флагов:

    Флаги
    SDL_RENDERER_SOFTWARE — запасной вариант по;
    SDL_RENDERER_ACCELERATED — использование аппаратного ускорения;
    SDL_RENDERER_PRESENTVSYNC — вертикальная синхронизация;
    SDL_RENDERER_TARGETTEXTURE — поддержка рендеринга в текстуру.

    Дальше мы используем функцию SDL_SetRenderDrawColor, которая устанавливает цвет рисования примитивов.

    После этого инициализируем IMG и возвращаем ok.

        int flags = IMG_INIT_PNG;
        if (!(IMG_Init(flags) & flags)) {
            cout << "Can't init image: " << IMG_GetError() << endl;
            ok = false;
        }
    
        return ok;
    }
    

    Теперь напишем функцию Load.

    bool load() {
        bool ok = true;
        SDL_Surface * temp_surf = NULL;
        temp_surf = IMG_Load("flower.png");
        if (temp_surf == NULL) {
            cout << "Can't load image: " << IMG_GetError() << endl;
            ok = false;
        }
    

    Здесь мы так же создали переменную ok, для тех же нужд. Создали временную поверхность и загрузили в нее изображения цветка.

    Далее нам нужно сделать из поверхности текстуру.

        flower = SDL_CreateTextureFromSurface(ren, temp_surf);
        if (flower == NULL) {
            cout << "Can't create texture from surface: " << SDL_GetError() << endl;
            ok = false;
        }
    

    В создании текстуры нам поможет функция SDL_CreateTextureFromSurface. Она принимает значения рендера и поверхности. Возвращяет уже экземпляр класса SDL_Texture.

    Чтобы не засорять память, нам нужно очистить временную поверхность. После этого возвращяем ok и функция готова.

    Функция Quit обрела еще несколько действий.

    void quit() {
        SDL_DestroyWindow(win);
        win = NULL;
    
        SDL_DestroyRenderer(ren);
        ren = NULL;
    
        SDL_DestroyTexture(flower);
        flower = NULL;
    
        SDL_Quit();
        IMG_Quit();
    }
    

    Здесь мы удалили окно, рендер, текстуру и вышли из SDL и IMG. Также я присвоил всем удаленным объектам NULL для еще лучшей очистки памяти.

    Начинаем писать Main функцию.

    int main (int argc, char ** argv) {
    
        if (!init()) {
            quit();
            return 1;
        }
        if (!load()) {
            quit();
            return 1;
        }
    

    Написали инициализацию и загрузку, здесь не останавливаемся.

    Следующим шагом создадим 2 переменные.

        bool run = true;
        SDL_Event e;
    

    Эта программа будет с главным циклом, чтобы освежить память, так что начнем его неаписание.

    while (run) {
            while(SDL_PollEvent(&e) != 0) {
                if (e.type == SDL_QUIT) {
                    run = false;
                }
            }
    

    Обработали событие нажатия крестика и всё.

    Пришло время рисования. При использовании текстур и рендера для отрисовки используются отличные функции от тех, что мы знаем. Для того, чтобы очистить экран от нарисованных текстур, используется функция SDL_RenderClear. Она закрашивает экран цветом, который мы указали функцией SDL_SetRenderDrawColor. Для отрисовки текстуры исрользуется функция SDL_RenderCopy, а для обновления экрана — SDL_RenderPresent. Сечас их напишем.

            SDL_RenderClear(ren);
            SDL_RenderCopy(ren, flower, NULL, NULL);
            SDL_RenderPresent(ren);
        }
    

    Разберем только функцию SDL_RenderCopy. Она принимает 4 значения. Первое — рендер, второе — текстура, третье — прямоугольник, область которого мы хотим вырезать для отрисовки, четвертое — прямоугольник, координаты которого используются для отрисовки, а ширина и высота — для изменения размеров текстуры.

    Далее вызываем функцию Quit и возвращаем 0.

        quit();
        return 0;
    }
    

    На этом я урок окончю, если что-то было непонятно — пишите, а я прощаюсь, всем пока!

    Кстати вот полный код:

    #include <SDL2/SDL.h>
    #include <SDL2/SDL_image.h>
    #include <iostream>
    
    using namespace std;
    
    int SCREEN_WIDTH = 640;
    int SCREEN_HEIGHT = 480;
    
    SDL_Window *win = NULL;
    SDL_Renderer *ren = NULL;
    SDL_Texture *flower = NULL;
    
    bool init() {
        bool ok = true;
    
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
            cout << "Can't init: " << SDL_GetError() << endl;
            ok = false;
        }
    
        win = SDL_CreateWindow("Текстуры", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
        if (win == NULL) {
            cout << "Can't create window: " << SDL_GetError() << endl;
            ok = false;
        }
    
        ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
        if (ren == NULL) {
            cout << "Can't create renderer: " << SDL_GetError() << endl;
            ok = false;
        }
        SDL_SetRenderDrawColor(ren, 0xFF, 0xFF, 0xFF, 0xFF);
    
        int flags = IMG_INIT_PNG;
        if (!(IMG_Init(flags) & flags)) {
            cout << "Can't init image: " << IMG_GetError() << endl;
            ok = false;
        }
    
        return ok;
    }
    
    bool load() {
        bool ok = true;
        SDL_Surface * temp_surf = NULL;
        temp_surf = IMG_Load("flower.png");
        if (temp_surf == NULL) {
            cout << "Can't load image: " << IMG_GetError() << endl;
            ok = false;
        }
    
        flower = SDL_CreateTextureFromSurface(ren, temp_surf);
        if (flower == NULL) {
            cout << "Can't create texture from surface: " << SDL_GetError() << endl;
            ok = false;
        }
    
        SDL_FreeSurface(temp_surf);
    
        return ok;
    }
    
    void quit() {
        SDL_DestroyWindow(win);
        win = NULL;
    
        SDL_DestroyRenderer(ren);
        ren = NULL;
    
        SDL_DestroyTexture(flower);
        flower = NULL;
    
        SDL_Quit();
        IMG_Quit();
    }
    
    int main (int argc, char ** argv) {
    
        if (!init()) {
            quit();
            return 1;
        }
        if (!load()) {
            quit();
            return 1;
        }
    
        bool run = true;
        SDL_Event e;
    
        while (run) {
            while(SDL_PollEvent(&e) != 0) {
                if (e.type == SDL_QUIT) {
                    run = false;
                }
            }
    
            SDL_RenderClear(ren);
            SDL_RenderCopy(ren, flower, NULL, NULL);
            SDL_RenderPresent(ren);
        }
    
        quit();
        return 0;
    }
    

    Предыдущий урок | Следующий урок
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое