Horizons Interactive Entertainment proudly presents

UNDERSTANDING THE VGA PALETTE

By Brian Bartels

Palette Basics:

Have you ever noticed while making some graphics for some crappy QBasic game that the default VGA palette is really ugly? Have you ever wondered if you can change those colors. Well, you can. It is a very simple process. The first thing you must understand is that every color that your monitor can display is made up of the three primary colors red, green, and blue, or RGB. To change the RGB values for a given color all you have to do is use this command: PALETTE color, red+(green*256)+(blue*65536) The red, green and blue can range from 0 to 63. The higher the number, the greater the brightness of the color. It's that simple!

Advanced Topics:

Now that you have played around with PALETTE for a while you have probably noticed that it is extremely slow. The QBasic PALETTE statement is slow for two reasons, the first being that it has to do all of that math (red+ green*256+blue*65536) every time you use it, the second being that every time you use it it waits for the screen to refresh, which makes this statement tottaly unusable for fading in, out, or to another palette. How do you get around this problem? Well, you simply write your own PALTTE subroutine that doesn't do all of that math and doesn't wait for the screen to refresh. This can easily be accomplished with four simple OUT commands. Here is the code for an extremely fast palette setting routine:

SUB setpal (col%, r%, g%, b%)
OUT &H3C8, col%
OUT &H3C9, r%
OUT &H3C9, g%
OUT &H3C9, b%
END SUB

Now that you have a palette routine that is really fast you can do cool stuff like fading the entire screen in or out or to another palette. Fading palettes is a lot simpler than is sounds. The first thing you have to do is think of each color as three values red, green, and blue. First lets just discuss how to generate a gradient between two colors. Ok, lets say than color number 26 is bright red, meaning that its red value is 63 (the max value) and its green and blue values are both 0. Lets also say that color 65 is bright blue, meaning that its blue value is 63 and its red and green values are both zero. Ok, what we wan't to do is make all the colors in between 26 and 65 be a gradient of colors 26 and 65. So, first we are going to store the first RGB values (color 26) in three variables, we will call them r1%, g1%, and b1%. We will also store the second RGB values (color 65) in three arrays, we will call them r2%, g2%, and b2%. Then we have to figure out how many steps of the gradient we want which is simply 65-26. Then we must figure out how much to add on to the r, g, and b values for each level of the gradient we will do this with this code:

numofsteps% = 65 - 26
rinc# = (r2% - r1%) / numofsteps%
ginc# = (g2% - g1%) / numofsteps%
binc# = (b2% - b1%) / numofsteps%

Then it is simply a matter of making a FOR loop that adds these increments to the colors in our gradient sequentially like this:

r# = r1%
g# = g1%
b# = b1%
FOR col% = 27 to 64
   r# = r# + rinc#
   g# = g# + ginc#
   b# = b# + binc#
   setpal col%, INT(r#), INT(g#), INT(b#)
NEXT

Now, all of the colors in between 26 and 65 are a gradient. Wow, wasn't that fun?! If you haven't already figured it out, fading in or out a palette, or even fading to another palette is very simple. You basically do the same thing we just discussed except that instead of having one starting value and one ending value and gradients in between you have 256 starting values, 256 ending values, and 256 increment values. You should have an array called startpal which will be dimensioned with thew following line:

DIM startpal(2,255)

You will notice that this array is two dimensional, that is becuase we need to store red, green, and blue values for all 256 colors, this array works like this:

startpal(0, col%) = red value of col%
startpal(1, col%) = green value of col%
startpal(2, col%) = blue value of col%

We will also need three more arrays called endpal, palinc, and pal. These three arrays will be dimensioned exactly the same as with startpal except that endpal will contain the destination RGB values for every color, palinc will contain the RGB increments for every color and pal will be the current palette and will be what we add the increments to each time. The only thing you have to remember when doing this is that when you do the computations for the incrments and when you add on the incremtns you have to do it for every color. To fade in a palette you would simply make all the startpal values equal zero and make endpal be the palette you want to fade in. Fading out a palette is done the same way except backwards. Fading to another palette is done by making startpal equal you current palette and endpal the palette you want to fade to. The number of steps you use will determine how fast the palette fades. Here is the code for fading.

DIM startpal(2,255) AS INTEGER
DIM endpal(2,255) AS INTEGER
DIM pal(2,255) AS DOUBLE
DIM palinc(2,255) AS DOUBLE
steps% = 50

'set startpal and endpal here

FOR col% = 0 TO 255
   FOR j% = 0 TO 2
      palinc(j%, col%) = (endpal(j%, col%) - startpal(j%, col%)) / steps%
   NEXT
NEXT
FOR col% = 0 TO 255
   FOR j% = 0 TO 2
      pal(j%, col%) = startpal(j%, col%)
   NEXT
NEXT
FOR q% = 0 TO steps%
   FOR col% = 0 TO 255
      FOR j% = 0 TO 2
         pal(j%, col%) = pal(j%, col%) + palinc(j%, col%)
      NEXT
   NEXT
   FOR col% = 0 TO 255
         setpal col%, INT(pal(0, col%)), INT(pal(1, col%)), INT(pal(2, col%))
   NEXT
NEXT

That's all there is to it!

Well, thats all the tutorials we have for you this month. Next month we will hopefully have many many more! =) Please remember to send us a tut sometime.