💾 Archived View for gemini.spam.works › mirrors › textfiles › programming › astrainer.txt captured on 2022-04-29 at 00:27:00.

View Raw

More Information

⬅️ Previous capture (2020-10-31)

-=-=-=-=-=-=-

Hello there.

My name is Denthor (Grant Smith) of the South African demo group ASPHYXIA.
This is a trainer that have been writing on and off for the last few months
in order to help out budding young graphics programmers. Currently there are
nine tutorials in all, each with a text file and accompianing pascal source
file. Also included are two or three "bonus" pascal files with various
effects.

I have left the files in their origional form, so they contain some local
stuff which you can ignore.

PLEASE LEAVE A RESPONSE! Any comments/criticisms/flames/suggestions etc are
very welcome (I love getting mail!)

Leave all comments to   smith9@batis.bis.und.ac.za

Hope to hear from you soon!

--
                          DENTHOR, coder for ...
        _____   _____   ____   __   __  ___  ___ ___  ___  __   _____
       /  _  \ /  ___> |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
       |  _  | \___  \ |  __/ |   _   |  \    /   >    <  |  | |  _  |
       \_/ \_/ <_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
                       smith9@batis.bis.und.ac.za
    The great South African Demo Team! Contact us for info/code exchange!    
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 1 ]==--



? Introduction



Hi there! This is Denthor of ASPHYXIA, AKA Grant Smith. This training
program is aimed at all those budding young demo coders out there. I am
assuming that the reader is fairly young, has a bit of basic Std. 6 math
under his belt, has done a bit of programming before, probably in BASIC,
and wants to learn how to write a demo all of his/her own.

This I what I am going to do. I am going to describe how certain routines
work, and even give you working source code on how you do it. The source
code will assume that you have a VGA card that can handle the
320x200x256 mode. I will also assume that you have Turbo Pascal 6.0 or
above (this is because some of the code will be in Assembly language,
and Turbo Pascal 6.0 makes this incredibly easy to use). By the end of
the first "run" of sections, you will be able to code some cool demo
stuff all by yourself. The info you need, I will provide to you, but it
will be you who decides on the most spectacular way to use it.

Why not download some of our demos and see what I'm trying to head you
towards.

I will be posting one part a week on the Mailbox BBS. I have the first
"run" of sections worked out, but if you want me to also do sections on
other areas of coding, leave a message to Grant Smith in private E-Mail,
or start a conversation here in this conference. I will do a bit of
moderating of a sort, and point out things that have been done wrong.

In this, the first part, I will show you how you are supposed to set up
your Pascal program, how to get into 320x200x256 graphics mode without a
BGI file, and various methods of putpixels and a clearscreen utility.

NOTE : I drop source code all through my explanations. You needn't try
       to grab all of it from all over the place, at the end of each part I
       add a little program that uses all the new routines that we have
       learned. If you do not fully understand a section, leave me
       private mail telling me what you don't understand or asking how I
       got something etc, and I will try to make myself clearer. One
       last thing : When you spot a mistake I have made in one of my
       parts, leave me mail and I will correct it post-haste.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Disclaimer



Hi again, sorry that I have to add this, but here goes. All source code
obtained from this series of instruction programs is used at your own
risk. Denthor and the ASPHYXIA demo team hold no responsibility for any
loss or damage suffered by anyone through the use of this code. Look
guys, the code I'm going to give you has been used by us before in
Demos, Applications etc, and we have never had any compliants of machine
damage, but if something does go wrong with your computer, don't blame
us. Sorry, but that's the way it is.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? The MCGA mode and how you get into it in Pascal without a BGI


Lets face it. BGI's are next to worthless for demo coding. It is
difficult to find something that is slower then the BGI units for doing
graphics. Another thing is, they wern't really meant for 256 color
screens anyhow. You have to obtain a specific external 256VGA BGI to get
into it in Pascal, and it just doesn't make the grade.

So the question remains, how do we get into MCGA 320x200x256 mode in
Pascal without a BGI? The answer is simple : Assembly language.
Obviously assembly language has loads of functions to handle the VGA
card, and this is just one of them. If you look in Norton Gides to
Assembly Language, it says this ...

____________________________________________________________________
INT 10h,  00h (0)        Set Video Mode

    Sets the video mode.

       On entry:      AH         00h
                      AL         Video mode

       Returns:       None

       Registers destroyed:      AX, SP, BP, SI, DI
??????????????????????????????????????????????????????????????????????????

This is all well and good, but what does it mean? It means that if you
plug in the video mode into AL and call interrupt 10h, SHAZAM! you are
in the mode of your choice. Now, the MCGA video mode is mode 13h, and
here is how we do it in Pascal.

Procedure SetMCGA;
BEGIN
  asm
        mov     ax,0013h
        int     10h
  end;
END;

There you have it! One call to that procedure, and BANG you are in
320x200x256 mode. We can't actually do anything in it yet, so to go back
to text mode, you make the video mode equal to 03h, as seen below :

Procedure SetText;
BEGIN
  asm
        mov     ax,0003h
        int     10h
  end;
END;


BANG! We are back in text mode! Now, cry all your enquiring minds, what
use is this? We can get into the mode, but how do we actually SHOW
something on the screen? For that, you must move onto the next section
....

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Clearing the screen to a specific color

Now that we are in MCGA mode, how do we clear the screen. The answer is
simple : you must just remember that the base adress of the screen is
$a000. From $a000, the next 64000 bytes are what is actually displayed on
the screen (Note : 320 * 200 = 64000). So to clear the screen, you just use
the fillchar command (a basic Pascal command) like so :

      FillChar (Mem [$a000:0],64000,Col);

What the mem command passes the Segment base and the Offset of a part of
memory : in this case the screen base is the Segment, and we are starting
at the top of the screen; Offset 0. The 64000 is the size of the screen
(see above), and Col is a value between 0 and 255, which represents the
color you want to clear the screen to.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Putting a pixel on the screen (two different methoods)

If you look in Norton Guides about putting a pixel onto the screen, you
will see this  :


??????????????????????????????????????????????????????????????????????????
    Writes a pixel dot of a specified color at a specified screen
    coordinate.

    On entry:      AH         0Ch
                   AL         Pixel color
                   CX         Horizontal position of pixel
                   DX         Vertical position of pixel
                   BH         Display page number (graphics modes with more
                              than 1 page)

    Returns:       None

    Registers destroyed:      AX, SP, BP, SI, DI
??????????????????????????????????????????????????????????????????????????

As seen from our SetMCGA example, you would write this by doing the following:

Procedure INTPutpixel (X,Y : Integer; Col : Byte);
BEGIN
  asm
     mov        ah,0Ch
     mov        al,[col]
     mov        cx,[x]
     mov        dx,[y]
     mov        bx,[1]
     int        10h
  end;
END;

The X would be the X-Coordinate, the Y would be the Y-Coordinate, and the Col
would be the color of the pixel to place. Note that MCGA has 256 colors,
numbered 0 to 255. The startoff pallette is pretty grotty, and I will show
you how to alter it in my next lesson, but for now you will have to hunt for
colors that fit in for what you want to do. Luckily, a byte is 0 to 255, so
that is what we pass to the col variable. Have a look at the following.

    CGA = 4 colours.
    4x4 = 16
    EGA = 16 colors.
    16x16 = 256
    VGA = 256 colors.
    Therefore an EGA is a CGA squared, and a VGA is an EGA squared ;-)

Anyway, back to reality. Even though the abouve procedure is written in
assembly language, it is slooow. Why? I hear your enquiring minds cry. The
reason is simple : It uses interrupts (It calls INT 10h). Interrupts are
sloooow ... which is okay for getting into MCGA mode, but not for trying
to put down a pixel lickety-split. So, why not try the following ...

Procedure MEMPutpixel (X,Y : Integer; Col : Byte);
BEGIN
  Mem [VGA:X+(Y*320)]:=Col;
END;


The Mem command, as we have seen above, allows you to point at a certain
point in memory ... the starting point is $a000, the base of the VGA's
memory, and then we specify how far into this base memory we start.
Think of the monitor this way. It starts in the top left hand corner at
0. As you increase the number, you start to move across the screen to your
right, until you reach 320. At 320, you have gone all the way across the
screen and come back out the left side, one pixel down. This carries on
until you reach 63999, at the bottom right hand side of the screen. This
is how we get the equation X+(Y*320). For every increased Y, we must
increment the number by 320. Once we are at the beginning of the Y line
we want, we add our X by how far out we want to be. This gives us the
exact point in memory that we want to be at, and then we set it equal to
the pixel value we want.

The MEM methood of putpixel is much faster, and it is shown in the sample
program at the end of this lesson. The ASPHYXIA team uses neither putpixel;
we use a DMA-Straight-To-Screen-Kill-Yer-Momma-With-An-Axe type putipixel
which is FAST. We will give it out, but only to those of you who show us
you are serious about coding. If you do do anything, upload it to me,
I will be very interested to see it. Remember : If you do glean anything
from these training sessions, give us a mention in your demos and UPLOAD
YOUR DEMO TO US!

Well, after this is the sample program; have fun with it, UNDERSTAND it,
and next week I will start on fun with the pallette.

See you all later,
    - Denthor




                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 2 ]==--



? Introduction



Hi there again! This is Grant Smith, AKA Denthor of ASPHYXIA. This is the
second part of my Training Program for new programmers. I have only had a
lukewarm response to my first part of the trainer series ... remember, if
I don't hear from you, I will assume that you are all dead and will stop
writing the series ;-). Also, if you do get in contact with me I will give
you some of our fast assembly routines which will speed up your demos no
end. So go on, leave mail to GRANT SMITH in the main section of the
MailBox BBS, start up a discussion or ask a few questions in this Conference,
leave mail to ASPHYXIA on the ASPHYXIA BBS, leave mail to Denthor on
Connectix, or write to Grant Smith,
                       P.O.Box 270
                       Kloof
                       3640
See, there are many ways you can get in contact with me! Use one of them!

In this part, I will put the Pallette through it's paces. What the hell is
a pallette? How do I find out what it is? How do I set it? How do I stop
the "fuzz" that appears on the screen when I change the pallette? How do
I black out the screen using the pallette? How do I fade in a screen?
How do I fade out a screen? Why are telephone calls so expensive?
Most of these quesions will be answered in this, the second part of my
Trainer Series for Pascal.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is the Pallette?

A few weeks ago a friend of mine was playing a computer game. In the game
there was a machine with stripes of blue running across it. When the
machine was activated, while half of the the blue stripes stayed the same,
the other half started to change color and glow. He asked me how two stripes
of the same color suddenly become different like that. The answer is simple:
the program was changing the pallette. As you know from Part 1, there are
256 colors in MCGA mode, numbered 0 to 255. What you don't know is that each
if those colors is made up of different intensities of Red, Green and Blue,
the primary colors (you should have learned about the primary colors at
school). These intensities are numbers between 0 and 63. The color of
bright red would for example be obtained by setting red intensity to 63,
green intensity to 0, and blue intensity to 0. This means that two colors
can look exactly the same, eg you can set color 10 to bright red and color
78 to color bright red. If you draw a picture using both of those colors,
no-one will be able to tell the difference between the two.. It is only
when you again change the pallette of either of them will they be able to
tell the difference. Also, by changing the whole pallette, you can obtain
the "Fade in" and "Fade out" effects found in many demos and games.
Pallette manipulation can become quite confusing to some people, because
colors that look the same are in fact totally seperate.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I read in the pallette value of a color?

This is very easy to do. To read in the pallette value, you enter in the
number of the color you want into port $3c7, then read in the values of
red, green and blue respectively from port $3c9. Simple, huh? Here is a
procedure that does it for you :

Procedure GetPal(ColorNo : Byte; Var R,G,B : Byte);
  { This reads the values of the Red, Green and Blue values of a certain
    color and returns them to you. }
Begin
   Port[$3c7] := ColorNo;
   R := Port[$3c9];
   G := Port[$3c9];
   B := Port[$3c9];
End;

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I set the pallette value of a color?

This is also as easy as 3.1415926535897932385. What you do is you enter in
the number of the color you want to change into port $3c8, then enter the
values of red, green and blue respectively into port $3c9. Because you are
all so lazy I have written the procedure for you ;-)


Procedure Pal(ColorNo : Byte; R,G,B : Byte);
  { This sets the Red, Green and Blue values of a certain color }
Begin
   Port[$3c8] := ColorNo;
   Port[$3c9] := R;
   Port[$3c9] := G;
   Port[$3c9] := B;
End;


Asphyxia doesn't use the above pallete procedures, we use assembler versions,
which will be given to PEOPLE WHO RESPOND TO THIS TRAINER SERIES (HINT,
HINT)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I stop the "fuzz" that appears on my screen when I change the
        pallette?

If you have used the pallette before, you will have noticed that there is
quite a bit of "fuzz" on the screen when you change it. The way we counter
this is as follows : There is an elctron beam on your monitor that is
constantly updating your screen from top to bottom. As it gets to the
bottom of the screen, it takes a while for it to get back up to the top of
the screen to start updating the screen again. The period where it moves
from the bottom to the top is called the Verticle Retrace. During the
verticle retrace you may change the pallette without affecting what is
on the screen. What we do is that we wait until a verticle retrace has
started by calling a certain procedure; this means that everything we do
now will only be shown after the verticle retrace, so we can do all sorts
of strange and unusual things to the screen during this retrace and only
the results will be shown when the retrace is finished. This is way cool,
as it means that when we change the pallette, the fuzz doesn't appear on
the screen, only the result (the changed pallette), is seen after the
retrace! Neat, huh? ;-) I have put the purely assembler WaitRetrace routine
in the sample code that follows this message. Use it wisely, my son.

NOTE : WaitRetrace can be a great help to your coding ... code that fits
       into one retrace will mean that the demo will run at the same
       speed no matter what your computer speed (unless you are doing a lot
       during the WaitRetrace and the computer is slooooow). Note that in
       the following sample program and in our SilkyDemo, the thing will run
       at the same speed whether turbo is on or off.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I black out the screen using the pallette?

This is basic : just set the Red, Green and Blue values of all colors to
zero intensity, like so :

Procedure Blackout;
  { This procedure blackens the screen by setting the pallette values of
    all the colors to zero. }
VAR loop1:integer;
BEGIN
  WaitRetrace;
  For loop1:=0 to 255 do
    Pal (loop1,0,0,0);
END;


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I fade in a screen?

Okay, this can be VERY effective. What you must first do is grab the
pallette into a variable, like so :

   VAR Pall := Array [0.255,1..3] of BYTE;

0 to 255 is for the 256 colors in MCGA mode, 1 to 3 is red, green and blue
intensity values;

Procedure GrabPallette;
VAR loop1:integer;
BEGIN
  For loop1:=0 to 255 do
    Getpal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]);
END;

This loads the entire pallette into variable pall. Then you must blackout
the screen (see above), and draw what you want to screen without the
construction being shown. Then what you do is go throgh the pallette. For
each color, you see if the individual intensities are what they should be.
If not, you increase them by one unit until they are. Beacuse intensites
are in a range from 0 to 63, you only need do this a maximum of 64 times.

Procedure Fadeup;
VAR loop1,loop2:integer;
    Tmp : Array [1..3] of byte;
      { This is temporary storage for the values of a color }
BEGIN
  For loop1:=1 to 64 do BEGIN
      { A color value for Red, green or blue is 0 to 63, so this loop only
        need be executed a maximum of 64 times }
    WaitRetrace;
    For loop2:=0 to 255 do BEGIN
      Getpal (loop2,Tmp[1],Tmp[2],Tmp[3]);
      If Tmp[1]<Pall[loop2,1] then inc (Tmp[1]);
      If Tmp[2]<Pall[loop2,2] then inc (Tmp[2]);
      If Tmp[3]<Pall[loop2,3] then inc (Tmp[3]);
        { If the Red, Green or Blue values of color loop2 are less then they
          should be, increase them by one. }
      Pal (loop2,Tmp[1],Tmp[2],Tmp[3]);
        { Set the new, altered pallette color. }
    END;
  END;
END;

Hey-presto! The screen fades up. You can just add in a delay before the
waitretrace if you feel it is too fast. Cool, no?


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I fade out a screen?

This is just like the fade in of a screen, just in the opposite direction.
What you do is you check each color intensity. If it is not yet zero, you
decrease it by one until it is. BAAASIIIC!

Procedure FadeDown;
VAR loop1,loop2:integer;
    Tmp : Array [1..3] of byte;
      { This is temporary storage for the values of a color }
BEGIN
  For loop1:=1 to 64 do BEGIN
    WaitRetrace;
    For loop2:=0 to 255 do BEGIN
      Getpal (loop2,Tmp[1],Tmp[2],Tmp[3]);
      If Tmp[1]>0 then dec (Tmp[1]);
      If Tmp[2]>0 then dec (Tmp[2]);
      If Tmp[3]>0 then dec (Tmp[3]);
        { If the Red, Green or Blue values of color loop2 are not yet zero,
          then, decrease them by one. }
      Pal (loop2,Tmp[1],Tmp[2],Tmp[3]);
        { Set the new, altered pallette color. }
    END;
  END;
END;

Again, to slow the above down, put in a delay above the WaitRetrace. Fading
out the screen looks SO much more impressive then just clearing the screen;
it can make a world of difference in the impression your demo etc will
leave on the people viewing it. To restore the pallette, just do this :

Procedure RestorePallette;
VAR loop1:integer;
BEGIN
  WaitRetrace;
  For loop1:=0 to 255 do
    pal (loop1,Pall[loop1,1],Pall[loop1,2],Pall[loop1,3]);
END;


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

Well, there are most of those origional questions answered ;-) The following
sample program is quite big, so it might take you a while to get around it.
Persevere and thou shalt overcome. Pallette manipulation has been a thorn
in many coders sides for quite some time, yet hopefully I have shown you
all how amazingly simple it is once you have grasped the basics.

I need more feedback! In which direction would you like me to head? Is there
any particular section you would like more info on? Also, upload me your
demo's, however trivial they might seem. We really want to get in contact
with/help out new and old coders alike, but you have to leave us that message
telling us about yourself and what you have done or want to do.

IS THERE ANYBODY OUT THERE!?!

P.S. Our new demo should be out soon ... it is going to be GOOOD ... keep
     an eye out for it.

          [ And so she came across him, slumped over his keyboard
            yet again . 'It's three in the morning' she whispered.
            'Let's get you to bed'. He stirred, his face bathed in
            the dull light of his monitor. He mutters something.
            As she leans across him to disconnect the power, she
            asks him; 'Was it worth it?'. His answer surprises her.
            'No.' he says. In his caffiene-enduced haze, he smiles.
            'But it sure is a great way to relax.'                  ]
                                           - Grant Smith
                                              Tue 13 July, 1993
                                               2:23 am.

See you next week!
   - Denthor

                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 3 ]==--



? Introduction



Greetings! This is the third part of the VGA Trainer series! Sorry it 
took so long to get out, but I had a running battle with the traffic
department for three days to get my car registered, and then the MailBox
went down. Ahh, well, life stinks. Anyway, today will do some things
vital to most programs : Lines and circles.

Watch out for next week's part : Virtual screens. The easy way to
eliminate flicker, "doubled sprites", and subjecting the user to watch
you building your screen. Almost every ASPHYXIA demo has used a virtual
screen (with the exception of the SilkyDemo), so this is one to watch out
for. I will also show you how to put all of these loose procedures into
units.

If you would like to contact me, or the team, there are many ways you 
can do it : 1) Write a message to Grant Smith in private mail here on
                  the Mailbox BBS.
            2) Write a message here in the Programming conference here
                  on the Mailbox (Preferred if you have a general
                  programming query or problem others would benefit from)
            3) Write to ASPHYXIA on the ASPHYXIA BBS.
            4) Write to Denthor, Eze or Livewire on Connectix.
            5) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
            6) Call me (Grant Smith) at 73 2129 (leave a message if you 
                  call during varsity)
                  
NB : If you are a representative of a company or BBS, and want ASPHYXIA 
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Circle Algorithim

You all know what a circle looks like. But how do you draw one on the
computer?

You probably know circles drawn with the degrees at these points :

                                0
                              ??|??
                             ???|???
                        270 ----+---- 90
                             ???|???
                              ??|??
                               180

Sorry about my ASCI ;-) ... anyway, Pascal doesn't work that way ... it
works with radians instead of degrees. (You can convert radians to degrees,
but I'm not going to go into that now. Note though that in pascal, the
circle goes like this :

                               270
                              ??|??
                             ???|???
                        180 ----+---- 0
                             ???|???
                              ??|??
                                90


Even so, we can still use the famous equations to draw our circle ...
(You derive the following by using the theorem of our good friend
Pythagoras)
                     Sin (deg) = Y/R
                     Cos (deg) = X/R
(This is standard 8(?) maths ... if you haven't reached that level yet,
take this to your dad, or if you get stuck leave me a message and I'll
do a bit of basic Trig with you. I aim to please ;-))

Where Y = your Y-coord
      X = your X-coord
      R = your radius (the size of your circle)
      deg = the degree

To simplify matters, we rewrite the equation to get our X and Y values :

                     Y = R*Sin(deg)
                     X = R*Cos(deg)

This obviousy is perfect for us, because it gives us our X and Y co-ords
to put into our putpixel routine (see Part 1). Because the Sin and Cos
functions return a Real value, we use a round function to transform it
into an Integer.

     Procedure Circle (oX,oY,rad:integer;Col:Byte);
     VAR deg:real;
         X,Y:integer;
     BEGIN
       deg:=0;
       repeat
         X:=round(rad*COS (deg));
         Y:=round(rad*sin (deg));
         putpixel (x+ox,y+oy,Col);
         deg:=deg+0.005;
       until (deg>6.4);
     END;

In the above example, the smaller the amount that deg is increased by,
the closer the pixels in the circle will be, but the slower the procedure.
0.005 seem to be best for the 320x200 screen. NOTE : ASPHYXIA does not use
this particular circle algorithm, ours is in assembly language, but this
one should be fast enough for most. If it isn't, give us the stuff you are
using it for and we'll give you ours.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Line algorithms

There are many ways to draw a line on the computer. I will describe one
and give you two. (The second one you can figure out for yourselves; it
is based on the first one but is faster)

The first thing you need to do is pass what you want the line to look
like to your line procedure. What I have done is said that x1,y1 is the
first point on the screen, and x2,y2 is the second point. We also pass the
color to the procedure. (Remember the screens top left hand corner is (0,0);
see Part 1)

Ie.            o  (X1,Y1)
                ooooooooo
                         ooooooooo
                                  oooooooo  (X2,Y2)

Again, sorry about my drawings ;-)

To find the length of the line, we say the following :

           XLength = ABS (x1-x2)
           YLength = ABS (y1-y2)

The ABS function means that whatever the result, it will give you an
absolute, or posotive, answer. At this stage I set a variable stating
wheter the difference between the two x's are negative, zero or posotive.
(I do the same for the y's) If the difference is zero, I just use a loop
keeping the two with the zero difference posotive, then exit.

If neither the x's or y's have a zero difference, I calculate the X and Y
slopes, using the following two equations :

           Xslope = Xlength / Ylength
           Yslope = Ylength / Xlength

As you can see, the slopes are real numbers.
NOTE : XSlope = 1 / YSlope

Now, there are two ways of drawing the lines :

           X = XSlope * Y
           Y = YSlope * X

The question is, which one to use? if you use the wrong one, your line
will look like this :

        o
           o
              o

Instead of this :

        ooo
           ooo
              ooo

Well, the solution is as follows :

                           *\``|``/*
                           ***\|/***
                           ----+----
                           ***/|\***
                           */``|``\*

If the slope angle is in the area of the stars (*) then use the first
equation, if it is in the other section (`) then use the second one.
What you do is you calculate the variable on the left hand side by
putting the variable on the right hand side in a loop and solving. Below
is our finished line routine :

Procedure Line (x1,y1,x2,y2:integer;col:byte);
VAR x,y,xlength,ylength,dx,dy:integer;
    xslope,yslope:real;
BEGIN
  xlength:=abs (x1-x2);
  if (x1-x2)<0 then dx:=-1;
  if (x1-x2)=0 then dx:=0;
  if (x1-x2)>0 then dx:=+1;
  ylength:=abs (y1-y2);
  if (y1-y2)<0 then dy:=-1;
  if (y1-y2)=0 then dy:=0;
  if (y1-y2)>0 then dy:=+1;
  if (dy=0) then BEGIN
    if dx<0 then for x:=x1 to x2 do
      putpixel (x,y1,col);
    if dx>0 then for x:=x2 to x1 do
      putpixel (x,y1,col);
    exit;
  END;
  if (dx=0) then BEGIN
    if dy<0 then for y:=y1 to y2 do
      putpixel (x1,y,col);
    if dy>0 then for y:=y2 to y1 do
      putpixel (x1,y,col);
    exit;
  END;
  xslope:=xlength/ylength;
  yslope:=ylength/xlength;
  if (yslope/xslope<1) and (yslope/xslope>-1) then BEGIN
    if dx<0 then for x:=x1 to x2 do BEGIN
                   y:= round (yslope*x);
                   putpixel (x,y,col);
                 END;
    if dx>0 then for x:=x2 to x1 do BEGIN
                   y:= round (yslope*x);
                   putpixel (x,y,col);
                 END;
  END
  ELSE
  BEGIN
    if dy<0 then for y:=y1 to y2 do BEGIN
                   x:= round (xslope*y);
                   putpixel (x,y,col);
                 END;
    if dy>0 then for y:=y2 to y1 do BEGIN
                   x:= round (xslope*y);
                   putpixel (x,y,col);
                 END;
  END;
END;

Quite big, isn't it? Here is a much shorter way of doing much the same
thing :

function sgn(a:real):integer;
begin
     if a>0 then sgn:=+1;
     if a<0 then sgn:=-1;
     if a=0 then sgn:=0;
end;

procedure line(a,b,c,d,col:integer);
var u,s,v,d1x,d1y,d2x,d2y,m,n:real;
    i:integer;
begin
     u:= c - a;
     v:= d - b;
     d1x:= SGN(u);
     d1y:= SGN(v);
     d2x:= SGN(u);
     d2y:= 0;
     m:= ABS(u);
     n := ABS(v);
     IF NOT (M>N) then
     BEGIN
          d2x := 0 ;
          d2y := SGN(v);
          m := ABS(v);
          n := ABS(u);
     END;
     s := INT(m / 2);
     FOR i := 0 TO round(m) DO
     BEGIN
          putpixel(a,b,col);
          s := s + n;
          IF not (s<m) THEN
          BEGIN
               s := s - m;
               a:= a +round(d1x);
               b := b + round(d1y);
          END
          ELSE
          BEGIN
               a := a + round(d2x);
               b := b + round(d2y);
          END;
     end;
END;

This routine is very fast, and should meet almost all of your requirements
(ASPHYXIA used it for quite a while before we made our new one.)
In the end program, both the new line routine and the circle routine are
tested. A few of the procedures of the first parts are also used.

Line and circle routines may seem like fairly trivial things, but they are
a vital component of many programs, and you may like to look up other
methods of drawing them in books in the library (I know that here at the
varsity they have books for doing this kind of stuff all over the place)
A good line routine to look out for is the Bressenhams line routine ...
there is a Bressenhams circle routine too ... I have documentaiton for them
if anybody is interested, they are by far some of the fastest routines
you will use.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

Varsity has started again, so I am (shock) going to bed before three in
the morning, so my quote this week wasn't written in the same wasted way
my last weeks one was (For last week's one, I had gotten 8 hours sleep in
3 days, and thought up and wrote the quote at 2:23 am before I fell asleep.)

        [  "What does it do?" she asks.
           "It's a computer," he replies.
           "Yes, dear, but what does it do?"
           "It ..er.. computes! It's a computer."
           "What does it compute?"
           "What? Er? Um. Numbers! Yes, numbers!" He smiles
              worriedly.
           "Why?"
           "Why? Well ..um.. why?" He starts to sweat.
           "I mean, is it just something to dust around, or does
              it actually do something useful?"
           "Um...you can call other computers with it!" Hope lights
              up his eyes. "So you can get programs from other computers!"
           "I see. Tell me, what do these programs do?"
           "Do? I don't think I fol..."
           "I see. They compute. Numbers. For no particular reason." He
              withers under her gaze.
           "Yes, but..."
           She smiles, and he trails off, defeated. She takes another look
               at the thing. "Although," she says, with a strange look in
               her eyes. He looks up, an insane look of hope on his
               face. "Does it come in pink?" she asks.
                                                                           ]
                                                     - Grant Smith
                                                        Tue 27 July, 1993
                                                         9:35 pm.

See you next time,
    - Denthor

                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 4 ]==--



? Introduction


Howdy all! Welcome to the fourth part of this trainer series! It's a
little late, but I am sure you will find that the wait was worth it,
becase today I am going to show you how to use a very powerful tool :
Virtual Screens.

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith in private mail here on
                  the Mailbox BBS.
            2) Write a message here in the Programming conference here
                  on the Mailbox (Preferred if you have a general
                  programming query or problem others would benefit from)
            3) Write to ASPHYXIA on the ASPHYXIA BBS.
            4) Write to Denthor, Eze or Livewire on Connectix.
            5) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
            6) Call me (Grant Smith) at 73 2129 (leave a message if you
                  call during varsity)

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is a Virtual Screen and why do we need it?

Let us say you are generating a complex screen numerous times on the fly
(for example scrolling up the screen then redrawing all the sprites for
each frame of a game you are writing.) Do you have any idea how awful it
would look if the user could actually see you erasing and redrawing each
sprite for each frame? Can you visualise the flicker effect this would
give off? Do you realise that there would be a "sprite doubling" effect
(where you see two copies of the same sprite next to each other)? In the
sample program I have included a part where I do not use virtual screens
to demonstrate these problems. Virtual screens are not the only way to
solve these problems, but they are definately the easiest to code in.

A virtual screen is this : a section of memory set aside that is exactly
like the VGA screen on which you do all your working, then "flip" it
on to your true screen. In EGA 640x350x16 you automatically have a
virtual page, and it is possible to have up to four on the MCGA using a
particular tweaked mode, but for our puposes we will set one up using base
memory.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Setting up a virtual screen

As you will have seen in the first part of this trainer series, the MCGA
screen is 64000 bytes big (320x200=64000). You may also have noticed that
in TP 6.0 you arn't allowed too much space for normal variables. For
example, saying :

VAR Virtual : Array [1..64000] of byte;

would be a no-no, as you wouldn't have any space for your other variables.
What is the solution? I hear you enquiring minds cry. The answer : pointers!
Pointers to not use up the base 64k allocated to you by TP 6.0, it gets
space from somewhere else in the base 640k memory of your computer. Here is
how you set them up :

Type Virtual = Array [1..64000] of byte;  { The size of our Virtual Screen }
     VirtPtr = ^Virtual;                  { Pointer to the virtual screen }

VAR Virscr : VirtPtr;                      { Our first Virtual screen }
    Vaddr  : word;                        { The segment of our virtual screen}

If you put this in a program as it stands, and try to acess VirScr, your
machine will probably crash. Why? Because you have to get the memory for
your pointers before you can acess them! You do that as follows :

Procedure SetUpVirtual;
BEGIN
  GetMem (VirScr,64000);
  vaddr := seg (virscr^);
END;

This procedure has got the memory for the screen, then set vaddr to the
screens segment. DON'T EVER LEAVE THIS PROCEDURE OUT OF YOUR PROGRAM!
If you leave it out, when you write to your virtual screen you will probably
be writing over DOS or some such thing. Not a good plan ;-).

When you have finished your program, you will want to free the memory
taken up by the virtual screen by doing the following :

Procedure ShutDown;
BEGIN
  FreeMem (VirScr,64000);
END;

If you don't do this your other programs will have less memory to use for
themselves.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Putting a pixel to your virtual screen

This is very similar to putting a pixel to your normal MCGA screen, as
discussed in part one... here is our origonal putpixel :

Procedure PutPixel (X,Y : Integer; Col : Byte);
BEGIN
  Mem [VGA:X+(Y*320)]:=col;
END;

For our virtual screen, we do the following :

Procedure VirtPutPixel (X,Y : Integer; Col : Byte);
BEGIN
  Mem [Vaddr:X+(Y*320)]:=col;
END;

It seems quite wasteful to have two procedures doing exactly the same thing,
just to different screens, doesn't it? So why don't we combine the two like
this :

Procedure PutPixel (X,Y : Integer; Col : Byte; Where : Word);
BEGIN
  Mem [Where:X+(Y*320)]:=col;
END;

To use this, you will say something like :

Putpixel (20,20,32,VGA);
PutPixel (30,30,64,Vaddr);

These two statements draw two pixels ... one to the VGA screen and one to
the virtual screen! Doesn't that make you jump  with joy! ;-) You will
have noticed that we still can't actually SEE the virtual screen, so on to
the next part ...

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How to "Flip" your virtual screen on to the true screen

You in fact already have to tools to do this yourselves from information
in the previous parts of this trainer series. We will of course use the
Move command, like so :

Move (Virscr^,mem [VGA:0],64000);

simple, eh? Yuo may want to wait for a verticle retrace (Part 2) before you
do that, as it may make the flip much smoother (and, alas, slower).

Note that most of our other procedures may be altered to support the
virtual screen, such as Cls etc. (see Part 1 of this series), using the
methoods described above (I have altered the CLS procedure in the sample
program given at the end of this Part.)

We of ASPHYXIA have used virtual screens in almost all of our demos.
Can you imagine how awful the SoftelDemo would have looked if you had to
watch us redrawing the moving background, text and vectorballs for EACH
FRAME? The flicker, doubling effects etc would have made it awful! So
we used a virtual screen, and are very pleased with the result.
Note, though, that to get the speed we needed to get the demo fast enough,
we wrote our sprites routines, flip routines, pallette routines etc. all
in assembly. The move command is very fast, but not as fast as ASM ;-)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

I am writing this on the varsity computers in between lectures. I prefer
writing & coding between 6pm and 4am, but it isn't a good plan when
varsity is on ;-), so this is the first part of the trainer series ever
written before 9pm.

I have been asked to do a part on scrolling the screen, so that is
probably what I will do for next week. Also, ASPHYXIA will soon be putting
up a small demo with source on the local boards. It will use routines
that we have discussed in this series, and demonstrate how powerful these
routines can be if used in the correct manner.

Some projects for you to do :
  1) Rewrite the flip statement so that you can say :
        flip (Vaddr,VGA);
        flip (VGA,Vaddr);
      ( This is how ASPHYXIAS one works )

  2) Put most of the routines (putpixel, cls, pal etc.) into a unit,
     so that you do not need to duplicate the procedures in each program
     you write. If you need help, leave me mail.


See you next week
   - Denthor


                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 5 ]==--



? Introduction

Hello! This is Denthor here with the 5 part of the ASPHYXIA VGA Trainer
Series : The Scrolling Saga. I have had many requests for information on
scrolling, so I decided to make it this weeks topic. Note that I do make
reference to my recently released program TEXTER5, which should be available
from wherever you get this message. (Note to Sysops : If you put the trainer
series up on your boards, please add WORMIE.ZIP and TEXTER5.ZIP as they
both suppliment this series)

By the way, sorry for the delay in the appearance of this part. Tests,
projects and a few wild days of sin at the Wild Coast all conspired
against the prompt appearance of this part. Also note I need more input as
to what I should do future parts on, so leave me mail.

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith in private mail here on
                  the Mailbox BBS.
            2) Write a message here in the Programming conference here
                  on the Mailbox (Preferred if you have a general
                  programming query or problem others would benefit from)
            3) Write to ASPHYXIA on the ASPHYXIA BBS.
            4) Write to Denthor, Eze or Livewire on Connectix.
            5) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
            6) Call me (Grant Smith) at 73 2129 (leave a message if you
                  call during varsity)

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is scrolling?

If you have ever seen a demo, you have probably seen some form of scrolling.
Our SILKYDEMO has quite a nice example of scrolling. What it is is a long
row of text moving across your screen, usually from right to left, eg :

                                       H     : Step 1
                                      He     : Step 2
                                     Hel     : Step 3
                                    Hell     : Step 4
                                   Hello     : Step 5
                                  Hello      : Step 6

etc. etc. See the program attatched for an example of scrolling.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What do we scroll?

Usually, letters. Most groups put greetings and information in their
'scrollies', as they are termed. You can also scroll and entire screen
using the scrolling technique. Scrolling your text is a hell of a lot
less boring then just having it appear on your screen. Unfortunately,
'scrollies' have been used so many times in demos they are wearing a
bit thin, so usually they are accompanied by a cool picture or some nice
routine happening at the same time (In our SILKYDEMO we had a moving
checkerboard and colour bars going at the same time).

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do we scroll from side to side?

The theory behind scrolling is quite easy. Let us imagine that we are
scrolling a 16x16 font grabbed by TEXTER (;-)) across the top of the
screen (ie. 320 pixels) As we know, the VGA screen starts at zero at the
top left hand part of the screen, then counts up to the right to 319, then
goes back to the left hand side one pixel down at 320. (See Tut 1) This means
that a 16*320 scroller takes up the space 0 to 5119 on the screen. In ascii
this looks like this :

            (0)   .                                    .  (319)
            (320) .                                    .  (639)
                            "             "           "
           (4800) .                                    .   (5119)

Simple enough. Now what we do is we put down the first Y-line of the first
character onto the very right hand side of the screen , like so :

              For loop1:=1 to 16 do
                Putpixel (319,loop1-1,font['A',1,loop1],vga);

This will draw some stuff on the very right hand side. Your screen should now
look like this :

            (0)   .                                   X.  (319)
            (320) .                                   X.  (639)
                            "             "           "
           (4800) .                                   X.   (5119)

Next, we move each line one to the left, ie :

              For loop1:=0 to 15 do
                Move (mem[VGA:loop1*320+1],mem[VGA:loop1*320],320);

This scrolls the screen from right to left, which is the easiest to read.
To scroll the screen from left to right, swap the +1 onto the other side
of the command. Also, to increase the size of the portion scrolled, increase
the 15 to however many lines from the top you wish to scroll-1.

After this move, your screen will look like this :

            (0)   .                                  X .  (319)
            (320) .                                  X .  (639)
                            "             "           "
           (4800) .                                  X .   (5119)
                                                      ^
                                                Note this space


What you then do is draw in the next line on the right hand side, move it,
draw the next line, move it etc. etc. Tah-Dah! You have a scrolly! Fairly
simple, isn't it?

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do we scroll up or down?

To scroll up or down is also fairly simple. This can be used for 'movie
credit' endings (I once wrote a little game with a desert scrolling down
with you being a little robot on the bottom of the screen). The theory is
this : Draw the top line (or bottom line) then move the entire screen :

             Move (mem[vga:0],mem[vga:320],63680);
                       { 64000 - 320 = 63680 }

For scrolling down, or :

             Move (mem[vga:320],mem[vga:0],63680);

For scrolling up. You then draw the next line and repeat.

Because of the simplicity of coding in a scrolly, most demos have one. It
is usually best to have something extra happening on the screen so that
the viewer doesn't get too bored, even, as I say, if it is only a really nice
picture.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

The University of Natal, Durban, Science Dept., now has 10 new 486's!
This is a great boon, as now I can program nice routines during frees
(even though I am a Commerce Student (Shhhhh) ;-) ). I can now use those
previously wasted hours that I spent socialising and making friends
coding instead ;-)

I suggest you get a copy of TEXTER, for coding demos with fonts, or in fact
almost any graphics application, it is an amazing help, and we have used it
for *ALL* our demos. (P.S. We have written many demos, but many have been
written for companies and have not been released for the general public)
NOTE : For TEXTER's test program TEST.PAS, add {$X+} {$R-} if you have range
checking on (I code with it off.)

            [  "I'm from the Computer Inspection Agency, sir,
                   I'm here to check your computer. Here is
                   my identification."
               "Certainly. Have a look, I'm clean. I don't have
                   any pirated software."
               The C-man pushes past him and sits in front of the
                   computer. He notes the fact that the computer
                   is currently off with a look of disdain. He
                   makes a note on his clipboard. He boots up.
               "What is this?" he asks, pointing at the screen.
               "It's MasterMenu" stutters the man. "I wrote it
                   myself!"
               "Do you know what the penalty is for using junk
                   like this on a private machine?" The C-man smiles.
                   "This is a two-month sentance in itself!"
               "I'm sorry sir! It won't happen again!"
               "I know. I'll make sure of that." He smiles again.
               The C-man runs through the hard drive, checking for
                   illeagal software, bad programs and anti-government
                   propaganda. He notes with satisfaction that he has
                   enough to put this weenie away for ten years, not that
                   it mattered. He usually could just make something up.
               He comes to the last entry on the aphebetised menu tree.
                   His hands jerk away from the keyboard. Then, tentatively,
                   he types in the three letters of doom. He looks at the
                   man, who is backing away with wide eyes and his hands
                   outstretched in front of him, as if to ward off a blow.
               The C-man smiles, his lips a thin, hard line.
               "Windows!"
                                                                     ]
                                                           - Grant Smith
                                                               1:55pm
                                                                 16/9/93

Cheers,
  - Denthor

                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 6 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi there! I'm back, with the latest part in the series : Pregenerated
arrays. This is a fairly simple concept that can treble the speed of
your code, so have a look.

I still suggest that if you haven't got a copy of TEXTER that you get it.
This is shareware, written by me, that allows you to grab fonts and use
them in your own programs.

I downloaded the Friendly City BBS Demo, an intro for a PE BBS, written
by a new group called DamnRite, with coder Brett Step. The music was
excellent, written by Kon Wilms (If I'm not mistaken, he is an Amiga
weenie ;-)). A very nice first production, and I can't wait to see more
of their work. I will try con a local BBS to allow me to send Brett some
fido-mail.

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith in private mail here on
                  the Mailbox BBS.
            2) Write a message here in the Programming conference here
                  on the Mailbox (Preferred if you have a general
                  programming query or problem others would benefit from)
            3) Write to ASPHYXIA on the ASPHYXIA BBS.
            4) Write to Denthor, Eze or Livewire on Connectix.
            5) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
            6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity)

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Why do I need a lookup table? What is it?

A lookup table is an imaginary table in memory where you look up the
answers to certain mathematical equations instead of recalculating them
each time. This may speed things up considerably. Please note that a
lookup table is sometimes referred to as a pregenerated array.

One way of looking at a lookup table is as follows : Let us say that for
some obscure reason you need to calculate a lot of multiplications (eg.
5*5 , 7*4 , 9*2 etc.). Instead of actually doing a slow multiply each
time, you can generate a kind of bonds table, as seen below :


?????????????????????????????????????????????????????????????????????
?????   1   ?  2   ?  3   ?  4   ?  5   ?  6   ?  7   ?  8   ?  9   ?
?????????????????????????????????????????????????????????????????????
? 1 ?   1   ?  2   ?  3   ?  4   ?  5   ?  6   ?  7   ?  8   ?  9   ?
?????????????????????????????????????????????????????????????????????
? 2 ?   2   ?  4   ?  6   ?  8   ?  10  ?  12  ?  14  ?  16  ?  18  ?
?????????????????????????????????????????????????????????????????????
? 3 ?   3   ?  6   ?  9   ?  12  ?  15  ?  18  ?  21  ?  24  ?  27  ?
?????????????????????????????????????????????????????????????????????
? 4 ?   4   ?  8   ?  12  ?  16  ?  20  ?  24  ?  28  ?  32  ?  36  ?
?????????????????????????????????????????????????????????????????????
? 5 ?   5   ?  10  ?  15  ?  20  ?  25  ?  30  ?  35  ?  40  ?  45  ?
?????????????????????????????????????????????????????????????????????
? 6 ?   6   ?  12  ?  18  ?  24  ?  30  ?  36  ?  42  ?  48  ?  54  ?
?????????????????????????????????????????????????????????????????????
? 7 ?   7   ?  14  ?  21  ?  28  ?  35  ?  42  ?  49  ?  56  ?  63  ?
?????????????????????????????????????????????????????????????????????
? 8 ?   8   ?  16  ?  24  ?  32  ?  40  ?  48  ?  56  ?  64  ?  72  ?
?????????????????????????????????????????????????????????????????????
? 9 ?   9   ?  18  ?  27  ?  36  ?  45  ?  54  ?  63  ?  72  ?  81  ?
?????????????????????????????????????????????????????????????????????

This means that instead of calculating 9*4, you just find the 9 on the
top and the 4 on the side, and the resulting number is the answer.  This
type of table is very useful when the equations are very long to do.

The example I am going to use for this part is that of circles. Cast
your minds back to Part 3 on lines and circles. The circle section took
quite a while to finish drawing, mainly because I had to calculate the
SIN and COS for EVERY SINGLE POINT. Calculating SIN and COS is obviously
very slow, and that was reflected in the speed of the section.



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I generate a lookup table?

This is very simple. In my example, I am drawing a circle. A circle has
360 degrees, but for greater accuracy, to draw my circle I will start
with zero and increase my degrees by 0.4. This means that in each circle
there need to be 8000 SINs and COSes (360/0.4=8000). Putting these into
the base 64k that Pascal allocates for normal variables is obviously not
a happening thing, so we define them as pointers in the following
manner: 
        TYPE   table = Array [1..8000] of real;

        VAR    sintbl : ^table;
               costbl : ^table;

Then in the program we get the memory for these two pointers. Asphyxia 
was originally thinking of calling itself Creative Reboot Inc., mainly 
because we always forgot to get the necessary memory for our pointers.
(Though a bit of creative assembly coding also contributed to this. We
wound up rating our reboots on a scale of 1 to 10 ;-)). The next obvious
step is to place our necessary answers into our lookup tables.  This can
take a bit of time, so in a demo, you would do it in the very beginning
(people just think it's slow disk access or something), or after you
have shown a picture (while the viewer is admiring it, you are
calculating pi to its 37th degree in the background ;-)) Another way of
doing it is, after calculating it once, you save it to a file which you
then load into the variable at the beginning of the program. Anyway,
this is how we will calculate the table for our circle :

    Procedure Setup;
    VAR deg:real;
    BEGIN
      deg:=0;
      for loop1:=1 to 8000 do BEGIN
        deg:=deg+0.4;
        costbl^[loop1]:=cos (rad(deg));
        sintbl^[loop1]:=sin (rad(deg));
      END;
    END;

This will calculate the needed 16000 reals and place them into our two
variables. The amount of time this takes is dependant on your computer.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do I use a lookup table?

This is very easy. In your program, wherever you put
               cos (rad(deg)),
you just replace it with :
               costbl^[deg]

Easy, no? Note that the new "deg" variable is now an integer, always
between 1 and 8000.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Where else do I use lookup tables?

Lookup tables may be used in many different ways. For example, when
working out 3-dimensional objects, sin and cos are needed often, and are
best put in a lookup table. In a game, you may pregen the course an
enemy may take when attacking. Even saving a picture (for example, a
plasma screen) after generating it, then loading it up later is a form
of pregeneration.

When you feel that your program is going much too slow, your problems
may be totally sorted out by using a table. Or, maybe not. ;-)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

As you have seen above, lookup tables aren't all that exciting, but they
are useful and you need to know how to use them. The attached sample
program will demonstrate just how big a difference they can make.

Keep on coding, and if you finish anything, let me know about it! I
never get any mail, so all mail is greatly appreciated ;-)

Sorry, no quote today, it's hot and I'm tired. Maybe next time ;-)

  - Denthor
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 7 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello! By popular request, this part is all about animation. I will be
going over three methods of doing animation on a PC, and will
concerntrate specifically on one, which will be demonstrated in the
attached sample code.

Although not often used in demo coding, animation is usually used in
games coding, which can be almost as rewarding ;-)

In this part I will also be a lot less stingy with assembler code :)
Included will be a fairly fast pure assembler putpixel, an asm screen
flip command, an asm icon placer, an asm partial-flip and one or two
others. I will be explaining how these work in detail, so this may also
be used as a bit of an asm-trainer too.

By the way, I apologise for this part taking so long to be released, but
I only finished my exams a few days ago, and they of course took
preference ;-). I have also noticed that the MailBox BBS is no longer
operational, so the trainer will be uploaded regularly to the BBS lists
shown at the end of this tutorial.

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write a message in the Programming conference on the
                  For Your Eyes Only BBS (of which I am the Moderator )
                  This is preferred if you have a general programming query
                  or problem others would benefit from.
            4) Write to Denthor, Eze or Livewire on Connectix.
            5) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
            6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity)
            7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and
                  mention the word Denthor near the top of the letter.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  The Principals of Animation

I am sure all of you have seen a computer game with animation at one or
other time. There are a few things that an animation sequence must do in
order to give an impression of realism. Firstly, it must move,
preferably using different frames to add to the realism (for example,
with a man walking you should have different frames with the arms an
legs in different positions). Secondly, it must not destroy the
background, but restore it after it has passed over it.

This sounds obvious enough, but can be very difficult to code when you
have no idea of how to go about achieving that.

In this trainer I will discuss various methods of meeting these two
objectives.



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Frames and Object Control

It is quite obvious that for most animation to succeed, you must have
numerous frames of the object in various poses (such as a man with
several frames of him walking). When shown one after the other, these
give the impression of natural movement.

So, how do we store these frames? I hear you cry. Well, the obvious
method is to store them in arrays. After drawing a frame in Autodesk
Animator and saving it as a .CEL, we usually use the following code to
load it in :

TYPE icon = Array [1..50,1..50] of byte;

VAR tree : icon;

Procedure LoadCEL (FileName :  string; ScrPtr : pointer);
var
  Fil : file;
  Buf : array [1..1024] of byte;
  BlocksRead, Count : word;
begin
  assign (Fil, FileName);
  reset (Fil, 1);
  BlockRead (Fil, Buf, 800);    { Read and ignore the 800 byte header }
  Count := 0; BlocksRead := $FFFF;
  while (not eof (Fil)) and (BlocksRead <> 0) do begin
    BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead);
    Count := Count + 1024;
  end;
  close (Fil);
end;

BEGIN
  Loadcel ('Tree.CEL',addr (tree));
END.

We now have the 50x50 picture of TREE.CEL in our array tree. We may access
this array in the usual manner (eg. col:=tree [25,30]). If the frame is
large, or if you have many frames, try using pointers (see previous
parts)

Now that we have the picture, how do we control the object? What if we
want multiple trees wandering around doing their own thing? The solution
is to have a record of information for each tree. A typical data
structure may look like the following :

TYPE Treeinfo = Record
                  x,y:word;       { Where the tree is }
                  speed:byte;     { How fast the tree is moving }
                  Direction:byte; { Where the tree is facing }
                  frame:byte      { Which animation frame the tree is
                                    currently involved in }
                  active:boolean; { Is the tree actually supposed to be
                                    shown/used? }
                END;

VAR Forest : Array [1..20] of Treeinfo;

You now have 20 trees, each with their own information, location etc.
These are accessed using the following means :
                  Forest [15].x:=100;
This would set the 15th tree's x coordinate to 100.



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Restoring the Overwritten Background

I will discuss three methods of doing this. These are NOT NECESSARILY
THE ONLY OR BEST WAYS TO DO THIS! You must experiment and decide which
is the best for your particular type of program.

METHOD 1 :

Step 1 : Create two virtual pages, Vaddr and Vaddr2.
Step 2 : Draw the background to Vaddr2.
Step 3 : Flip Vaddr2 to Vaddr.
Step 4 : Draw all the foreground objects onto Vaddr.
Step 5 : Flip Vaddr to VGA.
Step 6 : Repeat from 3 continuously.

In ascii, it looks like follows ...

    +---------+           +---------+           +---------+
    |         |           |         |           |         |
    |  VGA    | <=======  |  VADDR  |  <======  |  VADDR2 |
    |         |           | (bckgnd)|           | (bckgnd)|
    |         |           |+(icons) |           |         |
    +---------+           +---------+           +---------+

The advantages of this approach is that it is straightforward, continual
reading of the background is not needed, there is no flicker and it is
simple to implement.  The disadvantages are that two 64000 byte virtual
screens are needed, and the procedure is not very fast because of the
slow speed of flipping.


METHOD 2 :

Step 1 : Draw background to VGA.
Step 2 : Grab portion of background that icon will be placed on.
Step 3 : Place icon.
Step 4 : Replace portion of background from Step 2 over icon.
Step 5 : Repeat from step 2 continuously.

In terms of ascii ...

      +---------+
      |      +--|------- + Background restored (3)
      |      * -|------> * Background saved to memory (1)
      |      ^  |
      |      +--|------- # Icon placed (2)
      +---------+

The advantages of this method is that very little extra memory is
needed. The disadvantages are that writing to VGA is slower then writing
to memory, and there may be large amounts of flicker.


METHOD 3 :

Step 1 : Set up one virtual screen, VADDR.
Step 2 : Draw background to VADDR.
Step 3 : Flip VADDR to VGA.
Step 4 : Draw icon to VGA.
Step 5 : Transfer background portion from VADDR to VGA.
Step 6 : Repeat from step 4 continuously.

In ascii ...

     +---------+           +---------+
     |         |           |         |
     |   VGA   |           |  VADDR  |
     |         |           | (bckgnd)|
     | Icon>* <|-----------|--+      |
     +---------+           +---------+

The advantages are that writing from the virtual screen is quicker then
from VGA, and there is less flicker then in Method 2. Disadvantages are
that you are using a 64000 byte virtual screen, and flickering occurs
with large numbers of objects.

In the attached sample program, a mixture of Method 3 and Method 1 is
used. It is faster then Method 1, and has no flicker, unlike Method 3.
What I do is I use VADDR2 for background, but only restore the
background that has been changed to VADDR, before flipping to VGA.

In the sample program, you will see that I restore the entire background
of each of the icons, and then place all the icons. This is because if I
replace the background then place the icon on each object individually,
if two objects are overlapping, one is partially overwritten.

The following sections are explanations of how the various assembler
routines work. This will probably be fairly boring for you if you
already know assembler, but should help beginners and dabblers alike.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  The ASM Putpixel

To begin with, I will explain a few of the ASM variables and functions :

<NOTE THAT THIS IS AN EXTREMELY SIMPLISTIC VIEW OF ASSEMBLY LANGUAGE!
There are numerous books to advance your knowledge, and the Norton
Guides assembler guide  may be invaluable for people beginning to code
in assembler. I haven't given you the pretty pictures you are supposed
to have to help you understand it easier, I have merely laid it out like
a programming language with it's own special procedures. >

There are 4 register variables : AX,BX,CX,DX. These are words (double
bytes) with a range from 0 to 65535. You may access the high and low
bytes of these by replacing the X with a "H" for high or "L" for low.
For example, AL has a range from 0-255.

You also have two pointers : ES:DI and DS:SI. The part on the left is
the segment to which you are pointing (eg $a000), and the right hand
part is the offset, which is how far into the segment you are pointing.
Turbo Pascal places a variable over 16k into the base of a segment, ie.
DI or SI will be zero at the start of the variable.

If you wish to be pointing to pixel number 3000 on the VGA screen (see
previous parts for the layout of the VGA screen), ES would be equal to
$a000 and DI would be equal to 3000.  You can quite as easily make ES or
DS be equal to the offset of a virtual screen.

Here are a few functions that you will need to know :

      mov   destination,source       This moves the value in source to
                                     destination. eg  mov ax,50
      add   destination,source       This adds source to destination,
                                     the result being stored in destination
      mul   source                   This multiplies AX by source. If
                                     source is a byte, the source is
                                     multiplied by AL, the result being
                                     stored in AX. If source is a word,
                                     the source is multiplied by AX, the
                                     result being stored in DX:AX
      movsb                          This moves the byte that DS:SI is
                                     pointing to into ES:DI, and
                                     increments SI and DI.
      movsw                          Same as movsb except it moves a
                                     word instead of a byte.
      stosw                          This moves AX into ES:DI. stosb
                                     moves AL into ES:DI. DI is then
                                     incremented.
      push register                  This saves the value of register by
                                     pushing it onto the stack. The
                                     register may then be altered, but
                                     will be restored to it's original
                                     value when popped.
      pop register                   This restores the value of a pushed
                                     register. NOTE : Pushed values must
                                     be popped in the SAME ORDER but
                                     REVERSED.
      rep  command                   This repeats Command by as many
                                     times as the value in CX


SHL Destination,count      ;
and SHR Destination,count  ;
need a bit more explaining. As you know, computers think in ones and
zeroes. Each number may be represented in this base 2 operation. A byte
consists of 8 ones and zeroes (bits), and have a range from 0 to 255. A 
word consists of 16 ones and zeroes (bits), and has a range from 0 to 
65535. A double word consists of 32 bits.

The number 53 may be represented as follows :  00110101.  Ask someone who
looks clever to explain to you how to convert from binary to decimal and
vice-versa.

What happens if you shift everything to the left? Drop the leftmost
number and add a zero to the right? This is what happens :

                00110101     =  53
                 <-----
                01101010     =  106

As you can see, the value has doubled! In the same way, by shifting one
to the right, you halve the value! This is a VERY quick way of
multiplying or dividing by 2. (note that for dividing by shifting, we
get the trunc of the result ... ie.  15 shr 1 = 7)

In assembler the format is SHL destination,count    This shifts
destination by as many bits in count (1=*2, 2=*4, 3=*8, 4=*16 etc)
Note that a shift takes only 2 clock cycles, while a mul can take up to 133
clock cycles. Quite a difference, no? Only 286es or above may have count
being greater then one.

This is why to do the following to calculate the screen coordinates for
a putpixel is very slow :

           mov    ax,[Y]
           mov    bx,320
           mul    bx
           add    ax,[X]
           mov    di,ax

But alas! I hear you cry. 320 is not a value you may shift by, as you
may only shift by 2,4,8,16,32,64,128,256,512 etc.etc. The solution is
very cunning. Watch.

    mov     bx,[X]
    mov     dx,[Y]
    push    bx
    mov     bx, dx                  {; bx = dx = Y}
    mov     dh, dl                  {; dh = dl = Y}
    xor     dl, dl                  {; These 2 lines equal dx*256 }
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1                   {; bx = bx * 64}
    add     dx, bx                  {; dx = dx + bx (ie y*320)}
    pop     bx                      {; get back our x}
    add     bx, dx                  {; finalise location}
    mov     di, bx

Let us have a look at this a bit closer shall we?
bx=dx=y        dx=dx*256  ;   bx=bx*64     ( Note, 256+64 = 320 )

dx+bx=Correct y value, just add X!

As you can see, in assembler, the shortest code is often not the
fastest.

The complete putpixel procedure is as follows :

Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
  { This puts a pixel on the screen by writing directly to memory. }
BEGIN
  Asm
    push    ds                      {; Make sure these two go out the }
    push    es                      {; same they went in }
    mov     ax,[where]
    mov     es,ax                   {; Point to segment of screen }
    mov     bx,[X]
    mov     dx,[Y]
    push    bx                      {; and this again for later}
    mov     bx, dx                  {; bx = dx}
    mov     dh, dl                  {; dx = dx * 256}
    xor     dl, dl
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1
    shl     bx, 1                   {; bx = bx * 64}
    add     dx, bx                  {; dx = dx + bx (ie y*320)}
    pop     bx                      {; get back our x}
    add     bx, dx                  {; finalise location}
    mov     di, bx                  {; di = offset }
    {; es:di = where to go}
    xor     al,al
    mov     ah, [Col]
    mov     es:[di],ah              {; move the value in ah to screen
                                       point es:[di] }
    pop     es
    pop     ds
  End;
END;

Note that with DI and SI, when you use them :
      mov   di,50      Moves di to position 50
      mov   [di],50    Moves 50 into the place di is pointing to


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  The Flip Procedure

This is fairly straightforward. We get ES:DI to point to the start of
the destination screen, and DS:SI to point to the start of the source
screen, then do 32000 movsw (64000 bytes).

procedure flip(source,dest:Word);
  { This copies the entire screen at "source" to destination }
begin
  asm
    push    ds
    mov     ax, [Dest]
    mov     es, ax                  { ES = Segment of source }
    mov     ax, [Source]
    mov     ds, ax                  { DS = Segment of source }
    xor     si, si                  { SI = 0   Faster then mov si,0 }
    xor     di, di                  { DI = 0 }
    mov     cx, 32000
    rep     movsw                   { Repeat movsw 32000 times }
    pop     ds
  end;
end;

The cls procedure works in much the same way, only it moves the color
into AX then uses a rep stosw (see program for details)

The PAL command is almost exactly the same as it's Pascal equivalent
(see previous tutorials). Look in the sample code to see how it uses the
out and in commands.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In Closing

The assembler procedures presented to you in here are not at their best.
Most of these are procedures ASPHYXIA abandoned for better ones after
months of use. But, as you will soon see, they are all MUCH faster then
the original Pascal equivalents I originally gave you. In future, I
hope to give you more and more assembler procedures for your ever
growing collections. But, as you know, I am not always very prompt with
this series (I don't know if even one has been released within one week
of the previous one), so if you want to get any stuff done, try do it
yourself. What do you have to lose, aside from your temper and a few
rather inventive reboots ;-)

What should I do for the next trainer? A simple 3-d tutorial? You may
not like it, because I would go into minute detail of how it works :)
Leave me suggestions for future trainers by any of the means discussed
at the top of this trainer.

After the customary quote, I will place a listing of the BBSes I
currently know that regularly carry this Trainer Series. If your BBS
receives it regularly, no matter where in the country you are, get a
message to me and I'll add it to the list. Let's make it more convenient
for locals to grab a copy without calling long distance ;-)

            [  There they sit, the preschooler class encircling their
                  mentor, the substitute teacher.
               "Now class, today we will talk about what you want to be
                  when you grow up. Isn't that fun?" The teacher looks
                  around and spots the child, silent, apart from the others
                  and deep in thought. "Jonny, why don't you start?" she
                  encourages him.
               Jonny looks around, confused, his train of thought
                  disrupted. He collects himself, and stares at the teacher
                  with a steady eye. "I want to code demos," he says,
                  his words becoming stronger and more confidant as he
                  speaks. "I want to write something that will change
                  peoples perception of reality. I want them to walk
                  away from the computer dazed, unsure of their footing
                  and eyesight. I want to write something that will
                  reach out of the screen and grab them, making
                  heartbeats and breathing slow to almost a halt. I want
                  to write something that, when it is finished, they
                  are reluctant to leave, knowing that nothing they
                  experience that day will be quite as real, as
                  insightful, as good. I want to write demos."
               Silence. The class and the teacher stare at Jonny, stunned. It
                  is the teachers turn to be confused. Jonny blushes,
                  feeling that something more is required.  "Either that
                  or I want to be a fireman."
                                                                     ]
                                                       - Grant Smith
                                                            14:32
                                                               21/11/93

See you next time,
  - DENTHOR

These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)

?????????????????????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?Msg?File?Past?
?????????????????????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?(031) 765-5312  ?ALL  ? * ? *  ? *  ?
?ASPHYXIA BBS #2           ?(031) 765-6293  ?ALL  ? * ? *  ? *  ?
?Connectix BBS             ?(031) 266-9992  ?ALL  ? * ? *  ? *  ?
?For Your Eyes Only BBS    ?(031) 285-318   ?A/H  ? * ? *  ? *  ?
?????????????????????????????????????????????????????????????????

Open = Open at all times or only A/H
Msg  = Available in message base
File = Available in file base
Past = Previous Parts available
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 8 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello everybody! Christmas is over, the last of the chocolates have been
eaten, so it's time to get on with this, the eighth part of the ASPHYXIA
Demo Trainer Series. This particular part is primarily about 3-D, but
also includes a bit on optimisation.

If you are already a 3-D guru, you may as well skip this text file, have
a quick look at the sample program then go back to sleep, because I am
going to explain in minute detail exactly how the routines work ;)

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write a message in the Programming conference on the
                  For Your Eyes Only BBS (of which I am the Moderator )
                  This is preferred if you have a general programming query
                  or problem others would benefit from.
            4) Write to Denthor, EzE or Goth on Connectix.
            5) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
            6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity)
            7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and
                  mention the word Denthor near the top of the letter.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Optimisation

Before I begin with the note on 3-D, I would like to stress that many of
these routines, and probably most of your own, could be sped up quite a
bit with a little optimisation. One must realise, however, that you must
take a look at WHAT to optimise ... converting a routine that is only
called once at startup into a tightly coded assembler routine may show
off your merits as a coder, but does absolutely nothing to speed up your
program. Something that is called often per frame is something that
needs to be as fast as possible. For some, a much used procedure is the
PutPixel procedure. Here is the putpixel procedure I gave you last week:

Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
BEGIN
  Asm
    push    ds                      { 14   clock ticks }
    push    es                      { 14 }
    mov     ax,[where]              { 8  }
    mov     es,ax                   { 2 }
    mov     bx,[X]                  { 8  }
    mov     dx,[Y]                  { 8  }
    push    bx                      { 15 }
    mov     bx, dx                  { 2  }
    mov     dh, dl                  { 2  }
    xor     dl, dl                  { 3  }
    shl     bx, 1                   { 2  }
    shl     bx, 1                   { 2  }
    shl     bx, 1                   { 2  }
    shl     bx, 1                   { 2  }
    shl     bx, 1                   { 2  }
    shl     bx, 1                   { 2  }
    add     dx, bx                  { 3  }
    pop     bx                      { 12 }
    add     bx, dx                  { 3  }
    mov     di, bx                  { 2 }
    xor     al,al                   { 3  }
    mov     ah, [Col]               { 8  }
    mov     es:[di],ah              { 10 }
    pop     es                      { 12 }
    pop     ds                      { 12 }
  End;
END;
                            Total = 153 clock ticks
NOTE : Don't take my clock ticks as gospel, I probably got one or two
       wrong.

Right, now for some optimising. Firstly, if you have 286 instructions
turned on, you may replace the 6 shl,1 with shl,6. Secondly, the Pascal
compiler automatically pushes and pops ES, so those two lines may be
removed. DS:[SI] is not altered in this procedure, so we may remove
those too. Also, instead of moving COL into ah, we move it into AL and
call stosb (es:[di]:=al; inc di). Let's have a look at the routine now :

Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
BEGIN
  Asm
    mov     ax,[where]              { 8  }
    mov     es,ax                   { 2 }
    mov     bx,[X]                  { 8  }
    mov     dx,[Y]                  { 8  }
    push    bx                      { 15 }
    mov     bx, dx                  { 2  }
    mov     dh, dl                  { 2  }
    xor     dl, dl                  { 3  }
    shl     bx, 6                   { 8  }
    add     dx, bx                  { 3  }
    pop     bx                      { 12 }
    add     bx, dx                  { 3  }
    mov     di, bx                  { 2 }
    mov     al, [Col]               { 8  }
    stosb                           { 11 }
  End;
END;
                            Total = 95 clock ticks

Now, let us move the value of BX directly into DI, thereby removing a
costly push and pop. The MOV and the XOR of DX can be replaced by it's
equivalent, SHL DX,8

Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); assembler;
asm
    mov     ax,[where]              { 8  }
    mov     es,ax                   { 2  }
    mov     bx,[X]                  { 8  }
    mov     dx,[Y]                  { 8  }
    mov     di,bx                   { 2  }
    mov     bx, dx                  { 2  }
    shl     dx, 8                   { 8  }
    shl     bx, 6                   { 8  }
    add     dx, bx                  { 3  }
    add     di, dx                  { 3  }
    mov     al, [Col]               { 8  }
    stosb                           { 11 }
end;
                            Total = 71 clock ticks

As you can see, we have brought the clock ticks down from 153 ticks to
71 ticks ... quite an improvement. (The current ASPHYXIA putpixel takes
48 clock ticks) . As you can see, by going through your routines a few
times, you can spot and remove unnecessary instructions, thereby greatly
increasing the speed of your program.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Defining a 3-D object

Drawing an object in 3-D is not that easy. Sitting down and plotting a
list of X,Y and Z points can be a time consuming business. So, let us
first look at the three axes you are drawing them on :

                    Y    Z
                   /|\  /
                    | /
             X<-----|----->
                    |
                   \|/

X is the horisontal axis, from left to right. Y is the vertical axis,
from top to bottom. Z is the depth, going straight into the screen.

In this trainer, we are using lines, so we define 2 X,Y and Z
coordinates, one for each end of the line. A line from far away, in the
upper left of the X and Y axes, to close up in the bottom right of the
X and Y axes, would look like this :

{       x1 y1  z1   x2  y2 z2    }
    ( (-10,10,-10),(10,-10,10) )


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Rotating a point with matrixes

NOTE : I thought that more then one matix are matrisese (sp), but my 
       spellchecker insists it is matrixes, so I let it have it's way 
       ;-)

Having a 3-D object is useless unless you can rotate it some way. For
demonstration purposes, I will begin by working in two dimensions, X and
Y.

Let us say you have a point, A,B, on a graph.
                      Y
                      |  /O1 (Cos (a)*A-Sin (a)*B , Sin (a)*A+Cos (a)*B)
                      |/      (A,B)
               X<-----|------O-->
                      |
                      |

Now, let us say we rotate this point by 45 degrees anti-clockwise. The
new A,B can be easily be calculated using sin and cos, by an adaption of
our circle algorithm, ie.
           A2:=Cos (45)*A - Sin (45)*B
           B2:=Sin (45)*A + Cos (45)*B
I recall that in standard 8 and 9, we went rather heavily into this in
maths. If you have troubles, fine a 8/9/10 maths book and have a look;
it will go through the proofs etc.

Anyway, we have now rotated an object in two dimensions, AROUND THE Z
AXIS. In matrix form, the equation looks like this :

   [  Cos (a)   -Sin (a)      0        0     ]    [  x ]
   [  Sin (a)    Cos (a)      0        0     ]  . [  y ]
   [     0         0          1        0     ]    [  z ]
   [     0         0          0        1     ]    [  1 ]

I will not go to deeply into matrixes math at this stage, as there are
many books on the subject (it is not part of matric maths, however). To
multiply a matrix, to add the products of the row of the left matrix and
the column of the right matrix, and repeat this for all the columns of the
left matrix. I don't explain it as well as my first year maths lecturer,
but have a look at how I derived A2 and B2 above. Here are the other
matrixes :

Matrix for rotation around the Y axis :
   [  Cos (a)      0       -Sin (a)    0     ]    [  x ]
   [     0         1          0        0     ]  . [  y ]
   [  Sin (a)      0        Cos (a)    0     ]    [  z ]
   [     0         0          0        1     ]    [  1 ]

Matrix for rotation around the X axis :
   [     1         0                   0     ]    [  x ]
   [     0       Cos (a)   -Sin (a)    0     ]  . [  y ]
   [     0       Sin (a)    Cos (a)    0     ]    [  z ]
   [     0         0          0        1     ]    [  1 ]

By putting all these matrixes together, we can translate out 3D points
around the origin of 0,0,0. See the sample program for how we put them
together.

In the sample program, we have a constant, never changing base object.
This is rotated into a second variable, which is then drawn. I am sure
many of you can thing of cool ways to change the base object, the
effects of which will appear while the object is rotating. One idea is
to "pulsate" a certain point of the object according to the beat of the
music being played in the background. Be creative. If you feel up to it,
you could make your own version of transformers ;)



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Drawing a 3D point to screen

Having a rotated 3D object is useless unless we can draw it to screen.
But how do we show a 3D point on a 2D screen? The answer needs a bit of
explaining. Examine the following diagram :

              |         ________-------------
          ____|___------      o Object at X,Y,Z     o1 Object at X,Y,Z2
 Eye -> O)____|___
              |   ------________
              |                 -------------- Field of vision
            Screen

Let us pretend that the centre of the screen is the horizon of our
little 3D world. If we draw a three dimensional line from object "o" to
the centre of the eye, and place a pixel on the X and Y coordinates
where it passes through the screen, we will notice that when we do the
same with object o1, the pixel is closer to the horizon, even though
their 3D X and Y coords are identical, but "o1"'s Z is larger then
"o"'s. This means that the further away a point is, the closer to the
horizon it is, or the smaller the object will appear. That sounds
right, doesent it? But, I hear you cry, how do we translate this into a
formula? The answer is quite simple. Divide your X and your Y by your Z.
Think about it. The larger the number you divide by, the closer to zero,
or the horizon, is the result! This means, the bigger the Z, the
further away is the object! Here it is in equation form :

       nx := 256*x div (z-Zoff)+Xoff
       ny := 256*y div (z-Zoff)+Yoff

NOTE : Zoff is how far away the entire object is, Xoff is the objects X
       value, and Yoff is the objects Y value. In the sample program,
       Xoff start off at 160 and Yoff starts off at 100, so that the
       object is in the middle of the screen.

The 256 that you times by is the perspective with which you are viewing.
Changing this value gives you a "fish eye" effect when viewing the
object. Anyway, there you have it! Draw a pixel at nx,ny, and viola! you
are now doing 3D! Easy, wasn't it?


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Possible improvements

This program is not the most optimised routine you will ever encounter
(;-)) ... it uses 12 muls and 2 divs per point. (Asphyxia currently has
9 muls and 2 divs per point) Real math is used for all the calculations
in the sample program, which is slow, so fixed point math should be
implemented (I will cover fixed point math in a future trainer). The
line routine currently being used is very slow. Chain-4 could be used to
cut down on screen flipping times.

Color values per line should be added, base object morphing could be put
in, polygons could be used instead of lines, handling of more then one
object should be implemented, clipping should be added instead of not
drawing something if any part of it is out of bounds.

In other words, you have a lot of work ahead of you ;)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

There are a lot of books out there on 3D, and quite a few sample
programs too. Have a look at them, and use the best bits to create your
own, unique 3D engine, with which you can do anything you want. I am
very interested in 3D (though EzE and Goth wrote most of ASPHYXIA'S 3D
routines), and would like to see what you can do with it. Leave me a
message through one of the means described above.

I am delving into the murky world of texture mapping. If anyone out 
there has some routines on the subject and are interested in swapping, 
give me a buzz!

What to do in future trainers? Help me out on this one! Are there any
effects/areas you would like a bit of info on? Leave me a message!

I unfortunately did not get any messages regarding BBS's that carry this
series, so the list that follows is the same one from last time. Give
me your names, sysops!

Aaaaargh!!! Try as I might, I can't think of a new quote. Next time, I
promise! ;-)

Bye for now,
  - Denthor


These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)

?????????????????????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?Msg?File?Past?
?????????????????????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?(031) 765-5312  ?ALL  ? * ? *  ? *  ?
?ASPHYXIA BBS #2           ?(031) 765-6293  ?ALL  ? * ? *  ? *  ?
?Connectix BBS             ?(031) 266-9992  ?ALL  ? * ?    ?    ?
?For Your Eyes Only BBS    ?(031) 285-318   ?A/H  ? * ? *  ? *  ?
?????????????????????????????????????????????????????????????????

Open = Open at all times or only A/H
Msg  = Available in message base
File = Available in file base
Past = Previous Parts available
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 9 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi there! ASPHYXIA is BACK with our first MegaDemo, Psycho Neurosis! A
paltry 1.3MB download is all it takes to see the group from Durbs first
major production! We are quite proud of it, and think you should see it
;)

Secondly, I released a small little trainer (a trainerette ;-)) on
RsaPROG and Connexctix BBS mail, also on the ASPHYXIA BBS as COPPERS.ZIP
It is a small Pascal program demonstrating how to display copper bars in
text mode. Also includes a check for horizontal retrace (A lot of people
wanted it, that is why I wrote the program) (ASPHYXIA ... first with the
trainer goodies ;-)  aargh, sorry, had to be done ))

Thirdly, sorry about the problems with Tut 8! If you had all the
checking on, the tutorial would probably die on the first points. The
reason is this : in the first loop, we have DrawPoints then
RotatePoints. The variables used in DrawPoints are set in RotatePoints,
so if you put RotatePoints before DrawPoints, the program should work
fine. Alternatively, turn off error checking 8-)

Fourthly, I have had a surprisingly large number of people saying that
"I get this, like, strange '286 instructions not enabled' message!
What's wrong with your code, dude?"  To all of you, get into Pascal, hit
Alt-O (for options), hit enter and a 2 (for Enable 286 instructions). Hard
hey? Doesn't anyone EVER set up their version of Pascal?

Now, on to todays tutorial! 3D solids. That is what the people wanted,
that is what the people get! This tutorial is mainly on how to draw the
polygon on screen. For details on how the 3D stuff works, check out tut
8.



If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to Denthor, EzE or Goth on Connectix.
            3) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
            4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity)
            5) Write to mcphail@beastie.cs.und.ac.za on InterNet, and
                  mention the word Denthor near the top of the letter.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? How to draw a polygon

Sounds easy enough, right? WRONG! There are many, many different ways to
go about this, and today I'll only be showing you one. Please don't take
what is written here as anything approaching the best method, it is just
here to get you on your way...

The procedure I will be using here is based on something most of us
learned in standard eight ... I think. I seem to recall doing something
like this in Mrs. Reids maths class all those years ago ;)

Take two points, x1,y1 and x2,y2. Draw them :

                  + (x1,y1)
                   \
                     \  <-- Point a somewhere along the line
                       \
                         + (x2,y2)

Right, so what we have to do is this : if we know the y-coord of a, what
is it's x-coord? To prove the method we will give the points random
values.

                 + (2,10)
                  \
                    \  <-- a.y = 12
                      \
                        +  (15,30)

Right. Simple enough problem. This is how we do it :
   (a.y-y1) = (12 - 10)  {to get a.y as though y1 was zero}
   *(x2-x1) = *(15 - 2)  {the total x-length of the line}
   /(y2-y1) = /(30 - 10) {the total y-length of the line}
        +x1 = +2         { to get the equation back to real coords}

So our equation is :  (a.y-y1)*(x2-x1)/(y2-y1)+x4    or
                      (12-10)*(15-2)/(30-10)+2
      which gives you :
                      2*13/20+2 = 26/20+2
                                = 3.3

That means that along the line with y=12, x is equal to 3.3. Since we
are not concerned with the decimal place, we replace the  /  with a div,
which in Pascal gives us an integer result, and is faster too. All well
and good, I hear you cry, but what does this have to do with life and
how it relates to polygons in general. The answer is simple. For each of
the four sides of the polygon we do the above test for each y line. We
store the smallest and the largest x values into separate variables for
each line, and draw a horizontal line between them. Ta-Dah! We have a
cool polygon!

For example : Two lines going down :
    
                +             +
               / <-x1     x2->|   <--For this y line
             /                |
           +                  +

Find x1 and x2 for that y, then draw a line between them. Repeat for all
y values.

Of course, it's not as simple as that. We have to make sure we only
check those y lines that contain the polygon (a simple min y, max y test
for all the points). We also have to check that the line we are
calculating actually extends as far as where our current y is (check
that the point is between both y's). We have to compare each x to see
weather it is smaller then the minimum x value so far, or bigger then
the maximum (the original x min is set as a high number, and the x max
is set as a small number). We must also check that we only draw to the
place that we can see ( 0-319 on the x ; 0-199 on the y (the size of the
MCGA screen))

To see how this looks in practice, have a look at the sample code
provided. (Mrs. Reid would probably kill me for the above explanation,
so when you learn it in school, split it up into thousands of smaller
equations to get the same answer ;))

Okay, that's it! What's that? How do you draw a vertical line? Thats
simple ...

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Drawing a vertical line

Right, this is a lot easier than drawing a normal line (Tut 5 .. I
think), because you stay on the same y value. So, what you do is you set
ES to the screen you want to write to, and get DI to the start of the
y-line (see earlier trainers for a description of how SEGMENT:OFFSET
works.

IN   : x1 , x2, y, color, where

           asm
             mov    ax,where
             mov    es,ax
             mov    di,y
             mov    ax,y
             shl    di,8   { di:=di*256 }
             shl    ax,6   { ax:=ax*64 }
             add    di,ax  { di := (y*256)+(y*64) := y*320 Faster then a
                             straight multiplication }

Right, now you add the first x value to get your startoff.
             add    di,x1
Move the color to store into ah and al
             mov    al,color
             mov    ah,al       { ah:=al:=color }
then get CX equal to how many pixels across you want to go
             mov    cx,x2
             sub    cx,x1   { cx:=x2-x1 }
Okay, as we all know, moving a word is a lot faster then moving a byte,
so we halve CX
             shr    cx,1    { cx:=cx/2 }
but what happens if CX was an odd number. After a shift, the value of
the last number is placed in the carry flag, so what we do is jump over
a single byte move if the carry flag is zero, or execute it if it is
one.
            jnc     @Start  { If there is no carry, jump to label Start }
            stosb           { ES:[DI]:=al ; increment DI }
        @Start :            { Label Start }
            rep     stosw   { ES:[DI]:=ax ; DI:=DI+2; repeat CX times }

Right, the finished product looks like this :

Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler;
  { This draws a horizontal line from x1 to x2 on line y in color col }
asm
  mov   ax,where
  mov   es,ax
  mov   ax,y
  mov   di,ax
  shl   ax,8
  shl   di,6
  add   di,ax
  add   di,x1

  mov   al,col
  mov   ah,al
  mov   cx,x2
  sub   cx,x1
  shr   cx,1
  jnc   @start
  stosb
@Start :
  rep   stosw
end;

Done!

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

This 3D system is still not perfect. It needs to be faster, and now I
have also dumped the problem of face-sorting on you! Nyahahahaha!

           [ My sister and I were driving along the other day when she
               asked me, what would I like for my computer.
             I thought long and hard about it, and came up with the
               following hypothesis. When a girl gets a Barbie doll, she
               then wants the extra ballgown for the doll, then the
               hairbrush, and the car, and the house, and the friends
               etc.
             When a guy gets a computer, he wants the extra memory, the
               bigger hard drive, the maths co-pro, the better
               motherboard, the latest software, and the bigger monitor
               etc.
             I told my sister all of this, and finished up with : "So as
               you can see, computers are Barbie dolls for MEN!"
             She called me a chauvinist. And hit me. Hard.
                                                                   ]
                                                       - Grant Smith
                                                           19:24
                                                             26/2/94

See you next time!
  - Denthor

These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)

?????????????????????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?Msg?File?Past?
?????????????????????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?(031) 765-5312  ?ALL  ? * ? *  ? *  ?
?ASPHYXIA BBS #2           ?(031) 765-6293  ?ALL  ? * ? *  ? *  ?
?Connectix BBS             ?(031) 266-9992  ?ALL  ?   ? *  ? *  ?
?????????????????????????????????????????????????????????????????

Open = Open at all times or only A/H
Msg  = Available in message base
File = Available in file base
Past = Previous Parts available

Does no other BBS's ANYWHERE carry the trainer? Am I writing this for
three people who get it from one of these BBS's each week? Should I go
on? (Hehehehe ... I was pleased to note that Tut 8 was THE most
downloaded file from ASPHYXIA BBS last month ... )       

                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 10 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Wow! The trainer has finally reached part 10! This will also be the
first part introduced simultaneously to local BBS's and the INTERNET at
the same time! Yes folks, I put up a copy of previous tutorials onto
various ftp sites, and awaited the flames saying that the net.gurus
already knew this stuff, and why was I wasting disk space! The flames
did not appear (well, except for one), and I got some messages saying
keep it up, so from now on I will upload all future trainers to ftp
sites too (wasp.eng.ufl.edu , cs.uwp.edu etc.). I will also leave a
notice in the USENET groups comp.lang.pascal and comp.sys.ibm.pc.demos
when a new part is finished (Until enough people say stop ;-))

I can also be reached at my new E-Mail address,
                 smith9@batis.bis.und.ac.za

Well, this tutorial is on Chain-4. When asked to do a trainer on
Chain-4, I felt that I would be walking on much travelled ground (I have
seen numerous trainers on the subject), but the people who asked me said
that they hadn't seen any, so could I do one anyway? Who am I to say no?

The sample program attached isn't that great, but I am sure that all you
people out there can immediately see the potential that Chain-4 holds.


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to Denthor, EzE or Goth on Connectix.
            3) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            5) Write to smith9@batis.bis.und.ac.za in E-Mail.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? What is Chain-4?

You people out there all have at least 256k vga cards. Most of you have
512k vga cards, and some have 1MB vga cards. But what you see on your
screen, as discussed in previous trainers, is 64k of data! What happened
to the other 192k??? Chain-4 is a method of using all 256k at one time.

The way this is done is simple. 1 screen = 64k. 64k * 4 = 256k.
Therefore, chain-4 allows you to write to four screens, while displaying
one of them. You can then move around these four screens to see the data
on them. Think of the Chain-4 screen as a big canvas. The viewport,
the bit you see out of, is a smaller rectangle which can be anywhere
over the bigger canvas.

     +----------------------------+ Chain-4 screen
     |          +--+              |
     |          |  | <- Viewport  |
     |          +--+              |
     |                            |
     +----------------------------+


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? The size of the chain-4 screen

The Chain-4 screen, can be any size that adds up to 4 screens.

For example, it can be 4 screens across and one screen down, or one
screen across and 4 screens down, or two screens across and two screens
down, and any size in between.

In the sample program, the size is a constant. The size * 8 is how many
pixels across there are on the chain-4 screen, ie
   Size = 40   = 320 pixels across = 1 screen across, 4 screens down
   Size = 80   = 640 pixels across = 2 screens across, 2 screens down
etc.

We need to know the size of the screen for almost all dealings with the
Chain-4 screen, for obvious reasons.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Layout of the chain-4 screen, and accessing it

If you will remember all the way back to Part 1 of this series, I
explained that the memory layout of the MCGA screen is linear. Ie, the
top left hand pixel was pixel zero, the one to the right of it was
number one, the next one was number two etc. With Chain-4, things are
very different.

Chain-4 gets the 4 screens and chains them together (hence the name :)).
Each screen has a different plane value, and must be accessed
differently. The reason for this is that a segment of memory is only 64k
big, so that we could not fit the entire Chain-4 screen into one
segment.

All Chain-4 screens are accessed from $a000, just like in MCGA mode.
What we do is, before we write to the screen, find out what plane we are
writing to, set that plane, then plot the pixel. Here is how we find out
how far in to plot the pixel and what plane it is on :

 Instead of the linear model of MCGA mode, ie :
        ?????????????????????????????????????
        ?00?01?02?03?04?05?06?07?08?09?10?11? ...

 Each plane of the Chain-4 screen accesses the memory in this way :

       Plane 0 :
        ?????????????????????????????????????
        ?00?  ?  ?  ?01?  ?  ?  ?02?  ?  ?  ? ...

       Plane 1 :
        ?????????????????????????????????????
        ?  ?00?  ?  ?  ?01?  ?  ?  ?02?  ?  ? ...

       Plane 2 :
        ?????????????????????????????????????
        ?  ?  ?00?  ?  ?  ?01?  ?  ?  ?02?  ? ...

       Plane 3 :
        ?????????????????????????????????????
        ?  ?  ?  ?00?  ?  ?  ?01?  ?  ?  ?02? ...

In this way, by choosing the right plane to write to, we can access all
of the 256k of memory available to us. The plane that we write to can
easily be found by the simple calculation of  x mod 4, and the x
coordinate is also found by  x div 4. We work out our y by multiplying
it by the size of our chain-4 screen.

NOTE : It is possible to write to all four planes at once by setting the
       correct port values.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Uses of Chain-4

The uses of Chain-4 are many. One could write data to one screen, then
flip to it (the move_to command is almost instantaneous). This means
that 64k of memory does not need to be set aside for a virtual screen,
you are using the vga cards memory instead!

Scrolling is much easier to code for in Chain-4 mode.

It is possible to "tweak" the mode into other resolutions. In our demo,
our vectors were in 320x240 mode, and our dot vectors were in 320x400
mode.

The main disadvantage of chain-4 as I see it is the plane swapping,
which can be slow. With a bit of clever coding however, these can be
kept down to a minimum.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? The sample programs

The first sample program is GFX.PAS. This is a until in which I have
placed most of our routines from previous tuts. All the procedures and
variables you can see under the INTERFACE section can be used in any
program with GFX in the USES clause. In other words, I could do this :

USES GFX,crt;

BEGIN
  Setupvirtual;
  cls (vaddr,0);
  Shutdown;
END.

This program would compile perfectly. What I suggest you do is this :
Rename the file to a name that suites you (eg your group name), change
the first line of the unit to that name, then add all useful procedures
etc. to the unit. Make it grow :-).

The second file is the sample program (note the USES GFX,crt; up near
the top!). The program is easy to understand and is documented. The bit
that I want to draw your attention to is the constant, BIT. Because I
am distributing this file to many places in text form, not binary form,
I could not just add a .CEL file with the program. So what I did was
write some text in one color then saved it as a .CEL . I then wrote a
ten line program that did the following : Moving from left to right, it
counted how many pixels were of color zero, then saved the byte value to
an array. When it came across color one, is counted for how long that
went on then saved the byte value and saved it to an array and so on.
When it was finished, I converted the array into a text file in the
CONST format. Not too cunning, but I thought I had better explain it ;-)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? In closing

There are other documents and sample programs available on Chain-4 and
it's like : Try XLIB for one...

Finally! Some BBS's have joined my BBS list! (Okay, only two new ones,
but it's a start ;-)) All you international BBS's! If you will regularly
download the tuts from an FTP site, give me your names!

I own a car. The car's name is Bob. A few days ago, Bob was in an
accident, and now has major damage to his front. Knowing insurance, I
probably won't get much, probably nothing (the other guy wasn't insured,
and I am only 18 :( ). I will probably have to find work in order to pay
for my repairs. The point to this meandering is this : I am upset, so if
you think you are getting a quote, you can just forget it.

Oh, well. Life goes on!

See you next time,
  - Denthor

These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)

?????????????????????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?Msg?File?Past?
?????????????????????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?(031) 765-5312  ?ALL  ? * ? *  ? *  ?
?ASPHYXIA BBS #2           ?(031) 765-6293  ?ALL  ? * ? *  ? *  ?
?Connectix BBS             ?(031) 266-9992  ?ALL  ?   ? *  ? *  ?
?POP!                      ?(012) 661-1257  ?ALL  ?   ? *  ? *  ?
?Pure Surf BBS             ?(031) 561-5943  ?A/H  ?   ? *  ? *  ?
?????????????????????????????????????????????????????????????????

For international users : If you live outside the Republic of South
Africa, do the following : Dial +27, dont dial the first 0, but dial
the rest of the number. Eg, for the ASPHYXIA BBS : +27-31-765-5312

Open = Open at all times or only A/H
Msg  = Available in message base
File = Available in file base
Past = Previous Parts available

                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 11 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello again everybody!

The reason _this_ one is delayed (every single trainer has been so far ;))
is mainly due to a birthday (my 19th), and numerous tests at the
university (ugh!).  But anyway, here it is. The sample program this time
is on cross-fading. The reason for this is that many people have
commented that I should be moving over to a few basic demo effects now
that we have most of the basics of VGA programming.  I was also thinking
of either doing sound in a future version of this trainer, or starting a
separate "ASPHYXIA Sound Tutorial" series. Comments?

One major difference between this trainer and previous ones is that I am
including binary files (pictures in this case). This means that it will
not be available in the message bases of selected boards anymore, and it
must be obtained from the file base.  Notice will however be given of
it's existence in the message base.

Asphyxia has formalised things a bit, and we now have a few official
distribution sites for all our demos and trainers. If you would like
your BBS to become a distribution site, please email me at
smith9@batis.bis.und.ac.za and I will send you the necessary info.


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix.
            3) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            5) Write to smith9@batis.bis.und.ac.za in E-Mail.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? What is a "Crossfade"?

This is a simple question. When you are watching a TV program, you will
often see one picture on the screen, which slowly fades to a new
picture, with the new picture becoming more and more prominent and the
old one becoming less and less prominent. This is a crossfade. Easy huh?

Perhaps, but it is not that easy to code on a computer...

In most demos, there is a crossfade of two colors, black and white, for
example : The words 'MYDEMOTEAM' appears in large with letters, then
crossfades to 'PRESENTS' in large white letters.

I decided to allow the programmer to have a bit of color to his
crossfade, and the sample program can handle a many color crossfade.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? How does a crossfade work?

Here comes the clever bit.

To do a crossfade, we load in two pictures, FROM and TO. Then, for every
pixel in which they are different, put a new pixel in a third screen.

For example, wherever there is pixel color 9 on screen 1 and pixel color
45 on screen 2, put pixel color 1 on the third screen. You then repeat
this for all combinations of pixels on screen one and two, and put the
results into screen 3. Here it is in ascii ...

  Screen 1     Screen 2     Screen 3
   .1...        .3...        .1...
   .....        ..2..        ..2..
   ...8.    +   ...1.    =   ...3.
   .1...        ....2        .4..2

Note how the values on screen 3 are sequential? We keep a count for
this... The two "2"'s on screen 3 are identical, so we do not use a new
color for it...

We also keep to pallettes ... source and dest.

For the above example source[1] would be the pallette of 1 in screen 1,
and dest[1] would be the pallette of 3 in screen 2 (Note that screen 1
and screen 2 have different pallettes)

When we are finished with the picture, we flip screen 3 to the vga and
do the following : move the pallette from source to dest or vice versa.
Thats it. No fancy screen manipulations for the crossfade, we just
change the pallette. Cool, huh? It also means that you can be doing fun
stuff in the foreground with unused pallette colors without your program
executing at two frames per second ;)

The sample program is fully documented, and you shouldn't have a problem
deciphering it... If you ever use this effect in a demo or game, greet
me! :-)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Problems with crossfades

The main problem with crossfading is this : there may only be 256 colors
on screen 3, in other words, only 256 combinations of colors.  In the
sample program, if you load up two pics with more then 256 combinations,
the program gives an error message and exits to dos. To sort this
problem out, you can do two things : reduce the number of places where
the two pictures intersect, or squeeze down the pallette, using
Autodesk Animators "SQUEEZE" command. This reduces the number of colors
used by the picture, and therefore reduces the number of combinations.
The picture does however lose a bit of quality.

The second problem with crossfading is this : It hogs most of the
colors. Whatever you want to do in the foreground, make sure you do it
with as few colors as possible.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? In closing

So, what do you think? Should I continue with demo effects, or should I
find more basic things to do? Perhaps I should stop and just do sound
coding from now on? It is up to you, so leave me mail.

You will notice that the sample program can load in any .CEL files, you
needn't be restricted by the ones I have given you. Try crossfading a
few of your own pictures and see how it turns out. The picture of the
robot was draw by Fubar for our demo Psycho Neurosis, and I then
squeezed down the pallette somewhat in order for the crossfade to work.
The word "ASPHYXIA" was drawn by me, also in Autodesk Animator.

Oh well, I had better get this off quickly, today is the last time for
the next few days that I can get on to the Net. I will also be voting
tomorrow! If I see a CNN camera, I'll wave (Thats me, the one on the
left in the red shirt! ;-))  The next trainer will be coming from the
New South Africa (TM)

See you next time!
 - Denthor
     - 9:16, 26 April, 1994

PS. Does anyone in Holland with net access want to act as a courier
between myself and the Accidental Connection BBS? Please leave me mail
at smith9@batis.bis.und.ac.za ....

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?Connectix BBS             ?+27-31-266-9992 ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Pure Surf BBS             ?+27-31-561-5943 ?A/H  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.

(I will find out the country code for Wasted Image later...)

                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 12 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello! :-)

Well, a lot has happened since the last trainer, which is the reason for
the amazingly long delay. First, the elections. These were quite easy
actually, I went and watched a move (Demolition Man) (Election day
special, all movies R2, which is about 50 US cents), then went and voted
after most voters had gone home, so no long lines ;-). Soon after were
exams. These did not go too well, and I am not looking forward to the
results. Finally, I got measles and pneumonia at the same time and was
sent off to hospital for a few days. All in all, not events which are
conducive to coding! This has meant that the trainer has been delayed,
and ASPHYXIA was not able to enter into the local democompo, Dexterity
'94, which we were hoping to do well in. Oh well, onward and upward!

This trainer is on full screen scrolling in Chain-4, by request. This is
actually very easy to do (and smooth), and holds a lot of potential, as
I am sure you can immediately imagine.

A few more things : People have been saying they have had hassles
sending me email, and I have found that this is because they forget the
numbers in my name. They send mail to smith@batis... which does not
exist, or smith@beastie... which is my brothers account. He is getting a
bit sick of forwarding my mail to me ;). The two address are :
       smith9@batis.bis.und.ac.za
       smith0@beastie.cs.und.ac.za

I have lost about 200k worth of email, chalk it up to my beginner status
at Unix. The test to see if your mail got through? I have answered
_every_ email message sent to me (no easy task), so if you haven't got a
reply, please resend the message.

You can now also send a group message to all members of Asphyxia. Just
send mail to asphyxia@beastie.cs.und.ac.za and we will all get a copy
... which could mean numerous replies to one querey ;)


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix.
            3) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            5) Write to smith9@batis.bis.und.ac.za in E-Mail.
            6) Write to asphyxia@beastie.cs.und.ac.za

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is full screen scrolling?

I seem to recall doing this in a previous tut, but here goes again! Full
screen scrolling is when the entire screen moves in a particular
direction, with the new picture scrolling on to the screen. Um. Think of
movie credits. The screen, filled with text, is scrolled off the top of
the screen while the new text is scrolled on from the bottom. This is
full screen scrolling.

Full screen scrolling is not limited to movie credits. Games like Raptor
have you flying over a scrolling landscape while you are shooting down
the bad guys. In this tutorial we will be doing vertical scrolling, but
the code can very easily be altered for horizontal scrolling too.

Remember that we will be using Chain-4 to do our scrolling, so you may
want to brush up on tut 10 in which that was covered. I will assume a
brief knowledge of how chain-4 works for this tutorial.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  The theory

The theory behind full screen scrolling in Chain-4 is acually very
simple.

Picture if you will, a screen that is two monitors high. Chain-4
actually has four, but for this we only need two. Now, for this screen
that is two monitors high, we can only see one monitors worth. Here it
is in ASCII

    +-------------+  Screen two monitors high
    |             |
    |             |
    |             |
    |             |
    |+-----------+|
    ||           ||
    ||           ||<- This is the bit we can see, one monitors worth
    ||           ||
    |+-----------+|
    +-------------+

We can move the bit we can see up or down the enlarged screen. So, for
example, if the screen two monitors high had a picture on it, we could
move the bit we see up and down to try glimpse the entire picture. Think
of it in this way : The screen is a large painting, but we can only see
though a small magnifing glass. We can move this magnifing glass around
the painting, but can never see the painting all at once.

This actually works in our favour. Anything done outside the bit we are
looking through cannot be seen, so we can do our work without changing
our screen.

On to scrolling. The method we will use this time is as follows :

1) Draw the next line to be seen just above and just below the part we
   can see.

      +------------+ The enlarged screen
      |            |
      |            |
      |111111111111|  The new part of the picture
      |+----------+|
      ||          || The bit we can see
      |+----------+|
      |111111111111|  The new part of the picture
      +------------+

2) Move the view up one pixel so that the new part of the picture is
   visible at the top of the screen.

3) Repeat Steps 1) and 2) until the whole screen is filled. Our screen
   will look as follows :

     +---------------+
     |+-------------+|
     ||3333333333333||
     ||2222222222222|| Viewscreen
     ||1111111111111||
     |+-------------+|
     |333333333333333|
     |222222222222222|
     |111111111111111|
     +---------------+

Check this picture with steps 1) and 2), you will see that this is
correct.

4) Set our viewport to the bottom of the enlarged screen.

     +---------------+
     |333333333333333|
     |222222222222222|
     |111111111111111|
     |+-------------+|
     ||3333333333333||
     ||2222222222222|| New position of viewscreen
     ||1111111111111||
     |+-------------+|
     +---------------+

As you can see, the bit we will be looking at is exactly the same as
before, we are now just at the bottom of the larger screen instead of
the top!

5) Jump back to 1). The entire sequence can begin again, and we can have
   infinate scrolling in the upward direction. Clever huh?


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Our code

In the sample code, we have 21 different icons. What we do is decide
what the next row of icons is going to consist of. We then draw the next
line of pixels above and below the viewscreen according to what icons we
are displaying. We then scroll up one pixel and begin again. When we
have completed a row of icons, we randomly select a new row and begin
again. Our icons are 16x16, so exactly 20 fit across a 320 pixel screen.

When we hit the top of our enlarged screen, we flip down to the bottom
which looks exactly the same as the screen we have left. In this manner
we have obtained smooth, infinate full screen scrolling!


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Extra bits

As you will see from the code, it would be the work of but a few minutes
to extend our landscape across the two unused screens, thereby allowing
limited horizontal movement along with our vertical movement. In fact,
the entire routine could easily be made to be a horizontal scrolling
routine.

A map of sorts could be generated, with one byte equalling one terrain
type. In this manner, the terrain scrolled over could be set, as in a
flying game (Flying Shark, Raptor etc). The terrain could also easily be
replaced with letters for our movie-style credits.

Free direction scrolling, ie scrolling in all directions, is a very
different matter, with very different methods to get it to work. Perhaps
this will be discussed in a later trainer. But for now, work with this,
know it, understand it, and think up many great things to do with it!
How about a full screen text scrolly? A game? Go wild!


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

Well, I hope you enjoyed this, the latest trainer. The sample program is
a little short, but that is because the concept is so simple. Attached
is a file, PICCS.DAT, which contains the terrain and letters for the
sample program. They were .CEL's, which I loaded into the des^ variable,
which I then dumped to disk, for easy access later. The .CEL's were
drawn on short notice, but still produces some nice terrain.

I have recieved a few requests for future trainers, and most of them are
for effects, so I guess that is what will be done from now on. A
surprising number have told me not to do a sound trainer and stick with
graphics stuff, with only a few asking for sound stuff, so I will hold
off on that until there is more of a demand.

I am still open to suggestions for future trainers, and of course
suggestions for improving the series. Leave me mail!

Hmm. A quote? Okay, let me think ....

        [    The little devil sat atop the alpine slopes, frolicking in the
           snow.  He threw a snowball at a nearby squirrel, which
           missed. The resulting avalance buried two villages and a ski
           resort.
             The little devil was scared. Avalances were bad for
           business. The locals would form team spirit, be nice to
           each other and work together and free those trapped beneath
           the snow, which created even more goodwill. The man
           downstairs didn't like goodwill. He didn't like it at
           all.
             In the blink of an eye the devil was in his penthouse
           apartment, dressed in his usual suit. He picked up the phone.
           Dialing was for mortals.
             "Hello, Micros..."
             "This is Mister Crowley", interrupted the devil.
             There were sounds of thumping on the other side of the
           phone, then there was a new voice. "Hello, Bill here, we
           haven't heard from you in a while, Mister Crowley." The fear
           of the man on the other end was almost tangible. The devil
           smiled.
             "Hello Bill. Something has come up."
             "No!" The man on the other side almost shouted with terror.
           "Not Win..."
             "Yes, Bill. It is time."
             "Havn't I paid enough for my sins? Just that one night..."
           The man was almost sobbing.
             "You are touching me, Bill. But nevertheless, it is time."
             "No." The man sounded beaten, alone.
             "Yes. Bill, it is time for a new update."
                                                                       ]
                                                      - Grant Smith
                                                          14:23
                                                            23-7-94

See you next time!
  - Denthor

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?Connectix BBS             ?+27-31-266-9992 ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Pure Surf BBS             ?+27-31-561-5943 ?A/H  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.


                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 13 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello again! Here I am, cooped up at home, recovering from my illness
with nothing to do, so of course it is the perfect time to write another
trainer! After the long delay between parts 11 and 12, two trainers in
two days doesn't sound like a bad idea.

This trainer is on starfields, which is by request of more then one
person. This is quite an easy effect, and you should have no trouble
grasping the concept behind it. I will be doing a 3d starfield, a
horizontal starfield is very easy with you merely incrementing a x-value
for each star for each frame. I am not even going to bother doing code
for that one (unless requested).

So I am off to go grab my antibiotics pills and I will be right back
with the tutorial! ;-)


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix.
            3) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            5) Write to smith9@batis.bis.und.ac.za in E-Mail.
            6) Write to asphyxia@beastie.cs.und.ac.za

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is a 3d starfield?

I am not even sure if I should do this bit. Go watch any episode of Star
Trek, the movies, Star Wars, or just about any sci-fi movie. Somewhere
there will be a scene where you can see stars whizzing past the
viewscreen, with the ones that are further away moving slower then the
ones that are passed quite close to.

This is a 3d starfield. If you look closely, you will see that all the
stars seem to originate from a point, the point you are travelling
towards.  This is an illusion which thankfully happens automatically,
you don't have to code for it ;)

Starfields look very nice, and can make a big difference to an otherwise
black background. It also makes a great screen saver ;-)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do they work?

This is actually quite simple. Imagine if you will, each star in the
heavens having an x,y and z coordinate, with you being at 0,0,0. Easy?
Right. Now, if you were to say move forward, ie. increase your z value,
to you you will still be at 0,0,0 , but all the stars z values would
have appeared to decrease by the exact same amount.

In easier language, we decrease the z value of all the the stars so that
they come closer to you, and eventually whizz past.

This solves all our problems. Stars that are close to us on the x and y
scales will pass us by faster then those that are very far from us on
the x and y scales. The only thing we must watch out for is that no star
is at 0,0 , ie. exactly in front of us, otherwise there will be a
collision which will not look good.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do we code this?

The first thing to be done is to generate our starfield. This is quite
easy, with us choosing x values between -160 and 160, and y values
between -100 and 100 randomly. Each z is sequentially greater for each
star so that we don't get large areas with no stars. We must remember to
check that there are no stars at 0,0!

Okay, now we start the actual viewing section. Here are the steps :

1) Convert our 3-d coords into their 2-d versions. Have a look at tut 8
   to see how this is done, but basically we divide by z.

2) Clear away all old stars that may be on the screen.

3) Draw all our stars according to our 2-d values we have calculated in
   1)

4) Move all the stars either closer to us or further away from us by
   decreasing or increasing their z values respectively.

5) If a star's z value has passed into the negative, place it at the
   very back of our "queue" so that it will come around again

6) Jump back to 1) ad-infinitum.

That is, as they say, it. In our sample program the steps have been
neatly placed into individual procedures for easy reading.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What next?

Okay, so now we have a cool looking starfield. What next? How about
adding left and right motion? A menu or a scrolly in the foreground? How
about figuring out how a star tunnel works? A cool 3d routine going in
front of the stars?

A starfield can make just about any routine look just that much more
professional, and can itself be improved to be a great effect all on
it's own.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

So, this was yet another effect in the series. Do you still want more
effects, or what? Leave me mail with further ideas for trainers. I may
not do it if you don't ask for it!

Oh, well, the medicine has been taken, it is time for me to go. Hello to
all those people who have sent me mail, and those great guys on #coders
in IRC (you know who you are). Wow. That is the first greets I have ever
done in a trainer. Hmm. Maybe I'm just ill ;-)

Happy coding people!
  - Denthor
      19:28
        24-7-94

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?Connectix BBS             ?+27-31-266-9992 ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.


                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 14 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello there. Exams are just around the corner (again :( ), so I thought 
I better get round to doing the next trainer. As usual, there seems to 
have been a big delay between this one and the last one... sorry about 
that ;-)

Well, this trainer is mainly on four things : Glenzing, faster polys,
fixed point and assembler. The sample program is basically tut 9
rewritten to include the above.

I'll go through them in order, and hopefully you won't have any hassles
grasping the concepts. By the way, do any of you read the text files? I
find myself answering questions via E-Mail etc. that were discussed in
the text sections of the trainers ... oh well, I'll just ramble along
anyway ;-)

Please dont send any mail to smith9@batis.bis.und.ac.za anymore ... I 
don't know for how much longer the account will be valid (How can a 
non-BIS person get onto the BIS UNIX machine in the BIS2 directory? If 
his name is Denthor I suppose ;-) Oh well, I got about 8 months use out 
of it. The account expires on Christmas day anyway...) So anyway, please
leave all messages to denthor@beastie.cs.und.ac.za
                                                  

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? What is glenzing?

This is an easy one. Imagine, in a 3D object, that all the sides are
made out of colored glass. That means that every time you look through
that side, everything behind it is tinged in a certain color.

In ascii ...
          +---------+
          |      <--|---Light blue
          |         |
     +--------+     |
     |    | <-|-----|---Dark blue
     |    +---|-----+
     |     <--|---------Light blue
     +--------+

So where the two sides overlap, the color values of the two sides are 
added. Easy huh? It is also easy to code. This is how you do it :

Set up your pallette to be a nice run of colors.
Draw your first poly.
While drawing poly 1, instead of plonking down a set pixel color, grab the
  backgrond pixel, add 1 to it, then put the result down.
Draw your second poly.
While drawing poly 2, instead of plonking down a set pixel color, grab the
  backgrond pixel, add 2 to it, then put the result down.
and so forth.

So if the color behind poly 1 was 5, you would place pixel 6 down
instead.

If you do this for every single pixel of every single side of your 3d 
object, you then have glenzing going. This is obviously slightly slower
then just drawing an item straight, but in the sample program it goes
quite quickly ... this is because of the following sections...
  

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Faster Polygons

In Tut 9, you probably noticed that we were using a multiply for every
single line of the poly that we drew. This is not good. Let's find out
how to speed it up, shall we...

With the multiply method, we went through every line, to find out the
minimum x and maximum x value for that line.

                           +
                   ------/---\------- Find min x and max x, draw a line
                       /       \        between them.
                     +           +
                       \       /
                         \   /
                           +

How about if we found out all the min and max x's for every line first, 
then just went through an array drawing them. We could do it by 
"scanning" each side in turn. Here is how we do it :

                          + 1
                        /
                      /
                  2 +

We go from point one to point two. For every single y we go down, we 
move a constant x value. This value is found like this :

           xchange := (x1-x2)/(y1-y2)

Remember gradients? This is how you calulated the slope of a line waaay
back in school. You never thought it would be any use, didn't you ;-)

Anyway, with this value, we can do the following :

    For loop1:=y1 to y2 do BEGIN
      [ Put clever stuff here ]
      x:=x+xchange;
    END;
    
and we will go through all the x-values we need for that line. Clever, 
huh?

Now for the clever bit. You have an array, from 0 to 199 (which is all
the possible y-values your onscreen poly can have). Inside this is two 
values, which will be your min x and your max x. You start off with the 
min x being a huge number, and the max x being a low number. Then you 
scan a side. For each y, check to see if one of the following has 
happened :    If the x value is smaller then the xmin value in your
                array, make the xmin value equal to the x value
              If the x value is larger then the xmax value in your
                array, make the xmax value equal to the x value

The loop now looks like this :

    For loop1:=y1 to y2 do BEGIN
      if x>poly[loop1,1] then poly[loop1,1]:=x;
      if x<poly[loop1,1] then poly[loop1,1]:=x;
      x:=x+xchange;
    END;

Easy? Do this for all four sides (you can change this for polys with 
different numbers of sides), and then you have all the x min and x max
values you need to draw your polygon.

In the sample program, if you replaced the Hline procedure with one that
draws solid lines, you could use the given drawpoly for solids.

Even this procedure is sped up by the next section, on fixed point.
   

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is fixed point?

Have you ever noticed how slow reals are? I mean slooooow. You can get a
massive speed increase in most programs by replacing your reals with 
integers, words etc. But, I hear you cry, what happens to the much 
needed fraction bit after the decimal point? The answer? You keep it. 
Here's how.

Let us say you have a word, which is 16 bits. If you want to use it as a
fixed point value, you can separate it into 2 sections, one of which 
holds the whole value, and one which holds the fraction.

             00000000  00000000   <-Bits
             Whole     Fraction
             
The number 6.5 would therefore be shown as follows :
 
             Top byte    :  6
             Bottom byte :  128
             
128 is half (or .5) of 256, and in the case of the fraction section, 256
would equal one whole number.

So let us say we had 6.5 * 2. Using reals this would be a slow mul, but 
with fixed point ...

            Top Byte    :  6     
            Bottom Byte :  128
            Value       :  1664   <-This is the true value of the word
                                     ie. (top byte*256)+bottom byte).
                                     this is how the computer sees the 
                                     word.
             1664 shl 1 = 3328    <-shl 1 is the same as *2, just faster.
            Top byte    :  13
            Bottom byte :  0

As you can see, we got the correct result! And in a fraction of the time
that a multiplication of a real would have taken us. You can add and
subtract fixed point values with no hassles, and multiply and divide 
them by normal values too. When you need the whole value section, you 
can just read the high byte, or do the following

             whole = word shr 8
         eg  1664 shr 8 = 6
         
As you can see, the fraction is truncated. Obviously, the more bits you 
set aside for the fraction section, the more accurate your calculation 
is, but the lesser the maximum whole number you can have. For example, 
in the above numbers, the maximum value of your whole number was 256, a
far cry from the 65535 a normal (non fixed point) word's maximum.

There are a lot of hassles using fixed point (go on, try shift a
negative value), most of which have to do with the fact that you have 
severely decreased the maximum number you may have, but trust me, the 
speed increase is worth it (With longintegers, and/or extended 386
registers, you can even have 16x16 fixed point, which means high
accuracy and high maximum values)

Try write a program using fixed point. It is not difficult and you will
get it perfect easily. Trust me, I'm a democoder ;-)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Assembler

In the sample program I used one or two assembler commands that I havent
discussed with you ... here they are ...

  imul  value      This is the same as mul, but for integer values. It
                     multiplies ax by the value. If the value is a word,
                     it returns the result in DX:AX

  sal  register,value   This is the same as shl, but it is arithmetic,
                          in other words it works on integers. If you
                          had to shl a negative value, the result would
                          mean nothing to you.

  rcl  register,value   This is the same as shl, but after you have
                          shifted, the value in the carry flag is placed
                          in the now-vacated rightmost bit. The carry
                          flag is set when you do an operation where the
                          result is greater then the upmost possible
                          value of the variable (usually 65535 or 32767)
                          eg mov ax,64000
                             shl ax,1     {<- Carry flag now = 1}
                             
For more info on shifting etc, re-read tut 7, it goes into the concept
in detail.

The sample program is basically Tut 9 rewritten. To see how the
assembler stuff is working, do the following ... Go into 50 line mode
(-Much- easier to debug), then hit [Alt - D] then R. A little box with
all your registers, segments etc and their values will pop up. Move it
down to where you want it, then go back to the program screen (Hit Alt
and it's number together), and resize it so that you have both it and
the register box onscreen at once (Alt - 5 to resize) ... then use F4,
F7 and F8 to trace though the program (you know how). The current value
of the registers will always be in that box.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? In closing

Well, that is about it. The sample program may start as being a little 
intimidating to some when they first look at it, just remember to read 
it with tut 9, very little is different, it's just with fixed point and 
a bit of assembler.

Before I forget, with Tut 13, the program crashes if you have error 
checking on. This is how you sort it out :

1) Turn off error checking     or
2) Make logo a pointer, and get and free the memory     or
3) Read the logo directly to screen     or
4) Use the {$M ......} command with various values at the top of the 
     program till it works.
     
I prefer options 3 or 2, but hey ... the problem was that the logo was
rather large (16k), and Pascal likes complaining ;-)

I am in doubt as to weather to continue doing quotes ... here is a 
conversation I had with Pipsy, after the group conversation got around 
to weather we were normal or not ...

Me : I'm normal.
Pipsy : No your not.
Me : Prove it.
Pipsy : Just look at your quotes in your trainers.
Me : What? You think those are weird?
Pipsy : Too weird.
Me : You mean that there is a weirdness line, and I crossed it?
Pipsy : Yes.

Bit of a conversation killer that, so we stopped there.

Anyway, this trainer won't have a quote in it ... how about a disclaimer
instead? Feel free to use it in your messages ...

------------------------------------------------------------------------
The views expressed above are mine and not Novells. In fact, I've never
worked for them in my life!

Byeeee....
  - Denthor
      18:57
        9-9-94


The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 15 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hello again. As you can see, this tut is very soon after the last one.
This is because of two reasons ... 1) The PCGPE ][ will be out soon, so
I thought I would make sure I have more then just four new trainers for it,
and 2) I am usually so late between tuts, I thought I would make up for it.

There is a discussion going on in Usenet, mostly saying that trainers etc.
should be written a bit more formally and none of this gay banter and
familiar language should be used. My "quotes" would definately be out ;-)
But, until I get paid for doing this (and there don't seem to be any takers
on that score), I will continue to write in this manner. My apologies to those
who dont like this, but hey, its free, what did you expect?

This trainer is on plasmas, and the sample program actually became quite large,
mostly due to the fact that there was some plasma stuff I wanted to try out.

The concept is very simple, at least for this plasma, so you shouldn't have
any problems understanding it ... AFTER you have read the text file ...
jumping straight into the source may be hazardous to your brain.

Plasmas are a great way to wow your friends by their wierd shapes and forms.
I was at one stage going to write a game where the bad guy just had two
circular plasmas instead of eyes... I am sure you will find creative and
inventive new ways of doing and using plasmas.


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How do plasmas work?

I will only cover one type of plasma here ... a realtime plasma of course.
Other types of plasmas include a static picture with a pallette rotation...

When you get right down to it, this method of realtime plasmas is merely an
intersection of four COS waves. We get our color at a particular point by
saying :
      col := costbl[one]+costbl[two]+costbl[three]+costbl[four];

The trick is getting the four indexes of that cos table array to create
something that looks nice. This is how we organise it : Have two of them
being indexes for vertical movement and two of them being indexes for
horizontal movement.

This means that by changing these values we can move along the plasma. To
draw an individual screen, we pass the values of the four to another four
so that we do not disturb the origional values. For every pixel across, we
add values to the first two indexes, then display the next pixel. For
every row down, we add values to the second two indexes. Sound complex
enough? Good, because that what we want, a complex shape on the screen.

By altering the origional four values, we can get all sorts of cool movement
and cycling of the plasma. The reason we use a cos table is as follows :
a cos table has a nice curve in the value of the numbers ... when you
put two or more together, it is possible to get circular pictures ...
circles are hard to do on a computer, so this makes it a lot easier...

Okay, now you can have a look at the source file, all I do is put the above
into practice. I did add one or two things though ...

Background : This is just a large array, with the values in the array being
added to the plasma at that pixel.

Psychadelic : This cycles through about 7000 colors instead of just rotating
through the base 256.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Clever fading

You will notice when the sample program fades in and out that the colors
all reach their destination at the same time ... it other words, they don't
all increment by one until they hit the right color then stop. When done
in that way the fading does not look as professional.

Here is how we do a step-crossfade.

Each r,g,b value can be between 0 and 64. Have the pallette we want to get
to in bob and the temporary pallette in bob2. For each step, from 0 to 63
do the following :
     bob2[loop1].r:=bob[loop1].r*step/64;

That means if we are halfway through the crossfade (step=32) and the red
value is meant to get to 16, our equation looks like this :
    r:=16*32/64
     r=8

Which is half of the way to where it wants to be. This means all colors will
fade in/out with the same ratios... and look nicer.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Rotating the pallette

I have done this one before I think .. here it is ...

move color 0 into temp

move color 1 into color 0
move color 2 into color 1
move color 3 into color 2
and so on till color 255

move temp into color 255

And you pallette is rotating. Easy huh? Recheck tut 2 for more info on
pallette rotation

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

The text file was a bit short this time, but that is mostly because the
sample file is self explanitory. The file can however be speeded up, and
of course you can add certain things which will totally change the look
of the plasma.

As always, I am on the lookout for more ideas for future tuts, if you have
some, mail me!

No quote today, this lan doesn't encourage creative thinking ;) However,
there will be quotes in future as I have been told that some people like
them. Even Pipsy said this while we were playing Ctrl-Alt-Del (two player
game, one has to hit ctrl and alt as the other hits del, and the person
hitting the del has to do it quickly so that the computer doesnt reboot.
If the computer reboots the person who was hitting ctrl and alt has won.
I thought I was doing really badly against Pipsy until I found out that the
computer had frozen ;-))

Byeeee....
  - Denthor
      14:11
        16-9-94


The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 16 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi there. This trainer is on the scaling of an arbitrary sized bitmap to
screen in two dimensions. The sample program seems to work quite quickly,
and the code is document. The scaling procedure is however totally in
assembler ... hopefully this won't cause to many problems.

EzE has released a trainer! It is on the speeding up of 3D for normal 3D
and for virtual worlds. Check it out, it is quite good (even though I get
a bit of ribbing in his quote ;-)) It will be in PCGPE ][, to be released
shortly.

I have set up a mailserver (that doesn't seem to work all the time, but
the ones that miss I post manually). It works like this :

Send mail to denthor@beastie.cs.und.ac.za with the subject line :
request-list ... it will automatically mail you back with a list of
subject lines with which you can grab certain files. You will then mail me
with the subject line of a specific file and it will send you a uuencoded
version of that file automatically. Cool, huh?

Remember, no more mail to smith9@batis.bis.und.ac.za, send it all to
denthor@beastie.cs.und.ac.za ! Thanks.


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  What is scaling?

I think that most of you know this one already, but here goes. Let us say
you have a picture (10x10 pixels) and you want to draw it to a different
size (say 5x7 pixel), the process of altering the picture to fit into the
new size is called scaling. Scaling only works on rectangular areas.

With scaling to can easily strech and shrink your bitmaps.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Okay, so how do we code it?

Right. The way I am going to do scaling is as follows :

For the horizontal area, I am going to calculate a certain step value. I
will then trace along the bitmap, adding this step to my position, and
placing the nearest pixel on to the screen. Let me explain this simpler ...

Let us say I have a 10 pixel wide bitmap. I want to squish it into 5 pixels.
Along the bitmap, I would draw every second pixel to screen. In ascii :

  1234567890   13579
  +--------+   +---+
  |        |   |   |
  | bitmap |   |   |dest
  |        |   |   |
  +--------+   +---+

As you can see, by stepping through every second pixel, I have shrunk the
bitmap to a width of 5 pixels.

The equation is as follows :

            step = origionalwidth / wantedwidth;

Let us say we have a 100 pixel wide bitmap, which we want to get to 20 pixels.

            step = 100 / 20
            step = 5

If we draw every fifth pixel from the origional bitmap, we have scaled it down
correctly! This also works for all values, if step is of type real.

We also find the step for the height in the same way.

Our horizontal loop is as follows :

       For loop1:=1 to wantedwidth do BEGIN
         putpixel (loop1,height,bitmap[round (curpos)],vga);
         curpos:=curpos+xstep;
       END;

And the vertical loop is much the same. Easy huh? So east in fact, I wrote the
procedure in pure assembler for you ;-) ... don't worry, it's commented.

In the sample program, instead of using reals I have used fixed point math.
Refer to tut 14 if you have any hassles with fixed point, it is fairly
straightforward.

I also use psuedo 3-d perspective transforms to get the positions smooth...
after Tut8, this should be a breeze.

There are no new commands in the assembler for you, so you should get by with
what you learned in tut7/8 ... whew! A lot of back referencing there ;) We
really are building on our knowledge :)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

Well, that is about it. As you can see the concept is easy, and in fact
fairly obvious, but that didn't stop me from having to sit down with a
pencil and a piece of paper a few months ago and puzzle it out ;-)

I have a lot of work ahead of me for a while, so this may be the last
trainer for a few months ... unless I can find some free time available.
So please be patient!


       [ "Sir! My computer has just gone haywire!"
         "What?" shouts the CO. "That is a multimilliondollar machine!
           find out what's wrong! This is a critical time lieutenant!"
         "Yes sir"
         The young lieutenant furiously types away at the keyboard, but
           the machine totally ignores her.
         "What is going on, soldier?"
         "I don't know sir! It is just doing totally arbitrary things
           after it's assigned tasks are completed. In the computer world
           this is known as Denthorisms."
         The computer starts to make random beeps, and prints out a payroll
           program.
         "Get it working NOW soldier"
         The lieutenant ignores him, and contines typing. She gets partial
           control of the system, she can run programs, but the computer is
           continually running arb tasks in the background. One of the
           techhies who have gathered behing her suddenly cries "Hey! It's
           accessing the missile codes! It wants to launch them!"
         The typing gathers speed, but to no avail. Another techhie says
           "I could disconnect the computer from the link, but that would take
           hours! And this thing will have the codes in under five minutes
           at the speed it's going!"
         A smile forms on the lieutanants face, and she leans back in her chair.
         "What the hell are you doing?" yells the CO. "Why have you stopped?"
         Again ignoring him, the lieutenant instead turns to the techhie. "Go
           disconnect the machine, I know how to get you the time you need."
         "How on earth will you do that? The machines going at top speed!"
         She smiles again, leans forward, types in three letters and hits the
           carriage return. The computer grinds to a halt.
         The smile breaks into a grin. "Maybe it _does_ have it's uses after
           all."
                                                                        ]
                                                         - Grant Smith
                                                             15:30
                                                               23-9-94

Byeeeee.....

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
?Reckless Life             ?351-01-716 67 58?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 17 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi there everybody. It's a new year, but the parties are over and it's time
to get coding again!

My mailserver died. Various sysadmins decided it was time to upgrade the
OS, and wound up nuking the hard drive :-( ... this means that request-list
is not working at the moment, and I have probably lost lots of mail.

denthor@beastie.cs.und.ac.za is still the account to write to, and
hopefully the mailserver will be back up in the near future.

There are various C/C++ conversions of my trainer, best of which seem to be
those by Snowman ... he runs through the text files with C++ updates (and
seems to point out my previous mistakes with glee ;-), as well is giving a
fully documented C++ conversion of the source ... very nice stuff.

Also, my trainers are being put on a World Wide Web site ... it is still
under construction, but go to http://www.cit.gu.edu.au/~rwong
my site is at http://goth.vironix.co.za/~denthor ... it is currently pretty
awful, anyone want to write a nice one for me? ;)

I have just about finished Asphyxia's new game, I will let you all know
when it is completed.

Tut 16 dies with large bitmaps ... the way to sort this out is to decrease
the accuracy of the fixed point from 256 to 128 ... then you can have
bitmaps up to 512 pixels wide. I will be putting an updated scale routine
in the gfx4.pas unit.

This tutor is on a few demo effects (pixel morphs and static) ... after
this one, I will go on to more theory ... perhaps some more 3d stuff, such
as gourad shading etc. Comments?


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Pixel Morphing

Have you ever lain down on your back in the grass and looked up at the
cloudy sky? If you have, you have probably seen the clouds move together
and create wonderful shapes ... that cloud plus that cloud together make a
whale ... a ship ... a face etc.

We can't quite outdo mother nature, but we can sure give it a shot. The
effect I am going to show you is where various pixels at different starting
points move together and create an overall picture.

The theory behind it is simple : Each pixel has bits of data associated
with it, most important of which is as follows :

This is my color
This is where I am
This is where I want to be.

The pixel, keeping it's color, goes from where it is to where it wants to
be. Our main problem is _how_ it moves from where it is to where it wants
to be. A obvious approach would be to say "If it's destination is above it,
decrement it's y value, if the destination is to the left, decrement it's x
value and so on."

This would be bad. The pixel would only ever move at set angles, as you can
see below :

                Dest   O-----------------\
                                           \  <--- Path
                                             \
                                               \
                                                O Source

Doesn't look very nice, does it? The pixels would also take different times
to get to their destination, whereas we want them to reach their points at
the same time, ie :

     Dest 1   O-------------------------------O Source 1
     Dest 2   O-----------------O Source 2

Pixels 1 and 2 must get to their destinations at the same time for the best
effect. The way this is done by defining the number of frames or "hops"
needed to get from source to destination. For example, we could tell pixel
one it is allowed 64 hops to get to it's destination, and the same for
point 2, and they would both arrive at the same time, even though pixel 2
is closer.

The next question, it how do we move the pixels in a straight line? This is
easier then you think...

Let us assume that for each pixel, x1,y1 is where it is, and x2,y2 is where
it wants to be.

   (x2-x1) = The distance on the X axis between the two points
   (y2-y1) = The distance on the Y axis between the two points

If we do the following :

  dx := (x2-x1)/64;

we come out with a value in dx wich is very useful. If we added dx to x1 64
times, the result would be x2! Let us check...

  dx = (x2-x1)/64
  dx*64 = x2-x1         { Multiply both sides by 64 }
  dx*64+x1 = x2         { Add x1 to both sides }

This is high school math stuff, and is pretty self explanitory. So what we
have is the x movement for every frame that the pixel has to undergo. We
find the y movement in the same manner.

  dy := (y2-y1)/64;

So our program is as follows :

  Set x1,y1 and x2,y2 values
  dx:= (x2-x1)/64;
  dy:= (y2-y1)/64;

  for loop1:=1 to 64 do BEGIN
    putpixel (x1,y1)
    wait;
    clear pixel (x1,y1);
    x1:=x1+dx;
    y1:=y1+dy;
  END;

If there was a compiler that could use the above pseudocode, it would move
the pixel from x1,y1 to x2,y2 in 64 steps.

So, what we do is set up an array of many pixels with this information, and
move them all at once ... viola, we have pixel morphing! It is usually best
to use a bitmap which defines the color and destination of the pixels, then
randomly scatter them around the screen.

Why not use pixel morphing on a base object in 3d? It would be the work of
a moment to add in a Z axis to the above.

The sample program uses fixed point math in order to achieve high speeds,
but it is basically the above algorithm.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Static

A static screen was one of the first effects Asphyxia ever did. We never
actually released it because we couldn't find anywhere it would fit. Maybe
you can.

The easiest way to get a sreen of static is to tune your TV into an unused
station ... you even get the cool noise effect too. Those people who build
TV's really know how to code ;-)

For us on a PC however, it is not as easy to generate a screen full of
static (unless you desperately need a new monitor)

What we do is this :

Set colors 1-16 to various shades of grey.
Fill the screen up with random pixels between colors 1 and 16
Rotate the pallette of colors 1 to 16.

That's it! You have a screenfull of static! To get two images in one static
screen, all you need to do is fade up/down the specific colors you are
using for static in one of the images.

A nice thing about a static screen is that it is just pallette rotations
... you can do lots of things in the foreground at the same time (such as a
scroller).

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

Well, that is about it ... as I say, I will be doing more theory stuff in
future, as individual demo effects can be thought up if you know the base
stuff.

Note the putpixel in this GFX3.PAS unit ... it is _very_ fast .. but
remember, just calling a procedure eats clock ticks... so imbed putpixels
in your code if you need them. Most of the time a putpixel is not needed
though.

PCGPE ][ will be out on the 10th of Feburary. All the new tutors will be on
it (if you aren't reading this from it right now! ;-) ... grab a copy of
it, it is a very useful ting to have handy.

I have found out that these tutors have been distributed inside paper
magazines ... please remember that Denthor and Asphyxia retain full
copyright to the series (as mentioned earlier in the series), and if you
want to use a version in a magazine, CONTACT ME FIRST ... I will probably
also modify it/cut out various unneccesary things ... other then that, you
must not alter the files without my permission, or at least leave a copy of
the origional with the update. Maybe I could even start up a nice column
for some magazine or other :)

Sorry 'bout that, but it had to be said ...

I am writing a column for the Demuan list, a Florida-based electronic
magazine ... pick it up off ftp.eng.ufl.edu ... I have written various
articles, all bordering on quote-like design.

There are more BBS's to be added to the list at the end, but I don't have
them here... this tut has taken long enough ;-)

Byeeeee....
  - Denthor

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
?Reckless Life             ?351-01-716 67 58?ALL  ?
?Mach 5 BBS                ?+1 319-355-7336 ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 18 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Welcome back! I know, I know, you all all shocked that this tut is out so
soon after the last one, but the reason for this is that I want to have Tut
20 out by the time PCGPE ][ is released. I probably won't get that far, but
I'll try! ;)

This tut is on file packing, and putting everything into one executeable
file. For tut 19, I am thinking of doing a bit more on explaining
assembler, and perhaps demonstrating with a fire effect or something.

My mailserver is back up, thanks to Nobody (that's his handle). You write
to denthor@beastie.cs.und.ac.za with the subject line request-list. The
mailserver checks each incoming letter for this subject line, and if it
finds one of the specific strings, it mails you back a certain file. I
never get to see these messages! If you want to mail me personally, give
your message a unique subject name! Anyway, you can request all the tuts
through this mailserver.

I hope you are all subscribed to the Demuan List! If not, ftp it off
ftp.eng.ufl.edu every sunday. I am writing a "humor" column there until
someone can figure out something else I could write ;-).

Pipsy wants mail! She is at cowan@beastie.cs.und.ac.za and wants to chat :)
Go on, mail her. The co-founder of ctrl-alt-del, she is also a good
graphics coder.


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Loading a PCX file

This is actually quite easy. The PCX file is divided into three sections,
mainly a 128 byte header, a data section, and a 768 byte pallette.

You can usually ignore the 128 byte header, but here it is :

0  Manufacturer     10 = ZSoft .PCX file
1  Version
2  Encoding
3  Bits Per Pixel
4  XMin, Ymin, XMax, YMax  (2 bytes each)
12 Horizontal Resolution (2 bytes)
14 Verticle Resolution (2 bytes)
16 Color pallette setting (48 bytes)
64 Reserved
65 Number of color planes
66 Bytes per line (2 bytes)
68 1 = Color    2 = Grayscale  (2 bytes)
70 Blank (58 bytes)

That makes 128 bytes.

The pallette file, which is 768 bytes, is situated at the very end of the
PCX file. The 769'th byte back should be the decimal 12, which indicates
that a VGA color pallette is to follow.

There is one thing that we have to do to get the pallette correct in VGA ...
the PCX pallette values for R,G,B are 0 to 255 respectively. To convert this
to our standard (VGA) pallette, we must divide the R,G,B values by 4, to get
them into a range of 0 to 63.

Actually decoding the image is very simple. Starting after the 128 byte
header, we read a byte.

If the top two bits of this byte are not set, we dump the value to the screen.

We check bits as follows :

if ((temp and $c0) = $c0) then ...(bits are set)... else ...(bits are not set)

C0 in hex = 11000000 in binary = 192 in decimal

Let's look at that more closely...

  temp  and  c0h
  temp  and  11000000b

That means, when represented in bit format, both corresponding bits have
to be set to one for the result to be one.

0 and 0 = 0     1 and 0 = 0    0 and 1 = 0    1 and 1 = 1

In the above case then, both of the top two bits of temp have to be set for
the result to equal 11000000b. If it does not equal that, the top two bits
are not both set, and we can put the pixel.

So

  if ((temp and $c0) = $c0) then BEGIN
  END else BEGIN
    putpixel (screenpos,0,temp,vga);
    inc (screenpos);
  END;

If the top two bits _are_ set, things change. The bottom six bits become
a loop counter, which the next byte is repeated.

  if ((temp and $c0) = $c0) then BEGIN
{    Read in next byte, temp2 here.}
    for loop1:=1 to (temp and $3f) do BEGIN
      putpixel (screenpos,0,temp2,vga);
      inc (screenpos);
    END;
  END else BEGIN
    putpixel (screenpos,0,temp,vga);
    inc (screenpos);
  END;

There is our PCX loader. You will note that by and'ing temp by $3f, I am
and'ing it by 00111111b ... in other words, clearing the top two bits.

The sample program has the above in assembler, but it is the same procedure...
and you can read tut 19 for more info on how to code in assembler.

In the sample I assume that the pic is 320x200, with a maximum size of 66432
bytes.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  File packing

The question is simple .. how do I get all my files into one executeable?
Having many small data files can start to look unprofessional.

An easy way to have one .exe and one .dat file when dealing with many
cel's etc. is easy .... you would alter your load procedure, which looks
as follows :

VAR temp : Array [1..5,1..256] of byte;
Procedure Init;
BEGIN
  loadcel ('pic1.cel',temp[1]);
  loadcel ('pic2.cel',temp[2]);
  loadcel ('pic3.cel',temp[3]);
  loadcel ('pic4.cel',temp[4]);
  loadcel ('pic5.cel',temp[5]);
END;

For one complile you would do this :

VAR temp : Array [1..5,1..256] of byte;
Procedure Init;
VAR f:File;
BEGIN
  loadcel ('pic1.cel',temp[1]);
  loadcel ('pic2.cel',temp[2]);
  loadcel ('pic3.cel',temp[3]);
  loadcel ('pic4.cel',temp[4]);
  loadcel ('pic5.cel',temp[5]);
  assign (f,'pic.dat');
  rewrite (f,1);
  blockwrite (f,temp,sizeof(temp));
  close (f);
END;

From then on, you would do :

VAR temp : Array [1..5,1..256] of byte;
Procedure Init;
VAR f:File;
BEGIN
  assign (f,'pic.dat');
  reset (f,1);
  blockread (f,temp,sizeof(temp));
  close (f);
END;

This means that instead of five data files, you now have one! You have also
stripped the 800 byte cel header too :) ... note that this will work for any
form of data, not just cel files.

The next logical step is to include this data in the .exe file, but the
question is how?  In an earlier tutorial, I converted my data file to
constants and placed it inside my main program. This is not good mainly
because of space restrictions ... you can only have so many constants, and
what if your data file is two megs big?

Attached with this tutorial is a solution. I have written a program that
combines your data files with your executeable file, no matter how big
the data is. The only thing you have to worry about is a small change in
your data loading methods. Lets find out what.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Using the file packer

Normally you would load your data as follows :

Procedure Init;
BEGIN
  loadcel ('bob.bob',temp);
  loadpcx ('den.pcx',VGA);        { Load a PCX file }
  loaddat ('data.dat',lookup);    { Load raw data into lookup }
END;

Easy, hey? Now, using the file packer, you would change this to :

USES fpack;
Procedure Init;
BEGIN
  total := 3;
  infodat[1] := 'bob.bob';
  infodat[2] := 'den.pcx';
  infodat[3] := 'data.dat';
  loadcel (1,temp);
  loadpcx (2,VGA);
  loaddat (3,lookup);
END;

Not too difficult? Now, this is still using the normal data files on your
hard drive. You would then run PACK.EXE, select the program's .exe as the
base, then select "bob.bob", "den.pcx" and "data.dat", in order (1, 2, 3).
Hit "c" to contine, and it will combine the files. Your programs .exe file
will be able to run independantly of the separate data files on disk,
because the data files are imbedded with the .exe.

Let us take a closer look at the load procedures. Normally a load procedure
would look as follows :

Procedure LoadData (name:string; p:pointer);
VAR f:file;
BEGIN
  assign (f,name);
  reset (f,1);
  blockread (f,p^,filesize(f);
  close (f);
END;

In FPack.pas, we do the following :

Function LoadData (num:integer; p:pointer):Boolean;
VAR f:file;
BEGIN
  If pack then BEGIN
    assign (f,paramstr(0));
    reset (f,1);
    seek (f,infopos[num]);
    blockread (f, p^, infopos[num+1]-infopos[num]);
    close (f);
  END else BEGIN
    assign (f,infodat[num]);
    reset (f,1);
    blockread (f, p^, filesize (f));
    close (f);
  END;
END;

As you can see, we just have two special cases depending on weather or not
the .exe file has been packed yet.

NOTE : After you have packed the file, you CAN NOT pklite it. You can
       however pklite the .exe _before_ you run pack.exe ... in other
       words, you can not use pklite to try pack your data files.

PACK.EXE does have a limitation ... you can only pack 24 data files together.
If you would like it to do more, mail me ... It should be easy to increase the
number.

In the sample program, FINAL.EXE is the same as temp.pas, except it has
it's PCX embedded inside it. I ran pack2.exe, selected final.exe and
eye.pcx, hit "C", and there it was. You will notice that eye.pcx is not
included in the directory ... it is now part of the exe!

eye.pcx was draw by Gary Morton of iCANDi Design. The other pcx is an old
one draw by Fubar.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

Well, that's about it for this trainer... next one (as I have mentioned
twice already ;) will be on assembler, with a flame routine thrown in.

Any good html programmers out there? My web page really needs help ;-)

As soon as I figure out how, I will also be creating a mailing list, in
which people with internet addresses will be able to get all new trainers
dilivered directly into their mailbox's. I hope to announce something in
tut 20.

This tut has been a bit of a departure from normal tuts ... aside from the
PCX loading routines, the rest has been "non programming" oriented ...
don't worry, next weeks one will be back to normal.


Byeeeee....
  - Denthor

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ? *Moving*
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ? *Moving*
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
?Reckless Life             ?351-01-716 67 58?ALL  ?
?Mach 5 BBS                ?+1 319-355-7336 ?ALL  ?
?House of Horror           ?+1 513-734-6470 ?ALL  ?
?Zero Level                ?+39 6-810-9934  ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 19 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi there. As promised in Tut 18, this trainer is on assembler. For those
people who already know assembler quite well, this tut is also on the flame
effect.

Okay, here is the total list of ways to get my trainers :

http://goth.vironix.co.za/~denthor                     (WWW)
ftp.eng.ufl.edu pub/msdos/demos/code/graph/tutor       (FTP)
denthor@beastie.cs.und.ac.za  Subject : request-list   (EMAIL)

As well as the BBS numbers shown at the end ... I will add a few ftp sits
to that list (x2ftp.oulu.fi etc.)

Tut 20? How about 3d shading, hidden surface removal etc? Mail me :)


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Assembler - the short version

Okay, there are many assembler trainers out there, many of which are
probably better then this one. I will focus on the areas of assembler that
I find important ... if you want more, go buy a book (go for the Michael
Abrash ones), or scour the 'net for others.

First, let us start off with the basic set up of an assembler program.

DOSSEG

This tells your assembler program to order your segments in the same manner
that high level languages do.

.MODEL <MODEL>

<MODEL> can be : Tiny       Code + Data < 64k   (Can be made a COM file)
                 Small      Code < 64k          Data < 64k
                 Medium     Code > 64k          Data < 64k
                 Compact    Code < 64k          Data > 64k
                 Large      Code > 64k          Data > 64k
                 Huge       Arrays > 64k

.286

Enable 286 instructions ... can be .386 ; .386P etc.

.STACK <size>

<size> will be the size of your stack. I usually use 200h

.DATA

Tells the program that the data is about to follow. (Everything after this
will be placed in the data segment)

.CODE

Tells the program that the code is about to follow. (Everything after this
will be placed in the code segment)

START :

Tells the program that this is where the code begins.

END START

Tells the program that this is where the code ends.

To compile and run an assembler file, we run
tasm bob
tlink bob

I personally use tasm, you will have to find out how your assembler works.

Now, if we ran the above file as follows :

DOSSEG
.MODEL SMALL
.286
.STACK 200h
.DATA
.CODE

START
END START

You would think that is would just exit to dos immediately, right? Wrong.
You have to specifically give dos back control, by doing the following :

START
        mov     ax,4c00h
        int     21h
END START

Now if you compiled it, it would run and do nothing.

Okay, let us kick off with registers.

Firstly : A bit is a value that is either 1 or 0

This is obviously quite limited, but if we start counting in them, we can
get larger numbers. Counting with ones and zeros is known as binary, and we
call it base 2. Counting in normal decimal is known as base 10, and
counting in hexidecimal is known as base 16.

    Base 2 (Binary)     Base 10 (Decimal)    Base 16 (Hexidecimal)
         0                      0                       0
         1                      1                       1
         10                     2                       2
         11                     3                       3
         100                    4                       4
         101                    5                       5
         110                    6                       6
         111                    7                       7
         1000                   8                       8
         1001                   9                       9
         1010                   10                      A
         1011                   11                      B
         1100                   12                      C
         1101                   13                      D
         1110                   14                      E
         1111                   15                      F

As you can see, you need four bits to count up to 15, and we call this a
nibble. With eight bits, we can count up to 255, and we call this a byte.
With sixteen bits, we can count up to 65535, and we call this a word. With
thirty two bits, we can count up to lots, and we call this a double word. :)

A quick note : Converting from binary to hex is actually quite easy. You
break up the binary into groups of four bits, starting on the right, and
convers these groups of four to hex.

      1010 0010 1111 0001
  =      A    2    F    1

Converting to decimal is a bit more difficult. What you do, is you multiply
each number by it's base to the power of it's index ...

  A2F1 hex
= (A*16^3) + (2*16^2) + (F*16^1) + (1*16^0)
= (10*4096) + (2*256) + (15*16) + (1)
= 40960 + 512 + 240 + 1
= 41713 decimal

The same system can be used for binary.

To convert from decimal to another base, you divide the decimal value by the
desired base, keeping a note of the remainders, and then reading the results
backwards.

               16   |   41713
               16   |   2607    r   1       (41713 / 16 = 2607 r 1)
               16   |   162     r   F       (2607 / 16 = 162 r 15)
               16   |   10      r   2       (162 / 16 = 10 r 2)
                    |   0       r   A       (10 / 16 = 0 r 10)

Read the remainders bacckwards, our number is : A2F1 hex. Again, the same
method can be used for binary.

The reason why hex is popular is obvious ... using bits, it is impossible
to get a reasonable base 10 (decimal) system going, and binary get's unwieldly
at high values. Don't worry too much though : most assemblers (like Tasm)
will convert all your decimal values to hex for you.

You have four general purpose registers : AX, BX, CX and DX
Think of them as variables that you will always have. On a 286, these
registers are 16 bytes long, or one word.

As you know, a word consists of two bytes, and in assembler you can access
these bytes individualy. They are separated into high bytes and low bytes per
word.

   High Byte |  Low Byte
   0000 0000 | 0000 0000  bits
   [--------Word-------]

The method of access is easy. The high byte of AX is AH, and the low byte is
AL ... you can also access BH, BL, CH, CL, DH and DL.

A 386 has extended registers : EAX, EBX, ECX, EDX ... you can access the
lower word normally (as AX, with bytes AH and AL), but you cannot access the
high word directly ... you must ror EAX,16 (rotate the binary value through
16 bits), after which the high word and low word swap ... do it again to
return them. Acessing EAX as a whole is no problem ... mov eax,10 ;
add eax,ebx ... these are all vaild.

Next come segments. As you have probably heard, computer memory is divided
into various 64k segments (note : 64k = 65536 bytes, sound familiar?) A
segment register points to which segment you are looking at. An offset
register points to how far into that segment you are looking. One way
of looking at it is like looking at a 2d array ... the segments are your
columns and your offsets are your rows. Segments and offsets are displayed
as Segment:Offset ... so $a000:50 would mean the fiftieth byte in segment
$a000.

The segment registers are ES, DS, SS and CS. A 386 also has FS an GS.
These values are words (0-65535), and you cannot access the high or low bytes
separately. CS points to you your code segment, and usually if you touch this
your program will explode. SS points to your stack segment, again, this
baby is dangerous. DS points to your data segment, and can be altered, if
you put it back after you use it, and don't use any global variables while
it is altered. ES is your extra segment, and you can do what you want with
it.

The offset registers are DI, SI, IP, SP, BP. Offset registers are generally
asscociated with specific segment registers, as follows :
ES:DI  DS:SI  CS:IP  SS:SP ... On a 286, BX can be used instead of the above
offset registers, and on a 386, any register may be used. DS:BX is therefore
valid.

If you create a global variable (let's say bob), when you access that
variable, the compiler will actually look for it in the data segment.
This means that the statement :

ax = bob
could be
ax = ds:[15]

A quick note : A value may be signed or unsigned. An unsigned word has a
range from 0 to 65535. A signed word is called an integer and has a range
-32768 to 32767. With a signed value, if the leftmost bit is equal to 1,
the value is in the negative.

Next, let us have a look at the stack. Let us say that you want to save the
value in ax, use ax to do other things, then restore it to it's origional
value afterwards. This is done by utilising the stack. Have a look at the
following code :

mov   ax, 50      ; ax is equal to 50
push  ax          ; push ax onto the stack
mov   ax, 27      ; ax is equal to 27
pop   ax          ; pop ax off the stack
At this point, ax is equal to 50.

Remember we defined the stack to be 200h further up? This is part of the
reason we have it. When you push a value onto the stack, that value is
recorded on the stack heap (referenced by SS:SP, SP is incremented) When you
pop a value off the stack, the value is placed into the variable you are
poping it back in to, SP is decremented and so forth. Note that the computer
does not care what you pop the value back in to ...

mov   ax, 50
push  ax
pop   bx

Would set the values of both ax and bx to 50. (there are faster ways of doing
this, pushing and poping are fairly fast though)

push ax
push bx
pop  ax
pop  bx

would swap the values of ax and bx. As you can see, to pop the values back
in to the origional variables, you must pop them back in the opposite
direction to which you pushed them.

push ax
push bx
push cx

pop cx
pop bx
pop ax

would result in no change for any of the registers.

When a procedure is called, all the parameters for that procedure are pushed
onto the stack. These can actually be read right off the stack, if you want
to.

As you have already seen, the mov command moves a value...

mov  <dest>, <source>

Note that dest and source must be the same number of bits long...

mov  ax, dl

would not work, and neither would

mov  cl,bx

However, mov  cx,dx
         mov  ax,50
         mov  es,ax
are all valid.

Shl I have explained before, it is where all the bits in a register are
shifted one to the left and a zero added on to the right. This is the
eqivalent of multiplying the value by two. Shr works in the opposite
direction.

Rol does the same, except that the bit that is removed from the left is
replaced on the right hand side. Ror works in the opposite direction.

div <value> divides the value in ax by value and returns the result in
al if value is a byte, placing the remainder in ah. If value is a word,
the double word DX:AX is divided by value, the result being placed in ax
and the remainder in dx. Note that this only works for unsigned values.

idiv <value> does the same as above, but for signed variables.

mul <value>  If value is a byte, al is multiplied by value and the result
is stored in ax. If value is a word, ax is multiplied by value and the
result is stored in the double word DX:AX

imul <value> does the same as above, but for signed variables.

The j* commands are fairly simple : if a condition is met, jump to a certain
lable.

jz  <label>   Jump if zero
ja  <label>   Jump above     (unsigned)
jg  <label>   Jump greater   (signed)

and so forth.

An example ...

cmp  ax,50    ; Compare ax to 50
je   @Equal   ; If they are equal, jump to label @equal

call MyProc   Runs procedure MyProc and then returns to the next line of code.

Procedures are declared as follows :

MyProc   proc near
           ret    ; Must be here to return from where it was called
MyProc   endp

Variables are also easy :

bob  db 50

creates a variable bob, a byte, with an initial value of 50.

bob2 dw 50

creates a variable bob2, a word, with an initial value of 50.

bob3 db 1,2,3,4,5,65,23

creates bob3, an array of 7 bytes.

bob4 db 100 dup (?)

creates bob4, an array of 100 bytes, with no starting value.

Go back and look at tut 7 for a whole lot more assembler commands, and get
some sort of reference guide to help you out with others. I personally use
the Norton Guides help file to program assembler.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Fire Routines

To demonstrate how to write an assembler program, we will write a fire
routine in 100% assembler. The theory is simple...

Set the pallette to go from white to yellow to red to blue to black.
Create a 2d array representing the screen on the computer.
Place high values at the bottom of the array (screen)
for each element, do the following :
  Take the average of the four elements under it

                         * Current element
                        123
                         4  Other elements
  Get the average of the four elements, and place the result in the current
  element.
Repeat

Easy, no? I first saw a fire routine in the Iguana demo, and I just had to
do one ;) ... it looks very effective.

With the sample file, I have created a batch file, make.bat ... it basically
says :
        tasm fire
        tlink fire

So to build and run the fire program, type :
make
fire

The source file is commented quite well, so there shouldn't be any problems.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

As you can see, the sample program is in 100% assembler. For the next tut
I will return to Pascal, and hopefully your new found assembler skills will
help you there too.



Byeeeee....
  - Denthor

The following are official ASPHYXIA distribution sites :

???????????????????????????????????????????????????
?BBS Name                  ?Telephone No.   ?Open ?
???????????????????????????????????????????????????
?ASPHYXIA BBS #1           ?+27-31-765-5312 ?ALL  ?
?ASPHYXIA BBS #2           ?+27-31-765-6293 ?ALL  ?
?C-Spam BBS                ?410-531-5886    ?ALL  ?
?POP!                      ?+27-12-661-1257 ?ALL  ?
?Soul Asylum               ?+358-0-5055041  ?ALL  ?
?Wasted Image              ?407-838-4525    ?ALL  ?
?Reckless Life             ?351-01-716 67 58?ALL  ?
?Mach 5 BBS                ?+1 319-355-7336 ?ALL  ?
?House of Horror           ?+1 513-734-6470 ?ALL  ?
?Zero Level                ?+39 6-810-9934  ?ALL  ?
???????????????????????????????????????????????????

Leave me mail if you want to become an official Asphyxia BBS
distribution site.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 20 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi all! It has been a _long_ time since my last trainer (as I am sure many
of you have noticed) A lot has happened between now and the last trainer...
but for once I won't bore you with the details ;) I do have a full time job
though, coding C++ applications.

I have taken over the production of the PCGPE from Mark Feldman. He is
mailing all the articles written so far, and as soon as I get them I will
get to work on releasing the PCGPE II. Mark is working on the Windows GPE.

This trainer is on 3d hidden face removal and face sorting. I was going to
add shading, but that can wait until a later trainer. For conveniance I
will build on the 3d code from tut 16(?). The maths for face removal is a
bit tricky, but just think back to your old High School trig classes.

I have noticed that in my absence, one or two people have started their own
trainer series. Read Hornet DemoNews for a great column by Trixter covering
some of the more tricky demo effects.

Well, on with the trainer!


If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during varsity). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

NB : If you are a representative of a company or BBS, and want ASPHYXIA
       to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
        quite lonely and want to meet/help out/exchange code with other demo
        groups. What do you have to lose? Leave a message here and we can work
        out how to transfer it. We really want to hear from you!

http://goth.vironix.co.za/~denthor                     (WWW)
ftp.eng.ufl.edu pub/msdos/demos/code/graph/tutor       (FTP)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Face Sorting

There are many ways to sort faces in a 3d object. For now, I will show you
just about the easiest one of the lot.

Say you have to polygons....

                ------P1

           ------------------P2

                   Eye

As you can see, P1 has to be drawn before P2. The easiest way to do this is
as follows:

On startup, find the mid point of each of the polys, through the easy
equations,
        x = (P2.1.x + P2.2.x + P2.3.x + p2.4.x)/4
        y = (P2.1.y + P2.2.y + P2.3.y + p2.4.y)/4
        z = (P2.1.z + P2.2.z + P2.3.z + p2.4.z)/4

NOTE : For a triangle you would obviously only use three points and divide
by three.

Anyway, now you have the X,Y,Z of the midpoint of the polygon. You can then
rotate this point with the others. When it comes time to draw, you can
compare the resulting Z of the midpoint, sort all of the Z items, and then
draw them from back to front.

In the sample program I use a simple bubble sort... basically, I check the
first two values against each other, and swap them if the first is bigger
then the second. I continue doing this to all the numbers until I run
through the entire list without swapping once. Bubble sorts are standard
seven computer science topics... perhaps borrow a text book to find out
more about them and other (better) sorting methods.

The above isn't perfect, but it should work 90% of the time. But it still
means that when you are drawing a cube, you have to draw all 6 sides every
frame, even though only three or so are visible. That is where hidden face
removal comes in...

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Hidden Face Removal

Pick up something square. A stiffy disk will do fine. Face it towards you,
and number all the corners from one to four in a clockwise direction.

                1 +-------------+ 2
                  |             |
                  |             |
                  |             |
                  |             |
                4 +-------------+ 3

Now rotate the stiffy disk on all three axese, making sure that you can
still see the front of the disk. You will notice that whenever you can see
the front of the disk, the four points are still in alphabetical order. Now
rotate it so that you can see the back of the stiffy. Your points will now
be :

                2 +-------------+ 1
                  |             |
                  |             |
                  |             |
                  |             |
                3 +-------------+ 4

The points are now anti-clockwise! This means, in it's simplest form, that
if you define all your poygon points in a clockwise order, when drawing you
ignore the polys that are anticlockwise. (Obviously when you define the 3d
object, you define the polygons facing away from you in an anticlockwise
order)

To find out weather a poly's points are clockwise or not, we need to find
it's normal. Here is where things start getting fun.

In school, you are told that a normal is perpendicular to the plane. In
ascii :
                      | Normal
                      |
                      |
        --------------------------- Polygon

As you can see, the normal is at 90 degrees to the surface of the poly. We
must extend this to three dimensions for our polygons. You'll have to trust
me on that, I can't draw it in ascii :)

To find a normal, you only need three points from your poly (ABC) :
A(x0,y0,z0), B(X1,Y1,Z1), C(X2,Y2,Z2)

then the vector normal = AB^AC = (Xn,Yn,Zn) with
        Xn=(y1-y0)(z0-z2)-(z1-z0)(y0-y2)
        Yn=(z1-z0)(x0-x2)-(x1-x0)(z0-z2)
        Zn=(x1-x0)(y0-y2)-(y1-y0)(x0-x2)

We are interested in the Z normal, so we will use the function :
  normal:=(x1-x0)(y0-y2)-(y1-y0)(x0-x2);

The result is something of a sine wave when you rotate the poly in three
dimensions. A negative value means that the poly is facing you, a posotive
value means that it is pointing away.

The above means that with a mere two muls you can discount an entire poly
and not draw it. This method is perfect for "closed" objects such as cubes
etc.

I am anything but a maths teacher, so go borrow someones math book to find
out more about surface normals. Trust me, there is a lot more written about
them then you think.

An extension of calculating your normal is finding out about light-sourcing
your polygons. Watch for more information in one of the next few tutors.


A combination of the above two routines should work quite nicely in
creating 3d objects with little or no overlapping. The example file will
show you the two methods and how well they work.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

As you can see, the above was quite easy. I have a few ideas for tut 21, so
keep watch for it. Also keep an eye open for PCGPE ][ (but don't mail me
asking when it's due! I already get too many of those! ;-)

My sister got married a few days ago. The worst part was that I was forced
to cut my hair. My hair was quite long (slightly longer then when the pic
on my web page was taken), and it is all quite depressing. Anyway, the
wedding was great, so it wasn't all for nothing.

I hope to get tut 21 and possibly 22 out before christmas, but I will be on
holiday from the 18th. I will be in Cape Town sometime after christmas day
for a week or two, so if you're there I'll meet you on the cable car :-)

I wrote a quote for this tut, but I have decided I didn't like it. I'll try
do better for tut 21 ;)

Byeeeee.....
  - Denthor
      14-12-95

PS. I seem to have lost my list of distribution sites... could you all
re-mail me your details? Thanks.
                   ?????????????????????????????????
                   ?         W E L C O M E         ?
                   ?  To the VGA Trainer Program   ? ?
                   ?              By               ? ?
                   ?      DENTHOR of ASPHYXIA      ? ? ?
                   ????????????????????????????????? ? ?
                     ????????????????????????????????? ?
                       ?????????????????????????????????

                           --==[ PART 21 ]==--



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
? Introduction

Hi there! It's been quite a long time (again) since the last tutorial ...
I'll bet some of you had given up one me ;-)

Today is my 21st birthday, so I decided it would be the perfect time to
finish up this trainer which I have been meaning to send out for weeks.
It's on texure mapping. I know, I know, I said light sourcing, then gourad,
then texture mapping, but I got enough mail (a deluge in fact ;) telling me
to do texure mapping...

I'll be using the code from Tut 20 quite extensively, so make sure you know
whats going on in there... well, on with the show!

BTW, I've improved my web page quite a bit... give it a visit, I want to
really ramp up that hit count :)

If you would like to contact me, or the team, there are many ways you
can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                  on the ASPHYXIA BBS.
            2) Write to :  Grant Smith
                           P.O.Box 270 Kloof
                           3640
                           Natal
                           South Africa
            3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                  call during work hours). Call +27-31-73-2129 if you call
                  from outside South Africa. (It's YOUR phone bill ;-))
            4) Write to denthor@goth.vironix.co.za in E-Mail.
            5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
               us at once.

http://www.vironix.co.za/~grants                       (WWW)
ftp.eng.ufl.edu pub/msdos/demos/code/graph/tutor       (FTP)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  Free Direction Texture Mapping

There are two things you should know before we begin.

Firstly, I am cheating. The texture mapping I am going to show you is not
perspective-correct, with clever divides for z-placement etc. This method
looks almost as good and is quite a bit faster too.

Secondly, you will find it all rather easy. The reason for this is that it's
all rather simple. I first made the routine by sitting down with some paper
and a pencil and had it on the machine in a few hours. A while later when
people on the net started discussing their methods, they were remarkably
similar.

Let me show you what I mean.

Let us assume you have a texture of 128x128 (a straight array of bytes
[0..127, 0..127]) which you want to map onto the side of a polygon. The
problem of course being that the polygon can be all over the place, with
one side longer then the other etc.

Our first step is to make sure we know which end is up... let me
demonstrate...
                      1
                    +
                 /    \
              /         \
          4 +            +  2
              \        /
                \   /
                  +
                  3

Let us say that the above is the chosen polygon. We have decided that point
1 is the top left, point 3 is bottom right. This means that
  1 - 2   is the top of the texture
  2 - 3   is the right of the texture
  3 - 4   is the bottom of the texture
  4 - 1   is the left of the texture

The same polygon, but rotated :

                      3
                    +
                 /    \
              /         \
          2 +            +  4
              \        /
                \   /
                  +
                  1

Although the positions of the points are different, point 1 is still the
top left of our texture.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  How to put it to screen

Okay, so now you have four points and know which one of them is also the top
left of our texture. What next?

If you think back to our tutorial on polygons, you will remember we draw it
scanline by scanline. We do texture mapping the same way.

Lets look at that picture again :

                      1
                    +
               a /    \  b
              /         \
          4 +            +  2
              \        /
                \   /
                  +
                  3

We know that point 1 is at [0,0] in our texture. Point 2 is at [127,0],
Point 3 is at [127,127], and Point 4 is at [0,127].

The clever bit, and the entire key to texture mapping, is making the
logical leap that precisely half way between Point 1 and Point 2 (b), we are at
[64,0] in our texture. (a) is in the same manner at [0,64].

That's it. All we need to know per y scanline is :
The starting position on the x axis of the polgon line
The position on the x in the texture map referenced by that point
The position on the y in the texture map referenced by that point

The ending position on the x axis of the polgon line
The position on the x in the texture map referenced by that point
The position on the y in the texture map referenced by that point

Let me give you an example. Let's sat that (a) and (b) from the above
picture are on the same y scanline. We know that the x of that scanline is
(say) 100 pixels at the start and 200 pixels at the end, making it's width
100 pixels.

We know that on the left hand side, the texture is at [0,64], and at the
right hand side, the texture is at [64,0]. In 100 pixels we have to
traverse our texture from [0,64] to [64,0].

Assume at the start we have figured out the starting and ending points in
the texture
  textureX = 0;
  textureY = 64;
  textureEndX = 64;
  textureEndY = 0;

  dx := (TextureEndX-TextureX)/(maxx-minx);
  dy := (TextureEndY-TextureY)/(maxx-minx);
  for loop1 := minx to maxx do BEGIN
    PutPixel (loop1, ypos, texture [textureX, textureY], VGA);
    textureX = textureX + dx;
    textureY = textureY + dy;
  END;


Do the above for all the scanlines, and you have a texture mapped polygon!
It's that simple.

We find our beginning and ending positions in the usual fasion. We know
that Point 1 is [0,0]. We know that Point 2 is [127,0]. We know the number
of scanlines on the y axis between Point 1 and Point 2.

  textureDX = 127/abs (point2.y - point1.y)

We run though all the y scanlines, starting from [0,0] and adding the above
formula to the X every time. When we hit the last scanline, we will be at
point [127,0] in the texure.

Repeat for all four sides, and you have the six needed variables per
scanline.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
?  In closing

As you can see, texture mapping (this type at least) is quite easy, and
produces quite a good result. You will however notice a bit of distortion
if you bring the polygon too close. This can be fixed by a) Subdividing the
polygon, so the one is made up of four or more smaller polygons. Much
bigger, but works; b) Using more accurate fixed point; or c) Figuring out
perspective correct texture mapping, mapping along constant-z lines etc.

When people write me, they often refer to my "tutes". This stems back to
Mark Feldman calling them such in the PCGPE. I always though a "tute" was
something you did with your car to gain someones attention. I dunno, maybe
its an Australian thing ;-)

I have been coding almost exclusively in C/C++ for the past year or so.
Sorry guys, thats all they will pay me for ;) Anyway, the trainers will
continue to be in Pascal for ease of understanding by beginners, but if
someone (*ahem* Snowman) doesn't start converting them to C soon, I will do
it myself. He also corrected any mistakes I made while he was converting,
so I'd prefer he did it (sort of a proofreader after release...)

Send me presents! It's my birthday!

Byeeeee.....
  - Denthor
      16-04-96