Grafikkurs: "Picasso und all die an- dern..." (Teil 3) ----------------------------------------
Willkommen zum dritten Teil des Grafik- kurses. Nachdem wir ja nun die Sprites abgehandelt hätten, können wir uns die- sen Monat nun endlich an die oft begehr- te Programmierung der HIRES-Grafik ma- chen. Auch dies ist ein relativ komple- xes Thema, obwohl wir diesmal nicht all- zu vielen in Registern "herumpoken" müs- sen, als bei den Sprites. Das kompli- zierte hierbei ist mal wieder der Aufbau einer HIRES-Grafik, doch das sollte nun auch kein Problem mehr für Sie sein. Außerdem werden Sie auch noch ein anständiges Stück vom Binärsystem benö- tigen, beziehungsweise Sie sollten mitt- lerweile vielleicht etwas geübter in der Benutzung der logischen Operatoren von BASIC sein, das hatten wir ja aber auch schon, und somit kann ja nichts mehr schief gehen... Klären wir doch zunächst einmal, was "HIRES" überhaupt bedeutet. HIRES ist schlichtweg die Abkürzung für "HIgh RE- Solution" und das heißt nichts anderes als "hohe Auflösung". Sie haben also bei einer HIRES-Grafik eine hohe Auflösung zur Verfügung - genauer gesagt erstreckt sich diese auf eine Ausdehnung von 320x200 Punkten, oder Pixels, wie man sie auch oft nennt. Dieses Feld von Punkten wird vom Bildschirmrand einge- rahmt. Das heißt also, daß wir mit Hilfe des HIRES-Modus des C64 jeden einzelnen Punkt auf dem Bildschirm seperat ans- teuern können. Doch wie geht das nun vor sich? Zunächst einmal sollte ich vielleicht erwähnen, daß eine solche Grafik, wie die Sprites auch, natürlich Speicherplatz benötigt. Und das in verhältnismäßig gewaltigem Maße! Wie Sie sich bestimmt denken repräsentiert ein Grafikpunkt hier natürlich auch ein Bit im Speicher des 64ers, das hatten wir ja bei den Sprites ja auch scon, nun können Sie sich das ja mal ausrechnen. Wir haben da 320*200=64000 Pixel, das ganze dividie- ren wir durch 8, weil ja ein Byte 8 Bit hat, und so kommen wir auf 8000 Bytes pro Grafik! Das macht schon ein Achtel des Gesamtspeichers des 64ers aus - Sie sehen, die hohe Auflösung hat ihren Preis. Doch da gibt es noch ein riesengroßes Problem für uns. Für die paar kleinen Sprites aus den letzten beiden Kurstei- len haben wir ja noch Speicherplatz ge- funden, aber 8000 Bytes sind nicht mehr so einfach dazischenzumogeln. Der ganze Speicher des 64ers ist ja schon komplett für andere spezifische Aufgaben reser- viert. Woher also nehmen, wenn nicht stehlen? Genau das werden wir jetzt aber tun müssen! Wir werden uns etwas Spei- cher von unserem 64er "klauen" müssen, sonst is nix drin mit HIRES. Und das geht folgendermaßen: Das Betriebssystem hat ganz am Anfang des Speichers eine ganze Menge Speicher- stellen für sich reserviert, in dem es sich einige Zwischenergebnisse und Hin- tergrundinformationen "merkt". Dort be- finden sich auch zwei kleine Speicher- zellen, die ihm die Startadresse des Basicspeichers angeben. In der Fachspra- che nennt man so etwas "Pointer", oder auch "Zeiger" (ähnlich wie die Sprite- zeiger bei Sprites). Nomalerweise liegt- der Basicspeicher, wie ich auch schon im fünften Teil des Basickurses erwähnte, ab Adresse 2048. Der Trick, den wir nun anwenden werden, ist schlichtweg der, daß wir dem Betriebssystem vorgaukeln, der Basicspeicher beginne weiter hinten, und schon können wir uns einen passenden Speicherbereich für unsere Grafik reser- vieren. Aber Vorsicht! Wie bei den Spri- tes auch können wir uns da nicht jeden X-beliebigen Speicherberech rausgreifen. Hiresgrafiken dürfen nämlich grundsätz- lich nur bei Speicherstellen beginnen, die durch 8192 teilbar sind (bei Sprites war der Teiler ja 64...). Demnach gibt es also insgesamt 8 Bereiche, die in Frage kämen, nämlich:
Nr. Von Bis ----------------
0 0 7999 1 8192 16191 2 16192 24191 3 24192 32191 4 32192 40191 5 40192 48191 6 48192 56191 7 56192 64191
Wir werden uns Bereich 1 wählen, aus 2 ganz bestimmten Gründen, die ich Ihnen jetzt noch näher erklären möchte. Be- reich 0 können wir ja vergessen, hier sind ja wieder vorreserviete Funktionen angelegt, die man tunlichst in Ruhe las- sen sollte. Soviel hierzu. Jetzt zu den Bereichen 2 bis 7. Diese sind ja eigent- lich auch alle in reservierten Berei- chen, aber es wäre auch hier denkbar (über viele Tricks) sie "bebaubar" zu machen. Das ist sogar sehr gut möglich und wird auch von sehr vielen Programmen eifrig praktiziert. Doch damit das ein- facher geht, ist es meist sinnvoller das Ganze in Assembler zu versuchen (zu die- sem Zweck können Sie ja einmal in den Assemblerkurs reinschauen, der seit Ja- nuar parallel zu meinem hier läuft - eine echte Gelegenheit für Basicprofis noch tiefer in die Materie einzustei- gen), und dann gibt es da auch noch ein internes Problem, das mit dem VIC zu tun hat, was jedoch zuviel wäre jetzt hier erwähnt zu werden. Bereich 1 ist einfach am Besten, da pflegeleicht und für uns leicht erreich- bar. Also dann wollen wir einmal den Basic- speicheranfang etwas höher setzen. Die beiden Speicherstellen die ich eben erwähnte belegen die Adressen 43 und 44. Der 64er hat ja insgesamt 65535 Spei- cherstellen, was der 16-Bit-Zahl "1111111111111111" (16 mal "Bit ge- setzt") entspricht. Um eine Adresse in- nerhalb des Speichers für den Computer darstellen zu können, brauchen wir also immer 16 Bit, gleich 2 Byte. So auch bei der Adresse des Basicanfangs (daher auch 2 Speicherstellen!). Die beiden Bytes, die wir benötigen, teilen sich auf in ein sogenanntes "niederwertiges-" oder "LOW-Byte" und in ein "höherwertiges" oder auch "HIGH-Byte". In Adresse 43 ist nun das LOW- und in Adresse 44 das HIGH-Byte des Basicanfangs gespeichert. Lesen wir doch einfach einmal diese bei- den Bytes aus, also:
PRINT PEEK(43),PEEK(44)
Auf dem Bildschirm sollten jetzt die beiden Zahlen: 1 8 stehen. 1 wäre also dann der Wert des LOW-Bytes und 8 der des HIGH-Bytes. Set- zen wir uns also unsere 16-Bit-Zahl aus diesen beiden Bytes zusammen. Das höher- wertige Byte kommt beim Schreiben der Binärzahl nach "oben" also nach links, das niederwertige nach "untern" bezie- hungsweise nach rechts:
--> 00001000 00000001 =8(HIGH) =1(LOW) --> in dezimaler Schreibweise: 2↑11+2↑1=2049
Huch, das ist ja 2049 und nicht 2048, wo ja eigentlich der Basicspeicher norma- lerweise beginnen sollte! Doch keine Angst, es stimmt schon so, denn das Be- triebssystem möchte mämlich hier die "wahre" Anfangsadresse des Basicspei- chers plus 1 stehen haben. Das 0. Byte dieses Bereichs wird noch zu einem ande- ren Zweck benutzt, wie wir gleich noch sehen werden. Möchten wir also bei- spielsweise den Anfang des Basicspei- chers nach Adresse 20000 verschieben, so müßten wir hier die Adresse 20001 ange- ben! Ok? Zugegeben, das Prozedere, eine Adresse zuerst einmal als Binärzahl zu schrei- ben, um sie dann in zwei Bytewerte umzu- rechnen ist relativ umständlich, deshalb möchte ich Ihnen hier noch einen einfa- cherern Weg zeigen, wie ein solcher 2- Byte-Wert umgerechnet werden kann: Das erste Bit des höherwertigen Bytes hat ja in der 16-Bit-Schreibweise den Dezimalwert 2↑8=256, da es ja das 8. Bit der 16-Bit-Zahl ist (das Zweite 2↑9=512 etc.). Demnach wäre also die niedrigste Zahl, die (ausschließlich) mit dem HIGH-Byte dargestellt werden kann (das LOW-Byte hat also den Wert 0) die Zahl 256. Demnach genügt es schlichtweg, die absolute 8-Bit-Zahl des HIGH-Bytes mit dem Wert 256 zu multiplizieren. Der Wert des LOW-Bytes bleibt erhalten und wird einfach zu dem 256fachen Wert des HIGH- Bytes hinzuaddiert, also: --> HI*256+LO=absolute Adresse --> Oder in unserem Beispiel:
8*256+1=2048+1=2049
Genauso geht es auch umgekehrt. Um das HIGH-Byte eines absoluten Wertes zu er- mitteln dividieren wir diesen durch 256 und nehmen den ganzzahligen Anteil des Ergebnisses als HIGH-Byte (also OHNE Nachkommastellen, falls die Division nicht aufgehen sollte). Das LOW-Byte wird nun ermittelt, indem wir das HIGH- Byte mit 256 multiplizieren und das Er- gebnis von dem absoluten (Anfangs-)Wert subtrahieren. Das hört sich vielleicht komplizierter an als es ist, der Ein- fachheit halber hier die Umrechnung als kleines BASIC-Programm:
10 INPUT"Absoluter Wert (max. 65535)";WE 20 HI=INT(WE/256) 30 LO=WE-256*HI 40 PRINT "LOW-Byte : "LO 50 PRINT "HIGH-Byte: "HI
Starten Sie doch einmal dieses Programm (auf der Vorderseite der MD unter dem Namen "LO-HI-UMRECHNUNG") und geben Sie einmal den Wert 2049 ein. Das Ergebnis ist, wie erwartet, eine 1 für das LOW- und eine 8 für das HIGH-Byte. Doch nun wollen wir endlich einmal den Speicher für unsere Grafik verschieben. Wir hatten uns ja darauf geeinigt, daß wir Bereich 1 hierfür beanspruchen wol- len, der sich ja von 8192 bis 16191 er- streckt. Lassen wir also den neuen Ba- sicspeicher bei Adresse 16192 beginnen. Sie sollten übrigens bedenken, daß bei einer Verschiebung der Anfangsadresse des Basicspeichers nach hinten, dieser natürlich an Länge verliert! Vorher er- streckte er sich ja von 2048 bis 40959, und wir hatten somit 38911 "BASIC BYTES FREE" (=40959-2048). Bei 16192 sind das jetzt nur noch 24767 Bytes (=40959- 16192)! Deshalb sollten wir auch kein Byte zuviel wegnehmen, wenn dies nicht unbedingt erforderlich ist! Bei 16192 soll nun also die neue Starta- dresse liegen. Zuerst müssen noch eine 1 hinzuaddieren, bevor wir die Zahl in HIGH- und LOW umrechnen können (Sie erinnern sich - in 43/44 muß die gewoll- te Adresse plus 1 stehen). Also:
16192+1=16193 HIGH=INT(16193/256)=63 LOW=16193-63*256=16193-16128=65
Das LOW-Byte hat also den Wert 65, das HIGH-Byte den Wert 63. Nun noch schnell etwas über das 0. Byte des Basicspei- chers (bei uns das Byte mit der Adresse 16192). Dieses dient quasi als "Kennmar- ke" für unseren 64er, daß hier der Ba- sicspeicher beginnt und muß deshalb IM- MER den Wert 0 enthalten, andernfalls erkennt BASIC nicht mehr die Befehle NEW, CLR und RUN als Basicbefehle an und bricht mit einem "SYNTAX ERROR" ab! Des- halb also immer auch eine 0 in das null- te Byte des neuen Basicanfangs schrei- ben, also:
POKE 16192,0 :REM 0.Byte POKE 43,65 :REM LOW-Byte POKE 44,63 :REM HIGH-Byte
Das wars. Der Basicanfang ist nun ver- schoben, und der Bereich von 2048 bis 16191 geschützt, er kann von nun an also nicht mehr von BASIC-Programmen über- schrieben werden. Öbrigens kann es sein, daß da hinten im Speicher noch irgenwo Datenmüll rumsteht, der ja eigentlich kein richtiges BASIC-Programm mehr repräsentiert. Gibt man LIST ein, so versucht der 64er doch noch was daraus zu machen, was natürlich in einem riesi- gen Chaos endet, deshalb sollten Sie auf alle Fälle den Basicspeicher noch zusätzlich initialisiern, indem Sie Ihn mit NEW löschen, also: NEW Jetzt können Sie Ihr HIRES-Basic- Programm schreiben. Achten Sie aller- dings bitte darauf, daß Sie dieses unbe- dingt mit einem ",8" abspeichern und vor allem laden und nicht etwa mit ",8,1", denn dann wird das Programm nämlich ab- solut geladen. Wenn Sie es also abge- speichert haben, als der Basicanfang noch bei 2048 lag, dann wird es auch dort hingeladen. Bei einem ",8" lädt der C64 es jedoch an den aktuellen Basic- speicheranfang, in unserem Fall also 16192! Im Öbrigen können Sie sich möglicherwei- se noch erinnern, daß ich bei den Spri- tes erwähnte, daß es da auch noch andere Möglichkeiten gibt, Speicherplatz für Sprites zu schaffen. Genau das was wir eben praktizierten meinte ich damit. Verschieben Sie sich einfach den Basic- speicher etwas nach vorne, um noch Platz für Sprites zu bekommen. Wenn Sie auch noch gleichzeitig eine Grafik benutzen, dann haben Sie sowieso den Speicher von 2048 bis 8192 frei, genügend also, für eine ganze Menge Sprites... Welche Register des VIC Sie jetzt ans- prechen müssen, um endlich mit dem Gra- fikbildschirm arbeiten zu können, werde ich Ihnen dann nächsten Monat erklären. Bis dahin "Gut Hack" und Servus.
(ub)