Malprogramm TT Paint 256, Teil 3

Diesmal geht's um die Programmierung der einzelnen Menüpunkte, Lade- und Speicherroutinen.

Da der Menüaufbau und die dafür notwendigen grafischen Primitive in den letzten Kursteilen eingehend beschrieben wurden, soll nun auf die Funktion und Programmierung der einzelnen Menüpunkte eingegangen werden. In dieser Folge werden die vier letzten Verwaltungsfunktionen Laden, Speichern, Pinselgröße, Sprühradius und die grundlegenden Zeichenfunktionen Linie, Rechteck, Ellipse, Polygon, Text und Spray in das System integriert. Der Einbau der neuen Funktionen gestaltet sich wie immer einfach. Die leeren Funktionshülsen sind durch die vollständigen Routinen zu ersetzen. Der Compiler wird auch jetzt noch einige Warnings ausgeben, die Sie aber ignorieren können.

Um dem Anwender die Möglichkeit zu geben, mühevoll gezeichnete Bilder dauerhaft zu archivieren, werden die Lade- und Speicherfunktionen als erstes integriert und beschrieben. Damit TTPaint-Bilder weiter verwendet werden können (z.B. Grafikkonverter, eigene Spiele, Slideshows, Hardcopyroutinen ... ), muß natürlich das spezifische TTPaint-Format bekannt sein.

Das File-Format, das TTPaint zur Verwaltung der Bilder verwendet, ist möglichst einfach gehalten und hat folgende Struktur:

1536 Byte Farbinformation + 153 600 Byte Bildinformation = 155 136 Byte Gesamtlänge.

Die Farbinformation setzt sich aus 256 Farbeinträgen zu je 6 Byte zusammen. Die 6 Byte pro Farbe sind zu 3 Words aufgeteilt, da GEM pro Grundfarbe (Rot, Grün, Blau) die Helligkeitsstufen von 0 bis 1000 verwendet. Die 1536 Byte Farbinformation haben somit folgende Gestalt:

Word Inhalt Farbindex
0 Rot 0
1 Grün 0
2 Blau 0
3 Rot 1
4 Grün 1
5 Blau 1 usw. ...
1533 Rot 255
1534 Grün 255
1535 Blau 255

Der TT und STE verwendet tatsächlich nur 16 Helligkeitswerte (4 Bit) einer Grundfarbe. Speichern der Farben mit jeweils 48 Bit (3 x 16 Bit) erscheint gegenüber den tatsächlich benötigten 12 Bit (3 x 4 Bit) zunächst maßlos übertrieben. Die Vorteile, die sich aus dieser Methode ergeben, überwiegen die Nachteile jedoch bei weitem. Übergibt man derart codierte Farben einer leistungsfähigeren Grafikhardware oder auch einem »normalen ST«, so werden die Farbinformationen von GEM automatisch bestmöglich an die vorhandene Hardware angepaßt. Eine Truecolor-Grafikkarte (24 Bit Farbinformation pro Pixel) würde beispielsweise die Helligkeitswerte von 0 bis 1000 auf 0 bis 255 anpassen, womit die Hardware optimal ausgenutzt wäre. Dies läßt den Verlust einigen Speicherplatzes leicht verschmerzen.

Den weitaus größeren Teil am Speicherbedarf eines Bildes nimmt jedoch die eigentliche Pixelinformation ein. Das Format entspricht exakt dem Aufbau des Bildschirmspeichers in der niedrigen TT-Auflösung. Der TT hat in TT-LOW eine Auflösung von 320 x 480 Punkten in 8 Ebenen. Anstatt wie etwa bei VGA-Karten je einem Pixel ein Byte zuzuordnen, ging man leider bei Atari kompliziertere Wege, was sich nur als Erbgut der alten ST-Bildschirmorganisation erklären läßt.

Will man zum Beispiel mit einer VGA-Karte im Standardmodus 0x13 (320 x 200 Punkte, 256 Farben) einen Punkt an (X/Y) in Farbe Color setzen, so geschieht das folgendermaßen: Bildspeicher [(Y<<8+Y<<6)+X] = Color, mit char Bildspeicher [64000] (wobei Bildspeicher an 0xa000:0000 beginnt) und char Color. Diese Bildschirmspeicherorganisation ist offensichtlich äußerst einfach zu programmieren und sehr schnell. Die Funktion BitBlt zum pixelgenauen Kopieren von rechteckigen Speicherbereichen für z.B. Animation wird geradezu trivial.

Doch nun zurück zur Grafikhardware des TT. Der Bildschirmspeicher ist linear angeordnet und umfaßt 153 600 Byte. Die 8 Bit Farbinformation eines Pixels sind auf 8 aufeinanderfolgende Byte (64 Bit) verteilt. Jedes Byte dieser 64 Bit ist als Bitplane aufzufassen, die 8 Pixel repräsentiert. Somit enthalten die gesamten 64 Bit die komplette Farbinformation von 8 Pixel. Um beispielsweise das Pixel in der linken, oberen Ecke des Bildschirms auf den Farbindex 115 zu setzen, müssen die ersten 8 Byte des Bildschirmspeichers folgendermaßen manipuliert werden: Die notwendige Bitakrobatik wird schnell einsichtig. Der neue TT-Shifter zieht über einen 64 Bit Hochgeschwindigkeitsbus diese 8 Byte in einem Zug. Für den GEM-Programmierer ist die Struktur der Hardware jedoch relativ unwichtig, da die Hardware über geeignete Treiber (VDI) angesprochen werden kann. Nachdem nun das Bildformat spezifiziert wurde, kann mit den Massenspeicheroperationen begonnen werden.

Laden von Bilddateien

Die Funktion Load_Pic benötigt keine Übergabeparameter, alle notwendigen Variablen werden lokal erzeugt. Zunächst werden alle verwendeten Strings gelöscht und der komplette Menübildschirm mit der Funktion Copy_Screen zwischengespeichert. Copy_Screen verlangt zwei Parameter, Quelladresse und Zieladresse, und kopiert 153 600 Byte von Quelle nach Ziel. Dies wird benötigt, da der AES-Fileselector den Bildschirm zerstört. Über die komfortable AES-Funktion fsel_exinput wird der Pfad zum Bild, der Bildname und der Status beim Verlassen der Selectorbox erfragt. Falls tatsächlich eine Datei geladen werden soll, wird aus Pfad und Name ein kompletter Dateiname erzeugt. Mit diesem Namen wird versucht, das entsprechende File über Fopen zu öffnen. Bei Erfolg liefert Fopen ein sog. FileHandle. Dieser Wert dient zur Verwaltung der I/O-Kanäle. Alle Dateizugriffe laufen zukünftig über diesen Wert. Wie oben beschrieben, befinden sich am Anfang der Bilddatei 1536 Byte Farbinformation, die als erstes in den Farbpuffer »Color_buf« geladen werden. Diese Aufgabe übernimmt die Funktion Fread, die anschließend auch zum Einladen der 153 600 Byte Bildinformation herangezogen wird. Zum Abschluß wird der geöffnete I/O-Kanal mit Fclose geschlossen und die Farbpalette mit den neuen Werten geladen. Das geladene Bild befindet sich wie erwünscht im Arbeitsblatt und kann dort weiterverarbeitet werden. Die Load_Pic-Routine bemerkt nicht, welche Art von Datei geladen werden soll. Sie »frißt« einfach alles, wobei nicht unbedingt sinnvolle Bildinformation entsteht (Bit-Salat).

Speichern von Bilddateien

Save_Pic entspricht, was die Auswahl des Dateinamens angeht, genau der Funktion Load_Pic. Der Unterschied liegt darin, daß mit Fcreate eine neue Datei angelegt, oder eine namensgleiche Datei zum Überschreiben freigegeben wird. Es werden nun die 1536 Byte Farbinformation, gefolgt von den 153600 Byte Bildinformation mit Fwrite gespeichert.

Set_LineWidth

In dieser Funktion wird über eine Alert-Box die Linienstärke eingestellt. Dazu wird eine Alert-Box mit drei Auswahlmöglichkeiten geöffnet. Abhängig von dem angeklickten Button liefert die Alert-Box einen Rückgabewert, der bei drei Knöpfen im Bereich von 1 - 3 liegt. Aus diesem Rückgabewert, von dem zunächst eins subtrahiert wird, werden geeignete Strichstärken berechnet, indem er mit einem entsprechendem Skalierungsfaktor (hier 2) multipliziert wird.

Set_Airbrush

Entsprechend der Funktion Set-LineWidth wird eine Alert-Box zur Ermittlung des gewünschten Sprühradius benutzt und ein geeigneter Radius zurückgegeben, der auf ähnliche Weise wie bei Set_LineWidth berechnet wird.

Free_Line

Zu Beginn werden die Pinselattribute gesetzt und in die Hauptschleife gesprungen, die nur mit der rechten Maustaste verlassen werden kann. Hier wird auf den linken Mausknopf gewartet, was der Auswahl des Startpunktes entspricht. Von diesem Startpunkt aus wird jetzt ein Rubberband zur aktuellen Mausposition gezogen. Dieser Effekt wird mittels des Schreibmodus XOR erzeugt. Wird die linke Maustaste losgelassen, wird die endgültige Linie ins Bild gezeichnet.

Free_Box

Free-Box entspricht weitgehend der Funktion Free_Line, nur wird hier anstelle der Linie ein Rechteck gezeichnet, dessen Diagonale mit der Maus gewählt werden kann. Über das Flag F_Toggle wird entschieden, ob das Rechteck gefüllt oder leer sein soll. Die Funktionsaufrufe vsf_perimeter (handle, !F_Toggle) und vsf_interior(handle, F_Toggle) gestatten das Umschalten zwischen gefüllt und ungefüllt, je nach Zustand von F-Toggle.

Free_Ellipse

Die Funktion Free_Ellipse folgt der gleichen Systematik, wie die beiden oben genannten Zeichenfunktionen. Der erste gesetzte Punkt wird der zukünftige Mittelpunkt der Ellipse. Aus der relativen Position des Mauszeigers zum Mittelpunkt werden die beiden Radien rx und ry berechnet. Dadurch ergibt sich die Ellipse.

Ob die Ellipse gefüllt oder ungefüllt dargestellt werden soll, wird durch die Variable F_Toggle gesteuert.

Free-Poly

Free_Poly dient zum Zeichnen von gefüllten und ungefüllten Polygonen. Neben dem Drücken der rechten Maustaste bedingt hier eine zu große Anzahl von Koordinaten den Ausstieg aus der Funktion. Der erste Punkt wird nach Betätigung der linken Maustaste im Parray abgelegt und wie bei Free_Line ein Rubberband erzeugt. Das Setzen eines weiteren Punktes bewirkt jedoch, daß das Rubberband nun das geschlossene Polygon repräsentiert. Es werden nun so lange Punkte hinzugefügt, bis die rechte Maustaste betätigt wird oder ein Punktüberlauf stattfindet. In beiden Fällen wird das Polygon nun endgültig in das Bild gezeichnet. Wird noch einmal die rechte Maustaste betätigt, erfolgt der Rücksprung zur Toolbox. Wird stattdessen die linke Maustaste gedrückt, kann ein weiteres Polygon konstruiert werden. Ob Polygone gefüllt oder ungefüllt dargestellt werden, entscheidet das Flag F_toggle.

Swap_Ft

In der kurzen Funktion Swap_Ft wird das Flag F_Toggle invertiert, d.h Leer - > Voll, Voll - > Leer und die entsprechenden Symbole in der Toolbox angepaßt.

Free_Text

Die Prozedur Free_Text besteht zum großen Teil aus einem einfachen Line-Editor. Der einzeilige Text kann wie gewohnt mit der Tastatur editiert werden. Mit der rechten Maustaste kann die Funktion verlassen werden. Mit kbhit wird überprüft, ob eine Taste betätigt wurde. War dies der Fall, wird der ASCII-Wert durch die Funktion getch erfragt. Wurde die Taste »BACKSPACE« gedrückt, wird, falls bereits ein »normaler« Buchstabe eingegeben wurde, der letzte Eintrag entfernt. Dies geschieht dadurch, daß der Textlängenzähler »Index« um eins dekrementiert wird. Der Text folgt jeder Mausbewegung. Mit der linken Maustaste wird er fest ins Bild geschrieben, der am Mauszeiger haftende String kann verändert werden.

Spray

Mit der Sprayfunktion wird eine Sprühdose simuliert, die so lange sprüht, wie die linke Maustaste gedrückt wird. Das Sprühen in einen runden Bereich wird durch einen einfachen Trick ermöglicht. Der Sprühradius, also die Größe des vom Sprühnebel abgedeckten Bereiches, wird in der globalen Variable Airadius festgelegt. Nun werden Zufallskoordinaten im Wertebereich des Durchmessers erzeugt. Diese Koordinaten werden nun durch Subtraktion des Radius auf den Mittelpunkt (Position des Mauszeigers) transformiert. Durch diese Vorgehensweise erhält man Koordinaten, die ein Quadrat um den Mittelpunkt abdecken, es ergäbe sich kein Sprühkreis sondern ein Sprühviereck. Die ungültigen Koordinaten, die außerhalb des Kreises liegen, der wiederum innerhalb des Quadrates liegt, werden durch den bekannten Satz von Pythagoras eliminiert: a2 + b2 = c2. Hierbei entspricht c dem Radius, a der x-Koordinate und b der y-Koordinate. c ist der maximal zulässige Radius. Alle Punkte, die größer als c sind, liegen außerhalb des Kreises und werden nicht gezeichnet. Durch schnellstmögliches Zeichnen der zulässigen Punkte wird nun das Sprühen simuliert. Die Eiform des Sprühnebels rührt aus dem ungünstigen »Aspectratio« der Auflösung 320 x 480 Punkte, dem Seitenverhältnis von X-Auflösung zu Y-Auflösung. Diese Asymmetrie ist jedoch einfach zu korrigieren. Mit diesen neuen Zeichenfunktionen kann bereits sehr gut gearbeitet, die volle 256-Farben-Pracht ausgenutzt werden. Die Default-Farbpalette bietet schon ein breites Experimentierfeld.

In der 4. Folge des Kurses werden die sehr wichtigen und komplexeren Funktionen zum Vergrößern und Füllen von Bildschirmbereichen sowie nötige Farbmanipulationen behandelt, doch schon jetzt kann man sagen: »Auf zur Documenta 9 nach Kassel!« (uw)

TT Paint Source 10/1992

Carsten und Hendrik Behrens/hu



Aus: ST-Magazin 10 / 1992, Seite

Links

Copyright-Bestimmungen: siehe Über diese Seite