VC 20-Kurs

Der gläserne VC 20 – Teil 5

In Folge 4 haben wir die Grundlagen für das Arbeiten mit selbstdefinierten Grafikzeichen besprochen. Diesmal werden wir sehen, welche Fähigkeiten der VIC in bezug auf Grafik sonst noch besitzt.

Beginnen wollen wir heute mit dem Bitmapping, also dem Arbeiten mit hochauflösender Grafik. Hochauflösend deshalb, weil die einzelnen Grafikpunkte sehr klein und das Gesamtbild dadurch sehr fein (eben hochauflösend) ist. Vorher aber noch eine Begriffserklärung: Bitmapping (engl. Map = Landkarte) bedeutet etwa soviel, wie den Bildschirm zu kartografieren, das heißt jede Bildschirmposition ist in hochauflösender Grafik über eine Koordinate erreichbar. Wer das Superexpander-Modul (VC 1211A) besitzt, der kann mittels einfacher Befehle wie PLOT, DRAW, CIRCLE etc. mit der Hires-(high resolution) Grafik arbeiten. Beim »nackten« VC 20 ist dies jedoch nicht so einfach möglich.

Das Bitmapping

Im Gegensatz zu anderen Computern unterstützt der VC 20 diese Art Grafik überhaupt nicht; man muß sich also eine Softwarelösung einfallen lassen.

Die einzige Möglichkeit, einzelne Grafikpunkte (auch Pixels genannt) — aus denen sich ja jedes Zeichen zusammensetzt — anzusprechen, haben wir in der letzten Folge kennengelernt. Ich spreche von der Möglichkeit, sich Zeichen selbst zu definieren.

Wollen wir also Bitmapping betreiben, so bleibt uns nichts anderes übrig, als den gesamten Bildschirm mit verschiedenen Sonderzeichen vollzuschreiben und diese dann umzudefinieren, so daß ein komplettes, neues Bild in Hires-Grafik entsteht.

Doch mit diesem Vorhaben stößt man bereits auf erste Schwierigkeiten, denn der VC 20 kann ja nur 256 verschiedene Zeichen auf einmal auf dem Bildschirm darstellen. Daher müßte man sich mit einer relativ kleinen Fläche für die hochauflösenden Pixels zufrieden geben.

Da die Anzahl der darstellbaren Zeichen (diese setzen sich — um dies noch einmal zu wiederholen — aus 8 x 8 Pixels zusammen) auf 256 beschränkt ist, muß man sich eine andere Lösung einfallen lassen. Diese ist aber — man wird es kaum glauben — bereits in den VIC eingebaut worden. Das sieht praktisch so aus: Man vergrößert die im Bildschirmspeicher abgelegten Zeichen von 8 x 8 auf 16 x 8 Pixels (bei gleicher Auflösung), wodurch sich gleichzeitig die zur Verfügung stehende Zeichenfläche erhöht. Diese Vergrößerung wird über ein bestimmtes Bit im VIC-Kontrollregister #3 eingestellt (vergleiche Folge 4, Tabelle 3). Ist Bit 0 dieser Speicherstelle auf 0, so bleibt alles wie es war, das heißt jedes Zeichen wird innerhalb einer 8 x 8-Matrix dargestellt.

Setzt man dieses Bit nun aber mit »POKE 36867, PEEK (36867) OR 1« auf 1, so sind alle Zeichen plötzlich doppelt so hoch. Ein Charakter wird nämlich innerhalb eines 16 x 8-Gitters abgebildet (Bild 1). Das ist nun alles schön und gut, einen Nachteil hat dieser Betriebszustand aber (wer es selbst ausprobiert hat wird es sicherlich schon bemerkt haben). Denn mit dem normalen Zeichensatz kommt auf dem Bildschirm keine vernünftige Zeichenfolge mehr zustande. So wird beispielsweise aus dem @ (Klammeraffe) das Zeichen

@
A

aus dem A das Zeichen

B
C

und so fort. Drückt man nun eine Taste, so wird nicht der entsprechende Buchstabe abgebildet, sondern irgendwelche anderen Zeichen, die, wie eben beschrieben, übereinander gestapelt sind.

Bild 1. Ein typisches 16 x 8 Bit Zeichen

Doppelt hohe Zeichendarstellung

Die Erklärung dafür ist im Prinzip ganz einfach. Wie wir das letzte Mal gesehen haben, errechnet sich der VIC die relative Adresse eines Charakters im Zeichengenerator (relativ deshalb, weil die Adreßangaben auf eine Anfangsadresse bezogen sind), indem er den Bildschirmcode (auch hier erinnern wir uns daran, daß der Bildschirmcode die Reihenfolge der Zeichen im Charaktergenerator ist) jeweils mit 8 multipliziert.

Durch die Umschaltung auf 16-zeilige Zeichen liest der VIC für einen Charakter 16 Zeilen aus dem ROM. Daher werden — da das Zeichengenerator-ROM auf achtzeilige Zeichen ausgelegt ist — eben die Informationen von ursprünglich zwei Zeichen in einem dargestellt. Folglich multipliziert der VIC bei der Adreßermittlung den Bildschirmcode nicht mehr mit 8, sondern mit 16.

Auf diese Weise erklärt sich auch der Zahlensalat in diesem Betriebsmodus. Diese Darstellungsart hat jedoch den erheblichen Vorteil, daß jetzt mehr Zeichen als normalerweise abgebildet werden können. Es sind nämlich bereits in 128 Zeichen die Informationen von ursprünglich 256 Zeichen enthalten. Bei dem 129. Zeichen (RVS ON und @) beginnt daher schon der zweite Zeichensatz des VC. Somit lassen sich diese zwei erstmalig gemeinsam auf dem Bildschirm ausdrucken. Statt bisher 256 »normaler« Zeichen läßt sich nun die gleiche Menge in doppelter Höhe (das entspricht also 512 regulären Zeichen) abbilden. Damit sind wir jetzt in der Lage, den gesamten Bildschirm füllen zu können. Darauf gehen wir aber später noch ausführlicher ein.

Das Naheliegendste wäre es ja nun, den Zeichengenerator ins RAM zu verlegen und dabei die Zeichen so umzubauen, daß man sie wieder richtig lesen kann. Dazu muß beim Kopieren jede Zeile verdoppelt werden; sonst bleibt ja alles beim Alten.

Das Programm in Listing 1 enthält zwei Zähler. Der eine zählt die ROM-, der andere die RAM-Speicherplätze, wobei letzterer genau doppelt so schnell läuft, denn eine ROM-Zeile soll ja zweimal hintereinander ins RAM geschrieben werden (dieses »Strecken« eines Zeichens ist in Bild 2 zu sehen). Da diese Schriftart natürlich besonders auffällig ist, eignet sie sich beispielsweise für Schaufensterwerbung oder ähnliches.

100 rem *******************************
110 rem ***                         ***
120 rem ***  doppelt hohe zeichen-  ***
130 rem ***  darstellung.           ***
140 rem ***                         ***
150 rem ***   a c h t u n g  ! !    ***
160 rem ***  bei 8 kbyte erweiter.  ***
170 rem ***    vor  dem laden       ***
180 rem ***   >> poke  44,32 <<     ***
190 rem ***     eingeben !!!!       ***
200 rem *******************************
210 poke55,0:poke56,24:clr
220 rem *** zeile 210 entfaellt bei
230 rem *** der 8 kbyte erweiterung.
240 aw=6144:ew=7147:g=14
250 rem *** bei 8 kbyte erweiterung
260 rem *** zeile 230 folgendermassen
270 rem *** aendern :
280 rem *** aw=5120:ew=8192:g=13
290 z1=32768
300 forz2=awtoewstep2
310 we=peek(z1)
320 pokez2,we:pokez2+1,we
330 z1=z1+1:next
340 poke36869,peek(36869)org
350 poke36865,21
360 poke36867,33
Listing 1. Doppelt hohe Zeichendarstellung
Bild 2. Durch die Verdoppelung (»Strecken«) eines normalen Zeichens, kann man auch doppelt hohe Zeichen darstellen

Wir wollen uns aber nun wieder unserem eigentlichen Thema — dem Bitmapping — zuwenden. Wie so oft stellt sich auch hier wieder die Frage nach dem Speicherplatz. Denn egal mit welcher Speicherausbauversion man gerade arbeitet, immer kommt es zu Kollisionen zwischen dem Zeichen- und dem Bildschirmspeicher. Daher müssen wir hier die Anzahl der verfügbaren Zeichen dementsprechend reduzieren. Wenn wir möglichst den ganzen Bildschirm füllen wollen, so muß es immer zu einem Kompromiß zwischen Bildschirmgröße und Speicherplatz kommen — logisch, denn je größer die verfügbare Hires-Fläche sein soll, um so mehr Speicherplatz benötigt man für die Sonderzeichen, über die das Bitmapping abgewickelt wird.

Ich glaube, mit 189 je 16 x 8 Bit-Zeichen einen solchen Kompromiß gefunden zu haben. Anhand von Listing 2, das in mehrere Teile gegliedert ist, möchte ich das Verfahren beim Bitmapping erklären. Programmteil 2 beschreibt den Bildschirm mit den veranschlagten 189 Zeichen. Vorher wird der Rahmen noch entsprechend der etwas »krummen« Zeichenzahl angepaßt. Denn da eben nicht der gesamte Bildschirm genutzt werden kann, wird der leere Rest einfach abgeschnitten, was durch Verkleinerung der Bildschirmfläche geschieht. Wenn man die Zeilen 240 — 260 aus dem Programm herausläßt, sieht man das ganz deutlich. In Teil 3 des Listings wird dann schließlich der gesamte Zeichengenerator von Adresse 5120 bis 8192 gelöscht, damit der Bildschirm auch wirklich restlos leer ist.

Damit sind alle Vorbereitungen getroffen, die wir vor dem eigentlichen Plotten durchführen müssen. Nun geht es darum, die eingegebenen Koordinaten aus den Variablen X und Y so umzuwandeln, daß die entsprechende Zeichenzeile im Charaktergenerator verändert werden kann. Als erstes verschaffen wir uns einen Überblick, wie die Zeichen auf dem Bildschirm angeordnet sind (Bild 3).

Bild 3. Durch das Beschreiben des Bildschirms mit 189 aufeinanderfolgenden Zeichen kann das Bitmapping realisiert werden

Durch die Verkleinerung der Fläche ergeben sich bei 189 verteilten Zeichen 21 Spalten und 9 Zeilen. Eine Spalte ist immer noch 8 Bit breit, denn sie rührt ja von der Zeichenbreite her. Daher ergibt sich durch Multiplikation eine Gesamtbreite von 168 Pixels. Analog verhält es sich mit der Zeilenzahl: 9 Zeilen à 16 Zeichenzeilen ergibt 144 als maximale Y-Koordinate. Übrigens hat das Koordinatensystem seinen Ursprung (X = 0/ Y=0) nicht — wie in der Mathematik — links unten, sondern links oben.

Die Koordinaten müssen aus programmtechnischen Gründen in zwei Teile aufgespalten werden; nämlich in den sogenannten Grob- (oder auch Zeichen-) anteil und in den Feinanteil (auch Pixelposition genannt).

Die Koordinatenumrechnung

Der Grobanteil ist nötig, damit zunächst einmal die Anfangsadresse eines Zeichens im Zeichengenerator festgestellt werden kann. Mit Hilfe des Feinanteils adressiert man dann die benötigte Zeichenzeile und in dieser dann die Pixelposition (aber dazu später mehr).

Anhand eines konkreten Beispiels wollen wir den zur Berechnung nötigen Algorithmus entwickeln: Der Punkt mit den Koordinaten X = 43 und Y= 106 soll auf dem Bildschirm gesetzt werden.

Nun wird als erstes festgestellt, in welchem Zeichen eine Änderung vorgenommen werden muß. Zu diesem Zweck wird die Koordinate in die besagten Grobanteile aufgespalten, was durch einfache Division geschieht. Die Spaltenkoordinate wird durch 8 (Zeichenbreite), der Zeilenanteil wird durch 16 (Zeilenhöhe) dividiert:

X: 43÷ 8=5Rest 3
Y:106÷16=6Rest10

Das Ergebnis ist jeweils der Grobanteil, der Rest ist dann automatisch die Pixelposition ( = Feinanteil). Der erste Teil dieser Rechnung wird in Listing 2 in den Zeilen 640 und 650 durchgeführt.

Danach wird die relative Position eines Zeichens im Charaktergenerator ermittelt. Die dafür nötigen »Formeln« haben wir ja bereits das letzte Mal besprochen:

Position = ZY x Zeichen pro Zeile + ZX

= 6 x 21 ÷ 5 = 131.

Das betreffende Zeichen hat also den Bildschirmcode 131. Da ein Charakter (nach der Umschaltung auf eine 16 x 8 Matrix) den Platzbedarf von 16 Byte hat, kann man auch ganz leicht die Anfangsadresse der ersten Zeichenzeile errechnen:

ADRESSE = Position x Platzbedarf + Basisadresse = 131 x 16 + 5120 = 7216

Dann ermitteln wir als nächstes über den Pixelanteil der Y-Koordinate die benötigte Zeichenzeile. In unserem Beispiel muß zur Zeichenadresse der Wert von PY — also 10 — dazuaddiert werden. Damit haben wir die endgültige Adresse der angewählten Zeichenzeile berechnet. Dies klingt alles viel komplizierter, als es in Wirklichkeit ist, denn alle drei Schritte können zu einem (Zeile 690) zusammengefaßt werden.

Damit sind wir schon fast am Ziel (das kann man hier sogar wörtlich nehmen) angelangt. Als letztes muß das durch die Pixel-X-Koordinate vorgegebene Bit in der Zeichenzeile gesetzt werden. Dies wird durch eine ODER-Verknüpfung des Wertes mit der Zeichenzeile erreicht.

Vorher ist aber noch eine letzte Hürde zu überwinden, die Koordinate ist nämlich nicht Byte-identisch. Was bedeutet das? Nun, unser Bildschirm entspricht beim Bitmapping ja auch einem Koordinatensystem. Denn über die horizontale (X-) und die vertikale (Y-) Koordinate läßt sich jeder beliebige Pixelpunkt durch ein Zahlenpaar (eben durch den X- und Y-Wert) eindeutig adressieren. Dabei hat der Punkt links oben die Koordinaten (0/0), der rechts unten die Koordinaten (167/143).

Für die X-Achse bedeutet dies, daß der Wert nach rechts ansteigt. Für die Fein-X-Koordinate gilt natürlich das Gleiche; sie kann von links nach rechts folgende Positionen annehmen: 0,1,2,3,4,5,6,7.

Hier liegt nun der springende Punkt. Position 0 entspricht nämlich Bit 7 in der Zeichenzeile, Position 1 Bit 6, die Position 2 Bit 5 und so fort. Diese Bits laufen also genau in entgegengesetzter Richtung. Folglich muß die Pixel-X-Koordinate dementsprechend »umgepolt« werden. Dies wird ganz einfach dadurch erreicht, indem man diesen Wert von der 7 subtrahiert:

Bitformat = 7 — (Pixel-X-Koordinate)

In unserem Beispiel ergibt sich: Bitposition= 7 — 3 = 4

Bit 4 soll nun in der Zeichenzeile gesetzt werden. Dies erreichen wir — wie bereits erwähnt — durch die ODER-Verknüpfung des Wertes mit dem Zeichenbyte. Wer den letzten Teil aufmerksam verfolgt hat, dem wird dies nicht schwerfallen. Da Bit 4 die Wertigkeit 16 (= 24) hat, wird die Zeichenzeile eben mit 16 ODER-verknüpft.

Wenn man alle drei Schritte zusammenfaßt, ergibt sich folgende Zeile: POKE AD, PEEK (AD) OR 2 ↑ (7-PX).

Damit ist der entsprechende Pixelpunkt gesetzt. Mit diesem letzten Teilstück haben wir nun endlich den kompletten Routinenteil beieinander, um ihn als Unterprogramm in Teil 4 von Listing 2 zu verwenden. Natürlich können mit Hilfe dieser Methode auch Punkte gelöscht oder abgefragt werden. Das Löschen wird mit Hilfe der AND-Operation bewerkstelligt. Das zu löschende Bit muß im Operanden auf Null, alle anderen, die unberührt bleiben sollen, auf eins gesetzt werden. Folgende Zeile löscht den adressierten Pixelpunkt: POKE AD, PEEK (AD) AND 255-2↑ (7-PX).

Die Abfrage von Punkten wird ebenfalls über die AND-Operation abgewickelt. Das gewünschte Bit wird im Operanden gesetzt und danach mit der Speicherstelle UND-verknüpft. Ist das adressierte Pixel gesetzt, so ist die IF-THEN-Bedingung erfüllt, ansonsten nicht: IF 2↑ (7-PX) = (PEEK(AD) AND 2↑ (7-PX)) THEN…

Natürlich sollte man anstelle des Ausdrucks 2↑ (7-PX) eine Variable definieren, damit das Programm kürzer und schneller wird.

Zeichnen auf dem Bildschirm — der Joypainter

Soweit also die Erklärung des Bitmapping beim VC 20. Um einmal zu zeigen, was man mit diesen Erkenntnissen anfangen kann, habe ich ein Joypainter-Programm in Maschinensprache entwickelt. Der Basic-Lader (Listing 3 und 4) transferiert das Programm aus den DATA-Zeilen automatisch in die Speicherbereiche ab $2000 und nur dort ist es lauffähig (Der Speicher muß also um mindestens 8 KByte erweitert sein). Beide Listings müssen nacheinander geladen und gestartet werden. Zunächst zur Bedienung der Routine, die mit »SYS 9682« gestartet wird.

Der Joystickpainter arbeitet — wie der Name bereits sagt — mit dem Joystick. Der kleine »Zeichencursor« kann mit dem Steuerknüppel in alle vier Himmelsrichtungen und in alle Diagonalen bewegt werden.

Es ist aber auch möglich, den Cursor über die Tasten E, S, D und X zu bewegen (ganz nach Belieben). Auch die Cursortasten können für die Steuerung herangezogen werden, über die Tastatur hat man allerdings nur vier Bewegungsrichtungen für den Zeichencursor zur Verfügung. Die Tasten verwendet man sinnvollerweise dann, wenn es darum geht, besonders exakt zu zeichnen. Aus diesem Grund kann man auch die Bewegungsgeschwindigkeit über die Funktionstasten F5 und F7 auf schnell beziehungsweise langsam stellen.

Gezeichnet wird mit den Funktionstasten F1 und F3. Die obere setzt einen Punkt (und rückt den Cursor um eins nach rechts), die andere löscht einen Punkt (diese Tasten haben eine Wiederholungsfunktion). Auch der Feuerknopf kann zum Zeichnen verwendet werden. Ein kurzer Druck bewirkt das Setzen, ein langer das Löschen eines Pixels. Über die CTRL-Taste können darüber hinaus noch andere Funktionen wie Dauerzeichnen oder Dauerlöschen angewählt werden. Tabelle 1 zeigt den kompletten Befehlsvorrat.

Taste Funktion
F1 Punkt setzen
F3 Punkt löschen
F5 Cursor auf schnelle Bewegung umschalten
F7 Cursor auf langsame Bewegung umschalten
E Steuertasten für den Zeichencursor
S
D
X
CTRL C Bildschirm löschen
CTRL F Farbe des Bildschirmes mit den Tasten + und — ändern. Mit RETURN beendet man die Farbeinstellung
CTRL L LOAD von Band oder Floppy
CTRL S SAVE von Band oder Floppy
CTRL F1 Zeichenmodus: Der Joystick (oder die Tasten) werden zu einem Zeichenstift, das heißt, bei jeder Bewegung wird ein Punkt gesetzt.
CTRL F3 Radiermodus: Joypainter wird auf Dauerlöschen umgeschaltet.
SHIFT »hebt« den Zeichenstift, beziehungsweise den Radiergummi. Solange man diese Taste drückt, kann man den Cursor bewegen, ohne daß das Bild verändert wird.
RUN/STOP Hebt den Zeichen- beziehungsweise Radiermodus ganz auf
Tabelle 1. Die Steuerfunktionen beim Joypainter-Programm

Natürlich fehlen diesem Programm — da es nicht allzu lang ist — einige Funktionen, die es noch komfortabler machen würden, wie beispielsweise die Verschiebung eines Zeichenblocks auf dem Bildschirm. Solch ein Programm würde aber samt Erklärung den Rahmen dieses Kurses sprengen.

Diejenigen, die einige Routinen wie das Bitmapping-Unterprogramm oder ähnliches in ihren eigenen Programmen verwenden möchten, finden in Tabelle 2 eine Auflistung der wichtigsten Programmteile.

Anfangsadresse Funktion
$2000 Cursortasten abfragen
$2047 Joystickabfrage
$2084 Startbild (64’er....)
$21B2 Grafik (Bitmapping) einschalten
$21DC Grafik löschen
$21F5 Koordinaten-Umrechnung
$225F Punkt setzen
$226B Punkt löschen
$2279 Punkt abfragen
$22D9 Feuerknopf Verarbeitung (kurzer Druck, langer Druck)
$233D Joypaintroutine
$2410 Kontrolltastenabfrage und -verarbeitung
$25D2 Startadresse
Tabelle 2. Die wichtigsten Unterroutinen im Joypainter-Programm

Das Unterprogramm zur Joystickabfrage wird übrigens in der nächsten Folge ausführlicher besprochen. Einen bedeutenden Nachteil hat die Hires-Grafik aber, sie ist nämlich ziemlich farblos. Warum ist dies so?

Da sich diese Grafikart aus den 8 x 8- (oder 16 x 8-) Basiszeichen zusammensetzt, kann man — wie es auch bei »normalen« Buchstaben und Grafikzeichen üblich ist — jeder Videospeicherposition über das Farb-RAM jeweils nur eine Farbe (von 0 bis 7) zuweisen.

Die Darstellung von verschiedenen Farben innerhalb eines Zeichens ist also nicht möglich. Für manche Zwecke benötigt man aber nun gerade mehrere Farben innerhalb einer Zeichenmatrix. In diesem Fall wird dann ganz einfach auf den Multicolormodus — den wir im folgenden genauer besprechen werden — umgeschaltet.

Buntes Alleriei: Multicolor

Ist innerhalb eines 8 x 8 Zeichengitters irgendwo ein Bit mit dem Wert 1, so wird die entsprechende Bildschirmzelle mit dem Farbwert, der in der zugehörigen Farbspeicherstelle steht, ausgefüllt. Befindet sich in dieser Pixelzelle der Binärwert 0, so wird diese in der Hintergrundfarbe auf dem Bildschirm abgebildet (sie ist also nicht zu sehen).

In einem normalen hochauflösenden Zeichen können also zwei verschiedene Farben dargestellt werden:

Wie Sie sehen, kann man die zwei Zustände auch als Farbcodes interpretieren. Ebenso verhält es sich im Multicolormodus: Hier werden nun zwei Bit in einer Zeichenzeile zusammengefaßt, die ebenfalls einen solchen Farbcode (allerdings für vier Farben) bilden. Ein Pixel ist in diesem Fall dann aber auch doppelt so breit wie normal, wodurch sich auch die Auflösung um die Hälfte reduziert. Bild 4 verdeutlicht den Unterschied zwischen diesen beiden Grafikarten. Diese vier möglichen Farbcodes sind auch hierbei wiederum nur die Zeiger auf Speicherstellen, in denen die eigentlichen Farbinformationen enthalten sind. Hier die möglichen Kombinationen:

00: Hintergrundfarbe
01: Rahmenfarbe
10: Zeichenfarbe
11: Hilfsfarbe
Bild 4. Das Hires-Zeichen »A« (4a) wird im Multicolormodus (4b) zu einem mehrfarbigen Gebilde. Der Vielfarb-modus eignet sich aber besonders für Spielfiguren (4c) oder ähnliches.

Die Werte 00 und 01, also Hintergrund- und Rahmenfarbe zeigen auf das VIC-Register # 15 (36879), in dem ja die Informationen über Rahmen- und Hintergrundfarbe abgelegt sind. Diese Farben sind also für alle Multicolorzeichen einheitlich vorgewählt. Auch der Code 11 — die Hilfsfarbe — wird einheitlich vorgewählt. Dieser Farbwert wird allerdings in einem Register gespeichert, das eigentlich mit Grafik überhaupt nichts zu tun hat, nämlich dem VIC-Register # 14 (36878), mit dem ja auch die Lautstärke festgelegt wird. Die Bits 0 bis 3 enthalten also den Lautstärkewert, die oberen vier Bit die Hilfsfarbe. Diese muß demnach speziell für Multicolor eingestellt werden, denn normalerweise ist diese Speicherstelle auf Null gesetzt (damit die Lautstärke ebenfalls null ist).

Schließlich ist noch Farbcode 10 zu erwähnen. Dieser wird für jedes Zeichen einzeln in der entsprechenden Farbspeicherstelle — wie wir es ja von den Hires-Zeichen her kennen — bestimmt. Die Bits 0 bis 2 speichern die gewünschte Farbe, Bit 3 hat eine besondere Funktion: Über dieses Bit wird — und das ist neu — der Grafikmodus ausgewählt. Ist es auf 0 (was ja der Normalfall ist), so stellt der Computer den in der dazugehörigen Videospeicherposition abgelegten Charakter im Zweifarbmodus (also in Hires-Grafik) dar. Setzt man das Bit 3 nun aber auf 1, so wird der Vierfarbmodus für dieses Zeichen eingeschaltet.

Folglich kann also die Darstellungsart für jedes Zeichen im Farb-RAM selektiert werden. Daher kann also sowohl der eine, als auch der andere Grafiktyp gleichzeitig auf dem Bildschirm abgebildet werden.

Probieren Sie es gleich einmal aus: die 1, also das Zeichen A, wird in die Bildschirmspeicherstelle 7680 (4096) gePOKEt. Danach ist in der entsprechenden Farbspeicherstelle der Colorwert mit POKE 38400,6 (beziehungsweise 37888,6) zu vermerken. In der linken oberen Ecke steht also nun ein blaues »A«. Als nächstes wird Bit 3 im Farb-RAM für diese Zeichen gesetzt: POKE 38400, PEEK (38400) OR 8.

Nun verschwimmen die Konturen des Charakters und ein farbiges Gebilde erscheint, das nur noch entfernt an den Buchstaben A erinnert. Nun, wie Sie schon bei den doppelt hohen Zeichen gesehen haben, ist das Zeichengenerator-ROM für eine bestimmte Betriebsart konzipiert. Natürlich werden die Zeichen deshalb in hochauflösender Grafik dargestellt, damit sie besser unterscheidbar sind. Da der Zeichengenerator wiederum nur für Hires-Zeichen konzipiert wurde, kann man in Multicolor nicht viel mit ihnen anfangen.

Wegen ihrer geringen Auflösung eignet sich diese Betriebsart sowieso nur für Spielfiguren oder ähnliche Zeichen. Dazu muß der Zeichengenerator wieder ins RAM verlegt werden, was ja durch eine Änderung im Register #5 geschieht. Dann können die Zeichen wie in Bild 4 programmiert werden. In Listing 5 ist eine solche Routine zu finden. Sie erzeugt ein kleines Multicolor-Männchen (der Klammeraffe @ wird entsprechend umdefiniert).

Soweit unser etwas ausgedehnter Exkurs in die Welt der VC 20-Grafik, mit dem ich diese Folge beschließen möchte. In der nächsten Folge unseres Kurses möchte ich noch einmal auf das Betriebssystem und dessen Routinen eingehen, denn auch hier tut sich dem Programmierer ein weites Betätigungsfeld auf.

(Christoph Sauer/ev)
100 rem *******************************
110 rem *** vc 20 bitmappingroutine ***
120 rem *** fuer speicher  >8 kbyte ***
130 rem ***                         ***
140 rem ***    a c h t u n g !      ***
150 rem ***    vor  dem  laden      ***
160 rem ***   >> poke  44,32 <<     ***
170 rem ***     eingeben !!!!       ***
180 rem *******************************
190 rem
200 rem
210 rem ---------- teil 1 -------------
220 rem
230 rem *** bildschirm einrichten
240 poke36864,13  : rem linker rand
250 poke36865,44  : rem oberer rand
260 poke36866,21  : rem 21 spalten
270 poke36867,19  : rem 18 zeilen (16*8)
280 poke36869,205 : rem zeichen ab 5120
290 rem
300 rem ---------- teil 2 -------------
310 rem
320 rem *** 189 zeichen in den bild-
330 rem *** schirmspeicher poken.
340 fort=0to188:poke4096+t,t
350 poke37888+t,6:next
360 rem
370 rem ---------- teil 3 -------------
380 rem
390 rem *** hiresscreen loeschen
400 fort=0to3024:poke5120+t,0:next
410 rem
420 rem ---------- teil 4 -------------
430 rem
440 rem
450 rem *** hier  wurde  als  demon-
460 rem *** strationsbeispiel   eine
470 rem *** sin-funktion eingesetzt.
480 forx=0to167
490 y=(sin(x*2*~/167)+1)*71.7
500 gosub 640
510 next
520 goto520
530 rem
540 rem ---------- teil 5 -------------
550 rem
560 rem ***    bitmappingroutine
570 rem ***    =================
580 rem *** die hochaufloesenden pixels
590 rem *** koennen  ueber  koordinaten
600 rem *** angesprochen werden.
610 rem *** die x-koordinate muss <168,
620 rem *** y muss  <144 sein.
630 rem
640 zx=int(x/8) : px=x-zx*8
650 zy=int(y/16): py=y-zy*16
660 rem *** die koordinaten  werden in
670 rem *** einen zeichen-  und  einen
680 rem *** pixelanteil aufgespalten.
690 ad=5120 +zx*16 +zy*336 +py
700 rem *** ad  ist  die zeilenadresse
710 rem *** eines  chatnrakters  im zei-
720 rem *** chengeneraror ram.
730 poke ad,peek (ad) or (2^ (7-px))
740 rem *** in dieser  zeile wird  das
750 rem *** gewuenschte pixel gesetzt.
760 return
Listing 2. Die Bitmapping-Routine
100 rem *** joypaint teil 1
110 rem >> vor dem laden <<
120 rem poke 44,39:poke9984,0
130 rem >> eingeben <<
140 fort=8192to9015:readd:s=s+d:poket,d:next
150 ifs<>92869thenprint"{clr}{down}{down}{down}fehler in datas !!":end
160 print"bitte teil 2 laden"
170 data 095,234,152,072,165,197,162,003
180 data 221,059,032,240,005,202,016,248
190 data 208,005,189,063,032,208,027,162
200 data 001,221,067,032,240,005,202,016
210 data 248,208,005,189,069,032,208,004
220 data 169,000,240,006,172,141,002,208
230 data 001,010,133,184,104,168,234,234
240 data 165,184,096,041,018,026,049,004
250 data 008,002,001,023,031,004,001,120
260 data 152,072,169,000,141,019,145,169
270 data 127,141,034,145,173,032,145,041
280 data 128,073,128,074,074,074,074,133
290 data 184,169,255,141,034,145,173,017
300 data 145,041,060,073,060,074,074,133
310 data 185,041,008,074,074,074,133,250
320 data 165,185,041,007,005,184,170,104
330 data 168,138,088,096,169,059,141,015
340 data 144,162,000,189,160,032,032,210
350 data 255,232,208,247,189,160,033,240
360 data 006,032,210,255,232,208,245,096
370 data 147,031,206,163,163,205,032,032
380 data 032,206,163,165,032,207,165,013
390 data 165,207,208,186,032,032,206,206
400 data 165,165,032,204,165,013,165,165
410 data 032,032,032,206,206,032,165,165
420 data 032,032,032,206,163,163,205,167
430 data 208,206,208,013,165,163,163,205
440 data 032,165,204,164,165,204,032,032
450 data 032,165,207,208,167,167,032,164
460 data 186,013,165,207,208,167,032,165
470 data 032,032,032,167,032,032,032,165
480 data 163,163,167,167,032,165,013,165
490 data 204,186,167,032,163,163,163,165
500 data 207,032,032,032,165,207,163,163
510 data 167,032,165,013,205,164,164,206
520 data 032,032,032,032,204,165,032,032
530 data 032,205,163,163,208,167,032,165
540 data 013,032,032,032,032,032,032,032
550 data 032,032,032,032,032,032,032,163
560 data 163,163,032,163,013,017,017,018
570 data 032,032,032,032,032,032,032,032
580 data 032,032,032,032,032,032,032,032
590 data 032,032,032,032,032,032,032,032
600 data 032,074,079,089,083,084,073,067
610 data 075,032,080,065,073,078,084,069
620 data 082,032,032,032,032,032,032,032
630 data 032,032,032,032,032,032,032,032
640 data 032,032,032,032,032,032,032,032
650 data 032,032,013,017,017,144,032,040
660 data 067,041,032,049,057,056,052,032
670 data 032,066,089,032,067,046,083,065
680 data 085,069,082,013,017,017,029,029
690 data 029,029,029,018,156,032,032,032
700 data 084,065,083,084,069,032,032,032
710 data 013,000,169,013,141,000,144,169
720 data 044,141,001,144,169,021,141,002
730 data 144,169,019,141,003,144,169,205
740 data 141,005,144,162,189,138,157,000
750 data 016,169,006,157,000,148,202,224
760 data 255,208,242,096,169,020,133,177
770 data 169,000,133,176,160,000,145,176
780 data 230,176,208,002,230,177,166,177
790 data 224,032,208,242,096,134,176,132
800 data 177,138,041,248,133,178,165,176
810 data 056,229,178,133,180,165,177,041
820 data 240,133,179,165,177,056,229,179
830 data 133,181,169,000,133,176,133,182
840 data 169,020,133,177,162,021,165,179
850 data 032,083,034,202,208,248,165,178
860 data 024,010,168,169,000,101,182,133
870 data 182,152,032,083,034,169,000,133
880 data 182,165,181,032,083,034,056,169
890 data 007,229,180,170,240,009,169,001
900 data 010,202,208,252,133,182,096,169
910 data 001,208,249,024,101,176,133,176
920 data 165,182,101,177,133,177,096,032
930 data 245,033,160,000,177,176,005,182
940 data 145,176,096,032,245,033,160,000
950 data 165,182,073,255,049,176,145,176
960 data 096,032,245,033,160,000,177,176
970 data 037,182,197,182,208,002,160,001
980 data 096,160,048,032,071,032,165,250
990 data 208,008,136,208,246,160,000,132
1000 data 069,096,169,240,141,012,144,160
1010 data 037,162,255,234,234,234,234,234
1020 data 202,208,248,136,208,243,160,255
1030 data 032,071,032,165,250,208,013,136
1040 data 208,246,160,001,132,069,169,000
1050 data 141,012,144,096,169,144,141,012
1060 data 144,160,032,162,255,234,234,202
1070 data 208,251,136,208,246,160,002,208
1080 data 227,169,015,141,014,144,032,137
1090 data 034,192,000,240,006,165,069,201
1100 data 002,240,001,096,169,000,141,014
1110 data 144,032,137,034,192,002,240,249
1120 data 160,002,132,069,208,237,165,197
1130 data 201,039,240,009,201,047,240,014
1140 data 160,000,132,069,096,169,240,032
1150 data 032,035,160,001,208,007,169,144
1160 data 032,032,035,160,002,132,069,096
1170 data 141,012,144,169,015,141,014,144
1180 data 160,037,162,255,234,234,202,208
1190 data 251,136,208,246,169,000,141,012
Listing 3. Basic-Lader »Joypaint« (Teil 1)
100 rem *** joypaint teil 2
110 rem >> vor dem laden <<
120 rem >> poke 44,39 eingeben <<
130 fort=9016to9825:readd:s=s+d:poket,d:next
140 ifs<>93663thenprint"{clr}{down}{down}{down}fehler in datas !!":end
150 sys9682
160 data 144,141,014,144,096,032,178,033
170 data 169,000,170,149,064,232,224,006
180 data 208,249,170,168,032,095,034,032
190 data 217,034,208,003,032,254,034,208
200 data 124,032,016,036,032,071,032,208
210 data 009,032,002,032,208,004,169,000
220 data 240,229,133,183,165,068,240,007
230 data 032,098,034,169,000,240,003,032
240 data 110,034,166,183,189,249,035,168
250 data 189,239,035,024,101,064,201,255
260 data 240,006,201,166,176,006,208,006
270 data 169,000,240,002,169,166,133,064
280 data 133,065,170,024,152,101,066,201
290 data 255,240,006,201,143,176,006,208
300 data 006,169,000,240,002,169,143,133
310 data 066,133,067,168,032,121,034,133
320 data 068,168,240,007,032,110,034,169
330 data 000,240,003,032,098,034,164,050
340 data 032,042,035,165,070,240,128,169
350 data 000,133,070,240,132,165,069,201
360 data 002,240,014,169,008,162,001,134
370 data 068,133,183,169,001,133,070,208
380 data 131,162,000,169,004,208,240,234
390 data 000,000,000,255,255,255,000,001
400 data 001,001,255,001,000,000,255,001
410 data 000,000,255,001,000,000,000,000
420 data 000,000,000,000,000,000,000,000
430 data 173,141,002,201,001,240,006,165
440 data 053,048,002,133,068,173,141,002
450 data 201,004,240,018,165,197,201,024
460 data 208,003,076,211,036,201,055,240
470 data 067,201,063,240,068,096,173,015
480 data 144,133,055,169,008,141,015,144
490 data 165,197,162,021,221,079,038,240
500 data 016,202,208,248,173,141,002,201
510 data 004,240,237,165,055,141,015,144
520 data 096,138,010,170,234,189,084,038
530 data 133,048,189,085,038,133,049,165
540 data 055,141,015,144,160,144,032,042
550 data 035,108,048,000,169,003,133,050
560 data 096,169,043,208,249,169,004,141
570 data 014,144,169,160,141,011,144,173
580 data 015,144,133,051,141,015,144,165
590 data 197,201,064,240,250,201,005,240
600 data 010,201,061,240,010,201,015,240
610 data 032,208,236,169,001,208,002,169
620 data 255,133,052,165,051,024,101,052
630 data 133,051,160,048,162,255,234,234
640 data 234,202,208,250,136,208,245,240
650 data 203,169,000,141,011,144,141,014
660 data 144,096,169,001,133,053,096,169
670 data 000,240,249,169,255,208,245,165
680 data 068,240,007,032,098,034,169,000
690 data 240,003,032,110,034,032,024,229
700 data 096,032,178,033,076,195,035,169
710 data 000,133,198,032,215,036,162,000
720 data 189,255,037,032,210,255,232,224
730 data 017,208,245,162,000,032,015,225
740 data 201,013,240,008,157,000,002,232
750 data 224,016,144,241,134,250,162,000
760 data 189,016,038,032,210,255,232,224
770 data 049,208,245,032,228,255,240,251
780 data 201,049,240,006,201,050,240,006
790 data 208,241,162,001,208,002,162,008
800 data 134,251,169,000,133,193,133,172
810 data 133,174,169,020,133,194,133,173
820 data 169,032,133,175,165,250,133,183
830 data 169,000,133,187,169,002,133,188
840 data 165,251,133,186,032,249,253,169
850 data 060,133,178,169,003,133,179,096
860 data 032,239,036,032,130,246,032,134
870 data 037,076,233,036,032,239,036,166
880 data 193,164,194,169,000,032,066,245
890 data 032,134,037,076,233,036,169,013
900 data 032,210,255,165,251,201,001,240
910 data 032,169,008,032,180,255,169,111
920 data 032,150,255,032,165,255,201,013
930 data 240,006,032,066,231,184,080,243
940 data 032,066,231,032,171,255,024,144
950 data 012,032,183,255,240,007,169,105
960 data 160,195,032,030,203,169,008,133
970 data 255,162,255,160,255,234,234,136
980 data 208,251,202,208,246,198,255,208
990 data 240,096,032,132,032,032,228,255
1000 data 201,000,240,249,169,027,141,015
1010 data 144,169,037,133,050,169,255,133
1020 data 053,165,254,201,210,240,003,032
1030 data 220,033,169,210,133,254,076,061
1040 data 035,234,234,234,234,234,234,234
1050 data 147,017,018,070,073,076,069,013
1060 data 018,078,065,077,069,058,146,032
1070 data 013,017,017,018,068,069,086,073
1080 data 067,069,058,146,032,049,046,032
1090 data 084,065,080,069,032,032,032,040
1100 data 049,041,013,032,032,032,032,032
1110 data 032,032,032,050,046,032,070,076
1120 data 079,080,080,089,032,040,056,041
1130 data 013,017,017,070,079,080,080,089
1140 data 032,069,082,082,079,082,058,032
1150 data 034,042,041,021,039,047,220,033
1160 data 125,036,104,037,116,037,202,036
1170 data 207,036
Listing 4. Basic-Lader »Joypaint« (Teil 2, Schluß)
100 rem ********************************
110 rem ***                          ***
120 rem ***  multicolor-figur  fuer  ***
130 rem ***  alle   ausbauversionen  ***
140 rem ***                          ***
150 rem ********************************
160 print"{clr}"
170 fort=0to7:readd:poke7168+t,d:next
180 pokepeek(648)*256+69,0
190 rem *** @ in bildschirmposition
200 poke 38469,10
210 rem *** bei 8 kbyte erweiterung
220 rem *** den poke durch 37957,10
230 poke36869,peek(36869)or15
240 rem *** zeichengenerator ins ram
250 goto250
260 data48,68,204,48,100,48,48,136
Listing 5. Ein Multicolor-Demo
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →