Hlavní navigace

SDL: Hry nejen pro Linux (3)

8. 3. 2005
Doba čtení: 5 minut

Sdílet

V první části článku se podíváme na konvenci názvů SDL funkcí a speciální datové typy, které SDL přináší. Ve druhé části bude popsána inicializace a deinicializace SDL.

Konvence názvů SDL funkcí

Knihovna SDL má jen jednoduchou konvenci pro pojmenování svých funkcí, v podstatě se jedná pouze o předponu SDL_. Jako příklad lze uvést jakoukoli funkci, např. inicializační SDL_Init() se musí zavolat na začátku naprosto každého programu, který využívá služeb knihovny SDL.

Za předponou SDL_ se dále může nacházet WM_ nebo GL_, což označuje funkci poskytující operace vztahující se ke správci oken (Window Manager) resp. týkající se knihovny OpenGL. Jako příklad lze uvést příkaz SDL_WM_Toggle­FullScreen(), jenž přepíná aplikaci mezi režimem okno/fullscreen, a SDL_GL_SwapBuf­fers() sloužící pro výměnu předního a zadního bufferu po vykreslení OpenGL scény.

Z předchozích dvou příkladů si lze všimnout, že těla jmen funkcí začínají velkým písmenem, a pokud se skládají z více slov, jsou počáteční písmena jednotlivých slov velká.

SDL datové typy

Pro dosažení co největší přenositelnosti kódu definuje SDL své vlastní datové typy, které se při deklaraci proměnných doporučuje upřednostňovat. S jejich použitím se nestane, že u jiného kompilátoru nebo systému, než na kterém probíhá hlavní vývoj, bude mít některý datový typ programovacího jazyka jiný rozsah. Klasickým příkladem je šestnácti- a třicetidvoubi­tový int.

SDL definuje následující datové typy:

Datové typy
Jazyk C SDL
int SDL_bool (SDL_FALSE, SDL_TRUE)
unsigned char Uint8
unsigned short Uint16
unsigned int Uint32
unsigned long long Uint64
signed char Sint8
signed short Sint16
signed int Sint32
signed long long Sint64

Je nutné podotknout, že 64bitový int nemusí být podporován všemi platformami.

Hlavičkové soubory

Při vývoji stačí většinou vkládat pouze hlavičkový soubor SDL.h, jiné se používají spíše ve speciálních nebo výjimečných případech. Osobně jsem se dále setkal jen s SDL_opengl.h, který řeší umístění knihovny OpenGL na různých platformách. Např. v MacOS je k ní jiná cesta než ve Windows a v Linuxu.

#include <SDL.h>

V zájmu přenositelnosti by také měla být zachována uvedená velikost písmen – tedy SDL velkými a malé h, aby ho byl case sensitive operační systém schopen najít. I když se to nezdá, jedná se o docela častý problém Windows programátorů, kteří, když se onehdy rozhodnou portovat svůj jinak naprosto správný program, stráví tři hodiny nadáváním na ten každý-si-doplňte-své-slovo Linux ;-).

Někdy se lze také setkat s vkládáním hlavičkového souboru jako SDL/SDL.h, ale tento způsob spíše vytváří problémy (/ a \ lomítko), než aby něčemu pomáhal. Cestu k hlavičkovým souborům lze nastavit ve vývojovém prostředí.

Vstup do programu

Že první funkcí, kterou volá operační systém při spouštění programu, je main(), ví jistě každý programátor. I přesto, že je vytvářena MS Windows aplikace, měla by být tato funkce upřednostněna před WinMain(). Před samotným spuštěním main() SDL provádí ještě určité inicializace.

Pokud je z nějakého důvodu WinMain() nutná, podívejte se do souboru src/main/win32/SDL­_main.c ve zdrojových kódech SDL, abyste věděli, jaký druh dodatečné inicializace ještě potřebujete, aby SDL pracovalo tak, jak má.

Některé „exotické“ kompilátory také mohou mít problémy s formátem zápisu main(), a proto by měla být vždy deklarována takto

int main(int argc, char *argv[])

Inicializace SDL

SDL se inicializuje voláním funkce

int SDL_Init(Uint32 flags);

která při úspěchu vrátí hodnotu 0 a při neúspěchu –1. Parametr flags specifikuje, co všechno se má inicializovat. Lze předat symbolické konstanty z následující tabulky nebo jejich binárně OR-ovanou kombinaci.

Symbolické konstanty
Symbolická konstanta Inicializuje se…
SDL_INIT_VIDEO grafika
SDL_INIT_AUDIO zvuky
SDL_INIT_TIMER časovače
SDL_INIT_CDROM CD-ROM
SDL_INIT_JOYSTICK joystick
SDL_INIT_EVERYTHING vše
SDL_INIT_NOPA­RACHUTE nereagovat na chybové signály (SIGSEGV ap.)

Linux a BeOS podporují také parametr SDL_INIT_EVEN­TTHREAD, který, pokud bude předán do SDL_Init(), způsobí, že smyčka hlídající události bude běžet asynchronně ve vlastním vláknu.

Pozn.: Pokud budete mít problémy s laděním SDL aplikace ve Visual C++ debuggeru, zkuste nastavit flag SDL_INIT_NOPA­RACHUTE.

Inicializace dalších subsystémů

Kdykoli po hlavní inicializaci lze pomocí následující funkce inicializovat i další subsystémy. Chování obou rutin je analogické.

int SDL_InitSubSystem(Uint32 flags);

Kontrola inicializace subsystémů

Zjištění, které subsystémy byly inicializovány a které ne, se provede pomocí

Uint32 SDL_WasInit(Uint32 flags);

Za parametr flags se předají subsystémy, které se mají otestovat, a vrácena je bitová maska subsystémů, které jsou inicializovány.

V následujícím příkladu se pokusí aplikace o inicializaci grafického a zvukového subsystému. Pokud se grafiku nepodaří inicializovat, program skončí. V případě nedostupnosti zvuků bude program pokračovat dále bez nich.

// Globální proměnná
bool use_audio = true;

// V main()
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) == -1)
{
  fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());

  Uint32 flags = SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO);

  // Grafika musí být vždy
  if(!(flags & SDL_INIT_VIDEO))
  {
    SDL_Quit();
    return 1;
  }

  // Zvuky používat pouze, pokud jsou dostupné
  use_audio = (flags & SDL_INIT_AUDIO) ? true : false;
}

Určení typu chyby

V příkladu výše byla po neúspěšné inicializaci vypisována chybová zpráva, na jejíž konec byl připojen řetězec s upřesněním získaným od SDL. Funkce SDL_GetError() vrátí NULLem ukončený řetězec obsahující informace o poslední vnitřní chybě SDL.

char *SDL_GetError(void);

Dále existují ještě dvě funkce, které jsou však určeny spíše pro vývojáře knihovny SDL než pro její uživatele. Pomocí první se nastavuje řetězec s chybou a tou druhou se maže.

void SDL_SetError(const char *fmt, ...);
void SDL_ClearError(void);

Pozn.: U výše uvedeného výpisu textu pomocí fprintf() resp. printf() se v Linuxu zobrazí text do konzole, pod MS Windows v nekonzolové aplikaci se ve stejném adresáři, kde je umístěn spuštěný EXE soubor, automaticky vytvoří soubory stderr.txt a stdout.txt.

Deinicializace

Před ukončením programu by měla být vždy zavolána funkce SDL_Quit(), která se postará o veškerý úklid.

void SDL_Quit(void);

V některých cizích zdrojových kódech se lze též setkat s příkazem atexit(SDL_Quit);, který je zapsán hned za SDL_Init() a který při ukončení programu zavolá SDL_Quit() automaticky. Nicméně každá trochu delší aplikace obsahuje alespoň náznak nějaké ukončovací logiky, lepší je umístit SDL_Quit() tam.

Podobně, jako mělo SDL_Init() protějšek v SDL_InitSub­System(), i SDL_Quit() má svůj SDL_QuitSubSys­tem(). Pokud ale není subsystém ukončován někde uprostřed aplikace, stačí na konci zavolat pouze SDL_Quit() a je uvolněno všechno.

CS24_early

void SDL_QuitSubSystem(Uint32 flags);

Ukázkový program

Tento díl bude bohužel bez příkladu. Probíraná látka byla předběžně ukázána už v programu z minulé lekce.

Download

Pokračování

Příště se podíváme na vytváření okna se vším, co s tím souvisí.

Byl pro vás článek přínosný?

Autor článku

Backend programátor ve společnosti Avast, kde vyvíjí a spravuje BigData systém pro příjem a analýzu událostí odesílaných z klientských aplikací založený na Apache Kafka a Apache Hadoop.