Spellcaster presents:


TTTTTTTTTT HH      HH EEEEEEEEEE    MM      MM    AAAA     GGGGGGGGG
    TT     HH      HH EE            MMM    MMM   AA  AA   GG
    TT     HH      HH EE            MM M  M MM  AA    AA  GG  
    TT     HHHHHHHHHH EEEEEE        MM  MM  MM  AAAAAAAA  GG   
    TT     HH      HH EE            MM      MM  AA    AA  GG    GGGG
    TT     HH      HH EE            MM      MM  AA    AA  GG      GG
    TT     HH      HH EEEEEEEEEE    MM      MM  AA    AA   GGGGGGGG

                                                        Issue 3
                                                        4-10-95



 Index

        1. Introduction
          1.1. About the magazine
          1.2. About the author
          1.3. Distribution
          1.4. Contribuitions
          1.5. Hellos and greets
        2. Resolution of your homework
        3. Procedures and functions
          3.1. What are they ?
          3.2. How to use
          3.3. Global and local variables
          3.4. Parameters
          3.5. Functions
        4. Introduction to assembly
          4.1. Segments and offsets
          4.2. Registers
          4.3. The stack
          4.4. The flags
          4.5. More about segments
          4.6. Basic instructions
        5. Graphics, part 2 : The palette
          5.1. Introduction
          5.2. What's the palette
          5.3. How to set and get the palette ?
          5.4. The retrace
          5.5. Palette effects
              5.5.1. Rotations
              5.5.2. Fades
              5.5.3. The static screen
        6. Points of View
        7. The adventures of Spellcaster, part 3.


 Introduction

   About the magazine

    So, we've finally reached issue 3... A small step to me, but a great step
  to computerkind...
    This issue is packed with information... We have the second part of our
  mode 13h tutorial (dedicated to palettes), plus an article on procedures and
  functions for the begginers out there, besides other stuff.
    This issue also has a special bonus... You probably have noticed that when
  you decompress 'The Mag', you don't get only this text file, but a lot of
  other files... They are a part of a small demo I did in two days, especially
  for the mag. To run the demo, type in 'CBLIND' at the DOS prompt. I made it
  to acompany this week's mode 13h tutorial, to demonstrate the potencial of the
  palette, and the wonderfull effects you can achieve with it, if you think for
  a bit... The hardest thing to do in the demo was to think of the effects.
  Coding them is easy (except the cross-fade). The effects will be explained in
  the Graphics section of 'The Mag'.
    This magazine is dedicated to all the programmers and would-be programmers
  out there, to those who wish to learn how to program anything, from demos
  to games, passing through utilities and all sort of thing your mind can
  think of.

    When you read this magazine, I'll assume some things. First, I assume you
  have Borland's Turbo Pascal, version 6 and upwards. I'll also think you have
  a 80386 (or 386 for short; a 486 would be even better), a load of patience
  and a sense of humor. This last is almost essencial, because I don't receive
  any money for doing this, so I must have fun doing it. I will also take for
  certain you have the 9th grade (or equivelent).

    As I stated above, this magazine will be made especially for those who don't
  know where to get information, or want it all in the same place, and to those
  who want to learn how to program, so I'll try to build knowledge, building up
  your skills issue by issue. If you sometimes fail to grasp some concept, don't
  despair; try to work it out.
    That's what I did... Almost everything I know was learnt from painfull
  experience. If you re-re-re-read the article, and still can't understand it,
  just drop a line, by mail, or just plain forget it. Most of the things I 
  try to teach here aren't linked to each other (unless I say so), so if you
  don't understand something, skip it and go back to it some weeks later. It
  should be clearer for you then. Likewise, if you see any terms or words you 
  don't understand, follow the same measures as before.

    Ok, as I'm earing the Net gurus and other god-like creatures talking
  already, I'm just going to explain why I use Pascal.
  For starters, Pascal is a very good language, ideal for the beginner, like 
  BASIC (yech!), but it's powerfull enough to make top-notch programms.
  Also, I'll will be using assembly language in later issues, and Pascal makes
  it so EASY to use. 
  Finally, if you don't like my choice of language, you can stop whining. The
  teory behind each article is very simple, and common with any of the main
  languages (C, C++, Assembly - Yes, that's true... BASIC isn't a decent
  language).

    Just one last thing... The final part of the magazine is a little story
  made up by my distorted mind. It's just a little humor I like to write, and
  it hasn't got nothing to do with programming (well, it has a little), but, 
  as I said before, I just like to write it.

   About the author

    Ok, so I'm a little egocentric, but tell me... If you had the trouble of 
  writing hundreds of lines, wouldn't you like someone to know you, even by 
  name ?

    My name is Diogo de Andrade, alias Spellcaster, and I'm the creator, 
  editor and writer of this magazine. 
    I live in a small town called Setbal, just near Lisbon, the capital of
  Portugal... If you don't know where it is, get an encyclopedia, and look for
  Europe. Then, look for Spain. Next to it, there's Portugal, and Setbal is in
  the middle.

    I'm 18 years old, and I just made it in to the university (if you do want
  to know, I'm in the Technical Institute of Lisbon, Portugal), so I'm not 
  a God-Like creature, with dozens of years of practice (I only program by 
  eight years now, and I started in a Spectrum, progressing later to an Amiga.
  I only program in the PC for a year or so), with a mega-computer (I own a 
  386SX, 16 Mhz), that wear glasses with lens that look like the bottom of a 
  bottle (I use glasses, but only sometimes), that has his head bigger than a 
  pumpkin (I have a normal sized head) and with an IQ of over 220 (mine is 
  actually something like 180). I can program in C, C++, Pascal, Assembly 
  and even BASIC (yech!).

    So, if I am a normal person, why do I spend time writing this ?
  Well, because I have the insane urge to write thousands of words every now
  and then, and while I'm at it, I may do something productive, like teaching
  someone. I may be young, but I know a lot about computers (how humble I am;
  I know, modesty isn't one of my qualities).

    Just one more thing, if you ever program anything, please send to me... I
  would love to see some work you got, maybe I even could learn something with
  it. Also, give me a greet in your program/game/demo... I love seeing my 
  name.

   Contributions

    I as I stated before, I'm not a God... I do make mistakes, and I don't 
  have (always) the best way of doing things. So, if you think you've spotted
  an error, or you have thought of a better way of doing things, let me know.
  I'll be happy to receive anything, even if it is just mail saying 'Keep it 
  up'. As all human beings, I need incentive.

    Also, if you do like to write, please do... Send in articles, they will be
  welcome, and you will have the chance to see your names up in lights.
    They can be about anything, for a review of a book or program that can
  help a programmer, to a point of view or a moan.

    If anyone out there has a question or wants to see an article about 
  something in particular, feel free to write... All letters will be answered,
  provided you give me your address.

    I'm also trying to start a new demo/game/utility group, and I need all sort 
  of people, from coders (sometimes, one isn't enough), musicians (I can 
  compose, but I'm a bit limited), graphics artists (I can't draw nothing) and
  spreaders... I mean, by a spreader, someone who spreads things, like this mag.
  If you have a BBS and you want it to include this magazine, feel free to
  write me...

    You can also contact me personally, if study on the IST (if you don't
  know what the IST is, you don't study there). I'm the freshman with the 
  black hair and dark-brown eyes... Yes, the one that is occupying one of
  the X-terminals... I recommend you to contact me personally, if you can,
  especially if you are a member of the opposite sex (I'm a man, for those
  of you who are wondering).

    My adress is:
                 Praceta Carlos Manito Torres, n4/6C
                 2900 Setbal
                 Portugal

    Email: dgan@rnl.ist.utl


   Hellos and greets

    I'll say hellos and thanks to all my friend, especially for those who put 
  up with my constant whining (you know who you are).
    Special greets go to Denthor from Asphyxia (for the excelent VGA trainers),
  Draeden from VLA (for assembly tutorials), Joaquim Elder Guerreiro, alias
  Dr.Shadow (Delta Team is still up), Alex "Darkfox" (thanks for letting me
  use your BBS), Joo Neves and Henrique Craveiro for sugestions, and all the
  demo groups out there.
    I also want to say hi to my idols (I know they don't read this, but...),
  Chris Roberts, Franois Lionet, Archer MacLean, everybody at ID Software and
  Apogee, Sierra On-Line, Lucas Arts and Team 17, for showing me what 
  programming is all about.




 Resolution of your homework

    In last issue, I chalenged you to make an improvement in the 'Maths'
  program I gave in Issue 1. Well, here's one of the possible improvements.
  This gives you the hability to choose the operation you want to execute.

  Program Maths(Input,Output);

  Var A,B:Integer;
      C,OP:Integer;

  Begin
       Writeln('The Maths Version 2.0');
       writeln;
       Writeln('1 - Add');
       Writeln('2 - Subract');
       Writeln('3 - Multiply');
       Writeln('4 - Divide');
       Writeln('5 - Remainder');
       Writeln;
       Write('Type in the number of the operation:');
       Readln(OP);
       Write('Type in number A : ');
       Readln(A);
       Write('Type in number B : ');
       Readln(B);
       If OP=1 Then C:=A+B;
       If OP=2 Then C:=A-B;
       If OP=3 Then C:=A*B;
       If OP=4 Then C:=A Div B;
       If OP=5 Then C:=A Mod B;
       Writeln;
       Writeln('The result is ',C);
       Writeln;
       Readln;
  End.

    This is quite simple... Depending on what operation you type in, the
  program executes the relevant calculation and prints out the result.
    There is still room from improvement in the program, but I leave to you
  decide what to do. You already know, if you have questions, mail them to me
  and I will answear them, or by mail or by the magazine.



 Procedures and functions

    These are two of the more powerfull of Pascal's resources. These give you
  the hability to create new commands and functions. They are almost identical
  in the way they work, so I will explain deeply the procedure and then I will
  pass to the function, teaching you the diferences.

   What are they ?

    Think of procedures like new commands, defined by you to do whatever you
  want. They are very usefull, as you will see. Let's say you have a program
  that writes the string 'Ok !' lots of time, and you don't want to spend time
  always writing "WRITELN('OK !')", what do you do? You use a procedure !!

   How to use

    In the above example, you would do something like this: before the start of
  the main program block, write this:

  Procedure Writeok;
  Begin
       Writeln('Ok !');
  End;

    Then, everytime you would write "Writeok" in your program, the program would
  write 'OK !' in the screen. Let's see a working example:

  Program Test_8;

  Procedure Writeok;
  Begin
       Writeln('Ok !');
  End;

  Begin
       Writeln('How are you ?');
       Writeok;
       Readln;
  End.

    The above example is stupid, but it's just for you to get the picture.
  Notice that you can do ANYTHING you want in a procedure, just like in the
  main block. You can even call other procedures from it. A procedure is like
  an independant program, with it's one set of instructions and variables...

   Local and global variables

    The procedure can have it's own variables, independants from the main
  program. Look at the next example:

  Program Test_9;

  Var B:Integer;

  Procedure Something;
  Var B:Word;
  Begin
       B:=10;
       Writeln('In the procedure, B=',B);
  End;

  Begin
       B:=5;
       Something;
       Writeln('In the main program, B=',B);
       Readln;
  End.

    See what I mean? The main program ignores the changes made to variable B
  inside the procedure. The variable B of the procedure is diferent of variable
  B in the main program.
    So, you come to a new concept. The variables defined outside the procedures
  are called GLOBAL VARIABLES, and those who are created inside of a procedure
  are called LOCAL VARIABLES.
    The diference between them is that global variables can be used in all
  program, not just in the main block, but in all procedures and functions,
  while local variables can only be used inside the place they are defined.

   Parameters

    Imagine now that you wanted to make a procedure to do a complex calculation
  between the numbers 5 and 7. You would now use something that is called
  PARAMETERS. They are used like this:

  Procedure DoCalc(A,B:Integer);
  Var C:Integer;
  Begin
       C:=A+B*B;
       Writeln('The result is ',C);
  End;

    Now, you called the procedure like this:

             DoCalc(5,7);

    This works like this. The var A would get the value 5, and var B would get
  the value 7. Then, the procedure's main code would be executed and the result
  would be printed to the screen.
    A parameter can be anything, from a number to a string. You can even have
  different types of parameters, like this:

  Procedure Print(X,Y:Byte;S:String);

    You just use a semi-colon between them.
    I know this is a little confusing at first, because you're dealing with new
  concepts, but after you master this, you will get a priceless resource.

   Functions

    The function is defined in the same way as the procedure, except that you
  use the keyword FUNCTION instead of the PROCEDURE keyword. They work the same
  way, but they have a diference. The function returns a value. This can be a
  number, a char or even a string. The sintax is a little diferent, because of
  this:

  Function DoCalc(A,B:Integer):Integer;     { This defines function DoCalc, }
                                            { that requires two integers as }
                                            { parameters, and that returns  }
                                            { and integer value }
  Var C:Integer;                            { Defines local variable C      }
  Begin
       C:=A+B*B;                            { This executes the calculation }
                                            { and places the result in C    }
       DoCalc:=C;                           { This tells the function to    }
                                            { return the value in C.        }
  End;

    Do call this, you would do something like this:

       D:=DoCalc(5,7);       { D is a global variable, defined as an integer }
       Writeln(D);

       or

       Writeln(DoCalc(5,7);  { This saves a variable }

    There isn't a rule for what to use, procedure or function. It depends on
  the program you are making. You can mix them up, having a procedure that calls
  a function or vice-versa. You can even call a procedure with a function as a
  parameter.

    There's a lot I haven't told you about procedures and functions, but I will
  leave that for a future issue. In next issue I will talk about loops and
  cicles. These are an almost essencial part of a program.




 Introduction to assembly

    Somebody requested me to do an article about assembly, so here it is. This
  is a very simplistic view of it, but it should be enough to make you start
  coding some simple routines in Pascal with assembly.
    Don't forget that assembly language is very complicated, and only people
  that had a previous programming experience with some kind of high-level
  language should try to venture themselves in it.
    In the previous issue I explained some simple concepts of assembler, things
  like the what is the BIOS, interrupts and other things like that. I even
  explained how Pascal works with assembly. In the first issue, I explained
  what are bytes and bits and their relatives, so I will assume you already
  know that. So, without further due, I will talk about...

   Segments and offsets

    This is the more annoying and complicated thing on the PC. Back in the time
  when dinossaurs ruled the Earth, the guys that designed the original 8088
  thought that nobody would ever need to address more than a meg (short for
  megabyte) of memory, so they decided to built a machine that couldn't access
  more than one meg of memory. But, for addressing one meg of memory, there was
  the need for a 20 bit number. Because this wasn't pratical, they've came up
  with a 'brilliant' way to do it. They would use two 16 bit registers. I know
  this adds up to a 32 bit number, but that's not the way it works. It works
  like this:

  Segment        0010100010001001
  Offset             0010101010100101

  20 bit adress: 00101011001100110101 !!!!

    Here you have it... Segments and offsets combine to produce an absolute
  address of memory. The standart notation for the memory addresses is:

                         Segment:Offset

    So, if somebody says that somethings in the address 6F1A:3652, that means
  that it is in the segment 6F1A (in hex, of course), offset 3652 (still in
  hex). Think of segments and offsets like this. The segment is the number of
  the page, and the offset is how far in the page the data is...
    Now, that you know what segments and offsets are, I can move on to...

   Registers

    Registers are a special kind of variables, that are available to the
  processor. They perform various functions inside the CPU, and they are a very
  important part of assembly language. A list of their names, alongside with
  their uses follows:

         AX

          AX (also called the accumulator) is a general purpose 16 bit register.
          It can be acessed as a word, or as two bytes, using AL or AH (the low
          and the high part).
          Examples:
                   AX=10  =>   AL=10
                               AH=0

                   AX=256 =>   AL=1
                               AH=1

          General rule, anything you do to AL or AH will influence AX, because
          you're manipulating it's low and high bytes.
          Before I forget: AX = AH * 256 + AL
          Do you understand it ?
          AX has some special uses. General rule it is the destination for
          memory grabs and multiplications. It's also plays a big part in port
          accessing.

         BX (BH/BL)

          BX is just like AX... You can also access its lower and higher bytes.
          BX's special use is usually as an offset register.

         CX (CH/CL)

          CX is just like AX and BX.
          It is used as a counter in loops.

         DX (DH/DL)

          DX is like AX, BX and CX.
          It is used as destination is calculations and as a port index.

         DI

          DI is a index register, a 16 bit register that is used for offsets.
          You can't access it's higher and lower bytes.

         SI

          Same as DI, but usually DI is paired with the ES segment register,
          while SI is paired with the DS register.

         DS

          This is a segment register, and it usually points to the Data Segment.

         ES

          This is a segment register, that points to the Extra Segment.

         FS

          This is like ES, but it only exists in the 386+.

         GS

          Same as FS.

        The next registers you SHOULDN'T mess, unless you want your computer to
        crash.

         BP

          Base pointer. This is an offset to use with the Stack Segment.

         SP

          Stack pointer. This is an offset to use with the Stack Segment.

         SS

          This is a segment register, that points to the Stack Segment.

         CS

          This is a segment register, that points to the Code Segment.

         IP

          This is the Intruction Pointer, that is used with CS.


   The stack

    The stack is a temporary storage place, where data doesn't stay for long.
  It has the same principle of a stack of plates, except that the stack starts
  in the roof. This follows the order first in, last out, so, you must take the
  things in the reverse order that you put them in.
    I know this is confusing, but after some examples, you will feal right at
  home.


   The flags

    The flags are like status indicators. They have all sort of indications for
  you to read and interpret. They only have the value true or false, and you
  can't access them directly.
    There are 17 flags, but you only have to know some of them:

         Carry Flag (CF)

          The carry flag is used for many things. It's like a general purpose
          flag. It is one of the more used flags.

         Parity Flag (PF)

          This flag is active when the value returned from last operation is
          even.

         Zero Flag (ZF)

          This flag is set when the last operation returned a zero.

         Overflow Flag (OF)

          This flag is set when the last operation went out of bounds.

    These are the ones mostly used. There are others, as stated before, but
  they aren't very used.

   More about segments

    In pure assembly, you can define the segmentation of your program, but has
  we are using assembly with Pascal, we must use the Pascal's default
  segmentation, that is called Dos Segmentation. This means that there are four
  principal segments. There are addressed by CS, SS, DS, ES. They are called
  Code Segment, Stack Segment, Data Segment and Extra Segment.

         Code Segment

          This is where your program resides. You probably now already that a
          segment can only have 64Kb of size, so you only get 64Kb for the code
          of your program. Now figure out why is it dangerous to change the CS
          register.
          One more thing about the CS register. It pairs up with the IP register
          to give the computer the address of the current instruction.

         Stack Segment

          This is the place of the stack.

         Data Segment

          This is where the data normally goes... It can go to other places,
          using pointers, but that's another story.

         Extra Segment

          An extra segment for data.

   Basic instructions

    Next, it follows a list of the essencial assembly instructions, the ones
    you should know from back to forth.

         Mov

          This is the single more important instruction in Asm (short for
          assembly). The sintax is:

                         Mov to,from

          The to and from parameters can be almost anything you want. Let's
          show some examples:

          Mov AX,40         This puts the imediate value 40 in AX
          Mov AL,20         This puts the imediate value 20 in AL
          Mov DH,10         This puts the imediate value 10 in DH
          Mov CX,BX         This puts what's in BX in CX
          Mov AX,[DS:SI]    This puts the word that is at DS:SI in AX
          Mov [ES:DI],BX    This puts what's in BX in ES:DI
          Mov [ES:DI+5],CX  This puts what's in CX in ES:DI+5
          Mov DX,[x]        This puts what's in var x in DX

          This is easy enough.


         Int

          I already talked about this command in last issue. This command calls
          up an interrupt. Sintax:

                           Int n

          Examples:
                           Int 10h      This calls interrupt 10 (in hex)
                           Int 10       This calls interrupt 10 (in dec)


         Stosb

          This stores what's in AL in destination ES:DI, and then increments
          DI by one. It hasn't got any parameters.

         Stosw

          Just like Stosb, but is transfers whats in AX and increments Di by
          two.

         Movsb

          This moves the byte that is in DS:SI to ES:DI, and then increments
          SI and DI by one.

         Movsw

          This moves the word as DS:SI to ES:DI, and then increments SI and DI
          by two.

         Add

          Sintax:
                        Add dest,source

          This adds source to dest and stores the result in dest. Dest can't be
          and imediate value, as obvious.

         Sub

          Sintax:
                        Sub dest,source

          This subtracts source from dest and stores the result in dest.

         Mul

          Sintax:
                        Mul source

          This multiplies source by AX (if source is a word) or by AL (if
          source is a byte). The result is stored in AX (if source is a byte)
          or in DX:AX (if source is a word).

         Push

          This pushes something onto the stack. The sintax is:

                        Push source

          Source can be a register or an immediate value.

         Pop

          This takes off something off the stack. The sintax is:

                        Pop dest

          Dest is where you want to put the value you take.
          Remember what I said about first in, last out ?
          Take a look at these examples:

               Mov ax,5                 AX=5
               Push ax                  Puts AX in the stack
               Mov ax,10                AX=10
               Pop ax                   Takes the last value put in the stack,
                                        in this case, AX=5

               Mov ax,10
               Mov bx,5
               Push ax
               Push bx       This piece of code would swap the values of AX and
               Pop ax        BX. Because first in is the last out.
               Pop bx

    So, that's about it... There's lots of other things, but this should cover
    up the basic. Get some source codes and experiment with them. If you have
    any doubts, drop me a line and I'll try to explain myself better. If you
    want some source code, feel free to ask me some...



 Graphics, part II : Palettes

     Introduction

      The palette is a mistery to most programmers, even professional ones, and
    often overlooked as beeing not too important. But I'm of those who think
    that the palette and effects derived from it have a great potencial. To see
    what I'm saying, just execute the 'Color Blind' demo I made especially for
    the magazine. I made it in a couple of days, and I think it's fairly good,
    considering that it pratically just uses the palette.

     What's the palette

      A palette is a place where colors are stored. Has you should already now,
    the mode 13h palette has 256 colors. Each one has a number, ranging from 0
    to 255, and an intensity value for each of it's components.
      In the PC, as in real life, colors are the result of the mixture of
    primary colors. You should have learned about it in the 5th grade. But, in
    real life, the primary colors are blue, yellow, magenta, black and white.
    In computerland, there are only three basic colors: red, green and blue.
    Each one of them can be mixed together in diferent ammounts.
      But (there's always a but everywhere), NEVER forget that two colors can
    look just the same in the screen and be completely different. Also, don't
    forget that when you alter the palette, all the pixels in the screen drawn
    with that color will be changed. For example, imagine you just set color 53
    and 80 with the same RGB (short for red,green and blue components), and
    filled the screen with pixels color 53 and 80. Well, when you looked at the
    screen, it would look like it was filled with the same color, but when you
    changed color 80, the entire screen would change the look entirely.

     How to set and get the palette

      This is easy. You just have to remember that everything concerning the
    palette is done through the ports 3C7h, 3C8h and 3C8h.
      So, let's get the palette of a specific color. All you have to do is to
    enter the number of the color you want into port 3C7h and then read in the
    values of the red, green and blue components from port 3C9h. For acessing
    the ports, you use a Pascal defined array that is called PORT. It is
    something like the MEM array. The sintax is:

                   Port[number of the port]

      So, a procedure to read in the RGB values of one color would be like
    this:

      Procedure GetColor(Col:Byte;Var R,G,B:Byte);
      Begin
           Port[$3C7]:=Col;
           R:=Port[$3C9];
           G:=Port[$3C9];
           B:=Port[$3C9];
      End;

      To set the palette, it's almost the same... You put the number of the
    color you want to change into port 3C8h and then put the values in port
    3C9h, in the order red, green and blue. Remember that the intensity is a
    number from 0 to 63.

      Procedure SetColor(Col,R,B,G:Byte);
      Begin
           Port[$3C8]:=Col;
           Port[$3C9]:=R;
           Port[$3C9]:=G;
           Port[$3C9]:=B;
      End;

      This is very easy, tough it has some quirks...
      Now, let's go to something harder... Setting the whole palette !!
      The way I do it is like this: first I define two records, one to store
    the RGB value of one color and the other to store the whole palette.

      Type RgbItem=Record
                         R,G,B:Byte;
                   End;
           RgbList=Array[0..255] of RgbItem;

      Then, you define the procedure to read the palette into a var of the
    predefined type:

      Procedure GetPalette(Var Pal:RgbList);
      Var A:Byte;
      Begin
           For A:=0 To 255 do GetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
      End;

      You just get the colors of the 256 colors and store them into an array,
    where you can change them at you will. To set the whole palette, just do
    the same, like this:

      Procedure SetPalette(Pal:RgbList);
      Var A:Byte;
      Begin
           For A:=0 To 255 do SetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
      End;

      As you see, it's fairly easy... But, if you are brave, you'll probably
    just went and tried the routines. If you do so, you will be disapointed with
    the results. You'll probably get a screen full of "snow". The "Snow" is the
    dots that appear in your screen when you change colors.

     The retrace

      So, how can you stop this? First, you must understand something about
    monitor theory. As you may already know, the image in your screen is updated
    by an electron beam, that sweeps the screen, from left to right. When it
    reaches the end of a line, it goes to another line. When it reaches the end
    of the screen, the electron beam resets to it's initial position in the
    upper left corner. This period, while the beam goes from the lower right
    corner to the upper left one, is called the Vertical Retrace, or Vertical
    Blank. How is this helpfull? Well, during this period, anything you do to
    the screen won't show imediatly, so, you can change the palette, draw
    sprites, or anything else, and it would only show in the next retrace. But,
    everything has a downside, and the VBL (Vertical BLank) is no exception. The
    period is very, very short. So that you'll know, it occurs a VBL almost 70
    times a second, so, anything you want to do you'll have to do it fast... You
    should use frequenty the retrace, especially when you do lot's of thing on
    the screen.
      But this is enough for setting the whole palette without fuzz. The
    following procedure waits first for the retrace to begin. It is all in
    assembler, and it's quite complicated. To the tech-minded out there, we
    simply get a byte from port 3DAh. If the third bit of the byte is set,
    that means that VBL in occuring.

      Procedure WaitVBL; Assembler;
      Label A1,A2;
      Asm
         Mov DX,3DAh
      A1:
         In AL,DX
         And AL,08h
         Jnz A1
      A2:
         In AL,DX
         And AL,08h
         Jz A2
      End;

      So, here you have it... A procedure to test the VBL. Now, the SetPalette
    procedure should be like this:

      Procedure SetPalette(Pal:RgbList);
      Var A:Byte;
      Begin
           WaitVBL;
           For A:=0 To 255 do SetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
      End;

      Easy, isn't it ?...

     Palette effects

      Now, I will talk about two types of effects, and the application of one
    of them. The palette by it's own is capable of some nice effects, as I think
    I've shown in my Color Blind demo.

       Rotations

        Rotating the palette is a good effect to start coding, and a very
      effective one. Most of the effects in Color Blind are diferent types of
      rotations.
        Rotating the palette is just a matter of making color 0 be color 1,
      color 1 be color 2, and so forth, until color 255 be color 0. You can also
      do a reverse rotation, just by changing the direction. Code follows:

        Procedure RotatePal(Var Pal:RgbList);
        Var Temp:RgbItem;
            A:Byte;
        Begin
             Temp:=Pal[255];
             For A:=254 DownTo 0 Do
             Begin
                  Pal[A+1]:=Pal[A];
             End;
             Pal[0]:=Temp;
        End;

        Study this piece of code, I think it's very simple. This rotates the
      colors of a palette buffer (type RgbList), not the colors of the screen.
      After you rotate the buffer, you'd still have to set them, so you'll
      notice the effect. It can be done with something like this:

        Var Pal1:RgbList;
        .......
        .......
        GetPalette(Pal1);
        Repeat
              RotatePal(Pal1);
              SetPalette(Pal1);
        Until Keypressed;
        .......
        .......
        .......

        This would rotate the palette of the screen until some key is pressed.
        Now, let's move forth to a tougher effect:

       Fades

        If you watch TV (and who doesn't ?), you'll see that most of the times,
      the images don't just appear out of nowhere. They slowly fade in or out,
      the colors slowly transforming to do the image. Well, it's fairly easy to
      do so in the PC, and it is a bonus, because it's more impressive to see
      the image slowly appearing than throwing it to the screen altogether.
        The theory behind a fade is fairly simple. You have a source pallete
      (usually the screen palette) and a target palette. Than, you compare
      each color and increase or decrease their RGB values.
        You compare the RGB values of color 0 of the source palette with the
      RGB values of color 0 of target palette, and change their values in face
      of that. The next piece of code was the first fade I've ever made, and it
      is very badly done. It can be done a lot faster and prettier, but I leave
      that to you.

        Procedure Fade(Target:RgbList);
        Var Tmp:RgbList;
            Flag:Boolean;
            Loop:Integer;
        Begin
             Repeat
                   Flag:=True;
                   GetPalette(Tmp);
                   For Loop:=0 To 255 Do
                   Begin
                        If Tmp[Loop].R>Target[Loop].R Then
                        Begin
                             Dec(Tmp[Loop].R);
                             Flag:=False;
                        End;
                        If Tmp[Loop].G>Target[Loop].G Then
                        Begin
                             Dec(Tmp[Loop].G);
                             Flag:=False;
                        End;
                        If Tmp[Loop].B>Target[Loop].B Then
                        Begin
                             Dec(Tmp[Loop].B);
                             Flag:=False;
                        End;
                        If Tmp[Loop].R<Target[Loop].R Then
                        Begin
                             Inc(Tmp[Loop].R);
                             Flag:=False;
                        End;
                        If Tmp[Loop].G<Target[Loop].G Then
                        Begin
                             Inc(Tmp[Loop].G);
                             Flag:=False;
                        End;
                        If Tmp[Loop].B<Target[Loop].B Then
                        Begin
                             Inc(Tmp[Loop].B);
                             Flag:=False;
                        End;
                   End;
                   SetPalette(Tmp);
             Until Flag;
        End;

        This is very straighforward, and very simple. You just check all the
      256 colors until they all reach their target counterpart. This procedure
      can be expanded to allow speed control and other things like that, but
      it works fine just as it is. For example, to fade out a screen (to fade
      to black), you just set all colors in the target palette to 0 and then
      fade the screen.
        Now, we'll go on to discuss a pratical way to use the palette
      rotations.

       The static screen

        If you saw the Color Blind demo, you'll notice one of the last effects:
      the static screen. This is a screen full of static (like if you tune the
      TV to an unused station). This is simple to code, and impressive, never
      the less, if coupled with some other effects, like a text scroll or a
      fade in/out kind of stuff like in Color Blind.
        To do a static screen, you must first define a pallete in which the
      first 16 colors are greys, like this:

        Procedure SetGreys(Var Pal:RgbList);
        Var A:Byte;
        Begin
             For A:=0 to 15 Do
             Begin
                  Pal[A].R:=A*4;
                  Pal[A].G:=A*4;
                  Pal[A].B:=A*4;
             End;
        End;

        Then, you fill the screen with the first 16 colors, using the Random
      function to maximaize the effect.

        Procedure FillScreen;
        Var X,Y:Integer;
        Begin
             For Y:=0 to 199 Do For X:=0 to 319 Do PutPixel(X,Y,Random(15));
        End;

        Finally, you cicle the 16 first colors. To do this, you'll have to
      change a bit the RotatePal procedure. It must be something like this:

        Procedure RotatePal(Var Pal:RgbList;First,Last:Byte);
        Var Temp:RgbItem;
            A:Byte;
        Begin
             Temp:=Pal[Last];
             For A:=Last-1 DownTo First Do
             Begin
                  Pal[A+1]:=Pal[A];
             End;
             Pal[First]:=Temp;
        End;

        To rotate the 16 first colors, you'll have to do something like this:

                  RotatePal(Pal1,0,15);

        I assume your palette buffer is called Pal1.
        So, here you have it... You personal untuned TV.


        Program Static_Screen;

        Uses Crt;

        Const VGA=$A000;

        Type RgbItem=Record
                           R,G,B:Byte;
                     End;
             RgbList=Array[0..255] of RgbItem;

        Var Pal1:RgbList;

        Procedure Initgraph; Assembler;
        Asm
           Mov AH,0
           Mov AL,13h
           Int 10h
        End;

        Procedure Closegraph; Assembler;
        Asm
           Mov AH,0
           Mov AL,03h
           Int 10h
        End;

        Procedure WaitVBL; Assembler;
        Label A1,A2;
        Asm
           Mov DX,3DAh
        A1:
           In AL,DX
           And AL,08h
           Jnz A1
        A2:
           In AL,DX
           And AL,08h
           Jz A2
        End;

        Procedure PutPixel(X,Y,C:Word);
        Begin
             Mem[VGA:(Y*320)+X]:=C;
        End;

        Procedure GetColor(Col:Byte;Var R,G,B:Byte);
        Begin
             Port[$3C7]:=Col;
             R:=Port[$3C9];
             G:=Port[$3C9];
             B:=Port[$3C9];
        End;

        Procedure SetColor(Col,R,B,G:Byte);
        Begin
             Port[$3C8]:=Col;
             Port[$3C9]:=R;
             Port[$3C9]:=G;
             Port[$3C9]:=B;
        End;

        Procedure GetPalette(Var Pal:RgbList);
        Var A:Byte;
        Begin
             For A:=0 To 255 do GetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
        End;

        Procedure SetPalette(Pal:RgbList);
        Var A:Byte;
        Begin
             WaitVBL;
             For A:=0 To 255 do SetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
        End;

        Procedure SetGreys(Var Pal:RgbList);
        Var A:Byte;
        Begin
             For A:=0 to 15 Do
             Begin
                  Pal[A+1].R:=A*4;
                  Pal[A+1].G:=A*4;
                  Pal[A+1].B:=A*4;
             End;
        End;

        Procedure SetBlack(Var Pal:RgbList);  { This sets the buffer to black }
        Var A:Byte;
        Begin
             For A:=0 to 255 Do
             Begin
                  Pal[A].R:=0;
                  Pal[A].G:=0;
                  Pal[A].B:=0;
             End;
        End;

        Procedure FillScreen;
        Var X,Y:Integer;
        Begin
             For Y:=0 to 199 Do For X:=0 to 319 Do PutPixel(X,Y,Random(15));
        End;

        Procedure RotatePal(Var Pal:RgbList;First,Last:Byte);
        Var Temp:RgbItem;
            A:Byte;
        Begin
             Temp:=Pal[Last];
             For A:=Last-1 DownTo First Do
             Begin
                  Pal[A+1]:=Pal[A];
             End;
             Pal[First]:=Temp;
        End;

        Procedure Fade(Target:RgbList);
        Var Tmp:RgbList;
            Flag:Boolean;
            Loop:Integer;
        Begin
             Repeat
                   Flag:=True;
                   GetPalette(Tmp);
                   For Loop:=0 To 255 Do
                   Begin
                        If Tmp[Loop].R>Target[Loop].R Then
                        Begin
                             Dec(Tmp[Loop].R);
                             Flag:=False;
                        End;
                        If Tmp[Loop].G>Target[Loop].G Then
                        Begin
                             Dec(Tmp[Loop].G);
                             Flag:=False;
                        End;
                        If Tmp[Loop].B>Target[Loop].B Then
                        Begin
                             Dec(Tmp[Loop].B);
                             Flag:=False;
                        End;
                        If Tmp[Loop].R<Target[Loop].R Then
                        Begin
                             Inc(Tmp[Loop].R);
                             Flag:=False;
                        End;
                        If Tmp[Loop].G<Target[Loop].G Then
                        Begin
                             Inc(Tmp[Loop].G);
                             Flag:=False;
                        End;
                        If Tmp[Loop].B<Target[Loop].B Then
                        Begin
                             Inc(Tmp[Loop].B);
                             Flag:=False;
                        End;
                   End;
                   SetPalette(Tmp);
             Until Flag;
        End;

        Begin
             Initgraph;
             SetBlack(Pal1);
             SetPalette(Pal1);
             FillScreen;
             SetGreys(Pal1);
             Fade(Pal1);
             Repeat
                   RotatePal(Pal1,1,16);
                   SetPalette(Pal1);
             Until KeyPressed;
             SetBlack(Pal1);
             Fade(Pal1);
             Closegraph;
             Writeln('Another SpellCaster production... The Static Screen...');
             Writeln('Press RETURN to quit...');
             Readln;
        End.

      So, here you have it... The Static Screen. I like this effect very much.
    I was to include also a part about the cross-fade effect, but it's a lot
    more complicated and requires other knowledge. As soon as I feel you're
    ready, I'll make a tutor on it too.



 Points of view

    Well, I have bad news for all fans out there... I'm going to start school
  tomorrow, so, I think the next issue of 'The Mag' will be slightly delayed,
  because I'm moving to a new scholl that's almost 50 km from where I live, and
  I don't know anything nor anyone there, so I don't think I can prepare the
  next issue in time... But don't worry, I'll still be making the magazine, for
  all coders and would-be coders out there.
    I also don't have time because I'm going to start coding a new game...
  I don't know the name for it, nor the kind of game it will be, but I have some
  ideas. If you would like to make a sugestion, feel free to write. I need input
  from all of you out there on what kind of game is the favourite amongst you.
    I was writing a game, called "Titans", a strategy wargame, but because of
  my insane ambition, I can't do it without learning first how to work with
  Extended and Expanded memory. If anyone out there knows, type me a letter.
    So, I think this is goodbye... I think this was a great issue, with assembly
  and other stuff in it. If you think so too, write to me and say something.



 The adventures of Spellcaster, the rebel programmer of the year 2018.

  Episode 3 - Escape

    Everything is set now. After one month of pure disgust, I'ver learned to
  program the Atari, at least enough to make a virus powerfull enough to disable
  the prison's power grid. I've just finished my chores, so I can go now to the
  computer center and activate the virus.
    I walked slowly, fearing that some guard noticed my thoughts, and prevented
  my long-awayted freedom. I walked until the room. The guard in the door
  looked at me, as if it could read my mind, and smilled with a grin, making me
  a signal to enter. I went inside the gloomy room. It was cold and dark, only
  the brightness of the monitors to lighten it up. There it was... The Atari
  520ST, with it's patetic 32 color display. I sat down at the keyboard and
  closed my eyes. It was still hard for me to look at that disgusting thing. I
  typed away, and an half-hour later, everything was done. I prepared the virus
  to go active at two o'clock in the morning. Then, I returned to my chambers,
  where I lyed down, with my eyes open. At 11:00, the lazer bars were activated
  and the lights were turned off. I looked at the entry to my cell, staring at
  the red light that crossed it, knowing that this was probably the last time
  I would see them.
    At precisely 2:00, the red light went off. Seconds later, I got up and
  started walking quitly by the walkway, trying to make no noise. I felt someone
  breathing in my neck, I turned my head and I saw that I was beeing followed.
  The other inmates also noticed the power shortage. Suddently, lazer shots were
  heard, and screams raised all around. The guards noticed us and were firing.
  I start running, followed by another convict, and I knocked a guard over,
  jumping over him and punching him until he was dead... I didn't had conscience
  problems... I got up and continued running. In a few minutes, I was out of the
  prison's gates, and I suddently stopped. The taste of freedom filled my mouth,
  when I was knocked over by someone, followed by a stream of lazer shots, that
  hitted the ground where I stood. The person that was now on top of me saved my
  life! I pushed him of me, then got up, helping the other man getting up. It was
  a tall, blond man, that smilled at me. I looked at him and smilled back. Then,
  we both started running, as there was no tomorrow, until we could run no more.
  I drop down to my knees and looked back. At some distance, I could still hear
  screams and lazer shots of the Atari Penetenciary. Then, I noticed that the
  tall man was still behind me, looking forward. I looked forward and saw the
  Atlantic Ocean right in front of me. Then I yelled, as loud as I could:
  - I'M FREE !!!!!!!


                                         See you in the next issue
                                        Diogo "SpellCaster" Andrade
