Open GL Super Bible

Previous Table of Contents Next


Creating and Selecting a Rendering Context

Notice first the new data type HGLRC, which represents a handle to a rendering context. The wglCreateContext function takes a handle to a windows GDI device context and returns a handle to an OpenGL rendering context. Like a GDI device context, a rendering context must be deleted when you are through with it. The wglDeleteContext function does this for you, taking as its only parameter the handle of the rendering context to be deleted.

When a rendering context is created for a given device context, it is said to be suitable for drawing on that device context. When the rendering context is made current with wglMakeCurrent, it is not strictly necessary that the device context specified be the one used to create the rendering context in the first place. However, the device context used when a rendering context is made current must have the same characteristics as the device context used to create the rendering context. These characteristics include color depth, buffer definitions, and so forth, and are embodied in what is known as the pixel format.

To make a rendering context current for a device context different from that used to create it, they must both have the same pixel format. You may deselect the current rendering context either by making another rendering context current, or by calling wglMakeCurrent with NULL for the rendering context. (Selecting and setting the pixel format for the device context will be covered shortly.)

Painting with OpenGL

If you haven’t done much GDI programming, keeping track of both the device context and the rendering context may seem bewildering, but it’s actually very simple to do after you’ve seen it done once. In the old days of 16-bit Windows programming, you needed to retrieve a device context, process it quickly, and release it as soon as you were done with it—because Windows could only remember five device contexts at a time. In the new era of 32-bit Windows, these internal resource limitations are all but gone. This does not give us permission to be careless, but it does mean that there are fewer implications to creating a window with its own private device context (window style WS_OWNDC), getting the window, and hanging on until we are done with it. Furthermore, since most of our examples will be animated, we can avoid repeated (and expensive) calls to GetDC every time we need to make the rendering context current. Another time-saver for us is to make the rendering context current once it is created, and keep it current. If only one window per thread uses OpenGL, this will never be a problem, and it will save the time of repeated calls to wglMakeCurrent.

Only two window messages require any code that handles the creating and deleting of a rendering context: WM_CREATE and WM_DESTROY. Naturally, the rendering context is created in the WM_CREATE message, and it is deleted in the WM_DESTROY message. The following skeleton section from a window procedure of a window that uses OpenGL graphics shows the creation and deleting of a rendering context:

LRESULT CALLBACK WndProc(HWND hWnd, …
        {
        static HGLRC hRC;     // Save the rendering context between calls
        static HDC hDC;       // Save the device context between calls

        switch(msg)
                {
                case WM_CREATE:
                       hDeviceContext = GetDC(hWnd)
                       …

                       hRenderContext = wglCreateContext(hDC);
                       wglMakeCurrent(hDC,hRC);
                break;

                case WM_DESTROY:
                       wglMakeCurrent(hDC,NULL);
                       wglDeleteContext(hRC);

                       PostQuitMessage(0);
                break;
                }
        }

The painting and drawing of the window is still handled by the WM_PAINT message, only now it will contain your OpenGL drawing commands. In this message, you can dispense with the BeginPaint/EndPaint sequence. (These functions cleared the window, hid the caret for drawing operations, and validated the window region after painting.) With OpenGL, you only need to validate the window client area in order to keep a constant stream of WM_PAINT messages from being posted to the window. Here is a skeletal WM_PAINT handler:

case WM_PAINT:
        {
        // OpenGL drawing code or your Render function called here.
        RenderScene();

        ValidateRect(hWnd,NULL);
        }
break;


Programming Trick:  
You can still use the device context with GDI commands to draw in the window after the OpenGL scene is drawn. The Microsoft documentation states that this is fully supported except in double-buffered windows. You can, however, use GDI calls in double-buffered windows—as long as you make your calls after the buffer swap. What’s actually not supported are GDI calls to the back buffer of a double-buffered window. It’s best to avoid such calls, anyway, since one of the primary reasons for using double buffering is to provide flicker-free and instantaneous screen updates.

Preparing the Window for OpenGL

At this point you may be chomping at the bit to write a quick-and-dirty windows program using the foregoing code and a render function from a previous chapter in the WM_PAINT handler. But don’t start cobbling together code just yet. There are still two important preparatory steps we need to take before creating the rendering context.

Window Styles

In order for OpenGL to draw in a window, the window must be created with the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles set, and it must not contain the CS_PARENTDC style. This is because the rendering context is only suitable for drawing in the window for which it was created (as specified by the device context in the wglCreateContext function), or in a window with exactly the same pixel format. The WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles keep the paint function from trying to update any child windows. CS_PARENTDC (which causes a window to inherit its parent’s device context) is forbidden because a rendering context can be associated with only one device context and window. If these styles are not specified you will not be able to set a pixel format for the window—the last detail before we begin our first Windows OpenGL program.


Previous Table of Contents Next