SDL-Tutorial #2 - Bitmaps


von Nicolai 'Prefect' Hähnle
angepasst auf diese Homepage von Ricco Clemens

 

Im letzten Kapitel haben wir SDL eingerichtet und ein erstes kleines Programm geschrieben. Dieses hat aber nur ein schwarzes Fenster gezeigt und sich dann bei Tastendruck beendet.

In diesem Kapitel werden wir ein Bitmap einladen und auf dem Bildschirm darstellen.

Glücklicherweise hat SDL eine Funktion, die .bmp-Dateien einlädt. Diese Funktion, SDL_LoadBMP() speichert das Bild der Datei dann in einer sogenannten Surface (zu deutsch: Oberfläche).
Eine Surface ist im Prinzip einfach nur ein rechteckiger Bereich, indem sich irgendwelche Grafiken befinden. Sie kann also das Bild aus einer .bmp-Datei enthalten. Genauso könnte sich in einer Surface aber auch ein automatisch vom Programm erzeugtes Muster befinden.
Selbst der Bildschirm, d.h. das, was der Spieler sehen kann, wird im Programm als Surface repräsentiert - diese Bildschirmsurface war schon im letzten Kapitel zu sehen, aber wir haben uns nicht weiter darum gekümmert.

So... jetzt wird es Zeit, das Programm vorzustellen:

#include <STDLIB.H>
#include <STDIO.H>

#include <SDL.H>

#ifdef _WIN32
#undef main
#endif
int main()
{
    SDL_Surface *screen, *bitmap;
    int running;

Wie Ihr seht brauchen wir einen zweiten Zeiger auf SDL_Surface, bitmap.

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "SDL konnte nicht initialisiert werden: %s\n",
            SDL_GetError());
        exit(1);
    }
    atexit(SDL_Quit);

     screen = SDL_SetVideoMode(640, 480, 0, 0);
    if (!screen) {
        fprintf(stderr, "Konnte Bildschirmmodus nicht setzen: %s\n",
            SDL_GetError());
        exit(1);
    }

An der Initialisierungssequenz hat sich nichts geändert.


    bitmap = SDL_LoadBMP("galaxien.bmp");
    if (!bitmap) {
        fprintf(stderr, "Bitmap konnte nicht geladen werden: %s\n",
            SDL_GetError());
        exit(1);
    }

Jetzt laden wir das Bitmap, 'galaxien.bmp'. Die Funktion SDL_LoadBMP() macht glücklicherweise alle Arbeit für uns. Bei Erfolg wird ein Zeiger auf die neue Surface zurückgegeben, bei Fehlern wird 0 zurückgegeben.
SDL_LoadBMP() kann alle unkomprimierten Windows BMP-Dateien laden. Komprimierte Bitmaps werden im Moment nicht unterstützt, und solange sich nicht einer von Euch dazu aufrafft, eine entsprechende Funktion zu schreiben, werden komprimierte Bitmaps wahrscheinlich auch nie unterstützt werden. Hier sieht man recht deutlich die Nachteile (faule Programmierer) und Vorteile (jeder kann Features hinzufügen) von Opensource ;)

Ihr solltet übrigens keine DOS-artigen Pfade, sondern Unix-artige Pfade im Zusammenhang mit SDL_LoadBMP() verwenden. Mit anderen Worten, verwendet: ‘SDL_LoadBMP("pics/dasbild.bmp");’ anstatt ‘SDL_LoadBMP("pics\\dasbild.bmp");’.


    SDL_BlitSurface(bitmap, 0, screen, 0);

Die Funktion SDL_BlitSurface() kopiert Bildausschnitte von einer Surface in eine andere. In unserem Fall wird als zweiter und vierter Parameter 0 übergeben, weil wir das ganze Bitmap kopieren wollen. Normalerweise übergibt man aber einen Zeiger auf zwei SDL_Rect, die die Position und Größe der zu kopierenden Bildausschnitte angeben (wir werden das erst im nächsten Kapitel machen).

SDL_BlitSurface() wandelt verschiedene Bildformate automatisch ineinander um, falls dies notwendig sein sollte. SDL_BlitSurface() kann Bildausschnitte allerdings nicht strecken oder stauchen.


    SDL_UpdateRect(screen, 0, 0, 0, 0);

SDL_UpdateRect() sorgt dafür, daß alle Änderungen, die wir an der Surface 'screen' vorgenommen haben, auch garantiert auf dem Bildschirm erscheinen. Die vier zusätzlichen Parameter geben an, welche Teile der Surface geändert wurden. Wir haben aber die komplette Surface geändert. Dies geben wir an, indem wir alle Parameter auf 0 setzen.

    running = 1;
    while(running) {
        SDL_Event event;

        while(SDL_PollEvent(&event)) {
            switch(event.type) {
            case SDL_KEYDOWN:
                running = 0;
                break;
            case SDL_QUIT:
                running = 0;
                break;
            }
        }
    }

    SDL_FreeSurface(bitmap);

  return 0;
}

An der Programmschleife hat sich nichts geändert. Wir müssen aber, bevor das Programm beendet wird, die Surface 'bitmap' löschen, da ansonsten nicht aller Speicher freigegeben wird. Die screen-Surface sollte man übrigens nicht löschen, da SDL dies automatisch tut.

Ein Hinweis für die MSVC++-Leute

Ihr könnt meine Projektdateien natürlich verwenden, andererseits enthalten sie womöglich absolute Pfadangaben, die mit Eurem System nicht übereinstimmen. Ich selbst habe die Tutorialdateien immer im Verzeichnis c:\develop\sdl-tut\tut2\ usw. SDL ist in c:\develop\sdl\sdl-1.2.2\ installiert.

Da MSVC++ die kompilierte .exe-Datei in einem Unterverzeichnis des Projektverzeichnisses speichert, empfiehlt es sich eigentlich, das Programm beim Testen aus dem eigentlichen Projektverzeichnis heraus zu starten. Ansonsten müßtet Ihr evtl. DLLs und Bitmaps immer in das Verzeichnis kopieren, in dem sich die .exe befindet.
Um das Startverzeichnis beim Debuggen von MSVC++ aus zu ändern geht Ihr ins Menü Projekt -> Einstellungen... und wählt Debug-Einstellungen. Dort gibt es ein entsprechendes Eingabefeld.

Dann war da noch

Der Quellcode zu diesem Tutorial sowie die Makefile und MSVC++-Projektdateien und das Beispielbild galaxien.bmp sind zum Download verfügbar (tar gzipped, 717kB; zipped, 717kB)

Das von mir verwendete Bild "galaxien.bmp" stammt übrigens vom Hubble Space Telescope, und kann über die Homepage der NASA heruntergeladen werden. Dort findet Ihr auch die Bestimmungen zur Nutzung des Bildes.

Dieses Tutorial ist Copyright (c) 2001 Nicolai 'Prefect' Hähnle.
Es darf zu nicht-kommerziellen Zwecken beliebig in ungekürzter und unmodifizierter Form vervielfältigt werden, sofern alle dazugehörigen Dateien, ebenfalls unmodifiziert, mitgeliefert werden.
Der mitgelieferte Sourcecode ist Public Domain.

Ihr könnt mich unter prefect_@gmx.net erreichen. Außerdem lese ich die Coding-Foren von http://www.thewall.de/ und hänge zuviel in #thewall.de auf irc.gamesnet.net rum...


 
Teil 1