Заняття №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_TIMERtimer subsystem
SDL_INIT_AUDIOaudio subsystem
SDL_INIT_VIDEOvideo subsystem; automatically initializes the events subsystem
SDL_INIT_JOYSTICKjoystick subsystem; automatically initializes the events subsystem
SDL_INIT_HAPTIChaptic (force feedback) subsystem
SDL_INIT_GAMECONTROLLERcontroller subsystem; automatically initializes the joystick subsystem
SDL_INIT_EVENTSevents subsystem
SDL_INIT_EVERYTHINGall 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_FULLSCREENfullscreen window
SDL_WINDOW_OPENGLwindow usable with OpenGL context
SDL_WINDOW_SHOWNwindow is visible
SDL_WINDOW_HIDDENwindow is not visible
SDL_WINDOW_BORDERLESSno window decoration
SDL_WINDOW_RESIZABLEwindow can be resized
SDL_WINDOW_MINIMIZEDwindow is minimized
SDL_WINDOW_MAXIMIZEDwindow is maximized
SDL_WINDOW_MOUSE_GRABBEDwindow has grabbed mouse input
SDL_WINDOW_INPUT_FOCUSwindow has input focus
SDL_WINDOW_MOUSE_FOCUSwindow has mouse focus
SDL_WINDOW_FULLSCREEN_DESKTOP
SDL_WINDOW_FOREIGNwindow not created by SDL
SDL_WINDOW_ALLOW_HIGHDPIwindow 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_CAPTUREwindow has mouse captured (unrelated to MOUSE_GRABBED)
SDL_WINDOW_ALWAYS_ON_TOPwindow should always be above others
SDL_WINDOW_SKIP_TASKBARwindow should not be added to the taskbar
SDL_WINDOW_UTILITYwindow should be treated as a utility window
SDL_WINDOW_TOOLTIPwindow should be treated as a tooltip
SDL_WINDOW_POPUP_MENUwindow should be treated as a popup menu
SDL_WINDOW_KEYBOARD_GRABBEDwindow has grabbed keyboard input
SDL_WINDOW_VULKANwindow usable for Vulkan surface
SDL_WINDOW_METALwindow usable for Metal view
SDL_WINDOW_INPUT_GRABBEDequivalent 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

Заняття №2