In this part, I will put the palette through its paces. What the hell is a palette? 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 palette? How do I black out the screen using the palette? How do I fade in a screen? How do I fade out a screen? Why are telephone calls so expensive? Most of these questions will be answered in this, the second part of my Trainer Series for Pascal.

DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___> |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   >    <  |  | |  _  |
\_/ \_/ <_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  

Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the creation of demo effects in the 90s. I reproduce them here, as they offer so much insight into the demo scene of the time.

These articles apply some formatting to Denthor's original ASCII files, plus a few typo fixes.

What is the palette?

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 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 palette. 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 of 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, i.e. 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 palette of either of them will they be able to tell the difference.

Also, by changing the whole palette, you can obtain the “Fade in” and “Fade out” effects found in many demos and games. palette manipulation can become quite confusing to some people, because colors that look the same are in fact totally separate.

How do I read in the palette value of a color?

This is very easy to do. To read in the palette 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 palette 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;

How do I stop the “fuzz” that appears on my screen when I change the palette?

If you have used the palette 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 electron 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 Vertical Retrace. During the vertical retrace you may change the palette without affecting what is on the screen. What we do is that we wait until a vertical retrace has started by calling a certain procedure; this means that everything we do now will only be shown after the vertical 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 palette, the fuzz doesn’t appear on the screen, only the result (the changed palette), 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.

procedure WaitRetrace; assembler;
label
  l1, l2;
asm
    mov dx,3DAh
l1:
    in al,dx
    and al,08h
    jnz l1
l2:
    in al,dx
    and al,08h
    jz  l2
end;

How do I black out the screen using the palette?

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 palette 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 palette 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 Grabpalette;
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 palette 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 through the palette. 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. Because 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 palette 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 palette 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 than just clearing the screen; it can make a world of difference in the impression your demo will leave on the people viewing it. To restore the palette, just do this:

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

Palette 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.