Содержание блога
Финальные проекты на Си и на C++:
Результат:

Напишем программу с нуля, которая выводит текст на русском с помощью библиотеки SDL3_ttf и рисует отрезками равносторонний треугольник.
Установка инструментов
- Установите CMake и MinGW 13.1 по пошаговой инструкции: Установка CMake и MinGW 13.1
- Скачайте следующие архивы библиотек:
- Извлеките содержимое архивов выше в какую-нибудь общую папку, например, с именем "libs" на C:

- Примечание. Эти архивы я скачал с официальных репозиториев на вкладках Release: SDL3 3.4.2 и SDL3_ttf 3.2.2. Я сократил глубину вложенность папок в архивах со словом "devel" в имени.
- Пути к папкам с "win32-x64" в именах нужно добавить в переменную окружения Path. В этих папках лежат SDL3.dll и SDL3_ttf.dll. Добавьте пути к этим папкам в Path:
- C:\libs\SDL3-3.4.2-win32-x64
- C:\libs\SDL3_ttf-3.2.2-win32-x64
- Установите редактор кода или IDE, например: Notepad++ или VSCode. Я использую Sublime Text 4 и Qt Creator
Настройка и запуск стартового проекта
- Скачайте стартовый проект: start-text-sdl3-c.zip
- Примечание. Этот стартовый проект был создан по пошаговой инструкции: Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
- Извлеките пример из архива:

- Код стартового примера:
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 // Использовать функции обратного вызова вместо main()
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.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("Рендерер SDL3", 400, 300, 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; // Завершаем программу, сообщая ОС об успехе
}
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается один раз за кадр и является сердцем программы
SDL_AppResult SDL_AppIterate(void *appstate)
{
SDL_SetRenderDrawColor(renderer, 38, 43, 51, 255); // Цвет заливки холста
SDL_RenderClear(renderer); // Начинаем с чистого холста - заливаем холст указанным выше цветов
// Выводим результат на экран
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается один раз при завершении работы
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
// 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
27
28
| cmake_minimum_required(VERSION 3.21)
project(start-text-sdl3-c)
# Устанавливаем стандарт C
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Задаем название будущего приложения (в Windows это будет app.exe, а
# в вебе было бы app.js / app.wasm)
add_executable(app)
# Указываем точное местоположение конфигурационных файлов библиотек
# Имя переменной должно строго соответствовать: НазваниеБиблиотеки_DIR
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.2-mingw/lib/cmake/SDL3")
# Добавляем исходный код к проекту
target_sources(app
PRIVATE
src/main.c
)
# Проверяем наличие библиотек в системе
# Если она не будет найдены, CMake прервет настройку с ошибкой
# REQUIRED - переводится, как "обязательно" или "требуется"
find_package(SDL3 REQUIRED)
# Привязываем библиотеки к нашему приложению
target_link_libraries(app PRIVATE SDL3::SDL3) |
|
config-exe.bat
| Bash | 1
2
| cmake -G "MinGW Makefiles" -S . -B dist/win ^
-DCMAKE_BUILD_TYPE=Debug |
|
build-exe.bat
| Bash | 1
2
3
| cd dist\win
cmake --build .
cd ..\.. |
|
run-exe.bat
- Откройте папку примера в каком-нибудь текстовом редакторе - например, в Sublime Text 4 (ST4), Notepad++, VS Code и т.д. В ST4 можно открыть проекта, набрав в консоли из папки проекта: "subl ." (без ковычек). Либо откройте проект в Qt Creator - для этого в левом верхнем углу Qt Creator нажмите "Fire" > "Open File or Project..." и выберите файл "CMakeLists.txt" из папки скаченного проекта
- Откройте файл "CMakeLists.txt" и убедитесь, что путь к библиотеке SDL3 такой же как у вас и при необходимости измените его на ваш путь:
| Bash | 1
| set(SDL3_DIR "C:/libs/SDL3-devel-3.4.2-mingw/lib/cmake/SDL3") |
|
- Откройте консоль в текущей папке и поочерёдно введите команды для конфигурирования, сборки и запуска EXE:
| Bash | 1
2
3
| config-exe
build-exe
run-exe |
|
- Будет запущено приложение, которое создаёт окно с помощью библиотеки SDL3 и заливает холст заданным цветом с помощью SDL3 Renderer:

- Мы настроили и протестировали корректный запуск стартового примера
Подключение библиотеки SDL3_ttf
- Откройте файл "CMakeLists.txt" в редакторе кода
- Добавьте создание переменной SDL3_ttf_DIR с значением пути, куда вы распаковали архив "SDL3_ttf-devel-3.2.2-mingw":
| Bash | 1
| set(SDL3_ttf_DIR "C:/libs/SDL3_ttf-devel-3.2.2-mingw/lib/cmake/SDL3_ttf") |
|
- Добавьте команду find_package для SDL3_ttf:
| Bash | 1
2
3
| # Загружаем настройки пакетов (параметры компиляции и пути к заголовкам)
find_package(SDL3 REQUIRED)
find_package(SDL3_ttf REQUIRED) |
|
- Добавьте привязку библиотеки SDL3_ttf к своему приложению:
| Bash | 1
2
| # Привязываем библиотеки к нашему приложению
target_link_libraries(app PRIVATE SDL3_ttf::SDL3_ttf SDL3::SDL3) |
|
- В результате получается следующий файл "CMakeLists.txt":
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
27
28
29
30
| cmake_minimum_required(VERSION 3.21)
project(finish-text-sdl3-c)
# Устанавливаем стандарт C
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Задаем название будущего приложения (в Windows это будет app.exe, а
# в вебе было бы app.js / app.wasm)
add_executable(app)
# Указываем точное местоположение конфигурационных файлов библиотек
# Имя переменной должно строго соответствовать: НазваниеБиблиотеки_DIR
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.2-mingw/lib/cmake/SDL3")
set(SDL3_ttf_DIR "C:/libs/SDL3_ttf-devel-3.2.2-mingw/lib/cmake/SDL3_ttf")
# Добавляем исходный код к проекту
target_sources(app
PRIVATE
src/main.c
)
# Проверяем наличие библиотек в системе
# Если она не будет найдены, CMake прервет настройку с ошибкой
# REQUIRED - переводится, как "обязательно" или "требуется"
find_package(SDL3 REQUIRED)
find_package(SDL3_ttf REQUIRED)
# Привязываем библиотеки к нашему приложению
target_link_libraries(app PRIVATE SDL3_ttf::SDL3_ttf SDL3::SDL3) |
|
Загрузка TTF-файла и вывод текста на холст
- Скачайте бесплатный шрифт: LiberationSans-Regular.zip
- Примечание. Шрифт был взять по ссылке
- Извлеките архив с файлом шрифта в новую папку "assets/fonts" внутри проекта
- Откройте в редакторе кода файл "src/main.c"
- Подключите заголовок "SDL_ttf.h" в начале файла:
| C | 1
2
3
4
| #define SDL_MAIN_USE_CALLBACKS 1 // Использовать функции обратного вызова вместо main()
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_ttf/SDL_ttf.h> |
|
- После создания переменной-указателя "renderer" добавьте переменную-указатель "textTexture" для текстуры, на которую будет рисоваться текст
- Сразу, чтобы не забыть освободить ресурс, добавьте удаление текстуры в функцию SDL_AppQuit() и добавьте завершить работу SDL3_ttf:
| C | 1
2
3
4
5
6
7
8
9
10
11
12
| // Эта функция запускается один раз при завершении работы
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
if (textTexture)
{
SDL_DestroyTexture(textTexture);
}
TTF_Quit();
// SDL3 автоматически освободит все ресурсы подсистем (окна, рендереры) при выходе
} |
|
- В функции SDL_AppInit() после вызова SDL_Init() добавьте инициализацию библиотеки SDL3_ttf:
| C | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Эта функция запускается один раз при старте
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 (!TTF_Init())
{
SDL_Log("Couldn't initialize TTF: %s", SDL_GetError());
return SDL_APP_FAILURE;
} |
|
- После вызова функции включения вертикальной синхронизации SDL_SetRenderVSync() добавьте код загрузки файла-шрифта и создания текстуры для текста:
| C | 1
2
3
4
5
6
7
8
9
10
11
12
13
| SDL_SetRenderVSync(renderer, 1);
TTF_Font *font = TTF_OpenFont("assets/fonts/LiberationSans-Regular.ttf", 28);
if (!font)
{
SDL_Log("TTF_OpenFont failed: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_Color textColor = (SDL_Color) { 245, 240, 220 };
SDL_Surface *surface = TTF_RenderText_Blended(font, "Равносторонний треугольник", 0, textColor);
texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_DestroySurface(surface);
TTF_CloseFont(font); |
|
- В цикле рисования, то есть в функции SDL_AppIterate(), добавьте код рисования текста:
| 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
| // Эта функция запускается один раз за кадр и является сердцем программы
SDL_AppResult SDL_AppIterate(void *appstate)
{
// Устанавливаем позицию, в которой хотим нарисовать текст
float x = 10.f;
float y = 30.f;
// Создаем прямоугольник для хранения размеров текстуры
SDL_FRect rect;
SDL_GetTextureSize(textTexture, &rect.w, &rect.h);
rect.x = x;
rect.y = y;
// Очищаем экран
SDL_SetRenderDrawColor(renderer, 38, 43, 51, 255); // Цвет заливки холста
// Начинаем с чистого холста - заливаем холст указанным выше цветов
SDL_RenderClear(renderer);
// Отрисовываем текст
SDL_RenderTexture(renderer, textTexture, NULL, &rect);
// Выводим результат на экран
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; // Продолжаем работу программы
} |
|
- Запустите сборку командой "build-exe" и запустите приложение командой "run-exe". Текст выводится на экран:

- Текущий код для вывода текста:
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
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
87
88
89
90
91
92
93
94
95
96
97
| #define SDL_MAIN_USE_CALLBACKS 1 // Использовать функции обратного вызова вместо main()
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_ttf/SDL_ttf.h>
// Мы будем использовать этот рендерер для рисования в этом окне каждый кадр
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Texture *textTexture = 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 (!TTF_Init())
{
SDL_Log("Couldn't initialize TTF: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("Рендерер SDL3", 400, 300, 0, &window, &renderer))
{
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetRenderVSync(renderer, 1);
TTF_Font *font = TTF_OpenFont("assets/fonts/LiberationSans-Regular.ttf", 28);
if (!font)
{
SDL_Log("TTF_OpenFont failed: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_Color textColor = (SDL_Color) { 245, 240, 220 };
SDL_Surface *surface = TTF_RenderText_Blended(font, "Равносторонний треугольник", 0, textColor);
textTexture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_DestroySurface(surface);
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается, когда происходит новое событие (ввод мыши, нажатие клавиш и т.д.)
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT)
{
return SDL_APP_SUCCESS; // Завершаем программу, сообщая ОС об успехе
}
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается один раз за кадр и является сердцем программы
SDL_AppResult SDL_AppIterate(void *appstate)
{
// Устанавливаем позицию, в которой хотим нарисовать текст
float x = 10.f;
float y = 30.f;
// Создаем прямоугольник для хранения размеров текстуры
SDL_FRect rect;
SDL_GetTextureSize(textTexture, &rect.w, &rect.h);
rect.x = x;
rect.y = y;
// Очищаем экран
SDL_SetRenderDrawColor(renderer, 38, 43, 51, 255); // Цвет заливки холста
// Начинаем с чистого холста - заливаем холст указанным выше цветов
SDL_RenderClear(renderer);
// Отрисовываем текст
SDL_RenderTexture(renderer, textTexture, NULL, &rect);
// Выводим результат на экран
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается один раз при завершении работы
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
if (textTexture)
{
SDL_DestroyTexture(textTexture);
textTexture = NULL;
}
TTF_Quit();
// SDL3 автоматически освободит все ресурсы подсистем (окна, рендереры) при выходе
} |
|
Далее, два бонусных примера, которые сгенерировал ИИ Gemini.
Рисуем координатные оси и правильный треугольник

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
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
| #define SDL_MAIN_USE_CALLBACKS 1 // Использовать функции обратного вызова вместо main()
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_ttf/SDL_ttf.h>
// Мы будем использовать этот рендерер для рисования в этом окне каждый кадр
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Texture *textTexture = NULL;
static TTF_Font *font = NULL;
// Текстуры для подписей вершин
static SDL_Texture *coordTextures[3] = { NULL, NULL, NULL };
// Вспомогательная функция для создания текстуры из строки
SDL_Texture* CreateTextTexture(const char* text, SDL_Color color)
{
SDL_Surface *surface = TTF_RenderText_Blended(font, text, 0, color);
SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, surface);
SDL_DestroySurface(surface);
return tex;
}
// Эта функция запускается один раз при старте
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 (!TTF_Init())
{
SDL_Log("Couldn't initialize TTF: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("Рендерер SDL3", 400, 300, 0, &window, &renderer))
{
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetRenderVSync(renderer, 1);
TTF_Font *font = TTF_OpenFont("assets/fonts/LiberationSans-Regular.ttf", 28);
if (!font)
{
SDL_Log("TTF_OpenFont failed: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_Color textColor = (SDL_Color) { 245, 240, 220 };
SDL_Surface *surface = TTF_RenderText_Blended(font, "Равносторонний треугольник", 0, textColor);
textTexture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_DestroySurface(surface);
TTF_CloseFont(font);
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается, когда происходит новое событие (ввод мыши, нажатие клавиш и т.д.)
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT)
{
return SDL_APP_SUCCESS; // Завершаем программу, сообщая ОС об успехе
}
return SDL_APP_CONTINUE; // Продолжаем работу программы
}
// Эта функция запускается один раз за кадр и является сердцем программы
SDL_AppResult SDL_AppIterate(void *appstate)
{
int winW, winH;
SDL_GetWindowSize(window, &winW, &winH);
// Очистка экрана
SDL_SetRenderDrawColor(renderer, 38, 43, 51, 255);
SDL_RenderClear(renderer);
// Отрисовка текста (в обычных координатах: Y вниз)
float tw, th;
SDL_GetTextureSize(textTexture, &tw, &th);
SDL_FRect textRect = { (winW - tw) / 2.0f, 20.0f, tw, th };
SDL_RenderTexture(renderer, textTexture, NULL, &textRect);
// Центр координат: середина по X, и чуть ниже текста по Y
float originX = winW / 2.0f;
float originY = winH / 2.0f + 40.0f;
// Вспомогательная функция для перевода наших координат в экранные
// Экранное_X = originX + наш_X
// Экранное_Y = originY - наш_Y (минус, так как в SDL Y растет вниз, а нам нужно вверх)
// Рисуем оси
// Ось X
SDL_SetRenderDrawColor(renderer, 180, 80, 80, 255);
SDL_RenderLine(renderer, originX - 150, originY, originX + 150, originY);
// Ось Y
SDL_SetRenderDrawColor(renderer, 80, 180, 80, 255);
SDL_RenderLine(renderer, originX, originY + 100, originX, originY - 120);
// Рисуем правильный треугольник
float a = 150.0f; // Сторона треугольника
float h = a * SDL_sqrtf(3.0f) / 2.0f;
float r_in = h / 3.0f; // Расстояние от центра до основания
float r_out = 2.0f * h / 3.0f; // Расстояние от центра до вершины
// Координаты вершин относительно центра (0,0), где Y смотрит вверх
SDL_FPoint trianglePoints[4] = {
{ originX - a / 2.0f, originY + r_in }, // Лево-низ (в SDL это +r_in, т.к. экранный Y вниз)
{ originX + a / 2.0f, originY + r_in }, // Право-низ
{ originX, originY - r_out }, // Вершина (в SDL это -r_out, чтобы была вверху)
{ originX - a / 2.0f, originY + r_in } // Замыкаем
};
SDL_SetRenderDrawColor(renderer, 245, 240, 220, 255); // Светло-кремовый
SDL_RenderLines(renderer, trianglePoints, 4);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
}
// Эта функция запускается один раз при завершении работы
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
if (textTexture)
{
SDL_DestroyTexture(textTexture);
}
TTF_Quit();
// SDL3 автоматически освободит все ресурсы подсистем (окна, рендереры) при выходе
} |
|
Подписи координат вершин треугольника

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
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
| #define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <stdio.h>
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Texture *textTexture = NULL;
static TTF_Font *font = NULL;
static SDL_Texture *coordTextures[3] = { NULL, NULL, NULL };
static const float TRIANGLE_A = 280.0f; // Длина стороны треугольника
static const float AXIS_X_LEN = 200.0f; // Половина длины оси X
static const float AXIS_Y_LEN = 180.0f; // Длина осей вверх/вниз
SDL_Texture *CreateTextTexture(const char *text, SDL_Color color)
{
SDL_Surface *surface = TTF_RenderText_Blended(font, text, 0, color);
SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, surface);
SDL_DestroySurface(surface);
return tex;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO))
return SDL_APP_FAILURE;
if (!TTF_Init())
return SDL_APP_FAILURE;
// Увеличили окно для большого треугольника
if (!SDL_CreateWindowAndRenderer("Рендерер SDL3", 500, 500, 0, &window, &renderer))
return SDL_APP_FAILURE;
SDL_SetRenderVSync(renderer, 1);
// Загружаем шрифт с базовым размером
font = TTF_OpenFont("assets/fonts/LiberationSans-Regular.ttf", 20);
if (!font)
return SDL_APP_FAILURE;
SDL_Color titleColor = { 245, 240, 220, 255 };
SDL_Color coordColor = { 200, 200, 200, 255 };
// Создаем заголовок
TTF_SetFontSize(font, 28);
textTexture = CreateTextTexture("Равносторонний треугольник", titleColor);
// Рассчитываем и создаем подписи координат
TTF_SetFontSize(font, 20); // Размер для координат
float h = TRIANGLE_A * SDL_sqrtf(3.0f) / 2.0f;
float r_in = h / 3.0f;
float r_out = 2.0f * h / 3.0f;
char buf[64];
// Лево-низ
sprintf(buf, "(%.1f, %.1f)", -TRIANGLE_A / 2.0f, -r_in);
coordTextures[0] = CreateTextTexture(buf, coordColor);
// Право-низ
sprintf(buf, "(%.1f, %.1f)", TRIANGLE_A / 2.0f, -r_in);
coordTextures[1] = CreateTextTexture(buf, coordColor);
// Верх
sprintf(buf, "(0.0, %.1f)", r_out);
coordTextures[2] = CreateTextTexture(buf, coordColor);
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT)
return SDL_APP_SUCCESS;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
int winW, winH;
SDL_GetWindowSize(window, &winW, &winH);
SDL_SetRenderDrawColor(renderer, 38, 43, 51, 255);
SDL_RenderClear(renderer);
// Отрисовка заголовка
float tw, th;
SDL_GetTextureSize(textTexture, &tw, &th);
SDL_FRect textRect = { (winW - tw) / 2.0f, 20.0f, tw, th };
SDL_RenderTexture(renderer, textTexture, NULL, &textRect);
// Оси координат
float originX = winW / 2.0f;
float originY = winH / 2.0f + 50.0f; // Центр системы координат
SDL_SetRenderDrawColor(renderer, 180, 80, 80, 255); // Мягкий красный
SDL_RenderLine(renderer, originX - AXIS_X_LEN, originY, originX + AXIS_X_LEN, originY);
SDL_SetRenderDrawColor(renderer, 80, 180, 80, 255); // Мягкий зеленый
SDL_RenderLine(renderer, originX, originY + AXIS_Y_LEN, originX, originY - AXIS_Y_LEN);
// Расчет точек треугольника
float h = TRIANGLE_A * SDL_sqrtf(3.0f) / 2.0f;
float r_in = h / 3.0f;
float r_out = 2.0f * h / 3.0f;
SDL_FPoint pts[4] = {
{ originX - TRIANGLE_A / 2.0f, originY + r_in },
{ originX + TRIANGLE_A / 2.0f, originY + r_in },
{ originX, originY - r_out },
{ originX - TRIANGLE_A / 2.0f, originY + r_in }
};
SDL_SetRenderDrawColor(renderer, 245, 240, 220, 255);
SDL_RenderLines(renderer, pts, 4);
// Отрисовка подписей
for (int i = 0; i < 3; i++)
{
float cw, ch;
SDL_GetTextureSize(coordTextures[i], &cw, &ch);
// Увеличили отступ (offset), чтобы крупный текст не налипал на вершины
float offset = 15.0f;
SDL_FRect cRect = {
pts[i].x - cw / 2.0f,
pts[i].y + (i == 2 ? -ch - offset : offset),
cw, ch
};
SDL_RenderTexture(renderer, coordTextures[i], NULL, &cRect);
}
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
SDL_DestroyTexture(textTexture);
for (int i = 0; i < 3; i++)
SDL_DestroyTexture(coordTextures[i]);
TTF_CloseFont(font);
TTF_Quit();
} |
|
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
27
28
29
30
| cmake_minimum_required(VERSION 3.21)
project(finish-zoom-text-sdl3-c)
# Задаем название будущего приложения (в Windows это будет app.exe, а
# в вебе было бы app.js / app.wasm)
add_executable(app)
# Устанавливаем стандарт C
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Указываем точное местоположение конфигурационных файлов библиотек
# Имя переменной должно строго соответствовать: НазваниеБиблиотеки_DIR
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.2-mingw/lib/cmake/SDL3")
set(SDL3_ttf_DIR "C:/libs/SDL3_ttf-devel-3.2.2-mingw/lib/cmake/SDL3_ttf")
# Добавляем исходный код к проекту
target_sources(app
PRIVATE
src/main.c
)
# Проверяем наличие библиотек в системе
# Если она не будет найдены, CMake прервет настройку с ошибкой
# REQUIRED - переводится, как "обязательно" или "требуется"
find_package(SDL3 REQUIRED)
find_package(SDL3_ttf REQUIRED)
# Привязываем библиотеки к нашему приложению
target_link_libraries(app PRIVATE SDL3_ttf::SDL3_ttf SDL3::SDL3) |
|
config-exe.bat
| Bash | 1
2
| cmake -G "MinGW Makefiles" -S . -B dist/win ^
-DCMAKE_BUILD_TYPE=Debug |
|
build-exe.bat
| Bash | 1
2
3
| cd dist\win
cmake --build .
cd ..\.. |
|
run-exe.bat
|