雖然大部分的 GDI 應用程式通常會搭配邏輯調色盤使用色彩索引,但通常較適合 OpenGL 應用程式使用 RGBA 模式。 其效果優於數個效果的色彩對應,例如陰影、光源、霧和紋理對應。
RGBA 模式會使用紅色、綠色和藍色 (R、G 和 B) 色彩值,一起指定顯示器中每個圖元的色彩。 R、G 和 B 值會指定每個色彩的強度(紅色、綠色和藍色):值的範圍從 0.0(最不強烈)到 1.0(最強烈)。 每個元件的位數會根據所使用的硬體而有所不同(可能為 2、3、5、6 和 8 位)。顯示的色彩是三個色彩值總和的結果。 如果這三個值都是0.0,結果會是黑色。 如果這三個值都是 1.0,結果會是白色。 其他色彩是 R、G 和 B 值組合的結果,其落在 0 到 1.0 之間。 A (alpha) 位不會用來指定色彩。
標準 super-VGA 顯示器會使用每個圖元有八個色位的調色盤。 八個位會從緩衝區讀取,並當做系統調色盤中的索引來取得 R、G 和 B 值。 在裝置內容中選取並實現 RGB 調色盤時,OpenGL 可以使用 RGBA 模式來轉譯。
由於每個圖元有八個色位,OpenGL 強調使用三三二 RGBA 調色盤。 「三三二」是指硬體或實體調色盤如何處理色彩位數據。 紅色 (R) 和綠色 (G) 分別由三個位指定:藍色 (B) 是由兩個位所指定。 紅色是最小有效位,藍色是最重要的位。
您可以使用 PALETTEENTRY 結構來判斷應用程式邏輯調色盤的色彩。 一般而言,您會建立 PALETTEENTRY 結構的數位,以指定邏輯調色盤的整個調色盤項目數據表。
RGBA 模式調色盤範例
下列代碼段示範如何建立三三二 RGBA 調色盤。
/*
* win8map.c - program to create an 8-bit RGB color map for
* use with OpenGL
*
* For OpenGL RGB rendering you need to know red, green, & blue
* component bit sizes and positions. On 8 bit palette devices you need
* to create a logical palette that has the correct RGBA values for all
* 256 possible entries. This program creates an 8 bit RGBA color cube
* with a default gamma of 1.4
*
* Unfortunately, because the standard 20 colors in the system palette
* cannot be changed,if you select this palette into an 8-bit display
* DC, you will not realize all of the logical palette. The program
* changes some of the entries in the logical palette to match enties in
* the system palette using a least-squares calculation to find which
* entries to replace
*
* Note: Three bits for red & green and two bits for blue; red is the
* least-significant bit and blue is the most-significant bit
*/
#include <stdio.h>
#include <math.h>
#define DEFAULT_GAMMA 1.4F
#define MAX_PAL_ERROR (3*256*256L)
struct colorentry {
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct rampentry {
struct colorentry color;
long defaultindex;
unsigned char flags;
};
struct defaultentry {
struct colorentry color;
long rampindex;
unsigned char flags;
};
/* values for flags */
#define EXACTMATCH 0x01
#define CHANGED 0x02 /* one of the default entries is close */
/*
* These arrays hold bit arrays with a gamma of 1.0
* used to convert n bit values to 8-bit values
*/
unsigned char threeto8[8] = {
0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};
unsigned char twoto8[4] = {
0, 0x55, 0xaa, 0xff
};
unsigned char oneto8[2] = {
0, 255
};
struct defaultentry defaultpal[20] = {
{ 0, 0, 0 },
{ 0x80,0, 0 },
{ 0, 0x80,0 },
{ 0x80,0x80,0 },
{ 0, 0, 0x80 },
{ 0x80,0, 0x80 },
{ 0, 0x80,0x80 },
{ 0xC0,0xC0,0xC0 },
{ 192, 220, 192 },
{ 166, 202, 240 },
{ 255, 251, 240 },
{ 160, 160, 164 },
{ 0x80,0x80,0x80 },
{ 0xFF,0, 0 },
{ 0, 0xFF,0 },
{ 0xFF,0xFF,0 },
{ 0, 0, 0xFF },
{ 0xFF,0, 0xFF },
{ 0, 0xFF,0xFF },
{ 0xFF,0xFF,0xFF }
};
struct rampentry rampmap[256];
void
gammacorrect(double gamma)
{
int i;
unsigned char v, nv;
double dv;
for (i=0; i<8; i++) {
v = threeto8[i];
dv = (255.0 * pow(v/255.0, 1.0/gamma)) + 0.5;
nv = (unsigned char)dv;
printf("Gamma correct %d to %d (gamma %.2f)\n", v, nv, gamma);
threeto8[i] = nv;
}
for (i=0; i<4; i++) {
v = twoto8[i];
dv = (255.0 * pow(v/255.0, 1.0/gamma)) + 0.5;
nv = (unsigned char)dv;
printf("Gamma correct %d to %d (gamma %.2f)\n", v, nv, gamma);
twoto8[i] = nv;
}
printf("\n");
}
main(int argc, char *argv[])
{
long i, j, error, min_error;
long error_index, delta;
double gamma;
struct colorentry *pc;
if (argc == 2)
gamma = atof(argv[1]);
else
gamma = DEFAULT_GAMMA;
gammacorrect(gamma);
/* First create a 256 entry RGB color cube */
for (i = 0; i < 256; i++) {
/* BGR: 2:3:3 */
rampmap[i].color.red = threeto8[(i&7)];
rampmap[i].color.green = threeto8[((i>>3)&7)];
rampmap[i].color.blue = twoto8[(i>>6)&3];
}
/* Go through the default palette and find exact matches */
for (i=0; i<20; i++) {
for(j=0; j<256; j++) {
if ( (defaultpal[i].color.red == rampmap[j].color.red) &&
(defaultpal[i].color.green == rampmap[j].color.green) &&
(defaultpal[i].color.blue == rampmap[j].color.blue)) {
rampmap[j].flags = EXACTMATCH;
rampmap[j].defaultindex = i;
defaultpal[i].rampindex = j;
defaultpal[i].flags = EXACTMATCH;
break;
}
}
}
/* Now find close matches */
for (i=0; i<20; i++) {
if (defaultpal[i].flags == EXACTMATCH)
continue; /* skip entries w/ exact matches */
min_error = MAX_PAL_ERROR;
/* Loop through RGB ramp and calculate least square error */
/* if an entry has already been used, skip it */
for(j=0; j<256; j++) {
if (rampmap[j].flags != 0) /* Already used */
continue;
delta = defaultpal[i].color.red - rampmap[j].color.red;
error = (delta * delta);
delta = defaultpal[i].color.green - rampmap[j].color.green;
error += (delta * delta);
delta = defaultpal[i].color.blue - rampmap[j].color.blue;
error += (delta * delta);
if (error < min_error) { /* New minimum? */
error_index = j;
min_error = error;
}
}
defaultpal[i].rampindex = error_index;
rampmap[error_index].flags = CHANGED;
rampmap[error_index].defaultindex = i;
}
/* First print out the color cube */
printf("Standard 8-bit RGB color cube with gamma %.2f:\n", gamma);
for (i=0; i<256; i++) {
pc = &rampmap[i].color;
printf("%3ld: (%3-D, %3-D, %3-D)\n", i, pc->red,
pc->green, pc->blue);
}
printf("\n");
/* Now print out the default entries that have an exact match */
for (i=0; i<20; i++) {
if (defaultpal[i].flags == EXACTMATCH) {
pc = &defaultpal[i].color;
printf("Default entry %2ld exactly matched RGB ramp entry
%3ld", i, defaultpal[i].rampindex);
printf(" (%3-D, %3-D, %3-D)\n", pc->red, pc->green, pc->blue);
}
}
printf("\n");
/* Now print out the closest entries for rest of
* the default entries */
for (i=0; i<20; i++) {
if (defaultpal[i].flags != EXACTMATCH) {
pc = &defaultpal[i].color;
printf("Default entry %2ld (%3-D, %3-D, %3-D) is close to ",
i, pc->red, pc->green, pc->blue);
pc = &rampmap[defaultpal[i].rampindex].color;
printf("RGB ramp entry %3ld (%3-D, %3-D, %3-D)\n",
defaultpal[i].rampindex, pc->red, pc->green, pc->blue);
}
}
printf("\n");
/* Print out code to initialize a logical palette
* that will not overflow */
printf("Here is code you can use to create a logical palette\n");
printf("static struct {\n");
printf(" WORD palVersion;\n");
printf(" WORD palNumEntries;\n");
printf(" PALETTEENTRY palPalEntries[256];\n");
printf("} rgb8palette = {\n");
printf(" 0x300,\n");
printf(" 256,\n");
for (i=0; i<256; i++) {
if (rampmap[i].flags == 0)
pc = &rampmap[i].color;
else
pc = &defaultpal[rampmap[i].defaultindex].color;
printf(" %3-D, %3-D, %3-D, 0, /* %ld",
pc->red, pc->green, pc->blue, i);
if (rampmap[i].flags == EXACTMATCH)
printf(" - Exact match with default %d",
rampmap[i].defaultindex);
if (rampmap[i].flags == CHANGED)
printf(" - Changed to match default %d",
rampmap[i].defaultindex);
printf(" */\n");
}
printf("};\n");
printf("\n * * *\n\n");
printf(" hpal = CreatePalette((LOGPALETTE *)&rgb8palette);\n");
return 0;
}