Open GL Super Bible

Previous Table of Contents Next


Building the Palette

Unfortunately, at this time OpenGL for Windows will only support 3-3-2 palettes in RGBA color mode. This is actually specified in the PIXELFORMATDESCRIPTOR returned by DescribePixelFormat(). The members cRedBits, cGreenBits, and cBluebits specify 3, 3, and 2, respectively, for the number of bits that can represent each component. Furthermore, the cRedShift, cGreenShift, and cBlueShift values specify how much to shift the respective component value to the left (in this case, 0, 3, and 6 for red, green, and blue shifts). These sets of values compose the palette index (Figure 8-14).


Figure 8-14  3-3-2 palette packing

The code in Listing 8-4 creates a palette if needed and returns its handle. This function makes use of the component bit counts and shift information in the PIXELFORMATDESCRIPTOR to accommodate any subsequent palette requirements, such as a 2-2-2 palette .

Listing 8-4 Function to create a palette for OpenGL

// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
   {
   HPALETTE hRetPal = NULL;     // Handle to palette to be created
   PIXELFORMATDESCRIPTOR pfd;   // Pixel Format Descriptor
   LOGPALETTE *pPal;            // Pointer to memory for logical palette
   int nPixelFormat;            // Pixel format index
   int nColors;                 // Number of entries in palette
   int i;                       // Counting variable
   BYTE RedRange,GreenRange,BlueRange;
                                // Range for each color entry (7,7,and 3) 
 
   // Get the pixel format index and retrieve the pixel format description
   nPixelFormat = GetPixelFormat(hDC);
   DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR),
   &pfd); 
 
   // Does this pixel format require a palette?  If not, do not create a
   // palette and just return NULL
   if(!(pfd.dwFlags & PFD_NEED_PALETTE))
           return NULL; 
 
   // Number of entries in palette. 8 bits yields 256 entries
   nColors = 1 << pfd.cColorBits; 
 
   // Allocate space for a logical palette structure plus all the palette
   // entries
   pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
   nColors*sizeof(PALETTEENTRY)); 
 
   // Fill in palette header
   pPal->palVersion = 0x300;// Windows 3.0
   pPal->palNumEntries = nColors; // table size 
 
   // Build mask of all 1's. This creates a number represented by having
   // the low order ?bits set, where ?= pfd.cRedBits, pfd.cGreenBits,and
   // pfd.cBlueBits.
   RedRange = (1 << pfd.cRedBits) -1;       // 7 for 3-3-2 palettes
   GreenRange = (1 << pfd.cGreenBits) - 1;  // 7 for 3-3-2 palettes
   BlueRange = (1 << pfd.cBlueBits) -1;     // 3 for 3-3-2 palettes 
 
   // Loop through all the palette entries
   for(i = 0; i < nColors; i++)
           {
           // Fill in the 8-bit equivalents for each component
           pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
           pPal->palPalEntry[i].peRed = (unsigned char)(
                      (double) pPal->palPalEntry[i].peRed * 255.0
   / RedRange); 
 
           pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift)
   & GreenRange;
           pPal->palPalEntry[i].peGreen = (unsigned char)(
                      (double)pPal->palPalEntry[i].peGreen * 255.0
   /GreenRange); 
 
           pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift)
   & BlueRange;
           pPal->palPalEntry[i].peBlue = (unsigned char)(
                      (double)pPal->palPalEntry[i].peBlue * 255.0
   / BlueRange); 
 
           pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
           } 
   
   // Create the palette
   hRetPal = CreatePalette(pPal); 
 
   // Go ahead and select and realize the palette for this device context
   SelectPalette(hDC,hRetPal,FALSE);
   RealizePalette(hDC); 
 
   // Free the memory used for the logical palette structure
   free(pPal); 
 
   // Return the handle to the new palette
   return hRetPal;
   }

Palette Creation and Disposal

The palette should be created and realized before the rendering context is created or made current. The function in Listing 8-4 requires only the device context, once the pixel format has been set. It will then return a handle to a palette if one is needed. Listing 8-5 shows the sequence of operations when the window is created and destroyed. This is similar to code presented previously for the creation and destruction of the rendering context, only now it also takes into account the possible existence of a palette.

Listing 8-5 A palette is created and destroyed

     // Window creation, setup for OpenGL
     case WM_CREATE:
             // Store the device context
             hDC = GetDC(hWnd);

             // Select the pixel format
             SetDCPixelFormat(hDC);

             // Create the palette if needed
             hPalette = GetOpenGLPalette(hDC);

             // Create the rendering context and make it current
             hRC = wglCreateContext(hDC);
             wglMakeCurrent(hDC, hRC);
             break;

     // Window is being destroyed, cleanup
     case WM_DESTROY:
            // Deselect the current rendering context and delete it
            wglMakeCurrent(hDC,NULL);
            wglDeleteContext(hRC);

            // If a palette was created, destroy it here
            if(hPalette != NULL)
                   DeleteObject(hPalette);

            // Tell the application to terminate after the window
            // is gone.
            PostQuitMessage(0);
            break;

Some Restrictions Apply

Not all of your 256 palette entries will actually be mapped to the system palette. Windows reserves 20 entries for static system colors that include the standard 16 VGA/EGA colors. This protects the standard windows components (title bars, buttons, etc.) from alteration whenever an application changes the system palette. When your application realizes its palette, these 20 colors will not be overwritten. Fortunately, some of these colors already exist or are closely matched in the 3-3-2 palette. Those that don’t are closely enough matched that you shouldn’t be able to tell the difference.


Previous Table of Contents Next