                  Phobos' Turbo Pascal Demo Coding Tutors
                           [C++ Update by Karma]
                         Tutor 6 - Virtual Screens

12/2/97

      Hi, this is a conversion of Phobos Pascal tutes to C++.
      I've converted all of his pascal code into C++ but I have left
      the original text unaltered.  So I take *no* credit for this
      tutorial, so you still have to mail questions to phobos ;-)
      Anyway the code was written and tested in Borland C++ 3.1
      Any comments by me will be in [ ]. -Karma-

Introduction
-------------
Hello everyone, welcome to my sixth tutor.  Those of you that have
visited my web site may be aware that I am (or was) in a demo group called
Creative Illusions.  Anyway, after seeing Ballistic, CI's first ever demo,
myself, Hippie, and Karma were very disappointed.  It was useless!  We
decided to split from CI and form our own demo group - Abduction.  This is an
all British demo group!  The only one I know of.  Because of this I've had to
change my email address.  It's now a.phobos@dial.pipex.com .  It's a bugger
someone has already taken just Phobos!

[ First of all, I apologise for the extreme delay in this conversion.
  Because of studies I've had _very_ little time for coding. ]

Sorry this tutor is a bit late, it's becoming a bit of a tradition ;-)  I
discovered Quake Internet deathmatch over the weekend.  Woooah!!  It's cool!
BTW - If you wanna challenge me to a few frags anytime just email me and we
can arrange something.

Virtual Screens
----------------
Anyway, I suppose I'd better get on with it.  Okay, up to now we have been
drawing everything we do to the VGA screen.  Straight on to our display.
This is fine for stuff that doesn't move, or where every pixel is updated,
(like the fire in tut5) but if we want to do some animation, things start to
get a bit messy.  If you've been experimenting with some of your own effects
(you should be) you may have tried moving stuff around the screen, redrawing
the thing and deleting the old one.  Looks bad doesn't it.  This is why we
use virtual screens!

A virtual screen is the same as a vga screen except instead of actually being
_the screen_, it's a place in memory.  The place in memory is the exact same
size etc as the vga screen, and we can also address it in the same way too.

[ Its also quicker to write to main memory, than video memory and simply
  copy the lot to the screen in one go.
  If anyone ever emails me, perhaps I'll write some 32-bit screen copy
  routines. hint!, hint! ]

Here's an example of a virtual screen in use :

---------------------------------------------------------

putpixel (160,100,15,vaddr);
flip (vaddr,vga);
cls (vaddr,0);

[ Exactly the same in C++ ]
---------------------------------------------------------

What this code does is puts pixel at 160(x) 100(y) to our virtual screen.
The virtual screen is called vaddr.  Next, the entire virtual screen is
flipped onto the real screen.  Lastly the virtual screen is cleared.
This may seem a long winded way of putting a pixel on the screen.  However,
it means we can do some neat animation.  Look :

-----------------------------------------------------

[Pascal]

USES crt,gfx3;

VAR x : INTEGER;

BEGIN
  setupvirtual;
  setmcga;
  cls (vaddr,0);
  x := 0;
  REPEAT
    line (x,0,x,199,15,vaddr);
    flip (vaddr,vga);
    cls (vaddr,0);
    INC (x);
  UNTIL x = 319;
  settext;
  shutdown;
END.

[C++]

#include "gfx.cpp"

void main() {
  int x;
  setupvirtual();
  setmcga();
  cls(vaddr,0);
  x = 0;
  do {
    line(x,0,x,199,15,vaddr);
    flip(vaddr,vga);
    cls(vaddr,0);
    x++;
    } while (x != 319);
  settext();
  shutdown();
 }

----------------------------------------------------

Paste this program in Pascal and run it.  You may have to add a DELAY (x)
where x is the time in milliseconds to slow it down.  Quite smooth isn't it?
You could speed it up more if you draw a black line to the vaddr instead of
clearing the entire screen.

There are a few commands there that I haven't explained yet so here we go.
When you use virtual screens, you are using a piece of memory.  This piece
of memory must be set up first so you MUST ALWAYS call setupvirtual at the
start of your code.  At this point it's probably a good idea to clear the
vaddr by typing cls(vaddr,0);  This is will ensure there's no crap in it.

[ If you use a virtual screen, you may need to shell to DOS to run your
  program. Because you may not have enough memory to run it from the IDE. ]

At the end of your program you'll want to get rid of your 64K virtual screen.
Just add shutdown to do it.

            REMEMBER - ALWAYS USE setupvirtual AND shutdown
          FAILURE TO DO SO MAY CAUSE ON INTERESTING REBOOTS!!! 
[ And thats a fact! ;-) ]

Well, that's pretty much how it works.  Not too hard eh?  Okay lets make
a nice little bar with our new found knowledge.

First of all, a procedure to draw the bar...

----------------------------------------------

[Pascal]

PROCEDURE bar (y_pos : BYTE);
  VAR loop,loop2,col : INTEGER;
BEGIN
  col := 17;
  FOR loop := 0 TO 20 DO BEGIN
    IF y_pos+loop < 200 THEN FOR loop2 := 0 TO 319 DO
      putpixel (loop2,y_pos+loop,col,vaddr);   {notice we use vaddr not vga}
    IF loop <= 10 THEN INC (col);
    IF loop > 10 THEN DEC (col);
  END;
END;

[C++]

void bar(byte y_pos) {
  int loop,loop2,col = 17;
   for(loop=0;loop<20;loop++) {
    if(y_pos+loop < 200)
     for(loop2=0;loop2<319;loop2++)
      putpixel(loop2,y_pos+loop,col,vaddr); // vaddr instead of vga.
      if(loop <= 10) col++;
      if(loop > 10) col--;
    }
 }

--------------------------------------------------
This will draw a nice little grey shaded bar.  The code is pretty simple to
understand, basically we draw 20 horizontal lines, the first 10 going from
dark to light, the second 10 going from light to dark.  I could have used the
line command instead of drawing 320 pixels on the same row.  This method is
faster however as the line command in gfx3 also has routines for doing
vertical and diagonal lines which slows things down unnecessarily.

Now we just call the bar procedure changing the y position each time.
--------------------------------------------------

[Pascal]

VAR movey : BYTE;

BEGIN
  setupvirtual;
  cls (vaddr,0);
  setmcga;
  movey := 0;
  REPEAT
    REPEAT
      bar (movey);
      waitretrace;
      flip (vaddr,0);
      cls (vaddr,0);
      INC (movey);
    UNTIL (movey = 180) OR (keypressed);
    REPEAT
      bar (movey);
      waitretrace;
      flip (vaddr,vga);
      cls (vaddr,0);
      DEC (movey);
    UNTIL (movey = 0) OR (keypressed);
  UNTIL keypressed;
  settext;
  shuttdown;
END.

[C++]

void main() {
 byte movey = 0;
  setupvirtual();
  cls(vaddr,0);
  setmcga();
   do {
      bar(movey);
      waitretrace();
      flip(vaddr,vga);
      cls(vaddr,0);
      movey++;
    } while (movey < 180 && !kbhit());
    do {
      bar(movey);
      waitretrace();
      flip(vaddr,vga);
      cls(vaddr,0);
      movey--;
    } while (movey > 0 && !kbhit());
  settext();
  shutdown();
 }

------------------------------------------------
This makes the bar move down the screen in the first REPEAT-UNTIL loop, and
then up the screen in the second.  The waitretrace statement makes the
computer wait until the screen display is updated before drawing to it.  This
makes it look much smoother.

In closing
-----------
Well that's about it I think for virtual screens.  As usual, if you have any
problems, questions, flames, comments, etc.. just mail me!

I have added a nice little sinus part to the end of the example code.  I'll
leave it for you to work it out until next week when I'll be explaining sinus
lines, and circles!

-----------------------------------------------------------------------------
                            - C O N T A C T -

Email Phobos!

a.phobos@dial.pipex.com

[ I would like some comments/feedback on these conversions.
  email Karma at: karma@digicron.com ]

Visit my TP demo coding web page!

http://dspace.dial.pipex.com/town/place/abi67/


Seeya...

