Open GL Super Bible

Previous Table of Contents Next


Palette Arbitration

Windows multitasking allows many applications to be on screen at once. The hardware supports only 256 colors on screen at once, however, so all applications must share the same system palette. If one application changes the system palette, images in the other windows may have scrambled colors, producing some undesired psychedelic effects. To arbitrate palette usage among applications, Windows sends a set of messages. Applications are notified when another application has changed the system palette, and they are notified when their window has received focus and palette modification is possible.

When an application receives keyboard or mouse input focus, Windows sends a WM_QUERYNEWPALETTE message to the main window of the application. This message asks the application if it wants to realize a new palette. Realizing a palette means the application copies the palette entries from its private palette to the system palette. To do this, the application must first select the palette into the device context for the window being updated, and then call RealizePalette. Listing 8-2 presents the code for this message handler; it will be in all subsequent examples from this book.

Listing 8-2 Typical palette-arbitration code for Windows-based applications

     static HPALETTE hPalette = NULL;     // Permenant palette handle

      …
      …
     // Palette is created and referenced by hPalette
      …
      …
     // Windows is telling the application that it may modify
     // the system palette. This message in essance asks the
     // application for a new palette.
     case WM_QUERYNEWPALETTE:
             // If the palette was created.
             if(hPalette)
                    {
                    int nRet;

                    // Selects the palette into the current device context
                    SelectPalette(hDC, hPalette, FALSE);

                    // Map entries from the currently selected palette to
                    // the system palette. The return value is the number
                    // of palette entries modified.
                    nRet = RealizePalette(hDC);

                    // Repaint, forces remap of palette in current window
                    InvalidateRect(hWnd,NULL,FALSE);

                    return nRet;
                    }
             break;

     // This window may set the palette, even though it is not the
     // currently active window.
     case WM_PALETTECHANGED:
             // Don't do anything if the palette does not exist, or if
             // this is the window that changed the palette.
             if((hPalette != NULL) && ((HWND)wParam != hWnd))
                     {
                     // Select the palette into the device context
                     SelectPalette(hDC,hPalette,FALSE);

                     // Map entries to system palette
                     RealizePalette(hDC);

                     // Remap the current colors to the newly realized
                   palette
                     UpdateColors(hDC);
                     return 0;
                     }
             break;

Another message sent by Windows for palette realization is WM_PALETTECHANGED. This message is sent to windows that can realize their palette but may not have the current focus. When this message is sent, you must also check the value of wParam. If wParam contains the handle to the current window receiving the message, then WM_QUERYNEWPALETTE has already been processed, and the palette does not need to be realized again.

Note also in Listing 8-2 that the value of hPalette is checked against NULL before either of these palette-realization messages is processed. If the application is not running in 8-bit color mode, then no palette needs to be created or realized by these functions. Structuring your code in this way makes it useful for displays that don’t use palettes as well as those that do.

Creating a Palette

Unfortunately, palette considerations are a necessary evil if your application is to run on the 8-bit hardware that’s still in use in some environments. So what do you do if your code is executing on a machine that only supports 256 colors?

For image reproduction, we recommend selecting a range of colors that closely match the original colors. For OpenGL rendering under most circumstances, however, you want the widest possible range of colors for general-purpose use. The trick is to select the palette colors so that they’re evenly distributed throughout the color cube. Then, whenever a color is specified that is not already in the palette, Windows will select the nearest color in the color cube. As mentioned earlier, this is not ideal for some applications, but for OpenGL rendered scenes it is the best we can do. Unless there is substantial texture mapping in the scene with a wide variety of colors, results are usually acceptable.

Do You Need a Palette?

To determine if your application needs a palette, you can call DescribePixelFormat() after you have set the pixel format. Test the dwFlags member of the PIXELFORMATDECRIPTOR returned by DescribePixelFormat(), for the bit value PFD_NEED_PALETTE. If this bit is set, you will need to create a palette for use by your application. Listing 8-3 shows the necessary code for this test.

Listing 8-3 Testing to see if an application needs a palette

     PIXELFORMATDESCRIPTOR pfd;     // Pixel Format Descriptor
     int nPixelFormat;
                                    // Pixel format index

     // 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(!(pfd.dwFlags & PFD_NEED_PALETTE))
             return NULL;// Does not need a palette

     // Palette creation code
      …
      …


Previous Table of Contents Next