Событийно-ориентированное программирование

До этого момента, вы, вероятно, писали программы в "командно-ориентированном" стиле, используя cin и cout. Эта руководство научит вас как проверять и обрабатывать события.

В оригинале автор использует термин "X out". Как я понял под этим подразумевается закрытие приложение, либо при помощи нажатия на значок крестика в заголовке окна, либо при помощи соответствующего клавиатурного сочетания, например, Alt + F4. Я буду называть это действие "закрытие приложения"

Событие это просто что-то, что произошло. Это может быть нажатие клавиши, движение мыши, изменение размера окна или в нашем случае, желание пользователя закрыть окно.

//Заголовки
#include
#include
#include
//Аттрибуты экрана
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//Поверхности, которые будут использоваться
SDL_Surface *image = NULL;
SDL_Surface *screen = NULL;

Здесь у нас все тоже самое что и раньше: подключение заголовочных файлов и объявление констант и структур для поверхностей.

//Структура для событий, которые будут использоваться
SDL_Event event;

А вот это уже кое-что новенькое. Структура SDL_Event хранит данные события, которые мы будем обрабатывать.

SDL_Surface *load_image( std::string filename ) {
    //Временное хранилище для загружаемого изображения
    SDL_Surface* loadedImage = NULL;
    //Оптимизированное изображение, которое и будет использоваться
    SDL_Surface* optimizedImage = NULL;
    //Загрузить изображение
    loadedImage = IMG_Load( filename.c_str() );
    //Если изображение загружено
    if( loadedImage != NULL ) {
        //Создать оптимизированное изображение
        optimizedImage = SDL_DisplayFormat( loadedImage );
        //Освободить ресурсы из-под старого изображения
        SDL_FreeSurface( loadedImage );
    }
    //Вернуть оптимизированное изображение
    return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination ) {
    //Делаем прямоугольник, для временного хранения смещений
    SDL_Rect offset;
    //Кладем смещения в прямоугольник
    offset.x = x;
    offset.y = y;
    //Копировать поверхность
    SDL_BlitSurface( source, NULL, destination, &offset );
}

Это наши функции для загрузки и копирования поверхностей. По сравнению с прошлой частью руководства ничего не поменялось.

bool init() {
    //Инициализировать все подсистемы SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) {
        return false;
    }
    //Подготовить экран
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT,
        SCREEN_BPP, SDL_SWSURFACE );
    //Если при подготовке экрана произошла ошибка
    if( screen == NULL ) {
        return false;
    }
    //Установить заголовок окна
    SDL_WM_SetCaption( "Event test", NULL );
    //Если все прошло хорошо
    return true;
}

Это наша функция инициализации. Она запускает SDL, подготавливает окно, устанавливает заголовок и возвращает false если происходит какая-нибудь ошибка.

bool load_files() {
    //Загрузить изображение
    image = load_image( "x.png" );
    //Если при загрузке произошла ошибка
    if( image == NULL ) {
        return false;
    }
    //Если все загрузилось
    return true;
}

Это функция загружающая файлы. Она загружает изображения и возвращает false если возникли какие-то проблемы.

void clean_up() {
    //Освободить поверхность
    SDL_FreeSurface( image );
    //Завершаем SDL
    SDL_Quit();
}

Здесь у нас функция очистки, вызываемая при завершении программы. Она освобождает нашу поверхность и завершает работу SDL.

int main( int argc, char* args[] ) {
    //Подтверждение того, что программа ожидает выхода
    bool quit = false;

Теперь мы дошли до нашей функции main Здесь мы объявляем переменную quit, которая следит за тем, желает ли пользователь покинуть программу. Так как приложение только что запустилось, мы устанавливаем ее в false, иначе завершение работы произойдет немедленно.

    //Инициализация
    if( init() == false ) {
        return 1;
    }
    //Загрузить файлы
    if( load_files() == false ) {
        return 1;
    }

Теперь мы вызываем функции инициализации и загрузки файлов, сделанные ранее.

    //Скопировать поверхность на экран
    apply_surface( 0, 0, image, screen );
    //Обновить экран
    if( SDL_Flip( screen ) == -1 ) {
        return 1;
    }

Затем мы показываем изображение на экране.

//До тех пор, пока пользователь не захотел закрыть приложение
    while( quit == false ) {

Теперь мы запускаем главный цикл программы. Этот цикл выполняется до тех пор, пока пользователь не установит quit в true.

        //Пока есть события для обработки
        while( SDL_PollEvent( &event ) ) {

В SDL, когда происходит событие, она попадает в "очередь событий". Очередь событий хранит данные для каждого произошедшего события. Поэтому если вы нажали кнопку мыши, передвинули мышь, а затем нажали на клавишу на клавиатуре, очередь событий будет выглядеть как-то так:SDL_PollEvent() занимается тем, что берет событие из очереди и помещает его данные в нашу структуру:В результате этот код продолжает получать данные событий, пока очередь не опустеет.

             //Если пользователь попытался закрыть окно
            if( event.type == SDL_QUIT ) {
                //Закрываем приложение
                quit = true;
            }
        }
    }

Когда пользователь попытается закрыть приложение, тип полученного события будет SDL_QUIT. Но когда пользователь делает это, программа не закрывается; это только сообщает нам, что пользователь хочет выйти из программы. А поскольку мы хотим чтобы программа завершилась, когда пользователь попытается её закрыть, мы устанавливаем quit в true и это прерывает цикл, в котором мы находимся.

    //Освободить поверхность и завершить работу SDL
    clean_up();
    return 0;
}

В конце концов, мы выполняем функцию очистки. Есть и другие способы обработки событий, например, SDL_WaitEvent() и SDL_PeepEvents(). Вы можете узнать о них в документации.

Скачать исходники

Примечание: теперь самое время узнать побольше о функциях SDL по обработке ошибок. У меня нет руководства по ним, но я затрагиваю их в статье 5 (англ.). В документация по SDL объясняется функция SDL_GetError(), а документация по SDL_image объясняет IMG_GetError(). SDL_ttf и SDL_mixer так же имеют свои функции обработки ошибок, так что не забудьте посмотреть и их.

Допольнительные материалы:
Cобытийно-ориентированное программирование (Event Driven Programming)

Установка библиотек расширений

SDL изначально поддерживает только файлы .bmp, но при использовании библиотеки SDL_image, вы сможете загружать BMP, PNM, XPM, LBM, PCX, GIF, JPEG, TGA и PNG. Библиотеки расширений позволяют вам использовать функции, которые SDL не поддерживает изначально. Установка расширений SDL совсем не сложна. Я бы даже сказал, что это проще чем базовая настройка SDL. Это часть руководства научит вас тому, как установить и настроить библиотек SDL_image. Как только вы узнаете как установить это расширение, вы сможете установить и настроить любое другое.

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

  1. Пользователи Ubuntu могут воспользоваться пакетным менеджером. Открыв его ищите пакет libsdl-image1.2-dev, который является пакетом для разработки под SDL. Как только вы нашли его, нажимайте установить. Если вы устанавливаете SDL_ttf, ищите libsdl-ttf2.0-dev. Если SDL_mixed, ищите libsdl-mixer1.2-dev. И т.д. и т.д.
  2. Для дистрибутивов основанных на RPM, вам нужны пакеты SDL_image для разбаботчиков. Пакет SDL_image можно найти на этой странице. Прокрутите окно до секции "Binary" и скачайте нужный пакет:Теперь запустите RPM и дайте ей сделать свое дело.
  3. Если в первой части руководства вы использовали apt-get, aptitude или yum для установки SDL, то у вас уже должны быть установлены пакеты SDL_image, SDL_ttf и SDL_mixer.

Теперь, когда вы установили библиотеки разработчика, самое время научится компилировать приложения с использованием библиотек. Когда вы компилируете приложение, просто добавьте -lSDL_image после g++ -o myprogram mysource.cpp -lSDL Если вы связываете с SDL_ttf, добавляйте -lSDL_ttf. Если SDL_mixer, то -lSDL_mixer. И т.д. и т.д. Для использования SDL_image убедитесь что вы включили заголовочный файл.

#include

Для SDL_ttf:

#include

Для SDL_mixer:

#include

И т.д. и т.д. Теперь библиотека готова к использованию. И можно использовать функции SDL_image. Главная функция, о которой вы бы хотели узнать это IMG_Load().

SDL_Surface *load_image( std::string filename ) {
    //Временное хранилище для загружаемого изображения
    SDL_Surface* loadedImage = NULL;
     //Оптимизированное изображение, которое и будет использоваться
    SDL_Surface* optimizedImage = NULL;
    //Загружаем изображение при помощи SDL_image
    loadedImage = IMG_Load( filename.c_str() );
    //Если изображение загружено
    if( loadedImage != NULL ) {
        //Создать оптимизированное изображение
        optimizedImage = SDL_DisplayFormat( loadedImage );
        //Освободить ресурсы из-под старого изображения
        SDL_FreeSurface( loadedImage );
    }
    //Вернуть оптимизированное изображение
    return optimizedImage;
}

Перед вами пересмотренная версия функции загрузки изображений из предыдущей части руководства. Как вы можете видеть, IMG_Load() работает так же как и SDL_LoadBMP(), но с одни большим исключением: IMG_Load() может загружать файлы BMP, PNM, XPM, LBM, PCX, GIF, JPEG, TGA и PNG Начиная с этого момента, в руководствах будут использоваться изображения в формате PNG. Изображения в этом формате используют великолепный алгоритм сжатия без потерь.

Скачать исходники. Рекомендую держать под рукой документацию по SDL_image. Попоробуйте ввести в терминале

man IMG_Load

Если документация не установилась при установке пакетов, вы можете найти ее на этой странице.

Загрузка и копирование оптимизированных поверхностей

Оригинальный заголовок: Optimized Surface Loading and Blitting. В английском варианте используется термин BLIT — BLock Image Transfer. Дословно его можно перевести как "перенос блоков изображения". В сущности "блитинг" заключается в копировании прямоугольника с одной поверхности в такой же или меньший прямоугольник другой поверхности. Поэтому в переводе я буду использовать термин "копирование", как перевод для "блитинга"

Теперь, когда вы получили изображение на экране во второй половине предыдущей части руководства, самое время научиться загружать и копировать поверхности в более эффективной манере.

//Заголовки
#include
#include

Тут мы подключаем заголовочые файлы для нашей программы. SDL.h подключен потому, что мы, очевидно, будем использовать функции SDL. Заголовок string используется потому, что ... эмм, я просто больше предпочитаю std::string чем char*.

//Аттрибуты экрана
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

Тут мы определяем различные аттрибуты для экрана. Я вполне уверен что вы и сами понимаете зачем нужны SCREEN_WIDTH и SCREEN_HEIGHT. SCREEN_BP это количество битов на пиксель. Во всех частях руководства будет использоваться значение в 32 бита на пиксель.

//Поверхности, которые будут использоваться
SDL_Surface *message = NULL;
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;

Это три изображения, которые мы будем использовать. "background" очевидно соответствует фоновому изображению, "message" это растровое изображение говорящее "Hello", ну и "screen" — очевидно экран. Помните: хорошей практикой будет всегда устанавливать ваши указатели в NULL, если они пока что никуда не указывают.

SDL_Surface *load_image( std::string filename ) {
    //Временное хранилище для загружаемого изображения
    SDL_Surface* loadedImage = NULL;
    //Оптимизированное изображение, которое и будет использоваться
    SDL_Surface* optimizedImage = NULL;

Это наша функция, загружающая изображения. Она загружает изображение и возвращает указатель на оптимизированную версию загруженной картинки. Аргумент "filename" это путь к изображению, которое нужно загрузить. "loadedImage" — поверхность в которую изначально загружается изображение. "optimizedImage" — поверхность, которая будет использоваться впоследствии.

    //Загрузить изображение
    loadedImage = SDL_LoadBMP( filename.c_str() );

Перво наперво загружаем изображение при помощи SDL_LoadBMP() Но не следует использовать его сразу, потому что оно 24-битное. Экран 32-битный и не самой лучшей идеей будет копировать одну поверхность на другую, отличающуюся форматом, потому что SDL будет вынуждена изменять формат на лету, что вызовет падение производительности.

    //Если при загрузке изображения не произошло ничего непредвиденного
    if( loadedImage != NULL ) {
        //Создать оптимизированное изображение
        optimizedImage = SDL_DisplayFormat( loadedImage );
        //Освободить ресурсы из-под старого изображения
        SDL_FreeSurface( loadedImage );
    }

Дальше мы проверяем успешно ли было загружено изображение. Если произошла ошибка, loadedImage будет равно NULL Если изображение загружено правильно, мы вызываем SDL_DisplayFormat(), которая создаст новую версию "loadedImage" в формате экрана. Причина по которой мы это делаем, заключается в том, что когда вы попытаетесь поместить одну поверхность на другую с отличающимся форматом, SDL преобразует поверхности так, чтобы они были в одном формате. Создание преобразованных поверхностей каждый раз, когда вы их копируете, в пустую тратит процессорное время, что выливается в пониженную скорость выполнения. Так как мы преобразуем поверхность в момент загрузки, то когда вы захотите перенести ее на экран, они уже будут в одинаковых форматах. И тогда SDL не придется преобразовывать их на лету. И так, теперь у нас есть две поверхности: старое загруженное изображение и новое оптимизированное.SDL_DisplayFormat() создала новое оптимизированное изображение, но не избавилась от старого. Поэтому мы вызываем SDL_FreeSurface() чтобы избавится от старого загруженного изображения.

    //Вернуть оптимизированное изображение
    return optimizedImage;
}

Теперь мы возвращаем только что созданное оптимизированное изображение.

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination ) {
    //Делаем прямоугольник, для временного хранения смещений
    SDL_Rect offset;
    //Кладем смещения в прямоугольник
    offset.x = x;
    offset.y = y;

Это наша функция для копирования поверхностей. Она принимает координаты места, куда вы хотите скопировать поверхность, поверхность которую вы собираетесь копировать и поверхность на которую вы собираетесь копировать. В начале мы берем смещения и присваиваем их полям структуры SDL_Rect. Мы делаем это потому, что SDL_BlitSurface() принимает смещения только внутри SDL_Rect. SDL_Rect — тип данных, представляющий прямоугольник. Он содержит четыре поля, представляющих смещения по X, по Y, а также ширину и высоту прямоугольника. В данном случае нас интересуют только поля x и y.

    //Копировать поверхность
    SDL_BlitSurface( source, NULL, destination, &offset );
}

Теперь мы на самом деле копируем поверхность при помощи SDL_BlitSurface(). Первый аргумент это поверхность, которую мы используем. Не волнуйтесь по поводу второго аргумента, мы просто пока что присваиваем ему NULL. Третий аргумент это поверхность на которую мы собираемся копировать. Четвертый аргумент хранит смещения, по которым наша поверхность (source) будет скопирована на целевую (destination).

int main( int argc, char* args[] ) {

Теперь мы напишем нашу главную функцию — main При использовании SDL, вам всегда следует использовать:

int main( int argc, char* args[] )

или

int main( int argc, char** args )

Использование int main(), void main() или любого другого типа не сработает.

    //Инициализировать все подсистемы SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) {
        return 1;
    }

Тут мы запускаем SDL при помощи SDL_Init() Мы передаем в SDL_Init() флаг SDL_INIT_EVERYTHING, который запускает все подсистемы SDL. Подсистемы SDL это сущности типа видео, аудио, таймеров и т.д., которые являются отдельными компонентам движка, используемыми для создания игры. Мы не собираемся использовать все подсистемы, но не будет ничего страшного если мы тем не менее инициализируем их. Если SDL не удается запуститься, она возвращает -1. В этом случае мы обрабатываем ошибку, возвращая 1, тем самым завершая выполнение приложения.

    //Подготовить экран
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
        SDL_SWSURFACE );

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

    //Если при подготовке экрана произошла ошибка
    if( screen == NULL ) {
        return 1;
    }

Если при создании экрана что-то пошло не так, screen будет равно NULL

    //Установить заголовок окна
    SDL_WM_SetCaption( "Hello World", NULL );

Здесь мы устанавливаем текст заголовка окна: "Hello World" Заголовок это часть окна:

    //Загрузить изображения
    message = load_image( "hello.bmp" );
    background = load_image( "background.bmp" );

Теперь изображения загружены при помощи функции которую мы сделали.

    //Копировать фоновое изображение на экран
    apply_surface( 0, 0, background, screen );

Теперь пора скопировать фоновое изображение при помощи нашей функции. До того как мы скопировали фон, экран выглядит так:А теперь, когда мы скопировали фоновое изображение, экран в памяти выглядит так:Когда вы копируете поверхности, вы копируете пиксели с одной поверхности на другую. Поэтому теперь наш экран содержит фоновое изображение в верхнем левом углу, но мы хотим заполнить им все доступное место. Значит ли это что мы должны загрузить фоновое изображение еще три раза?

    apply_surface( 320, 0, background, screen );
    apply_surface( 0, 240, background, screen );
    apply_surface( 320, 240, background, screen );

Нет. Мы просто напросто можем скопировать ту же самую поверхность еще три раза.

    //Скопировать сообщение на экран
    apply_surface( 180, 140, message, screen );

Теперь мы собираемся скопировать поверхность с сообщением на экран со смещениями 180 по оси x и 140 по оси y. Суть в том, что координатная система в SDL не выглядит как то так:Система координат SDL выглядит так:Поэтому начало координат (0, 0) в левом верхнем углу, вместо левого нижнего. И поэтому когда вы копируете поверхность сообщения, она скопируется на 180 пикселей правее и на 140 пикселей ниже относительно начала координат в левом верхнем углу:Система координат SDL по началу кажется неудобной, но вы привыкнете к ней.

    //Обновить экран
    if( SDL_Flip( screen ) == -1 ) {
        return 1;
    }

Хотя мы и скопировали наши поверхности, экран по прежнему пуст. Теперь мы должны обновить экран при помоще SDL_Flip(), чтобы поверхность экрана в памяти совпадала с тем, что изображено на мониторе. Если при этом произошла ошибка, мы вернем 1;

    //Подождать две секунды
    SDL_Delay( 2000 );

Мы вызываем SDL_Delay() для того, чтобы окно не исчезло через долю секунды, сразу после появления. SDL_Delay() принимает время в миллисекундах, тоесть 1/1000 секунды. И так, окно будет будет показываться в течение 2000/1000 секунды, проще говоря две секунды.

    //Освободить поверхности
    SDL_FreeSurface( message );
    SDL_FreeSurface( background );
    //Завершаем SDL
    SDL_Quit();
    //Возвращаем 0
    return 0;
}

И наконец мы выполняем очищающие процедуры.SDL_FreeSurface() используется для того чтобы избавится от загруженных изображений, так как мы больше ими не пользуемся. Если мы не будет освобождать память которую мы использовали, это приведет к утечкам памяти. Потом SDL_Quit() вызывается для завершения работы SDL. Затем мы возвращаем 0, завершая выполнение программы. Вы возможно спрашиваете себя, "почему мы не освобождаем поверхность экрана (screen). Не волнуйтесь. SDL_Quit() позаботится об этом для нас.

Если при запуске приложения, изображения не появляются или окно появляется и тут же исчезает, и вы видите в консоли (или в файле stderr.txt): Ошибка сегментирования или Fatal signal: Segmentation Fault То это потому, что программа пытается обратится по адресу памяти, по которому ей не следует этого делать. Скорее всего это происходит потому, что apply_surface() попыталась обратится по нулевому указателю (NULL). Это означает что вам нужно убедится что файлы с изображениями находятся в той же директории что и сама программа. Если окно появляется, но изображений не видно, опять таки, убедитесь что файлы изображений в той же директории что и сама программа или в директории проекта.

Скачать исходники и материалы

Вывод на экран первого изображения

Это часть руководства о том, как написать Hello World в стиле SDL. Теперь, когда вы установили SDL, самое время написать простейшее графическое приложение, которое загружает и отображает изображение на экране.

//Подключить описания функция и типов данных SDL
#include

В самом верху исходного файла мы подключаем заголовочный файл SDL, для того чтобы мы могли использовать функции и типы данных SDL. Обращаю ваше внимание на то, что некоторым из вас (например тем кто использует Visual Studio) необходимо подключать заголовок SDL. Например так:

#include "SDL.h"

Так что если компилятор жалуется на то, что он не может найти <SDL/SDL.h>, то либо вы подключаете файл по неправильному пути, либо вы забыли положить SDL.h в нужное место.

int main( int argc, char* args[] )
{
    //Изображения
    SDL_Surface* hello = NULL;
    SDL_Surface* screen = NULL;

В начале функции main(), мы объявляем два указателя на структуры SDL_Surface. SDL_Surface это изображение, и в этом приложении мы собираемся иметь дело с двумя изображениями. Поверхность(surface) "hello" это изображение, которое мы собираемся загружать и отображать. "screen" это то, что будет видно на экране. Когда вы имеете дело с указателями, вы всегда должны их инициализировать. Также, когда вы работаете с SDL, вы должны объявлять вашу функцию main() таким же образом как в коде выше. Вы не можете использовать void main()target="_blank" или что-то подобное.

    //Инициализировать SDL
    SDL_Init( SDL_INIT_EVERYTHING );
    //Настроить экран
    screen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
    //Загрузить изображение
    hello = SDL_LoadBMP( "hello.bmp" );

Первая функция, которую мы вызываем в main это SDL_Init(). Вызов SDL_Init() инициализирует все подсистемы SDL, поэтому мы можем начать использовать графические функции SDL. Дальше мы вызываем SDL_SetVideoMode(), которая устанавливает ширину окна в 640 пикселей, высоту в 480 и глубину цвета в 32 бита на пиксель. Последний аргумент(SDL_SWSURFACE) располагает поверхность в программной памяти. Вызов SDL_SetVideoMode() возвращает указатель на поверхность окна, так что мы теперь можем ее использовать. После того как окно настроено, мы загружаем наше изображений при помощи SDL_LoadBMP(). SDL_LoadBMP() принимает в качестве аргумента путь к растровому изображению (bitmap) и возвращает указатель на загруженную SDL_Surface. В случае ошибки загрузки эта функци вернет NULL.

    //Вывести изображение на экран
    SDL_BlitSurface( hello, NULL, screen, NULL );
    //Обновить экран
    SDL_Flip( screen );
    //Пауза
    SDL_Delay( 2000 );

Теперь, когда мы настроили наше окно и загрузили изображение, мы хотим вывести загруженное изображение на экран. Мы делаем это при помощи функции SDL_BlitSurface(). Первый аргумент SDL_BlitSurface() это поверхность, которую мы хотим вывести (source, источник). Третий аргумент это поверхность, на которую мы хотим вывести наше изображение (destination, назначение). SDL_BlitSurface() помещает поверхность источника на поверхность назначения. В нашем случае она собирается вывести наше загруженное изображение на экран. О втором аргументе будет рассказано в последующих частях руководства. Теперь, когда наше изображение расположено на экране, нам нужно обновить экран, чтобы мы могли его увидеть. Мы делаем это используя SDL_Flip(). Если вы не вызовите SDL_Flip(), все что вы увидете это черный не обновленный экран. Теперь когда изображение выведено на экран и сделано видимым, нам нужно сделать так, чтобы окно оставалось видимым некоторое время, а не просто моргнуло на мгновение и исчезло. Мы добьемся этого вызовом SDL_Delay(). Здесь мы делаем задержку на 2000 миллисекунд(2 секунды). Более хороший способ заставить окно оставаться на месте мы узнаем в четвертой части руководства.

    //Освободить память из-под загруженного изображения
    SDL_FreeSurface( hello );
    //Освободить ресурсы занятые SDL
    SDL_Quit();
    return 0;
}

Теперь, когда нам больше не нужно загруженное изображение в нашей программе, нам надо удалить его из памяти. Вы не можете просто удалить указатель, вы должны использовать SDL_FreeSurface() для того чтобы удалить изображение из памяти. В конце мы вызываем SDL_Quit() для того чтобы завершить работу SDL. Вы возможно хотите узнать, почему мы не удаляем поверхность экрана(screen). Не волнуйтесь. SDL_Quit() удалит ее за нас. Поздравляю! Вы только написали ваше первое графическое приложение.

Скачать исходники

Установка SDL

Оригинал: Lazy Foo SDL Tutorial Представляю мой пробный перевод первой части руководства по SDL от Lazy Foo. Так как перевод пробный, я для начала переведу только ту часть руководства, которую я непосредственно проходил и соответственно тестировал. Это относится к тем частям, которые зависят от операционной системы и используемого ПО. В частности в этой статье я переведу установку SDL только под Linux, а сборку приложения только из командной строки. Так как SDL это сторонняя библиотека, вам придется устанавливать ее самостоятельно. Здесь я приведу пошаговое руководство по её установке. Если у вас возникли какие то проблемы, попробуйте почитать FAQ по разработке на SDL. Как только вы установите SDL, вы можете переходить ко второй половине руководства и научитесь загружать и отображать изображения на экране.

Так как существует огромное количество дистрибутивов, это руководство, возможно, не сработает на вашем дистрибутиве. Попробуйте почитать SDL Linux FAQ. Если вы все перепробовали и все еще ничего не работает, свяжитесь со мной и я попробую добавить инструкции по конкретному дистрибутиву.

Для дистрибутивов использующих APT (Debian, Ubuntu, Mint, etc) введите в терминале эти команды:

$ sudo aptitude install libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev

Или если aptitude не установлен:

$ sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev

Для дистрибутивов использующих yum(Yellow dog Updater) используйте следующее:

$ yum install SDL-devel SDL_mixer-devel SDL_image-devel SDL_ttf-devel

Так же как для aptitude или apt-get для установки вам нужны административные привилегии. (Запуск через sudo или от имени root'а) Для дистрибутивов основанных на RPM вы найдете эти пакеты на сайте SDL, в особенности на этой странице. Теперь, когда вы установили SDL, самое время открыть вашу любимую IDE или текстовый редактор.

Создайте текстовый файл(тоесть исходник) со следущим содержимым:

#include
int main( int argc, char* args[] )
{
   //Инициализировать SDL
   SDL_Init( SDL_INIT_EVERYTHING );
   //Освободить ресурсы занятые SDL
   SDL_Quit();
   return 0;
}

Теперь введите в командной строке:

g++ -o myprogram mysource.cpp -lSDL

и мы закончили.