Integrating Dear ImGui with SDL3 on Windows & Ubuntu (OpenGL 3.3) Интеграция Dear ImGui с SDL3 под Windows и Ubuntu (OpenGL 3.3)
A step-by-step guide to configuring and integrating Dear ImGui with SDL3 and an OpenGL 3.3 context using CMake on Windows and Ubuntu. Пошаговое руководство по настройке и интеграции библиотеки Dear ImGui с SDL3 и контекстом OpenGL 3.3 с использованием CMake под Windows и Ubuntu.
- Windows (MinGW, CMake & Ninja) Setup Guide Руководство по настройке Windows (MinGW, CMake и Ninja)
- Ubuntu C/C++ Development Environment Setup Guide Руководство по настройке среды разработки C/C++ на Ubuntu
- Building SDL3 Static Library for Windows Сборка статической библиотеки SDL3 для Windows
- Building SDL3 Static Library for Ubuntu Сборка статической библиотеки SDL3 для Ubuntu
- Installing GLAD OpenGL Loader Library on Windows & Ubuntu (OpenGL 3.3) Установка библиотеки-загрузчика OpenGL GLAD под Windows и Ubuntu (OpenGL 3.3)
- Installing Dear ImGui Library on Windows & Ubuntu (OpenGL 3.3) Установка библиотеки Dear ImGui под Windows и Ubuntu (OpenGL 3.3)
Step 1: Create Project Directory Шаг 1: Создание директории проекта
Create a workspace folder and a new directory for your ImGui + SDL3 test project: Создайте рабочую папку для проектов и новую директорию для вашего тестового проекта ImGui + SDL3:
Windows (Command Prompt / PowerShell)
mkdir C:\projects\imgui-sdl3-opengl-test
cd C:\projects\imgui-sdl3-opengl-test
Ubuntu (Terminal)
mkdir -p ~/projects/imgui-sdl3-opengl-test
cd ~/projects/imgui-sdl3-opengl-test
Step 2: Create Source Files (main.cpp & CMakeLists.txt) Шаг 2: Создание исходных файлов (main.cpp и CMakeLists.txt)
You can create these files using Notepad / Sublime Text on Windows, or nano in the Ubuntu terminal:
Вы можете создать эти файлы через Notepad / Sublime Text в Windows или с помощью nano в терминале Ubuntu:
Windows (Terminal / Notepad)
notepad main.cpp
notepad CMakeLists.txt
Ubuntu (Terminal / Nano)
nano main.cpp
nano CMakeLists.txt
1A. File Contents for main.cpp (Classic Loop) 1A. Содержимое файла main.cpp (Классический цикл)
#include <iostream>
#include <glad/glad.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_opengl3.h"
int main(int argc, char* argv[]) {
// 1. Initialize SDL3
if (!SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "SDL Initialization failed: " << SDL_GetError() << std::endl;
return -1;
}
// 2. Set OpenGL 3.3 Core Profile attributes
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// 3. Create SDL3 Window
SDL_Window* window = SDL_CreateWindow("Dear ImGui + SDL3 (OpenGL 3.3) - Classic", 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!window) {
std::cerr << "Window creation failed: " << SDL_GetError() << std::endl;
SDL_Quit();
return -1;
}
// 4. Create OpenGL Context
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext) {
std::cerr << "OpenGL context creation failed: " << SDL_GetError() << std::endl;
SDL_DestroyWindow(window);
SDL_Quit();
return -1;
}
SDL_GL_MakeCurrent(window, glContext);
SDL_GL_SetSwapInterval(1); // Enable VSync
// 5. Initialize GLAD loader
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
std::cerr << "Failed to initialize GLAD!" << std::endl;
SDL_GL_DestroyContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
return -1;
}
// 6. Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
ImGui::StyleColorsDark();
// 7. Setup Platform/Renderer backends
ImGui_ImplSDL3_InitForOpenGL(window, glContext);
ImGui_ImplOpenGL3_Init("#version 330");
bool running = true;
bool showDemoWindow = true;
// 8. Main Event Loop
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
// Forward events to Dear ImGui
ImGui_ImplSDL3_ProcessEvent(&event);
if (event.type == SDL_EVENT_QUIT) {
running = false;
}
}
// Start Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
// UI Definition
{
ImGui::Begin("ImGui + SDL3 Integration");
ImGui::Text("Dear ImGui version: %s", IMGUI_VERSION);
ImGui::Text("Application average: %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::Checkbox("Show Demo Window", &showDemoWindow);
ImGui::End();
}
if (showDemoWindow) {
ImGui::ShowDemoWindow(&showDemoWindow);
}
// Rendering
ImGui::Render();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(0.25f, 0.35f, 0.45f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(window);
}
// 9. Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
SDL_GL_DestroyContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
1B. File Contents for main.cpp (SDL3 Callbacks API) 1B. Содержимое файла main.cpp (SDL3 Callbacks API)
#define SDL_MAIN_USE_CALLBACKS 1
#include <iostream>
#include <glad/glad.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_opengl3.h"
struct AppState {
SDL_Window* window = nullptr;
SDL_GLContext glContext = nullptr;
bool showDemoWindow = true;
};
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
if (!SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "60")) {
return SDL_APP_FAILURE;
}
if (!SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "SDL Initialization failed: " << SDL_GetError() << std::endl;
return SDL_APP_FAILURE;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
AppState* state = new AppState();
*appstate = state;
state->window = SDL_CreateWindow("Dear ImGui + SDL3 (OpenGL 3.3) - Callbacks", 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!state->window) {
return SDL_APP_FAILURE;
}
state->glContext = SDL_GL_CreateContext(state->window);
if (!state->glContext) {
return SDL_APP_FAILURE;
}
SDL_GL_MakeCurrent(state->window, state->glContext);
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
std::cerr << "Failed to initialize GLAD!" << std::endl;
return SDL_APP_FAILURE;
}
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
ImGui::StyleColorsDark();
ImGui_ImplSDL3_InitForOpenGL(state->window, state->glContext);
ImGui_ImplOpenGL3_Init("#version 330");
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
ImGui_ImplSDL3_ProcessEvent(event);
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void* appstate) {
auto* state = static_cast<AppState*>(appstate);
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
{
ImGui::Begin("ImGui + SDL3 Callbacks API");
ImGui::Text("Dear ImGui version: %s", IMGUI_VERSION);
ImGui::Text("Application average: %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::Checkbox("Show Demo Window", &state->showDemoWindow);
ImGui::End();
}
if (state->showDemoWindow) {
ImGui::ShowDemoWindow(&state->showDemoWindow);
}
ImGui::Render();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(0.25f, 0.35f, 0.45f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(state->window);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void* appstate, SDL_AppResult result) {
if (appstate) {
auto* state = static_cast<AppState*>(appstate);
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
if (state->glContext) {
SDL_GL_DestroyContext(state->glContext);
}
if (state->window) {
SDL_DestroyWindow(state->window);
}
delete state;
}
SDL_Quit();
}
Option 1A uses the traditional main() event loop. Option 1B uses the new SDL3 recommended Callbacks API (via SDL_MAIN_USE_CALLBACKS). The Callbacks API hands main loop control over to the OS, preventing window rendering freezes during drag/resize operations and enabling seamless cross-platform support across WebAssembly, iOS, and Android.
Вариант 1A использует традиционный цикл событий main(). Вариант 1B использует новый рекомендуемый в SDL3 Callbacks API (через SDL_MAIN_USE_CALLBACKS). Callbacks API передаёт управление основным циклом операционной системе, что предотвращает зависание рендеринга при перетаскивании или изменении размера окна и обеспечивает нативную кроссплатформенность для WebAssembly, iOS и Android.
2. File Contents for CMakeLists.txt 2. Содержимое файла CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
project(imgui_sdl3_opengl_test CXX C)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# -----------------------------------------------------------------------------
# Paths
# -----------------------------------------------------------------------------
if(WIN32)
set(IMGUI_DIR "C:/libs/imgui-1.93.0")
set(GLAD_DIR "C:/libs/glad-0.1.36/opengl-3.3")
set(SDL3_DIR "C:/libs/sdl3-3.4.18-mingw/lib/cmake/SDL3")
else()
set(IMGUI_DIR "$ENV{HOME}/libs/imgui-1.93.0")
set(GLAD_DIR "$ENV{HOME}/libs/glad-0.1.36/opengl-3.3")
set(SDL3_DIR "$ENV{HOME}/libs/sdl3-3.4.18-ubuntu/lib/cmake/SDL3")
endif()
# -----------------------------------------------------------------------------
# Locate Official SDL3 CMake Package
# -----------------------------------------------------------------------------
find_package(SDL3 REQUIRED CONFIG)
# -----------------------------------------------------------------------------
# ImGui Sources (including Demo Window and SDL3/OpenGL3 Backends)
# -----------------------------------------------------------------------------
set(IMGUI_SOURCES
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_demo.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
${IMGUI_DIR}/backends/imgui_impl_sdl3.cpp
${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
)
# -----------------------------------------------------------------------------
# Executable Target
# -----------------------------------------------------------------------------
add_executable(app
main.cpp
${IMGUI_SOURCES}
${GLAD_DIR}/src/glad.c
)
# -----------------------------------------------------------------------------
# Include Directories
# -----------------------------------------------------------------------------
target_include_directories(app PRIVATE
${IMGUI_DIR}
${IMGUI_DIR}/backends
${GLAD_DIR}/include
)
# -----------------------------------------------------------------------------
# Backend Selection Definition
# -----------------------------------------------------------------------------
target_compile_definitions(app PRIVATE
IMGUI_IMPL_OPENGL_LOADER_GLAD
)
# -----------------------------------------------------------------------------
# Static C++ Runtime (Applied to BOTH Windows & Ubuntu)
# -----------------------------------------------------------------------------
target_link_options(app PRIVATE -static-libgcc -static-libstdc++)
# -----------------------------------------------------------------------------
# Optimization & Symbol Stripping (Release Builds Only)
# -----------------------------------------------------------------------------
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
target_compile_options(app PRIVATE -Os)
target_link_options(app PRIVATE -s)
endif()
# -----------------------------------------------------------------------------
# Platform Linking & Dependencies
# -----------------------------------------------------------------------------
if(WIN32)
target_link_libraries(app PRIVATE
SDL3::SDL3-static
opengl32
)
# Windows static linking & subsystem selection
target_link_options(app PRIVATE -static)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_options(app PRIVATE -mconsole)
else()
target_link_options(app PRIVATE -mwindows)
endif()
else()
target_link_libraries(app PRIVATE
SDL3::SDL3-static
GL
dl
pthread
m
)
endif()
Step 3: Create Build & Execution Scripts Шаг 3: Создание скриптов сборки и запуска
Windows (MinGW / Batch Scripts)
config-win.bat
cmake -G Ninja -S . -B dist/win
build-win.bat
cmake --build dist/win
run-win.bat
@echo off
.\dist\win\app.exe
Run the scripts sequentially in Command Prompt or PowerShell: Последовательно запустите скрипты в командной строке или PowerShell:
config-win.bat
build-win.bat
run-win.bat
Ubuntu (Bash Scripts)
config-linux.sh
#!/usr/bin/env bash
set -e
cmake -G Ninja -S . -B dist/linux
build-linux.sh
#!/usr/bin/env bash
set -e
cmake --build dist/linux
run-linux.sh
#!/usr/bin/env bash
set -e
./dist/linux/app
Grant execute permissions on Ubuntu before running: Предоставьте права на выполнение в Ubuntu перед запуском:
chmod +x config-linux.sh build-linux.sh run-linux.sh
./config-linux.sh
./build-linux.sh
./run-linux.sh
Step 4: Expected Output Шаг 4: Ожидаемый результат
After running the build and execution scripts, a native desktop window will appear displaying Dear ImGui with the dark style, responsive widgets, and the interactive demo window: После запуска скриптов сборки и выполнения откроется нативное окно приложения с интерфейсом Dear ImGui в темной теме, интерактивными элементами управления и окном Demo:
Dear ImGui + SDL3 (OpenGL 3.3) - Classic
or (if using the Callbacks API version): или (если используется версия с Callbacks API):
Dear ImGui + SDL3 (OpenGL 3.3) - Callbacks
Support My Work Поддержать проект
If these tutorials helped you, consider buying me a coffee! Если эти туториалы вам помогли, вы можете поддержать автора.
Sberbank (Russia only) Сбербанк (только для РФ)
Direct transfer via phone number (Russia only) Перевод по номеру телефона (только для РФ)
USDT TRC20
Support via Cryptocurrency Поддержка криптовалютой