Open GL Super Bible

Previous Table of Contents Next


Notice that we store the device context and rendering contexts in the class variables m_hDC and m_hRC. Immediately after creating the rendering context, we make it current and call the external function GLSetupRC. This function will do any initialization we need for the rendering context, after which we make it not current. This allows us to use more than one rendering context in case we need multiple windows that use OpenGL. (We wonít for our sample, but if you build on this, itís wise to have the option for more than one OpenGL window without the need to recode what you already have.)

Clean Up the Rendering Context

We should go ahead and add the code to clean up and delete the rendering context before we forget. We do this in the WM_DESTROY handler, added in Figure 21-3. We also release the device context obtained for the window.

// The window is being destroyed, delete the rendering context,
// and release the device context
void CMfcglView::OnDestroy()
        {
        wglDeleteContext(m_hRC);
        ReleaseDC(m_hWnd,m_hDC);

        CView::OnDestroy();
        }

Handling Window Resizing

When the window size changes, the WM_SIZE message is posted to the window. We add a handler for this message with Class Wizard, and call the external function GLResize, passing the new width and height of the window. The rendering context must be made current before calling this function, or the OpenGL function calls in GLResize will have no effect on the rendering context. Hereís the code:

void CMfcglView::OnSize(UINT nType, int cx, int cy)
        {
        CView::OnSize(nType, cx, cy);
        VERIFY(wglMakeCurrent(m_hDC,m_hRC));
        GLResize(cx, cy);
        VERIFY(wglMakeCurrent(NULL,NULL));
        }

Rendering the Scene

Now we are ready to add the code that actually draws the OpenGL scene. The member function OnDraw is called whenever the window receives a WM_PAINT message. Here we make the rendering context current and call the GLRenderScene function, which contains only OpenGL function calls. Since we earlier requested a double-buffered window, we call SwapBuffers afterward and then again make the rendering context not current.

// Called when window receives WM_PAINT, render our scene
void CMfcglView::OnDraw(CDC* pDC)
        {
        // Make the rendering context current
        wglMakeCurrent(m_hDC,m_hRC);

        // Call our external OpenGL code
        GLRenderScene(NULL);

        // Swap our scene to the front
        SwapBuffers(m_hDC);

        // Allow other rendering contexts to coexist
        wglMakeCurrent(m_hDC,NULL);
        }

Donít Erase First

Whenever the window is resized or invalidated, MFC will erase the window background before repainting. Since our OpenGL background is black, this erasing (which sets the window to white) will cause a flicker every time OnDraw is called.

To keep the window from flickering, we override the default handling of WM_ERASEBACKGROUND. Usually, the window is erased before being repainted after a resize. If we return FALSE from this function, however, the window will never be erased before a repaint and there wonít be any flicker. Usually this function returns CView::OnEraseBkgnd(pDC), which implements the default behavior of erasing the background, but you can just return FALSE to prevent this behavior.

// Override to keep the background from being erased every time
// the window is repainted
BOOL CMfcglView::OnEraseBkgnd(CDC* pDC)
        {
        return FALSE;
        }

CPalette Handling

Our finishing touch in the MFC sample is creating and realizing the RGB palette on devices that use palettes (256 color cards). Instead of maintaining a handle to the palette as in Chapter 8, here weíll create an MFC object of type CPalette.

For our function in Listing 21-2 we declare an instance of CPalette in mfcglView.h:

CPalette m_GLPalette;   // Logical Palette

and then manually add a member function to CMfcGlView that initializes the palette. This code is nearly identical to the function GetOpenGLPalette presented in Chapter 8, except that a CPalette object is constructed instead of a handle to a palette returned.


Previous Table of Contents Next