Kleine Einführung in die Dreamcast-Programmierung mit SDL

Aus SEGA-DC.DE

An wen richtet sich diese Anleitung?

Diese Anleitung richtet sich an alle, die grundlegende Kenntnisse in der Programmierung mit C oder C++ haben und ihre Dreamcast-Entwicklungsumgebung bereits konfiguriert haben. Eure Kenntnisse müssen nicht überragend sein, es reicht völlig, wenn ihr wisst was Variablen, Klassen, Header, Zeiger und Funktionen sind. In dieser Anleitung lernt ihr, wie man mit Hilfe von SDL für die Dreamcast-Konsole programmiert.

Fangen wir mit ein paar Headerdateien an:

#include <kos.h>
#include <stdio.h>
#include <SDL.h>
#include <SDL_dreamcast.h>

kos.h ist der Standard-Header von KallistiOS, stdio.h ist eion Header aus der C-Standardbibliothek, SDL.h ist der Header der SDL-Bibliothek und SDL_dreamcast.h enthält Dreamcast-spezifische Teile von SDL. Das ganze ist also nichts wirklich neues.

SDL_Surface *screen = NULL;
SDL_Surface *bild= NULL;

Hier deklarieren wir 2 Objekte der Klasse SDL_Surface. SDL_Surface ist eine Klasse aus SDL und kann Bilder und Ähnliches enthalten. Die gesamte Anzeige des Bildschirms wird auch als ein Objekt gesehen. Auf dieser screen-Variable werdet ihr die Variable "bild" auch später "blitten" - sprich in die screen-Variable laden. Dazu aber später.

Hier erstellen wir eine Funktion, die für uns später eine Datei "hallo_welt.bmp" ausliest, in das aktuelle Anzeigeformat konvertiert und dann diese in das Objekt "bild" speichert.

SDL_Surface *bild_laden( const char* dateiname)  {
   
   SDL_Surface* BildGeladen = NULL;
   SDL_Surface* optimiertesBild = NULL;

   BildGeladen = SDL_LoadBMP( filename );
    
   if( BildGeladen != NULL ) {

       optimiertesBild = SDL_DisplayFormat( BildGeladen );
       

       SDL_FreeSurface( BildGeladen );
        
   }
    
   return optimiertesBild;
}


Diese Funktion gibt ein SDL_Surface zurück - was nötig ist, damit das ganze auch in die bild-Variable geladen werden kann. Die ersten zwei Variablen, die wir hier definieren sind nur ein Zwischenspeicher. Richtig interessant wird's erst hier: BildGeladen = SDL_LoadBMP( dateiname );. Hier wird in die weiter oben definierte Variable Bild mit Hilfe der Funktion SDL_LoadBMP ein Bild geladen. dateiname ist hierbei das Argument vom char-Typ, das der Funktion bild_laden am Anfang übergeben wird. SDL_LoadBMP lädt nur Bitmaps, andere Dateiformate können mit Hilfe einer weiteren Funktion aus einer weiteren Header-Datei der SDL-Bibliothek benutzt werden, allerdings werden wir in dieser kleinen Einführung vorerst nicht darauf zu sprechen kommen. In der nächsten if-Abfrage prüfen wir, ob in BildGeladen erfolgreich ein Bild gespeichert werden konnte. Falls ja wird mit Hilfe von SDL_DisplayFormat das Bild, das momentan in BildGeladen gespeichert ist, in das Format der aktuellen Anzeige umgewandelt und dann in optimiertesBild gespeichert. Sprich: Wenn das Bild ein 24bit-Bitmap ist und das Zielsystem auf 32bit-Auflösung läuft, dann erledigt diese Funktion die Umwandlungs-Arbeit für euch. Mit SDL_FreeSurface( BildGeladen ); löschen wir das alte Objekt, das nun nicht mehr gebraucht wird. Zu guter letzt geben wir das optimierte Objekt als Rückgabewert der Funktion bild_laden mit return optimiertesBild; zurück. Jetzt ist unsere Funktion einsatzbereit.

Jetzt kümmern wir uns mal um die Hauptunkfunktion:

int main(int narg,char**arg) {

  SDL_Init( SDL_INIT_EVERYTHING );
  screen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
  
  bild = bild_laden("/rd/hallo_welt.bmp");
  
  SDL_Rect offset;
  
   offset.x = 0;
   offset.y = 0;
   
   SDL_BlitSurface( bild, NULL, screen, &offset );
  
  SDL_Flip( screen );
}

Die main()-Funktion wird ganz normal wie auf dem PC aufgerufen. mit SDL_Init( SDL_INIT_EVERYTHING ); initialisieren wir die SDL-Bibliothek und mit screen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE ); setzten wir den Video-Modus. Die Argumente, die an die Funktion übergeben werden sind: Breite, Höhe, Bit und um das letzte Argument müsst ihr euch vorerst gar nicht kümmern.

Als nächstes rufen wir unsere oben definierte Funktion auf. SDL_Rect offset ist ein Rechteck, das wir brauchen, um festzulegen, ab welchen Koordinaten später das Bild angezeigt werden soll. Da das ganze ab dem oberen Bildschirmrand angezeigt werden soll, setzen wir die x- und y-Koordinaten auf 0. Mit SDL_BlitSurface( bild, NULL, screen, &offset ); "blitten" wir unser Objekt bild auf das Objekt screen.

SDLTut1.gif

screen beinhaltet also nun unser Objekt bild.

screen ist wie bereits oben gesagt, der gesamte Bildschirm. Das erste Argument von SDL_BlitSurface( bild, NULL, screen, &offset ); ist das Objekt, das in das andere Objekt kopiert bzw "geblittet" werden soll. Das zweite Argument würde angeben ob nur ein bestimmter Teil des im ersten Argument übergebenen Bildes kopiert werden soll. Da wir aber das gesamte Objekt kopieren möchten, nehmen wir hier NULL. Das dritte Objekt hier ist das Objekt, in das das erste Objekt kopiert werden soll. Das vierte Argument, vom Typ SDL_Rect, gibt an, an welcher Position das ganze dann angezeigt werden soll. Danach wäre das Objekt screen auch fertig. Doch dann müsst ihr mit SDL_Flip( screen ); noch den Bildschirm "aktualisieren". Dann ist euer Programm fertig und eure Dreamcast-Konsole zeigt ein schmuckes Bild aus der Datei hallo_welt.bmp an! Was ihr in diese Datei malt, bleibt letztendlich euch überlassen....

Dieses Programm wird sich leider auch nicht selbst beenden, dass heißt, wenn ihr genug von eurem Bild habt, dann müsst ihr eure Konsole mit einem Druck auf die Powertaste ausschalten.

Die Datei main.c, könnt ihr einfach erstellen, in dem ihr den Inhalt der mit "Code" markierten Beispiele einfach in eine Datei kopiert und diese dann main.c nennt.

Das Makefile, das ihr zum Kompilieren benötigt, ist hier:

TARGET = main

OPTFLAGS=-O3 -fomit-frame-pointer

KOS_CFLAGS+= -I$(KOS_BASE)/../kos-ports/include/SDL $(OPTFLAGS) 

all: $(TARGET).bin

include $(KOS_BASE)/Makefile.rules

.SRCS   =   main.c \

OBJS = $(.SRCS:.c=.o)

clean:
  rm -f $(OBJS) $(TARGET).elf $(TARGET).bin

$(TARGET).elf: $(OBJS)
  $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET).elf $(KOS_START) \
     $(OBJS) -lSDL_129 -lm $(OBJEXTRA) $(KOS_LIBS)

$(TARGET).bin: $(TARGET).elf
  $(KOS_OBJCOPY) -R .stack -O binary $(TARGET).elf $(TARGET).bin

run: $(TARGET).bin
  $(KOS_LOADER) $(TARGET).bin


Die Dateien "Makefile" und "main.c" müssen irgendwo in eurem Cygwin-Ordner sein. Öffnet einfach die Cygwin-Konsole, geht in den Ordner in dem ihr die beiden Dateien abgespeichert habt und gebt "make" ein. Kurz darauf dürftet ihr eine "main.elf"-Datei haben, eine ausführbare Dreamcast-Datei!