VGA-Kurs - Part #7 Hallo Leute! Es wird Zeit fr 'T.C.P.'s Beginner's Guide To VGA Coding', Part VII! In den ersten 6 Teilen haben wir die Grundlagen des VGA Codings besprochen (allerdings ohne dabei auf die Register der VGA-Karte selbst einzugehen, wer dazu Informationen braucht, m”ge sich bitte ein Buch kaufen, ich empfehle "VGA- und SVGA-Programmierung" von M. Uphoff, Addison Wesley). Ich werde ab jetzt in den folgenden Teilen dieses Kurses diese Grundlagen als Wissen vorraussetzen und auf verschiedene Effekte, Tricks oder „hnliches eingehen. In diesem Teil will ich mit einem sehr simplen Effekt anfangen, mit dem sich allerdings sehr sch”ne Resultate erzielen lassen: Der Shadebob-Effekt. Die Shadebobs sind meiner Meinung nach zu Unrecht wegen ihrer einfachen Programmierung in Verruf gekommen, und werden h„ufig als Lamer-Effekt betitelt. Ich fr meinen Teil habe nichts gegen Shadebobs in Demos, auch wenn sie schon etwas „lter sind. Man kann mit dem Prinzip wirklich sehr viel anfangen, man sollte es nur nicht bertreiben, wie es manche „ltere Demos zeigen, in denen zum Teil bis zu 5 Minuten lange Shadebob-Parts enthalten sind. Aber fangen wir jetzt an. Das Prinzip der Shadebobs ist einfach erkl„rt. Wenn man sich ein beliebiges Quadrat auf dem schwarzen Screen sucht, und alle Pixelwerte dieses Quadrates um eins erh”ht, sieht man ein blaues Quadrat, weil in der Standardpalette nach der Farbe 0 (schwarz) die Farbe blau kommt. Wenn man nun ein anderes, gleichgroáes Quadrat nimmt, das sich mit dem alten in einem Pixel berlagert, dann ist dieses auch blau, nur das eine Pixel, an dem sich die beiden berlagern, hat die Farbe grn, denn sein Farbwert wurde zweimal erh”ht. Falls ihr euch nicht so genau vorstellen k”nnt, wie das vor sich geht, hilft euch vielleicht das Listing weiter. uses crt; var n1,n2 : byte; begin asm mov ax,13h; int 10h end; for n1 := 0 to 9 do for n2 := 0 to 9 do mem[$A000:n2*320+n1] := mem[$A000:n2*320+n1] + 1; for n1 := 9 to 18 do for n2 := 9 to 18 do mem[$A000:n2*320+n1] := mem[$A000:n2*320+n1] + 1; readkey; asm mov ax,3; int 10h end; end. Wenn wir jetzt eine Farbpalette setzen, die einen durchgehenden blauen Farbverlauf enth„lt, und st„ndig neue Quadrate an zuf„lligen Positionen auf den Bildschirm setzen, h„tten wir den ersten Shadebob-Typ: Die Colorcycle-Bobs. uses crt; var Pal : array[0..767] of byte; n1,n2 : byte; procedure SetPalette;assembler; { Setzt die Palette in Pal } asm mov dx,3C8h xor al,al out dx,al mov cx,768 mov dx,3C9h mov si,offset pal @Jmp1: lodsb out dx,al loop @Jmp1 end; procedure BluePal; { Schreibt eine blaue Palette in Pal setzt sie mittels } var loop : integer; { SetPalette } begin for loop := 0 to 31 do begin pal[loop*3+2] := loop * 2; pal[(63-loop)*3+2] := loop * 2; pal[(loop+64)*3+2] := loop * 2; pal[(127-loop)*3+2] := loop * 2; pal[(loop+128)*3+2] := loop * 2; pal[(191-loop)*3+2] := loop * 2; pal[(loop+192)*3+2] := loop * 2; pal[(255-loop)*3+2] := loop * 2; end; setpalette; end; procedure SetBob(x,y:word); { Setzt ein Bob an die Koords X,Y } var n1,n2 : byte; begin for n1 := 0 to 19 do { Hier werden in einem 20x20 Pixel groáen Quadrat } for n2 := 0 to 19 do { alle Pixelwerte um 1 erh”ht } mem[$A000:(n2+y)*320+n1+x] := mem[$A000:(n2+y)*320+n1+x] + 1; end; begin asm mov ax,13h; int 10h end; BluePal; randomize; repeat SetBob(random(300),random(180)); { Bob an zuf„llige Position setzen } until keypressed; readkey; asm mov ax,3; int 10h end; end. Das obige Listing enth„lt noch eine Pascal-Version der SetBob-Routine, die nicht gerade sehr optimiert ist. Wer also gerade zu viel Zeit hat, kann das Ganze noch ein biáchen optimieren. In der dritten Zeile der SetBob-Prozedur kann das '+ 1' durch ein '+ random(4)' ersetzt werden. Dadurch wird der Effekt k”rniger. Ist Geschmackssache. So, das Prinzip der Shadebobs drfte jetzt klar sein. Als zweite in der Reihe der verschiedenen Shadebob-Typen w„ren da die Snakebobs. Bei dieser Art von Bobs werden entweder ein oder mehrere (je mehr desto besser) Shadebobs gezeichnet und dann z.B. um ein Pixel nach rechts und eins nach unten bewegt. Das macht man solange, bis der Bob am unteren Rand des Screens angelangt hat. Man hat jetzt eine Line, die schr„g ber den Bildschirm verl„uft. Nun „ndert man die Bewegungsrichtung, indem man den Inkrementationsparameter umkehrt, also den Bob jetzt nach oben bewegt. Trifft der Bob nun auf den rechten Rand des Screens, kehrt man auch die horizontale Bewegungsrichtung um. Das sieht dann so aus: uses crt; var Pal : array[0..767] of byte; x1,y1,x2,y2 : word; { X- und Y-Koords der beiden Bobs } incx1,incy1,incx2,incy2 : shortint; { Inkrementationsparameter } { Hier die Prozeduren SetBob und SetPalette einfgen } procedure RainbowPal; { Erstellt eine bunte Palette } var loop : integer; begin for loop := 0 to 31 do begin pal[loop*3] := loop * 2; pal[(63-loop)*3] := loop * 2; pal[(loop+64)*3+1] := loop * 2; pal[(127-loop)*3+1] := loop * 2; pal[(loop+128)*3+2] := loop * 2; pal[(191-loop)*3+2] := loop * 2; pal[(loop+192)*3] := loop * 2; pal[(loop+192)*3+1] := loop * 2; pal[(loop+192)*3+2] := loop * 2; pal[(255-loop)*3] := loop * 2; pal[(255-loop)*3+1] := loop * 2; pal[(255-loop)*3+2] := loop * 2; end; setpalette; end; begin asm mov ax,13h; int 10h end; RainbowPal; randomize; x1 := random(280); { Zuf„llige X- und Y- Positionen fr } y1 := random(160); { beide Bobs } x2 := random(280); y2 := random(160); incx1 := 1; { Bob 1 wird nach rechts und nach unten } incy1 := 1; { bewegt } incx2 := -1; { Bob 2 wird nach links und nach unten } incy2 := 1; { bewegt } repeat inc(x1,incx1); { Bob-Positionen ver„ndern } inc(y1,incy1); inc(x2,incx2); inc(y2,incy2); if (x1 = 299) or (x1 = 0) then incx1 := -incx1; { šberprfen, ob einer } if (y1 = 179) or (y1 = 0) then incy1 := -incy1; { der Bobs am Rand des } if (x2 = 299) or (x2 = 0) then incx2 := -incx2; { Screens ist, und wenn } if (y2 = 179) or (y2 = 0) then incy2 := -incy2; { ja dann Wert umkehren } SetBob(x1,y1); { Die beiden Bobs zeichnen } SetBob(x2,y2); until keypressed; readkey; asm mov ax,3; int 10h end; end. Wir kommen nun zu meinen pers”nlichen Lieblingsbobs, den Sinusbobs. Der Name basiert darauf, daá hier mittels einer Sinusformel die Koordinaten fr die Bobs berechnet werden, wodurch sehr sch”ne Formen zustande kommen. Allerdings sind die Quadratischen Bobs hier nicht geeignet, passender sind runde. Man kann stattdessen natrlich auch kleine Symbole oder Logos benutzen, das sieht nicht schlecht aus. uses crt; const VGA : word = $A000; SinOfs = 40; { Offset } SinAmp = 50; { Amplitude } SinLen = 255; { und L„nge der Sinustabelle } SprPic : array[0..15,0..15] of byte = ( (0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0), (0,0,0,0,2,2,3,3,3,3,2,2,0,0,0,0), (0,0,0,2,3,3,3,3,3,3,3,3,2,0,0,0), (0,0,2,3,3,3,3,3,3,3,3,3,3,2,0,0), (0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0), (0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0), (2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2), (2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2), (2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2), (2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2), (0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0), (0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0), (0,0,2,3,3,3,3,3,3,3,3,3,3,2,0,0), (0,0,0,2,3,3,3,3,3,3,3,3,2,0,0,0), (0,0,0,0,2,2,3,3,3,3,2,2,0,0,0,0), (0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0) ); var SinTab : array[0..SinLen] of word; Pal : array[0..767] of byte; X,Y,n : integer; I1,I2,J1,J2 : byte; { Hier die Prozeduren SetPalette und BluePal einsetzen } procedure CalcSinus(SinPar:byte); begin for n := 0 to SinLen do SinTab[n] := round(sin(n*SinPar*pi/SinLen)*SinAmp)+SinOfs; end; procedure WaitRetrace;assembler; asm mov dx,3DAh @loop1: in al,dx and al,08h jz @loop1 @loop2: in al,dx and al,08h jz @loop2 end; procedure SetBob(X,Y:word;W,H:byte;Sprite:pointer);assembler; asm push ds { DS sichern } lds si,[Sprite] { DS:SI mit dem Spritepointer laden } mov es,vga { VGA-Segment nach ES } cld mov ax,Y { Offset des Bobs berechnen } shl ax,6 mov di,ax shl ax,2 add di,ax add di,X mov bh,H mov cx,320 sub cl,W sbb ch,0 @L: mov bl,W @L2: lodsb { Wert laden } or al,al { Wert = 0 ? } jz @S { Wenn ja, nicht erh”hen } mov dl,es:[di] { Pixelwert vom VGA holen } add dl,al { Wert erh”hen } and dl,63 mov es:[di],dl { und neuen Pixelwert schreiben } @S: inc di { n„chste Pixelposition } dec bl { Z„hler dekrementieren } jnz @L2 { wenn <> 0 dann innerer Loop } add di,cx { n„chste Zeile auf VGA } dec bh { Z„hler dekrementieren } jnz @L { wenn <> 0 dann „uáerer Loop } pop ds end; begin asm mov ax,13h; int 10h end; BluePal; randomize; CalcSinus(random(8)); { Sinustabelle berechnen } I1 := 0; { Indizes fr Sinustabelle } I2 := 200; J1 := 0; J2 := 200; repeat X := SinTab[I1]+SinTab[I2]; { Werte addieren } Y := SinTab[J1]+SinTab[J2]; inc(I1,2); { Neue Indexwerte } inc(I2,3); inc(J1); inc(J2,2); waitretrace; SetBob(80+X,Y,16,16,addr(SprPic)); { Bob zeichnen } until keypressed; readkey; asm mov ax,3; int 10h end; end. Das Wesentliche hier, das Berechnen der Sinustabelle, findet in der Prozedur CalcSinus statt, der ein Parameter bergeben wird, nach dem sich die sp„tere Form der Bobs richtet. Ebenso k”nnen die Konstanten fr das Offset und die Amplitude der Tabelle am Anfang des Listings ver„ndert werden. Wer ein biáchen Ahnung von Mathe hat, kann so zu sehr sch”nen Formen kommen. Die Prozedur SetBob ist in diesem Fall 100% Assembler, allerdings zeichnet sie kein Quadrat, sondern das Sprite SprPic auf den Bildschirm, wobei sie die Pixelwerte um die Werte im Sprite erh”ht. Ich hoffe, ihr k”nnt mit diesen sch”nen Effekten etwas anfangen und aus ihnen lernen. Es gibt noch eine Menge anderer M”glichkeiten, die einem die Shadebobs bieten. Man k”nnte sie zum Beispiel mit ein paar Vektorroutinen verbinden. Auch Delay-Vektoren w„ren hiermit m”glich, allerdings ist es wohl sinnvoller, wenn man, anstatt alle Farbwerte des vorigen Objekts herabzusetzen, das Objekt neu in einer dunkleren Farbe zeichnet. In der n„chsten Ausgabe werde ich wahrscheinlich einen anderen Effekt beschreiben. Welchen, weiá ich noch nicht genau. [ This text copyright (c) 1995-96 Johannes Spohr. All rights reserved. ] [ Distributed exclusively through PC-Heimwerker, Verlag Thomas Eberle. ] [ ] [ No part of this document may be reproduced, transmitted, ] [ transcribed, stored in a retrieval system, or translated into any ] [ human or computer language, in any form or by any means; electronic, ] [ mechanical, magnetic, optical, chemical, manual or otherwise, ] [ without the expressed written permission of the author. ] [ ] [ The information contained in this text is believed to be correct. ] [ The text is subject to change without notice and does not represent ] [ a commitment on the part of the author. ] [ The author does not make a warranty of any kind with regard to this ] [ material, including, but not limited to, the implied warranties of ] [ merchantability and fitness for a particular purpose. The author ] [ shall not be liable for errors contained herein or for incidental or ] [ consequential damages in connection with the furnishing, performance ] [ or use of this material. ]