24 bit offscreen rendering possible in 8 bit mode in Windows? (for picking)

I am trying to implement a picking method that basically renders each primitive as a unique color, and then does a glReadPixels() call to get the color underneath the mouse. This color is then used to match the id of the primitive picked.

The method works, except in anything but 24 bit color modes.

When you perform a glReadPixels(), the color you get back is not exactly the color you assigned, since the 16 bit color mode of the graphics driver forces the color to be the closest color.

Now one method is to render to an offscreen buffer or DIB in windows, so that the display driver doesn’t mess up the colors when you read it back. Then you perform a glReadPixels on the off screen buffer/HGLRC created from the HDC using a DIB instead of the standard HDC.

This method of off screen rendering is explained in the OpenGL Superbible 2nd edition.

It works beautifully for 24 and 16. However, it does not work in 8 bit mode, even though the book says it should. I’m setting up the right pixel format and ChoosePixelFormat() even returns the right one (24 bit mode for rendering to DIB). When I save the DIB surface out to disk, it produces a black and white image, where it normally produces a 24 bit image (I’m saving as .BMP).

How come it breaks down in 8 bit rendering mode even though rendering to DIB (and the associated HDC) should be device independent?

Here is the relevant code for the off screen hdc and dib creation:

viewer_off_screen_hdc = CreateCompatibleDC(NULL);

memset(&bitmap_info, 0, sizeof(bitmap_info));
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmap_info.bmiHeader.biWidth = width;
bitmap_info.bmiHeader.biHeight = height;
bitmap_info.bmiHeader.biPlanes = 1;
bitmap_info.bmiHeader.biBitCount = 24;
bitmap_info.bmiHeader.biCompression = BI_RGB;
bitmap = CreateDIBSection(viewer_off_screen_hdc, &bitmap_info, DIB_RGB_COLORS, (void **)&bitmap_bits, NULL, 0);

SelectObject(viewer_off_screen_hdc, bitmap);

Any help?

Forgot to add that glReadPixels() also crashes when trying to read from the DIB surface (when the OpenGL resource context is set to the one created from the DIB-using HRC), only in 8 bit mode.

I had the same problem trying to uniquely identify the objects by their color. The way I solved it was to use glColor3ub() rather than glColor3f. This way I always get back integers from glReadPixels().