Vytvoření SDL okna

Woq mě požádal, abych napsal tutoriál pro používání OpenGL pod knihovnou SDL. Je to můj první tutoriál, takže doufám, že se bude líbit. Zkusíme vytvořit kód, který bude odpovídat druhé lekci "normálních" tutoriálů. Zdrojový kód je "oficiální" NeHe port druhé lekce do SDL. Pokusím se popsat, jak se vytváří okno a věci okolo.

Na úvod bych chtěl poděkovat Bernymu za sebe i za všechny, kterým tento článek velice pomohl, a kteří si myslí, že dělat programy výhradně pro komerční Wokna není tou správnou cestou.

Nejdříve něco o tom, co je SDL. SDL, univerzální knihovna, slouží pro tvorbu her. Znáte-li Allegro, tak SDL je mu trochu podobné. Bylo napsáno v C(/C++) a jeho domovské prostředí bylo Linux. Nyní ale existuje i pod BeOS, MacOS, Windows, QNX, AmigaOS, PS2,.... Obsahuje základní API pro vytvoření okna, 2D grafiku, vícevláknové programování, obsluhu klávesnice, krysy a joysticku, přehrávání videa a zvuků. Ke knihovně jsou ještě podpůrné knihovničky pro načítáni rozmanitých grafických formátů, pro lepší ozvučení (mp3, ogg,..) a síťové služby pro multiplayer. Přímo podporuje využití OpenGL, které samo o sobě manipulaci s okny, komunikaci se systémem a všechnu práci okolo neumí a tudíž nedělá. Kód který vytvoříte v SDL můžete velice snadno přenést jinam jednoduchým překompilováním (bude to fungovat, pokud nepíšete jako čuňata). SDL není jen nějaká malá knihovnička, ale používají ji i komerční hry. Většina her od Lokisoft (portují hry pod Linux) je nad SDL a Unreal Tournament 2003 také. Nejlepší bude, pokud navštívíte domovský web - http://www.libsdl.org/. Jsou tam všemožné helpy, návody, manuály a také vystaveny práce lidí, kteří SDL používají; pár dílek i z ČR.

Než začneme, ujistěte se, že máte knihovnu SDL. Pokud ne, navštivte výše uvedenou adresu a stáhněte si soubory pro vaši konkrétní platformu.

A teď už se vrhneme na programování. Nejdříve vložíme hlavičkové soubory. Možná se to zdá na první pohled jako šílenost, ale vyřešíme přenášení kódu na různé OS. Proto doporučuji toto vkládání nechat tak, jak je.

#ifdef WIN32 // Pokud se bude kompilovat program po Windows

#define WIN32_LEAN_AND_MEAN

#include <windows.h> // Hlavičkový soubor pro Windows

#endif

#if defined(__APPLE__) && defined(__MACH__) // Pokud se bude kompilovat program pro Apple

#include <OpenGL/gl.h> // Hlavičkový soubor pro OpenGL32 knihovnu v Applu

#include <OpenGL/glu.h> // Hlavičkový soubor pro GLu32 knihovnu v Applu

#else

#include <GL/gl.h> // Hlavičkový soubor pro OpenGL32 knihovnu

#include <GL/glu.h> // Hlavičkový soubor pro GLu32 knihovnu

#endif

#include "SDL.h" // Hlavičkový soubor pro SDL

Vytvoříme funkci na inicializaci OpenGL (smíchané InitGL() a ResizeGLScene() z klasických tutoriálů). Naším cílem není rozebírat OpenGL, ale spíše vysvětlit SDL. Pro detaily se podívejte do druhé lekce.

void InitGL(int Width, int Height) // Tuto funkci voláme hned po vytvoření okna pro inicializace OpenGL

{

glViewport(0, 0, Width, Height);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Černé pozadí

glClearDepth(1.0); // Povolíme mazání pozadí

glDepthFunc(GL_LESS); // Vybereme typ Depth Testu

glEnable(GL_DEPTH_TEST); // Povolíme Depth Test

glShadeModel(GL_SMOOTH); // Povolíme Smooth Color Shading

glMatrixMode(GL_PROJECTION);

glLoadIdentity(); // Resetujeme projekční matici

gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Vypočítáme poměr okna

glMatrixMode(GL_MODELVIEW);

}

Vykreslování...

void DrawGLScene() // Hlavní vykreslovací funkce

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Vymazání obrazovkového a hloubkového bufferu

glLoadIdentity(); // Reset matice pohledu

glTranslatef(-1.5f,0.0f,-6.0f); // Posun o 1.5 doleva a o 6 do hloubky

// Nakreslí trojúhelník

glBegin(GL_POLYGON);

glVertex3f(0.0f, 1.0f, 0.0f);

glVertex3f(1.0f,-1.0f, 0.0f);

glVertex3f(-1.0f,-1.0f, 0.0f);

glEnd();

glTranslatef(3.0f,0.0f,0.0f); // Posuneme se o 3 doprava

// Nakreslí čtverec

glBegin(GL_QUADS);

glVertex3f(-1.0f, 1.0f, 0.0f);

glVertex3f( 1.0f, 1.0f, 0.0f);

glVertex3f( 1.0f,-1.0f, 0.0f);

glVertex3f(-1.0f,-1.0f, 0.0f);

glEnd();

Na konci provedeme drobnou změnu. Zavoláme funkci SDL_GL_SwapBuffers(), která zajistí, že se na obrazovce objeví vše, co jsme ve funkci DrawGLScene() nakreslili. V klasických tutoriálech najdete SwapBuffers() ve WinMain() po volání této funkce.

SDL_GL_SwapBuffers(); // Prohozeni bufferu, aby se zobrazilo, co jsme nakreslili

}

Že se funkce main() provádí po spuštění programu jako první doufám víte :-] Leží zde většina SDL kódu. Nejprve provedeme inicializaci a pak cyklujeme dokola v jednoduché smyčce zpráv. Dávejte si pozor, aby deklarace main() byla přesně taková, jak má být - nikdy nevynechávat argumenty a návratovou hodnotu.

int main(int argc, char **argv) // Prostě main() :-)

{

int done; // Ukončovací proměnná

Inicializace knihovny se musí zavolat jako první před vším ostatním. SDL_INIT_VIDEO znamená, že budeme chtít inicializovat výstup na obrazovku. Může se kombinovat i s dalšími jako třeba timerem, audiem,... Knihovna SDL nám umožňuje používat stdout a stderr pro textový výstup. V Linuxu vypisuje na terminál, ve windows vytvoří soubory stdout.txt a stderr.txt (v případě, že do nich nic nezapíšete je pak opět smaže).

if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) // Inicializace SDL s grafickým výstupem

{

fprintf(stderr, "Selhala inicializace SDL: %s\n", SDL_GetError());

exit(1);

}

Teď můžeme vytvořit okno aplikace. Máme k tomu funkci SDL_SetVideoMode. První dva parametry jsou rozměry okna, další parametr určuje barevnou hloubku (0 zachovává současnou). Poslední parametr je kombinací různých flagů. Pokud chceme požívat OpenGL, musíme zadat SDL_OPENGL (nebo SDL_OPENGLBLIT). Pokud chcete fullscreen, můžete přidat flag SDL_FULLSCREEN. V X11 (Linuxu) můžete přepínat mezi fullscreenem a oknem svobodně kdykoliv se vám zachce voláním funkce SDL_WM_ToggleFullScreen(), ale ve Windows si v SDL_SetVideoMode() jednou vyberete a to vám pak zůstane. Protože jsme inicializovali SDL, musíme ho v případě erroru také ukončit. Má to na starosti funkce SDL_Quit().

if (SDL_SetVideoMode(640, 480, 0, SDL_OPENGL) == NULL) // Vytvoření OpenGL okna 640x480

{

fprintf(stderr, "Neni mozne vytvorit OpenGL okno: %s\n", SDL_GetError());

SDL_Quit(); // Ukončení SDL

exit(2);

}

Nastavíme titulek okna. Můžeme přidat i ikonku, ale protože žádnou nemáme, použijeme NULL.

SDL_WM_SetCaption("Jeff Molofee's GL Code Tutorial ... NeHe '99", NULL); // Titulek okna

InitGL(640, 480); // Inicializace OpenGL

Hlavní cyklus programu. Pro opuštění programu použijeme proměnnou done (deklarovaná na začátku main(), kterou testujeme v každém průběhu hlavním cyklem.

done = 0; // Ještě nekončit

while (!done) // Hlavní cyklus programu

{

DrawGLScene(); // Vykreslení scény

Obsluha událostí by měla přijít do zvláštní funkce (analogie WndProc() z Windows), ale nebudeme jednoduchý kód komplikovat. Nejprve vytvoříme proměnou typu SDL_Event. Pak pro načtení zpráv voláme v cyklu SDL_PollEvent(). Dokud přicházejí události, tak se jimi zabýváme. Tentokrát zareagujeme pouze na požadavek ukončení pomocí klávesy ESC. Přesuny okna, změna jeho velikosti ap. se dějí automaticky.

SDL_Event event; // Proměnná zprávy

while (SDL_PollEvent(&event)) // Zpracovávat zprávy

{

if (event.type == SDL_QUIT) // Zpráva o ukončení

{

done = 1; // Ukončit hlavní cyklus

}

if (event.type == SDL_KEYDOWN) // Zpráva o stisku klávesy

{

if (event.key.keysym.sym == SDLK_ESCAPE) // Klávesa ESC

{

done = 1; // Ukončit hlavní cyklus

}

}

}

}

Na konci už jen ukončíme SDL.

SDL_Quit(); // Ukončení SDL

return 0;

}

Pro kompilaci tutoriálu v Linuxu můžeme použít např. příkaz níže. Spustíme standardní kompilátor gcc a zapneme všechna varovná hlášení. Chceme zkompilovat soubor lesson02.c a přilinkovat knihovny pro SDL (všimněte si zpětných apostrofů!!! - na klávesnici pod Esc), OpenGL a GLU. Výsledný spustitelný soubor se vytvoří ve stejném adresáři, ve kterém se právě nacházíme, a bude mít název lesson02. Tento nový program se může spustit buď přes libovolný souborový manažer nebo - když už jsme ve shellu - příkazem ./lesson02. Pokud dáme na konec ampérsand, spustí se na pozadí a nebudeme mít blokovanou příkazovou řádku. Aby šel program spustit, musí na počítači běžet XFree server (XFree86, X, X11, XWindow - prostě grafický režim :-).

[woq@komputerovka c]$ gcc -Wall lesson02.c `sdl-config --libs --cflags` -lGL -lGLU -o lesson02

[woq@komputerovka c]$ ./lesson02 &

Ve Windows a Visual C++ je zprovoznění maličko komplikovanější. Vycházím z jednoho článku o SDL, který napsal František Jahoda a který jsem kdysi stáhl z http://www.builder.cz/. Povětšinou CTRL+C & CTRL+V :-] V prostředí Microsoft Visual C++ postupujte takto:

napsal: Bernard Lidický - Berny <2berny (zavináč) seznam.cz>, 17.02.2003

Zdrojové kódy

Errata

SDL program pod Mandrake GNU/Linuxem, KDE 3.2 - Plastik