abrash-black-book/55-02.md
2013-12-30 20:26:41 +11:00

121 lines
5.1 KiB
Markdown

So it's perfectly reasonable to maintain 24 bits of color resolution,
and X-Sharp represents colors internally as ideal, device-independent
24-bit RGB triplets. All shading calculations are performed on these
triplets, with 24-bit color precision. It's only after the final 24-bit
RGB drawing color is calculated that the display adapter's color
capabilities come into play, as the X-Sharp function
**ModelColorToColorIndex()** is called to map the desired RGB color to
the closest match the adapter is capable of displaying. Of course, that
mapping is adapter-dependent. On a 24-bpp device, it's pretty obvious
how the internal RGB color format maps to displayed pixel colors:
directly. On VGAs with 15-bpp Sierra Hicolor DACS, the mapping is
equally simple, with the five upper bits of each color component mapping
straight to display pixels. But how on earth do we map those
16,000,000-plus RGB colors into the 256-color space of a standard VGA?
This is the "color definition" problem I mentioned at the start of this
chapter. The VGA palette is arbitrarily programmable to any set of 256
colors, with each color defined by six bits each of red, green, and blue
intensity. In X-Sharp, the function **InitializePalette()** can be
customized to set up the palette however we wish; this gives us nearly
complete flexibility in defining the working color set. Even with
infinite flexibility, however, 256 out of 16,000,000 or so possible
colors is a pretty puny selection. It's easy to set up the palette to
give yourself a good selection of just blue intensities, or of just
greens; but for general color modeling there's simply not enough palette
to go around.
One way to deal with the limited simultaneous color capabilities of the
VGA is to build an application that uses only a subset of RGB space,
then bias the VGA's palette toward that subspace. This is the approach
used in the DEMO1 sample program in X-Sharp; Listings 55.2 and 55.3 show
the versions of **InitializePalette()** and **ModelColorToColorIndex()**
that set up and perform the color mapping for DEMO1.
**LISTING 55.2 L55-2.C**
/* Sets up the palette in mode X, to a 2-2-2 general R-G-B organization, with
64 separate levels each of pure red, green, and blue. This is very good
for pure colors, but mediocre at best for mixes.
------------------------
|0 0 | Red|Green| Blue |
------------------------
7 6 5 4 3 2 1 0
------------------------
|0 1 | Red |
------------------------
7 6 5 4 3 2 1 0
------------------------
|1 0 | Green |
------------------------
7 6 5 4 3 2 1 0
------------------------
|1 1 | Blue |
------------------------
7 6 5 4 3 2 1 0
Colors are gamma corrected for a gamma of 2.3 to provide approximately
even intensity steps on the screen.
*/
#include <dos.h>
#include "polygon.h"
static unsigned char Gamma4Levels[] = { 0, 39, 53, 63 };
static unsigned char Gamma64Levels[] = {
0, 10, 14, 17, 19, 21, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34,
35, 36, 37, 37, 38, 39, 40, 41, 41, 42, 43, 44, 44, 45, 46, 46,
47, 48, 48, 49, 49, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55,
56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63,
};
static unsigned char PaletteBlock[256][3]; /* 256 RGB entries */
void InitializePalette()
{
int Red, Green, Blue, Index;
union REGS regset;
struct SREGS sregset;
for (Red=0; Red<4; Red++) {
for (Green=0; Green<4; Green++) {
for (Blue=0; Blue<4; Blue++) {
Index = (Red<<4)+(Green<<2)+Blue;
PaletteBlock[Index][0] = Gamma4Levels[Red];
PaletteBlock[Index][1] = Gamma4Levels[Green];
PaletteBlock[Index][2] = Gamma4Levels[Blue];
}
}
}
for (Red=0; Red<64; Red++) {
PaletteBlock[64+Red][0] = Gamma64Levels[Red];
PaletteBlock[64+Red][1] = 0;
PaletteBlock[64+Red][2] = 0;
}
for (Green=0; Green<64; Green++) {
PaletteBlock[128+Green][0] = 0;
PaletteBlock[128+Green][1] = Gamma64Levels[Green];
PaletteBlock[128+Green][2] = 0;
}
for (Blue=0; Blue<64; Blue++) {
PaletteBlock[192+Blue][0] = 0;
PaletteBlock[192+Blue][1] = 0;
PaletteBlock[192+Blue][2] = Gamma64Levels[Blue];
}
/* Now set up the palette */
regset.x.ax = 0x1012; /* set block of DAC registers function */
regset.x.bx = 0; /* first DAC location to load */
regset.x.cx = 256; /* # of DAC locations to load */
regset.x.dx = (unsigned int)PaletteBlock; /* offset of array from which
to load RGB settings */
sregset.es = DS; /* segment of array from which to load settings */
int86x(0x10, &regset, &regset, &sregset); /* load the palette block */
}