Die BITMAP-Modes des VIC-II
Nach der Behandlung der Textmodes im letzten Beitrag VIC-II: Grafikmodes – Text, werfen wir nun mal einen Blick auf die Bitmap-Eigenschaften des C64. Es geht hier erstmal um die beiden standard Modi: Hi-Res und Multi-Color.
Wat is ne BITMAP? Da stelle mer uns janz dumm. Und da sage mer so…
Eine Bitmap erlaubt es uns, direkt jeden einzelnen Pixel der Anzeige anzusprechen. Wir können also jeden Punkt der 320*200 Pixel, die der C64 uns zur Verfügung stellt, direkt setzen oder löschen. Diese maximale Auflösung wird Hi-Res genannt und die schauen wir uns jetzt als Erstes an, dort werden wir uns auch die genaue Funktionsweise erarbeiten.
Hi-Res
Im Hi-Res-Modus haben wir Zugriff auf die höhste Auflösung des C64. Wie wir aus der Werbung und den Technischendaten wissen, beträgt diese 320*200 Punkte. Wenn wir nun den Speicherbedarf berechnen, dann kommen wir zunächst auf fast 8KB (320*200/8 = 8000 Byte) für die einzelnen Bildschirmpunkte. Da dies für C64-Verhältnisse schon eine Menge Platz ist, sollten wir uns als erstes um die Speicherbelegung kümmern.
Wie man die Speicheraufteilung vornimmt und den Hi-Res-Modus aktiviert, wurde bereits in VIC-II: Speicherbereiche festlegen erklärt, dieser Text wird nun vorausgesetzt!
Wir beginnen nun damit, unseren Speicherbereich festzulegen und den Bitmap-Modus (Hi-Res) zu aktivieren. Wir sind mal ganz mutig und verwenden weiterhin die VIC-Bank-0 (dies ist bekanntlich der Standard nach dem Einschalten). Unsere 8KB große Bitmap legen wir in die zweite Hälfte der 16KB-Bank, also in den Speicherbereich $2000 – $3fff. Die restlichen Einstellungen lassen wir unangetastet.
Hier nun das erste Progrämmchen…
;*** VIC-II Speicher-Konstanten VICBANKNO = 0 ;Nr. (0 - 3) der 16KB Bank | Standard: 0 VICSCREENBLOCKNO = 1 ;Nr. (0 -15) des 1KB-Blocks für den Textbildschirm | Standard: 1 VICCHARSETBLOCKNO = 2 ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz | Standard: 2 VICBITMAPBBLOCKNO = 1 ;Nr. (0 - 1) des 8KB-Blocks für die BITMAP-Grafik | Standard: 0 VICBASEADR = VICBANKNO*16384 ;Startadresse der gewählten VIC-Bank | Standard: $0000 VICCHARSETADR = VICBASEADR+VICCHARSETBLOCKNO*2048 ;Adresse des Zeichensatzes | Standard: $1000 ($d000) VICSCREENRAM = VICBASEADR+VICSCREENBLOCKNO*1024 ;Adresse des Bildschirmspeichers VICBITMAPADR = VICBASEADR+VICBITMAPBBLOCKNO * 8192 ;Adresse der BITMAP ;*** Startadresse *=$0801 ;** BASIC-Zeile: 2018 SYS 2062 !word main-2, 2018 !byte $9e !text " 2062" !byte $00,$00,$00 !zone main main ;*** Bitmap-Modus aktivieren lda $d011 ;VIC-II Register 17 in den Akku ora #%00100000 ;Bitmap-Modus sta $d011 ;aktivieren ;*** Start des Bitmapspeichers festlegen lda $d018 ;VIC-II Register 24 in den Akku holen and #%11110111 ;Mit Bit-3 ora #VICBITMAPBBLOCKNO*8 ;den Beginn des sta $d018 ;Bitmapspeichers festlegen rts ;zurück zum BASIC
Wie unter VIC-II: Die Register erwähnt, wird der Bitmap-Modus mit Bit-5 im Register 17 $d011 aktiviert, das machen wir auch direkt bei main. Danach legen wir dann natürlich noch den Bitmap-Speicher fest. Am Schluß geht es zurück zum BASIC.
Starten wir nun das Programm einmal.
Die Anzeige ist irgendwie enttäuschend. Das sieht doch eher nach einem Textmodus aus, oder? Eure Anzeige könnte übrigens ein anderes Muster aufweisen, es hängt davon ab, was im von uns gewählten Speicherbereich steht. Der Standard bei VICE sieht vor, dass der Speicher abwechselnd mit $00 und $ff gefüllt wird, es werden immer 64 Bytes am Stück mit den erwähnt Werten gefüllt.
Löschen wir zunächst mal den Bildschirm. Dazu müssen wir diesmal 8KB auf $00 setzen. Fügt eine neue Konstante ZP_HELPADR1 = $fb ;Hilfsadresse auf der Zero-Page zum Programm hinzu und vor dem rts rufen wir nun die Löschfunktion auf jsr clrHiResBitmap ;BITMAP löschen.
Diese Routine sieht dann so aus:
!zone clrHiResBitmap ;*** Die 8KB der Hi-Res BITMAP löschen clrHiResBitmap lda #<VICBITMAPADR ;auf die Zero-Page sta ZP_HELPADR1 lda #>VICBITMAPADR sta ZP_HELPADR1+1 ldx #32 ;Schleifenzähler 32 Pages (32 * 256 = 8192 = 8KB) ldy #0 ;Schleifenzähler für 256 BYTES je Page tya ;Akku auf 0 setzen .loop sta (ZP_HELPADR1),Y ;Akku 'ausgeben' dey ;Y verringern bne .loop ;solange größer 0 nochmal -> .loop inc ZP_HELPADR1+1 ;Adresse auf der Zeropage um eine Page erhöhen dex ;Pagezähler verringern bne .loop ;solange größer 0 nochmal -> .loop rts ;zurück zum Aufrufer
Als erstes legen wir die Startadresse der Bitmap auf der Zero-Page ab. Das X-Register dient als Schleifenzähler für die Pages (wie ihr wisst, hat eine Page 256 Bytes). Diese 256-Bytes zählen wir mit dem Y-Register. Dann legen wir eine 0 im Akku ab und schreiben diese 0 in die 8192 Bytes, die wir für die Bitmap benötigen, um diese zu löschen. Wie ihr oben gesehen habt, sind es eigentlich nur 8000 Bytes, aber aus Bequemlichkeit löschen wir immer eine komplette Page. Wurden alle Bytes auf 0 gesetzt, dann wird die Funktion wieder verlassen.
Ein weiterer Start führt zur obigen Anzeige. Das sieht schon besser aus, aber der Bildschirm ist noch nicht ganz sauber. Legen wir doch mal den Text des Bildschirmspeichers darüber.
OK, nun ist es offensichtlich, wir erkennen, dass auch der normale Bildschirmspeicher bei Bitmaps benötigt wird. Löschen wir diesen also auch noch. Bauen wir daher eine einfache Löschfunktion für den Bildschirmspeicher (der liegt hier ja an der Standardadresse $0400) und rufen diese Routine direkt hinter dem Label clrHiResBitmap auf.
!zone clrHiResColor ;*** Bildschirmspeicher löschen clrHiResColor ldx #0 ;Schleifenzähler 256 BYTES txa ;0 in den Akku .loop sta VICSCREENRAM,X ;1. Page des Bildschirmspeichers sta VICSCREENRAM+256,X ;2. Page sta VICSCREENRAM+512,X ;3. Page sta VICSCREENRAM+768,X ;4. Page dex ;Schleifenzähler verringern bne .loop ;solange nicht 0 nochmal -> .loop rts ;zurück zum Aufrufer
Außerdem habe ich das rts am Ende von main noch gegen eine Endlosschleife jmp * ;Endlosschleife getauscht, damit der Bildschirm wirklich sauber ist.
Da der Bildschirmspeicher auch zur Hi-Res-BITMAP zu gehören scheint, beträgt der Speicherbedarf also nicht 8000, sondern sogar 9000 Bytes! Ihr könnt euch (an Hand der obigen Bilder) bestimmt schon denken, wozu der Bildschirmspeicher dient, oder? Ändert doch mal die Löschfunktion clrHiResColor geringfügig und verschiebt das txa hinter das Label .loop.
Wie ihr seht, dient der Bildschirmspeicher dazu die Farben zu beeinflussen. Es wird im Bitmap-Modus also nicht das Farb-RAM ab $d800, sondern der Bildschirmspeicher verwendet! Da wir alle Pixel gelöscht haben, kann es sich hier also nur um die Hintergrundfarbe handeln. Dies ist in der Tat so! Wir können hier für jeden 8*8-Pixel-Block separat die Hintergrundfarbe bestimmen. Diese Erkenntnis ist jetzt nicht unerheblich! Auch im Bitmap-Modus ist die gesamte Organisation sehr am Zeichen- / Textmodus angeleht! Wer möchte kann es im Bild oben nachzählen oder einfach ausrechnen: 320 Pixel / 8 = 40; 200 Pixel / 8 = 25. Das Ergebnis 40 * 25 sollte euch bekannt sein, das ist exakt die Auflösung im Textmodus.
Ändert die Löschroutine clrHiResColor bitte wieder so, dass der Bildschirm komplett gelöscht wird (also schwarz ist). Wir wollen nun einige Pixel setzen, dazu ändern wir main direkt vor der Endlosschleife jmp * etwas:
ldx #7 ;Schleifenzähler lda #$ff ;Pixelmuster .loop sta VICBITMAPADR,X ;Pixel ausgeben lsr ;Muster im Akku ändern dex ;Schleifenzähler verringern bpl .loop ;solange positiv nochmal -> .loop jmp * ;Endlosschleife
Bevor wir das Programm starten, was für eine Ausgabe erwartet ihr?
Wir geben über den Akku immer 8-Bit (also 8-Pixel) aus. Der Akku-Inhalt wird bei jedem Durchlauf nach rechts verschoben. Wer schon für andere Systeme programmiert hat, würde jetzt sicher acht unterschiedlich lange Linien nebeneinander erwarten, oder nicht?
Startet nun das Programm und ihr seht…nichts!
Ändert die Löschroutine clrHiResColor jetzt so, dass statt 0 der Bildschirm mit 1 gefüllt wird. Ersetzt dazu das txa einfach mit lda #1 und startet das Programm danach nochmal.
Ahhh, da ist ja etwas zu sehen. Wir erkennen nun, dass wir tatsächlich etwas in die Bitmap geschrieben haben. Allerdings war es durch die Verwendung von schwarz auf schwarz nicht wirklich gut zu erkennen 😉 . Wie können wir nun die Pixelfarbe bestimmen? Wir wissen ja, dass der C64 nur 16 Farben beherrscht
und das der Bildschirmspeicher beim Bitmap-Modus für die Hintergrundfarbe zuständig ist. Mit einem Nibble lassen sich aber bereits die 16 möglichen Farben bestimmen, daher wird es euch nicht überraschen, dass das obere Nibble eines Bytes im Bildschirmspeicher für die Pixelfarbe und das untere (wie eben gesehen) für die Hintergrundfarbe zuständig ist. Überprüfen wir dies durch eine kleine Programmänderung.
Ergänzt main vor der Endlosschleife noch um die folgenden beiden Zeilen
lda #$27 ;Pixel = rot / Hintergrund = gelb sta VICSCREENRAM ;Farbe über Bildschirmspeicher bestimmen
und startet dann das Programm…
Wie ihr seht, haben wir für den ersten 8*8 Pixel-Block die Hintergrundfarbe auf gelb und die Pixelfarbe auf rot gesetzt. Ihr könnt also für jeden dieser Blöcke jeweils eine eigene Pixel- und Hintergrundfarbe festlegen.
Außerdem stellen wir fest, dass wir nicht (wie weiter oben erwartet) die Linien nebeneinander, sondern übereinander erhalten (sie bilden das Dreieck, das wir auf dem BS sehen). Dies ist der bereits erwähnten Nähe zum Textmodus geschuldet.
Ihr könnt euch den Bitmap-Modus so vorstellen, als wäre er ein großer, frei änderbarer Zeichsatzspeicher. Nur dass dieser 1000 Zeichen umfasst und sich jedes Zeichen an einer festen Position befindet. Werft zum besseren Verständnis ggf. nochmal einen Blick auf VIC-II: Eigener Zeichensatz und schaut euch die folgende Grafik / Tabelle an.
In der obigen Grafik seht ihr, wo sich welches Byte der Hi-Res-Bitmap befindet und erkennt außerdem welche Adressen die Farbinformationen beinhalten (natürlich beziehen sich die Farb-Adressen ab $0400 nur auf unser Beispiel, der Bildschirmspeicher kann ja auch verschoben werden). Da ein Byte bekanntlich 8-Bits hat, könnt ihr euch so vielleicht besser vorstellen, dass die Bytes 0 bis 7 das erste 8*8-Pixel große „Zeichen“ bilden, die Bytes 8 bis 15 das zweite und die Bytes 312 bis 319 das 40. „Zeichen“, usw.
Wir können also nicht direkt einen Pixel durch die Angabe der X- und Y-Position setzen bzw. löschen, sondern müssen dazu einige Berechnungen anstellen. Wir müssen die Position des entsprechenden 8*8-Blocks, die Zeile (sprich das Byte) im jeweiligen Block berechnen und dort den gewünschen Pixel durch Bit-Manipulation ändern. Möchten wir jetzt das Pixel an X=314 & Y=197 setzen, dann sollten wir erstmal die gedachte Textzeile ermitteln, in der sich das benötigte Byte befindet. Also 197 / 8 = 24 Rest 5, wir landen also in der 25. „Textzeile“, wie es der Zufall will, finden wir diese oben in der Grafik 😉 . Der Rest von 5 bestimmt dann innerhalb dieser Textzeile die Byte-Zeile. Wir befinden uns also in der Reihe, die mit BYTE-7685 & BYTE-7693 beginnt (die Zählung beginnt wieder mit 0!). Jetzt müssen wir noch die X-Position (hier 314) umrechnen. Teilen wir nun 314 / 8 = 39 Rest 2; wir landen also im 40. Zeichen (oben in der Grafik BYTE-7997) und müssen dort das 3. Bit (Zählung beginnt bei 0!) von links (also eigentlich Bit-5) setzen. Erstellen wir nun auf Basis unserer Beobachtungen eine neue Funktion, mit der wir gezielt einzelne Pixel setzen können. Ein Problem sollten wir vorher noch klären: Wie wollen wir die X-Position an die Funktion übergeben? Schließlich kann X Werte von 0 bis 319 annehmen und diese passen schwerlich in ein Byte. Ich verwende hier einfach das Carry-Flag als höhstes Bit für die X-Position.
!zone setPixel ;*** X-Position = Carry + X-Register ;*** Y-Position = Y-Register setPixel lda #<VICBITMAPADR ;Bitmap-Adresse auf die Zero-Page sta ZP_HELPADR1 lda #>VICBITMAPADR sta ZP_HELPADR1+1 bcc .skip ;falls Carry gelöscht weiter -> .skip inc ZP_HELPADR1+1 ;sonst MSB+1 clc ;und C wieder löschen (für ADC) .skip txa ;X in den Akku pha ;und für später merken and #%11111000 ;'Pixel'-Position ausblenden adc ZP_HELPADR1 ;Anzahl der Bytes für X-Position addieren sta ZP_HELPADR1 ;und speichern bcc .skip1 ;falls C gelöscht ist weiter -> .skip1 inc ZP_HELPADR1+1 ;sonst MSB wegen gesetztem Carry erhöhen .skip1 tya ;Y in den Akku pha ;und merken lsr ;jetzt durch 8 teilen lsr lsr beq .skip2 tay .loop clc ;Für jede 'Textzeile' 320 Bytes addieren lda ZP_HELPADR1 adc #64 sta ZP_HELPADR1 lda ZP_HELPADR1+1 adc #1 sta ZP_HELPADR1+1 dey bne .loop .skip2 pla and #%00000111 ;Bytes für die 'Ziel-Textzeile' tay ;ins Y-Register (für Y-nach-indizierte-Adr.) pla ;jetzt noch die BIT-Position (X) berechnen and #%00000111 tax lda #$00 sec .loop1 ror ;Zielpixel 'einrotieren' dex bpl .loop1 ;wiederhole, solange X positiv ora (ZP_HELPADR1),Y ;mit bisherigen Wert ODER-Verknüpfen sta (ZP_HELPADR1),Y ;und speichern rts ;zurück zum Aufrufer
Die Routine legt zu Beginn die Startadresse des Bitmap-Speichers auf der Zero-Page ab. Dann wird geprüft, ob das Carry-Flag (X-Pos. größer 255) gesetzt ist. Falls dies der Fall sein sollte wird das MSB auf der Zero-Page direkt um eins erhöht und C für die gleich folgende Addition gelöscht. Anschließend kopieren wir den Inhalt des X-Registers in den Akku, merken uns den Wert auf dem Stack und blenden die unteren drei Bits aus, diese bestimmen später die exakte Pixelposition. Den Rest, der im Akku verblieben ist, addieren wir nun zur Adresse auf der Zero-Page. Damit haben wir die X-Position für unser Ziel-Byte berechnet. Nun muss noch die Y-Position addiert werden, dies geschieht ab .skip1. Dort kopieren wir den Inhalt des Y-Registers in den Akku und merken uns diesen wieder auf dem Stack. Nun teilen wir durch 8; bleibt nichts übrig geht es bei .skip2 weiter, sonst wird der Akku zurück ins Y-Register kopiert, dann blenden wir die unteren drei Bits aus und in einer Schleife wird für jede Zeile 320 zur Adresse auf der Zero-Page addiert. Zum Schluß brauchen wir noch die Reste. Der nicht durch 8 teilebare Rest der Y-Position landet direkt im Y-Register und wird gleich für die Y-nach-indizierte-Adressierung benötigt. Der nicht durch 8 teilbare Rest der X-Position wird verwendet, um durch Rotation & Verschieben das Bit für das Ziel-Byte an die richtige Stelle zu bringen. Da wir ein einzelnes Bit verändert, ist es wichtig, den aktuellen Inhalt des Ziel-Byte zu erhalten. Also verknüpfen wir unser Bit im Akku mit dem Byte an der berechneten Adresse (zzgl. dem Y-Register) per ora und speichern es abschließend an der berechneten Position.
Um dies nun zu testen, solltet ihr bei clrHiResColor die Farbe zum Löschen auf #$10 (weiße Pixel auf schwarzem Hintergrund) setzen. Dann ändert main noch etwas:
main ;*** Bitmap-Modus aktivieren lda $d011 ;VIC-II Register 17 in den Akku ora #%00100000 ;Bitmap-Modus sta $d011 ;aktivieren ;*** Start des Bitmapspeichers festlegen lda $d018 ;VIC-II Register 24 in den Akku holen and #%11110111 ;Mit Bit-3 ora #VICBITMAPBBLOCKNO*8 ;den Beginn des sta $d018 ;Bitmapspeichers festlegen jsr clrHiResBitmap clc ldx #0 ldy #0 jsr setPixel sec ldx #63 ldy #0 jsr setPixel sec ldx #63 ldy #199 jsr setPixel clc ldx #0 ldy #199 jsr setPixel clc ldx #160 ldy #100 jsr setPixel jmp * ;Endlosschleife
Wenn ihr das Programm jetzt ausführt, dann sollten euch weiße Punkte in den vier Ecken und in der Mitte des Bildschirms auffallen. (Ist blöd zu erkennen, ich hätte den Rahmen evtl. auch auf schwarz setzen sollen, aber dann hätte man nicht gesehen, dass die Punkte tatsächlich in den Ecken sitzen.)
Wer möchte kann ja gerne mal den kompletten Bildschirm per setPixel füllen, dass dies sehr langsam ist, sollte bei einem Blick auf die Funktion klar sein. Sie dient mal wieder einzig zur Anschauung. In der Praxis ist es wohl wenig sinnvoll so vorzugehen.
;*** VIC-II Speicher-Konstanten VICBANKNO = 0 ;Nr. (0 - 3) der 16KB Bank | Standard: 0 VICSCREENBLOCKNO = 1 ;Nr. (0 -15) des 1KB-Blocks für den Textbildschirm | Standard: 1 VICCHARSETBLOCKNO = 2 ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz | Standard: 2 VICBITMAPBBLOCKNO = 1 ;Nr. (0 - 1) des 8KB-Blocks für die BITMAP-Grafik | Standard: 0 VICBASEADR = VICBANKNO*16384 ;Startadresse der gewählten VIC-Bank | Standard: $0000 VICCHARSETADR = VICBASEADR+VICCHARSETBLOCKNO*2048 ;Adresse des Zeichensatzes | Standard: $1000 ($d000) VICSCREENRAM = VICBASEADR+VICSCREENBLOCKNO*1024 ;Adresse des Bildschirmspeichers VICBITMAPADR = VICBASEADR+VICBITMAPBBLOCKNO * 8192 ;Adresse der BITMAP ZP_HELPADR1 = $fb ;Hilfsadresse auf der Zero-Page ;*** Startadresse *=$0801 ;** BASIC-Zeile: 2018 SYS 2062 !word main-2, 2018 !byte $9e !text " 2062" !byte $00,$00,$00 main ;*** Bitmap-Modus aktivieren lda $d011 ;VIC-II Register 17 in den Akku ora #%00100000 ;Bitmap-Modus sta $d011 ;aktivieren ;*** Start des Bitmapspeichers festlegen lda $d018 ;VIC-II Register 24 in den Akku holen and #%11110111 ;Mit Bit-3 ora #VICBITMAPBBLOCKNO*8 ;den Beginn des sta $d018 ;Bitmapspeichers festlegen jsr clrHiResBitmap clc ldx #0 ldy #0 jsr setPixel sec ldx #63 ldy #0 jsr setPixel sec ldx #63 ldy #199 jsr setPixel clc ldx #0 ldy #199 jsr setPixel clc ldx #160 ldy #100 jsr setPixel jmp * ;Endlosschleife !zone setPixel ;*** X-Position = Carry + X-Register ;*** Y-Position = Y-Register setPixel lda #<VICBITMAPADR ;Bitmap-Adresse auf die Zero-Page sta ZP_HELPADR1 lda #>VICBITMAPADR sta ZP_HELPADR1+1 bcc .skip ;falls Carry gelöscht weiter -> .skip inc ZP_HELPADR1+1 ;sonst MSB+1 clc ;und C wieder löschen (für ADC) .skip txa ;X in den Akku pha ;und für später merken and #%11111000 ;'Pixel'-Position ausblenden adc ZP_HELPADR1 ;Anzahl der Bytes für X-Position addieren sta ZP_HELPADR1 ;und speichern bcc .skip1 ;falls C gelöscht ist weiter -> .skip1 inc ZP_HELPADR1+1 ;sonst MSB wegen gesetztem Carry erhöhen .skip1 tya ;Y in den Akku pha ;und merken lsr ;jetzt durch 8 teilen lsr lsr beq .skip2 tay .loop clc ;Für jede 'Textzeile' 320 Bytes addieren lda ZP_HELPADR1 adc #64 sta ZP_HELPADR1 lda ZP_HELPADR1+1 adc #1 sta ZP_HELPADR1+1 dey bne .loop .skip2 pla and #%00000111 ;Bytes für die 'Ziel-Textzeile' tay ;ins Y-Register (für Y-nach-indizierte-Adr.) pla ;jetzt noch die BIT-Position (X) berechnen and #%00000111 tax lda #$00 sec .loop1 ror ;Zielpixel 'einrotieren' dex bpl .loop1 ;wiederhole, solange X positiv ora (ZP_HELPADR1),Y ;mit bisherigen Wert ODER-Verknüpfen sta (ZP_HELPADR1),Y ;und speichern rts ;zurück zum Aufrufer !zone clrHiResBitmap ;*** Die 8KB der Hi-Res BITMAP löschen clrHiResBitmap jsr clrHiResColor lda #<VICBITMAPADR ;auf die Zero-Page sta ZP_HELPADR1 lda #>VICBITMAPADR sta ZP_HELPADR1+1 ldx #32 ;Schleifenzähler 32 Pages (32 * 256 = 8192 = 8KB) ldy #0 ;Schleifenzähler für 256 BYTES je Page tya ;Akku auf 0 setzen .loop sta (ZP_HELPADR1),Y ;Akku 'ausgeben' dey ;Y verringern bne .loop ;solange größer 0 nochmal -> .loop inc ZP_HELPADR1+1 ;Adresse auf der Zeropage um eine Page erhöhen dex ;Pagezähler verringern bne .loop ;solange größer 0 nochmal -> .loop rts ;zurück zum Aufrufer !zone clrHiResColor ;*** Bildschirmspeicher löschen clrHiResColor ldx #0 ;Schleifenzähler 256 BYTES lda #$10 .loop sta VICSCREENRAM,X ;1. Page des Bildschirmspeichers sta VICSCREENRAM+256,X ;2. Page sta VICSCREENRAM+512,X ;3. Page sta VICSCREENRAM+768,X ;4. Page dex ;Schleifenzähler verringern bne .loop ;solange nicht 0 nochmal -> .loop rts ;zurück zum Aufrufer
Euch steht nun die Welt der Hi-Res-Bitmaps offen. Ihr könnt die Pixel- und Hintergrundfarbe bestimmen und gezielt einzelne Bildpunkte setzen. Als abschließendes Beispiel könnt ihr euch eine Doodle-Hi-Res-Grafik (die stammt nicht von mir!) als Programm herunterladen.
Hi-Res-Grafik
Die Grafik ist direkt ins Programm eingebunden und wurde von mir so gelegt, dass die Bitmap gleich passend an unserer Startadresse liegt, nur die Farben müssen noch in den Bildschirmspeicher kopiert werden.
Im nächsten Beitrag zeige ich das Vorgehen detaillierter mit einem Koala-Bild.
Ihr habt auch gesehen, wie verquast die Bitmaps organisiert sind. Nun versteht ihr wohl etwas besser, warum es wenige Spiele gibt, die wirklich im Bitmap-Modus laufen. Unmöglich ist es natürlich nicht, neben 3D-Spielen, gibt es aber nur sehr wenige Titel in dieser Richtung. Ein schönes Beispiel ist The Trapdoor.
Nach dem Hi-Res-Modus, schauen wir uns demnächst natürlich noch den Multi-Color-Bitmap-Modus an. Da werfen wir auch einen Blick auf das Koala-Format und zeigen eine hübsche Grafik an.
danke für den guten artikel