Serwis Edukacyjny
Nauczycieli
w I-LO w Tarnowie

Do strony głównej I LO w Tarnowie

Materiały dla uczniów liceum

  Wyjście       Spis treści       Poprzedni       Następny  

©2019 mgr Jerzy Wałaszek
I LO w Tarnowie

logo

Autor artykułu: mgr Jerzy Wałaszek

 

 

SDL2

Okno

Rozdziały:
    Instalacja
    Typy danych
    Grafika rastrowa
    Okno
    Kontekst graficzny
    Punkty
    Odcinki
    Figury
    Algorytm Bresenhama
    Wypełnianie figur
    Wypełnianie obszarów
    Wypełnianie obszarów algorytmem Smitha
    Przezroczystość
    Zdarzenia

     Interfejs SDL2 wg nazw
     Interfejs SDL2 wg kategorii
W rozdziale:
Struktura programu
Okno graficzne
Podsumowanie

 

Struktura programu

Programowanie z wykorzystaniem biblioteki SDL2 jest w zasadzie normalnym programowaniem w języku C++. Sterowanie biblioteką odbywa się na zasadzie wywołań odpowiednich funkcji, które musisz poznać, aby móc z nich korzystać. Jednak jest kilka rzeczy, na które należy zwrócić uwagę.

Zakładam, że zainstalowałeś środowisko CodeBlocks oraz skonfigurowałeś je do współpracy z SDL2. Jeśli nie, to wróć tutaj i wykonaj wszystko wg podanych instrukcji.


Uruchom CodeBlocks.

Utwórz nowy projekt sdl2 z szablonu..

Do edytora skopiuj poniższy program (w Linuxie użyj dyrektywy: #include <SDL2/SDL.h>) :

 

#include <SDL.h>
#include <iostream>

using namespace std;

int main()
{
  return 0;
}

 

Spróbuj skompilować ten program. W Windows otrzymasz raport błędu, w którym pojawi się undefined reference to 'SDL_main', czyli niezdefiniowane odwołanie do 'SDL_main'. Oznacza to, że nie znaleziono funkcji main(). A przecież jest w naszym programie. Otóż SDL2 zostało napisane w języku C i wymaga funkcji main() z dwoma parametrami.


Skopiuj do edytora poniższy program (w Linuxie użyj dyrektywy: #include <SDL2/SDL.h>):

 

#include <SDL.h>
#include <iostream>

using namespace std;

int main(int argc, char* args[])
{
  return 0;
}

 

Teraz kompilacja przebiegnie bez problemów. Argumenty argc i args służą do pobierania parametrów z wiersza poleceń. Jeśli uruchomisz swój program z okna konsoli/terminala przez wpisanie jego nazwy, to za nazwą możesz umieścić różne dodatkowe parametry. Na przykład: załóżmy, że twój program nazywa się sdl2. Wpisałeś w oknie konsoli:

sdl2 grafika w SDL2

Wtedy do argc (ang. argument count, liczba argumentów) trafi wartość 4, bo tyle słów zostało wpisane:

słowo nr 1: sdl2
słowo nr 2: grafika
słowo nr 3: w
słowo nr 4: SDL2

Parametr args (ang. argument strings, łańcuchy argumentów) jest tablicą wskaźników, które adresują teksty poszczególnych słów wpisanych w wierszu polecenia, z tym, że słowo nr 1 (o indeksie 0 w tablicy args) zostaje dodatkowo wzbogacone o ścieżkę dostępu do pliku programu:

arg[0] → "ścieżka\sdl2.exe"
arg[1] → "grafika"
arg[2] → "w"
arg[3] → "SDL2"

Teksty są standardowo zakończone znakiem EOT (ang. End Of Text, koniec tekstu) o kodzie 0 wg konwencji języka C.


Skopiuj do edytora poniższy program (w Linuxie użyj dyrektywy: #include <SDL2/SDL.h>):

 

#include <SDL.h>
#include <iostream>

using namespace std;

int main(int argc, char* args[])
{
  cout << "LICZBA ARGUMENTOW = " << argc << endl;
  for(int i = 0; i < argc; i++)
    cout << "ARGUMENT NR " << i << " = " << args[i] << endl;
  return 0;
}

 

Z menu wybierz opcję: Project → Set programs' arguments.

W okienku dialogowym wpisz argumenty dla programu (przy uruchomieniu zostaną one przekazane do programu tak, jakbyś je wpisał za nazwą programu w wierszu poleceń):

Zatwierdź okno, skompiluj i uruchom program. Otrzymasz informację o liczbie wpisanych słów oraz same słowa.

Kiedyś, w czasach systemu DOS, był to powszechnie stosowany sposób przekazywania parametrów do programów. Dzisiaj, w dobie Windows 10, korzysta się z tego prawie wyłącznie w programach konsolowych. Programy graficzne też mogą ten sposób wykorzystywać. W każdym razie zapamiętaj: w SDL2 funkcja main() musi posiadać dwa argumenty: inc argc i char * args[ ] (w Linuxie nie jest to konieczne). Pierwszy określa liczbę parametrów wraz z nazwą programu, a drugi wskazuje słowa tworzące poszczególne argumenty. Oczywiście argumenty te nie mają nic wspólnego z SDL2 i możesz je wykorzystywać w każdym programie w C++.  Po prostu biblioteka SDL2 spodziewa się funkcji main() z tymi argumentami, zatem jeśli je pominiesz (co jest dozwolone w programach w języku C++), to powstanie błąd w czasie konsolidacji.

Gdy mamy za sobą parametry funkcji main(), przejdźmy do jej zawartości.


Do edytora wpisz poniższy program (w Linuxie użyj dyrektywy: #include <SDL2/SDL.h>):

 

#include <SDL.h>
#include <iostream>

using namespace std;

int main(int argc, char * args[])
{
  if(SDL_Init(SDL_INIT_VIDEO))
  {
    cout << "SDL_Init Error: " << SDL_GetError() << endl;
    return 1;
  }
  SDL_Quit();
  return 0;
}

 

Aby rozpocząć pracę z biblioteką SDL2, należy ją odpowiednio zainicjować. Do tego celu służy funkcja SDL_Init(). Parametrem tej funkcji jest stała, która określa, co ma zostać zainicjowane. SDL2 składa się z kilku podsystemów. Każdy z nich posiada swoją stałą dla funkcji SDL_Init():

Stała Opis
SDL_INIT_TIMER podsystem licznika czasu, tzw. timera (czytaj: tajmera)
SDL_INIT_AUDIO podsystem audio
SDL_INIT_VIDEO podsystem wideo; inicjalizuje również podsystem zdarzeń
SDL_INIT_JOYSTICK podsystem dżojstika; inicjuje również podsystem zdarzeń
SDL_INIT_HAPTIC podsystem kontrolera gier z siłowym sprzężeniem zwrotnym
SDL_INIT_GAMECONTROLLER podsystem kontrolera gier; inicjalizuje również podsystem joysticka
SDL_INIT_EVENTS podsystem zdarzeń
SDL_INIT_EVERYTHING wszystkie podsystemy

Stałe można łączyć ze sobą operatorem alternatywy bitowej o symbolu |. Na przykład chcemy zainicjować podsystemy wideo i audio. Stosujemy wywołanie:

SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)

Jeśli inicjalizacja się powiedzie, to funkcja SDL_Init() zwraca wartość 0. W przypadku błędu zwracana jest wartość ujemna.

W języku C++ wartość 0 traktowana jest jako fałsz, a wartość różna od 0 jako prawda. Instrukcja:

if(SDL_Init(SDL_INIT_VIDEO))
{
  ...
}

inicjuje podsystem wideo. Jeśli inicjalizacja się powiedzie, to funkcja SDL_Init() zwróci zero, które zostanie potraktowane przez instrukcję if jako fałsz. Zatem nie zostaną wykonane operacje w klamerkach, program przejdzie do wykonania instrukcji za klamrą zamykającą. W przypadku błędu SDL_Init() zwróci wartość różną od 0, co zostanie zinterpretowane przez instrukcję if jako prawda. Instrukcje w klamerkach zostaną wtedy wykonane. W klamerkach mamy dwie instrukcje:

    cout << "SDL_Init Error: " << SDL_GetError() << endl;
    return 1;

Pierwsza przesyła do strumienia wyjściowego konsoli cout (ang. console output) napis informujący o błędzie inicjalizacji biblioteki SDL. Opis zaistniałego błędu zwróci funkcja SDL_GetError().

Drugą instrukcją jest return 1, czyli wyjście z funkcji main() z wartością 1. Wyjście z głównej funkcji programu w C++ kończy działanie programu. Zatem w przypadku błędu w oknie konsoli pojawi się odpowiednia wiadomość i program zakończy działanie. To ważne! Nie możesz kontynuować działania programu, jeśli wystąpi jakiś błąd. Należy na niego odpowiednio zareagować. W przypadku błędu inicjalizacji dany podsystem staje się niedostępny dla programu, więc dobrym pomysłem jest po prostu zakończenie działania aplikacji.

Po zainicjowaniu biblioteki SDL możesz korzystać z jej zasobów. W naszym przykładowym programie z niczego nie korzystamy, ale to się szybko zmieni.

Gdy program ma zakończyć działanie, należy wywołać funkcję SDL_Quit(), która odpowiednio pozamyka użyte podsystemy. Dopiero po tym wywołaniu kończymy działanie programu za pomocą return 0.

Podsumujmy:

  • Główna funkcja programu musi mieć parametry: int main(int argc, char * args[]).
  • Na początku należy zainicjować bibliotekę SDL2 za pomocą funkcji SDL_Init(), do której przekazujemy jako parametr stałe określające inicjowane podsystemy.
  • Należy sprawdzić wynik SDL_Init(). Jeśli jest równy 0, to inicjalizacja się powiodła i program może być kontynuowany. Jeśli jest różny od zera, to wystąpił błąd inicjalizacji. Wykonanie programu należy wtedy zakończyć. Funkcja SDL_GetError() zwraca krótki opis błędu.
  • Po inicjalizacji program może korzystać z funkcji biblioteki SDL2 odnoszących się do zainicjowanych podsystemów.
  • Gdy program ma zakończyć działanie, należy wywołać funkcję SDL_Quit().

 

Okno graficzne

Aby twój program mógł umieszczać grafikę na ekranie, musi posiadać okno graficzne. W tym podrozdziale pokażemy, jak takie okno utworzyć za pomocą funkcji SDL2. Wyjaśnimy również kilka pojęć pomocnych przy pracy z grafiką komputerową.

Uruchom CodeBlocks i utwórz z szablonu nowy projekt sdl2.

Skopiuj do edytora poniższy program (w Linuxie użyj dyrektywy: #include <SDL2/SDL.h>):

 

// Okno graficzne w SDL2
//----------------------

#include <SDL.h>
#include <iostream>

using namespace std;

int main(int argc, char * args[])
{
  if(SDL_Init(SDL_INIT_VIDEO))
  {
    cout << "SDL_Init Error: " << SDL_GetError() << endl;
    return 1;
  }

  // Tutaj umieszczamy kod dla SDL2

  // Koniec pracy z SDL2
  SDL_Quit();

  return 0;
}

 

Jest to szablon aplikacji SDL2. Na początku zostaje zainicjowana biblioteka SDL2 i jej podsystem wideo. Jeśli wystąpi błąd, to w oknie konsoli pojawi się odpowiedni komunikat i program zakończy działanie.


Teraz wstawimy fragment kodu, który ma za zadanie utworzyć okno. W miejsce komentarza skopiuj do edytora poniższy fragment programu:

 

  // Tutaj umieszczamy kod dla SDL2
  
  SDL_Window * w = SDL_CreateWindow("Okno SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 320, 0);

  if(!w)
  {
    cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl;
    SDL_Quit();
    return 1;
  }

  // Czekamy 5 sekund
  SDL_Delay(5000);

  // Usuwamy okno
  SDL_DestroyWindow(w);

 

Gdy skompilujesz program, na ekranie pojawi się okno, a po upływie 5 sekund zniknie i program zakończy działanie.

Okno tworzy wywołanie funkcji SDL_CreateWindow(). Parametry są następujące:

SDL_Window * SDL_CreateWindow(t, x, y, w, h, f)

t – tytuł okienka,
x,y – współrzędne lewego górnego narożnika okna,
w – szerokość obszaru graficznego w pikselach (rzeczywiste okienko może być poszerzone o ramki, które tworzy system operacyjny),
h – wysokość obszaru graficznego okna (wysokość okna jest większa, ponieważ system dodaje jeszcze ramki i pasek tytułowy),
f – znaczniki

Układ współrzędnych ekranu rozpoczyna się w jego lewym górnym narożniku. Współrzędne y przebiegają w dół, a nie w górę.

Przyjęto takie rozwiązanie, ponieważ w sposób naturalny odzwierciedla ono zawartość bufora ekranowego, który zawiera treść ekranu w postaci linii obrazowych. Linie obrazowe przebiegają kolejno od góry w dół obrazu. Zatem to, co jest u góry ekranu, znajduje się na początku bufora.

Współrzędne x i y odnoszą się do lewego górnego narożnika okna. Możesz je podać w postaci liczbowej lub skorzystać ze zdefiniowanych stałych:

Stała Opis
SDL_WINDOWPOS_CENTERED okno zostanie wycentrowane w osi x lub y
SDL_WINDOWPOS_UNDEFINED położenie okna nie będzie zdefiniowane w programie, ustali to system operacyjny

W naszym przykładzie użyliśmy stałej SDL_WINDOWPOS_CENTERED dla obu współrzędnych x i y. Okienko pojawi się zatem na środku ekranu.

Ostatnim parametrem funkcji SDL_CreateWindow() są znaczniki. Określają one różne własności tworzonego okna za pomocą stałych, które można łączyć operatorem alternatywy bitowej |. Poniżej zestawiłem te stałe. Nie przejmuj się ich liczbą lub tym, że nie rozumiesz teraz ich funkcji. Wszystko wyjaśni się w dalszej części kursu.

Stała Opis
SDL_WINDOW_FULLSCREEN okno zajmie cały ekran, tzw. tryb pełnoekranowy
SDL_WINDOW_FULLSCREEN_DESKTOP okno zajmie cały ekran wykorzystując bieżącą rozdzielczość pulpitu
SDL_WINDOW_OPENGL okno do współpracy z OpenGL
SDL_WINDOW_HIDDEN okno będzie ukryte
SDL_WINDOW_BORDERLESS okno bez krawędzi
SDL_WINDOW_RESIZABLE okno z możliwością zmiany rozmiaru
SDL_WINDOW_MINIMIZED okno zminimalizowane na pasku zadań
SDL_WINDOW_MAXIMIZED okno zmaksymalizowane
SDL_WINDOW_INPUT_GRABBED okno z przechwyceniem skupienia
SDL_WINDOW_INPUT_FOCUS okno ze skupieniem wejścia
SDL_WINDOW_MOUSE_FOCUS okno ze skupieniem myszki
SDL_WINDOW_FOREIGN okno utworzone poza SDL2

Funkcja SDL_CreateWindow() zwraca wskaźnik do struktury SDL_Window. Zwykle nie musisz się tą strukturą przejmować, ponieważ służy ona do wewnętrznych celów w SDL2 i jej definicja jest ukryta przed programistą. Jeśli okno zostanie otwarte, to struktura SDL_Window zostanie utworzona w pamięci i funkcja zwróci wskaźnik (czyli adres) tej struktury. Wskaźnik zapamiętujemy w zmiennej w.

W języku C++ obowiązuje umowa, że wskaźnik o wartości 0 nie wskazuje żadnego obiektu w pamięci. Jeśli zatem funkcja SDL_CreateWindow() zwróci wskaźnik zerowy, to oznacza to błąd utworzenia okna. Aby wychwycić ten fakt, w instrukcji if stosujemy negację (0 jest w C++ traktowane jako fałsz):

  if(!w)
  {
    cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl;
    SDL_Quit();
    return 1;
  }

Instrukcje w klamerkach pod if wykonają się, gdy wskaźnik w będzie miał wartość NULL. W takim przypadku zostanie wypisany komunikat o błędzie, biblioteka SDL zostanie zamknięta i program zakończy swoje wykonanie.

Jeśli tworzenie okna się powiedzie, to wskaźnik w będzie miał wartość różną od NULL. Program przejdzie do wykonania instrukcji pod klamerką zamykającą if.

SDL_Delay(5000);

Funkcja SDL_Delay() czeka przez zadaną liczbę milisekund. 5000 oznacza 5 sekund oczekiwania. W tym czasie utworzone okno jest widoczne na ekranie. Jednak nic z nim nie możesz zrobić, ponieważ SDL_Delay() blokuje obsługę zdarzeń (zdarzeniami zajmiemy się w dalszej części kursu).

Gdy upłynie czas wyznaczony przez SDL_Delay(), wywołujemy funkcję SDL_DestroyWindow(), która usunie okno z ekranu i z pamięci komputera. Jako parametr przesyłamy do tej funkcji wskaźnik w, który został ustawiony przez SDL_CreateWindow(). Po usunięciu okna kończymy współpracę z SDL2 wywołaniem funkcji SDL_Quit() i rozkazem return 0 kończymy działanie programu.

Cel został osiągnięty. Stworzyliśmy program, który utworzył proste okno. W dalszej części kursu będziemy opanowywać różne operacje graficzne w oknie.

Podsumowanie

Pełna wersja programu z tego rozdziału powinna wyglądać następująco (w Linuxie użyj dyrektywy: #include <SDL2/SDL.h>):

 

// Okno graficzne w SDL2
//----------------------

#include <SDL.h>
#include <iostream>

using namespace std;

int main(int argc, char * args[])
{
  if(SDL_Init(SDL_INIT_VIDEO))
  {
    cout << "SDL_Init Error: " << SDL_GetError() << endl;
    return 1;
  }

  // Tutaj umieszczamy kod dla SDL2

  SDL_Window * w = SDL_CreateWindow("Okno SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 320, 0);

  if(!w)
  {
    cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl;
    SDL_Quit();
    return 1;
  }

  // Czekamy 5 sekund
  SDL_Delay(5000);

  // Usuwamy okno
  SDL_DestroyWindow(w);

  // Koniec pracy z SDL2
  SDL_Quit();

  return 0;
}

 

 

Podsumowanie

 
SDL_Init(f) – inicjuje bibliotekę SDL2. Zwraca 0, jeśli inicjalizacja się powiodła lub inną wartość przy błędzie.

f – znaczniki określające inicjowane podsystemy


SDL_GetError() – zwraca krótki opis ostatniego błędu w postaci tekstu.

 

SDL_CreateWindow(t,x,y,w,h,f) – tworzy okno graficzne. Zwraca wskaźnik do struktury SDL_Window lub NULL przy błędzie.

t – tytuł okienka,
x,y – współrzędne lewego górnego narożnika okna,
w – szerokość obszaru graficznego w pikselach,
h – wysokość obszaru graficznego okna,
f – znaczniki

 

SDL_Delay(d) – wstrzymuje wykonanie programu na zadaną liczbę milisekund.

d – liczba milisekund (1000 oznacza jedną sekundę).

 

SDL_DestroyWindow(w) – usuwa okno graficzne.

w – wskaźnik struktury SDL_Window

 

SDL_Quit() – kończy współpracę z SDL2.

 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2019 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.