s_rohrbacher (05/08/90)
Some days ago, one of you asked for a solution to do fast flicker-free animation in TurboPascal. I myself had the same problem and circumvented it by a simple technique called "page-flipping": nearly every graphic card has 2 independent graphic pages, so it is possible to draw at one page while showing the other. If the "background" page is finished, you just "flip" the pages: thus, at any time all actions take place in the background and you get a smooth animation! In TP, you choose the visible page with "SetVisualPage" and the working page with "SetActivePage". - Take the following program as an example: it animates a hatched square, either with or without page-flipping (adapt proc. "Initialize" if you have a Hercules instead of an EGA/VGA): PROGRAM page_flipping_demo; {by Kai Rohrbacher, TP 5.0, 4/25/90} USES Crt,Graph; CONST seeing_page:Word=0; {number of actual seen page} VAR GraphDriver,GraphMode,x,y,xold,yold,xtemp,ytemp:Integer; Sprite:Pointer; {pointer to sprite-data} ch:char; WITH_PAGE_FLIPPING:Boolean; {demonstration mode} PROCEDURE Initialize; {set any graphic-mode with 2 pages; here EGA} BEGIN GraphDriver:=EGA; GraphMode:=EGAHi; InitGraph(GraphDriver,GraphMode,''); IF GraphResult<>grOK THEN BEGIN Writeln('No EGA!'); Halt(1) END; END; PROCEDURE initialize_flip; {clear pages; show one, work on the other} BEGIN setactivepage(0); cleardevice; outtextxy(100,0,'Page 0 - Use I,J,K,M, Q=Quit'); setactivepage(1); cleardevice; outtextxy(100,0,'Page 1 - Use I,J,K,M, Q=Quit'); setactivepage(1-seeing_page); setvisualpage(seeing_page) END; PROCEDURE flip; {exchange active & visible page} BEGIN setactivepage(seeing_page); seeing_page:=1-seeing_page; setvisualpage(seeing_page); END; PROCEDURE update_sprite; {works totally on background page!} BEGIN IF (xold<>-1) AND (yold<>-1) THEN PutImage(xold,yold,sprite^,XORput); PutImage(x,y,sprite^,XORput) END; BEGIN {main} Write('With (1) or without (2) pageflipping? '); REPEAT ch:=UpCase(readkey) UNTIL ch in ['1','2']; WITH_PAGE_FLIPPING:=ch='1'; {set mode} Initialize; {generate sprite and save it on TP's stack:} rectangle(0,0,50,50); setFillStyle(Hatchfill,white); FloodFill(1,1,white); GetMem(sprite,ImageSize(0,0,50,50)); GetImage(0,0,50,50,sprite^); cleardevice; outtextxy(0,0,'Use I,J,K,M, Q=Quit'); IF WITH_PAGE_FLIPPING THEN initialize_flip; xold:=-1; yold:=-1; xtemp:=-1; ytemp:=-1; {-1=flag: 'currently not used'} x:=100; y:=100; {starting point of animation} REPEAT ch:=UpCase(readkey); CASE ch OF {what action?} 'J':dec(x); 'K':inc(x); 'I':dec(y); 'M':inc(y); 'Q':; ELSE BEGIN sound(1200); delay(100); nosound END END; update_sprite; {remove old, draw new} IF WITH_PAGE_FLIPPING THEN BEGIN {shift through: x->xtemp->xold, y->ytemp->yoldf} xold:=xtemp; yold:=ytemp; xtemp:=x; ytemp:=y; flip END {so after 2 cycles the sprite is cleared from correct page} ELSE BEGIN xold:=x; yold:=y END; {no flipping=no such mechanism needed} UNTIL ch='Q'; FreeMem(sprite,ImageSize(0,0,50,50)); closegraph; {end correctly} END. The only thing to notice is that you have to store coordinates for 2 cycles to be able to erase a sprite on the correct page. There remains one last possibility of (minor) flicker: depending on your PC's BIOS, it may happen that programs flip pages while the cathode ray is in the midst of displaying data: in that case you have to bypass BIOS and synchronize switching directly with the "vertical retrace" (the moment while the cathode ray moves back from the bottom-right to the upper-left corner). As a time-critical task (the corresponding bit at port $3DA, Bitmask 8 (or $3BA, Bitmask 128 for HGC) toggles with 50Hz), you should do that in assembler. To all of you who hope to program an arcade game completely in TP, be warned: TP is just to slow to do the job (try to animate -say- 30 sprites at once)! Me too, I had to discover this (3 years ago) -and came out with a self-written TP-unit, spritedesigner and a lot of integrated assembler stuff (for the animation itself, background-saving, collision detection, scrolling and that things). I am planning to release this package (as shareware) here in FRG very soon, so if you are interested, watch out! S_ROHRBACHER@IRAV1.IRA.UKA.DE (Kai Rohrbacher)
rener@cs.eur.nl (Rene Roelofs) (05/09/90)
>Some days ago, one of you asked for a solution to do fast flicker-free >animation in TurboPascal. I myself had the same problem and circumvented it by >a simple technique called "page-flipping": nearly every graphic card has 2 >independent graphic pages, so it is possible to draw at one page while showing >the other. If the "background" page is finished, you just "flip" the pages: >thus, at any time all actions take place in the background and you get a smooth >animation! This is a good demo and contains some usefull hints to get the flicker out of my game. But since I use more then yust one moving sprite on my screen and a lot of background (most of them random) items, I am looking for somekind of COPYVIDEOPAGE. This can then be used to avoid a lot of double drawing in both videopages and should be used as follow. Copyvideopage( 0, 1); updatepage_1; showpage_1; copyvideopage( 1, 0); updatepage_0 etc... Does anybody have any suggestions to create such a routine? -- |-----\ Rene Roelofs | | Dept. of Computer Science /|-----/ Erasmus University Rotterdam, The Netherlands \| \ uucp: mcvax!hp4nl!eurtrx!euraiv1!rener /| \