Блок заголовочных файлов
#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
Порядок уничтожения ресурсов полностью обратный порядку инициализации, чтобы избежать утечек памяти и остаточных ресурсов.
На этом разбор примера из предыдущего урока завершён. Если возникнут вопросы — оставляйте комментарии ниже.
