VIC-II: Grafikmodes – FLI

Nun wirds noch bunter…

C64 Studio & AMCE

In den vorangegangenen Beiträgen haben wir die offiziellen Grafikmodes des C64 kennengelernt. Es gibt aber noch eine Reihe Software-Grafikmodi. Schauen wir uns doch hier mal einen ersten dieser benutzerdefinierten Modi an.

Ihr solltet bereits mit den Beiträgen VIC-II: Grafikmodes – BITMAP (Multi-Color), VIC-II: Speicherbereiche festlegen und Der Rasterzeileninterrupt vertraut sein und wissen, wie man den Oberen & unteren Rand öffnen kann!

Flexible Line Interpretation (FLI)

Bevor wir vorwärts, Richtung FLI gehen, werfen wir noch mal einen Blick zurück auf den MultiColor-Bitmap-Modus. Wie wir gesehen haben, bietet der MC-Modus durch Halbierung der Auflösung in X-Richtung, die Möglichkeit mehr Farben zu verwenden. Außerdem ist der Bildschirm trotz Bitmap-Modus immer noch in 40*25 Zellen (bzw. Zeichen) zu je 4*8 Pixeln unterteilt. Durch setzen der Bit-Paare innerhalb einer jeden 4*8-Pixel großen Zelle können wir eine von vier Farben wählen. Die folgende Tabelle sollte euch bekannt sein.

Der FLI-Modus ist vom Prinzip identisch mit dem normalen MultiColor-Bitmap-Modus, nur dass er es uns ermöglicht pro 4*8 Pixel-Zelle sämtliche 16 Farben zu verwenden.

Die 16 Farben des C64.
Die 16 Farben des C64.
Wie kommen wir an mehr Farben?

Da uns auch im FLI-Modus nur zwei Bits je Farbe zur Verfügung stehen, stellt sich die Frage, wie man so bis zu 16 verschiedene Farben je Zelle verwenden kann? Wir müssen zur Laufzeit die festgelegten Farben ändern und dort kommt Der Rasterzeileninterrupt ins Spiel. Das Ändern der Hintergrundfarbe würde uns niemals für jedes Zeichen gelingen, dies scheidet also somit schon mal aus. Da sich das Farb-RAM immer an der Adresse $d800 befindet, müssten wir für jede Rasterzeile, für jede Zeichen-Zeile, einen neuen Wert dorthin schreiben. Auch dies ist unmöglich! Bleibt also nur der Bildschirmspeicher!! Von dort wird im Bitmap-Modus bei %01 bzw. %10 bekanntlich die Farbe für das Pixel geholt. Wo ist hier nun aber der Unterschied zum Color-RAM? Müssten wir nicht auch hier für jede Rasterzeile erneut Farbwerte in den BS-Speicher schreiben?? Theoretisch schon, es gibt aber auch eine schnellere Lösung (Tipp VIC-II: Speicherbereiche festlegen).

In Etappen zum FLI-Bild

Um die Theorie etwas aufzulockern, entwickeln wir jetzt eine FLI-Anzeigefunktion. Beginnen wir damit, die Speicherbereiche festzulegen, den Bitmap-Modus zu aktivieren und richten noch einen stabilen Raster-IRQ ein. Wir wählen die VIC-Bank 1, also den Bereich von $4000 - $7fff für unser Beispiel. Dort legen wir zu Beginn (also bei $4000) direkt das SCREENRAM ab. Die Bitmap landet in den zweiten 8KB, beginnend bei $6000. Das Basis-Programm solltet ihr mittlerweile selbst hinbekommen, daher verzichte ich auf weitere Ausführungen.

Mit einer Bitmap beginnen

Das Programm ist so zwar lauffähig, zeigt aber bisher nur ein zufälliges Bild, abhängig von der Speicherkonfiguration.

Unsere Vorbereitungen (VICE – Rahmen-Debuggen aktiv)
Unsere Vorbereitungen (VICE – Rahmen-Debuggen aktiv)

Nun wollen wir eine von uns definierte Musterausgabe generieren. Dazu löschen wir als Erstes die kompletten 16KB, der von uns gewählten VIC-II-Bank. Fügt die neue Funktion clearALL einfach direkt hinter der Zeile jmp * ;Endlosschleife ein.

Wie ihr seht, ist die Schleife sehr einfach. Die Hauptschleife bei .loop setzt jedes einzelne Byte der 16KB VIC-Bank auf 0. Da die Bank direkt mit unserem Bildschirmspeicher bei SCREENRAM beginnt, starten wir mit dem Löschen dort. Nach je 256 Bytes, erhöhen wir dann das MSB der Adresse um eins, bis alle 64 Pages gelöscht wurden. Zum Schluß setzen wir bei .loop1 auch noch das COLOR-RAM auf 0.

Jetzt müssen wir nur noch die neue Funktion clearALL aufrufen, außerdem setzen wir noch die Rahmen- und Hintergrundfarbe und deaktivieren die Sprites. Fügt die folgenden Zeilen direkt vor jmp * ;Endlosschleife ein.

Jetzt sollte unsere Anzeige schon mal sauber sein…

Es wurde „alles“ gelöscht.
Es wurde „alles“ gelöscht.

Nun bringen wir noch unser Testmuster auf den Bildschirm. Wir zeichnen dazu drei Zeilen mit je vier Zeichen, die jeweils eine Farbkombination enthalten und eine Zeile die alle möglichen Kombinationen enthält. Fügt die nächste Funktion drawPattern hinter der von eben ein.

Die Funktion ist total simpel: Bei .loop zeichnen wir unser Testmuster und bei .loop1 setzen wir die benötigten Farben im Bildschirmspeicher und Farb-RAM.

Das Muster im Detail
Das Muster im Detail

Sobald ihr direkt hinter jsr clearALL ;die komplette 16KB-VIC-II-Bank löschen! die neue Funktion mit jsr drawPattern ;unser Muster zeichnen aufruft und das Programm startet, erscheint das Muster auf dem Bildschirm.

Die Bildschirmausgabe mit unserem Testmuster.
Die Bildschirmausgabe mit unserem Testmuster.

Auch wenn es nicht danach aussieht, dies ist nun unsere MultiColor-Bitmap, mit dem Testmuster. Wir sehen hier nochmal den uns bekannten Fakt, dass ein MC-Bild in einem 4*8 Pixel großem Feld (die Zapfen unten am Muster) nur vier verschiedene Farben aufweisen kann.

Um nun doch mehr Farben, durch das eingangs erwähnte Ändern der Farbinformationen aus dem Bildschirmspeicher zu erreichen, müssen wir noch mal einen Blick auf die Funktionsweise des VIC-II und die Rasterzeilen werfen:
Wie wir wissen gibt es normale Rasterzeilen und die sog. Bad Lines. Diese benötigt der VIC, um die Daten für den Ausgabebereich vorzubereiten. Das macht er immer zu Beginn einer neuen Zeichen-Zeile, also jede achte Rasterzeile vom Anfang des Ausgabebereichs an.

Hier können wir nun ansetzen:
Um mehr Farben zu erreichen, müssen wir selbst für noch mehr Bad Lines sorgen!
Nur dann liest der VIC die neuen Daten und unsere Ausgabe ändert sich. Wie bereits erwähnt, reicht die Zeit aber nicht um die 1000 Bytes des Bildschirmspeichers zu kopieren. Aber wir können in der Zeit die Adresse für den Bildschirmspeicher ändern! Durch dieses Vorgehen erhöht sich natürlich auch unser Speicherbedarf. Wie wir gleichen sehen, brauchen wir dann bis zu 7KB mehr!

OK, schauen wir uns das mal genauer an und sorgen dafür, dass unser Testbild bunter wird.

Für mehr Farben sorgen

Beginnen wir damit, hinter SCREENRAM sieben weitere Speicherbereiche mit den gewünschten Farben einzurichten. Unser Ziel (für diesen ersten Versuch) ist es, folgende Ausgabe mit unserem Muster zu erreichen.

So bunt soll das Muster werden.
So bunt soll das Muster werden.

Wir wollen im oberen Bereich alle 16 Farben untereinander darstellen (pro Zeichen also 8 verschiedene Farben) und unten (in den Zapfen) verwenden wir in jedem 4*8-Pixel großen Zeichen sogar alle 16 Farben aufeinmal.

Dazu benötigen wir acht verschiedene Bildschirmspeicher. Jeder dieser Speicher wird für eine Rasterzeile einer Zeichen-Zeile aktiviert. Werft einfach einen Blick aufs folgende Bild, ich hoffe dann wird es klarer.

Zuordnung der einzelnen Bildschirmspeicher (Screen-RAM)
Zuordnung der einzelnen Bildschirmspeicher (Screen-RAM)

Rechts steht immer welches Screen-RAM in der jeweiligen Zeile aktiv ist. Schreiben wir also eine kleine Funktion, die die benötigten Bildschirmspeicher mit den entsprechenden Farben anlegt.

Wir gehen hier mit Y als Schleifenzähler, alle 8 Bildschirmspeicher durch. Dann holen wir uns aus der Tabelle testColors die benötigte Farbe und verwenden das X-Register um die vier Zeichen in einer Zeile zu füllen. Mit den sta SCREENRAM...,X Anweisungen füllen wir die vier Zeilen am Stück. Danach erhöhen wir das MSB aller sta SCREENRAM...,X-Anweisungen um 1024 (daher jeweils vier inc .loop1+...). Wurden alle acht Bildschirmspeicher vorbereitet, wird zum Schluß noch das Farb-RAM mit der Farbe gelb gefüllt und schon geht es zurück zum Aufrufer.

Löscht das bisherige Setzen der Farben aus drawPattern! Entfernt dafür alles nach bpl .loop ;solange positiv nochmal -> .loop und vor rts ;zurück zum Aufrufer.

Legt jetzt noch am Ende des Quellcodes die Tabelle testColors an.

Laßt uns initColors direkt vor jsr drawpattern ;unser Muster zeichnen mit jsr initColors ;die Farben setzen aufrufen. Startet ihr anschließend das Programm, dann sieht unsere Anzeige etwas anders aus.

Andere Farben.
Andere Farben.

In der Tabelle testColors sind jetzt andere Farben als weiter oben definiert, daher sieht unsere Anzeige nicht mehr wie eben aus.

Um gleich die Adresse für den Bildschirmspeicher schnell ändern zu können, sollten wir uns eine weitere Tabelle anlegen. Wir legen in dieser Tabelle direkt die für jede Rasterzeile benötigten Werte für das VIC-II-Register 24 $d018 ab. Dort wird bekanntlich über die Bits 7-4 festgelegt, wo sich der Bildschirmspeicher befinden soll. Wir lassen die Tabelle gleich vom Assembler bei der Programmerstellung anlegen.

Um die Taktzyklen besser unter Kontrolle zu haben, richten wir die Tabelle an der Pagegrenze aus.

Die Funktion zum Füllen ist wieder recht simpel. Wir legen in der Tabelle direkt die später benötigten Werte für $d018 ab. Wir nutzen dazu zwei !for-Schleifen, die vom Assembler bei der Programmerstellung ausgewertet werden, sie kosten uns also keine Zeit während der Programmausführung auf dem C64. Für $d018 benötigen wir im oberen Nibble die Adresse des Bildschirmspeichers und im unteren müssen wir daran denken, den MultiColor-Modus zu aktivieren. Die innere y-Schleife, legt immer acht Bytes an, die die benötigten Werte für $d018 enthalten. Durch die äußere x-Schleife wiederholen wir das ganze 32 mal und füllen somit die komplette Page.

Ein Start würde nichts ändern, schließlich wird die Tabelle d018Values nur gefüllt, aber bisher nicht genutzt. Wollt ihr die Daten kontrollieren, dann könnt ihr direkt vor jmp * zum Testen mal die beiden folgenden Zeilen eingeben.

Erhöht ihr den addierten Wert beim lda jetzt jedes Mal um 1 und startet das Programm, dann könnt ihr alle Farbkombinationen abrufen. Sobald ihr bei 7 angelangt seid, könnt ihr aufhören, danach geht es wieder von vorne los.

Die einzelnen Anzeigen durchs Umschalten des Bildschirmspeichers.
Die einzelnen Anzeigen durchs Umschalten des Bildschirmspeichers.

Vergesst nicht die beiden Zeilen wieder zu löschen!

Wie lösen wir eine Bad-Line aus?

Nun ist es an der Zeit, dass wir uns mal fragen, wie wir überhaupt eine Bad-Line auslösen? Eine Bad-Line tritt immer dann auf, wenn die unteren drei Bits der Rasterzeile mit den drei Bits für das vertikale Scrolling übereinstimmt! Wir können nun durch Veränderung der Scrollwerte, im VIC-Register 17 $d011, dafür sorgen, dass jede Rasterzeile zu einer Bad-Line wird! Auch hier sollten wir eine Tabelle, nennen wir sie d011Values 😉 , einsetzen. Fügt das Label ganz am Schluß, hinter dem d018Values-Block ein. Bytes brauchen wir diesmal nicht zu reservieren, hiernach kommt eh nichts mehr. Auch ein ALIGN 256 ist nicht nötig, da die Tabelle d018Values bereits an der Pagegrenze ausgelegt ist und sie exakt 256 Bytes belegt.

Wir können d011Values wieder ganz einfach vom Assembler füllen lassen:

Das erste FLI-Bild

Jetzt können wir im Raster-IRQ die Tabellen auslesen und für unser erstes FLI-Bild sorgen. Sucht das Label MyIRQMain und fügt direkt dahinter den folgenden Block ein.

Zu Anfang verbummeln wir einfach wieder etwas Zeit, dann nutzen wir das X-Register als Schleifenzähler, um unsere Rasterzeilen abzuklappern. Wir holen ab .loop jedes Mal die Werte für $d018 und $d011 aus den zugehörigen Tabellen und füllen die Register. Dann wird der Schleifenzähler erhöht und sobald wir Zeile 199 erreicht haben, verlassen wir die Schleife. Wichtig ist, dass die Schleife exakt soviele Taktzyklen benötigt, wie wir in einer Bad Line zur Verfügung haben, nämlich 23.

Ein Start zeigt euch unser erstes FLI-Bild. Die gelbe Linie über dem Ausgabebereich dient nur zur Veranschaulichung, hier beginnen wir damit Zeit zu verbummbeln.

Unser erste FLI-Bild.
Unser erste FLI-Bild.

Wie so oft 😉 , gibt es aber noch ein Problem! Schaut euch mal den Beginn des Musters an.

Da fehlt etwas!
Da fehlt etwas!

Es fehlen drei Zeilen! Das Muster sollte mit schwarz, weiß und rot beginnen. Wir müssen hier daran denken, dass wir die Anzeige scrollen, um Bad-Lines zu erzeugen. Dadurch wandert ein Teil der Anzeige unter den Rahmen. Also öffnen wir den Rahmen doch einfach. Wie es der Zufall will, sind wir nach unserer Schleife von eben, direkt an der richtigen Stelle dafür. Ihr braucht also hinter ;23 TZ nur noch Bad-Lines!!! nur die beiden folgenden Zeilen einfügen.

Leider bringt ein Start noch nicht ganz das gewünschte Ergebnis.

Ooops, was ist denn nun los?
Ooops, was ist denn nun los?

Wie ihr seht, geht der Rahmen noch nicht auf. Wir sollten $d011 noch in unserem Raster-IRQ zurücksetzen, sonst gerät das Timing aus dem Tritt! Sucht das Label DoubleIRQ. Kurz dahinter findet ihr vier nop-Anweisungen. Kommentiert drei davon aus und setzt das Register 17 $d011 zurück (s. gelb markierte Zeilen):

Jetzt könnt ihr das Programm starten und endlich sind wir am Ziel.

Endlich ist es vollbracht, das FLI-Bild wird korrekt angezeigt!
Endlich ist es vollbracht, das FLI-Bild wird korrekt angezeigt!

Schaut ihr euch das Muster in der Vergrößerung an, dann seht ihr, dass wir unser ganz oben ausgegebenes Ziel erreicht haben.

So bunt soll das Muster werden.
Lauter Farben…

Hier noch das komplette Listing zur Kontrolle…

So schön es auch ist, den FLI-Modus nun endlich ergründet zu haben, so langweilig ist unser Beispiel. Also zum Schluß noch ein Ausflug in die Praxis, wo wir übrigens auf ein weiteres Problem stoßen werden…

Wie sieht es in der Praxis aus?

Um mal schnell an ein Bild im FLI-Format zu kommen, habe ich eins konvertiert. Schauen wir uns erst mal die Unterschiede zu einer normalen Multi-Color-Bitmap an.

Nehmen wir dieses Bild als Ausgangspunkt…

Star Wars - The Clone Wars
Star Wars – The Clone Wars (Yoda Wallpaper)

…und konvertieren es, dann erhalten wir als Multi-Color-Bitmap folgendes Ergebnis…

als MC-Bitmap
Multi-Color-Bitmap

…als FLI sieht das Ganze gleich viel besser aus…

Die FLI-Version
FLI-Version

Das Bild musste etwas beschnitten werden, damit es Verzerrungsfrei in 320*200 Pixel passt.

Um den Unterschied noch etwas besser zu erkennen, hier beide Bilder im direkten Vergleich.

FLI und MC-Bitmap
FLI und MC-Bitmap

Wie ihr seht, bietet das FLI-Bild mehr Details, dies wird durch die zusätzlichen Farben ermöglicht.

Diese Bilder sind übrigens direkt das Ergebnis der Konvertierung, ohne jegliche Nachbearbeitung. In der Praxis würdet ihr natürlich noch Hand anlegen und das Bild weiter optimieren.

Laßt uns nun das konvertierte FLI-Bild mit unserem Programm von eben anzeigen. Dazu brauchen wir nur wenige Änderungen. Ich beschreibe hier kurz die Schritte, gleich folgt dann das komplette Listing.

Zunächst kann alles weg, was mit dem Muster zusammenhängt. Wir benötigen nur das Aufbauen der Tabellen! Dann binden wir am Ende des Sourcecodes einfach unser Yoda-Bild ein. Das Bild ist im FLI-Graph 2.2 (dies ist ein C64-Programm, mit dem ihr FLI-Grafiken erstellen könnt) Format gespeichert, daher binden wir das Bild ab $3b00 ins Programm ein. Dies hat den Vorteil, dass wir nur noch das Farb-RAM kopieren müssen (siehe copyToColorRAM im folgenden Listing) und schon erscheint Meister Yoda auf dem Bildschirm.

Packt die Yoda-Bilder bitte direkt ins Verzeichnis mit eurem Quellcode. Die Bilder findet ihr hier im ZIP…

Startet nun das obige Programm und ihr seht unser nächstes Problem.

Der linke Rand, nicht farbig er ist!
Der linke Rand, nicht farbig er ist!

Wie ihr seht, haben wir am linken Rand falsche Farben. Dies kommt durch unser pausenloses erzeugen der Bad-Lines. Bis die greifen, dauert es einfach etwas. Um das Problem zu beheben, kann man z. B. Sprites verwenden, die diesen Bereich überdecken und ansatzweise die richtigen Farben anzeigen könnten. Dies würde aber nur nach massiven Änderungen an unserem Programm klappen. Die einfachste Lösung ist es, das Bild auf der linken Seite zu bereinigen. Wir entfernen dazu alle Pixel auf der linken Seite auf einer Breite von exakt drei Zeichen.

Bindet einfach Yoda_2.fli ein und erstellt das Programm erneut:

Hier haben wir den linken Rand bereinigt.
Hier haben wir den linken Rand bereinigt.

So sieht die Anzeige doch besser aus, oder? Es fehlen zwar links die Bildinformationen, aber es sieht einfach schöner aus.
Falls euch der linke Rand wichtiger, als der rechte ist, dann könnt ihr das Bild natürlich auch einfach mit einem Grafikprogramm etwas verschieben. Yoda_3.fli zeigt, wie das aussehen könnte. Dabei habe ich das Logo aber noch gerettet.

Das Bild wurde mit einem Grafikprogramm etwas verschoben.
Das Bild wurde mit einem Grafikprogramm etwas verschoben.

So nun seid ihr für FLI gewappnet. Da der FLI-Modus sehr viel Rechenzeit und Arbeitsspeicher verbraucht, eignet er sich in erster Linie für Demos, Titelbilder oder evtl. für sehr statische Spiele (z. B. die Umsetzung von Brett- oder Kartenspielen).

Noch einige Anmerkung

Ihr könnt den Speicherbedarf und die Rechenzeit reduzieren, wenn ihr FLI-Bilder erzeugt, die z. B. nur jede zweite oder gar vierte Zeile neue Farben benötigen.

Wenn ihr euch das FLI-Graph-Format noch mal anseht…

…dann wundert ihr euch evtl. über den ersten Block. Ab $3b00 findet ihr für jede Rasterzeile eine eigene Hintergrundfarbe für $d021! Ihr könnt die FLI-Routine nämlich auch so bauen, dass ihr in jeder Rasterzeile eine andere Hintergrundfarbe verwendet! Dadurch habt ihr theroretisch die Möglichkeit 25 verschiedene Farben (16 über die Bildschirmspeicher + 8 über die Hintergrundfarbe + 1 aus dem Farb-RAM) je 4*8 Pixel großem Zeichen anzuzeigen. Es bleibt natürlich bei den max. 16 Farben, die der C64 beherrscht, aber durch die neuen Kombinationsmöglichkeiten lassen sich dann sehr viel schönere Grafiken erzeugen und anzeigen.

Wenn ihr euch mit dem FLI-Modus beschäftigt, läuft euch evtl. auch noch der IFLI-Modus (Interlaced Flexible Line Interpretation) über den Weg. Dabei wird der MCI-Modus (MultiColor Interlaced) mit dem eben behandelten FLI-Modus kombiniert. Dazu sollten wir uns aber erstmal im nächsten Beitrag, mit dem MCI-Modus beschäftigen.


Schrott!!Naja...Geht so...Ganz gut...SUPER! (7 Bewertungen | Ø 5,00 von 5 | 100,00%)

Loading...


ZurückWeiter

2 Gedanken zu „VIC-II: Grafikmodes – FLI“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Protected by WP Anti Spam