Neuer Treiber für die Grafikbibliothek
Realisierung der Low-Level-Funktionen
Die Einbindung der verschiedenen Ausgabegeräte wird über zwei Dateien realisiert:
- Eine Header-Datei, die im Hauptprogramm eingebunden wird und die Charakteristik der Ausgabegeräte, die Vereinbarung der globalen Variablen und die Prototypen enthält.
- Eine Datei, die den Programm-Code der Low-Level-Funktionen enthält und beim Übersetzen dazugelinkt wird.
Die Header-Datei
Der Name des Ausgabegerätes ist eine nützliche Information:
#define defDISPLAYNAME "ANSI-Console"Die Grafikbibliothek braucht natürlich die Maße des Ausgabegerätes in Punkten, damit die Clipping-Funktionen richtig arbeiten:
#define defDISPLAYWIDTH 80 #define defDISPLAYHEIGHT 24Die Anzahl der Farben ist für einige Befehle von Bedeutung und muß in der Header-Datei festgelegt werden:
#define defMAXCOLORS 8Die Farbtabelle ist nicht für jedes Display gleich, ferner haben diese oft eine unterschiedliche Anzahl darstellbarer Farben. Es muß also definiert werden, welche Farbe welcher darstellbaren Farbe zugeordnet wird. Bei einem S/W-Display könnten z.B. alle dunklen Farben (BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN und DARKGRAY) dem Wert 1 (Pixel gesetzt) zugeordnet werden, alle anderen dem Wert 0 (Pixel nicht gesetzt). Für ANSI (bei dem 8 Farben definiert sind), könnte die Zuordnungstabelle so aussehen:
const int BLACK=0; const int BLUE=1; const int GREEN=2; const int CYAN=3; const int RED=4; const int MAGENTA=5; const int BROWN=6; const int LIGHTGRAY=7; const int DARKGRAY=0; const int LIGHTBLUE=1; const int LIGHTGREEN=2; const int LIGHTCYAN=3; const int LIGHTRED=4; const int LIGHTMAGENTA=5; const int YELLOW=6; const int WHITE=7;Für das Linken ist es notwendig, daß einige Daten als Variablen gespeichert werden:
char *DISPLAYNAME=defDISPLAYNAME; const int DISPLAYWIDTH=defDISPLAYWIDTH; const int DISPLAYHEIGHT=defDISPLAYHEIGHT; const int MAXCOLORS=defMAXCOLORS;Die Grundstruktur der Grafikbibliothek sieht folgendermaßen aus und sollte nicht verändert werden:
unsigned char display[defDISPLAYWIDTH*defDISPLAYHEIGHT]; unsigned char rgb[defMAXCOLORS*3];Die Prototypendeklaration; da diese als Low-Level-Funktionen auch von den Funktionen der Grafikbibliothek aufgerufen werden, dürfen die Übergabeparameter nicht verändert werden:
void _setpixel(int x, int y); void _writearea(int left, int top, int right, int bottom); void _writedisplay(); void _initdisplay(); void _closedisplay();Die Low-Level-Funktionen
Natürlich müssen die für die Low-Level-Funktionen benötigten Header-Files eingebunden werden:
#include <stdio.h>Die Low-Level-Funktionen werden wahrscheinlich auch die Displaybreite und -höhe benötigen:
extern const int DISPLAYWIDTH; /* Anzahl der Zeilen */ extern const int DISPLAYHEIGHT; /* Anzahl der Spalten */ extern const int MAXCOLORS; /* Anzahl der Farben */Sofern Farben vorgegeben werden, müssen diese auch bekannt gemacht werden:
extern const int WHITE; extern const int BLACK;Das gleiche gilt für den Zwischenspeicher im RAM, dessen Inhalt auf das Display übertragen werden soll.
Soll ein Bildpunkt auf das Display übertragen werden, muß die Farbe des Bildpunktes bekannt sein. Der Zwischenspeicher enthält diese Information.
Da der Zwischenspeicher ein eindimensionales Feld ist, kann nicht, wie bei einem zweidimensionalen Feld, per display[x][y] zugegriffen werden. Die Zeilen des Displays sind in dem Feld hintereinander abgelegt, sodaß Sie den richtigen Farbwert folgendermaßen ermitteln können:
Farbwert = display[ y * DISPLAYWIDTH + x ];extern unsigned char display[]; /* Buffer im Speicher */Nun folgen die Funktionen.
_setpixel soll einen einzigen Punkt auf dem Ausgabegerät setzen.void _setpixel(int x,int y) { unsigned char color; color=display[y*DISPLAYWIDTH+x]; /* Farbe des Pixels ermitteln */ printf("\033[%i;%iH",y+1,x+1); /* richtige Position adressieren */ printf("\033[%im",color+40); /* Ausgabefarbe setzen */ printf(" "); /* und ausgeben... */ fflush(stdout); }_writedisplay kopiert den gesamten Inhalt des Zwischenspeichers zum Display.
void _writedisplay() { unsigned char color; int x,y; for(y=0;y<DISPLAYHEIGHT;y++) { printf("\033[%i;1H",y+1); /* an den Anfang der aktuellen Zeile gehen */ for(x=0;x<DISPLAYWIDTH;x++) { color=display[y*DISPLAYWIDTH+x]; /* Pixelfarbe ermitteln */ printf("\033[%im",color+40); /* Ausgabefarbe setzen */ printf(" "); /* und ausgeben... */ } } fflush(stdout); }_writearea entspricht _writedisplay, nur, daß nicht das gesamte Display kopiert werden soll, sondern nur ein Bildschirmausschnitt:
void _writearea(int left, int top, int right, int bottom) { unsigned char color; int x,y; for(y=top;y<=bottom;y++) { printf("\033[%i;%iH",y+1,x1+1); /* Position adressieren */ for(x=left;x<=right;x++) { color=display[y*DISPLAYWIDTH+x]; /* Pixelfarbe ermitteln */ printf("\033[%im",color+40); /* Ausgabefarbe setzen */ printf(" "); /* und ausgeben... */ } } fflush(stdout); }Mit der folgenden Funktion sollte das Display auf die Ausgabe vorbereitet werden:
void _initdisplay() { printf("\033c"); /* Reset */ printf("\033[0;%i;%im",30+BLACK,40+WHITE); /* Farbattribute setzen (schwarze Schrift auf weissem Grund) */ printf("\033[2J"); /* Bildschirm loeschen */ fflush(stdout); }Und schließlich eine Funktion, die das Ausgabegerät in den Grundzustand zurücksetzt bzw. schließt.
void _closedisplay() { printf("\033[0;%i;%im",30+WHITE,40+BLACK); /* Farbattribute setzen */ printf("\033[%i;1H",DISPLAYHEIGHT+1); /* An das Ende des Bildschirmes gehen */ printf("\033[K"); fflush(stdout); }www.mct.de