Die GFA-Befehle GET, PUT, SGET und SPUT zum Kopieren von Bildschirmausschnitten bzw. des ganzen Bildschirms sind leicht zu handhaben und arbeiten sehr schnell. Es gibt jedoch Probleme, wenn Programme mit diesen Befehlen voll unter GEM oder z.B. auf Rechnern mit Großmonitor laufen sollen.
Die Befehle SGET und SPLIT arbeiten nur in den normalen ST-Auflösungen mit 32000 Bytes pro Bild. Die Befehle GET und PUT verarbeiten auch nur Bildausschnitte mit maximal 32000 Bytes, so daß größere Ausschnitte auf mehrere GETs und PUTs verteilt werden müssen. Ein weiterer Nachteil ist, daß mit diesen Befehlen unter Umgehung von AES und VDI direkt auf den Bildschirmspeicher zugegriffen wird. Ein Clipping (die automatische Begrenzung der Bildschirmausgabe auf einen vordefinierten, rechteckigen Bereich, z.B. ein Fenster), ist daher mit allen genannten Befehlen natürlich auch nicht möglich.
Auf der Suche nach einer Alternative ohne diese Einschränkungen stößt der hartnäckige GFA-Programmierer auf den BITBLT-Befehl, welcher sich im GFA-BASIC-Handbuch zunächst durch eine Unzahl von Übergabeparametern und weiterhin durch didaktisch völlig mißlungene Programmbeispiele auszeichnet. Es gibt drei Befehlsvarianten, von denen zwei von vornherein ausscheiden, weil sie Line-A-Routinen aufrufen. (Line-A soll laut ATARI möglichst nicht mehr verwendet werden, siehe auch [2]).
Der Variante mit drei Arrays als Übergabeparameter, welche in den Prozeduren get und put verwendet wird, liegt dagegen eine VDI-Routine zugrunde, und zwar VDI 109, vro_cpyfm(). Die Prozeduren verarbeiten bei jeder Auflösung beliebig große Bildausschnitte. Ein eventuell gesetztes Clipping wird berücksichtigt. Die Übergabeparameter an die Prozeduren get und put enthalten die gleichen Werte wie die gleichnamigen GFA-BASIC-Befehle mit einer Ausnahme:
Anstelle der String-Variablen, die dort den Bildausschnitt enthält, wird hier die Adresse eines zuvor beim Betriebssystem angeforderten (allozierten) Speicherbereiches angegeben. Dieser Speicherbereich besteht aus einem 12 Byte langen Header und den daran anschließenden Bilddaten. Der Header enthält Informationen über die gespeicherten Daten: Byte 0-3: Rasterbreite, Byte 4-7: Rasterhöhe, Byte 8-11: Anzahl der Bildebenen. Ab Byte 12 folgen Bilddaten.
Der zu kopierende Bildschirm- bzw. Speicherbereich muß in einer MFDB-Struktur beschrieben werden (MFDB = Memory Form Definition Block). Diese Struktur wird von der Prozedurmfdb_/n/'f eingerichtet, welche daher vor der ersten Anwendung der Prozeduren get und put einmal aufgerufen werden muß. Die Prozedur vq_extnd, welche innerhalb von mfdbjnit aufgerufen wird, ermittelt mit Hilfe der gleichnamigen VDI-Auskunftsfunktion (VD1102) die Anzahl der Bildebenen, welche von der gerade bestehenden Bildschirmauflösung abhängt. Im Array src.mfdb%0 wird das Quellraster beschrieben, im Array des.mfdb%0 das Zielraster. In gp.par%0 stehen die Koordinaten von Quell- und Zielraster sowie der Kopiermodus. Die Array-Elemente werden im einzelnen wie folgt benutzt:
mfdb%(0): Anfangsadresse des Speicherblocks, in den bzw. aus dem kopiert werden soll
mfdb%(2): Pixel-Höhe des Rasters
mfdb%(3): Rasterbreite in Worten (=Pixel-Breite/16)
mfdb%(4): Format: 0=geräteabhängig, 1=Standardformat ! hier immer Null
mfdb%(5): Anzahl der Bildebenen, abhängig von der Auflösung
Die mfdb%()-Elemente 6-8 sind reserviert.
Rasterkoordinaten, Quellraster:
gp.par%(0) x links
gp.par%(1) y oben
gp.par%(2) x rechts
gp.par%(3) y unten
Rasterkoordinaten, Zielraster:
gp.par%(4) x links
gp.par%(5) y oben
gp.par%(6) x rechts
gp.par%(7) y unten
gp.par%(8) Kopiermodus (Werte von 0-15, z.B.: 3=replace, 6=xor)
Es tritt nur eine globale Variable auf - die Anzahl der Bildebenen fd_nplanes%. Dieser Wert wird beim Aufruf der Prozedur get in den o.a. Header geschrieben und kann im Zweifelsfalle über die gespeicherten Bilddaten Auskunft geben, z.B. wenn der Speicherbereich zwischenzeitlich auf Diskette/Festplatte ausgelagert war.
Im Beispielprogramm wird ein Teil des Bildschirms eingelesen, der Bildschirm gelöscht und dann (nach Tastendruck) das gespeicherte Raster an verschiedene Positionen kopiert. Dabei wird auch die Berücksichtigung des eingestellten Clippings gezeigt.
Literatur:
[1] GFA-BASIC-Interpreter, Handbuch, GFA Systemtechnik 1990
[2] ATARI Profibuch ST-STE-TT, Sybex-Verlag 1991
' *******************************************
' BITBLT - Anwendung des GFA-BASIC-Befehls
' Beispiel-Programm zur Anwendung der
' Prozeduren 'get' und 'put'
' in GFA-BASIC 3.6
' Markus Holtwiesche
' (c) 1992 MAXON Computer
' *******************************************
'
' MFDB einrichten
@mfdb init
' testbild zeichnen
DEFFILL 1,2,8
PBOX 100,100,200,250
GRAPHMODE 3
PCIRCLE 250,175,70
PBOX 80,150,350,200
' Ausschnitt einlesen
get(80,100,350,250,bildadresse%)
' Clipping setzen
CLIP OFF
CLIP 50,50 TO 589,349
' Bild löschen
' und Clipping-Rechteck darstellen
GRAPHMODE 1
DEFFILL 1,2,2
BOUNDARY 0
PBOX 50,50,589,349
BOX 50,50,589,349
PRINT AT(1,1);"Taste drücken!"
~INP(2)
'
' Ausschnitt über den Bildschirm wandern lassen
FOR i%=0 TO 399 STEP 30
get(i%,i%,i%+270,i%+150,hintergrundadresse%)
put(i%,i%,bildadresse%,3)
PAUSE 30
put(i%,i%,hintergrundadresse%,3)
NEXT i%
'
' vor dem Programmende sollten alle eventuell an-
' geforderten Speicherblöcke wieder freigegeben
' werden
' deshalb Vorsicht beim Programmabbruch
' mit Control-Shift-Alternate
IF bildadresse%>0
~MFREE(bildadresse%)
ENDIF
IF hintergrundadresse%>0
~MFREE(hintergrundadresse%)
ENDIF
END
' Programmende
' *******************************************
'
PROCEDURE mfdb_init
' richtet MFDB ein
' muß einmal zum Programmstart aufgerufen
' werden
DIM src.mfdb%(8)
DIM des.mfdb%(8)
DIM gp.par%(8)
@vq_extnd
fd_nplanes%=INTOUT(4) !Anzahl der Bildebenen
src.mfdb%(4)=0 !reserv.
src.mfdb%(5)=fd_nplanes%
des.mfdb%(4)=0 !reserv.
des.mfdb%(5)=fd_nplanes%
RETURN
'
PROCEDURE vq extnd
' Auskunftsfunktion des VDI
' Nach dem Aufruf stehen in INTOUT(0) bis
' INTOUT(44) diverse Parameter der Rechner-
' konfiguration; siehe auch [2]
DPOKE CONTRL+2,0
DPOKE CONTRL+4,6
DPOKE CONTRL+6,1
DPOKE CONTRL+8,45
DPOKE CONTRL+12,V~H
INTIN(0)=1 ! 0=normale- 1=erweiterte Auskunft
VDISYS 102
RETURN
'
PROCEDURE get (xs0%,ys0%,xs1%,ys1%,VAR bildadr%)
' liest beliebig großen Bildausschnitt in
' Speicherblock
LOCAL b.len%
' Bildlänge ausrechnen
b.len%=((xs1%-xs0%+16) AND &HFFF0)*(ys1%-ys0%+1)/8*fd_nplanes%
IF b.len%> 0
' nur weiter, wenn Bildlänge großer 0
IF bildadr%>0
' wenn Bildadresse schonmal vergeben
' Speicher freigeben
~MFREE (bildadr%)
ENDIF
' Speicher reservieren:
' Bildlange+Bürokratie(Header)
bildadr%=MALLOC(b.len%+12)
IF bildadr%>0
' wenn Speicher reserviert
src.mfdb%(0)=0 ! 0=BILDSCHIRM!! !
src.mfdb%(1)=(xs1%-xs0%+16) AND &HFFF0
src.mfdb%(2)=ys1%-ys0%+1
src.mfdb%(3)=src.mfdb%(1)/16
des.mfdb%(0)=bildadr%+12 ! SPEICHERADRESSE! !
des.mfdb%(1)=src.mfdb%(1)
des.mfdb%(2)=src.mfdb%{2)
des.mfdb%(0)=src.mfdb%(3)
gp.par%(0)=xs0%
gp.par%(1)=ys0%
gp.par%(2)=xs1%
gp.par%(3)=ys1%
gp.par%(4)=0
gp.par%(5)=0
gp.par%(6)=xs1%-xs0%
gp.par%(7)=ys1%-ys0%
gp.pr%(8)=3 !Kopier-Modus: 3=replace
' Bild in Speicher einiesen
BITBLT src.mfdb%(),des.mfdb%(),gp.par%()
' Header setzen
{bildadr%}=xs1%-xs0%
{bildadr%+4}=ys1%-ys0%
{bi1dadr%+8}=fd_np1anes%
ENDIF
ENDIF
RETURN
'
PROCEDURE put(xd0%,yd0%,bildadr%,mod%)
' zeichnet den eingelesenen Bildausschnitt
' an beliebiger Stelle auf den Bildschirm
IF bildadr%>0
' wenn Bildadresse vorhanden
src.mfdb%(0)=bildadr%+12 ! SPEICHERADRESSE!!
' Rasterdaten aus Header lesen
src.mfdb%(1)=({bildadr%}+16) AND &HFFF0
src.mfdb%(2)={bildadr%+4}+1
'
src.mfdb%(3)=src.mfdb%(1)/16
des.mfdb%(0)=0 ! 0=BILDSCHIRM! !
des.mfdb%(1)=src.mfdb%(1)
des.mfdb%(2)=src.mfdb%(2)
des.mfdb%(3)=src.mfdb%(3)
gp.par%(0)=0
gp.par%(1)=0
gp.par%(2)={bildadr%}
gp.par%(3)={bildadr%+4}
gp.par%(4)=xd0%
gp.par%(5)=yd0%
gp.par%(6)=xd0%+gp.par%(2)
gp.par%(7)=yd0%+gp.par%(3)
gp.par%(8)=mod%
' Bild auf den Schirm kopieren
BITBLT src.mfdb%(),des.mfdb%(),gp.par%()
ENDIF
RETURN