ATARIs neuer Greifvögel dürfte wohl mittlerweile in vielen Läden gelandet sein. Er besticht nicht nur durch seine interessanten Sound-Fähigkeiten, sondern auch durch eine Vielzahl neuer Grafikmodi, die im Vergleich zum betagten ST einen Riesenschritt nach vorne darstellen. So wird der Anwender mit Auflösungen und Farben verwöhnt, die ihm bisher nur aus dem PC-Bereich bekannt waren.
Der neidische Blick über Nachbars Zaun ist somit hinfällig, kann der Falcon030 doch tatsächlich bis zu 65536 Farben und Auflösungen von bis zu 768*512 Pixeln darstellen, und das, ohne durch den vom PC bekannten „Flaschenhals“ eingeengt zu werden; was also bedeutet, daß es keine Ports gibt, durch die die Grafik geschleust werden muß, um in den Bildschirmspeicher zu gelangen. Vor allen Dingen läßt sich der Bildschirmspeicher im Falcon an jeder beliebigen Stelle des Hauptspeichers plazieren, so wie es schon im STE möglich war.
Ein weiterer Vorteil des Falcons liegt in seiner Anschlußfreudigkeit an die verschiedensten Sichtgeräte. Von Haus aus ist er in der Lage, ein Fernsehbild zu erzeugen und es per handelsüblichem Kabel direkt an jeden Fernseher zu schicken, was natürlich nur für Einsteiger oder Gelegenheitsspieler interessant ist, weil das Fernsehgerät prinzipbedingt nur eine eher schlechte Bildqualität zuläßt. Die nächste Möglichkeit besteht im Anschluß eines normalen RGB-Monitors, wie z.B. dem ATARI SC 1224, den man vielleicht noch von seinem alten ST übrig hat. Dieser wird mit einem speziellen von ATARI gelieferten Adapter an den Falcon angeschlossen und ist in der Lage, sämtliche Farbtiefen und Auflösungen zwischen 320200 und 768512 (Overscan) darzustellen, wobei die Auflösungen mit mehr als 240 Zeilen im Interlace-Modus, das heißt, mit halber Frequenz und zwei Halbbildern, dargestellt werden. Es ist somit auch möglich, ST-Programme, die nur bei 640*400 Pixeln laufen, auf einem normalen RGB-Monitor weiter zu benutzen, aber leider nur flimmernd interlaced.
Der Fernseher stellt übrigens genau die gleichen Videomodi wie ein RGB-Monitor dar - und entsprechend auch interlaced. Auch der liebgewonnene monochrome Monitor SM 124 kann über diesen Adapter angeschlossen werden und zeigt sich im gewohnt flimmerfreien 71 Hz-640400-Pixel-Gewand. Die Neuerung auf diesem Sektor besteht in der Möglichkeit, einen VGA-Monitor über einen anderen Adapter anzuschließen und somit die hohen Auflösungen ohne Interlace darzustellen. Will man aber niedrigere Auflösungen, wie z.B. 640240, benutzen, wird aufgrund der festen Frequenzen einfach jede Zeile verdoppelt, und die Pixel erscheinen doppelt so hoch. Die festen Frequenzen haben leider auch einen entscheidenden Nachteil: die normalen VGA-Monitore sind nicht in der Lage, höhere Auflösungen als 640*480 Pixel anzuzeigen, es sei denn, man benutzt Grafikerweiterungen oder leistet sich den Luxus eines Multisync-Monitors (ab 15KHz Zeilenfrequenz), auf dem man sämtliche Auflösungen und Farbtiefen, die der Falcon im Stande ist zu produzieren, hervorzaubern kann. Ja, noch mehr, man kann sogar die Bildfrequenz im VGA-Betrieb durch Abändern eines Videoregisters auf etwa 78Hz erhöhen, was man aber auf jeden Fall auf einem Multisync-Monitor ausprobieren sollte, weil andere Monitore sich schmollend mit einer Rauchfahne verabschieden könnten.
Im übrigen läßt sich die gesamte Video-Hardware relativ frei programmieren, was aber, wie schon gesagt, zu unschönen Nebeneffekten führen kann. Es ist zum Beispiel möglich, in gewissen Grenzen die horizontale und vertikale Auflösung, die Frequenz sowie die Lage des Bildes in feinen Schritten abzuändem, was aber alles nicht vom Betriebssystem unterstützt wird und somit nur dem „Hacker“ Vorbehalten bleibt. ATARI selbst macht sich diese Register zunutze, um auf einem VGA-Monitor in den Kompatibilitätsmodi die Zeilenzahl auf 200 bzw. 400 Zeilen zu reduzieren und die Lage des Bildes entsprechend anzupassen.
Obwohl der Falcon genauso wie der TT mit einem 68030-Prozessor ausgestattet ist, wird er anstatt mit 32 nur mit 16 MHz getaktet, was sich besonders bei rechenintensiven und stark grafiklastigen Programmen bemerkbar macht. Da der Bildschirmspeicher in gewissen Modi sogar bis zu 720 KB groß wird, kommt der Speicherbus ganz schön ins Schwitzen und verlangsamt den Speicherzugriff der CPU doch merklich, wenn das Programm nicht auf den internen Prozessor-Cache optimiert ist. Auch der nun mit 16 MHz getaktete Blitter kann dieses Manko nicht beheben, weil er, wie bekannt, nur einige wenige Aufgaben im System übernimmt und demzufolge nicht übermäßig zur Performance-Steigerung beitragen kann. Des weiteren können der Prozessor und der Blitter leider nicht parallel auf den Speicher zugreifen, was zur Folge hat, daß, während der Blitter aktiv ist, der Prozessor sich nur mit dem Programmstück im 256-Byte-Cache beschäftigen kann und ansonsten auf Eis liegt, was seine Möglichkeiten betrifft, mit der Außenwelt zu kommunizieren.
Um aus dem recht flügellahmen „Flattermann“ dennoch einen pfeilschnellen Gesellen zu machen, muß man sich in die Tiefen der Maschinensprache begeben und optimierten Programmcode erstellen, der die Fähigkeit des Prozessors ausnutzt, kleine Programmschleifen im Cache besonders schnell abzuarbeiten. Gerade im Grafikbereich machen sich solche Assembler-Routinen sofort bezahlt, und der Erfolg wird direkt „sichtbar“.
Auch wenn es nicht zum sauberen, auflösungsunabhängigen Stil konform ist, läßt sich durch direktes Beschreiben des Video-RAMs eine enorme Ausgabegeschwindigkeit erzielen. Diese Methode setzt natürlich voraus, daß das Programm nur in dem speziellen Videomodus arbeitet, für den es geschrieben wurde. Solche Praktiken finden sehr häufig in Spielen, Grafik-Demos, schnellen Malprogrammen und ähnlichem Anwendung.
Der Falcon030 bietet zwei verschiedene Arten der Bildschirmorganisation an: zum einen die vom ST bekannte Interleaved-Bitplane-Organisation mit variabler Anzahl von Planes (1,2,4 und neu 8) und zum anderen die Pixel-Packed-Organisation.
Im Plane-Modus wird die Farbe des Bildpunktes wie folgt bestimmt: Die Anzahl der Planes gibt die Anzahl der aufeinanderfolgenden Speicher Wörter an, die für jeweils 16 Pixel relevant sind. Die Bit-Kombination der jeweils gleichwertigen Bits in diesen Wörtern bildet einen Zeiger auf die entsprechende Stelle in der Farbtabelle. Der an dieser Stelle stehende RGB-Wert bestimmt schließlich die Farbe des Bildschirmpunktes. Wie man leicht sieht, bestimmt die Anzahl der Planes auch die Anzahl der maximal gleichzeitig darstellbaren Farben, somit auch die Anzahl der gültigen Tabelleneinträge. Die Bit-Länge eines Tabelleneintrages wiederum bestimmt das Spektrum der Farben, aus denen man sich die aktuelle Farbpalette zusammenstellen kann. Im konkreten Fall, mit beispielsweise 8 Bitplanes, ergeben sich 28 = 256 mögliche Bit-Kombinationen pro Pixel, also eine maximale Zahl von 256 verschiedenen Farben. Bei einer Eintragslänge von 32 Bit, wobei hier, wie in der Skizze angegeben, aber nur 18 Bit verwendet werden, kann man sich diese 256 Farben also aus einer Gesamtpalette von 218 = 262144 Farben aus wählen. Es ist aber durchaus anzunehmen, daß die in der Skizze jeweils als unbenutzt deklarierten unteren 2 Bit eines Farbanteils in späteren Modellen der Falcon-Serie noch Verwendung finden und ein Farbspektrum von 224 = 16.7 Mio. Farben ermöglichen. Das Beschreiben dieser Bits hat beim Falcon030 keine negativen Auswirkungen und kann daher mit ruhigem Gewissen getan werden. Den Programmierern bietet diese Reserve die Möglichkeit, alle Berechnungen schon heute mit 16.7 Mio. Farben durchzuführen und die Programme bereits für später zu rüsten, ohne nachträglich diese Option einbauen zu müssen.
In der Pixel-Packed-Organisation gibt es keine Palettenregister mehr, und auch die Informationen zu einem Pixel sind nicht mehr auf mehrere Wörter verteilt, sondern befinden sich alle in einem einzigen Wort. Der Farbwert eines Pixels bestimmt sich, wie in dem Schema angegeben, also direkt aus der in diesem Wort codierten Farbe. Die Anzahl der maximal gleichzeitig darstellbaren Farben beträgt somit 216 = 65536; sie sind aber nicht aus einem größeren Spektrum wählbar und dadurch auf genau diese 65536 Farbwerte festgelegt. Nachteilig macht sich das vor allen Dingen bei Bildern bemerkbar, die viele Abstufungen einer Farbe benötigen, oder auch bei Graustufenbildern, denn in diesem Modus stehen nur 25 = 32 Abstufungen einer Farbe (mit Außnahme von purem Grün: 26 = 64) zur Verfügung. Im 256-Farben-Modus besteht die Auswahl immerhin aus 26 = 64 Abstufungen einer Farbe. Im Pixel-Packed-Modus hat ATARI die interessante Möglichkeit offengelassen, nur 15 statt der 16 Bit zur Farbcodierung zu benutzen und das übrige Bit, wie in der Abbildung angegeben, als sogenannten Chroma-Key zu verwenden (Overlay-Modus). Im Klartext bedeutet das, daß „nur“ noch 32768 Farben darstellbar sind, aber dafür wird bei den Wörtern, die dieses Overlay-Bit nicht gesetzt haben, der zugehörige Bildschirmpunkt durch ein externes Videosignal ersetzt. Das dient zum Beispiel der Videotiteleinblendung oder einfach nur zum Ersetzen des Desktop-Hintergrandes durch ein Fernsehbild, auf dem man seine Icons ablegen kann. Die technische Realisierung ist ganz simpel, denn das Overlay-Bit liegt einfach an einem Pin am Monitorausgang des Falcon an und ändert sich entsprechend im Pixel-Takt.
Wie so vieles, haben auch die beiden Bildschirmorganisationen ihre Vor- und Nachteile. Die Organisation des Bildschirms in Planes besticht besonders durch die Möglichkeit, nur einzelne Planes abzuändern, um beispielsweise Objekte auf den Bildschirm zu bringen, deren Farben man schon durch Setzen weniger Planes ansprechen kann, oder durch die Möglichkeit, die einzelnen Planes unabhängig voneinander scrollen zu können, was man häufig in Spielen sieht. Durch das Plane-Prinzip existieren nur Zeiger auf die Farbregister, so daß eine Änderung eines Palettenregisters sofortige Auswirkungen auf alle Pixel hat, die ihre Farbe aus diesem Register beziehen. Man muß also keine großartigen Operationen im Screen-RAM anstellen, um z.B den Bildschirminhalt langsam auszublenden. Auch zum Speicherplatzsparen ist die Plane-Anordnung geeignet, da in der Regel die Zeiger auf die Register kleiner sind als die zugehörigen Farbwerte an sich (z.B 4 Bit Zeiger aber 18 Bit Farbwert). Der entscheidende Nachteil der Plane-Struktur besteht in der großen Anzahl der Bit-Operationen, wenn man nur wenige Pixel ändern will (z.B müßte man im 8-Plane-Modus 8 Bits aus 8 Wörtern ändern, nur um ein einziges Pixel zu setzen). ATARI hat es leider auch versäumt, eine andere Plane-Anordnung anzubieten als die benutzte Interleave-Struktur (alle Planes sind ineinander verzahnt). Sinnvoll wäre eine getrennte Ablage der Planes im Speicher, am besten noch mit unabhängigen Adreßzeigern, die eine extrem komfortable Behandlung der einzelnen Planes ermöglichen würden.
Die Einführung des Packed-Pixel-Modus’ (Directcolor) birgt eine Unmenge an neuen Möglichkeiten der Bildmanipulation. Durch die Verbindung eines Pixels mit genau einem Wort öffnen sich die Tore zur schnellen Pixel-Zauberei. Es bietet sich geradezu an, in diesem Modus Vektorgrafiken oder riesige Sprites, die nunmehr keiner Verknüpfung mit dem Hintergrund mehr bedürfen, darzustellen. Auch Malprogramme werden schneller in den Pixel-Operationen, und die Probleme inkompatibler Paletten gehören genauso der Vergangenheit an, da es ja hier keine mehr gibt. Auch hier hätte ATARI noch Erweiterungen anbringen können, denn 16 Bit pro Pixel sind relativ viel und kosten somit eine Menge Speicher (bis zu 720 KB). Ein zusätzlicher Packed-Pixel-Modus mit 8 Bit pro Pixel, wie auf dem PC, wäre noch sehr schön gewesen, und je nach Anwendung hätte man zwischen Bitplanes und Directcolor wählen können. Ein weiterer Haken neben dem großen Speicherbedarf ist die aufwendige Farbänderung mehrerer Pixel gleichzeitig, um z.B auszublenden oder nachträglich Kontraste anzugleichen.
ATARI selbst empfiehlt, daß Spiele in der VGA-Auflösung 640480 bei 256 Farben laufen sollten. Bei Start auf einem RGB-Monitor würde man 80 Zeilen verlieren und wegen der unumgänglichen Interlace-Darstellung bald Kopfschmerzen bekommen. Vernünftiger auch im Sinne der Geschwindigkeit (ein Viertel des Speicherbedarfs) ist die niedrigere Auflösung von 320240 bei 256 oder 65536 Farben, wobei man in den unteren 40 Zeilen am besten nur Ziergrafik darstellt, weil sie auf dem RGB-Monitor sowieso nicht mehr zu sehen sind. Daß diese Auflösung ausreichend ist, beweisen jede Menge PC-Spiele, die fast alle in 320*200 laufen, es kommt halt nur auf die Farben an, die der Falcon ja zur Genüge besitzt.
Die neuen Grafikfähigkeiten des Falcon verlangen natürlich auch nach einer entsprechenden Unterstützung durch das Betriebssystem. Im Falcon-TOS befinden sich deshalb eine Reihe neuer XBIOS-Aufrufe, die es dem Anwender leichter machen, mit dem neuen Grafiksystem umzugehen. Man sollte so weit wie möglich diese vom TOS bereitgestellten Hilfsmittel auch benutzen, da eine direkte Programmierung der undokumentierten Register zu Inkompatibilitäten mit noch kommenden Rechnern führen kann. Das Argument des Geschwindigkeitsgewinns bei direktem Beschreiben der Register ist leicht außer Kraft zu setzen, denn selbst in Spielen, wo Geschwindigkeit eine sehr große Rolle spielt, braucht man die XBIOS-Aufrufe nur bei der Programminitialisierung, die nun wirklich nicht von der Geschwindigkeit abhängig ist. Eine Übersicht dieser Aufrufe befindet sich im abgedruckten Kasten.
Der Programmierer sollte aber auf jeden Fall darauf achten, daß sein Programm sich vor dem Benutzen der neuen XBIOS-Funktionen und der erweiterten Grafikfähigkeiten darüber informiert, ob der Rechner überhaupt mit diesen Fähigkeiten ausgestattet ist. Die nötigen Informationen darüber erhält er aus dem Video-Cookie, der im Falle des Falcons 030 den Inhalt 0x00030000 besitzt.
Abwärtskompatible Erweiterung des bekannten Setscreen-Aufrufs, um die neuen Auflösungen und Farbtiefen des Falcons abzudecken. Bei Aufruf werden automatisch der Bildschirmspeicher angepaßt und das VDI neu initialisiert, doch leider wird das P-Flag hier nicht richtig ausgewertet und am RGB-Monitor immer in den PAL-Modus geschaltet. Das V-Flag führt hier nicht, wie erwartet, zu VGA-Signalen, sondern nur zur Uminterpretierung des F-Flags. Auch das Reallozieren des Bildschirmspeichers klappt nicht für alle Umschaltungen, man sollte das besser selbst in die Hand nehmen und für phys und log eigene Adressen angeben.
Aufrufschema in C:
Setscreen(LONG log, LONG phys, WORD rez, WORD mode)
C-Binding:
#define Setscreen(a,b,c,d) (WORD)XBIOS(5,a,b,c,d)
Eingabeparameter:
log: Startadresse des logischen Bildschirmspeichers (-1 = keine Änderung)
phys: Startadresse des physikalischen Bildschirmspeichers (-1 = keine Änderung), im Normalfall stimmen log und phys überein
rez = 0: ST-Niedrig
1: ST-Mittel
2: ST-Hoch
3: benutze Auflösung aus mode
mode: modecode (siehe Vsetmode)
Rückgabewert:
keiner
Schaltet den Falcon in den angegebenen Videomodus, aber ohne das VDI neu zu initialisieren und den Bildschirmspeicher anzugleichen. Hier werden im Gegensatz zu Setscreen das P- und V-Flag richtig ausgewertet.
Aufrufschema in C:
return = Vsetmode(WORD modecode)
C-Binding:
#define Vsetmode(a) (WORD)XBIOS(88,a)
Eingabeparameter:
modecode = XXXX XXXF SOPV 8NNN (Bit-Vektor)
(-1 ändert nichts, liefert nur den aktuellen modecode)
X: reserviert
F: Vertical-Flag. 1 = Interlace-Modus an (RGB/TV), Zeilenverdopplung an (VGA)
S: ST-Kompatibilitäts-Flag. 1 = ST-kompatibel
O: Overscan-Flag. 1 = an (Breite u. Höhe *1.2, RGB/TV) bei VGA nur zentrierter Normalausschnitt sichtbar
P: PAL-Flag. 1 = PAL(50Hz) 0 = NTSC(60Hz)(nur RGB/TV)
V: VGA-Flag. 1 = VGA-Monitorsignale(60Hz), sonst RGB/TV
8: 80-Spalten-Flag. 1 = 80 Spalten (640 Pixel), 0 = 40 Spalten (320 Pixel)
NNN: Bits per Pixel 0 - 1 Bitplane (2 col.)
(Unsinnige Kombinationen werden nicht abgefangen!)
ATARI hat folgende Konstanten zur leichteren Bildung von modecode definiert:
#define VERTFLAG 0x100
#define STMODES 0x80
#define OVERSCAN 0x40
#define PAL 0x20
#define VGA 0x10
#define TV 0x0
#define COL80 0x08
#define COL40 0x0
#define BPS16 4
#define BPS8 3
#define BPS4 2
#define BPS2 1
#define BPS1 0
#define NUMCOLS 7 ; Maske für die Anzahl der Planes
z.B: modecode = VGA|COL80|BPS8 oder if (modecode & NUMCOLS)== BPS16 do_something();
Rückgabewert:
alter modecode (zum Zurückschreiben bei Programmende!)
Ermittelt den angeschlossenen Monitortyp anhand von Pin 18(M1) und 19(M0) des Video-Ports. Ein 0-Bit bedeutet Masse am entsprechenden Pin, ein 1-Bit bedeutet keine Verbindung.
Aufrufschema in C:
return = mon_type(void)
C-Binding:
#define mon_type() (WORD)XBIOS(89)
Eingabeparameter:
keine
Rückgabewert:
0 = ST-Monochrommonitor (M1:0 M0:0)
1 = ST-Farbmonitor (M1:0 M0:1)
2 = VGA-Monitor (M1:1 M0:0)
3 = TV (Video-Port frei) (M1:1 M0:1)
Bestimmt, ob die Video-Hardware extern anliegende Synchronisationssignale benutzen soll oder nicht. Funktioniert nicht im Kompatibilitätsmodus oder in den 4-Farben-Modi des Falcon.
Aufrufschema in C:
VsetSync(WORD external)
C-Binding:
#define VsetSync(a) (void)XBIOS(90,a)
Eingabeparameter:
external = 0000 Ohvc (Bit-Vektor)
0: reserviert
h: 1 = verwende externe Horizontalsynchronisation
v: 1 = verwende externe Vertikalsynchronisation
c: 1 = verwende externen Videotakt
Rückgabewert:
keiner
Liefert die Größe des Bildschirmspeichers des durch mode codierten Videomodus1, um z.B eine 2. Bildschirmseite anzulegen.
Aufrufschema in C:
return = VgetSize(WORD mode)
C-Binding:
#define VgetSize(a) (LONG)XBIOS(91,a)
Eingabeparameter:
mode: Videomodus (siehe Vsetmode)
Rückgabewert:
Größe des benötigten Bildschirmspeichers in Bytes
Ändert einen bestimmten Bereich der Palettenregister auf die angegebenen Farben ab. GEM-Programme sollten aber, um nur eine Farbe zu ändern, auf vs_color() des VDI zurückgreifen.
Aufrufschema in C:
VsetRGB(WORD index, WORD count, LONG array)
C-Binding:
#define VsetRGB(a,b,c) (void)XBIOS(93,a,b,c)
Eingabeparameter:
index: Nummer des Palettenregisters, mit dem begonnen wird (0-255)
count: Anzahl der zu setzenden Register (1-256)
array: Zeiger auf ein Long-Feld mit den zu setzenden Farben. Das Format der Farben weicht etwas vom Hardware-Format (siehe Abbildung) ab. Anstelle von RRGGXXBB nimmt man XXRRGGBB, aber die Bit-Belegung (nur 6 von 8 Bit) der Intensitäten bleibt die gleiche.
Rückgabewert:
keiner
Kopiert die RGB-Werte eines bestimmten Bereiches der Palettenregister in ein angegebenes Feld. GEM-Programme sollten auch hier besser auf vq_color() des VDI zurückgreifen
Aufrufschema in C:
VgetRGB(WORD index, WORD count, LONG array)
C-Binding:
#define VgetRGB(a,b,c) (void)XBIOS(94,a,b,c)
Eingabeparameter:
index: Nummer des Palettenregisters, mit dem begonnen wird (0-255)
count: Anzahl der zu lesenden Register (1-256)
array: Zeiger auf ein Long-Feld, in das die gelesenen Farben abgelegt werden. Das Format der Farben entspricht dem in VsetRGB angegebenen Format.
Rückgabewert:
keiner
Bestimmt die and- und or-Maske des VDI beim Setzen von Farbregistern per vs_color. Bei einem Aufruf von vs_color wird der angegebene Farbwert zuerst mit andmask logisch-UND-, danach mit ormask logisch-OR-verknüpft. Damit ist es möglich, eine beliebige Farbe als transparent bezüglich eines hinzugemischten Videosignals zu deklarieren (Overlay-Bit). Der Aufruf darf logischerweise nur im Direct-Color-Betrieb erfolgen und schaltet das System automatisch in den Overlay-Modus.
Aufrufschema in C:
VsetMask(WORD andmask, WORD ormask)
C-Binding:
#define VsetMask(a,b) (void)XBIOS(150,a,b)
Eingabeparameter:
andmask: Die 16 Bit-breite UND-Maske (Default = 0xFFFF)
ormask: Die 16 Bit-breite OR-Maske (Default = 0x0000)
Die Default-Werte bewirken keine Änderung der Farben.
Rückgabewert:
keiner
Für die Assembler-Programmierer: Um die XBIOS-Aufrufe in Assembler zu nutzen, müssen die Eingabeparameter in umgekehrter Reihenfolge auf dem Stack abgelegt und mit der XBIOS-Funktionsnummer abgeschlossen werden, z.B Setscreen:
move.w mode,-(sp)
move.w rez,-(sp)
move.l phys,-(sp)
move.l log,-(sp)
move.w #5,-(sp)
trap #14
lea 14(sp),sp
...
...
mode: dc.w %100101011 ;640*400 256col. 50Hz
rez: dc.w 3
phys: dc.l -1
log: dc.l -1
Wie bekannt, ist alle Theorie grau, deswegen soll anhand des kleinen Programmes der Falcon sich mal von seiner bunten Seite zeigen. Es handelt sich um eine kleine Sprite-Routine, die im Directcolor-Modus eine einstellbare Anzahl von Bällen über den Bildschirm fliegen läßt. Der Hintergrund besteht aus 5 horizontalen Farbbalken in jeweils verschiedenen Farben. Die Sprites retten vor dem Setzen den Hintergrund und restaurieren ihn später in umgekehrter Reihenfolge wieder, damit bei Überschneidungen mehrerer Sprites keine Fehler auftreten. Vor dem eigentlichen Programmteil befindet sich der interessante Teil der Systeminitialisierung, bei der die kleinen Fehler des Setscreen-Aufrufes durch ein paar Vorkehrungen umgangen werden. So werden das P-Flag durch den nachfolgenden Vsetmode-Aufruf doch noch ausgewertet und das Problem der fehlerhaften Bildschirmspeicheranpassung durch einen eigenen malloc-Aufruf aus der Welt geschafft. Während der Initialisierung wird außerdem getestet, ob es sich wirklich um einen Falcon030-Computer handelt und ob auch ein Farbmonitor oder Fernseher angeschlossen ist. Die maximale Zeilenzahl wird entsprechend der Monitorart ermittelt und für das Programm zur Verfügung gestellt, damit es die Grafik richtig anpassen kann. Obwohl es in der Directcolor-Betriebsart keine Farbpalette gibt, läßt sich die Hintergrundfarbe (Rahmenfarbe) trotzdem ändern, indem man das erste Farbre-gister per VsetRGB oder direkt an $FFFF9800 abändert. Im Programm wird der Rahmen einfach auf Schwarz geschaltet und nach Programmabbruch wieder zurück in die bisherige Rahmenfarbe. Das vorliegende Programm ist vollständig in Assembler geschrieben und benutzt an 2 Stellen 68030er-Code (mulu.l). Achten Sie also darauf, Ihren Assembler im 68030cr-Modus laufen zu lassen oder die entsprechenden Stellen anders zu programmieren, falls Ihr Assembler keine 68030er-Befehle versteht. Wer hier einen hochoptimierten Programmcode erwartet, der zahllose Sprites in einem Bildschirmaufbau darstellt, ist auf der falschen Fährte, da mehr Wert auf die grundsätzliche Programmierung des Videosystems und die Programmkürze gelegt wurde.
Mit all diesen Informationen zur Video-Hardware dürfte der Programmierer nun in der Lage sein, dem Falcon die buntesten Farben und schönsten Grafiken zu entlocken. Wie wäre es z.B. mit einem Genlock-Titelgenerator für den Hobby-Videofilmer in der Overscan-Auflösung mit 32768 Farben und verschiedenen Ein- und Ausblen-deffekten, Trickfilmspielereien, Titelbildgestaltung, und das natürlich alles mit der entsprechenden Sound-Untermalung durch das Sound-Sub-System? Ihrer Kreativität sind keinerlei Grenzen gesetzt, und der Falcon unterstützt Sie tatkräftig dabei, sie zu entfalten.
Literatur:
[1] Falcon030 Developer Documentation, October 30th 1992, ATARI
SM124 (71 Hz)
Auflösung | Interlace | Farben/Palette | Speicherbedarf |
---|---|---|---|
640*400 | nein | Monochrom | 32000 Bytes |
RGB/TV (50/60 Hz)
Auflösung | Interlace | Farben/Palette | Speicherbedarf |
---|---|---|---|
320*200 | nein | 4/4096 | 16000 Bytes |
320*200 | nein | 16/262144 | 32000 Bytes |
320*200 | nein | 256/262144 | 64000 Bytes |
320*200 | nein | 65536/keine | 128000 Bytes |
384*240 | nein | 4/4096 | 23040 Bytes |
384*240 | nein | 16/262144 | 46080 Bytes |
384*240 | nein | 256/262144 | 92160 Bytes |
384*240 | nein | 65536/keine 184320 Bytes | |
640*200 | nein | 2/262144 | 16000 Bytes |
640*200 | nein | 4/4096 | 32000 Bytes |
640*200 | nein | 16/262144 | 64000 Bytes |
640*200 | nein | 256/262144 | 128000 Bytes |
640*200 | nein | 65536/keine | 256000 Bytes |
768*240 | nein | 2/262144 | 23040 Bytes |
768*240 | nein | 4/4096 | 46080 Bytes |
768*240 | nein | 16/262144 | 92160 Bytes |
768*240 | nein | 256/262144 | 184320 Bytes |
768*240 | nein | 65536/keine | 368640 Bytes |
320*400 | ja | 4/4096 | 32000 Bytes |
320*400 | ja | 16/262144 | 64000 Bytes |
320*400 | ja | 256/262144 | 128000 Bytes |
320*400 | ja | 65536/keine 256000 Bytes | |
384*480 | ja | 4/4096 | 46080 Bytes |
384*480 | ja | 16/262144 | 92160 Bytes |
384*480 | ja | 256/262144 | 184320 Bytes |
384*480 | ja | 65536/keine | 368640 Bytes |
640*400 | ja | 2/262144 | 32000 Bytes |
640*400 | ja | 4/4096 | 64000 Bytes |
640*400 | ja | 16/262144 | 128000 Bytes |
640*400 | ja | 256/262144 | 256000 Bytes |
640*400 | ja | 65536/keine | 512000 Bytes |
768*480 | ja | 2/262144 | 46080 Bytes |
768*480 | ja | 4/4096 | 92160 Bytes |
768*480 | ja | 16/262144 | 184320 Bytes |
768*480 | ja | 256/262144 | 368640 Bytes |
768*480 | ja | 65536/keine | 737280 Bytes |
VGA (60 Hz)
Auflösung | Zeilenverdoppl. | Farben/Palette | Speicherbedarf |
---|---|---|---|
320*200 | ja | 16/4096 | 32000 Bytes |
320*240 | ja | 4/4096 | 19200 Bytes |
320*240 | ja | 16/262144 | 38400 Bytes |
320*240 | ja | 256/262144 | 76800 Bytes |
320*240 | ja | 65536/keine | 153600 Bytes |
640*200 | ja | 4/4096 | 32000 Bytes |
640*240 | ja | 2/262144 | 19200 Bytes |
640*240 | ja | 4/4096 | 38400 Bytes |
640*240 | ja | 16/262144 | 76800 Bytes |
640*240 | ja | 256/262144 | 153600 Bytes |
320*480 | nein | 4/4096 | 38400 Bytes |
320*480 | nein | 16/262144 | 76800 Bytes |
320*480 | nein | 256/262144 | 153600 Bytes |
320*480 | nein | 65536/keine | 307200 Bytes |
640*400 | nein | 2/4096 | 32000 Bytes |
640*480 | nein | 2/262144 | 38400 Bytes |
640*480 | nein | 4/4096 | 76800 Bytes |
640*480 | nein | 16/262144 | 153600 Bytes |
640*480 | nein | 256/262144 | 307200 Bytes |
_p_cookies equ $5a0 ;Systemvariable F30_val equ $00030000 ;Video-Cookie
; VGA-modecode 320*240 bei 65536 col. modeVGA equ %100010100
;RGB/TV-modecode 320*200 bei 65536 col. modeRGB equ %000100100
anz_spr equ 25 ;Spritezahl variabel
text
; Erstmal den unbenutzten Speicher freigeben move.l 4(sp),a0 ;Basepage lea newstack,sp move.l #$100,d0 ;Länge Basepage add.l $c(a0),d0 ;Länge Textseg. add.l $14(a0),d0 ;Länge Datenseg. add.l $1c(a0),d0 ;Länge BSS move.l d0,-(sp) ;Programmlänge move.l a0,-(sp) ;Basepagestart clr.w -(sp) ;Füllwert move.w #$4a,-(sp) ;Mshrink trap #1 lea 12(sp),sp
;schalte in den Supervisor-Modus des Prozessors clr.l -(sp) ;neuer SSP=USP move.w #$20,-(sp) ;Super trap #1 addq.l #6,sp move.l d0,oldstack ;rette alten SSP
;Haben wir wirklich einen Falcon 030? lea _p_cookies.w,a0 ;CookieJar Vektor move.l (a0),a0 ;Adresse des Jar beq.s failure ;keiner da! move.l #'_VDO',d0 ;Suche Video-Keks search_cookie: tst.l (a0) ;Ende der Liste? beq.s failure ;also kein Falcon lea 8(a0),a0 ;hinter Cookie cmp.l -8(a0),d0 ;Video-Cookie? bne.s search_cookie ;weiter suchen cmp.l #F30_val,-4(a0) ;Falcon-Video? beq.s found_cookie ;juhu
;Fehler: kein Falcon, Mono oder low memory failure: pea fail_text ;Meldung ausgeben move.w #9,-(sp) trap #1 addq.l #6,sp
move.l oldstack,-(sp) ;zurück in User
move.w #$20,-(sp) ;Super
trap #1
;keine Stack-Korrektur nötig
move.w #1,-(sp) ;Cconin
trap #1 ;warte auf Taste
addq.l #2,sp
clr.w -(sp) ;Pterm0
trap #1 ;Ciao Amigo
; Schalte in den richtigen Video-Modus um found_cookie:
;rette alten modecode
move.w #-1,-(sp) ;get modecode
move.w #88,-(sp) ;Vsetmode
trap #14
addq.l #4,sp
move.w d0,oldmode ;rette modecode
;rette alte Bildschirmspeicher
move.w #2,-(sp) ;Physbase
trap #14
addq.l #2,sp
move.l d0,oldphys
move.w #3,-(sp) ;Logbase
trap #14
addq.l #2,sp
move.l d0,oldlog
;welcher Monitor ist angeschlossen?
move.w #89,-(sp) ;mon_type
trap #14
addq.l #2,sp
tst d0 ;Monochrome?
beq.s failure ;dann raus
cmp.w #2,d0 ;VGA?
beq.s VGA_init ;yo, lucky guy
RGB_init:
move.w #modeRGB,d0 ;übergib modecode
bsr.s scr_allocate ;reserviere RAM
move.w #modeRGB,-(sp) ;neue Auflösung
move.w #3,-(sp)
move.l screen1,-(sp) ;neuer physbase
move.l screen2,-(sp) ;neuer logbase
move.w #5,-(sp) ;Setscreen
trap #14
lea 14(sp),sp
;um den PAL/NTSC-Bug zu beheben: Vsetmode
;denn Setscreen mißachtet das P-Flag
move.w #modeRGB,-(sp) ;gleiche modecode
move.w #88,-(sp) ;Vsetmode
trap #14
addq.l #4,sp
move.w #199,y_max ;200 Zeilen
bra go_on
VGA_init:
move.w #modeVGA,d0 ;übergib modecode
bsr.s scr_allocate ;reserviere RAM
move.w #modeVGA,-(sp) ;neue Auflösung
move.w #3,-(sp)
move.l screen1,-(sp) ;neuer physbase
move.l screen2,-(sp) ;neuer logbase
move.w #5,-(sp) ;Setscreen
trap #14
lea 14(sp),sp
move.w #239,y_max ;240 Zeilen
bra go_on
;Speicherplatz fur 2 Screens reservieren scr_allocate: ;berechne Größe des Bildschirms move.w d0,-(sp) ;modecode move.w #91,-(sp) ;VgetSize trap #14 addq.l #4,sp move.l d0,d6 ;Größe retten lsl.l #1,d0 ;nimm 2 add.l #1,d0 ;even-redundanz
;Speicher für 2 Bildschirme reservieren
move.l d0,-(sp) ;Größe d. Screens
move.w #$48,-(sp) ;Malloc
trap #1
addq.l #6,sp
tst d0
beq failure ;zu wenig RAM
addq.l #1,d0
and.l #$fffffffe,d0 ;even address!
move.l d0,screen1 ;1. Bildschirm
add.l d6,d0
move.l d0,screen2 ;2. Bildschirm
rts
;hierhin wird hex einem Tastendruck gesprungen quit: pea mausan ;Maus einschalten clr.w -(sp) ;1 Byte senden move.w #$19,-(sp) ;Ikbdws trap #14 addq.l #8,sp
;setze alte Rahmenfarbe
pea oldcolor ;neue Farbe
move.w #1,-(sp) ;nur 1 Farbe
clr.w -(sp) ;Hintergrundcolor
move.w #93,-(sp) ;VsetRGB
trap #14
lea 10(ep),sp
move.w oldmode,-(sp) ;alte Auflösung
move.w #3, -(sp)
move.l oldphys,-(sp) ;alter Screen
move.l oldlog,-(sp)
move.w #5,-(sp) ;Setscreen
trap #14
lea 14(sp),sp
;um den PAL/NTSC-Bug zu beheben: Vsetmode
;denn Setscreen mißachtet das P-Flag
move.w oldmode,-(sp) ;gleiche modecode
move.w #88,-(sp) ;Vsetmode
trap #14
addq.l #4,sp
move.l oldstack,-(sp) ;zurück in User
move.w #$20,-(sp) ;Super
trap #1
;keine Stack-Korrektur nötig
clr.w -(sp) ;asta la vista
trap #1 ;...baby
;Endlich im richtigen Videomodus! ;Hier kommt jetzt das eigentliche Programm go_on:
;rette alte Rahmenfarbe
pea oldcolor ;savebuffer
move.w #1,-(sp) ;nur 1 Farbe
clr.w -(sp) ;Hintergrundfarbe
move.w #94,-(sp) ;VgetRGB
trap #14
lea 10(sp),sp
;setze neue Rahmenfarbe
pea newcolor ;neue Farbe
move.w #1,-(sp) ;nur 1 Farbe
clr.w -(sp) ;Hintergrundfarbe
move.w #93,-(sp) ;VsetRGB
trap #14
lea 10(sp),sp
pea mausaus ;Maus ausschalten
clr.w -(sp) ;1 Byte senden
move.w #$19,-(sp) ;Xkbdws
trap #14
addq.l #8,sp
bsr prepare_screens ;Hintergrund-gfx
bsr init_koords ;Spritedaten init
main_loop:
bsr clear_sprites ;lösche Sprites
bsr calc_koords ;neue Koordinaten
bsr draw_sprites ;zeige Sprites
;wiederhole solange bis Tastendruck
move.w #$ff,-(sp) ;Taste gedruckt?
move.w #6,-(sp) ;Crawio
trap #1
addq.l #4,sp
tst d0 ;Taste?
bne quit ;ja, dann raus
;warte auf den nächsten Bildschirmaufbau
move.w #37,-(sp) ;Vsync
trap #14
addq.l #2,sp
;tausche 2 Bildschirme und Spritebuffer
move.l screen1,d0 ;tausche Screen
move.l screen2,screen1
move.l d0,screen2
move.l sprbuff1,d0 ;tausche Buffer
move.l sprbuff2,sprbuff1
move.l d0,sprbuff2
move.w #—1,—(sp) ;keine Änderung
move.l screen1,-(sp) ;anderer Screen
move.l screen2,-(sp)
move.w #5,-(sp) ;Setscreen
trap #14
lea 12(sp),sp
bra.s main_loop
;Den Sprites werden zufällige Koordinaten ;und zufällige Richtung mitgegeben init_koords: lea koordtab(pc),a6 ;x,y für Sprites move.w y_max,d6 ;untere Grenze sub #14,d6 ;Sprite-Höhe move.w #anz_spr-1,d7 ;Zähler moveq #0,d5 ;Puffer init_loop: bsr.s random move.b d0, d5 move.w d5,(a6)+ ;x-Koordinate move.w #1,(a6)+ ;erstmal rechts btst #0,d0 ;Zufallsrichtung beq.s .right move.w #-1,-2(a6) ;doch nach links .right: bsr.s random move.b d0,d5 cmp.w d6,d5 ;zu tief? ble.s .in_range ;nein sub.w #70,d5 ;angleichen .in_range: move.w d5,(a6)+ ;y-Koordinate move.w #1,(a6)+ ;erstmal runter btst #0,d0 ;Zufallsrichtung beq.s .down move.w #-1,-2(a6) ;doch nach oben .down: dbra d7,init_loop
move.l #-1,buffer1 ;init clear_sprite
move.l #-1,buffer2
rts
random:
;liefert in d0 24 Bit Zufallszahl
move.w #$11,-(sp)
trap #14
addq.l #2,sp
rts
;Die Spritekoordinaten werden auf den neusten ;Stand gebracht und evtl. Richtungsänderungen ;an den Rändern durchgefuhrt calc_koords: lea koordtab(pc),a0 move.w y_max,d4 ;unterer Rand sub #14,d4 move.w #anz_spr-1,d7 .fly_loop: movem.w (a0),d0-d3 ;alle Infos
tst d0 ;linker Rand?
bne.s .mayberight
moveq #1,d1 ;nach rechts
bra.s .calc_x
.mayberight:
cmp.w #320-15,d0 ;rechter Rand?
bne.s .calc_x
moveq #-1,d1 ;nach links
.calc_x:
add d1,d0
tst d2 ;oberer Rand?
bne.s .maybeup
moveq #1,d3 ;nach unten
bra.s .calc_y
.maybeup:
cmp.w d4,d2 ;unterer Rand?
bne.s .calc_y
moveq #-1,d3 ;nach oben
.calc_y:
add d3,d2
movem.w d0-d3,(a0) ;zurückschreiben
lea 8(a0),a0
dbra d7,.fly_loop
rts
;Die Sprites werden nach der Reihe auf den Screen ;gebracht und der Hintergrund gerettet draw_sprites: move.l sprbuff2(pc),a5 ;Savebuffer lea koordtab(pc),a4 ;Koordinaten move.w #anz_spr-1,d7 ;Zähler .draw_loop: move.w (a4),d0 ;x-Koordinate ext.l d0 move.w 4(a4),d1 ;y-Koordinate ext.l d1 addq #8,a4 ;Vorsicht mulu.l ist ein 68030 Befehl!!! mulu.l #640,d1 ;mal Zeilenbreite lsl d0 ;mal 2 (Word/Pix) add.l d0,d1 ;Index in Screen move.l screen2(pc),a6 ;log. Screen add.l d1,a6 ;neue Adresse move.l d1,(a5)+ ;Index retten lea spritegfx(pc),a3 ;Spritedaten
move.w #15-1,d6
.zeilenloop:
movem.l (a6),d0-d4/a0-a2 ;Hintergrund
movem.l d0-d4/a0-a2,(a5) ;retten
lea 32(a5),a5
move.w #15-1,d5
.pixelloop:
move.w (a3)+,d0 ;nimm Pixel
beq.s .transparent ;0=transp.
move.w d0,(a6) ;sonst auf Screen
.transparent:
addq #2,a6 ;Zeiger anpassen
dbra d5,.pixelloop
lea 640-30(a6),a6 ;nächste Zeile
dbra d6,.zeilenloop
dbra d7,.draw_loop
rts
;Bevor neue Sprites auf den Bildschirm kommen, ;müssen erstmal die alten in umgekehrter Reihen- ;folge wieder gelöscht werden. clear_sprites: move.l sprbuff2(pc),a5 ;Savebuffer tst.l (a5) ;schon was da? bpl.s .yip_yip ;ja rts .yip_yip: move.l screen2(pc),a6 ;Screen move.w #anz_spr-1,d7 move.w d7,d6 ;verdoppeln ext.l d6 ;auf long bringen ;Auch hier mulu.l für 68030, wenn mehr ;als 63 Sprites angegeben werden mulu.l #484,d6 ;Buffergröße add.l d6,a5 ;letzte Sprite .clear_loop: move.l a6,a4 ;Screenpointer add.l (a5)+,a4 ;Index auf Screen moveq #15-1,d6 ;15 Zeilen .zeilenloop: movem.l (a5)+,d0-d5/a0-a1 ;restore movem.l d0-d5/a0-a1,(a4) ;Background lea 640(a4),a4 ;nächste Zeile dbra d6,.zeilenloop lea -484*2(a5),a5 ;nächste Sprite dbra d7,.clear_loop rts
;bunte Balken auf den Hintergrund malen prepare_screens: move.l screen1(pc),a0 move.l screen2(pc),a1 move.w y_max,d7 ;Anzahl d. Zeilen .zeilenloop: move.w #5-1,d6 ;Anzahl d. Balken lea colcode(pc),a2 ;Tabelle m. RGB's moveq #0,d0 ;Start-RGB-Wert .balkenloop: move.w (a2)+,d1 ;nimm delta-RGB move.w #32-1,d5 ;Anzahl d. Farben .lefthalf: ;erst linke Seite move.w d0,(a0)+ ;in beide Screens move.w d0,(a1)+ add.w d1,d0 ;RGB ändern dbra d5,.lefthalf move.w #32-1,d5 ;Anzahl d. Farben .righthalf: ;nun rechte Seite sub.w d1,d0 ;RGB ändern move.w d0,(a0)+ ;in beide Screens move.w d0,(a1)+ dbra d5,.righthalf dbra d6,.balkenloop dbra d7,.zeilenloop rts
data
fail_text: dc.b 'Sorry, your machine is not ' dc.b 'powerful enough to launch this!',0
mausaus: dc.b $12 mausan: dc.b $08 even ;Farben der Hintergrundbalken colcode: dc.w $41,$800,$40,1,$340 ;Rahmenfarbe newcolor: dc.l 0
sprbuff1: dc.l buffer1 sprbuff2: dc.l buffer2
;Directcolor Sprite 15*15 Pixel spritegfx: dc.w $0000,$0000,$0000,$0000,$0000 dc.w $4208,$4208,$4208,$4208,$3186 dc.w $0000,$0000,$0000,$0000,$0000 dc.w $0000,$0000,$0000,$4208,$630c dc.w $8410,$738e,$738e,$630c,$528a dc.w $4208,$3186,$0000,$0000,$0000 dc.w $0000,$0000,$4208,$9492,$a514 dc.w $a514,$9492,$8410,$738e,$630c dc.w $528a,$3186,$3186,$0000,$0000 dc.w $0000,$4208,$a514,$d69a,$e71c dc.w $d69a,$b596,$a514,$8410,$738e dc.w $630c,$4208,$3186,$3186,$0000 dc.w $0000,$8410,$c618,$e71c,$f79e dc.w $e71c,$c618,$b596,$9492,$8410 dc.w $528a,$528a,$3186,$3186,$0000 dc.w $3186,$9492,$c618,$d69a,$e71c dc.w $d69a,$d69a,$b596,$9492,$8410 dc.w $630c,$528a,$4208,$3186,$1082 dc.w $528a,$9492,$9492,$c618,$c618 dc.w $c618,$b596,$9492,$9492,$8410 dc.w $630c,$528a,$4208,$3186,$2104 dc.w $528a,$8410,$9492,$b596,$b596 dc.w $a514,$b596,$9492,$8410,$738e dc.w $630c,$528a,$4208,$3186,$1082 dc.w $630c,$630c,$8410,$9492,$9492 dc.w $9492,$9492,$8410,$738e,$630c dc.w $528a,$528a,$4208,$3186,$1082 dc.w $3186,$630c,$630c,$8410,$8410 dc.w $8410,$8410,$738e,$630c,$528a dc.w $528a,$4208,$3186,$2104,$1082 dc.w $2104,$3186,$4208,$528a,$630c dc.w $630c,$630c,$528a,$528a,$528a dc.w $4208,$3186,$3186,$1082,$0000 dc.w $0000,$3186,$3186,$4208,$4208 dc.w $4208,$4208,$4208,$4208,$4208 dc.w $3186,$3186,$2104,$1082,$0000 dc.w $0000,$0000,$3186,$3186,$3186 dc.w $3186,$3186,$3186,$3186,$3186 dc.w $3186,$2104,$1082,$0000,$0000 dc.w $0000,$0000,$0000,$2104,$2104 dc.w $2104,$2104,$2104,$2104,$2104 dc.w $1082,$1082,$0000,$0000,$0000 dc.w $0000,$0000,$0000,$0000,$0000 dc.w $1082,$1082,$1082,$1082,$1082 dc.w $0000,$0000,$0000,$0000,$0000
bss
oldstack: ds.l 1 oldmode: ds.w l oldphys: ds.l 1 oldlog: ds.l 1 oldcolor: ds.l 1 screen1: ds.l 1 screen2: ds.l 1 y_max: ds.w 1 ;Sprite-Koordinaten-Buffer koordtab: ds.w 4anz_spr ;Sprite-Background-Buffer buffer1: ds.w (1615+2)anz_spr buffer2: ds.w (1615+2)*anz_spr
ds.l 300
newstack: ds.l 1