Den Bildschirmspeicher im Griff

Dass der Bildschirm ein sehr wichtiges Ausgabegerät ist, wird wohl niemand bestreiten können. Aus diesem Grund sollte sich jeder ernsthafte Programmierer damit auseinandersetzen, wie und wo der Computer die Bildinformation abspeichert. Ein solches Wissen ist spätestens dann erforderlich, wenn man Programme entwickeln will, die mit grafischen Spezialeffekten ausgestattet werden oder deren Arbeitsbereich über die Grenzen des gerade auf dem Bildschirm sichtbaren Bereichs hinausgehen sollen.

Wie ist es zum Beispiel möglich, daß bei Computerspielen Landschaften sofort aus dem Nichts auftauchen, ohne daß man auf lange Berechnungen oder auf einen Diskettenzugriff warten muß? Oder wie wie ist es möglich, zwei Bildschirme zu einer Einheit zusammenzufassen, um beispielsweise mit einem Malprogramm eine komplette DIN A4-Seite zu bearbeiten? Die Antwort auf dieseund weitere Fragen bietet dieser Artikel.

Speichern der Bildinformation

Alles, was auf dem Bildschirm zu sehen ist, ist irgendwo im RAM des Atari ST gespeichert. Dabei ist es dem Computer völlig egal, ob es sich um Grafik oder reine Textinformation handelt. Für den Computer ist das, was wir auf dem Bildschirm sehen, lediglich eine Reihe von Bildpunkten, die je nach gewählter Bildschirmauflösung entweder schwarzweiß oder farbig sind. Die Größe des benötigten Speicherplatzes für die gesamte Bildinformation ist jedoch in jedem Fall gleich und beträgt 32000 Byte. Im hochauflösenden Modus läßt sich die Größe des Bildschirmspeichers sehr leicht erklären. Der Computer kann in dieser Auflösungsstufe 640 Bildpunkte horizontal und 400 vertikal darstellen. Das ergibt also eine Gesamtzahl von 256000 Bildpunkten. Da jeder dieser Bildpunkte nur zwei Zustände annehmen kann, entweder weiß oder schwarz, läßt sich jeder Bildpunkt mit der kleinsten Informationseinheit des Computers, mit einem Bit, welches den Wert 0 oder 1 annehmen kann, definieren. Acht solcher Bits zusammengefaßt entsprechen einem Byte, was also bedeutet, daß man 256000 durch 8 teilen muß, um auf die Anzahl der benötigten Bytes zu kommen, womit wir bei dem Wert von 32000 Bytes angelangt wären. Um festzustellen, ab welcher Speicherstelle oder Adresse der Computer die Bildinformation im Moment abgelegt hat, bedient man sich des Befehls XBIOS (Adresse,2). Hierbei wird in der Variablen Adresse der Wert der Speicheradresse abgelegt, ab der der Computer das momentan sichtbare Bild darstellt. Diese Adresse muß nicht immer gleich sein, sondern kann vom Programmierer an eine andere Stelle gelegt werden; auch ist es möglich, mehrere solcher Speicherbereiche anzulegen, wobei natürlich immer nur die Information eines Bereichs auf dem Schirm sichtbar ist. Das einzige, was hierbei zu beachten ist, ist, daß die Adresse eines solchen Speicherbereichs, zumindest bei einem „normalen“ Atari ST, durch 256 teilbar sein muß (beim Atari STE reicht es aus, wenn sie durch 2 teilbar ist).

Mehrere Bildschirme

Natürlich kann man die Bildin-formajion nicht wahllos im Speicher ablegen, da man nie weiß, ob der Speicherplatz nicht schon von anderen Programmteilen besetzt ist. Aus diesem Grund ist es erforderlich, daß man sich Speicherplatz in einem RAM-Bereich reserviert, der, ohne großen Schaden anzurichten, vom Programmierer genutzt werden kann. Dazu dient der Befehl CLEAR. Wie wir wissen, benötigt ein kompletter Bildschirm 32000 Bytes. Daher muß also pro Bildschirm mindestens diese Speicherplatzmenge reserviert werden. Da ein mit CLEAR reservierter Speicherplatz jedoch nicht nur vom Programmierer allein genutzt wird, sondern auch vom sogenannten GEMDOS, einem Teil des Betriebssystems, der unter anderem für die Darstellung von Dateiauswahl- und Alarmboxen zuständig ist (OMIKRON.BASIC reserviert standardmäßig 65536 Bytes hierfür), ist es von Vorteil, großzügig zu sein und immer ein bißchen mehr zu reservieren. Wenn Speicherplatz reserviert wird, möchte man natürlich auch wissen, ab welcher Adresse man ihn nutzen kann. Das kann man mit der Funktion MEMORY in Erfahrung bringen [Beispiel: Adresse = MEMORY (32000)], die dann bei Angabe des zu reservierenden Speicherplatzes die entsprechende Speicheradresse zurückgibt, ab der der Platz reserviert wurde. Wenn man auf diese Weise mehrere Bildschirme erzeugt, nützt uns das jedoch recht wenig, wenn man auf diese Schirme keine Grafik oder keinen Text ausgeben kann. Daher gibt es einen X-BIOS-Befehl, der es unter anderem erlaubt, diese angelegten Speicherbereiche als sogenannte virtuelle (scheinbare) Bildschirme zu nutzen.

Sämtliche Befehle, die Text oder Grafik ausgeben, werden auf diese sozusagen im Hintergrund befindlichen, momentan also unsichtbaren, Schirme umgeleitet.

Der Befehl, der auch noch andere Funktionen beinhaltet, auf die im Rahmen dieses Artikels jedoch nicht eingegangen werden soll, sieht in diesem Fall folgendermaßen aus:

XBIOS (,5,HIGH(Adresse),LOW(Adresse),-1, -1, -1)

Adresse ist hierbei wieder die Adresse eines Speicherbereichs, in der die Bildinformation abgelegt werden soll.

Für das möglichst flackerfreie Sichtbarmachen dieser Bildschirme kann man sich des SCREEN-Befehls bedienen (SCREEN Schirmnummer, Adresse). Die Schirmnummer kann hierbei 0, 1 oder 2 sein, wobei 1 oder 2 vorzuziehen ist, da bei Schirmnummer 0 im sogenannten Link-Modus gearbeitet wird, das heißt, bei Textausgabe wird bei Zeilenüberschreitung ein senkrechter Strich dargestellt, der eventuell störend wirkt. Wie dieses ganze Wissen nun in der Praxis genutzt werden kann, zeigt Listing 1. In diesem Beispielprogramm werden im Hintergrund auf 10 Bildern konzentrische Kreise gezeichnet, die dann nacheinander als Computeranimation gezeigt werden.

Soft-Scrolling

In Grafikprogrammen, insbesondere bei Computerspielen, kann man oft beobachten, wie der Bildschirm zeilenweise nach oben oder unten oder auch seitwärts verschoben wird. Dieses Phänomen wird Scrolling genannt (to scroll - rollen). Wie man so eine zeilenweise Bildverschiebung in vertikaler Richtung, also von oben nach unten, oder umgekehrt vornehmen kann, soll uns nun noch ein wenig beschäftigen.

Zunächst einmal ist es sinnvoll zu überlegen, was beim Scrolling eigentlich passiert. Bei einem zeilenweisen vertikalen Scrolling wird im Grunde lediglich die Anzeigeadresse des Bildschirms um die Anzahl von Bytes verschoben, die der Bildinformation für eine Zeile entsprechen. Wieviel Bytes müßten das sein? In hoher Bildschirmauflösung entspricht jeder Bildpunkt, wie bereits bekannt, einem Bit. Bei einer Zeilenbreite von 640 Bildpunkten beträgt der benötigte Speicherplatz im Bildschirmspeicher also 640 Bits oder 80 Bytes (640/8=80). In diesem Fall müßte man also, wenn man den gesamten Bildinhalt um eine Zeile nach oben verschieben, möchte die Adresse des Bildschirmspeichers um 80 Bytes verschieben. Da jedoch die Bildschirmadresse beim „normalen“ ST durch 256 teilbar sein muß, ist das nicht ohne weiteres möglich. Man kann sich hier jedoch eines kleinen Tricks bedienen. Mit Hilfe des Befehls MEMORY_MOVE ist es möglich, Speicherbereiche, die an einer durch 2 teilbaren Adresse liegen, zu kopieren. Man kopiert also den um 80 Bytes verschobenen Bildinhalt an die durch 256 teilbare Startadresse eines Bereiches, der als Bildschirmspeicher benutzt werden soll. Aber es handelt sich nicht in jedem Fall um 80 Bytes pro Zeile. In mittlerer und geringer Auflösung muß nämlich noch die Information für die verschiedenen Farben abgelegt werden. In mittlerer Auflösung hat eine Bildschirmzeile ebenfalls 640 Bildpunkte. Jeder dieser Punkte kann jedoch eine von vier verschiedenen Farben annehmen. Der Computer muß das irgendwie auseinanderhalten können.

Dies tut er, indem für jeden Bildpunkt in mittlerer Auflösung zwei Bits zuständig sind. Mit zwei Bits kann man vier verschiedene Zustände (22=4), oder in diesem Fall Farben, darstellen (00=1, 01=2, 10=3, 11=4). Um den Bildschirm um eine Zeile zu verschieben, muß also die Bildschirmadresse um 1280 Bits (6402) oder 160 Bytes verschoben werden. Im Fall der geringen Auflösung, mit einer Zeilenbreite von 320 Bildpunkten und 16 Farben, müssen sich 4 Bits die Information für einen Bildpunkt teilen (24=16). Pro Zeile sind 3204 Bits, also ebenfalls 160 Bytes erforderlich. Listing 2 zeigt die Anwendung dieser Erkenntnisse. Es werden insgesamt 4 Bildschirme erzeugt. Die Schirme 3 und 4 werden per Zufallsgenerator mit Text beschrieben.

Anschließend wird die Bildinformation abwechselnd in Schirm 1 und 2 jeweils um eine Zeile verschoben hineinkopiert, und zwar so, daß Schirm 1 oder 2 erst nach dem Kopiervorgang zu sehen sind. Dieses Hin- und Herschalten dient der flimmerfreien Darstellung, da bei direktem Kopieren der Bildinformation in einen bereits sichtbaren Schirm der Bildaufbau nicht ganz mit dem Programm synchron läuft. Dieser Vorgang wird solange wiederholt, bis von Schirm 3 nach Schirm 4 gescrollt wurde. Das Demoprogramm ist in allen drei Auflösungen lauffähig. Experimentieren Sie ruhig ein wenig herum. Es ist zum Beispiel leicht möglich, in Schritten von zwei Zeilen oder mehr zu scrollen. Auch braucht man den Scroll-Vorgang nicht über den ganzen Schirm auszudehnen. Wird im Listing beim MEMORY_MOVE-Befehl die Anzahl der zu kopierenden Bytes von 32000 auf 16000 beschränkt, wird beispielsweise nur in der oberen Bildschirmhälfte gescrollt. Mit ein bißchen Geschick läßt sich so eine Vielzahl von Effekten programmieren.

' +---------------------------------+
' |           Listing 1             |
' | DEN BILDSCHIRMSPEICHER IM GRIFF | 
' |       mit OMIKRON-BASIC         |
' |             ANIMATION           |
' +---------------------------------+

CLEAR 360000:'Genügend Speicherplatz reservieren

Bildschirm:' Grundeinstellungen die mit der Auflösung zu tun haben Erzeuge_Schirme 11

SCREEN 1,Adr_Erster_Schirm%L:' Siehe Prozedur <Erzeuge_Schirme>

Cursor_Aus: 'Stört nur 

'Grafiken erzeugen 

X%L=Maxbreite%L\2
Y%L=Maxhoehe%L\2: 'Kreismittelpunkt
FOR I%L=2 TO 11

    'Text auf den ersten Schirm

    Aktiviere_Schirm 1:'Schirm 1 ist gerade sichtbar (SCREEN 1)
    LOCATE 2,1: PRINT "Bitte einen Moment Geduld" 
    LOCATE 3,1: PRINT "Grafik Nr. ";I%L-1;" wird gerade erzeugt"

    'Grafik im Hintergrund auf die Schirme 2 bis 11

    Aktiviere_Schirm I%L:’Zur Zeit unsichtbar im Hintergrund 
    LOCATE 2,1: PRINT "DEMO ANIMATION"
    FOR Radius%L=0 TO 400 STEP 20 
        CIRCLE X%L,Y%L,Radius%L+2*I%L 
    NEXT
NEXT

'ANIMATION

SCREEN 2,Adr_Erster_Schirm%L
Cursor_Aus
REPEAT
    FOR I%L=2 TO 11
        Schirmadresse%L=Adr_Erster_Schirm%L+(I%L-1)*32000
        WAIT 1/40:'Bildfrequenz 
        SCREEN 2, Schirmadresse%L 
    NEXT
UNTIL INKEY$ <>"":'Abbruch bei Tastendruck 

END

'Standard-Prozeduren die für die Demos benötigt werden

DEF PROC Bildschirm
    XBIOS (Aufloesung%L,4):'Bildschirmaufloesung ermitteln 
    Maxbreite%L=640+320*(Aufloesung%L=0):'Bildpunkte horizontal 
    Maxhoehe%L=400+200*(Aufloesung%L<2):'Bildpunkte vertikal 
    CLIP 0,0,Maxbreite%L,Maxhoehe%L 
    Bytes_Pro_Zeile%L=160+80*(Aufloesung%L=2) 
RETURN

DEF PROC Cursor_Aus 
    PRINT CHR$(27);"f";
RETURN

DEF PROC Erzeuge_Schirme(Nschirme%L)
    Adr_Erster_Schirm%L= MEMORY(32000*Nschirme%L+256)
    Adr_Erster_Schirm%L=(Adr_Erster_Schirm%L\256)*256+256
RETURN

DEF PROC Aktiviere_Schirm(Nr%L)
    LOCAL Adr%L
    Adr%L=Adr_Erster_Schirm%L+(Nr%L-1)*32000 
    XBIOS (,5, HIGH(Adr%L), LOW(Adr%L),-1,-1,-1) 
RETURN
'+---------------------------------+
'|           Listing 2             |
'| DEN BILDSCHIRMSPEICHER IM GRIFF |
'|       mit OMIKRON-BASIC         |
'|    VERTIKALES SOFT SCROLLING    |
'+---------------------------------+
' (c) 1991 MAXON Computer
CLEAR 150000: 'Genügend Speicherplatz reservieren

Bildschirm:' Grundeinstellungen die mit der Auflösung zu tun haben 
Erzeuge_Schirme 4

SCREEN 1,Adr_Erster_Schirm%L:'Siehe Prozedur <Erzeuge Schirme>
Cursor_Aus

FOR I%L=3 TO 4

    'Text auf den ersten Schirm

    Aktiviere_Schirm 1:'Schirm 1 ist gerade sichtbar (SCREEN 1)
    LOCATE 2,1: PRINT "Bitte einen Moment Geduld"
    LOCATE 3,1: PRINT "Schirm Nr. ";I%L-1;M wird gerade beschriftet"

    'Text im Hintergrund auf die Schirme 3 und 4

    Aktiviere_Schirm I%L:'Zur Zeit unsichtbar im Hintergrund
    LOCATE 2,1: PRINT "DEMO VERTIKALES SCROLLING" 
    FOR Zeile%L=4 TO 24
        Nspalten%L=80+40*(Aufloesung%L=0)
        FOR Spalte%L=0 TO Nspalten%L-1 
            LOCATE Zeile%L,Spalte%L
            PRINT CHR$( RND(64)+32);:‘Zeichenauswahl per Zufallsgenerator
        NEXT
    NEXT

NEXT

'VERTIKALES SCROLLING

SCREEN 2:Cursor_Aus
Schirm1%L=Adr_Erster Schirm%L
Schirm2%L=Adr_Erster_Schirm%L+32000
Nbildzeilen%L=400+200*(Aufloesung%L<>2)
Startadresse%L=Adr_Erster_Schirm%L+64000:'Dritter Schirm Anfang erste Zeile 
Zeilenoffset%L=0
FOR Bildzeile%L=1 TO Nbildzeilen%L
    MEMORY_MOVE Startadresse%L+Zeilenoffset%L,32000 TO Schirm2%L 
    SCREEN 2,Schirm2%L 
    SWAP Schirm1%L,Schirm2%L 
    Zeilenoffset%L=Zeilenoffset%L+Bytes_Pro_Zeile%L 
    WAIT 1/50: Bildfrequenz 
NEXT

END

'Standard-Prozeduren die wir für die Demos benötigen

DEF PROC Bildschirm
    XBIOS (Aufloesung%L,4):'Bildschirmaufloesung ermitteln 
    Maxbreite%L=640+320*(Auf1oesung%L=0):'Bildpunkte horizontal 
    Maxhoehe%L=400+200*(Aufloesung%L<2):'Bildpunkte vertikal 
    CLIP 0,0,Maxbreite%L,Maxhoehe%L 
    Bytes_Pro_Zeile%L=160+80*(Aufloesung%L=2) 
RETURN

DEF PROC Cursor_Aus 
    PRINT CHR$(27);"f";
RETURN

DEF PROC Erzeuge_Schirme(Nschirme%L)
    Adr_Erster_Schirm%L= MEMORY(32000*Nschirme%L+256)
    Adr_Erster_Schirm%L=(Adr_Erster_Schirm%L\256)*256+256
RETURN

DEF PROC Aktiviere_Schirm(Nr%L)
    LOCAL Adr%L
    Adr%L=Adr_Erster_Schirm%L+(Nr%L-1)*32000 
    XBIOS (,5, HIGH(Adr%L), LOW(Adr%L),-1,-1,-1) 
RETURN

Mario Srowig
Aus: ST-Computer 07 / 1991, Seite 92

Links

Copyright-Bestimmungen: siehe Über diese Seite