Classic Computer Magazine Archive COMPUTE! ISSUE 67 / DECEMBER 1985 / PAGE 99

Million-Color Palette For IBM PC & PCjr

John Klein and Jeff Klein

It's amazing but true—with this stunning technique you can generate more than a million apparent color variations on a PCjr. You can even display 256 colors simultaneously. The effects are less dramatic on a PC, but it's still possible to generate many more than the standard 16 colors. The programs require an Enhanced Model PCjr or a PC with color/graphics card, plus a TV set or composite color monitor. The palette is more limited on an RGB monitor, but still impressive.

No longer is your PC or PCjr restricted to a palette of 16 colors and the inability to display them all in higher resolutions. Now you can choose to display 256 colors from a palette of over 1,000,000 colors in high resolution, and display an entire palette of 256 colors in medium resolution. And each color is distinct and solid.

The secret is a combination of a technique called tile painting and the trick of fooling a TV or composite monitor into displaying new solid colors. To understand how it works, let's examine the way graphics are stored, changed, and displayed on the IBM video screen.

A Byte Of Pixels

Graphics images are stored differently in the computer's memory for each different graphics mode or screen. In its simplest form, the color of each pixel—the smallest controllable dot on the screen—is stored in a section of memory. This video memory is arranged by its location or coordinates on the screen. The image you see on the screen, therefore, is a copy of the contents of video memory. (Actually, screens are divided into several layers when stored in memory, but that's not important for this discussion; we're concerned with how the colors of pixels are represented in memory, not how each pixel is arranged.)

To figure out how many pixels can be represented in a byte of memory, remember that a byte is made up of eight bits, and a bit is the smallest unit of memory (a bit is either a zero or a one). Simply divide the amount of memory required for a certain screen mode by the number of pixels on the screen. The memory requirements for each screen mode are shown in Table 1.

Table 1: Screen Mode Memory Requirements

Screen ModeResolutionNumber of ColorsMemory per ScreenPixels/ByteBits/pixel
1320 X 200416K*42
2640 X 200216K81
3160 X 2001616K24
4320 X 200416K42
5320 X 2001632K24
6640 X 200432K42

*1K = 1024 bytes

Remember that RGB stands for the three primary colors of light: red, green, and blue. All colors can be made by mixing these three primary colors. That's why RGB monitors, color TVs, and composite color monitors have three electron guns inside their picture tubes, instead of the single gun found in black and white TVs and monochrome monitors. There is a red gun, a green gun, and a blue gun, all of which are controlled by the computer to produce color. If none of the guns is lighting a pixel, the pixel appears black.

Colors are represented in memory by arranging bits to denote which electron guns should be turned on or off when lighting the corresponding pixel. For instance, if a certain pixel is supposed to be blue, the group of bits representing that pixel in memory shows the blue gun is on and the others off. (A bit set to 1 means on, and 0 means off.) All the possible combinations of the three electron guns account for eight colors. To get eight more colors, the intensity, also called luminance, is varied by mixing a little white with the first eight colors. That's why the IBM PC and PCjr have a total of 16 color variations: two shades each of eight colors.

Table 2 shows how each of the 16 colors is represented. Remember that each bit turns an electron gun. either on or off. Notice how many bits it takes to represent all the possible combinations. It takes four bits, or half of a byte (sometimes called a nybble) to represent all 16 colors. So, all screen modes which use four bits to represent a pixel are 16-color modes. Only four-color combinations are possible with two bits, and only two combinations are possible with one bit. That's why some screen modes can display only four or two colors at a time.

The PCjr's PALETTE command can switch which colors are being displayed, but it can't add any more colors. You're still limited to the maximum number of colors for each screen mode.

Tile Painting

Once you're familiar with how pixels are represented in video memory, the technique of tile painting is easier to understand. Tile painting uses the PAINT command found in PCjr Cartridge BASIC and IBM BASICA to fill the bytes of screen memory with certain patterns of ones and zeros. This pattern is programmable, and it represents what is displayed on the TV or monitor. Instead of painting with the actual color, you paint with the bit pattern of the color. By using bit patterns, you can actually paint with more than one color around some specified border color.

PAINT (x, y), CHR$ (bit pattern) + CHR$ (bit pattern) + …, boundary color

The bit pattern consists of eight bits, so its decimal equivalent can range from 0 to 255 (integers only). The bit pattern must represent the colors of the pixels per byte of the screen mode you're using. This means four colors can be painted at a time in SCREEN 4 and 6, while only two colors can be painted at a time in SCREEN 3 and 5. The color patterns are put in memory next to each other as vertical lines on the screen. The following example paints SCREEN 1 with vertical bands of blue and green lines:

10 SCREEN 1 : CLS
20 PAINT (l, l), CHR$ (102), 3

The reason why the lines are blue and green can be seen when the number 102 is expressed in binary, revealing the bit pattern:

102 = 01100110

Table 3 shows how decimal 102 is derived from this binary number.

Table 2: Color Bits

Bits
LuminanceRedGreenBlueColor
0000Black
0001Blue
0010Green
0011Cyan
0100Red
0101Magenta
0110Brown
0111Light Gray
1000Dark Gray
1001Light Blue
1010Light Green
1011Light Cvan
1100Pink
1101Light Magenta
1110Yellow
1111White

Table 3: Converting Binary to Decimal

Value for each digit128 643216842101 = 0001 = blue
10 = 0010 = green
Binary01100110
128 * 0 = 0
64 * 1 = 64
32 * 1 = 32
16 * 0 = 0
8 * 0 = 0
4 * 1 = 4
2 * 1 = 2
1 * 0 = 0
			      		   102

SCREEN 1 stores four pixels per byte, so the pattern works out to these colors:

01100110
bluegreenbluegreen

But here's where things get tricky. If the computer is plugged into a color TV or composite color monitor (not an RGB monitor), you won't see the blue and green vertical lines that are supposed to be there. Instead, you'll see a solid bar of color that's sort of blue. And the blue is not one of the normal 16 colors available. It is a new color—one of the 256 shades that can be created this way on SCREEN 1 of the PCjr, and one of the 16 shades that can be created on SCREEN 1 of the PC.

What's happening here is something called artifacting. This effect takes advantage of the limited resolution of TVs and composite color monitors. When two very small pixels are placed next to each other on these screens, there isn't enough resolution to display them properly. As a result, the pixels tend to blend together and create a false color—an artifact color. The color wouldn't be visible if the screen had more resolution, which is why you usually need a TV or composite color monitor to observe this effect. RGB monitors have enough resolution to display the pixels as they're supposed to appear.

Creating New Colors

If the binary pattern 10 01 10 01 is used in the above example instead of 01 10 01 10, the shade is slightly different—blue-green-blue-green does not appear the same as green-blue-green-blue on a color TV or or composite monitor. They mix differently to create an entirely new shade of blue-green.

The PC can mix a fewer number of colors than the PCjr for two reasons. The first is that the PC has only two graphics modes, SCREEN 1 and SCREEN 2. Tile painting produces only 16 colors in SCREEN 1 and five shades of gray in SCREEN 2. Still, these are more colors than what are normally available in these modes. The second reason is that the PC does not have a PALETTE command as the PCjr does. The PC does have a second color palette in SCREEN 1, but the mixed colors look the same as the first palette on a color TV or composite monitor.

On SCREEN 6, available only in PCjr Cartridge BASIC, there are four pixels per byte. Because the pixels are very small (640 X 400 per screen), vertical bands of four different colors can be mixed to form shades of any color. In medium resolution, 320 X 200, vertical bands of two different colors form new solid colors. Tile painting doesn't work in low resolution, 160 X 200, because the pixels are too large.

For a demonstration of how closely spaced vertical bands create new colors, enter and run Program 1 (for the PCjr only). Using the LINE command instead of PAINT, line 20 fills the first 40 columns of SCREEN 6 with purple bands on every line that is a multiple of four: 0, 4, 8, 12, and so on. Line 30 fills the next 40 columns with the same color on every vertical line that is a multiple of four plus one: 1, 5, 9,13, and so on. Then the program fills the screen with lines of the other two colors available in SCREEN 6. The result, on a TV or composite monitor, is 12 different colors instead of the four you'd expect.

Adding up all the different combinations of four colors results in 256 shades, and all 256 can be displayed on the screen at the same time. When you take into account that the PALETTE command can change any of the four basic colors into any of the other 16 colors, there are 1,092,016 possible shades in high resolution.

Program 2 (for the PCjr only) proves it can be done. This program displays 256 shades on the screen by drawing the vertical lines using only the first four colors. After painting all the shades, it randomly changes the palettes. If the colors selected by the PALETTE command were never repeated, it would take about an hour and a half to cycle through all one million colors.

Colors In Other Modes

In SCREEN 5, there are 256 possible colors, as demonstrated by Program 3 (also for the PCjr only). In SCREEN 4 and SCREEN 1, which are the same resolution, only four basic colors are available, so tile painting lets us display up to 16 hues simultaneously. With the PALETTE command on the PCjr, you can select these 16 colors from 256 possibilities. Program 4 displays 16 shades, then uses the PALETTE command to get the rest. Vertical bands with four colors don't blend in this mode, so somehow bands of two must be painted. The secret is in line 40. Since there are four pixels per byte, the last half of the byte has to be reflected in the first half. This technique insures that only two colors are in each band of four. The first half is the same as the last half, so the first band of two will be the same as the last band of two. Program 4 will also work on the PC, but without the PALETTE command (line 80) you are limited to only 16 colors.

Tile painting doesn't work correctly in SCREEN 2, high resolution with two colors, because this screen is always in black and white. However, you can get five shades of gray, as shown by Program 5(for PC and PCjr). Solid lines form the brightest white. Lines separated by one line of black give the next-brightest white. Lines separated by two or three lines of black yield the next two shades. The middle gray can't be displayed when using the PAINT command, because it's not possible to create a bit pattern that represents two blacks and then a white. Table 4 shows which bit patterns generate the various shades of gray.

Tile painting doesn't work at all in SCREEN 3 because the pixels are too large. To see a demo of tile painting in SCREEN 1 for the PC or PCjr, run Program 6. It fills the screen with circles, displaying up to 256 colors on the PCjr and 16 colors on the PC.

Program 7, for the PC and PCjr with an RGB monitor, demonstrates the usefulness of the many new colors in a fascinating experiment. It uses SCREEN 1 and tile painting, but in a different way than seen above. Closely spaced vertical lines don't blend together on an RGB monitor, so the previous technique won't work. So instead, Program 7 uses the second part of the PAINT, command. The first CHR$ (bit pattern) controls the horizontal line above the second CHR$ (bit pattern). Now the PAINT command can control the horizontal as well as the vertical lines, forming a checkerboard.

Although the checkerboard blends the lines together to create new colors, the colors aren't as solid as those produced by vertical lines on a TV or composite monitor. Indeed, the effect won't look very pretty on a TV or composite monitor; it's passable on an RGB.

Program 8 (for the PCjr only) employs the same technique as Program 7, but uses SCREEN 5 on the PCjr to create all 240 possible colors on the RGB monitor at once. The PALETTE command won't create any new shades here, because all 16 colors and their possible combinations are displayed.

Program 9 (for the PCjr only) is the same as the last two, but uses SCREEN 6 on the PCjr. It does a much better job of blending, although the colors still aren't perfectly solid. Ten shades are displayed at once and the PALETTE command cycles through all 240 possible shades.

Painting Your Own Programs

To use the new colors in your own programs, simply choose one of the following example programs which uses the same screen mode. Table 5 summarizes the programs and the number of color variations possible in each.

If you're programming on a PCjr, remove the lines that deal with changing the palette. You can change palettes on the PCjr in direct mode until most of the shades you want are on the screen. We suggest not changing the palettes in the 16-color modes, because the unchanged palette creates the widest variety of colors with the least amount of extra work.

In four-color modes, the screen displays 16 shades. Pick the color you want, then refer to Table 6 for the corresponding decimal and hexadecimal translations of the bit patterns required.

If you're using a 16-color mode with a TV or composite monitor, the screen displays 256 shades and the bit patterns can be figured as follows: First choose the color. Then, starting at zero at the upper-left corner of the screen, count in hex across the screen to the column with the color you want. Remember to count in hex (0 through 9, then A through F). Then, still working in hex, count the number of rows down to the color you want. These two numbers form the bit pattern of the chosen color. Use them as shown below:

PAINT (x, y), CHR$ (&H row column), boundary

Example: If row = A and column = 2, then

PAINT (x, y), CHR$ (&HA2), boundary

If you're using an RGB monitor with a 16-color mode, choose which two of the 16 colors to make into the checkerboard. Then write each of their numbers in hex (0-F). Use these numbers as the bit pattern as shown below. Switching the first and second colors will create the checkerboard.

PAINT (x, y), CHR$&H 1st color 2nd color) + CHR$ (&H 2nd color 1st color), boundary

Example: If 1st color = B (light cyan) and 2nd color = 2 (green), then

PAINT (x, y), CHR$ (&HB2) + CHR$ (&H2B)

IBM boasts of only the checkerboard technique for shading colors. I find the other method more fascinating. Now you can enhance your screens with a new palette of bright, solid colors, which formerly were thought to be impossible on an IBM.

Table 4: Gray Scales in SCREEN 2

BinaryDecimalHexShade
color 1 =1 1 1 1 1 1 1 1= 256 =&HFF = White
0 1 0 1 0 1 0 1= 85 =&H55 =Dull White
(Not accessible)=Middle Gray
0 0 0 1 0 0 0 1= 17 =&H11 = Dark Gray
color 0 =0 0 0 0 0 0 0 0= 0 =&H00 =Black

Table 5: Program Descriptions

ProgramScreen ModeMax ColorsColors per ScreenPC or PCjrDisplay Device
Program 1SCREEN 61, 092, 016256PCjrTV or CC *.
Program 2SCREEN 61, 092, 016256PCjrTV or CC
Program 3SCREEN 5256256PCjr TV or CC
Program 4SCREEN 1 or 425616PCjrTV or CC
SCREEN 11616PC TV or CC
Program 5SCREEN 255PC/PCjr TV or CC
Program 6SCREEN 125616PCjrTV or CC
1616PCTV or CC
Program 7SCREEN 1 or 424010PCjrRGB
SCREEN 12010PC RGB
Program 8SCREEN 5240240PCjr RGB
Program 9SCREEN 624010PCjr RGB

* CC = Composite color monitor

Table 6: Translations of Bit Patterns in Four-Color Modes

TV or CompositeRGB
Shade PositionDecimalHexDecimalHex
00&H000 + 0&H00 + &H00
117&H1117 + 70&H11 + &H44
234&H2234 + 136&H22 + &H88
451&H3351 + 204&H33 + &HCC
570&H4470 + 17&H44 + &H11
6102&H66102 + 153&H66 + &H99
7119&H77119 + 221&H77 + &HDD
8136&H88136 + 34&H88 + &H22
9153&H99153 + 102&H99 + &H66
10176&HAA176 + 176&HAA + &HAA
11187&HBB187 + 238&HBB + &HEE
12204&HCC204 + 51&HCC + &H33
13221&HDD221 + 119&HDD + &H77
14238&HEE238 + 187&HEE + &HBB
15255&HFF255 + 255&HFF + &HFF

For instructions on entering these listings, please refer to "COMPUTE!'s Guide to Typing In Programs" published bimonthly in compute!. Also, see Table 5 for a description of the programs.

Program 1: PCjr

IE 10 CLEAR, , ,  32768!  :  SCREEN 6 : CLS : KEY OFF
DJ 20 FOR X = 0 TO 40 STEP 4 :  LINE (X, 0) - (X, 200), 3 : NEXT
JH 30 FOR X = 41 TO 80 STEP 4 : LINE (X, 0) - (X, 200), 3 : NEXT
1A 40 FOR X = 82 TO 120 STEP 4 : LINE (X, 0) - (X, 200), 3 : NEXT
GJ 50 FOR X = 123 TO 160 STEP 4 : LINE (X, 0) - (X, 200), 3 :  : NEXT
FA 60 FOR X = 160 TO 200 STEP 4 : LINE (X, 0) - (X, 200), 1 : NEXT
HN 70 FOR X = 201 TO 240 STEP 4 : LINE (X, 0) - (X, 200), 1 : NEXT
PO 80 FOR X = 242 TO 280 STEP 4 : LINE (X, 0) - (X, 200), 1 : NEXT
NH 90 FOR X = 283 TO 320 STEP 4 : LINE (X, 0) - (X, 200), 1 : NEXT
00 100 FOR X = 320 TO 360 STEP 4 : LINE (X, 0) - (X, 200), 2 : NEXT
MN 110 FOR X = 361 TO 400 STEP 4 : LINE (X, 0) - (X, 200), 2 : NEXT
OL 120 FOR X = 402 TO 440 STEP 4 : LINE (X, 0) - (X, 200), 2 : NEXT
G6 130 FOR X = 443 TO 480 STEP 4 : LINE (X, 0) - (X, 200), 2 : NEXT

Program 2 : PCjr

IE 10 CLEAR,  ,  , 32768! : SCREEN 6 : CLS : KEY OFF
LO 20 RANDOMIZE TIMER : Z =  - l : A = INT (640/16)
HB 30 FOR Y = 0 TO 15
DE 40 FOR X = 0 TO 15 : Z = Z + 1
ED 50 LINE (X * A, Y * 12.5) - (X * A + A, Y * 12.5 + 12.5), 3, B
PC 60 IF Z < > 0 THEN PAINT (X * A + 1, Y * 12.5 + l), CHR * (Z), 3
MH 70 LINE (X * A, Y * 12.5) - (X * A + A, Y * 12.5 + 12.5), 0, B
JI 80 NEXT X, Y
DD 90 PALETTE RND * 3, RND * 15 : GOTO 90

Program 3 : PCjr

HK 10 CLEAR, , , 32768! : SCREEN 5 : CLS : KEY OFF
BB 20 RANDOMIZE TIMER : Z = - l : A = INT (320/16)
HB 30 FOR Y = 0 TO 15
DE 40 FOR X = 0 TO 15 : Z = Z + 1
ED 50 LINE (X * A, Y * 12.5) - (X * A + A, Y * 12.5 + 12.5), 3, B
PC 60 IF Z< >0 THEN PAINT (X * A + 1, Y * 12.5 + 1), CHRS (Z), 3
MH 70 LINE (X * A, Y * 12.5) - (X * A + A, Y * 12.5 + 12.5), 0, B
JI 80 NEXT X, Y
KC 90 GOTO 90

Program 4: PC/PCjr

CA 10 SCREEN 1 : CLS : KEY OFF : COLOR,0
MM 20 RANDOMIZE VAL(RIGHT$(TIME$, 2)) : Z = - l : A = INT (320/16): Y = 0
DD 30 FOR X = 0 TO 15 : Z = Z + 1
II 40 LINE (X * A, 0) - (X * A + A, 200), 3
Kl 50 IF Z<>0 THEN PAINT (X * A + 1, 1), CHR$ (Z + Z * 16), 3
CD 60 LINE (X * A, 0) - (X * A + A, 200, 0, B
QM 70 NEXT X
GL 80 PALETTE RND * 3, RND * 15: 60 T0 80: ' Remove this line for PC

Program 5: PC/PCjr

CF 10 SCREEN 2, 1 : CLS: KEY OFF
MJ 20 FOR X = l TO 100: LINE (X, l) - (X, 200),1 : NEXT X
DH 30 FOR X = 101 TO 200 STEP 2: LINE (X, 1) - (X, 200), 1 : NEXT X
HN 40 FOR X = 201 TO 300 STEP 3: LINE (X, 1) - (X, 200), 1 : NEXT X
KD 50 FOR X = 301 TO 400 STEP 4: LINE (X, 1) - (X, 200), 1 : NEXT X
IE 60 GOTO 60

Program 6: PC/PCjr

CA 10 SCREEN 1: CLS: KEY OFF: COLOR
LD 20 RANDOMIZE VAL(RIGHT$(TIME$, 2))
GD 30 X = RND * 320: Y = RND * 200: R = RND* 10 + 10:
      TILE = INT(RND * (15) + 1)
BM 40 CIRCLE (X, Y), R, 3:PAINT (X, Y),CHR$ (TILE + TILE * 16), 3 :
      CIRCLE (X, Y), R, 0
AE 50 IF RND * 10>B THEN PALETTE R ND * 3 + 1, RND * 15:’
      Remove this line for PC
EA 60 GOTO 20

Program 7: PC/PCjr

CA 10 SCREEN 1: CLS: KEY OFF: COLOR, 0
CD 20 RANDOMIZE VAL(RIGHT$ (TIME$, 2)): Z = -1: A = INT (320/16) :
      Y = 0: C = 0
DD 30 FOR X = 0 TO 15: Z = Z + 1
NN 40 LINE (X * A, 0) - (X * A + A, 200), 3, B: Y = Z + Z * 16 :
      Q = Y * 4: R = INT (Q/256): Q = Q-R * 256 + R
KF 50 IF Z <> THEN PAINT (X * A + 1, 1),CHR$ (Y) + CHR$ (Q), 3
CD 60 LINE (X * A, 0) - (X * A + A, 200), 0, B
QM 70 NEXT X
GL 80 PALETTE RND * 3, RND * 15: GOTO 80:’ Remove this line for PC
EN 90 C = l-C : COLOR, C : FOR Z = l TO 100: NEXT: GOTO 80:’
      Remove this line for PC

Program 8: PCjr

HK 10 CLEAR, , , 32768! : SCREEN 5 : CL SS : KEY OFF
BB 20 RANDOMIZE TIMER:Z = -l: A = INT (320/16)
HB 30 FOR   Y = 0   TO   15
DE 40 FOR   X = 0   TO   15: Z = Z + 1
JD 50 LINE    (X * A, Y * 12.5) - (X * A + A, Y * 12.5 + 12.5), 3, B:
      Q = (Z) * l6 : R = INT(Q/256):Q = Q - R * 256 + R
DC 60 IF Z<>0 THEN PAINT (X * A + 1, Y * 12.5 + 1), CHR$(Z) + CHR; (Q), 3
MH 70 LINE (X * A, Y * 12.5) - (X * A + A, Y * 12.5 + 12.5), 0, B
JI 80 NEXT X, Y
KC 90 GOTO 90

Program 9: PCjr

IE 10 CLEAR, , , 32768! : SCREEN 6 : CLS : KEY OFF
BB 20 RANDOMIZE TIMER : Z = -1: A = INT (640/16) : Y = 0
DD 30 FOR X = 0 TO 15 : Z = Z + 1
MN 40 LINE (X * A, 0)-(X * A + A, 200), 3,  B: Y = Z + Z * 16 :
      Q = Y * 4: R = INT(Q/256):Q = Q - R * 256 + R
KF 50 IF Z < >0 THEN PAINT (X * A + 1, 1), CHR$ (Y) + CHR$ (Q), 3
CD 60 LINE (X * A, 0) - (X * A + A, 200), 0, B
QM 70 NEXT X
BE 30 PALETTE RND * 3, RND * 15: GOTO 80