Суброзділ SDL2
Заняття №2
01_hello_SDL
01_hello_SDL.cpp
/**
* @file 01_hello_SDL.cpp
* @author Sam4uk (sam4uk.site@gmail.com)
* @date 2025-05-03
*
* @copyright Copyright © Sam4uk 2025 (Sam4uk.site@gmail.com)
*
*/
#if defined(__linux)
#include <SDL2/SDL.h>
#elif defined(WIN32)
#include <SDL.h>
#endif
#include <exception>
#include <iostream>
#include <memory>
#include <stdexcept>
/** Screen dimension constants */
const int SCREEN_WIDTH{640}, SCREEN_HEIGHT{480};
int main(int argc, char* args[]) try {
/** Initialize SDL */
struct SDL_Guard {
SDL_Guard(Uint32 flags) {
if (0 > SDL_Init(flags))
throw std::runtime_error("SDL could not initialize! SDL_Error:" +
std::string(SDL_GetError()));
}
~SDL_Guard() { SDL_Quit(); }
} sdl_guart(SDL_INIT_VIDEO);
/** The window we'll be rendering to */
std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> window{
SDL_CreateWindow("C++ SDL blank by Sam4uk", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_SHOWN),
[](SDL_Window* w) {
if (w) SDL_DestroyWindow(w);
}};
if (!window)
throw std::runtime_error("Window could not be created! SDL_Error:\n" +
std::string(SDL_GetError()));
/** The surface contained by the window */
SDL_Surface* screenSurface{SDL_GetWindowSurface(window.get())};
/** Fill the surface white */
SDL_FillRect(screenSurface, NULL,
SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));
SDL_Event e;
bool quit{false};
do {
// Update the surface
SDL_UpdateWindowSurface(window.get());
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
quit = true;
break;
default:
break;
}
}
} while (!quit);
return EXIT_SUCCESS;
}
catch (const std::exception& e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
catch (...) {
std::cout << "Something wrong\n";
return -EXIT_FAILURE;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(01_hello_SDL)
add_executable(${PROJECT_NAME} 01_hello_SDL.cpp)
target_link_libraries(${PROJECT_NAME} SDL2)
Збирання проекту
cmake -B build -G="Unix Makefiles"
cmake --build ./build -j$(nproc)
Заняття №1 Налаштування та робота з вікнами
Заняття №1
01_hello_SDL.cpp
#if defined(__linux)
#include <SDL2/SDL.h>
#elif defined(WIN32)
#include <SDL.h>
#endif
#include <iostream>
Буду старатися використовувати розумний менеджмент пам’яті. Тому підключаємо необхідні для цього заголовки.
#include <memory>
Створимо структуру яка при вихоід з області видимоті автоматично викличе SDL_Quit()
.
Це обов’язково. А для початку треба ініціалізувати все, що нам потрібно функцією
SDL_Init(Uint32)
, яка проініціалізує потрібні нам системи.
SDL_INIT_TIMER | timer subsystem |
SDL_INIT_AUDIO | audio subsystem |
SDL_INIT_VIDEO | video subsystem; automatically initializes the events subsystem |
SDL_INIT_JOYSTICK | joystick subsystem; automatically initializes the events subsystem |
SDL_INIT_HAPTIC | haptic (force feedback) subsystem |
SDL_INIT_GAMECONTROLLER | controller subsystem; automatically initializes the joystick subsystem |
SDL_INIT_EVENTS | events subsystem |
SDL_INIT_EVERYTHING | all of the above subsystems |
Можна ініціалізувати всі потрібні системи одразу, або згодом при необхідності SDL_InitSubSystem(Uint32)
ініціалізувати конкретну систему, або зупинити SDL_QuitSubSystem(Uint32)
вже не потрібну систему. При виклику SDL_Quit()
зупиняються всі системи.
struct SDL_Guard {
SDL_Guard(Uint32 flags) {
if (0 > SDL_Init(flags))
throw std::runtime_error("SDL could not initialize! SDL_Error:" +
std::string(SDL_GetError()));
}
~SDL_Guard() { SDL_Quit(); }
};
Для вікна ми використаємо розумний вказівник який розглянемо трохи пізніше.
using UniqueWindow = std::unique_ptr<SDL_Window, void (*)(SDL_Window*)>;
Оголосимо main функцію для різних операційних систем
#if defined(_WIN32)
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
#elif defined(__APPLE__)
int main(int argc, char** argv)
#elif defined(__linux)
int main(int argc, char** argv, char** env)
#else
int main(int argc, char** argv)
#endif
try {
Нарешті тут ініціалізуємо всі системи у “розумні структурі”
SDL_Guard sdl_guart(SDL_INIT_EVERYTHING);
const int WINDOW_WIDTH{680}, WINDOWS_HEIGHT{480};
Створюємо вікно функцією SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
. Перший параметр це заголовок (назва) вікна і є собою c-string параметром. Інші параметри вказують на позицію та розміри вікна.
- | - |
---|---|
- | - |
- | - |
- | - |
- | - |
---|---|
SDL_WINDOW_FULLSCREEN | fullscreen window |
SDL_WINDOW_OPENGL | window usable with OpenGL context |
SDL_WINDOW_SHOWN | window is visible |
SDL_WINDOW_HIDDEN | window is not visible |
SDL_WINDOW_BORDERLESS | no window decoration |
SDL_WINDOW_RESIZABLE | window can be resized |
SDL_WINDOW_MINIMIZED | window is minimized |
SDL_WINDOW_MAXIMIZED | window is maximized |
SDL_WINDOW_MOUSE_GRABBED | window has grabbed mouse input |
SDL_WINDOW_INPUT_FOCUS | window has input focus |
SDL_WINDOW_MOUSE_FOCUS | window has mouse focus |
SDL_WINDOW_FULLSCREEN_DESKTOP | |
SDL_WINDOW_FOREIGN | window not created by SDL |
SDL_WINDOW_ALLOW_HIGHDPI | window should be created in high-DPI mode if supported. On macOS NSHighResolutionCapable must be set true in the application’s Info.plist for this to have any effect. |
SDL_WINDOW_MOUSE_CAPTURE | window has mouse captured (unrelated to MOUSE_GRABBED) |
SDL_WINDOW_ALWAYS_ON_TOP | window should always be above others |
SDL_WINDOW_SKIP_TASKBAR | window should not be added to the taskbar |
SDL_WINDOW_UTILITY | window should be treated as a utility window |
SDL_WINDOW_TOOLTIP | window should be treated as a tooltip |
SDL_WINDOW_POPUP_MENU | window should be treated as a popup menu |
SDL_WINDOW_KEYBOARD_GRABBED | window has grabbed keyboard input |
SDL_WINDOW_VULKAN | window usable for Vulkan surface |
SDL_WINDOW_METAL | window usable for Metal view |
SDL_WINDOW_INPUT_GRABBED | equivalent to SDL_WINDOW_MOUSE_GRABBED for compatibility |
UniqueWindow the_window{
SDL_CreateWindow("Example", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOWS_HEIGHT,
SDL_WINDOW_SHOWN),
Завжди створене вікно по завершеннютреба знищувати SDL_DestroyWindow(SDL_Window*)
SDL_DestroyWindow};
Переред початком роботи з вікном потрібно перевірити чи вдалося його створити.
if (!the_window)
throw std::runtime_error("Error creating window: " +
std::string(SDL_GetError()));
Отримуємо вкзівник на поверхню по якій бужемо малювати
SDL_Surface* winSurface{SDL_GetWindowSurface(the_window.get())};
Перевіряємо чи вдалося отримати вказіник на поверхню
if (!winSurface)
throw std::runtime_error("Error getting surface: " +
std::string(SDL_GetError()));
SDL_FillRect(winSurface, NULL,
SDL_MapRGB(winSurface->format, 0xFF, 0xFF, 0xFF));
SDL_Event e;
bool quit{false};
do {
SDL_UpdateWindowSurface(the_window.get());
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
quit = true;
break;
default:
break;
}
}
} while (!quit);
return EXIT_SUCCESS;
}
catch (const std::exception& e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
catch (...) {
std::cout << "Something wrong\n";
return -EXIT_FAILURE;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(Lesson01)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} SDL2)
Збирання проекту
cmake -B build -G="Unix Makefiles"
cmake --build ./build -j$(nproc)
./Lesson01