VIC-II: Grafikmodes – FLI

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

CBM prg Studio
Nun wirds noch bunter…

In den vorangegangenen Beiträgen haben wir die ‚offiziellen‚ Grafikmodi 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 also 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 bekanntlich bei %01 bzw. %10 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.

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

Unsere Vorbereitungen (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 ‘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 gesamte Bildschirmausgabe
Die gesamte 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.

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 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. Leider unterstützt uns der Assembler des CBM prg Studios bei dieser Aufgabe nicht (andere Assembler bieten dort mit Schleifen und komplexen Berechnungen, die Möglichkeit die Tabelle direkt bei der Programmerstellung anzulegen). Aber wir behelfen uns mit einer kleinen Funktion initTables, die die Tabelle zur Laufzeit erzeugt.

Sorgt am Ende des Sourcecodes dafür, dass wir etwas Platz für die benötigten Daten haben. 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…

Unsere Schleife verwendet das X-Register als Schleifenzähler, wir füllen darüber einfach alle 256 BYTEs, die wir reserviert haben. Der Schleifenzähler wird dann in den Akku kopiert und um vier BITs nach links ‚geshiftet‚. Dadurch füllen wir die BITs 7-4. Da wir nur acht verschiedene Bildschirmspeicheradressen verwenden, benötigen wir sogar nur die BITs 6-4! Daher löschen wir die restlichen BITs einfach. Wichtig ist aber, dass wir die Startadresse für die BITMAP unverändert lassen! Also setzen wir per ora zur Sicherheit noch BIT-3!! Den so berechneten Wert tragen wir dann in unsere Tabelle ein, verringern den Schleifenzähler und wiederholen alles, bis dieser den Wert 0 annimmt. Sonst wird die Funktion wieder verlassen.

Die neuen Funktion rufen wir dann direkt hinter  jsr drawpattern ;unser Muster zeichnen mit  jsr initTables ;Hilfstabelle aufbauen auf.
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 Test mal die beiden folgenden Zeilen eingeben.

Erhöht ihr den addierten Wert beim lda jetzt jedes Mal um 1 (bis 7, danach geht es wieder von Neuem los) und startet das Programm, dann könnt ihr alle Farbkombinationen abrufen.

Die einzelnen Werte aus $D018
Die einzelnen Werte aus $D018

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 ganz einfach von initTables mitfüllen lassen. Fügt dazu die neuen Zeilen (gelb hervorgehoben) einfach zur Schleife (zwischen sta d018Values,X und inx) hinzu:

 

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 MyIRQ_Main 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 200 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.

Das erste FLI-Bild
Das 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 unsere 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!
Endlich ist es vollbracht!

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 dieses 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.

Probleme am linken Rand!
‚Der 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:

Den linken Rand bereinigt.
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 etwas verschoben.
Das Bild wurde mit einem Grafikprogramm etwas verschoben.

Wer möchte, kann das obige Bild auch noch im Java-Emulator ‚bestaunen‚.


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 müssten wir uns aber erstmal im nächsten Beitrag, mit dem MCI-Modus beschäftigen.


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

Loading...


 

<<< zurück | weiter >>>

 

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

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