Частина 4 - Вікно та візуалізатор

Вікно та візуалізатор

Кожна SDL2 програма, яка має відображати певний графічний контент, повинна мати хоча б одне вікно SDL2 та візуалізатор SDL2. Вікно - це сутність, яка відображає графічний контент, а візуалізатор - це „машина”, яка генерує вихідні дані, що відображатимуться у вікні. Код для налаштування вікна та візуалізатора наступний.

program SDL_WindowAndRenderer;

uses SDL2;

var
  sdlWindow1: PSDL_Window;
  sdlRenderer: PSDL_Renderer;

begin

  //ініціалізація підсистеми відео
  if SDL_Init(SDL_INIT_VIDEO) < 0 then Halt;

  // повна ініціалізація
  sdlWindow1 := SDL_CreateWindow('Window1', 50, 50, 500, 500, SDL_WINDOW_SHOWN);
  if sdlWindow1 = nil then Halt;

  sdlRenderer := SDL_CreateRenderer(sdlWindow1, -1, 0);
  if sdlRenderer = nil then Halt;

  // швидка ініціалізація
  {
  if SDL_CreateWindowAndRenderer(500, 500, SDL_WINDOW_SHOWN, @sdlWindow1, @sdlRenderer) <> 0
    then Halt;
  }

  // візуалізація в вікно на 2 секунди
  SDL_RenderPresent(sdlRenderer);
  SDL_Delay(2000);

  // очистка пам'яті
  SDL_DestroyRenderer(sdlRenderer);
  SDL_DestroyWindow (sdlWindow1);

  //закриваємо SDL2
  SDL_Quit;

end.  

Давайте детальніше розглянемо розділ var.

var
  sdlWindow1: PSDL_Window;
  sdlRenderer: PSDL_Renderer;

Вікно SDL2

В SDL 2.0 Ви можете сворити стільки вікон, скільки Вам потрібно, і кожне вікно адресується власною зміною типу PSDL_Window. Зараз нам потрібне лише одне вікно, давайте назвемо його “sdlWindow1”. Ця змінна визначає властивості вікна, напр. розмір, зовнішній вигляд, межа, заголовок тощо. І в ній зберігається вміст, який відображається.

Створення вікна

  // повна ініціалізація
  sdlWindow1 := SDL_CreateWindow('Window1', 50, 50, 500, 500, SDL_WINDOW_SHOWN);
  if sdlWindow1 = nil then Halt;

Створення вікна SDL2 просте і використовує функцію SDL_CreateWindow(заголовок, x, y, ширина, висота, прапорці) або більш конкретно:

SDL_CreateWindow(const title: PAnsiChar; x: SInt32; y: SInt32; w: SInt32; h: SInt32; flags: UInt32): PSDL_Window

В нашому прикладі вікно називається “Window1”, воно розміщене в позиції x = 50 та y = 50 пікселів (відносно Вашого екрану). Вікно має ширину і висоту по 500 пікселів відповідно. І ми використали прапорець SDL_WINDOW_SHOWN. Детальніше про ці прапорці пізніше. Спочатку давайте зрозуміємо систему координат у SDL2.

Система координат в SDL 2.0

Це правило застосовується:

Початок від якого слід рахувати розміщення вікна завжди лівий верхній кут Вашого екрану.

Тож якщо Ви оберете (0/0) як координати лівого верхнього кута вікна лівий верхній вугол буде розміщено прямо в лівому верхньому куті Вашого екрану. Діаграма нижче може допомогти це зрозуміти. Ви можете спробувати SDL_WINDOWPOS_CENTERED для кожної з обох координат, що приведе до центрування вікна відносно екрану. Якщо Ви оберете SDL_WINDOWPOS_UNDEFINED, Вам буде байдуже позиція вікна.

SDL2 window and coordinates diagram
Creative Commons License Це зображення від https://www.freepascal-meets-sdl.net розповсюджується за умовами Creative Commons Attribution 4.0 International License.
Вікно розміщене відносно верхнього лівого кута екрану.

Вікна SDL 2.0 і їх властивості

Тепер давайте поговоримо про прапорці. Вони визначають властивості вікна. Подивіться нанаступну таблицю (джерело) можливих прапорців, і Ви можете зрозуміти, чим вони займаються.

Прапорець
Опис
SDL_WINDOW_FULLSCREENповноекранне вікно
SDL_WINDOW_FULLSCREEN_DESKTOPповноекранне вікно з поточною роздільною здатністю
SDL_WINDOW_OPENGLвікно, яке можна використовувати з контекстом OpenGL
SDL_WINDOW_SHOWNвікно видиме
SDL_WINDOW_HIDDENвікно не видиме
SDL_WINDOW_BORDERLESSвікно не має оформлення
SDL_WINDOW_RESIZABLEвікно може змінювати розмір
SDL_WINDOW_MINIMIZEDвікно згорнуте
SDL_WINDOW_MAXIMIZEDвікно розгорнуте
SDL_WINDOW_INPUT_GRABBEDвікно захопило фокус введення
SDL_WINDOW_INPUT_FOCUSвікно має фокус введення
SDL_WINDOW_MOUSE_FOCUSвікно має фокус мишки
SDL_WINDOW_FOREIGNвікно не створене SDL
SDL_WINDOW_ALLOW_HIGHDPIвікно слід створювати в режимі з високим DPI, якщо підтримується (доступно з SDL 2.0.1)

Як бачите, ці прапорці визначають різні властивості вікна. Наприклад SDL_WINDOW_FULLSCREEN створить повноекранне вікно та SDL_WINDOW_BORDERLESS створить вікно без полів. Ви можете поєднати кілька прапорців за допомогою оператора OR (за необхідності). Для нашої мети SDL_WINDOW_SHOWN хороший вибір, тому що ми створюємо просте видиме вікно без будь-яких подальших обмежень.

Візуалізатор SDL2

У комп'ютерній графіці візуалізація означає процес синтезу кінцевого зображення на екрані з окремих базових структур даних. Тому, щоб намалювати якийсь контент у вікно, нам потрібен візуатор. PSDL_Renderer (який ми оголосили у розділі var) відповідає за синтез усього контенту у вікні, будь то кілька ліній, рівномірний фон, текстура, 3d-об’єкт або що завгодно. Ми назвемо наш PSDL_Renderer “sdlRenderer”.

Створення візуалізатора

  sdlRenderer := SDL_CreateRenderer(sdlWindow1, -1, 0);
  if sdlRenderer = nil then Halt;

Створення візуалізатора просте, як один виклик функції SDL_CreateRenderer(вікно, індекс, прапорці) або

SDL_CreateRenderer(window: PSDL_Window; index: SInt32; flags: UInt32): PSDL_Renderer

Спочатку нам потрібно, щоб візуалізатор знав, де візуалізувати готовий / відтворений вивід. В нашому випадку то буде “Window1”. Далі показана функція запитує загадковий “індекс”. Що ж, кожен драйвер, який здатний візуалізувати (наприклад, OpenGL, Direct3d, Програмне забезпечення…), індексується в SDL 2.0. В принципі, Ви можете обрати конкретний драйвер, вибравши відповідний індекс. Оскільки на даний момент ми не знаємо надто багато про драйвери, найкращий вибір - -1. -1 означає, що перший драйвер який підтримується обраними прапорцями буде обрано. Говорячи про прапорці, є чотири з яких Ви можете обирати:

  1. SDL_RENDERER_SOFTWARE
  2. SDL_RENDERER_ACCELERATED
  3. SDL_RENDERER_PRESENTVSYNC
  4. SDL_RENDERER_TARGETTEXTURE

Ви завжди повинні віддавати перевагу SDL_RENDERER_ACCELERATED, тому що це означає що за візуалізацію графіки відповідатиме відеокарта, SDL_RENDERER_SOFTWARE на відміну, означає що візуалізацію буде виконувати процесор. Як говорилося раніше, відеокарта - найкращий вибір для задач пов'язаних з візуалізацією/графікою. SDL_RENDERER_PRESENTVSYNC дозволяє так звану вертикальну синхронізацію, що означає що відображення візуалізованого зображеннясинхронізується з частотою оновлення монітора. SDL_RENDERER_TARGETTEXTURE дозволяє візуалізувати в текстуру. Можливо, Ви помітили, що в прикладі коду не було використано жодного з цих прапорців, крім 0. Це автоматично надає пріоритет візуалізаторам з апаратним прискоренням.

Швидке створення вікна та візуалізатора

 // швидке встановлення
  {
  if SDL_CreateWindowAndRenderer(500, 500, SDL_WINDOW_SHOWN, @sdlWindow1, @sdlRenderer) <> 0
    then Halt;
  }

Замість того, щоб створювати вікно та візуалізатор окремо, як було показано вище, Ви можете використовувати SDL_CreateWindowAndRenderer(ширина, висота, прапорці вікна, вказівник вікна, вказівник візуалізатора). Ця перевага полягає в тому, що Вам потрібен лише один рядок для налаштування вікна та візуалізатора, хоча встановлення заголовка вікна, положення вікна або конкретних прапорців візуалізатора потрібно виконати потім, якщо це необхідно.

Просто видаліть фігурні дужки та закоментуйте частину “повна ініціалізація”, щоб спробувати.

SDL_CreateWindowAndRenderer(width: SInt32; height: SInt32; window_flags: UInt32; window: PPSDL_Window; renderer: PPSDL_Renderer): SInt32

Ця функція повертає 0 при успішному виконанні та -1 при невдачі.

Візуалізація сцени SDL2

Фактична візуалізація досягається викликом функції SDL_RenderPresent(візуалізатор). Як примітка для людей, які перейшли з використання SDL 1.2, це те що формально досягалось викликом SDL_Flip().

SDL_RenderPresent(renderer: PSDL_Renderer)

Заморожування (затримка) запущеної програми в SDL 2.0

SDL_Delay(час в мілісекундах) це проста, але потужна і важлива процедура щоб призупинити виконання програми на певний час в мілісекундах. 2000 мілісекунд відповідають двом секундам. Це свого роду двійник процедури Delay в мові Pascal.

Очистка пам'яті в SDL 2.0

Тепер обговоримо останні рядки коду. Тут дотримується одне з найважливіших правил для вишуканого програмування:

Завжди звільняйте пам'ять при завершенні програми.

Практично для будь-якого типу вказівника, створеного SDL 2.0, існує процедура знищення, щоб видалити його з пам'яті. Ці процедури можна порівняти з процедурою Dispose мови Pascal для видалення з пам'яті вказівників. Обов’язково знищуйте об’єкти в послідовності, протилежній їх створенню. Ми спочатку створили вікно, тоді візуалізатор. Тож тепер ми йдемо протилежною дорогою, спочатку знищуємо візуалізатор і лише тоді вікно процедурами SDL_DestroyRenderer(візуалізатор) і SDL_DestroyWindow(вікно) відповідно.

Ось де ми:

  // очистка пам'яті
  SDL_DestroyRenderer(sdlRenderer);
  SDL_DestroyWindow (sdlWindow1);

Не забудьте остаточно вийти з SDL2 (чого ми не робимо).

Ось воно. І тепер все стане дійсно цікаво :-).

← Попередня частина | Наступна частина →

Немає коментарів:

Дописати коментар