Montag, 8 Feb, 2010

Lektion 4

In dieser Lektion möchten wir ein paar mehr Grafiken auf den Bildschirm zaubern und dabei klären was eigentlich blitting ist.

Dazu schauen wir uns zuerst einmal an was wir seit der letzten Lektion haben. So sieht also aktuell unser Programm aus:

#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <string>
	
SDL_Surface *lade_bild( std::string bildpfad )
{
    //Nicht optimiertes Bild
    SDL_Surface* normal_img = NULL;
	
    //Optimiertes Bild
    SDL_Surface* opt_img = NULL;
    //Unoptimiertes Bild laden
    normal_img = IMG_Load( bildpfad.c_str() );
	
    //Optimiertes Bild erstellen
    opt_img = SDL_DisplayFormat( normal_img );
	
    //Unoptimiertes Bild freigeben
    SDL_FreeSurface( normal_img );
	
    //Farbschlüssel für die transparente Farbe im richigen Format erzeugen
    Uint32 colorkey = SDL_MapRGB( opt_img->format, 0xFF, 0, 0xFF );
	
    //Setze die Pixel der Farbe Rot 0, Grün 0xFF, Blau 0xFF auf Transparent
    SDL_SetColorKey( opt_img, SDL_SRCCOLORKEY, colorkey );
	
    return opt_img;
}
	
int main( int argc, char* args[] )
{
// Das Hallo Bild
SDL_Surface* hallo = NULL;
	
// Das Fenster in dem das Bild angezeigt werden soll
SDL_Surface* fenster = NULL;
	
//Initialisieren von SDL
SDL_Init( SDL_INIT_EVERYTHING );
	
//Fenster Konfigurieren
fenster = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
	
//Bild laden
hallo = lade_bild( "hallo.png" );
	
//Bild auf dem Fenster anzeigen
SDL_BlitSurface( hallo, NULL, fenster, NULL );
	
//Anzeige aktualisieren
SDL_Flip( fenster );
	
//Pause
SDL_Delay( 3000 );
	
//Bildspeicher freigeben
SDL_FreeSurface( hallo );
	
//SDL beenden
SDL_Quit();
	
return 0;
	
}

Was wir machen wollen ist eine Raumschschiffflotte in beliebiger Formation vor einen Weltraumhintergrund darzustellen, ca. so:

ziel.png

Um das zu bewerkstelligen, erstellen wir eine Funktion in der wir die SDL_BlitSurface() aufrufen. So können wir auf einfache weise ein Bild bliten. Aber was bedeutet eigentlich dieses blitten. Blitten heist ein Bild oder Bildteil in den Speicher zur Anzeige zu laden. Also wie bis her, unser Bild auf dem Fenster blitten. Wir haben also unser Bild auf das Fenster geschoben. Was jetzt neu hinzu kommt das wir die Position angeben an der ein Bild im Ziel angezeigt wird, in diesem Fall wird unsere Raumschiffe an einer bestimmten Position auf das Fenster geschoben.

blit.png

An der Stelle gibt es noch zu klären, wie das Koordinaten-System im SDL Funktioniert. Von Links nach Rechts verläuft zunehmend die X-Achse und von Oben nach unten die Y-Achse, also so:

koordinatensystem.png

Nun aber zu unserer Blittingfunktion. Diese hatte keinen Rückgabewert aber ein paar Parameter die sie übergeben bekommt. Die ersten beiden Parameter legen die Position fest, an der das Bild auf dem Ziel angezeigt werden soll. Parameter 3 enthält das Bild was auf eine Oberfläche geschoben werden soll und das vierte Argument enthält die Zieloberfläche auf der das Bild dargestellt werden soll. Die Positionsangabe speichern wir in einen SDL-Rechteck. Dieses enthält sowohl den x und y Offset und eine hohen und breiten Angabe für ein Rechteck. Das SDL-Rechteck benötigen wir dann für die Blitting-Funktion, da die nur ein SDL-Rect zur Positionsangabe akzeptiert

void blit_obj( int x, int y, SDL_Surface* quelle, SDL_Surface* ziel ) { 
    //Erzeugt ein temporäres Rechteck zur Positionierung der Quelle
    SDL_Rect offset; 
	
    //Übergibt die Position an das SDL-Rechteck
    offset.x = x; 
    offset.y = y;   

Als nächstes blitten wir unser Bild auf die Anzeigeoberfläche(um das verbleibende NULL kümmern wir uns in einer späteren Lektion):

    //Bild blitten
    SDL_BlitSurface( quelle, NULL, ziel, &offset ); 
} 

Jetzt kümmern wir uns um unsere Main Funktion. Als erstes deklarieren wir die SDL Oberflächen. Also einmal für das Fenster, einmal für den Hintergrund und einmal für das Raumschiff. An dieser Stelle merkt ihr schon das wir das Raumschiff nur einmal laden müssen und es dann 3 mal auf unterschiedliche Positionen blitten können.

int main( int argc, char* args[] )
{
    // Fenster
    SDL_Surface* fenster = NULL;
	
    //Hintergrund
    SDL_Surface* hintergrund = NULL;
	
    // Raumschiff
    SDL_Surface* raumschiff = NULL;

Dann initialisieren wir wieder SDL und setzen die Attribute für unser Fenster.

    //Initialisieren von SDL
    SDL_Init( SDL_INIT_EVERYTHING );
	
    //Fenster Konfigurieren
    fenster = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );

Nun laden wir unseren Hintergrund und unser Raumschiff:

    //Hintergrund laden
    hintergrund = lade_bild( "hintergrund.png" );
	
    //Raumschiff laden
    raumschiff = lade_bild( "raumschiff.png" );

So und jetzt blitten wir den Hintergrund und 3 mal das Raumschiff:

    //Hintergrund blitten
    blit_obj( 0,0, hintergrund, fenster );
	
    // Raumschiffe blitten
    blit_obj( 350,150, raumschiff, fenster );
    blit_obj( 250,250, raumschiff, fenster );
    blit_obj( 450,250, raumschiff, fenster );

Und nun Updaten wir das Fenster, warten ein paar Sekunden und räumen auf:

    //Anzeige aktualisieren
    SDL_Flip( fenster );
	
    //Pause
    SDL_Delay( 3000 );
	
    //Bildspeicher freigeben
    SDL_FreeSurface( hintergrund );
    SDL_FreeSurface( raumschiff );
	
    //SDL beenden
    SDL_Quit();
	
    return 0;
	
}

So und schon haben wir ein Raumschiffflotte =^=.