ほとんどの GDI アプリケーションでは、論理パレットでカラー インデックス作成を使用する傾向にありますが、通常、OPENGL アプリケーションでは RGBA モードが適しています。 シェーディング、照明、霧、テクスチャ マッピングなど、いくつかの効果に対するカラー マッピングよりも適切に機能します。
RGBA モードでは、赤、緑、青 (R、G、B) の色値が使用され、ディスプレイ内の各ピクセルの色が指定されます。 R、G、B の値は、各色の強度 (赤、緑、青) を指定します。値の範囲は 0.0 (最も強い値) から 1.0 (最も強い値) です。 各コンポーネントのビット数は、使用するハードウェアによって異なります (2、3、5、6、および 8 ビットが可能です)。表示される色は、3 つの色値の合計の結果です。 3 つの値がすべて 0.0 の場合、結果は黒になります。 3 つの値がすべて 1.0 の場合、結果は白になります。 その他の色は、0 から 1.0 の間の R、G、B の値の組み合わせの結果です。 A (アルファ) ビットは、色の指定には使用されません。
標準のスーパー VGA ディスプレイでは、ピクセルあたり 8 色ビットのパレットが使用されます。 8 ビットはバッファーから読み取られ、システム パレットのインデックスとして使用され、R、G、B の値を取得します。 RGB パレットが選択され、デバイス コンテキストで実現されると、OpenGL は RGBA モードを使用してレンダリングできます。
1 ピクセルあたり 8 色ビットであるため、OpenGL では 3-3-2 RGBA パレットの使用が強調されています。 "Three-three-two" は、ハードウェアまたは物理パレットによってカラービット データがどのように処理されるかを指します。 赤 (R) と緑 (G) はそれぞれ 3 ビットで指定されます。blue (B) は 2 ビットで指定されます。 赤は最下位ビットで、青は最上位ビットです。
PALETTEENTRY 構造を使用して、アプリケーションの論理パレット 色を決定します。 通常は、PALETTEENTRY 構造体 配列を作成して、論理パレットのパレット入力テーブル全体を指定します。
RGBA モード パレットのサンプル
次のコード フラグメントは、3- 3-2 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;
}