Dumme Tutorials Teil 1: Mit dem GBA Schreiben:

[Die Möglichkeiten] [Eine Schrift, aber wie?] [Wie kommt die Schrift in den GBA?] [Schlusswort] |  |
Autor: | Tharo Herberg
Erstellt: | 18.Aug.02 bis 21.Aug.02
Level: | Profi
Kenntnisse: | GBA

Hallo GBA Opfer, ich habe mich nun einmal daran gemacht ein kleines Tutorial dahin zu kritzeln das auf eine grundlegende und verflucht nervige Frage beim GBA Programmieren ein geht. Wie kann ich mit dem GBA schreiben ??? Ein absoluter Alptraum. Wir können zwar programmieren und experimentieren doch wenn der Bildschirm dann auf einmal schwarz bleibt geht das große Rätzelraten los. Was ist falsch? Wo habe ich etwas nicht richtig berechnett, eine Klammer oder ein Vorzeichen vergessen? Jeder PC Programmierer würde nun einfach ein paar Testwerte auf den DOS-Screen bzw. in die Popup Fenster stopfen um besser nachvollziehen zu können wo sein kranker und mindertalentierter Geist den Fehler gemacht hat. Leider kann der GBA das von Hausaus nicht weshalb wir ihm das am einfachstem nun mal beibringen wollen. Um es klipp, klar und einfach zu sagen: Wir müssen im Prinzip alles von null an selber machen. Das ist ganz gut, so kann wenigstens niemand den Faden verlieren. Ich könnte euch natürlich auch einfach die Schreibfunktion fertig zu fressen geben und euch sagen wie ihr sie zu benutzen habt, doch das währe zu einfach und nicht sinn dieses Tutorials. Dieses Tutorial ist nun schon etwas älter. Den hier enthaltenen Source gibt es in dieser Form daher schon länger nicht mehr... Aber kein Grund zu klagen. Damit sich niemand beschweren kann findet ihr in dem beigefügten Download am Ende die neuste Version die ich dann damals bei meinem Betriebsystem auch benutzt habe.

Die Möglichkeiten eine Schrift zu realisieren

Kommen wir zur Sache. Wir haben verschiedene Möglichkeiten eine Schrift zu realisieren... Welche, das soll euch folgende Tabelle einmal näher vor Augen führen.
Methode | Vorteile | Nachteile
Mode 3 Bild | Mode 3 ist der einfachste Grafikmodus den es gibt, wir haben also die Buchstaben einfach nur über den Bildschirm zu schreiben. | Wir "brennen" die Buchstaben quasi in den Bildschirm ein. Dort bleiben sie bis wir sie manuell überschreiben und sie selbst überschreiben auch das bisherige Bild.
Mode 4/5 Bild | Siehe Mode 3. Durch doublebuffering bei Mode 4 haben wir die Möglichkeit den Text auf einen zweiten Bildschirm zu schreiben und per Tastendruck zur Debug Textausgabe um zu schalten. Extrem Vorteilhaft bei Spieleprojekten! | Die GBA CPU kann nur minimal 16 bit große Wörter schreiben. Da wir aber nur 8 Bit Farben haben und so jeden 2. Pixel überschreiben würden, ist es zwingend nötig zu tricksen, was in der Regel langsamer bis sehr viel langsamer ist.
Mode 0,1,2,3 | Jeder Buchstabe hat ein eigenes "tile" das nicht neu geladen oder gezeichnet werden muss. Durch das benutzen von "map's" (wie Levelkarten) kann man dadurch sogar Scroling oder einen Debugmodus wie bei Mode 4 realisieren. | Unsere Buchstaben sind alle konstant in ein und der selben Größe und Entfernung zu einander. Wer auch ein Spiel mit Tiles programmiert hat schlicht keinen Platz für zu viel Bonis (es sei denn er nutzt die Schrift im Spiel sowieso schon)
Sprites | Sprites können wir quasi immer und überall benutzen. Pro Buchstaben ein Sprite können wir schreiben wann immer und wo immer wir wollen. | Wir haben aber nur 128 Sprites und pro gezeichneten, nicht pro vorhandenem Buchstaben verbrauchen wir eines. Hyperextrem verschwenderisch.
Emulator Debug Modies | Diese Emulatoren Outputs können völlig Resourcen sparend und jederzeit benutzt werden. [1] | Funktioniert halt nur in den Emulatoren und jeweils nur pro Emulator anders. Für Spiele später also nicht geeignet.
Das ist ne Menge, hm? In diesem Tutorial beschränken wir uns jedoch darauf einfach, schlicht und ergreifend Mode 3 zu Programmieren. Ich denke das reicht schon allemal um das Prinzip zu begreifen.

Eine Schrift machen, aber wie?

Eine Schrift machen, aber wie? Es gibt schon einige Schriftformate für den GBA, meines Wissens sogar die ersten Tools. Da wir jedoch bei 0 beginnen wollen benutzen wir die einfachste Möglichkeit zur Realisierung die uns dann ermöglicht in einer beliebigen Textfarbe zu schreiben. Erwartet nun aber blos keine Animierte Farbenschrift wie etwa bei Mario Kart, solche Labels werden immer als feste Grafiken gespeichert. Manche bangen nun vielleicht schon darum ob wir wirklich jedes Pixel einzeln setzen werden und ich kann dazu nur sagen: OOOOOOoooooooooooooooohhhjaaaaaaaa ! Wir werden *wuahahar* Wie aber machen wir das? Schauen wir uns mal einen Buchstaben an, zum Beispiel das "H".
Wie schreiben wir nun das "H" ? Wir dangen oben links an und hören unten rechts auf, so simpel ist das. Das machen wir dann Reihe für Reihe, alle 8x8 Pixel, und dann steht unser "Bild", in diesem Fall halt der Buchstabe, auf dem Bildschirm. Pseudocode mäßig würde das also so aussehen:
0 | int start = (*c)*8;
1 | for(reihe=0;reihe<8;reihe++) {
2 | buffer=gbfont[start+reihe];
3 | for(spalte=0;spalte<8;spalte++) {
4 | if(buffer & 0x80) {
5 | videoRAM[(y+reihe)*240 + (x+spalte)] = FordergrundFarbe;
6 | }
7 | else {
8 | videoRAM[(y+reihe)*240 + (x+spalte)] = HintergrundFarbe;
9 | }
10 | }
11 | buffer <<= 1;
12 | }
Wie schon erwähnt gehen wir alle 8x8 Felder durch. start ist die Speicheradresse innerhalb des Schrift Arrays, auf das wir später noch zu sprechen kommen, wo unsere Zeile liegt. reihe und zeile ist jeweils der Zählwert wo wir mit dem Zeichnen sind. Forder und Hintergrundfarbe ist der Farbwert (16bit) den halt die jeweilige Farbe hat. Wer keine Hintergrundfarbe will kommentiert diese Zeile einfach aus. c ist der aktuelle char, der Aktuelle Buchstabe den wir schreiben wollen. videoRAM ist der Verweis auf unseren Bildschirm wie ihr ihn aus den anderen Tutorials schon kennt. buffer ist unser Zwischenspeicher für die aktuelle Zeile die wir bearbeiten, gbfont ist das Bild Array in dem unsere Buchstaben zerstückelt liegen. Wie sie da hinein kommen, dazu später mehr. Zum Schluss schieben wir den Buffer um eine Stelle, dadurch kommen wir schließlich von links nach rechts in unserem Datenfeld während die For Schleife ja dafür sorgt das wir von oben nach unten kommen. In der vorletzten Reihe schieben wir unseren Buffer im Speicher zur Seite, dadurch gehen wir immer eine Spalte weiter in unserer Schrift. Würden wir den Wert an dieser Stelle nicht Buffern sondern das original gbfont Array benutzen, dann würden wir die vorherige Zeile überschreiben und könnten demnach jeden Buchstaben nur einmal schreiben ^-^;

Wie kommt die Schrift in den GBA?

Jo toll, nun wisst ihr wie man ne Schrift anzeigt und wie sie im Prinzip aufgebaut ist, also können wir uns im Prinzip ja auch vorstellen wie so eine Schrift dann gespeichert wird, nämlich wie alles im GBA auf binärer Basis. Schauen wir uns die Darstellung des "H"'s noch einmal unter dieser Denkweise an.
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 00100100 d | 24 h
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 00100100 d | 24 h
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 00100100 d | 24 h
0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 00111100 d | 3C h
0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 00111100 d | 3C h
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 00100100 d | 24 h
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 00100100 d | 24 h
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 00100100 d | 24 h
Hehe, ich konnte es nicht lassen auch gleich noch den Hexwert dazu zu schreiben. In der Tat, im Quelltext werden wir jede Zeile jedes Buchstabens im Hexcode auf diese Art angegeben was dann etwa so aussieht:
0 | static const unsigned char gbfont[2048] = {
1 | /* 000 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
2 | /* 001 */ 0x38, 0x44, 0xAA, 0x82, 0xBA, 0x92, 0x44, 0x38,
3 | /* 002 */ 0x38, 0x7C, 0xD6, 0xFE, 0xC6, 0xEE, 0x7C, 0x38,
4 | /* 003 */ 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, ...
Glücklicherweise hab ich im Internet eine kleine (bescheiden aussehende) aber auch funktionierende Schriftart gefunden die man dazu benutzen kann so das wir das nicht selbst alles eintippen müssen. Hier ist nun die vollständige "drawString" Funktion wie er sie jederzeit benutzen könnt, z.B. in Dovotos Tutorials die hier ja eh alle schon auswendig kennen dürften bzw. sollten. Der einzige Unterschied zu vorhin ist das wir nun nicht nur einen Buchstaben sondern ganze Strings schreiben. Wundert euch nicht das ich dort sämtliche Konstanten wie zum Beispiel den Anfang des VRAM's in der Funktion neu definiere. Dies mach ich aus dem Grund das die Funktion dadurch vollständig unabhängig ist von den Eigenheiten des jeweiligen Programmierers. Auch spätere Konflikte werden so geschickt vermieden.
0 | void draw_string(unsigned const char* c, int x, int y, unsigned short FColor, unsigned short BColor) {
1 | if (!c) return;
2 |
3 | u16* videoBuffer = (u16*)0x6000000;
4 |
5 | while (*c) {
6 | u8 bitbuffer;
7 |
8 | int x1, y1;
9 | int i = (*c) * 8;
10 |
11 | for (y1=0; y1 < 8; y1++) {
12 | bitbuffer = gbfont[i + y1];
13 | xv=0;
14 | for (x1=0; x1 < 8; x1++) {
15 | if (bitbuffer & 0x80) videoBuffer[(y+y1) *240 + (x+xv)] = FColor;
16 | else videoBuffer[(y+y1) *240 + (x+xv)] = BColor;
17 | }
18 | bitbuffer <<= 1;
19 | }
20 | c++;
21 | x+=8;
22 | }
23 | }
Soo, ich denke wenn man ein wenig nach denkt, z.B. wie man wohl am besten eine String durchläuft (Strichwort c++ im Code oben) und zuvor den text aufmerksam gelesen und verstanden hat, dann kann man das auch alles verstehen. Zum Schluss wir x immer mit 8 addiert. Wieso? Nun, sonst würden wir immer auf der selben Stelle schreiben ^^

Schlusswort

Ok. Schließlich kommt das Tutorial doch noch online. Ich weiß das es für die meisten von euch wahrscheinlich zu schwer und flüchtig geraten ist... Doch hoffe ich das es doch dem einem oder anderen etwas (vor allem Erfahrung) bringt und er dadurch seinen selbst gesetzten Zielen ein wenig näher kommmt. Kommen wir zu den Download. Er beinhaltet einen Beispielcode der einmal einen Satz ausgibt. Dies macht er unter Benutzung meiner "crapshell" die einst das Herz meines Betriebsystems war. Wer von euch auch in den Genuss der DOS Konsolen Ausgabe kommen will brauch dazu jedoch die Konsolenversion des Visual Boy Advances (SDL Version). Aber woher soll ich schon wissen wie das alles geht? Ich bin ja nur ein dummer Anfänger ;) Bis zum nächstem mal. Quellen: [1]: Visual Boy Advance SDL Downloads: Die Funktion und Beispielcode

DevGBA
www.robsite.de