SDL3 & OpenGL: Texture Loading with SDL3_image SDL3 и OpenGL: Загрузка текстур с помощью SDL3_image
A guide to loading image files into GPU memory as modern OpenGL textures within the SDL3 callback system. Руководство по загрузке файлов изображений в память GPU как текстур OpenGL в современной системе обратных вызовов SDL3.
-
1. Obtain SDL3 and GLAD 1. Получение SDL3 и GLAD
Follow the guide to install and configure SDL3 and GLAD using CMake: Setting up SDL3 with find_package (MinGW). Следуйте руководству по установке и настройке SDL3 и GLAD с помощью CMake: Настройка SDL3 с помощью find_package (MinGW).
2. Obtain SDL3_image 3.4.4 2. Получение SDL3_image 3.4.4
-
Download two archives from the official SDL_image release page:
Скачайте два архива со страницы официального релиза SDL_image:
-
Extract the SDL3_image-devel-3.4.4-mingw.zip archive to the
C:/libs/SDL3_image-devel-3.4.4-mingwfolder. Распакуйте архив SDL3_image-devel-3.4.4-mingw.zip в папкуC:/libs/SDL3_image-devel-3.4.4-mingw. -
Move the headers and libraries so the structure is
SDL3_image-devel-3.4.4-mingw/include, etc: Переместите заголовочные файлы и библиотеки так, чтобы структура папок былаSDL3_image-devel-3.4.4-mingw/includeи т. д.:
-
Extract the SDL3_image-3.4.4-win32-x64.zip archive so the path is exactly
C:/libs/SDL3_image-3.4.4-win32-x64: Распакуйте архив SDL3_image-3.4.4-win32-x64.zip так, чтобы путь был именноC:/libs/SDL3_image-3.4.4-win32-x64:
3. Add SDL3 to Environment Variables (Path) 3. Добавление SDL3 в переменные среды (Path)
To ensure your applications can find the SDL3.dll file at runtime, you should add the following path to the Path variable in your User variables section:
Чтобы приложения могли находить SDL3.dll файл при запуске, добавьте следующий путь в переменную Path в разделе Переменные среды пользователя:
C:\libs\SDL3_image-3.4.4-win32-x64
4. Project Structure and Assets 4. Структура проекта и ресурсы
Before creating the files, download the required asset: Перед созданием файлов скачайте необходимый ресурс:
- Download the PNG file with transparent background: right-arrow.zip Скачайте PNG-файл с прозрачным фоном: right-arrow.zip
- Note: This is a free file taken from this link. Примечание. Это бесплатный файл, который был взят по ссылке.
C Project: Create an empty folder named texture-sdl3-opengl-mingw-c and set up the following hierarchy by creating new CMakeLists.txt and main.c files:
Проект на C: Создайте пустую папку с именем texture-sdl3-opengl-mingw-c и подготовьте следующую иерархию, создав файлы CMakeLists.txt и main.c:
texture-sdl3-opengl-mingw-c/
├── CMakeLists.txt
├── assets/images/
│ └── right-arrow.png
└── src/
└── main.c
C++ Project: Create an empty folder named texture-sdl3-opengl-mingw-cpp and set up the following hierarchy by creating new CMakeLists.txt and main.cpp files:
Проект на C++: Создайте пустую папку с именем texture-sdl3-opengl-mingw-cpp и подготовьте следующую иерархию, создав файлы CMakeLists.txt и main.cpp:
texture-sdl3-opengl-mingw-cpp/
├── CMakeLists.txt
├── assets/images/
│ └── right-arrow.png
└── src/
└── main.cpp
5. CMake Configuration 5. Конфигурация CMake
C Project: Copy and paste the following code into the CMakeLists.txt file:
Проект на C: Скопируйте и вставьте следующее содержимое в файл CMakeLists.txt:
set(CMAKE_BUILD_TYPE "Debug")
cmake_minimum_required(VERSION 3.21)
project(texture-sdl3-opengl-mingw-c)
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.8-mingw/lib/cmake/SDL3")
set(SDL3_image_DIR "C:/libs/SDL3_image-devel-3.4.4-mingw/lib/cmake/SDL3_image")
find_package(SDL3 REQUIRED)
find_package(SDL3_image REQUIRED)
add_executable(app)
target_include_directories(app PRIVATE "C:/libs/glad-0.1.36/opengl-3.3/include")
target_sources(app
PRIVATE
src/main.c
"C:/libs/glad-0.1.36/opengl-3.3/src/glad.c"
)
# Copy the assets folder to the dist folder
if(EXISTS "${CMAKE_SOURCE_DIR}/assets")
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/assets"
"$<TARGET_FILE_DIR:app>/assets"
COMMENT "Copying assets directory"
)
endif()
target_link_libraries(app PRIVATE SDL3_image::SDL3_image SDL3::SDL3)
target_link_options(app PRIVATE -mconsole)
C++ Project: Copy and paste the following code into the CMakeLists.txt file:
Проект на C++: Скопируйте и вставьте следующее содержимое в файл CMakeLists.txt:
set(CMAKE_BUILD_TYPE "Debug")
cmake_minimum_required(VERSION 3.21)
project(texture-sdl3-opengl-mingw-cpp)
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.8-mingw/lib/cmake/SDL3")
set(SDL3_image_DIR "C:/libs/SDL3_image-devel-3.4.4-mingw/lib/cmake/SDL3_image")
find_package(SDL3 REQUIRED)
find_package(SDL3_image REQUIRED)
add_executable(app)
target_include_directories(app PRIVATE "C:/libs/glad-0.1.36/opengl-3.3/include")
target_sources(app
PRIVATE
src/main.cpp
"C:/libs/glad-0.1.36/opengl-3.3/src/glad.c"
)
# Copy the assets folder to the dist folder
if(EXISTS "${CMAKE_SOURCE_DIR}/assets")
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/assets"
"$<TARGET_FILE_DIR:app>/assets"
COMMENT "Copying assets directory"
)
endif()
target_link_libraries(app PRIVATE SDL3_image::SDL3_image SDL3::SDL3)
target_link_options(app PRIVATE -mconsole)
6. Source Code (OpenGL 3.3 Texture Mapping) 6. Исходный код (Текстурирование в OpenGL 3.3)
Copy and paste the following code into the src/main.c (or src/main.cpp) file:
Скопируйте и вставьте следующее содержимое в файл src/main.c (или src/main.cpp):
src/main.c (or src/main.cpp)
#define SDL_MAIN_USE_CALLBACKS 1
#include <glad/glad.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_image/SDL_image.h>
static SDL_Window *window = NULL;
static SDL_GLContext glContext = NULL;
static GLuint shaderProgram;
static GLuint VAO, VBO, EBO;
static GLuint textureID;
const char *vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPosition;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 vTexCoord;\n"
"void main() {\n"
" gl_Position = vec4(aPosition, 1.0);\n"
" vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\n"
"}";
const char *fragmentShaderSource =
"#version 330 core\n"
"precision mediump float;\n"
"out vec4 FragColor;\n"
"in vec2 vTexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main() {\n"
" FragColor = texture(ourTexture, vTexCoord);\n"
"}";
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO))
return SDL_APP_FAILURE;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
window = SDL_CreateWindow("SDL3_image OpenGL", 380, 380, SDL_WINDOW_OPENGL);
if (!window)
return SDL_APP_FAILURE;
glContext = SDL_GL_CreateContext(window);
// Load standard Desktop GLAD mapping
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
{
return SDL_APP_FAILURE;
}
SDL_GL_SetSwapInterval(1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Setup Geometry
float vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
unsigned int indices[] = { 0, 1, 3, 1, 2, 3 };
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// Simple Shader Compilation
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// Load Image file via SDL3_image directly into memory surface
const char *texturePath = "assets/images/right-arrow.png";
SDL_Surface *surface = IMG_Load(texturePath);
if (!surface)
{
SDL_Log("Image loading failed: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
// Convert to standardized ABGR8888 (Matches GL_RGBA memory layout perfectly)
SDL_Surface *optimizedSurface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888);
SDL_DestroySurface(surface); // Free the unoptimized source copy immediately
if (!optimizedSurface)
{
SDL_Log("Surface conversion failed: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
// Convert pixels to an OpenGL Texture Object
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
// Set wrapping/filtering options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload using strict GL_RGBA formatting (Since it is safely converted)
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
optimizedSurface->w,
optimizedSurface->h,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
optimizedSurface->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
// Free optimized surface copy from CPU RAM
SDL_DestroySurface(optimizedSurface);
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)
{
glClearColor(0.392f, 0.392f, 0.392f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindTexture(GL_TEXTURE_2D, textureID);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
SDL_GL_DestroyContext(glContext);
SDL_DestroyWindow(window);
}
7. Opening the Project in IDEs 7. Открытие проекта в IDE
Open the CMakeLists.txt file in CLion or Qt Creator. CMake will handle the rest. Откройте файл CMakeLists.txt в CLion или Qt Creator. CMake позаботится об остальном.
8. Automation Scripts (.bat) 8. Скрипты автоматизации (.bat)
You can open the project folder in Sublime Text 4 (or Notepad++). Create the following .bat scripts in the project root directory to automate the configuration, building, and running of your application:
Вы можете открыть папку проекта в Sublime Text 4 (или Notepad++). Создайте следующие .bat скрипты в корневой директории проекта для автоматизации конфигурации, сборки и запуска вашего приложения:
1. config-exe.bat
cmake -G "MinGW Makefiles" -S . -B dist/exe
2. build-exe.bat
cd dist\exe
cmake --build .
cd ..\..
3. run-exe.bat
dist\exe\app
To build and launch the application, run these scripts in the terminal in the following order:
Чтобы собрать и запустить приложение, выполните эти скрипты в терминале в следующем порядке:
config-exe
build-exe
run-exe
9. Source Code & Downloads 9. Исходный код и загрузки
You can download the complete configured project as a ZIP archive or explore the source code directly on GitHub: Вы можете скачать готовую настроенную сборку проекта в виде ZIP-архива или изучить исходный код прямо на GitHub:
Support My Work Поддержать проект
If these tutorials helped you, consider buying me a coffee! Если эти туториалы вам помогли, вы можете поддержать автора.
Sberbank
Direct transfer via phone number Перевод по номеру телефона
Bybit (USDT TRC20)
Support via Cryptocurrency Поддержка криптовалютой