QUICK Ecke 24 von Harald Schönfeld Wie jeder weiß, ist QUICK eine Sprache die sich hervorragend zum Programmieren grafischer Anwendungen eignet. Ein Grund dafür sind die Befehle CUT und PASTE, die man in keiner anderen Sprache findet. CUT dient zum Kopieren von Teilen hochauflösender Bilder vom Bildschirm (üblicherweise Grafik 8) in den Speicher. PASTE dient zum Kopieren dieser Bildblöcke von Speicher auf den Bildschirm an beliebigen Positionen. Bildschirm ist nicht gleich Speicher Der Bildschirmspeicher des XL (im Grafikmodus 8) besteht aus 40 Bytes pro Zeile und setzt sich aus 192 Zeilen zusammen. Pro Byte werden dabei 8 Pixel auf dem Bildschirm dargestellt. Will man diesen Bildspeicher teilweise kopieren (z.B. den Block im Rechteck zwischen 0,0 und 64,32), so reicht es nicht einfach "einen Teil" des Bildschirms z.B. mit BMOVE zu kopieren. Der Grund ist einfach: Der 64 Pixel breite Block belegt in jeder Zeile ja nur 8 Byte, d.h. die restlichen 32 Byte der Zeile würden jeweils unnötigerweise kopiert und würden nur Platz kosten. Um einen 32*8 Byte großen Block zu speichern würde man durch einfaches Kopieren des Bildscirmspeichers 32*40 Bytes benötigen. Eine Abhilfe wäre, mehrere BMOVEs zu verwenden, die jeweils nur 8 Byte einer Zeile kopieren, und das dann 32 mal. Das wäre zwar speichersparend aber doch recht aufwendig. Außderdem kann man auf diese Weise ausgeschnittene Blöcke immer nur wieder auf Bytegrenzen in den Bildspeicher zurückkopieren. CUT und PASTE All diese Schwierigkeiten beheben CUT und PASTE auf eine - für den Programmierer - extrem einfache Art. Man muß nur die Pixelkoordinaten des zu kopierenden Bereichs angeben und für genug Speicher sorgen, alles andere (das geschickte Zusammenfassen der einzelnen Zeilenbereiche, das bitweise Verschieben) erledigen CUT und PASTE. Näheres zur internen Arbeitsweise siehe ATARImagazin 5/89. CUT CUT(x1,y1,x2,y2,adr) schneidet den Inhalt des Rechtecks (x1,y1)(x2,y2) aus und speichert es ab der Adresse adr im Speicher ab. Der Bildschirm bleibt dabei unverändert. (Achtung: Leider befindet sich in der QUICK-Referenzkarte im Handbuch ein Druckfehler. Dort wurden x2 und y1 in der Angabe vertauscht!) Das einzige Problem ist, adr richtig zu setzen. adr muß natürlich auf einen freien Speicher zeigen. Und wenn man mehrere Blöcke speichern will, so muß man jedem Block eine eigene Adresse zuweisen. Das ist sicher einsichtig. Schwierig ist es allerdings herauszufinden, wie viel Speicher für einen Bildschirmausschnitt bestimmter Größe dann im Speicher verbraucht wird. Eine Abschätzung liefert folgende Formel: ((Breite des Rechtecks in Byte +2) * Höhe in Pixel) + 10. Das heißt, das pro Pixelzeile 2 Bytes mehr benötigt werden, als wenn man dan Bereich von Hand mit vielen BMOVEs kopieren würde. Die obige Formel ist nicht ganz exakt. Im Zweifelsfall sollte man etwas mehr Speicher bereitstellen, oder es genau "ausmessen". PASTE PASTE(m,x1,y1,adr) kopiert den Speicherblock ab der Adresse adr an die Bildschirmposition x1, y1. m gibt dabei den Modus in dem das geschehen soll an. Ist m=0, so wird der Inhalt des Bildschirms vom Speicherblock komplett überschrieben. Das sollte wohl der Normalfall sein. Ist m=1, so wird der Bildschirm mit dem Speicherblock odiert, das heißt in Garfik 8 werden beide in dem Sinn gemixt, daß überall ein Pixel gesetzt wird, wo im Speicher ODER auf dem Bildschirm ein Pixel gesetzt war. Wie gesagt sorgt PASTE dafür, daß ein Speicherblock an jeder Stelle des Bildschirms eingesetzt werden kann, nicht nur auf Bytegrenzen. Wie auf dem ATARI ST könnte man damit "Sprites" oder auch einen Mauszeiger in hoher Auflösung erzeugen, wenn man einen Speicherblock Spalte für Spalte bewegt. CUT und PASTE in Grafik 15 Eigentlich können CUT und PASTE nur in Grafik 8 verwendet werden. Rechnet man die Koordinaten von Grafik 15 jedoch richtig um, so kann man sie auch hier verwenden. Die X-Positionen in Grafik 15 müssen verdoppelt und dann um 1 erhöht werden. Dann klappt CUT und PASTE problemlos. Beispiel: Man will in Grafik 15 das Rechteck (10,15)(20,25) ausschneiden. Der CUT-Befehl lautet also: CUT(21,15,41,25,adr). Das Demo Das Programm QE24.QIK zeigt, wie man CUT und PASTE anwenden kann. Zuerst wird Grafik 8 eingeschaltet. Dann wird ein Bild geladen. Dieses Bild wird nun in 30 Rechtecken im Speicher zwischengespeichert. Dazu werden Blöcke der Größe 64*32 ausgeschnitten und der Reihe nach im Speicher ab $5600 abgespeichert. Die Länge eines Blocks beträgt 336. Nun wird der Bildschirm gelöscht. Dazu schaltet man einfach COLOR(125) ein und setzt einen Punkt. Dadurch wird (wie im BASIC) der BS komplett gelöscht. Nun werden die Bildblöcke vom Speicher wieder auf den Bildschirm zurückkopiert. Das geschieht mit dem PASTE-Befehl. Auch hier ist natürlich darauf zu achten, daß die Adressen die selben sind, wie vorher beim Schreiben in den Speicher. Damit das Ganze nicht zu schnell geht, wird jeweils mit .WAIT(5) eine kurze Pause gemacht. Nach einem weiteren Löschen des Bildschirms werden die Bildblöcke nun in umgekehrter Reihenfolge auf den Bildschirm kopiert. Und im nächsten Schritt wird die Reihenfolge des Kopierens auf den Bildschirm nun zufällig bestimmt. Dazu wird jeweils eine Zufallszahl für x und y erzeugt. Aus der Rechteckposition kann dann die Adresse des Bildblocks im Speicher errechnet werden: Pro Zeile gibt es 5 Blöcke, also wird y mit 5 multipliziert, dann wird x addiert. Das ergibt die "Nummer" des Speicherblocks. Also muß diese Nummer noch mit der Länge eines Blocks multipliziert werden. Dann wird die Adresse des ersten Speicherblocks addiert, und schon weis man, wo der zugehörige Block im Speicher zu finden ist. Da jeder Block 64*32 Pixel groß ist, wird nun das original x mit 64 und y mit 32 multipliziert. Nun kann man den Block mit PASTE an die richtige Stelle auf dem Bildschirm setzen. Das Ganze geschieht in einer Schleife 200 mal, damit der Bildschirm sicher ganz aufgebaut wird. Das Ergebnis ist ein Effekt, den man hin und wieder auch im Fernsehen vorgesetzt bekommt. Das komplette Programm sieht dann so aus: * CUT/PASTE IN QUICK * (C) '92 H.SCHOENFELD * * FUER USER MAG BYTE (+ Y1,Y2 I +) WORD (+ CSTART CADR CLEN X1,X2 ADR +) WORD (+ SAVMSC=88 Adresse des Bildspeichers +) MAIN * GRAFIK 8 einschalten CLOSE(6) OPEN(6,0,24,"S:") * S/W SETCOL(1,0,0) SETCOL(2,0,14) * Bild in Bildspeicher laden OPEN(1,4,0,"D1:ATARI.PIC") BGET(1,7680,SAVMSC) CLOSE(1) * Startadresse der CUT-Daten CSTART=$5600 * Laenge eines Blocks CLEN=336 * Aktuelle Adresse CADR=CSTART * Bloecke der Reihe nach ausschneiden X1=0 links oben beginnen Y1=0 REPEAT REPEAT ADD(X1,64,X2) Hoehe ADD(Y1,32,Y2) Breite CUT(X1,Y1,X2,Y2,CADR) ADD(CADR,CLEN,CADR) Naechste Adr ADD(X1,64,X1) Naechste X-Pos UNTIL X1>=320 X1=0 Naechste Zeile ADD(Y1,32,Y1) UNTIL Y1>=192 * Ganzen BS loeschen .WAIT(200) COLOR(125) PLOT(0,0) .WAIT(50) * Bloecke der Reihe nach zurueckholen CADR=CSTART akt. Adr X1=0 Links oben beginnen Y1=0 REPEAT REPEAT PASTE(0,X1,Y1,CADR) .WAIT(5) ADD(CADR,CLEN,CADR) Adr erhoehen ADD(X1,64,X1) naechste Spalte UNTIL X1>=320 X1=0 naechste Zeile ADD(Y1,32,Y1) UNTIL Y1>=192 * Ganzen BS loeschen .WAIT(200) COLOR(125) PLOT(0,0) .WAIT(50) * Bloecke in umgekehrter Reihenfolge * zurueckholen X1=320 rechts unten Y1=192 SUB(CADR,CLEN,CADR) Adr des letzten * Blocks REPEAT SUB(Y1,32,Y1) vorherige Zeile REPEAT SUB(X1,64,X1) vorherige Spalte PASTE(0,X1,Y1,CADR) .WAIT(5) SUB(CADR,CLEN,CADR) vorherige * Blockadresse UNTIL X1=0 X1=320 UNTIL Y1=0 * Ganzen BS loeschen .WAIT(200) COLOR(125) PLOT(0,0) .WAIT(50) * Blocke in zufaelliher Reihenfolge * zurueckholen I=0 Zaehler REPEAT .RND(5,X1) Zufaellige PASTE- .RND(6,Y1) Position MULT(Y1,5,ADR) Zeile * 5 ADD(X1,ADR,ADR) Spalte dazu MULT(ADR,CLEN,ADR) mal Blocklaenge ADD(ADR,CSTART,CADR) plus Startadr MULT(X1,64,X1) Pos mal Blockbreite MULT(Y1,32,Y1) Pos mal Blockhoehe PASTE(0,X1,Y1,CADR) I+ UNTIL I=200 ENDMAIN * Wartet x/50 Sekunden PROC WAIT IN BYTE (+ TIM=540 +) BEGIN REPEAT UNTIL TIM=0 ENDPROC * Liefert Zufallszahl kleiner Max * (Max zwischen 1 und 255) PROC RND IN BYTE (+ MAX +) OUT BYTE (+ RND +) LOCAL BYTE (+ RANDOM=53770 +) BEGIN REPEAT RND=RANDOM UNTIL RND