			͸
			
			
			
			
			
			ʹ
			Part III  -  THE PALETTE 
			

Hi and welcome to the issue number 3 of my weekly (who am I trying to kid 
here?) tutorial on programming graphics for the PC.

This collection of files could have reached you via one of the following
methods :

	FTP from   ftp://ftp.teleport.com/users/~craigl/vgatut

	or

	The Shetland Information Technology Project (SITP)
		Conferences/Computing/Graphics/Programming

If you recieved this from any other source then I'd like to hear about it
so that I can include it in this list.

An apology


You may have noticed an absence of PASCAL source code with this tutorial,
Rik is away on holiday as I write this and I didn't want it to be any later
than it already is.  If you'd like PASCAL source code then drop me a line
and I'll try and persuade Rik to forward it to you.

This tutorial is about the VGA palette.

Before we start :


ͻ
DISCLAIMER
Ľ
	The code for this tutorial, the compiled .EXEs and any ascociated text
	are freely distributable on the conditions that the contents of the 
	original .ZIP file are distributed as one and that no changes are made
	to any of the data or information contained within.
	The author expresses no warranty implied or otherwise as to the
	suitabilty of this software for execution on any machine other than
	the system on which it was developed (although there should be no
	problems).
	The author also takes no responsibilty for damage resulting from the
	use of information, code or otherwise, obtained from this tutorial 
	(again, I'd be surprised if such a thing did happen).
	Finally you should _NOT_ have paid anything for this tutorial.  
	If you parted with any money (other than a reasonalbe price for a 
	disk) then complain and get your money back.  Please let me know too. 
	This tutorial is FREE.  Please do not abuse this.


Sorry about all that, but unfortunately we live in a world where such things
are a necessity.

What is the palette anyway?


Let's start at the beginning shall we? :)

We know from Tutorial 1, that mode 13h is capable of displaying 256 colours
on screen at any one time.  If you take a look at the example programs
supplied with the first 2 tutorials (what do you mean you don't have them?!!)
you'll see that the colours on screen are pretty grotty.  This is the default
palette, the palette that is automatically set when you switch to this video
mode.  Luckily for us, the designers of the VGA card had the foresight to
allow us to change these colours... read on.

Changing the palette


In order to change the palette, we must first understand a little about the
way in which colours are formed.  The VGA palette allows us to specify Red,
Green & Blue values for each colour in our palette.  This is known as an RGB
triad, and works like this :

	When Red, Green & Blue are all equal to 0, the colour represented is
	black.
	Conversely when each of the 3 values is 63 (the maximum colour) the
	colour represented is white.
	A triad of 63,0,0 (Red, Green, Blue) represents a full intensity red.

As each element in the triad has a range of 0-63, (the first 6 bits of a byte)
the entire range of colours that we can choose from is... 

   64 * 64 * 64 = 262,144!!! different colours.

Remember though that we are still limited to a maximum of 256 on screen at one
time.

But how do we actually set the palette?!!


For this we need to use the ports of the VGA card.  We first send the
index of the colour that we want to change (0 - 255) to the appropriate
port.  In this case it is the port 0x3C8.

We can use the outp() function to do this....

     outp( 0x3C8, Index );

This will tell the VGA card to accept 3 values to port 0x3C9, in the
order Red, Green, Blue.

     outp( 0x3C9, Red );
     outp( 0x3C9, Green );
     outp( 0x3C9, Blue );

And, faster than you can say 'Why does C use the characters '0x' as a prefix 
to represent hexadecimal numbers?', the colour has been changed.

That's all there really is to it.

Getting the Palette


Almost exactly the same proceedure for setting the palette is involved.
We use the port 0x3C7 again to point to the colour index that we want to read
and 'as if by magic' the values appear at port 0x3C9 and can be read using the
inp() function like this....

	Red   = inp(0x3C9);
	Green = inp(0x3C9);
	Blue  = inp(0x3C9);

These two functions can be written in assembly like this.....

void SetOnePalette( int Index,
		    unsigned char R,
		    unsigned char G,
		    unsigned char B)
{
    _asm
    {
	mov dx, 0x3C8
	mov ax, [Index]
	out dx, al

	inc dx

	mov al, [R]
	out dx, al
	mov al, [G]
	out dx, al
	mov al, [B]
	out dx, al
    }
}

and to get the palette triad....

    _asm
    {
	mov dx, 0x3C7
	mov ax, [Index]
	out dx, al

	mov ax, 0x3C9
	in  al,  dx
	mov [Red], al
	in  al,  dx
	mov [Green], al
	in  al,  dx
	mov [Blue], al
    }

Eeeeezeee!

Fading the Palette to Black


This is pretty simple and more graceful than just clearing the screen.

The pseudocode looks like this....

   Check RGB values of current index
   if they are greater than 0 subtract 1
   loop until all values are equal to zero

I'm sure you can write the actual routine yourselves, but just in case you
can't be bothered you'll find it supplied in the ascociated .CPPs

An almost identical procedure is used for fading the palette from black to
a specified palette, except this time we need an array of bytes against which
we can compare the current index, and add 1 to the value if it is below the
desired level.

Again the code for doing this is provided in the ascociated .CPPs

A nicer way of fading the screen is to calculate the difference between
the two colours and divide the result by 64.  This will give you a floating
point value that will alow you to redcuce/increase the RGB triad in proportion
to the rest of the palette so that each colour reaches it's maximum/minimum
value at (almost) the same time.  This will produce a much smoother
, more professional looking fade.

Colour Cycling - How?


To do this, we need to shift each colour one place up and stuff the last
colour into the start of the palette.

We can use the GetAllPalette() function provided to store the entire
current palette into an array of unsigned chars like this....

    unsigned char Pal[768] = {0};

    GetAllPalette(Pal);

Now the code to rotate the palette :


// Rotate values stored in Pal up by 3 bytes (R + G + B)

void PalCycle( unsigned char *Pal )
{
    int nTmp;

    // holds a copy of the palette
    unsigned char Temp[3];

    for (int nLoop=0; nLoop<Number; nLoop++)
    {
	// store last colour
	memmove( Temp, &Pal[765], 3 );

	// move palette up 1
	memmove( &Pal[3], &Pal[0], 765 );

	// place highest colour in 1st index
	memmove( &Pal[0], Temp, 3 );
    }
}


The function in the supplied VGAPALL.CPP allows you to rotate the palette
by more than 3 bytes to produce faster rotation.  It also allows you
to rotate the palette backward by supplying a negative value.

The following code will now rotate the palette until a key is pressed :

   while (!_kbhit())
   {
	PalCycle( Palette );
	SetAllPalette( Palette );
   }

Other goodies


Because I'm so generous <grin> I've also provided a function which allows
you to create a smoothly faded gradient palette for use in your work.

It is fairly simple to use and works like this....

    GradPal is a structure which is used to hold palette data information
    and it holds data like this :

	Red value, Green value, Blue value, palette index

    To use it we create an array :

	GradPal[5]      // where 5 is the number of points you are specifying

    and initialise it like this.....

    // gradient array - fade from black to red to yellow to white to black
    GradPal BarsData[5] = { {  0,  0,  0,   0},
			    { 63,  0,  0,  64},
			    { 63, 63,  0, 128},
			    { 63, 63, 63, 192},
			    {  0,  0,  0, 255},
			  };

    You can see that it is quite obvious where the gaps to be filled are.

    This array is then passed, along with the address of the Palette array 
    and the number of points you are specifying, to the function....
    
	MakeGradPal( BarsData, 5, BarsPal );

    And Voila!  You have a nice gradient palette to be used with the
    SetAllPalette() function.


    Vertical Retrace
    


    You may notice that while you are manipulating the palette, you get
    noise appearing on the screen.  This is unsightly and makes your
    work look unprofessional.  Fortunately there is a way to avoid this..

    The image on the screen (as you probably know) is created by an electron
    beam scanning backwards and forwards across a grid of phosphor dots.
    When the beam reaches the foot of the screen there is a short period
    while it returns to the top when no screen updating is done.  This
    is known as the 'vertical retrace' and is an important factor in smooth
    palette manipulation.

    The function WaitVerticalRetrace() will only return control when a
    vertical retrace begins, thus, if you call this function just before
    you update the palette, you can change the palette during this gap
    and minimise the amount of noise.  Unfortunately (why does everything
    have to have a downside?) it will slow your program down, by tying it
    to the refresh speed of your monitor.


Goodbye....


And that's it....  Well not quite.  There are a number of other things
that you can do with the palette, (some of them are supplied)
but I'll leave you to discover them for yourselves. ;)

As you can see, changing the palette has a *big* effect on how your work
looks.  You are no longer limited to the disgusting VGA default palette
and can now begin producing even more stunning graphical works.

Tutorial 4 is going to be about drawing filled polygons.  So watch out
for it.

(Standard bit ripped from last tutorial)Ŀ
Ŀ
If there is anything in this tutorial which you would like further details 
on, then please do not hesitate to contact me.                             
                                                                           
If you produce anything nice, then please send it to me.  I am always keen 
to see other people's work.                                                
                                                                           
Comments on this tutorial will be gratefully recieved.  Was it any use to  
you? Too informal?  Too complicated?  Not clear enough?  Too simple?       
What subjects would you like to see covered in later editions?             

ĴFrom 'Soul Music' by Terry PratchettĿ
                                                                           
'Somewhere, in some other world far away from the Discworld,               
 someone tentetively picked up a musical instrument that echoed to         
 the rhythm of their soul.                                                 
 It will never die.                                                        
 It is here to stay. '                                                     
                                                                           


Barny Mercer    - (original code & text file) 23/8/95 @ 10:45pm

email : barny.mercer@zetnet.co.uk
WWW   : http://www.zetnet.co.uk/users/bmercer/
voice : 01595 692097

Richard Griffiths       - Pascal conversion
email : richard.griffiths@zetnet.co.uk
WWW   : http://www.zetnet.co.uk/users/rgriff/
	
