Разбор примера ImGui

Блок заголовочных файлов

#include <GLFW/glfw3.h>Code language: plaintext (plaintext)

Подключаем заголовок библиотеки окон GLFW: отвечает за создание окон, обработку ввода мыши/клавиатуры, управление контекстом OpenGL и циклом оконных сообщений.

GLFW — библиотека на языке C для создания и управления окнами. Она не зависит от ImGui, но без неё работа ImGui невозможна, поэтому мы обязательно подключаем её. На предыдущем занятии вы скачали библиотеку в папку проекта и настроили интеграцию.

#include "imgui.h"Code language: plaintext (plaintext)

Основной заголовочный файл ImGui, содержит все элементы интерфейса, контексты, стили и базовые API для отрисовки.

#include "backends/imgui_impl_glfw.h"Code language: plaintext (plaintext)

Мост между ImGui и GLFW, передаёт в ImGui данные окна, положение мыши, состояние клавиш и размер окна, полученные через GLFW.

#include "backends/imgui_impl_opengl3.h"Code language: plaintext (plaintext)

Слой адаптации бэкенда отрисовки OpenGL3 для ImGui: генерирует шейдеры и вершинные буферы OpenGL, передаёт графику интерфейса на отрисовку в видеокарту.

#include <cstdio>Code language: plaintext (plaintext)

Стандартная библиотека ввода-вывода C для C++, используется для вывода логов ошибок через функцию printf.


int main()

Точка входа в программу, дополнительных пояснений не требуется.

Инициализация GLFW

    // Initialize GLFW
    if (!glfwInit())
    {
        printf("GLFW initialization failed\n");
        return -1;
    }

glfwInit(): инициализирует глобальные ресурсы GLFW (видеокарта, драйверы окон, устройства ввода).

Если инициализация не удалась, выводится сообщение об ошибке и возвращается -1 для аварийного завершения программы; операционная система фиксирует этот код ошибки.

Настройка версии OpenGL

    // OpenGL 3.3
    const char* glsl_version = "#version 330";

Задаём строку версии шейдеров GLSL; OpenGL 3.3 соответствует GLSL версии 330.

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);

Устанавливаем основную версию OpenGL равной 3.

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

Устанавливаем второстепенную версию OpenGL равной 3.

 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

Используем Основной профиль (Core Profile)

Создание окна

    // Create window
    GLFWwindow* window = glfwCreateWindow(1000, 600, "ImGui Minimal Demo (VS2022)", nullptr, nullptr);

Размер окна 1000×600 пикселей, заголовок «ImGui Minimal Demo (VS2022)». Четвёртый аргумент nullptr — стандартный режим окна, пятый аргумент указывает окно с общим контекстом OpenGL; nullptr означает отсутствие общего доступа.

Функция возвращает указатель на дескриптор окна GLFWwindow*.

 if (!window)
    {
        glfwTerminate();
        return -1;
    }

Если создание окна завершилось ошибкой, указатель window принимает значение nullptr.

glfwTerminate() уничтожает все ресурсы, выделенные библиотекой GLFW.

Далее возвращаем -1, чтобы сообщить ОС о аварийном завершении программы.

glfwMakeContextCurrent(window);

Привязываем текущее окно как контекст отрисовки OpenGL; все последующие команды отрисовки OpenGL будут действовать для этого окна.

glfwSwapInterval(1);

Включаем вертикальную синхронизацию: параметр 1 — ожидаем обновление экрана для синхронизации частоты кадров, предотвращаем разрывы изображения; 0 отключает VSync без ограничения FPS.

Эта настройка критически важна: без неё отрисовка GLFW и обновление экрана не синхронизируются, из-за чего изображение искажается.

Глобальная инициализация ImGui

IMGUI_CHECKVERSION(); // Проверяем совпадение версий заголовка и бэкенда, при несовпадении выдаём ошибку ассерта
ImGui::CreateContext(); // Создаём глобальный контекст ImGui, храним все состояния работы интерфейса
ImGuiIO& io = ImGui::GetIO(); // Получаем объект настроек IO для управления вводом, шрифтами и глобальными переключателями
ImGui::StyleColorsDark(); // Подключаем официальную тёмную цветовую схему ImGui

Привязка бэкенда GLFW+OpenGL

ImGui_ImplGlfw_InitForOpenGL(window, true);

Если второй параметр равен true, ImGui перехватывает все события ввода (мышь, клавиатура) и блокирует передачу ввода нижнему слою игры.

 ImGui_ImplOpenGL3_Init(glsl_version);

Инициализируем бэкенд отрисовки OpenGL3, передаём строку версии GLSL, компилируем вершинные/фрагментные шейдеры для отрисовки интерфейса, создаём буферы видеокарты.

float slider_value = 0.5f;    // Значение, привязанное к ползунку
int click_count = 0;          // Счётчик нажатий на кнопку
bool show_full_demo = false;  // Управляем отображением официального демонстрационного окна ImGui

Эти переменные хранят значения элементов интерфейса, считываются и изменяются при каждом обновлении экрана, сохраняют значение между кадрами.

Основной цикл отрисовки

Ядро программы, выполняется от нескольких десятков до сотен раз в секунду.

while (!glfwWindowShouldClose(window))

Пока окно не получит сигнал закрытия (клик по крестику в правом верхнем углу или сочетание Alt+F4), отрисовка продолжается.

glfwPollEvents();

Опрашиваем все системные сообщения окна: клики/движение мыши, нажатия клавиш, изменение размера окна, закрытие и другое.

 ImGui_ImplOpenGL3_NewFrame();

Предобработка бэкенда OpenGL для каждого кадра: сброс ресурсов отрисовки, подготовка буфера под следующий кадр.

ImGui_ImplGlfw_NewFrame();

Предобработка бэкенда GLFW для каждого кадра: считываем текущие координаты мыши, состояние клавиш и размер окна, записываем данные ввода в IO ImGui.

ImGui::NewFrame();

Запускаем расчёт макета нового кадра интерфейса, вызываем перед любым кодом элементов ImGui::xxx(); внутренне очищаем команды отрисовки предыдущего кадра, готовимся к сборке данных текущего кадра.

Блок построения данных элементов интерфейса

// Draw custom UI panel
ImGui::Begin("Control Panel");                // Открываем пользовательское окно панели управления
ImGui::Text("Hello ImGui + VS2022");          // Вывод статичного текста
ImGui::SliderFloat("Slider Value", &slider_value, 0.f, 1.f); // Ползунок для дробных чисел, привязан к переменной

if (ImGui::Button("Click to Count"))          // Создаём кнопку, возвращает true при нажатии
    click_count++;                            // Увеличиваем счётчик при нажатии на кнопку
ImGui::SameLine();                            // Следующий элемент выводим в той же строке
ImGui::Text("Click Count: %d", click_count);  // Показываем количество нажатий кнопки

ImGui::Checkbox("Show Full ImGui Demo Window", &show_full_demo); // Флажок для скрытия/отображения демонстрационного окна
ImGui::End();                                 // Завершаем отрисовку текущего пользовательского окна

if (show_full_demo)
    ImGui::ShowDemoWindow(&show_full_demo);    // Открываем полное официальное демонстрационное окно ImGui

Этот блок отрисовывает интерфейс на каждой итерации цикла, отслеживает нажатия кнопки, увеличивает счётчик и выводит его значение.

Блок непосредственной отрисовки

// Render ImGui draw data
ImGui::Render();                                        // Генерируем вершинные данные отрисовки для текущего кадра
int width, height;
glfwGetFramebufferSize(window, &width, &height);        // Получаем реальное разрешение отрисовки окна
glViewport(0, 0, width, height);                       // Устанавливаем область просмотра OpenGL на всё окно
glClearColor(0.12f, 0.12f, 0.12f, 1.f);                // Задаём цвет очистки окна (тёмно-серый)
glClear(GL_COLOR_BUFFER_BIT);                           // Очищаем цветовой буфер экрана
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());// Отрисовываем весь интерфейс ImGui средствами OpenGL

glfwSwapBuffers(window);                                // Меняем передний и задний буферы, выводим готовое изображение

Очистка ресурсов после закрытия программы

Код ниже очищает все занятые ресурсы, когда пользователь закрывает программу.

// Cleanup resources
ImGui_ImplOpenGL3_Shutdown();  // Освобождаем ресурсы бэкенда OpenGL (шейдеры, буферы и т.д.)
ImGui_ImplGlfw_Shutdown();     // Освобождаем ресурсы бэкенда привязки GLFW
ImGui::DestroyContext();       // Уничтожаем глобальный контекст ImGui, освобождаем память интерфейса
glfwDestroyWindow(window);     // Закрываем окно GLFW, удаляем дескриптор окна
glfwTerminate();               // Полностью выгружаем библиотеку GLFW, освобождаем все глобальные ресурсы окон/ввода
return 0;                      // Нормальное завершение программы, возвращаем код успеха 0

Порядок уничтожения ресурсов полностью обратный порядку инициализации, чтобы избежать утечек памяти и остаточных ресурсов.

На этом разбор примера из предыдущего урока завершён. Если возникнут вопросы — оставляйте комментарии ниже.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *