Download as rtf, pdf, or txt
Download as rtf, pdf, or txt
You are on page 1of 28

V MANIPULATING VGA COLORS

5.1 INTRODUCTION

The previous chapter developed a very useful GFXLIB3.HPP library that will be used in
this chapter and some future chapters until it is, in turn, replaced by a newer and better
library. All the routines presented so far have allowed pixels, lines, and shapes to be
displayed in one of 256 different colors. As a matter of fact, the 320 X 200 VGA mode
was chosen intentionally because it allows 256 colors at one time. Selecting smaller
pixels will give greater resolution but it will also reduce the number of different colors to 16.
It is true that this problem can be solved by using a SVGA (Super VGA) card, but even
though it can be pretty much assumed that practically all computers have at least VGA
capabilities, it is not true that most computers have access to SVGA. The SVGA card
may be discussed in a third edition of this book, but right now the focus is still on graphics
with the VGA card. Concentrating on the VGA card also makes sense considering that
this book is primarily meant for learning graphics in a high school computer science
environment. Traditionally, high school computer science hardware has a difficult time
keeping up with the latest developments.

Even though 256 colors is already a very substantial selection there are actually 262,144
different colors that can be displayed with the VGA card in 320 X 200 mode. All colors are
created by a combination of Red, Green and Blue (RGB for short) intensities. Each of
the three basic colors can have 64 different shades that are ranked from 0 to 63. Since 64
X 64 X 64 = 262,144 it makes sense that there are such an enormous number of color
combinations. This chapter will explain how to have access, and manipulate all these
many color combinations.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter V Manipulating VGA Colors -5.1-


5.2 THE 256 INITIAL COLORS

It can be pretty exciting to consider 262,144 different colors, but for now let us first take a
look and see what the original 256 VGA colors have to offer. We will start with program
COLOR01 and show 256 vertical lines. Each one of them will show a different color,
starting with color 0 and ending with color 255.

────────────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH05_01.CPP displays each one of the 256 colors in the ***/
/*** VGA color pallette. Each colr is drawn as a vertical line ***/
/*** which starts with color 0 and then increases by 1 until color ***/
/*** 255 is reached. ***/
/**********************************************************************/

#include "GFXLIB3.HPP"

void main()
{
int X;

StartGfx();
for (Byte Color=0; Color<=255; Color++)
{
X = Color;
Line(X, 0, X, MAXX, Color);
} // End for loop.
Stop();
EndGfx();
} // End main program CH05_01.CPP.
────────────────────────────────────────────────────────────────────────────────

You will notice that this program is nice and short, which is one of the big benefits of using
the GFXLIB3.HPP include file. We can go on with the task at hand and not clutter up the
screen with various functions that have already been explained before.

When you view the execution of program CH05_01 there is little doubt in your mind that
many different colors are being displayed. But viewing 256 different colors that are all
immediately adjacent to each other is a little difficult.

Program CH05_02 comes to the rescue and 256 neat little rectangles, each one properly
separated from the previous one, will be displayed. There are various shades that are so
close to black that they are pretty much invisible.

────────────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH05_02.CPP demonstrates the 256 different colors by drawing ***/
/*** a small rectangle for each one of the colors. ***/
/**********************************************************************/

#include "GFXLIB3.HPP"

Chapter V Manipulating VGA Colors -5.2-


void main()
{
StartGfx();
Byte Color = 0;

for (int Row=0; Row<=15; Row++)


for (int Col=0; Col<=15; Col++)
{
Rectangle(Col*20, Row*12, Col*20+18, Row*12+10, Color, CLOSED);
Color++;
} // End for loop.
Stop();
EndGfx();
} // End main program CH05_02.CPP.
────────────────────────────────────────────────────────────────────────────────

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

5.3 SETTING RGB COLOR COMBINATIONS

This section will present a program that allows you to see any one of the 262,144 different
color combinations with keyboard input. The program starts in text mode and prompts the
user for one of 64 color values for RED, GREEN and BLUE. It then switches to graphics
mode and fills the entire screen with the RGB color combination. After <ENTER> is
pressed the screen returns to text mode and allows another RGB combination to be
displayed. This process continues until 100 is entered for RED.

Several new graphics features are introduced with this program. You will notice a user-
defined RGB structure and some more BIOS stuff. Before we get down to explaining what
is happening try to run the program first and get a good feel for the many different
combinations. The general rule is that the lower numbers are the darkest and the higher
numbers are the brightest.

You might try some of the RGB combinations that are listed after the sample program
CH05_03. They will give you a good idea how different combinations work together to
create many different colors.

────────────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH05_03.CPP allows the user to change the Red, Green, ***/
/*** and Blue (RGB) intensities for one color in order to examine ***/
/*** the variety of RGB color signatures. These are 64 x 64 x 64, ***/
/*** or 262,144 possible different color combinations. ***/
/**********************************************************************/

Chapter V Manipulating VGA Colors -5.3-


#include <iostream.h>
#include "GFXLIB3.HPP"

struct RGBSignature
{
Byte Red;
Byte Grn;
Byte Blu;
}; // End struct RGBSignature.

void SetRGB(Byte Num, RGBSignature Sig);

void main()
{
Boolean Done = False; // Main body repetition flag.
RGBSignature Signature; // Red, green, blue color combination record.

do
{
EndGfx();
cout << "ENTER VALUES RED, GREEN, BLUE IN [0..63] RANGE" << endl;
cout << endl;
cout << "ENTER 100 FOR RED TO EXIT PROGRAM" << endl;
cout << endl << endl;
do
{
cout << "Enter Color Value for Red ===> ";
cin >> Signature.Red;
cin.ignore(80,'\n');
} // End do loop.
while(!(((Signature.Red>=0) && (Signature.Red<=63))
|| (Signature.Red == 100)));
Done = Boolean(Signature.Red == 100);
if(!Done)
{
do
{
cout << "Enter Color Value for Green ===> ";
cin >> Signature.Grn;
cin.ignore(80,'\n');
}
while (!((Signature.Grn>=0) && (Signature.Grn<=63)));
do
{
cout << "Enter Color Value for Blue ===> ";
cin >> Signature.Blu;
cin.ignore(80,'\n');
}
while (!((Signature.Blu>=0) && (Signature.Blu<=63)));
StartGfx();
SetRGB(100,Signature);
ClearGfx(100);
Stop();
} // End if.
} // End do loop.
while(!Done);
} // End main program CH05_03.CPP.

void SetRGB(Byte Num, RGBSignature Sig)


{
_AH = 0x10;
_AL = 0x10;
_BX = Num;
_CH = Sig.Grn;

Chapter V Manipulating VGA Colors -5.4-


_CL = Sig.Blu;
_DH = Sig.Red;
geninterrupt(0x10);
} // End void function SetRGB.
────────────────────────────────────────────────────────────────────────────────

Chapter V Manipulating VGA Colors -5.5-


═════════════════════════════════════════════════════════════
EXAMPLES OF RGB COMBINATIONS
═════════════════════════════════════════════════════════════
RED GREEN BLUE RESULTING COLOR

0 0 0 Black
63 63 63 White
63 0 0 Bright Red
0 63 0 Bright Green
0 0 63 Bright Blue
63 63 0 Bright Yellow
0 63 63 Aqua Blue
63 0 63 Purple
═════════════════════════════════════════════════════════════

The main body of program CH05_03 presents mostly text-based programming. Prompts
are provided to let the user enter color values for RED, GREEN, and BLUE. Keyboard
input is requested in the range of 0 to 63. The purpose of this manual is to teach graphics
in as simple a manner as possible. Often totally correct, and protected programming
code, is all bloated with many program statements unrelated to the point being discussed.
Many of the programs presented are not examples of the best possible way to write a
graphics program, but rather a means to explain graphics concepts. After keyboard input
is finished StartGfx puts the computer in VGA mode and function SetRGB is called
followed by Rectangle. Function Rectangle is old news. It is used to conveniently fill up
the whole screen. Our concern is with the new SetRGB routine.

────────────────────────────────────────────────────────────────────────────────
void SetRGB(Byte Num, RGBSignature Sig)
{
_AH = 0x10;
_AL = 0x10;
_BX = Num;
_CH = Sig.Grn;
_CL = Sig.Blu;
_DH = Sig.Red;
geninterrupt(0x10);
} // End void function SetRGB.
────────────────────────────────────────────────────────────────────────────────

Each one of the user-entered color values that is entered into the Red, Grn or Blu fields of
the RGBSignature structure is called Signature. Signature is passed to function
SetRGB with the formal parameter Sig. Num is the color number (one of 256) that is
receiving a new RGB combination. All this color business is handled by the VGA graphics
card, and communication to this card is handled by BIOS function calls. Function SetRGB
finishes with a call to int 0x10, the video interrupt. That is now becoming a regular
pattern. Bios function 0x10 (AH) deals with palette setting commands. BIOS sub function
0x10 (AL) sets a single color RGB signature. The BX register is used for the color

Chapter V Manipulating VGA Colors -5.6-


number to be changed. The CH register is used for the Green shade, the CL register is
used for Blue shade, and the DH register is used for the Red shade. Then, int 0x10 is
called. The new color for Num is instantly activated and all pixels on the screen with the
same value as Num will change to the new RGB Color Signature.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

5.4 SHADES OF RED, GREEN AND BLUE

If we can manipulate the color combination of one single color, like we did in the last
section, it makes sense to try and manipulate many different colors. As a matter of fact
why not look at the different shades of Red, Green and Blue. Program CH05_03 should
have shown that keeping Green and Blue color 0, allows different shades of Red to be
displayed. Several tools will be needed for such a job. We already have a RGB structure.
Next, we need to create an array of RGB structure and we will call that array PaletteType.
Function SetRGB is ready to go, but it can only change one color at a time. We will need
another routine, called SetPalette, to set all the colors at once. Luckily BIOS subfunction
0x12 allows this. Also, values will need to be placed in each RGB structure of the palette
structure and RGBShades function does that. The final result is program COLOR04
below.

────────────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH05_04.CPP demonstrates the 64 different shade intensities ***/
/*** red, green, and blue that are available. Shades of red, green ***/
/*** and blue are displayed as rectangles of continuous color ***/
/*** intensity. ***/
/**********************************************************************/

#include "GFXLIB3.HPP"

struct RGBSignature
{
Byte Red;
Byte Grn;
Byte Blu;
}; // End struct RGBSignature.

typedef RGBSignature PaletteType[256];

Chapter V Manipulating VGA Colors -5.7-


// Global array of different color palettes.
PaletteType GlobalPalette;

void SetRGB(Byte Num, RGBSignature Sig);


void SetPalette(PaletteType P);
void RGBShades(PaletteType P);

void main()
{
StartGfx();
RGBShades(GlobalPalette);
SetPalette(GlobalPalette);
for(Byte Color=0; Color<=191; Color++)
Line(0,Color,MAXX,Color,Color);
Stop();
EndGfx();
} // End main program CH05_04.CPP.

void SetRGB(Byte Num, RGBSignature Sig)


{
_AH = 0x10;
_AL = 0x10;
_BX = Num;
_CH = Sig.Grn;
_CL = Sig.Blu;
_DH = Sig.Red;
geninterrupt(0x10);
} // End void function SetRGB.

void SetPalette(PaletteType P)
{
for(Byte Count=0; Count!=255; Count++)
SetRGB(Count, P[Count] );
} // End void function SetPallette.

void RGBShades(PaletteType P)
{
for(Byte Count=0; Count<=63; Count++)
{
P[Count].Red = Count;
P[Count].Grn = 0;
P[Count].Blu = 0;
}
for(Count=64; Count<=127; Count++)
{
P[Count].Red = Count;
P[Count].Grn = Count - 64;
P[Count].Blu = 0;
}
for(Count=128; Count<=191; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 0;
P[Count].Blu = Count-128;
}
} // End void function RGBShades.
────────────────────────────────────────────────────────────────────────────────

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter V Manipulating VGA Colors -5.8-


5.5 GRADUAL FADING BETWEEN COLORS

With the RGBShades routine, each section of is RED, GREEN and BLUE displayed a
gradual fading from very dark (invisible) to very intense and bright. even though fading
was gradual with each color, the switch between colors was very abrupt. In this section
we will use some rainbow fading techniques where colors gradually change from one color
to another color.

The technique is very similar to the one shown with program CH05_04. This time, the
RGBShades function is altered, and renamed MakeRainbow. In RGBShades, two out of
three colors were assigned 0 while the third color faded from 0 to 63. With
MakeRainbow, the general concept of filling in the values for the global palette array are
the same. But now you will notice that more than one color changes to create the
fade-in/fade-out appearance.

In an effort to save paper and make the program easier to understand, a smaller library file
has been created called COLOR01.HPP. It contains the global declarations of the color
routines along with functions SetRGB and SetPalette. COLOR01.HPP behaves
somewhat like the earlier GFXLIB1.HPP before we created GFXLIB2.HPP. Shortly, we
will improve the small color library file and include more routines specifically designed for
color manipulation.

The focus of program CH05_05 is on function MakeRainbow. When you look at the
execution of program CH05_05 you will see a wide spectrum of colors, and the starting
rectangle of each row is very clearly different from the color of the rectangle above or
below it. If you check, however, any two adjacent rectangles you will hardly notice any
difference. The change in shade is very, very subtle, yet the result is that colors change
from RED to GREEN to BLUE.

────────────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH05_05.CPP shows a continuous spectrum of colors from ***/
/*** red to green to blue, and the gradual fading between colors. ***/
/*** Each color is displayed as a small rectangle. This program ***/
/*** Will execute very slowly. ***/
/**********************************************************************/

#include "CLRLIB1.HPP"

void MakeRainbow(PaletteType P);

void main()
{
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
Byte Color=0;
for (int Row=0; Row<=15; Row++)
for (int Col=0; Col<=15; Col++)
{
Rectangle(Col*20, Row*12, Col*20+18, Row*12+10, Color, CLOSED);

Chapter V Manipulating VGA Colors -5.9-


Color++;
} // End for loop.
Stop();
EndGfx();
} // End main program CH05_05.CPP.

void MakeRainbow(PaletteType P)
{
for (Byte Count=0; Count<=63; Count++)
{
P[Count].Red = Count;
P[Count].Grn = 0;
P[Count].Blu = 0;
} // End for loop.
for (Count=64; Count<=127; Count++)
{
P[Count].Red = 127 - Count;
P[Count].Grn = Count - 64;
P[Count].Blu = 0;
} // End for loop.
for (Count=128; Count<=191; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 191 - Count;
P[Count].Blu = Count - 128;
} // End for loop.
for (Count=192; Count<=255; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 0;
P[Count].Blu = 255 - Count;
} // End for loop.
} // End void function MakeRainbow.
────────────────────────────────────────────────────────────────────────────────

The MakeRainbow function has a similar logic as the previous RGBShades.


RGBShades is a little easier to explain because there was only one color that changed
while the two other colors remained black. MakeRainbow needs to alter the colors in
such a way that Red, Green and Blue slowly fade into each other, similar to a rainbow
spectrum. This requires that more than one color is manipulated. The fading from one
color into another happens because the color Red, for example, fades with decreasing
values while simultaneously Green increases in intensity. As Red totally fades out to be
replaced by an intense Green the process repeats itself as now Green fades while Blue
slowly takes over in the rainbow spectrum.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

5.6 CYCLING THE RAINBOW SPECTRUM

Chapter V Manipulating VGA Colors -5.10-


It is time to update our COLOR library. The number of new color functions is not very
large, but these functions do increase the size of each color program considerably. Before
we investigate any more color programs let us take all the specialized color functions and
put them together in COLOR02.HPP. Normally, functions are introduced in a program first
before they are placed in a library. This time we will make an exception and add
CyclePalette, shown below, to the library before it is demonstrated in a program.
CyclePalette uses a loop to take each value in the global PaletteType array (P in this
case) and switch one array index. Using this allows colors to move rapidly and simulate
motion.

────────────────────────────────────────────────────────────────────────────────
void CyclePalette(PaletteType P)
{
Byte Count;
RGBSignature T;

T = P[1];
for (Count = 1; Count <= 254; Count++)
P[Count] = P[Count + 1];
P[255] = T;
} // End void function CyclePalette.
────────────────────────────────────────────────────────────────────────────────

It is possible to place all functions that have anything to do with graphics in one large
library file. Such a file becomes very large and unwieldy to handle. It is also simpler to
create multiple smaller files that specialize. As we progress in this book we will continue to
do this. Right now we are creating a specialized COLOR library. In the future there will
also be a specialized MOUSE library among various others that will assist you with
graphics programming.

────────────────────────────────────────────────────────────────────────────────
/*******************************************************************/
/*** The CLRLIB2.HPP file is a specialized file that strictly ***/
/*** focuses on those declarations and functions which are used ***/
/*** to manipulate the VGA color palette. It is an extension of ***/
/*** the CLRLIB1.HPP introduced earlier in this chapter. ***/
/*******************************************************************/

#include "GFXLIB3.HPP"

struct RGBSignature
{
Byte Red;
Byte Grn;
Byte Blu;
}; // End struct RGBSignature.

typedef RGBSignature PaletteType[256];

// Global array of different color palettes.


PaletteType GlobalPalette;

Chapter V Manipulating VGA Colors -5.11-


// Allows the RGB palette for each one of the 256 different colors.
void SetRGB(Byte Num, RGBSignature Sig);

// Sets the RGB palette for each one of the 256 different colors based
// on the values in the global palette array.
void SetPalette(PaletteType P);

// Sets the RGB palette with 256 combinations of color so that


// red, green, and blue gradually fade into each other.
void MakeRainbow(PaletteType P);

// Cycles the RGB palette of the global array palette to the


// next color value. Doing this continuously simulates a motion
// of colors.
void CyclePalette(PaletteType P);

void SetRGB(Byte Num, RGBSignature Sig)


{
_AH = 0x10;
_AL = 0x10;
_BX = Num;
_CH = Sig.Grn;
_CL = Sig.Blu;
_DH = Sig.Red;
geninterrupt(0x10);
} // End void function SetRGB.

void SetPalette(PaletteType P)
{
unsigned Segment, Offset; // Segment and offset of array.
unsigned char MyPal[768]; // Temporary palette.

for(int K=0; K<=255; K++)


{
MyPal[K*3] = P[K].Red;
MyPal[K*3+1] = P[K].Grn;
MyPal[K*3+2] = P[K].Blu;
} // End for loop.
Segment = FP_SEG(MyPal);
Offset = FP_OFF(MyPal);

_AH = 0x10; // Bios function $10, set palette.


_AL = 0x12; // Subfunction $12, set a block.
_BX = 0; // First color number of block.
_CX = 256; // Last color number of block.
_ES = Segment; // Segment address of block.
_DX = Offset; // Offset address of block.
geninterrupt(0x10); // Call the interrupt function.
} // End void function SetPallette.

void MakeRainbow(PaletteType P)
{
Byte Count;
for (Count=0; Count<=63; Count++)
{
P[Count].Red = Count;
P[Count].Grn = 0;
P[Count].Blu = 0;
} // End for loop.
for (Count=64; Count<=127; Count++)
{
P[Count].Red = 127 - Count;
P[Count].Grn = Count - 64;

Chapter V Manipulating VGA Colors -5.12-


P[Count].Blu = 0;
} // End for loop.
for (Count=128; Count<=191; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 191 - Count;
P[Count].Blu = Count - 128;
} // End for loop.
for (Count=192; Count<=255; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 0;
P[Count].Blu = 255 - Count;
} // End for loop.
} // End void function MakeRainbow.

void CyclePalette(PaletteType P)
{
Byte Count;
RGBSignature T;

T = P[1];
for(Count=1; Count<=254; Count++)
P[Count] = P[Count + 1];
P[255] = T;
} // End void function CyclePalette.
────────────────────────────────────────────────────────────────────────────────

We will test our new graphics library with program CH05_06. CH05_06 is similar to the
last program which showed a rainbow spectrum fading from red to green to blue. The
previous program used rectangles that appeared very slowly. Now vertical lines will be
used to demonstrate the gradual fading more effectively.

────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_06.CPP shows a continuous spectrum of colors from ***/
/*** red to green to blue, and the gradual fading between colors. ***/
/*** Each color is displayed as a verticle line. ***/
/***********************************************************************/

#include "CLRLIB1.HPP"

void MakeRainbow(PaletteType P);

void main()
{
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
for (Byte Color=0; Color!=255; Color++)
Line(Color, 0, Color, MAXY, Color);
Stop();
EndGfx();
} // End main program CH05_06.CPP.

void MakeRainbow(PaletteType P)
{
for (Byte Count=0; Count<=63; Count++)
{
P[Count].Red = Count;

Chapter V Manipulating VGA Colors -5.13-


P[Count].Grn = 0;
P[Count].Blu = 0;
} // End for loop.
for (Count=64; Count<=127; Count++)
{
P[Count].Red = 127 - Count;
P[Count].Grn = Count - 64;
P[Count].Blu = 0;
} // End for loop.
for (Count=128; Count<=191; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 191 - Count;
P[Count].Blu = Count - 128;
} // End for loop.
for (Count=192; Count<=255; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 0;
P[Count].Blu = 255 - Count;
} // End for loop.
} // End void function MakeRainbow.
────────────────────────────────────────────────────────────────────────────────

Now, check out CH05_07.

────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_07.CPP shows the red, green, and blue spectrum ***/
/*** from right to left across the screen. ***/
/***********************************************************************/

#include "CLRLIB1.HPP"

void SetAllPalette(PaletteType P);


void MakeRainbow(PaletteType P);
void CyclePalette(PaletteType P);

void main()
{
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
for (Byte Color=0; Color!=255; Color++)
Line(Color, 0, Color, MAXY, Color);
Stop();
do
{
CyclePalette(GlobalPalette);
SetAllPalette(GlobalPalette);
} // End do loop.
while( !kbhit() );
EndGfx();
} // End main program CH05_07.CPP.

void SetAllPalette(PaletteType P)
{
unsigned Segment, Offset; // Segment and offset of array.
unsigned char MyPal[768]; // Temporary palette.

Chapter V Manipulating VGA Colors -5.14-


for(int K=0; K<=255; K++)
{
MyPal[K*3] = P[K].Red;
MyPal[K*3+1] = P[K].Grn;
MyPal[K*3+2] = P[K].Blu;
} // End for loop.
Segment = FP_SEG(MyPal);
Offset = FP_OFF(MyPal);

_AH = 0x10; // Bios function $10, set palette.


_AL = 0x12; // Subfunction $12, set a block.
_BX = 0; // First color number of block.
_CX = 256; // Last color number of block.
_ES = Segment; // Segment address of block.
_DX = Offset; // Offset address of block.
geninterrupt(0x10); // Call the interrupt function.
} // End void function SetAllPallette.

void MakeRainbow(PaletteType P)
{
for (Byte Count=0; Count<=63; Count++)
{
P[Count].Red = Count;
P[Count].Grn = 0;
P[Count].Blu = 0;
} // End for loop.
for (Count=64; Count<=127; Count++)
{
P[Count].Red = 127 - Count;
P[Count].Grn = Count - 64;
P[Count].Blu = 0;
} // End for loop.
for (Count=128; Count<=191; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 191 - Count;
P[Count].Blu = Count - 128;
} // End for loop.
for (Count=192; Count<=255; Count++)
{
P[Count].Red = 0;
P[Count].Grn = 0;
P[Count].Blu = 255 - Count;
} // End for loop.
} // End void function MakeRainbow.

void CyclePalette(PaletteType P)
{
Byte Count;
RGBSignature T;

T = P[1];
for(Count=1; Count<=254; Count++)
P[Count] = P[Count + 1];
P[255] = T;
} // End void function CyclePalette.
────────────────────────────────────────────────────────────────────────────────

At first, it will appear that program CH05_07 is identical to CH05_06. Both programs show
a color spectrum that gradually changes from Red to Green to Blue. The difference is
that program CH05_07 will move the spectrum in a continuous cycle from right to left
across the screen.

Chapter V Manipulating VGA Colors -5.15-


The secret of this movement illusion is the CyclePalette function, shown earlier and now
hidden in the COLOR02.HPP file. Check the CyclePalette function again. You will note
that every element in the palette array is moved over to the previous array location, and
the first array element is moved to the end of the palette array.

The result is that the color palette stays the same in a relative sense. This means that
adjacent memory locations in the VGA_RAM occupy the same color codes. These codes,
however, are constantly moving, and thus, we create an illusion of movement by
continuously cycling the color values.

Do you remember the logic of drawing a circle with sin and cos. Well this same logic will
be used in the next program, CH05_08. This time, lines of different rainbow colors will be
displayed in a continuous position on a circle. After the circle is complete, the colors of the
lines will change in such a manner that it resembles circular motion.

The concept is identical to the previous program where function CyclePalette was
introduced to simulate motion. Therefore, there is actually nothing new in this program,
but it is often nice to show the same concepts with several different programming twists.

Chapter V Manipulating VGA Colors -5.16-


────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_08.CPP shows a rotating circle of red, green, and ***/
/*** blue palette colors. ***/
/***********************************************************************/

#include "CLRLIB2.HPP"

void Rotate(int X1, int Y1, int& X2, int& Y2, double R);

void main()
{
int X1, Y1, X2, Y2;

X1 = MIDX + 75;
Y1 = MIDY;
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
double Radians = 0.0;
for(int Degrees=0; Degrees<=359; Degrees++)
{
Radians = Degrees*3.14159/180;
Rotate(X1, Y1, X2, Y2, Radians);
Line(MIDX, MIDY, X2, Y2, Degrees);
} // End for loop.
Stop();
do
{
CyclePalette(GlobalPalette);
SetPalette(GlobalPalette);
} // End do loop.
while( !kbhit() );
EndGfx();
} // End main program CH05_08.CPP.

void Rotate(int X1, int Y1, int& X2, int& Y2, double R)
{
X1 -= MIDX;
Y1 -= MIDY;
X2 = X1 * cos(R) - Y1 * cos(R);
Y2 = X1 * sin(R) - Y1 * sin(R);
X2 += MIDX;
Y2 += MIDY;
} // End void function Rotate.
────────────────────────────────────────────────────────────────────────────────

Program CH05_08 does show a rotating array of rainbow colors, but something does not
look right. As red fades into green, which fades into blue, a true circular spectrum would
fade from blue into red in a continuous fading process. This is not what is happening.
Blue fades into red, which briefly fades into green, and then abruptly switches back to red.
Something is wrong with our fading scheme.

The problem is not difficult to understand or cure. We have casually moved around the
circle without any regard where we would end up. The circle is drawn with 360 lines with a
loop counter variable Degrees. The Degrees variable is also used to indicate the color of
each line. We have called the MakeRainbow function earlier to alter the color palette.
Now function MakeRainbow does a nice job creating a color spectrum for colors 0

Chapter V Manipulating VGA Colors -5.17-


through 255. If we select to pick colors beyond that, the process starts over. This
accounts for the abrupt switch from the gradual fading. There are only 256 colors
available at any one time.

The solution is found with program CH05_09. The trick is that we can only have
256 colors and yet we wish to draw 360 lines. It does not matter how lines are red, green,
blue or some rainbow color in between. Our desire is to have a gradual fading rainbow
spectrum. If we divide 255 by 360 we get a fraction that can be multiplied by the degree
value as it rotates from 0 to 360. In essence we make the loop control variable rotates
from 0 to 360 and the color parameter in the Line function from 0 to 255.

────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_09.CPP shows a rotating circle of red, green, and ***/
/*** blue spectrum colors with colors that show a true continuous ***/
/*** color spectrum. ***/
/***********************************************************************/

#include "CLRLIB2.HPP"

void Rotate(int X1, int Y1, int& X2, int& Y2, double R);

void main()
{
int X1, Y1, X2, Y2;

X1 = MIDX + 75;
Y1 = MIDY;
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
double Radians = 0.0;
for(int Degrees=0; Degrees<=359; Degrees++)
{
Radians = Degrees*3.14159/180;
Rotate(X1, Y1, X2, Y2, Radians);
Line(MIDX, MIDY, X2, Y2, Degrees * (0.70833) );
} // End for loop.
Stop();
do
{
CyclePalette(GlobalPalette);
SetPalette(GlobalPalette);
} // End do loop.
while( !kbhit() );
EndGfx();
} // End main program CH05_09.CPP.

void Rotate(int X1, int Y1, int& X2, int& Y2, double R)
{
X1 -= MIDX;
Y1 -= MIDY;
X2 = X1 * cos(R) - Y1 * cos(R);
Y2 = X1 * sin(R) - Y1 * sin(R);
X2 += MIDX;
Y2 += MIDY;
} // End void function Rotate.
────────────────────────────────────────────────────────────────────────────────

Chapter V Manipulating VGA Colors -5.18-


▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter V Manipulating VGA Colors -5.19-


5.7 MAKING A GRAPHICS IMAGE FADE AWAY

The world loves special effects and showy displays. It is not good enough to switch from
one scene to another scene. We have to do this with all kinds of exciting changes from
one scene to another. We are not exactly ready to do some exotic morphing between two
screens, but at least we can show a technique of making one display fade slowly into
nothingness.

Program CH05_10 starts by fading a solid color Red into black. This is not particularly
impressive, but it does demonstrate the basic technique of using "fading out" with a
graphics program. This program starts by changing color value 0, which is normally black,
to the most intense Red with the SetRed function. Another call to function FadeOut calls
the SetRGB routine 64 times and each times decreases the color intensity of red until it is
totally black.

────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_10.CPP shows a red screen fading to black. ***/
/***********************************************************************/

#include "CLRLIB2.HPP"

void SetRed();
void FadeOut();

void main()
{
StartGfx();
SetRed();
Stop();
FadeOut();
Stop();
EndGfx();
} // End main program CH05_10.CPP.

void SetRed()
{
RGBSignature Signature;

Signature.Grn = 0;
Signature.Blu = 0;
Signature.Red = 63;
SetRGB(0, Signature);
} // End void function SetRed.

void FadeOut()
{
RGBSignature Signature;

Signature.Grn = 0;
Signature.Blu = 0;
for (Byte Color=63; Color>0; Color--)
{
Signature.Red = Color;
SetRGB(0, Signature);

Chapter V Manipulating VGA Colors -5.20-


delay(100);
} // End for loop.
} // End void function FadeOut.
────────────────────────────────────────────────────────────────────────────────

Chapter V Manipulating VGA Colors -5.21-


Program CH05_10 was not so tough, but then again, we used a screen with one solid
color. How about a screen with a variety of shades? Well, creating such a screen is not
difficult. We call upon our rainbow spectrum program and create many different shades of
the rainbow. Take a look at program CH05_11 and see if the FadeOut function makes
sense. It is more complex than the previous FadeOut function, but the logic is essentially
the same.

────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_11.CPP shows a red screen fading to black. ***/
/***********************************************************************/

#include "CLRLIB2.HPP"

void FadeOut(PaletteType GlobalPalette);

void main()
{
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
for (Byte Color=0; Color!=255; Color++)
Line(Color, 0, Color, MAXY, Color);
Stop();
FadeOut(GlobalPalette);
Stop();
EndGfx();
} // End main program CH05_11.CPP.

void FadeOut(PaletteType GlobalPalette)


{
for(Byte Count1=0; Count1<=63; Count1++)
{
for(Byte Count2=0; Count2<=255; Count2++)
{
if(GlobalPalette[Count2].Red >0 )
GlobalPalette[Count2].Red--;
if(GlobalPalette[Count2].Blu >0 )
GlobalPalette[Count2].Blu--;
if(GlobalPalette[Count2].Grn >0 )
GlobalPalette[Count2].Grn--;
} // End for loop.
SetPalette(GlobalPalette);
delay(100);
} // End for loop.
} // End void function FadeOut.
────────────────────────────────────────────────────────────────────────────────

Function FadeOut now has a nested loop. We still go through 64 iterations changing the
potentially most intense color to black, but we need to consider many different colors. This
is the reason for the nested loop. Each time through the outer loop we repeat an iteration
of all 256 colors and decrement the Red, Green, and Blue intensity of each color in the
global palette. The decrement only happens if the color is not already at 0. After doing
this process 64 times every color on the screen is altered to black, and the whole picture
has faded.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter V Manipulating VGA Colors -5.22-


Chapter V Manipulating VGA Colors -5.23-
5.8 PLASMA, AN ADVANCED COLOR MANIPULATION

Some really attractive color changes can be achieved with the routines introduced in this
chapter, along with a good understanding of recursion. A program of considerable
complexity will be shown shortly that combines recursion with sophisticated palette
manipulation to make a Plasma. Essentially this is a splattering of colors that change
rhythmically through smooth, fluid shapes with the colors of the rainbow.

We will attack this program in two stages, and the first stage is to understand how the fill
up the screen recursively. Program CH05_12 will fill up the screen in a rotating clockwise
fashion, filling up little red squares that keep getting bigger. The general approach should
remind you of the FloodFill function.

────────────────────────────────────────────────────────────────────────────────
/***********************************************************************/
/*** CH05_12.CPP uses recursive techniques to fill ***/
/*** the screen with the color red. Alter the delay time for your ***/
/*** particular computer so that you can see the recursive sequence. ***/
/***********************************************************************/

#include "GFXLIB3.HPP"

void SubDivide(int X1, int Y1, int X2, int Y2);

void main()
{
StartGfx();
SubDivide(0, 0, MAXX, MAXY);
Stop();
EndGfx();
} // End main program CH05_12.CPP.

void SubDivide(int X1, int Y1, int X2, int Y2)


{
int X, Y;
Byte Color;

delay(1);
if( ! ((X2 - X1 < 2) && (Y2 - Y1 < 2)) )
{
X = (X1 + X2) / 2;
Y = (Y1 + Y2) / 2;
Pixel(X, Y, 4);
SubDivide(X1, Y1, X, Y);
SubDivide( X, Y1, X2, Y);
SubDivide( X, Y, X2, Y2);
SubDivide(X1, Y, X, Y2);
} // End if.
} // End void function SubDivide.
────────────────────────────────────────────────────────────────────────────────

The general logic of this program is to subdivide the screen into four big rectangles and

Chapter V Manipulating VGA Colors -5.24-


draw those areas with four function calls. Each smaller rectangle is again subdivided.
This process continues until subdividing is at the pixel level when additional subdividing is
no longer possible. It will help to adjust the delay value so that the recursive process can
be better viewed. Delay(1) seems to work well with a 486DX-50Mhz, but your computer
will probably be faster or slower. Many school computers may not require the delay
feature at all.

Was program CH05_12 pretty dull? It was! If you did not think that was dull, then you
probably will go bananas with program CH05_13. With this program the screen will be
filled in with the same recursive logic. This time, however, the color of each pixel is
carefully manipulated to create some neat random rainbow color patterns. After <Enter>
is pressed, the shapes will grow and shrink as the rainbow colors fade in and out. Try it, it
is pretty neat.

────────────────────────────────────────────────────────────────────────────────
/************************************************************************/
/*** CH05_13.CPP uses recursive techniques to fill the ***/
/*** the screen and various palette commands to alter existing colors ***/
/*** in a manner that creates an interesting graphics display. ***/
/************************************************************************/

#include <stdlib.h>
#include "CLRLIB2.HPP"

const MAX_COLOR = 255; // Highest color number in VGA graphics.


const MIN_COLOR = 1; // Minimum color number beyond black.

void NewCol(int XA, int YA, int X, int Y, int XB, int YB);
void SubDivide(int X1, int Y1, int X2, int Y2);

void main()
{
StartGfx();
MakeRainbow(GlobalPalette);
SetPalette(GlobalPalette);
randomize();
GlobalPalette[0].Red = 0;
GlobalPalette[0].Grn = 0;
GlobalPalette[0].Blu = 0;
Pixel(0, 0, MAX_COLOR);
Pixel(MAXX, MAXY, MIN_COLOR);
Pixel(0, MAXY, MIN_COLOR);
SubDivide(0, 0, MAXX, MAXY);
Stop();
do
{
CyclePalette(GlobalPalette);
SetPalette(GlobalPalette);
delay(10);
} // End do loop.
while( !kbhit() );
EndGfx();
} // End main program CH05_13.

void NewCol(int XA, int YA, int X, int Y, int XB, int YB)
{
Byte Color;

Chapter V Manipulating VGA Colors -5.25-


Color = abs(XA - XB) + abs(YA - YB);
Color = random(Color * 2) - Color;
Color = Color + (GetPixel(XA, YA) + GetPixel(XB, YB) + 1) /2;
if (Color < 1)
Color = 1;
else
if (Color > MAX_COLOR)
Color = Color % MAX_COLOR;
if (GetPixel(X,Y) == 0)
Pixel(X,Y, Color% MAX_COLOR);
} // End void function NewCol.

void SubDivide(int X1, int Y1, int X2, int Y2)


{
int X, Y;
Byte Color;

if( ! ((X2 - X1 < 2) && (Y2 - Y1 < 2)) )


{
X = (X1 + X2) / 2;
Y = (Y1 + Y2) / 2;
Pixel(X, Y, 4);
SubDivide(X1, Y1, X, Y);
SubDivide( X, Y1, X2, Y);
SubDivide( X, Y, X2, Y2);
SubDivide(X1, Y, X, Y2);
} // End if.
} // End void function SubDivide.
────────────────────────────────────────────────────────────────────────────────

The logic of program CH05_12 initially is the same as CH05_13. Recursively, the entire
screen is filled in. Function Subdivide is more intricate and makes four calls to a new
routine, called NewColor. The result is that the screen is not just filled in with a solid color,
as was the case with program CH05_12. The screen still fills up, but it is done with a color
spectrum of colors.

Random starting locations create different patterns each time, but additional colors are
controlled in a manner that creates gradual color change. The technique of the
CyclePalette function is used to create movement of a different nature. Before, neatly
placed vertical lines made the entire screen move to the left. Now the same cycle of
switching colors causes a color shift in many different directions, but in a very noticeable
pattern that repeats itself.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

5.9 SUMMARY

Chapter V Manipulating VGA Colors -5.26-


Understanding and controlling color is a cornerstone skill with graphics. Early text
programs existed in a dull monochrome world, and the introduction of color monitors with
color adapter cards caused incredible changes in the way that people viewed software
programs.

In graphics mode 0x13 we have access to 256 colors at any one time, yet there are many
more colors that can be selected. Each one of the 256 colors is a combination of Red,
Green and Blue intensities that we call the color's RGB Signature. When you write
graphics programs, you have access to 256 default colors, but it is possible to alter the
RGB Signature you desire. Since each one of the basic colors has 64 levels of intensity, it
results in 64 X 64 X 64 = 262,144 different RGB combinations.

The color work horse is the SetRGB function which gives you access to the RGB
Signature of a given color. Several BIOS functions are used to alter the default RGB
value of a specified color.

Function SetPalette controls the entire color palette with BIOS functions.

Function MakeRainbow manipulates the color intensities of Red, Green and Blue in such
a manner that gradual fading occurs between the basic color in a manner that resembles
the rainbow spectrum.

With the help of a global palette array, it becomes possible to change colors instantly and
create interesting special effects. One such effect, with the help of the CyclePalette
function, causes colors to change instantly. This gives the effect of motion as values are
cycled through the global palette array.

There were not many new functions introduced in this chapter, but the four functions that
were introduced allow considerable control over the graphics program that you create.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter V Manipulating VGA Colors -5.27-


Chapter V Manipulating VGA Colors -5.28-

You might also like