Inicjalizacja i obsługa błędów

Pierwsze co musisz zrobić, by skorzystać z biblioteki SDL, to oczywiście dołączyć jej plik nagłówkowy, by zapoznać kompilator z zawartością tej biblioteki:

#include <SDL.h>

Program używający SDL zaczyna się w normalnej, standardowej funkcji main ;-) Jest tak nawet gdy tworzysz projekt dla systemu Windows, bo wtedy SDL realizuje windowsową funkcję WinMain gdzieś w swoim wnętrzu. Takie rozwiązanie jest konieczne, by można było przenosić kod pomiędzy różnymi platformami systemowymi bez żadnych zmian [inne systemy niż Windows nie używają przecież tej niestandardowej funkcji WinMain :-P].

#include <SDL.h>

//Tu zaczyna się nasz program używający SDL
int main()
{
 //Tu będzie jego treść...
}

Podsystemy biblioteki SDL

Biblioteka SDL składa się z 8 podsystemów, z których każdy odpowiada za coś innego. Przypomina tym trochę bibliotekę DirectX, jednak jak pewnie wiesz, są między nimi pewne różnice ;-J Poniżej masz listę tych podsystemów wraz z opisem, czym się zajmuje każdy z nich:

VIDEO Podsystem odpowiedzialny za wyświetlanie grafiki 2D
AUDIO Podsystem odpowiedzialny za podstawową obsługę dźwięku
EVENTS Podsystem odpowiedzialny za obsługę zdarzeń
CDROM Podsystem odpowiedzialny za odtwarzanie muzyki CD-Audio i obsługę CD-ROMu
JOYSTICK Podsystem obsługi joysticka
TIMER Podsystem odmierzania czasu
THREADS Podsystem odpowiedzialny za obsługę wątków
FILES Podsystem wejścia/wyjścia plikowego

Przygotowanie do pracy

Aby rozpocząć zabawę z SDL, trzeba ją najpierw zainicjalizować [przygotować do pracy]. Zanim wywołasz jakąkolwiek funkcję z biblioteki SDL, musisz więc najpierw wywołać funkcję SDL_Init, której nagłówek prezentuje się tak:

int SDL_Init(Uint32 flags);

Pozwala Ci ona wybrać podsystemy, z których masz zamiar korzystać i przygotowuje je do pracy. Automatycznie przygotowuje trzy podsystemy: EVENTS, THREADS i FILES. Możesz wybrać dodatkowe podsystemy, podając jej odpowiednie parametry, które poznasz lada moment.

Jak widzisz, funkcja SDL_Init pobiera tylko jeden parametr, jednak jego typ może wydawać ci się dziwny :-P Biblioteka SDL wprowadza kilka nowych, własnych typów danych, by zapewnić jednakowy rozmiar danych w pamięci na różnych platformach. Typ Uint32 możesz rozumieć jako typ unsigned int z gwarancją, że zajmie 32 bity w pamięci.

Parametr ten służy głównie do wybierania, które podsystemy mają być dodatkowo zainicjalizowane, jednak ma też kilka innych możliwości. Możesz w nim przekazać jedną z poniższych stałych:

SDL_INIT_VIDEO Podsystem graficzny
SDL_INIT_AUDIO Podsystem dźwięku
SDL_INIT_TIMER Podsystem odmierzania czasu
SDL_INIT_CDROM Podsystem obsługi CD-ROMu
SDL_INIT_JOYSTICK Podsystem obsługi joysticka
SDL_INIT_EVERYTHING Inicjalizuje wszystkie podsystemy
SDL_INIT_NOPARACHUTE SDL nie będzie za ciebie obsługiwać wyjątków
SDL_INIT_EVENTTHREAD Do odbierania zdarzeń zostanie utworzony osobny wątek

Powyższe stałe są flagami bitowymi, więc możesz je łączyć operatorem |. Przykładowo inicjalizacja podsystemów VIDEO i TIMER mogłaby wyglądać tak:

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);

Funkcja zwraca 0 gdy inicjalizacja się powiodła. W przeciwnym razie zwraca -1.

Włączanie/wyłączanie podsystemów

Czasami nie da się zainicjalizować od razu wszystkiego. Przykładowo chcesz najpierw wyświetlić menu gry, z którego użytkownik wybierze czy chce skorzystać z joysticka. Dopiero wtedy można zainicjalizować podsystem joysticka. Co zrobić w takiej sytuacji? Jak uruchomić podsystem JOYSTICK, skoro funkcja SDL_Init była już wywołana?! :-/

Twórcy biblioteki przygotowali ją na takie sytuacje ;-) Możesz włączyć dodatkowe podsystemy w późniejszym czasie. Służy do tego funkcja SDL_InitSubSystem i pobiera ona dokładnie te same parametry, co SDL_Init. Tak wygląda jej nagłówek:

int SDL_InitSubSystem(Uint32 flags);

Gdy wszystko poszło dobrze, zwraca 0. W przypadku błędu zwraca -1.

Gdy dany podsystem przestaje ci być potrzebny, możesz wyłączyć tylko ten jeden podsystem, pozostawiając resztę. Robi się to funkcją SDL_QuitSubSystem. Pobiera ona te same parametry, co poprzednie funkcje. Nie zwraca jednak żadnej wartości. To zresztą logiczne, bo jeśli chcesz wyłączyć jakiś podsystem i miałoby się to nie udać, naraziłoby cię na kolejne błędy :-P Musi się udać zawsze.

void SDL_QuitSubSystem(Uint32 flags);

Ostateczne zakończenie całego SDL wymaga funkcji SDL_Quit. Nie pobiera ona żadnych parametrów i nic nie zwraca. Zamyka ona wszystkie podsystemy [włącznie z tymi trzema domyślnymi] i zwalnia zasoby przydzielone dla SDL. Jej nagłówek to:

void SDL_Quit(void);

Tą funkcję będziesz wywoływać, gdy zechcesz zakończyć pracę z SDL. Jeśli obawiasz się, że zapomnisz po sobie posprzątać, możesz na przykład ustawić tą funkcję jako handler w wywołaniu atexit gdy tylko inicjalizacja SDL zakończy się sukcesem, np. tak:

if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0 ) {
  //Coś poszło nie tak. Wyświetl komunikat o błędzie i zakończ z kodem błędu
  cout << "Błąd inicjalizacji SDL!" << endl;
  return -1;
}
//Inicjalizacja się powiodła, więc ustawiamy handler atexit()
atexit(SDL_Quit);

Przy okazji warto zauważyć, że w systemie Windows bibliotka SDL przekierowuje standardowe kanały wyjściowe do plików mająych nazwy stdout.txt i stderr.txt. Gdyby tak nie robiła, głupawy Windows tworzyłby ci dodatkowe okno konsoli gdy tylko coś wypiszesz na stdout [ach te Windowsy.. ;-P].

Najdziwniejszą funkcją inicjalizacji SDL jest SDL_WasInit. Sprawdza ona, które podsystemy zostały zainicjalizowane, a które nie. Oto jej nagłówek:

Uint32 SDL_WasInit(Uint32 flags);

Co ciekawe, możesz zapytać ją o konkretny zestaw podsystemów, podając odpowiednie flagi SDL_INIT_* w parametrze. Funkcja weźmie te twoje flagi i sprawdzi tylko te podsystemy, o które pytasz. Jako wynik zwróci wartość, która jest połączeniem flag bitowych tylko uruchomionych podsystemów, i tylko spośród tych, o które pytasz. Mówiąc prościej: z podanych przez Ciebie flag wywala te, których podsystemy były wyłączone, i zwraca to co zostało.

Najprostszy sposób użycia tej funkcji to pytanie o to, czy jeden konkretny podsystem już działa. Wykorzystujemy wtedy fakt, że jeśli żaden z podanych przez ciebie podsystemów nie pracuje, wynikiem funkcji będzie 0:

if ( SDL_WasInit(SDL_INIT_AUDIO) ) //Podsystem AUDIO działa...
else //Podsystem AUDIO nie działa...

Obsługa błędów

Wiele funkcji SDL w przypadku błędu zwraca po prostu -1. Ta wartość niewiele jednak mówi o przyczynie błędu. W tym celu istnieje funkcja SDL_GetError.

bla bla bla

#include <SDL.h>
#include <iostream>
using namespace std;

int main()
{
  cout << "Startujemy SDL..." << endl;
    
  // Przygotuj podsystemy: domyślne, VIDEO i AUDIO.
  if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0 ) {
    cout << "Błąd inicjalizacji SDL: " << SDL_GetError() << endl;
    return -1;
  }

  cout << "SDL gotowy do pracy!" << endl;

  // Tu będzie normalne działanie programu...

  cout << "Kończymy pracę SDL..." << endl;
    
  // Wyłączamy wszystkie podsystemy SDL.
  SDL_Quit();
  cout << "Program zakończony" << endl;
}

Subskrybcja

Buttony
Button1 Button2 Button3 Button4 Button5 Button6 Button7 Dodaj swój button