SIGGRAPH '97
Course 24: OpenGL and Window System Integration
OpenGL and Win32
Overlays & Underlays
Overlays and underlays are often used in applications for rendering
above (or below) the main OpenGL context. Setup and use of overlays
and underlays is discussed below.
Overlays
Some pixel formats include an overlay or underlay plane. If overlay
or underlay planes are desired, a pixel format with these must be
selected. You cannot have free-floating overlay windows that can move
over other windows. Overlay planes have a transparent color to allow
things drawn 'beneath' them to show through. Every layer has a palette
associated with it.
Unlike main plane pixel formats, overlay and underlay plane formats
don't have an equivalent ChoosePixelFormat(), so a method
similar to that described in the pixel format
section must be employed to find an appropriate format.
The following code will setup the pixel format to use an overlay plane
if available. Note that it looks very similar to the pixel format
choosing code developed in the last section. Notable differences are
the wglDescribeLayerPlane() function call in place of the
DescribePixelFormat() call in the previous example.
code defining oglPixelFormat() function in overlay.c
/* oglPixelFormat()
* Sets the pixel format for the context
*/
int oglSetPixelFormatOverlay(HDC hDC, BYTE type, DWORD flags)
{
int pf, maxpf;
PIXELFORMATDESCRIPTOR pfd;
LAYERPLANEDESCRIPTOR lpd; /* layer plane descriptor */
int nEntries = 2; /* number of entries in palette */
COLORREF crEntries[2] = { /* entries in custom palette */
0x00000000, /* black (ref #0 = transparent) */
0x00ff0000, /* blue */
};
/* get the maximum number of pixel formats */
maxpf = DescribePixelFormat(hDC, 0, 0, NULL);
/* find an overlay layer descriptor */
for(pf = 0; pf < maxpf; pf++) {
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
/* the bReserved field of the PIXELFORMATDESCRIPTOR contains the
number of overlay/underlay planes */
if (pfd.bReserved > 0) {
/* aha! This format has overlays/underlays */
wglDescribeLayerPlane(hDC, pf, 1,
sizeof(LAYERPLANEDESCRIPTOR), &lpd);
if (lpd.dwFlags & LPD_SUPPORT_OPENGL &&
lpd.dwFlags & flags)
{
goto found;
}
}
}
/* couldn't find any overlay/underlay planes */
MessageBox(NULL,
"Fatal Error: Hardware does not support overlay planes.",
"Error", MB_OK);
return 0;
found:
/* now get the "normal" pixel format descriptor for the layer */
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
/* set the pixel format */
if(SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL,
"SetPixelFormat() failed: Cannot set format specified.",
"Error", MB_OK);
return 0;
}
/* set up the layer palette */
wglSetLayerPaletteEntries(hDC, 1, 0, nEntries, crEntries);
/* realize the palette */
wglRealizeLayerPalette(hDC, 1, TRUE);
/* announce what we've got */
printf("Number of overlays = %d\n", pfd.bReserved);
printf("Color bits in the overlay = %d\n", lpd.cColorBits);
return pf;
}
Now simply create an overlay context in much the same way that you
create a main plane context. The number passed in to the
wglCreateLayerContext() function is the layer number.
code fragment from the main() function in overlay.c
/* main()
* Entry point
*/
int main(int argc, char** argv)
{
HWND hWnd; /* window */
MSG msg; /* message */
/* create a window */
hWnd = oglCreateWindow("OpenGL", 0, 0, 200, 200);
if (hWnd == NULL)
exit(1);
/* get the device context */
hDC = GetDC(hWnd);
/* set the pixel format */
if (oglSetPixelFormatOverlay(hDC, PFD_TYPE_RGBA, LPD_DOUBLEBUFFER) == 0)
exit(1);
/* get the device context */
hDC = GetDC(hWnd);
/* create an OpenGL overlay context */
hOverlayRC = wglCreateLayerContext(hDC, 1);
. . .
}
When rendering to the overlay, be sure to set it current. Also be
sure to swap the correct plane if using double buffering. Note that
you must also swap the main plane with wglSwapLayerBuffers(),
NOT SwapBuffers() when using overlay or underlay planes.
Pass in WGL_SWAP_MAIN_PLANE as the second argument to
wglSwapLayerBuffers() to swap the main plane, and
WGL_SWAP_OVERLAYi where i is the overlay number to swap an
overlay buffer.
code fragment from the main() function in overlay.c
/* main()
* Entry point
*/
int main(int argc, char** argv)
{
HWND hWnd; /* window */
MSG msg; /* message */
. . .
/* create an OpenGL overlay context */
hOverlayRC = wglCreateLayerContext(hDC, 1);
/* create an OpenGL context */
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
/* now we can start changing state & rendering */
while(1) {
/* first, check for (and process) messages in the queue */
while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
if(GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg); /* translate virtual-key messages */
DispatchMessage(&msg); /* call the window proc */
} else {
goto quit;
}
}
/* make current and draw a triangle */
wglMakeCurrent(hDC, hRC);
glClear(GL_COLOR_BUFFER_BIT);
glRotatef(1.0, 0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glColor3f(1.0, 0.0, 0.0);
glVertex2i( 0, 1);
glColor3f(0.0, 1.0, 0.0);
glVertex2i(-1, -1);
glColor3f(0.0, 0.0, 1.0);
glVertex2i( 1, -1);
glEnd();
glFlush();
wglSwapLayerBuffers(hDC, WGL_SWAP_MAIN_PLANE);
/* make current and draw a triangle */
wglMakeCurrent(hDC, hOverlayRC);
glClear(GL_COLOR_BUFFER_BIT);
glRotatef(-1.0, 0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glIndexi(1);
glVertex2i( 0, 1);
glVertex2i(-1, -1);
glVertex2i( 1, -1);
glEnd();
glFlush();
wglSwapLayerBuffers(hDC, WGL_SWAP_OVERLAY1);
}
quit:
/* clean up */
wglMakeCurrent(NULL, NULL); /* make our context 'un-'current */
ReleaseDC(hDC, hWnd); /* release handle to DC */
wglDeleteContext(hRC); /* delete the rendering context */
wglDeleteContext(hOverlayRC); /* delete the overlay context */
DestroyWindow(hWnd); /* destroy the window */
return TRUE;
}