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

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

Запись от Rem_ размещена 24.08.2015 в 09:22
Показов 7414 Комментарии 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
Просмотров: 522
Размер:	33.1 Кб
ID:	3276
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru