Содержание блога
Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным фоном) встроенными средствами библиотеки SDL3. Финальная демка запускается в браузерах на Desktop (Windows, Linux, macOS) и в браузерах на мобильных устройствах (Android и iOS). Исходники результата: finish-native-png-loader-wasm-sdl3-c.zip
Подключение библиотек SDL3 к стартовому примеру
- Установите Emscripten 4.0.15 и CMake по инструкции: Установка Emscripten SDK (emsdk) и CMake
- Скачайте стартовый пример: start-native-png-loader-wasm-sdl3-c.zip

- Код стартового примера:
src/main.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
| #define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stdio.h>
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO))
{
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("Example", 400, 400, 0, &window, &renderer))
{
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetRenderVSync(renderer, 1);
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT)
{
return SDL_APP_SUCCESS; // End the program, reporting success to the OS
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
// Clear the screen
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
SDL_RenderClear(renderer);
// Draw here...
// Update the screen
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
// SDL will clean up the window/renderer for us
} |
|
- Откройте папку со стартовым примером в какой-нибудь редакторе кода, например, в Notepad++ или в Sublime Text 4 (ST4): https://www.sublimetext.com/download
- Скачайте библиотеку SDL3: SDL3-devel-3.4.0-wasm.zip
- Извлеките содержимое архива в какую-нибудь новую общую папку, например, с именем "libs" на какой-нибудь диск, например, на C. Таким образом, создайте на диске C папку "lib", скопируйте в неё архивы и извлеките их в текущую папку:

- Откройте папку "SDL3-devel-3.4.0-wasm", перейдите в папку "lib/cmake/SDL3" и скопируйте абсолютный путь:

- В файле CMakeLists.txt стартового примера создайте переменную SDL3_DIR и установите ей значение скопированного пути, заменив обратные слеши на прямые:
| Bash | 1
| set(SDL3_DIR "C:/libs/SDL3-devel-3.4.0-wasm/lib/cmake/SDL3") |
|
- К этому моменту CMakeLists.txt выглядит так:
| Bash | 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
| cmake_minimum_required(VERSION 3.21)
project(start-load-png-wasm-sdl3-c)
# Задаем название будущего приложения (в Windows это был бы app.exe, а в вебе будет app.js / app.wasm)
add_executable(app)
# Устанавливаем стандарт C
set(CMAKE_C_STANDARD 11)
# Указываем точное местоположение конфигурационных файлов библиотеки SDL3
# Имя переменной должно строго соответствовать: НазваниеБиблиотеки_DIR
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.0-wasm/lib/cmake/SDL3")
# Проверяем наличие библиотек в системе
# Если она не будет найдены, CMake прервет настройку с ошибкой
# REQUIRED - переводится, как «обязательно» или «требуется»
find_package(SDL3 REQUIRED)
# Привязываем библиотеки к нашему приложению (настройка линковки и путей include)
target_link_libraries(app PRIVATE SDL3::SDL3)
# Добавляем исходный код к проекту
target_sources(app
PRIVATE
src/main.c
) |
|
Тестовая сборка и тестовый запуск стартового примера в браузере на локальном хостинге
- Откройте консоль (CMD) в корне стартового примера. Для этого можете просто в адресной строке папки (там где путь) написать "cmd" (без кавычек) и нажать Enter
- В CMD введите команду для конфигурирования:
- Примечание. "config-web" - это имя bash-файла (батника), который находится в корне папки стартового примера
- В CMD введите команду сборки проекта:
- Собранные файлы (app.js и app.wasm) будут скопированы в папку "public/js" (папка "public" лежит в корне проекта)
- В корне проекта запустите локальный сервер командой:
- Примечание 1. Будут выведены адреса:
| Bash | 1
2
3
4
| Available on:
http://192.168.1.65:8080
http://127.0.0.1:8080
Hit CTRL-C to stop the server |
|
- Примечание 2. Адрес 192.168.1.65:8080 можно использовать для запуска приложения на мобильном устройстве, если у вас есть Wi-Fi - просто вводите этот адрес в браузере мобильного устройства и приложение запустится. Если интересен запуск на мобильном устройстве, то пройдите пошаговую инструкцию: Основы отладки веб-приложений на SDL3 по USB и Wi-Fi
- Откройте новую вкладку в браузере. Если у вас Chrome или Edge, то нажмите Ctrl+Shift+J, чтобы открыть консоль браузера для контроля вывода информации. Если у вас FireFox, то нажмите Ctrl+Shift+K
- Перейдите по адресу:
- Примечание. Обновлять страницу после пересборки проекта лучше с очисткой кэша браузера. Для этого (обязательно с открытой консолью браузера) в браузере Chrome нужно найти в левом верхнем углу браузера кнопку обновления страницы (круговая стрелка), нажать по ней правой кнопкой мыши и выбрать "Empty Cache and Hard Reload"
- В браузере должен выводиться квадрат тёмного-серого цвета - это холст для рисования. Приложение должно собраться и запуститься без ошибок
Добавление файла изображения в проект
- Скачайте PNG-файл с прозрачным фоном: right-arrow.zip
- Примечание. Это бесплатный файл, который был взят по ссылке
- Внутри папки стартового примера создайте вложенную папку "assets/images" и скопируйте в неё скаченный файл:

- Откройте файл CMakeLists.txt в редакторе кода и скопируйте в него (в конец файла) код для встраивания изображения в файл "app.wasm":
| Bash | 1
2
3
4
5
6
| # Встраиваем изображение в файл app.wasm
if (EMSCRIPTEN)
target_link_options("app" PRIVATE "SHELL:--embed-file \"${CMAKE_CURRENT_SOURCE_DIR}/assets/images/right-arrow.png@/assets/images/right-arrow.png\"")
set_property(TARGET "app" APPEND PROPERTY LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/assets/images/right-arrow.png")
endif() |
|
- Изображение добавлено в проект. Таким же образом вы можете добавлять и другие файлы: звуковые файлы, файлы шрифтов и т.д.
Написание кода для вывода изображения
Лучше всего код набирать вручную, а не копировать, чтобы он лучше запоминался и в дальнейшем было проще и проще с ним работать. Мы напишем код пошагово - строка за строкой.
- Откройте файл src/main.c в редакторе кода
- Напишите код создания переменной указателя: texture после создания окна (window) и рисовальщика (renderer):
| C | 1
2
3
| static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Texture *texture = NULL; |
|
- Примечание 1. Ключевое слово static означает, что имя переменной-указателя будет видимо только в пределах файла.
- Примечание 2. Для того, чтобы избежать глобальных переменных нужно использовать аргумент appstate (первый аргумент всех 4-x callback-функции SDL3), как в прикреплённом примере этой инструкции по нативной сборки для Android: SDL3 для Android: Работа со звуком через SDL3_mixer
- Лучше сразу, чтобы не забыть, написать код уничтожения текстуры перед закрытием приложения в функции SDL_AppQuit():
| C | 1
2
3
4
5
6
| void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
// SDL will clean up the window/renderer for us
SDL_DestroyTexture(texture);
} |
|
- В начале файла main.c найдите функцию SDL_AppInit(), которая вызывается один раз самой первой:
| C | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO))
{
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("Example", 400, 400, 0, &window, &renderer))
{
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetRenderVSync(renderer, 1);
return SDL_APP_CONTINUE;
} |
|
- На данный момент здесь в начале происходит инициализация библиотеки SDL3 с помощью вызова функции SDL_Init():
| C | 1
2
3
4
5
| if (!SDL_Init(SDL_INIT_VIDEO))
{
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
} |
|
- Далее создаются окно и рисовальщик с помощью вызова функции SDL_CreateWindowAndRenderer()
- Вызов функции SDL_SetRenderVSync() включает синхронизацию, то есть вызов функции SDL_AppIterate() будет происходить с той же частотой, с которой работает монитор компьютера
- После функции SDL_SetRenderVSync() добавьте код загрузки файла-изображения и создания текстуры:
| C | 1
2
3
4
5
6
7
8
9
10
| const char *texturePath = "./assets/images/right-arrow.png";
SDL_Surface *surface = SDL_LoadPNG(texturePath);
if (!surface)
{
SDL_Log("PNG load failed: %s: %s\n", texturePath, SDL_GetError());
return SDL_APP_FAILURE;
}
texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_DestroySurface(surface); |
|
- В функции SDL_AppIterate() добавьте код вывода изображения:
| C | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| SDL_AppResult SDL_AppIterate(void *appstate)
{
// Clear the screen
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
SDL_RenderClear(renderer);
SDL_FRect srcRect = { 0, 0, 512, 512 };
SDL_FRect destRect = { 50, 50, 100, 100 };
SDL_RenderTexture(renderer, texture, &srcRect, &destRect);
// Update the screen
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
} |
|
- Сделаем сборку кода и запуск приложения. Сейчас у вас должен быть запущен локальный сервер от тестовой сборки вначале инструкции. Если нет, то запустите локальный сервер в корне проекта из CMD:
- Откройте ещё одну консоль внутри папки проекта и выполните команду:
- Примечание. Не нужно выполнять команду "config-web", потому что её требуется вводить только один раз, а далее CMake будет сам проверять перед сборкой были ли изменения в CMakeLists.txt и если изменения были, то CMake сам переконфигурирует проект
- Если вы закрыли вкладку браузера, то откройте новую, нажмите Ctrl+Shift+J в Chrome/Edge (Ctrl+Shift+K) в FireFox и обновите страницу
- Примечание. Можете подключить смартфон по USB-кабелю и протестировать код: Основы отладки веб-приложений на SDL3 по USB и Wi-Fi Если вы уже пробовали, то перейдите на компьютере по адресу chrome://inspect/#devices Найдите приложение в списке и нажмите "inspect". Вы увидите экран смартфона на компьютере
- В браузере да Desktop и в браузере на мобильном вы увидите результат работы приложения:

Сборка в релиз
- Для сборки в релиз нужно открыть файл "config-web.bat" в редакторе кода и исправить Debug на Release:
config-web.bat
| Bash | 1
| emcmake cmake -S . -B dist -DCMAKE_BUILD_TYPE=Release |
|
- Выполните команды конфигурирования и сборки:
- Примечание. Вес файлов после сборки в Debug:
| Code | 1
2
| app.js - 376 KB
app.wasm - 1.37 MB |
|
Вес файлов после сборки в Release:
| Code | 1
2
| app.js - 183 KB
app.wasm - 803 KB |
|
Развёртывание на бесплатном хостинге Vercel
- Скачайте установщик Node.js и установите: https://nodejs.org/en/download
- Установите Vercel следующей командой из консоли глобально:
- Зарегистрируйтесь на Vercel: https://vercel.com/
- Примечание. В стартовом прмер, который скачали в начале, уже есть файл vercel.json для решения проблемы с загрузкой wasm-файла
- В консоле в корне проекта выполните команду:
- Выполните команду:
- Примечание. Будут заданы вопросы в консоли - просто нажимайте всегда Enter
- В консоль будет выведен адрес вашего приложения: https://start-native-png-loade... vercel.app
- Примечание. Когда вы что-то измените в проекте и захотите загрузить изменённое приложение на сервер, то введите команду:
|