Aus Linux-Magazin 11/2013

Simple Directmedia Layer 2.0

© kzenon, 123RF.com

Nach mehreren Jahren Entwicklungsarbeit ist im August die modernisierte Version 2.0 der Bibliothek SDL erschienen. Trotz der zahlreichen Neuerungen fällt der Um- und Einstieg erstaunlich leicht.

Seit 1998 legt Simple Directmedia Layer (SDL) die Grundlage für unzählige Spiele, Multimedia-Anwendungen und sogar Virtualisierungslösungen. Die kleine plattformunabhängige Bibliothek erleichtert es Anwendungen, auf die Grafikkarte, die Audiohardware, die Tastatur und andere Eingabegeräte zuzugreifen. Da sie für viele verschiedene Plattformen und Betriebssysteme erhältlich ist, lassen sich mit ihr entwickelte Programme leicht portieren (siehe Kasten “Unterstützte Betriebssysteme”). Ohne sie müssten Linux-Nutzer vermutlich immer noch auf die Umsetzungen großer Spiele wie Portal warten (Abbildungen 1 und 2).

Unterstützte Betriebssysteme

Offiziell unterstützte die SDL 2.0.0 zum Redaktionsschluss folgende Betriebssysteme:

  • Linux ab Kernel 2.6
  • Android ab Version 2.3.3
  • Windows XP, Vista, 7 und 8
  • Mac OS X ab Version 10.5
  • I-OS ab Version 5.1.1

Unter Free BSD, Net BSD, Open BSD und Solaris soll sich die SDL 2.0 zwar ebenfalls übersetzen und einsetzen lassen, die Entwickler übernehmen dafür aber keine Garantie. Zudem existieren inoffizielle Portierungen auf Haiku, die Playstation Portable und Pandora.

Damit ist die Liste der unterstützten Systeme deutlich kürzer als die der SDL 1.2. Mangels Maintainer musste das Team insbesondere die Portierungen für ältere Betriebssysteme wie OS/2 und Beos streichen.

Abbildung 1: Auf der SDL basieren fast alle über Steam angebotenen Spiele, darunter auch Blockbuster wie das Knobelspiel Portal.

Abbildung 1: Auf der SDL basieren fast alle über Steam angebotenen Spiele, darunter auch Blockbuster wie das Knobelspiel Portal.

Abbildung 2: Aber auch ernsthafte Anwendungen, zum Beispiel die Virtualisierungssoftware Qemu und Virtualbox, nutzen die SDL unter anderem für ihre Bildschirmausgaben.

Abbildung 2: Aber auch ernsthafte Anwendungen, zum Beispiel die Virtualisierungssoftware Qemu und Virtualbox, nutzen die SDL unter anderem für ihre Bildschirmausgaben.

Erstaunliche zwölf Jahre lang bildete die Version 1.2 der SDL die Grundlage zahlreicher Programme. Änderungen gab es immer nur in homöopathischen Dosen, die letzte Revision (1.2.15) erschien im Januar 2012. Die SDL 1.2 gilt damit zwar als äußerst robust, die Hardware-Entwicklung hat sie jedoch gnadenlos überholt. Im Hintergrund arbeiteten die SDL-Entwickler deshalb schon seit mehreren Jahren parallel an einer runderneuerten, modernen Variante.

Die Entwicklerversionen trugen zunächst die Nummer 1.3, aufgrund der vielen internen Änderungen machten die Entwickler im Februar 2012 jedoch den Sprung auf die Nummer 2.0. Obwohl dieser neue Versionszweig bereits in vielen Softwareprojekten zum Einsatz kam, zögerten die Entwickler, ihm den Stempel “Stabil” aufzudrücken. Erst im August dieses Jahres zog Erfinder und Projektleiter Sam Lantinga einen Schlussstrich und gab den aktuellen Entwicklungsstand offiziell als Version 2.0.0 frei.

2.0 macht Tempo

Die neue Version kann endlich mehrere Fenster gleichzeitig öffnen, erkennt mehrere angeschlossene Bildschirme und kann mehrere Audiogeräte gleichzeitig ansteuern. Zur Ausgabe von 2-D-Grafik nutzt die SDL ab sofort die Hardwarebeschleunigung moderner 3-D-Grafikkarten. Unter Linux finden die Bilddaten dabei über die Open-GL-Schnittstelle ihren Weg auf den Bildschirm. Im Notfall oder auf Wunsch berechnet die schlanke Bibliothek aber auch die Grafik mit einem Software-Renderer selbst.

Die SDL bietet weiterhin nur Zeichenfunktionen für 2-D-Grafiken an. 3-D-Grafiken erzeugen Programmierer mit Open GL ab Version 3.0 beziehungsweise Open GL ES auf Mobilgeräten. Die SDL übernimmt dann lediglich alle übrigen Aufgaben, etwa die Audio-Ausgabe oder das Abfragen der Tastatur. Unter Windows, Mac OS X und Linux kann die neue SDL-Version endlich mit Force-Feedback-Geräten umgehen, zudem unterstützt sie Eingabegeräte mit Touch-Oberfläche.

Verbessertes Powermanagement soll für längere Laufzeiten vor allem auf Mobilgeräten sorgen. Obendrauf kommen zahlreiche kleine Verbesserungen, etwa die Unicode-Unterstützung. Vorhandene SDL-Programme lassen sich recht leicht auf die SDL 2.0 portieren, aufgrund der zahlreichen Änderungen reicht jedoch ein Neukompilieren nicht aus.

Auch bei der Lizenz gab es eine Änderung: Die LGPL-Lizenz der alten SDL 1.2 erschwerte die Nutzung in kommerziellen Projekten. Chefentwickler Sam Lantinga gründete zwischenzeitlich sogar eine Firma, über die Entwickler eine Lizenz für kommerzielle Programme erwerben konnten. Die neue Version 2.0 steht hingegen unter der liberaleren Zlib-Lizenz, die eine uneingeschränkte kommerzielle Nutzung der Bibliothek erlaubt.

Inbetriebnahme

Die in C geschriebene SDL bietet selbst nur eine C-Schnittstelle an. Diese lässt sich aber direkt aus C++-Programmen nutzen, Bindungen gibt es zudem schon für Python, C# und Pascal [2]. Da die SDL 2 noch keiner Distribution beiliegt, muss der Entwickler sie selbst übersetzen und einspielen. Um alle Funktionen nutzen zu können, benötigt er neben einem C-Compiler und »make« auch noch die Entwicklerpakete zu X11, Open GL, Alsa, Pulseaudio, Libudev, Pthreads, Dbus und je nach Bedarf noch die des ESD (Enlightened Sound Daemon), des Arts-Audio-Servers und die Libts-Bibliothek zur Ansteuerung von Touchscreens.

Die Installation ist mit dem üblichen Dreisprung schnell erledigt: »./configure; make; make install« . Die Ausgaben von »configure« sollte der Anwender nach nicht erfüllten Abhängigkeiten durchsuchen. Unter Umständen fehlen sonst später im Betrieb benötigte Funktionen, zum Beispiel die Unterstützung für den ESD. Nach der Installation sollte Root sicherheitshalber einmal »ldconfig« anwerfen. SDL 2 lässt sich übrigens problemlos neben der alten SDL 1.2 installieren und betreiben: Die Bibliothek selbst heißt »libSDL2.so« , die Headerdateien landen im Unterverzeichnis »SDL2« .

Erste Gehversuche

Da die SDL 2.0 ein klares und einfaches API besitzt, fallen die ersten Schritte leicht. Wer bereits mit der alten Version 1.2 gearbeitet hat, dürfte zudem einiges wiedererkennen. Im eigenen Programm bindet der Entwickler zunächst die SDL über eine einzige Headerdatei ein:

#include "SDL2/SDL.h"

Bevor er die Funktionen der SDL nutzen kann, muss er die Subsysteme der SDL initialisieren. Das übernimmt:

SDL_Init(SDL_INIT_EVERYTHING);

Als Parameter erwartet »SDL_Init()« ein so genanntes Flag, das angibt, welche Subsysteme die Funktion initialisieren soll. Das Flag »SDL_INIT_EVERYTHING« aktiviert alle verfügbaren Subsysteme. Wer später nur Grafiken ausgeben möchte, verwendet alternativ »SDL_INIT_VIDEO« .

Mehrere Flags darf der Programmierer mit einem logischen Oder verknüpfen und so mehrere ausgewählte Subsysteme initialisieren. Die folgende Anweisung aktiviert das Video- und das Audio-Subsystem:

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);

War der Aufruf erfolgreich, liefert »SDL_Init()« eine »0« zurück. Bei einem negativen Wert ist hingegen ein Fehler aufgetreten. Die Fehlermeldung dazu liefert die Funktion »SDL_GetError()« . Diese Form der Fehlerbehandlung nutzen auch die meisten anderen SDL-Funktionen. Damit eigener Code nicht gegen die Wand fährt, sollte der Programmierer folglich immer den Rückgabewert auswerten:

if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
    printf("Fehler: %s \n", SDL_GetError());
    return 1;
}

War dies SDL-1.2-Nutzern noch vertraut, folgt jetzt Neuland: Die SDL 2 schmeißt das gute alte »SDL_SetVideoMode()« über Bord.

Verlief die Initialisierung erfolgreich, kann der Anwender ein Fenster öffnen. Die dafür zuständige Funktion »SDL_CreateWindow()« verlangt als Parameter einen Namen für die Titelleiste, die Position der linken oberen Ecke des Fensters auf dem Bildschirm sowie die Größe des Fensters in Pixeln:

SDL_Window *fenster = SDL_CreateWindow("Hallo Welt!", 250, 300, 640, 480,SDL_WINDOW_SHOWN);

Hier trägt das Fenster den Titel »Hallo Welt!« , erscheint 250 Pixel vom linken und 300 Pixel vom oberen Bildschirmrand entfernt auf dem Desktop und ist außerdem 640 mal 480 Pixel groß. Das Flag »SDL_WINDOW_SHOWN« sorgt dafür, dass das Fenster definitiv auf dem Bildschirm zu sehen ist – »SDL_WINDOW_HIDDEN« würde es zunächst verstecken. Eine Alternative wäre »SDL_WINDOW_FULLSCREEN« , was den Fensterinhalt im Vollbildmodus anzeigt. Auch hier gibt es noch weitere Flags, die man per Oder verknüpfen kann: So entfernt »SDL_WINDOW_BORDERLESS« den Fensterrahmen, während »SDL_WINDOW_MAXIMIZED« das Fenster maximiert.

Die Funktion »SDL_CreateWindow()« liefert einen Zeiger auf ein »SDL_Window« -Objekt zurück. Über ihn lässt sich das Fenster gleich ansprechen. Sollte ein Fehler aufgetreten sein, dann ist der Zeiger »NULL« . Den Grund verrät wieder »SDL_GetError()« .

Großer Künstler

Als Nächstes benötigt der Entwickler einen so genannten Renderer, das ist der Maler, der in das Fenster zeichnet. Wie er das macht, bleibt ihm selbst überlassen. Unter Windows könnte er etwa Direct X verwenden, unter Linux nutzt er normalerweise Open GL. Einen Renderer erzeugt die Funktion »SDL_CreateRenderer()« :

SDL_Renderer *renderer =SDL_CreateRenderer(fenster, -1,SDL_RENDERER_ACCELERATED |SDL_RENDERER_PRESENTVSYNC);

Als ersten Parameter erwartet sie einen Zeiger auf das Fenster, in das der Renderer später alle Ausgaben schieben soll. Die »-1« weist die SDL an, einen Renderer mit ganz bestimmten Eigenschaften zu wählen. Welche das sind, geben die nachfolgenden Flags vor. Im Beispiel soll der Renderer die Hardwarebeschleunigung der Grafikkarte nutzen (»SDL_RENDERER_ACCELERATED« ) und den Bildaufbau mit der Bildschirmfrequenz synchronisieren (»SDL_RENDERER_PRESENTVSYNC« ). »SDL_CreateRenderer()« spuckt schließlich einen Zeiger auf einen passenden Renderer aus. Ist dieser Zeiger »NULL« , trat ein Fehler auf, den Grund verrät »SDL_GetError()« .

Den Renderer kann der Entwickler nun dazu anweisen, den Inhalt des Fensters zu leeren:

SDL_SetRenderDrawColor(renderer, 235, 235,235, 255);
SDL_RenderClear(renderer);

Die erste Funktion setzt die Zeichenfarbe auf ein Hellgrau mit dem RGB-Wert »235, 235, 235« . Der letzte Parameter von »SDL_SetRenderDrawColor()« legt die Transparenz fest (genauer gesagt den Wert des Alphakanals). Im vorliegenden Fall soll der Renderer das Hellgrau deckend auftragen. »SDL_RenderClear()« malt anschließend das Fenster mit der eingestellten Farbe aus.

Einladung

Um im Fenster ein Bild anzuzeigen, muss der Programmierer es erst einmal laden. Die SDL selbst bietet dazu lediglich die Funktion »SDL_LoadBMP()« an, die ein unkomprimiertes Bild im BMP-Format in den Speicher schaufelt. Dazu braucht der Entwickler ihr lediglich den Dateinamen zu übergeben:

SDL_Surface *bild = SDL_LoadBMP("logo.bmp");

Wie schon unter der alten SDL 1.2 ist das Ergebnis ein Zeiger auf eine so genannte Surface. Diese Datenstruktur kapselt einfach die Bitmap im Hauptspeicher. Wer andere Dateiformate einlesen möchte, muss diese entweder selbst laden und in eine »SDL_Surface« -Datenstruktur hämmern oder zu einer Hilfsbibliothek wie der beliebten SDL_Image greifen (siehe Kasten “Helfershelfer”).

Helfershelfer

Die SDL deckt mit ihrem Funktionsumfang nur den Grundbedarf eines Spieleprogrammierers ab. So lädt sie beispielsweise ausschließlich Bilder im BMP-Format. Daher haben einige Entwickler weitere Hilfsbibliotheken geschrieben: SDL_net vereinfacht zum Beispiel den Zugriff auf das Netzwerk, SDL_mixer ermöglicht das Abmischen von Audiomaterial, SDL_ttf verschönert Texte mit Truetype-Schriften, während SDL_Image Bilder in gängigen Dateiformaten einlädt.

Diese und einige weitere Bibliotheken haben sogar den Status einer “offiziellen Erweiterung” erhalten und eine Heimat auf der SDL-Homepage gefunden. Seit der Neugestaltung der Homepage sind sie jedoch nicht mehr direkt verlinkt [3].

Zusammen mit der SDL haben auch die vier oben genannten Bibliotheken einen Sprung auf Version 2 gemacht. Im Wesentlichen unterstützen sie die neuen Funktionen der SDL. So kann SDL_Image das geladene Bild direkt als Textur zurückgeben. Die folgende Anweisung holt so das Tiff-Foto »logo.tiff« von der Festplatte:

SDL_Texture *logo = IMG_LoadTexture(renderer, "logo.tiff");

Da die Bibliotheken folglich nur noch mit SDL 2 zusammenarbeiten, heißen sie jetzt SDL2_Image, SDL2_ttf, SDL2_mixer und SDL2_net.

Konvertit

An dieser Stelle ergibt sich ein kleines Problem: Der Renderer kann nur Texturen und keine Surface in das Fenster malen. Folglich muss der Programmierer die Surface in eine Textur konvertieren:

SDL_Texture *textur = SDL_CreateTextureFromSurface(renderer, bild);

Da die Surface jetzt überflüssig ist, gibt der Entwickler den von ihr belegten Speicherplatz wieder frei:

SDL_FreeSurface(bild);

Abschließend muss er nur noch den Renderer anweisen, die Textur in das Fenster zu kopieren:

SDL_RenderCopy(renderer, textur, NULL,NULL);

Das »NULL« im vorletzten Parameter weist den Renderer dazu an, die komplette Textur – und nicht nur einen Ausschnitt – in das Fenster zu zeichnen. Ist der letzte Parameter »NULL« , passt der Renderer die Textur in das Fenster ein. Sofern die Textur (also das geladene Bild) andere Abmessungen als das Fenster aufweist, führt das zwangsweise zu einer Verzerrung wie in Abbildung 3.

"Abbildung

Einpassen

Um das zu ändern, verrät der Entwickler der Funktion »SDL_RenderCopy()« noch die Größe der Textur sowie die Position, an der die linke obere Ecke des Bildes im Fenster erscheinen soll. Diese Informationen erwartet »SDL_RenderCopy()« in einem »SDL_Rect« . Das ist eine Datenstruktur, die schlicht die Abmessungen eines Rechtecks kapselt. Zunächst zeichnet »SDL_RECT pos;« also ein Rechteck. SDL zählt die Pixel von der linken oberen Fensterecke, beginnend bei »0« . Im Beispiel soll die linke obere Ecke der Textur 150 Pixel vom linken Fensterrand und 100 Pixel vom oberen Fensterrand entfernt erscheinen. Diese beiden Werte wandern in die Variablen »x« und »y« :

pos.x = 150;
pos.y = 100;

Wie breit und hoch die Textur im Fenster erscheint, verraten die Variablen »pos.w« und »pos.h« . Damit der Renderer die Textur nicht verzerrt, weist der Programmierer ihnen folglich die Breite und Höhe der Textur zu. Diese beiden Werte kann er entweder etwas umständlich mit einem Malprogramm herausfinden oder von der Funktion »SDL_QueryTexture()« ermitteln lassen:

SDL_QueryTexture(textur, NULL, NULL,&pos.w, &pos.h);

Sie liefert neben der Weite und Höhe der Textur auch das Pixelformat (RGB, YUV oder Ähnliches) sowie einen Zeiger auf die eigentliche Bitmap im Speicher. Diese Informationen sind hier nicht weiter von Interesse, weshalb sie »SDL_QueryTexture()« aufgrund der beiden »NULL« für sich behält.

In »pos« befinden sich jetzt die Position und die Größe, in der der Renderer die Textur in das Fenster malen soll. Der Entwickler braucht »SDL_RenderCopy()« nur noch einen Zeiger auf »pos« zu übergeben, das Ergebnis zeigt Abbildung 4:

"Abbildung

SDL_RenderCopy(renderer, textur, NULL,&pos);

Nach dem gleichen Prinzip malt der Programmierer weitere Texturen in das Fenster. Dabei zeichnet der Renderer die zuerst kopierten Texturen als Erstes. In folgendem Beispiel

SDL_RenderCopy(renderer, hinten, NULL,NULL);
SDL_RenderCopy(renderer, vorne, NULL, NULL);

würde der Renderer erst die Textur »hinten« in das Fenster malen und anschließend die Textur »vorne« drüberkleben. Zum Abschluss muss der Code den Renderer noch anweisen den aktualisierten Fensterinhalt anzuzeigen:

SDL_RenderPresent(renderer);

Dieser letzte Schritt scheint nur auf den ersten Blick überflüssig: Würde der Renderer jeden Zeichenvorgang direkt in das Fenster malen, müsste der spätere Anwender unter Umständen dabei zusehen, wie sich das Bild aus den einzelnen Texturen aufbaut. Die Folge wären unschöne, flackernde Animationen.

Haltestelle

Wer die Codestücke jetzt zu einem Programm zusammenfügen und starten würde, bekäme ein kurz aufgerissenes Fenster zu sehen, das sich sofort wieder beendet. Um das zu verhindern, könnte man das Programm einfach für 2 Sekunden anhalten:

SDL_Delay(2000);

Eleganter ist es jedoch, den Benutzer selbst das Programm per Tastendruck, einen Klick in das Fenster oder über den Schließen-Knopf in der Titelleiste beenden zu lassen. Ab hier dürfte SDL-1.2-Nutzern wieder einiges sehr bekannt vorkommen: Tastendrücke, Mausklicks und andere Eingaben sind für die SDL Ereignisse.

Bitte warten

Jedes ausgelöste Ereignis landet zunächst in einer Warteschlange. Das nächste Ereignis in der Schlange holt die Funktion »SDL_WaitEvent()« ab. Sollte die Warteschlange leer sein, wartet »SDL_WaitEvent()« so lange, bis ein Ereignis auftritt. Dann muss der Programmierer nur noch abfragen, um welches Ereignis es sich handelt. Das dabei entstehende Switch/Case-Monster zeigt Listing 1.

Listing 1

Ereignisbehandlung in SDL

01 SDL_Event ereignis;
02 int quit=1;
03 while(quit) {
04   SDL_WaitEvent(&ereignis);
05   switch(ereignis.type) {
06   case SDL_QUIT:
07     printf("Fenster geschlossen\n");
08     quit=0;
09     break;
10   case SDL_KEYDOWN:
11     printf("Tastendruck\n");
12     printf("Physische Taste %s als Taste %s gedrückt\n",
13            SDL_GetScancodeName(ereignis.key.keysym.scancode),
14            SDL_GetKeyName(ereignis.key.keysym.sym));
15     quit=0;
16     break;
17   case SDL_MOUSEBUTTONDOWN:
18     printf("Linke Maustaste gedrückt an\n");
19     printf("Position: (%d, %d)\n", ereignis.motion.x, ereignis.motion.y);
20     quit=0;
21     break;
22   }
23 }

Die Hilfsvariable »quit« signalisiert lediglich, ob das Programmende erreicht ist. »SDL_WaitEvent()« holt aus der Warteschlange das nächste Ereignis ab und steckt es in eine Datenstruktur vom Typ »SDL_Event« . Diese speichert in der Variablen »type« , um welche Art Ereignis es sich handelt. Drückt der Anwender eine Taste, besitzt »type« den Wert »SDL_KEYDOWN« . Um welche Taste es sich dabei handelt, verrät das Ereignis in der Variablen »ereignis.key.keysym.scancode« . Die Tastennummer übersetzt »SDL_GetScancodeName()« in den entsprechenden Buchstaben beziehungsweise die Tastenbezeichnung.

Da die Tastatur auf jedem System anders belegt ist, weist die SDL jeder Taste noch einen symbolischen Namen zu. Er liegt in der Variablen »ereignis.key.keysym.sym« , die Funktion »SDL_GetKeyName()« macht daraus ein lesbares Ergebnis (siehe Abbildung 5). Sofern der Anwender in das Fenster klickt, erzeugt er ein Ereignis vom Typ »SDL_MOUSEBUTTONDOWN« . Die Koordinaten des Mauszeigers liegen dabei in den Variablen »ereignis.motion.x« und »ereignis.motion.y« . Ein Spiel würde diese Koordinaten auswerten und prüfen, welches Spielobjekt darunterliegt.

"Abbildung

Das Ereignis »SDL_QUIT« löst der Anwender aus, wenn er das Programm schließt. Neben diesen drei vorgestellten kennt die SDL noch viele weitere Ereignisse [4]. Lässt der Anwender beispielsweise eine Taste los, erzeugt das ein »SDL_KEYUP« -Ereignis.

Runden drehen

Im Unterschied zur SDL 1.2 legt »SDL_WaitEvent()« die Anwendung beziehungsweise den Prozess nicht mehr schlafen. Stattdessen durchläuft »SDL_WaitEvent()« intern einfach so lange eine Schleife, bis ein Ereignis auftritt. Die Entwickler haben jedoch schon angedroht, dass sich dieses Verhalten in Zukunft noch einmal ändern kann.

Endreinigung

Zum Schluss gilt es, noch etwas aufzuräumen. So sollte der Entwickler den von der Textur belegten Speicher wieder freigeben, den Renderer und das Fenster zerstören sowie die SDL noch einmal feucht durchwischen lassen:

SDL_DestroyTexture(textur);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(fenster);
SDL_Quit();

Das damit komplette Programm zeigt noch einmal Listing 2. Um die Übersichtlichkeit zu erhöhen, fängt es nur bei der Initialisierung einen Fehler ab. Übersetzt ist es schnell via:

Listing 2

Ein Fenster öffnen, Bild und Textur laden und Tastendrücke registrieren

01 #include <stdio.h>
02 #include "SDL2/SDL.h"
03
04 int main(int argc, char** argv){
05
06   // SDL initialisieren:
07   if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
08     printf("Fehler: %s \n", SDL_GetError());
09     return 1;
10   }
11
12   // Fenster öffnen:
13   SDL_Window *fenster = SDL_CreateWindow("Hallo Welt!", 250, 300, 640, 480, SDL_WINDOW_SHOWN);
14
15   // Renderer erstellen:
16   SDL_Renderer *renderer = SDL_CreateRenderer(fenster, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
17
18   // Zeichenfarbe auf Schwarz setzen und dann Fenster leeren:
19   SDL_SetRenderDrawColor(renderer, 235, 235, 235, 255);
20   SDL_RenderClear(renderer);
21
22   // Bild laden:
23   SDL_Surface *bild = SDL_LoadBMP("logo.bmp");
24
25   // Textur erzeugen und Surface löschen:
26   SDL_Texture *textur = SDL_CreateTextureFromSurface(renderer, bild);
27   SDL_FreeSurface(bild);
28
29   // Größe und Position des Bildes im Fenster festlegen:
30   SDL_Rect pos;
31   pos.x = 150;
32   pos.y = 100;
33   SDL_QueryTexture(textur, NULL, NULL, &pos.w, &pos.h);
34
35   // Textur in das Fenster kleben:
36   SDL_RenderCopy(renderer, textur, NULL, &pos);
37
38   // Anzeigen:
39   SDL_RenderPresent(renderer);
40
41   // Warte auf Tastendruck oder Mausklick:
42   SDL_Event ereignis;
43   int quit=1;
44   while(quit) {
45     SDL_WaitEvent(&ereignis);
46     switch(ereignis.type) {
47     case SDL_QUIT:
48       printf("Fenster geschlossen\n");
49       quit=0;
50       break;
51     case SDL_KEYDOWN:
52       printf("Tastendruck\n");
53       printf("Physische Taste %s als Taste %s gedrückt\n",
54              SDL_GetScancodeName(ereignis.key.keysym.scancode),
55              SDL_GetKeyName(ereignis.key.keysym.sym));
56       quit=0;
57       break;
58     case SDL_MOUSEBUTTONDOWN:
59       printf("Linke Maustaste gedrückt an\n");
60       printf("Position: (%d, %d)\n", ereignis.motion.x, ereignis.motion.y);
61       quit=0;
62       break;
63     }
64   }
65
66   SDL_DestroyTexture(textur);
67   SDL_DestroyRenderer(renderer);
68   SDL_DestroyWindow(fenster);
69   SDL_Quit();
70
71   return 0;
72 }
gcc -Wall -o hallowelt hallowelt.c -lSDL2

Die Anwendung aus Listing 2 demonstriert nur einen kleinen Teil der Möglichkeiten, die die SDL bietet. Eine komplette Beschreibung des Funktionsumfangs würde ein ganzes Buch füllen. Leider ist gerade die Dokumentation ein Stiefkind der Entwickler. So bietet das offizielle SDL-Wiki (Abbildung 6) derzeit nur eine unvollständige Funktionsreferenz [5]. Die Entwickler empfehlen daher, möglichst die Kommentare in den Headerdateien als Referenz zu nutzen.

Abbildung 6: Die SDL-Entwickler suchen derzeit händeringend nach Freiwilligen, die das Wiki aktualisieren.

Abbildung 6: Die SDL-Entwickler suchen derzeit händeringend nach Freiwilligen, die das Wiki aktualisieren.

Umsteiger von der alten Version 1.2 sollten zudem unbedingt den Migration Guide lesen [6]. Ein gut gemachtes Tutorial für C++-Entwickler findet sich nur auf Github [7]. Alle anderen Anleitungen im Internet bezogen sich zum Redaktionsschluss noch auf die alte SDL 1.2.

Fazit

Die SDL 2.0 vereinfacht das Programmieren plattformunabhängiger Multimedia-Anwendungen enorm. Listing 2 läuft unverändert auf allen unterstützten Systemen. Die neuen Funktionen, etwa die Unterstützung von mehreren Fenstern sowie die Grafikbeschleunigung, waren überfällig und machen Hacks aus der Vergangenheit überflüssig.

Wie der Begriff Simple im Namen andeutet, ist die SDL jedoch auch weiterhin eine Low-Level-Bibliothek. Sie soll primär den Hardwarezugriff auf mehreren Plattformen vereinfachen und vereinheitlichen. Selbst die einfachen Zeichenfunktionen für Rechtecke und Kreise haben die Entwickler erst nach (vielfachen) Anwenderwünschen in die neue Version aufgenommen. Wer schnell zu Ergebnissen kommen möchte oder Prototypen baut, muss daher auf Spiele- oder 3-D-Engines wie Py Game, Unity oder Ogre 3D ausweichen. Die Entwickler haben einige ursprünglich für SDL 2.0 geplante Funktionen auf spätere Versionen verschoben. Das API soll jedoch vorerst stabil bleiben, erst für die Version 2.1 sind hier wieder Änderungen im Gespräch.

Schwerer wiegt, dass die Version 2.0.0 noch ein paar kleinere Fehler aufweist [8]. Trotzdem kommt die SDL 2.0 bereits in einigen Programmen zum Einsatz und läuft dort stabil. Wer mit der SDL Anwendungen entwickeln möchte, sollte jetzt nicht mehr auf die alte SDL 1.2 setzen – ihrer Nachfolgerin gehört eindeutig die Zukunft.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 6 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben