Форум программистов, компьютерный форум, киберфорум
Rem_
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

SDL2 разделение функций, вывод изображения.

Запись от Rem_ размещена 24.08.2015 в 09:22
Показов 7606 Комментарии 0

Мы научились открывать окно. Теперь выведем на него рисунок.
В оригинальном уроке автор теперь будет размещать только главные части кода.
Сам урок тут - http://lazyfoo.net/tutorials/S... /index.php
Архив с исходниками тут - http://lazyfoo.net/tutorials/S... screen.zip
Открывайте сразу код, он на 120 строк, и давайте изучать.

В первом уроке всё помещено в main функцию, так как программа маленькая. В реальных программах код разбивается на модули. Это позволит создавать отдельные части, каждую из которых можно независимо исправлять и изменять.
Создадим отдельные функции для инициализации, для загрузки изображения, и для закрытия sdl. Объявляем в верху исходника.
C
1
2
3
bool init();
bool loadMedia();
void close();
Теперь объявляем глобальные переменные. Обычно стараются избегать глобальных, но мы делаем программу как можно проще, всё находится в одном файле, поэтому оставим так.
Новый тип переменной - SDL_Surface - это просто тип данных изображения, в котором содержится информация о пикселях. SDL_Surface использует программный рендер. Это значит что для рендера будут использоваться ресурсы процессора (CPU). Можно рендерить используя аппаратные средства, но это чуть сложнее и будет рассмотрено позже на примере с использованием графической карты (GPU).
Изображение будет загружаться из файла и отображаться в окне.

Обратите внимание, что это SDL_Surface* указатель на поверхность. Для чего так сделано?
  1. Динамическое использование памяти для загрузки изображения
  2. Удобное обращение к изображению в памяти. Например, для отрисовки нескольких кирпичей. Намного проще держать в памяти одно изображение и использовать его несколько раз снова и снова.
И не забывайте после объявления сразу инициализировать значением NULL:
C
1
2
3
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
SDL_Surface* gHelloWorld = NULL;
Функцию инициализации и создания окна выносим в отдельную функцию. Мы вызываем SDL_GetWindowSurface, чтоб получить сёрфейс нашего окна. Именно туда мы будем выводить изображение.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool init()
{
    bool success = true;
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = false;
    }
    else
    {
        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
        {
            gScreenSurface = SDL_GetWindowSurface( gWindow );
        }
    }
    return success;
}
В функции загрузки изображения загружаются файлы используя SDL_LoadBMP. По указанному адресу берётся .bmp файл и помещается в указанную поверхность. Возвращает указатель на эту поверхность. Если вернуло NULL значит произошла ошибка и текст ошибки выведется на консоль.
C
1
2
3
4
5
6
7
8
9
10
11
bool loadMedia()
{
    bool success = true;
    gHelloWorld = SDL_LoadBMP( "02_getting_an_image_on_the_screen/hello_world.bmp" );
    if( gHelloWorld == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
        success = false;
    }
    return success;
}
В данном примере в папке проекта, в папке "02_getting_an_image_on_the_screen" ищется файл с именем "hello_world.bmp". Если программа не может найти изображение, проверяйте внимательнее адреса.

В завершающей функции нужно закрыть окно и выйти из SDL. Но перед этим нужно освободить память от поверхностей SDL_FreeSurface. Поверхность окна освободится при функции SDL_DestroyWindow.
Возьмите в привычку присваивать указателям значение NULL, когда они пока ни куда не указывают.
C
1
2
3
4
5
6
7
8
9
10
void close()
{
    SDL_FreeSurface( gHelloWorld );
    gHelloWorld = NULL;
 
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;
 
    SDL_Quit();
}
Теперь main функция. В ней вызываем инициализацию sdl и загрузку изображения. Если всё пройдёт успешно, то изображение из загруженной поверхности выведется на оконную поверхность используя SDL_BlitSurface.
Что делает блиттинг (blitting)? Он берёт исходную поверхность (source surface) и переносит на целевую поверхность (destination surface). Первый аргумент функции SDL_BlitSurface - поверхность источник, третий аргумент - конечная поверхность. Второй и четвертый будут рассмотрены позже.
Начало main функции:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main( int argc, char* args[] )
{
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
В нашем примере всего одна функция для рисования. Но изображения ещё не видно. Нужно сделать ещё шаг.
C
1
SDL_UpdateWindowSurface( gWindow );
Обычно, пока вы последовательно прорисовываете то, что нужно в данном кадре, вы этого не видите. Вам нужно обновить экран используя SDL_UpdateWindowSurface. Большинство систем рендеринга используют двойную буферизацию.
Когда вы рисуете используя SDL_BlitSurface, то рендер происходит в теневом буфере. На экране в этот момент показывается то, что находится в "переднем" буфере. Так делается, потому что в игре нужно нарисовать множество объектов. Если рисовать только во фронтальном буфере, то всё будет мигать, пока не нарисуется полный кадр. Поэтому сначала всё рисуется в теневом буфере, а затем мгновенно буферы меняются местами и человек видит полностью нарисованный кадр.
Не нужно вызывать SDL_UpdateWindowSurface после каждого блиттинга. Только после всех процедур рисования и блиттинга достаточно вызвать обновление, один раз для каждого кадра.

Вот мы всё нарисовали. Делаем задержку в 2 секунд, после чего закрываем программу
C
1
2
3
4
5
6
7
8
9
10
            //Wait two seconds
            SDL_Delay( 2000 );
        }
    }
 
    //Free resources and close SDL
    close();
 
    return 0;
}
В лучших традициях "всё правильно, но не работает" у меня не работает.
Почему? Потому что код написан в стиле c++, а компилятор думает что код написан на чистом c. Соответственно выхода два. Или код изменить под обычный си, или кодеблоксу объяснить, что надо компилировать в плюсах.
Сейчас я переделаю код, а в следующих уроках мы перейдём на c++. Кроме того, в коде будут изменения. Я попытаюсь нарисовать футбольный мячик на зеленом поле:
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <SDL.h>
#include <stdio.h>
 
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
 
int init(); // для инициализации. вместо типа bool пришлось поставить int
int loadMedia(); // для загрузки изображений
void close(); // для закрытия
 
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
SDL_Surface* gBall = NULL; // имя переделали для мяча
 
int init()
{
    int success = 1; // вместо bool пришлось использовать int и придавать числовые значения
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = 0;
    }
    else
    {
        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 = 0;
        }
        else
        {
            gScreenSurface = SDL_GetWindowSurface( gWindow ); // получаем поверхность окна
        }
    }
    return success;
}
 
int loadMedia()
{
    int success = 1;
    gBall = SDL_LoadBMP( "ball100.bmp" ); // размер нашего рисунка мяча 100*100 точек
    if( gBall == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", "ball100.bmp", SDL_GetError() );
        success = 0;
    }
    return success;
}
 
void close()
{
    SDL_FreeSurface( gBall ); // высвобождаем поверхности
    gBall = NULL;
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;
    SDL_Quit();
}
 
int main( int argc, char* args[] )
{
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            // заливаем поле зеленым
            SDL_FillRect( gScreenSurface, NULL, SDL_MapRGB( gScreenSurface->format, 0x00, 0x88, 0x00 ) );
            // рисуем мяч на поверхности окна
            SDL_BlitSurface( gBall, NULL, gScreenSurface, NULL );
            // обновляем окно
            SDL_UpdateWindowSurface( gWindow );
            SDL_Delay( 5000 );
        }
    }
    SDL_DestroyWindow( gWindow  );
    SDL_Quit();
    return 0;
}

Вот что получилось. Как видите, по углам остались белые уголки. В следующих уроках мы научимся использовать прозрачность для исправления этого, и отлавливать нажатия кнопок.
Нажмите на изображение для увеличения
Название: 2015-08-24 09 05 37.png
Просмотров: 546
Размер:	33.1 Кб
ID:	3276
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru