Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 16 SDL
  gp 16.1 Was ist und kann SDL?
  gp 16.2 SDL installieren
  gp 16.3 SDL-Anwendungen erstellen
  gp 16.4 SDL initialisieren und Videomodus einstellen
    gp 16.4.1 Programmbeispiel – SDL initialisieren und Videomodus einstellen
  gp 16.5 Direkt auf den Bildschirm zeichnen
    gp 16.5.1 Programmbeispiel – direkt auf den Bildschirm zeichnen
  gp 16.6 Bitmap laden und anzeigen
    gp 16.6.1 Programmbeispiel – Bitmap laden und anzeigen
  gp 16.7 Ein anderes Grafikformat laden und anzeigen
  gp 16.8 Der rechteckige Bildbereich von SDL
  gp 16.9 Farbenschlüssel, Transparenz und Alpha-Blending
    gp 16.9.1 Alpha-Blending
  gp 16.10 Animation
    gp 16.10.1 Programmbeispiel – Animation
  gp 16.11 Eingabe- und Ereignisverarbeitung
    gp 16.11.1 SDL-Event-Struktur
    gp 16.11.2 Maus-Events
    gp 16.11.3 Programmbeispiel – Maus-Event
    gp 16.11.4 Tastatur-Events
    gp 16.11.5 Programmbeispiel – Tastatur-Events
    gp 16.11.6 Joystick-Events
    gp 16.11.7 Programmbeispiel – Joystick-Events
    gp 16.11.8 Weitere Events
  gp 16.12 Audio
    gp 16.12.1 Programmbeispiel – Audio
  gp 16.13 Ausblick


Rheinwerk Computing

16.5 Direkt auf den Bildschirm zeichnen  downtop

Ein Hinweis gleich vorweg. Dieses Kapitel ist nur für denjenigen gedacht, der seine eigenen Funktionen (Bibliothek) zum Zeichnen von Linien, Kreisen oder Rechtecken erstellen will. Das Zeichnen eines Pixels stellt dabei immer die Grundlage für das Zeichnen anderer grafischer Primitiven da. Dies kann sich bezüglich der Performance positiv auswirken – doch es werden dabei ein wenig mehr geometrische Kenntnisse abverlangt. Wie dem auch sei, wer sich dafür interessiert, bekommt hiermit die Grundlagen zum Setzen eines Pixels. Alle anderen, die erst nur die SDL-Funktionen verwenden wollen, können dieses Kapitel überfliegen.


Hinweis   Für das Zeichnen von grafischen Primitiven wie Linien, Kreisen oder Polygonen können Sie die Bibliothek sdl_gfx verwenden. Diese Bibliothek stellt Ihnen Basiszeichenfunktionen, die alle auf das Zeichnen eines Pixels aufbauen, zur Verfügung. Um einen rechteckigen Bereich mit einer Farbe auszufüllen, wird der (Standard-)Bibliothek von SDL die Funktion SDL_FillRect() mitgeliefert.


Um ein Pixel zeichnen zu können, benötigen Sie wieder das Surface. In der Struktur SDL_Surface finden Sie eine Strukturvariable void *pixel. In dieser Variablen werden die Farbwerte der einzelnen Pixel gespeichert. Diese Strukturvariable benötigen Sie zum Manipulieren eines Pixels. Nun sind allerdings die Strukturvariablen alle mit dem Read-only-Attribut (nur zum Lesen) ausgestattet. Das Surface (einfach an eine Zeichen-Oberfläche denken), das sich ja im Grafikspeicher befindet und dessen Inhalt Sie auf dem Bildschirm wiedergegeben bekommen, muss jetzt verändert werden. Sie müssen somit direkt in den Grafikspeicher schreiben – was beim derzeitigen Stand Ihrer Kenntnisse unweigerlich zum Segmentation Fault führen würde. Der Grafikspeicher ist ein recht empfindlicher Teil der Hardware. Um das Schreiben zu realisieren, müssen Sie den Speicherbereich der Grafikkarte für andere Anwendungen sperren. Sperren können Sie das Surface mit folgender Funktion:

int SDL_LockSurface(SDL_Surface *surface);

Nachdem Sie die Sperre für das Surface gesetzt haben, haben Sie direkten Zugriff auf das Pixel. Zwischen dem Aufruf von SDL_LockSurface() und dem Aufheben der Sperre mit SDL_UnlockSurface() können Sie etwas in surface->pixel schreiben und auch wieder etwas daraus lesen, ohne dass es Probleme gibt. Da nicht alle Surfaces eine Sperre benötigen, können Sie das Makro SDL_MUSTLOCK(surface) verwenden, um zu überprüfen, ob eine Sperre nötig ist oder nicht. Gibt das Makro 0 zurück, können Sie auf dem Surface lesen und schreiben, wie es Ihnen in den Kram passt. Ansonsten müssen Sie das Surface sperren.


Hinweis   Ab Version 1.1.8 der SDL-Bibliothek wird das Sperren rekursiv ausgeführt. Das sollten Sie beachten, weil dies die Reihenfolge des Freigebens der Sperren beeinträchtigt (Stack!).


Bei Erfolg gibt die Funktion SDL_LockSurface() 0 und bei einem Fehler –1 zurück. Um die Sperre wieder aufzuheben, müssen Sie die Funktion SDL_UnlockSurface() verwenden.

void SDL_UnlockSurface(SDL_Surface *surface);

Ein Surface sollte so schnell wie möglich wieder freigegeben werden. Natürlich sollten Sie auch hier mit dem Makro SDL_MUSTLOCK() überprüfen, ob ein Sperren zuvor überhaupt nötig war, um nicht ein nicht gesperrtes Surface freizugeben.

Der Pixel alleine macht noch keinen Indian Summer auf Ihrem Bildschirm. Sie brauchen Farbinformationen. Farben werden hierbei nach dem üblichen RGB-Schema erstellt. Zum Glück stimmen hierbei die englischen Anfangsbuchstaben mit den deutschen überein – RGB für Rot, Grün, Blau. Aus diesen drei Farben können Sie je nach Mischung jede andere Farbe erzeugen. Der maximale Wert ist 255 und der kleinste 0. Geben Sie z. B. allen drei Werten den Wert 255, erzeugen Sie die Farbe Weiß. Bei Vergabe von 0 an alle drei Werte haben Sie Schwarz. Gelb würden Sie mit der Mischung (255, 255, 0) erreichen. Sie können anschließend gerne selbst damit experimentieren.


Hinweis   Natürlich können Sie bei der Angabe der Farben auch einen Hexwert (0x00 = 0 und 0xFF = 255) verwenden, wenn Sie damit besser vertraut sind.


Wenn Sie jetzt der Funktion die Farbwerte für Rot, Grün und Blau übergeben haben, müssen Sie daraus noch einen 32-Bit-Wert machen – was den internen Wert von SDL für RGB wiedergibt. Diesen Wert können Sie sich mit der Funktion SDL_MapRGB() zurückgeben lassen.

Uint32 SDL_MapRGB( SDL_PixelFormat *format, 
                   Uint8 r, Uint8 g, Uint8 b );

Der Parameter SDL_PixelFormat ist ein Mitglied der Struktur SDL_Surface und wird mit surface->format angesprochen. Die anderen drei Parameter sind die 8-Bit-RGB-Werte.

Wenn Sie jetzt den Wert der Strukturvariablen pixel an die Struktur SDL_Surface mit entsprechenden Informationen übergeben haben, fehlt noch eine Funktion, ohne die gar nichts auf dem Bildschirm passieren würde.

void  SDL_UpdateRect( SDL_Surface  *screen,  
                      Sint32  x,  Sint32 y, 
                      Sint32 w,  Sint32 h );

Damit geben Sie einen bestimmten Bereich des Surfaces an, der neu gezeichnet werden soll. Geben Sie für x, y, w und h den Wert 0 an, wird der komplette Bildschirm neu gezeichnet.


Hinweis   Wichtig ist es, dass Sie noch vor Verwendung der Funktion die Sperre für das Surface wieder freigeben.



Rheinwerk Computing

16.5.1 Programmbeispiel – direkt auf den Bildschirm zeichnetoptop

Das nun folgende Beispiel demonstriert Ihnen wieder die eben erwähnten Funktionen in der Praxis. Es wird ein 320 x 200 großes Surface mit 16 Bit Farbtiefe erstellt. Darin werden nach dem Zufallsprinzip 50000 einzelne Pixel gezeichnet. Anschließend beendet sich die Anwendung wieder.

/* sdl2.c */
#include <SDL/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd. h.>
/* Surface sperren */
static void Lock( SDL_Surface *screen ) {
  /* Muss gesperrt werden? */
  if (SDL_MUSTLOCK (screen)) {
    if (SDL_LockSurface (screen) < 0) {
      printf ("Konnte Surface nicht sperren: %s\n",
         SDL_GetError ());
      return;
    }
  }
}
/* Surface freigeben */
static void Unlock( SDL_Surface *screen ) {
  if (SDL_MUSTLOCK (screen)) {
    SDL_UnlockSurface (screen);
  }
}
/* Einen 32-Bit-RGB-Wert zurückgeben */
static Uint32 GetColor( SDL_Surface *screen,
                        Uint8 R, Uint8 G, Uint8 B ) {
  return SDL_MapRGB( screen->format, R, G, B );
}
/* Einen Pixel zeichnen */
static void DrawPixel (SDL_Surface * screen, int x, int y,
                       Uint8 R, Uint8 G, Uint8 B) {
  /* Surface sperren, falls nötig */
  Lock( screen );
  /* Farbtiefe des Surface ermitteln (in Byte) */
  switch (screen->format->BytesPerPixel) {
  case 1:     /* 1 Byte */
    {         /* Auflösung: 8 Bit */
      Uint8 *bufp;
      /* Position x, y des Pixels an bufp */
      bufp = (Uint8 *) screen->pixels + y * screen->pitch + x;
      /* Farbe des Pixels verändern */
      *bufp = GetColor( screen, R, G, B );
    }
    break;
  case 2:     /* 2 Bytes */
    {         /* Auflösung: 15 Bit oder 16 Bit */
      Uint16 *bufp;
      /* Position x, y des Pixels an bufp */
      bufp=(Uint16 *)screen->pixels + y * screen->pitch / 2 + x;
      /* Farbe des Pixels verändern */
      *bufp = GetColor( screen, R, G, B );
    }
    break;
  case 3:  /* 3 Bytes */
    {      /* 24-Bit-Modus, wird hier nicht verwendet */
      printf ( "Der 24-Bit-Modus wird in diesem Beispiel"
               " nicht unterstützt\n");
      exit (EXIT_FAILURE);
    }
    break;
  case 4:     /* 4 Byte */
    {         /* Auflösung: 32 Bit */
      Uint32 *bufp;
      /* Position x, y des Pixels an bufp */
      bufp=(Uint32 *)screen->pixels + y * screen->pitch / 4 + x;
      /* Farbe des Pixels verändern */
      *bufp = GetColor( screen, R, G, B );
    }
  default:
    printf ("Konnte die Farbtiefe nicht ermitteln!?!?\n");
    break;
  }
  /* Sperre wieder aufheben, falls nötig */
  Unlock( screen );
  /* Den Bereich, der verändert wurde, neu zeichnen */
  SDL_UpdateRect (screen, x, y, 1, 1);
}
int main (void) {
  SDL_Surface *screen;
  int i, points = 50000;
  /* SDLs Videosystem initialisieren und auf Fehler prüfen */
  if (SDL_Init (SDL_INIT_VIDEO) != 0) {
    printf ("Konnte SDL nicht initialisieren: %s\n",
       SDL_GetError ());
    return EXIT_FAILURE;
  }
  /* Wenn die Anwendung beendet wird,          */
  /* wird die Funktion SDL_Quit() ausgeführt   */
  atexit (SDL_Quit);
  /* Videomodus mit 640 x 480 Pixel, Hi-Color (16 Bit) */
  /* einrichten. Oberfläche (Surface) standardmäßig    */
  /* in den Hauptspeicher (SDL_SWSURFACE) legen       */
  screen = SDL_SetVideoMode (320, 200, 16, SDL_SWSURFACE);
  if (screen == NULL) {
    printf ("Videomodus konnte nicht eingerichtet werden: "
            " %s\n", SDL_GetError ());
    return EXIT_FAILURE;
  }
  for (i = 0; i < points; i++) {
    DrawPixel(screen, rand () % 320, rand () % 200, 0, 0, 255);
    DrawPixel(screen, rand () % 320, rand () % 200, 0, 255, 0);
    DrawPixel(screen, rand () % 320, rand () % 200, 255, 0, 0);
    DrawPixel(screen, rand () % 320, rand () % 200, 255,255,0);
  }
  /* 1000 ms warten ... */
  SDL_Delay (1000);  
  printf ("Erfolgreich beendet!\n");
  return EXIT_SUCCESS;
}

Das Programm bei der Ausführung:

$ gcc `sdl-config --libs` `sdl-config --cflags` -o sdl2 sdl2.c
$ ./sdl2

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 16.1    Zeichnen einzelner Pixel auf das Surface


Auch hier können Sie gerne nach Kenntnisstand herumexperimentieren. Sofern Sie die Algorithmen zum Implementieren von Grafikprimitiven kennen, steht Ihnen ja jetzt dank DrawPixel() nichts mehr im Wege.

 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern