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

SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++

Запись от 8Observer8 размещена 24.03.2026 в 06:18. Обновил(-а) 8Observer8 21.03.2026 в 02:12
Показов 2485 Комментарии 0
Метки bash, c, c++, cmake, gamedev, sdl, sdl3, си

Содержание блога

Финальные проекты на Си и на 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++
  • Извлеките пример из архива:
    Название: 7ea1de96-8017-4103-bafb-7724a2bed04f.png
Просмотров: 650

Размер: 3.0 Кб
  • Код стартового примера:

    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

    Bash
    1
    
    dist\win\app
  • Откройте папку примера в каком-нибудь текстовом редакторе - например, в 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

Bash
1
dist\win\app
Миниатюры

Нажмите на изображение для увеличения
Название: a565eb29-8960-4c0c-a0ff-0ec0b5a204e3.png
Просмотров: 745
Размер:	6.4 Кб
ID:	11787
Нажмите на изображение для увеличения
Название: f3e96ab3-fc40-4975-ace3-e756d6e4dbb4.png
Просмотров: 749
Размер:	3.6 Кб
ID:	11792
Нажмите на изображение для увеличения
Название: 2209237c-1029-4462-a4a3-5f2ff14115b8.png
Просмотров: 721
Размер:	7.3 Кб
ID:	11795
Нажмите на изображение для увеличения
Название: b17e11af-3200-4ff8-bbbb-854d899aef29.png
Просмотров: 705
Размер:	9.2 Кб
ID:	11799
Нажмите на изображение для увеличения
Название: a9f8e10b-76f9-4e27-b5fd-a01418a0883a.png
Просмотров: 10184
Размер:	18.0 Кб
ID:	11801
Вложения
Тип файла: zip SDL3-devel-3.4.2-mingw.zip (2.65 Мб, 108 просмотров)
Тип файла: zip SDL3-3.4.2-win32-x64.zip (1.10 Мб, 95 просмотров)
Тип файла: zip SDL3_ttf-devel-3.2.2-mingw.zip (2.63 Мб, 105 просмотров)
Тип файла: zip SDL3_ttf-3.2.2-win32-x64.zip (979.6 Кб, 104 просмотров)
Тип файла: zip LiberationSans-Regular.zip (206.0 Кб, 66 просмотров)
Тип файла: zip start-text-sdl3-c.zip (3.0 Кб, 74 просмотров)
Тип файла: zip finish-text-sdl3-c.zip (210.0 Кб, 309 просмотров)
Тип файла: zip finish-text-sdl3-cpp.zip (210.1 Кб, 293 просмотров)
Метки bash, c, c++, cmake, gamedev, sdl, sdl3, си
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Новые блоги и статьи
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru