Open GL Super Bible

Previous Table of Contents Next


Build the Shell

We start by building an SDI shell application with AppWizard, skipping all the options for database access and OLE functionality. Figure 21-1 shows the initial shell SDI application created by AppWizard.


Figure 21-1  Initial AppWizard SDI shell application

You might also want to turn off the option to add Print and Print Preview. OpenGL scenes can only be rendered to a printer device context if the printer is a color printer supporting four or more bitplanes of color depth (16 or more colors). Printing to a monochrome laser or dot-matrix printer is possible but cumbersome. See the supplementary program GLPRINT in the \OpenGL11 subdirectory for an example of printing OpenGL scenes using the new features in OpenGL version 1.1.

Add the Libraries

Before we start adding any OpenGL code to this shell, we have to add the OpenGL libraries to the project. You do this by selecting Build/Settings from your main menu. The dialog in Figure 21-2 illustrates where to put the OpenGL library names. You may have other libraries you will want to include, depending on your application. These are only the libraries you’ll need for OpenGL.


Figure 21-2  Adding the OpenGL libraries to your Visual C++ project

You’ll also need to add the OpenGL header files to the project. The easiest place to put these (so you can then just forget about them) is in stdafx.h. Just add the following two headers, and they will be included in the precompiled header file as well:

#include <gl\gl.h>      // OpenGL Libraries
#include <gl\glu.h>     // GLU OpenGL Libraries

Get CView Ready for OpenGL

When you use the document-view architecture encouraged by AppWizard’s SDI application generation, you end up with a class derived from CView that is responsible for the presentation layer of your application. In our example, that class is named CMfcglView. It’s declared in the file mfcglView.h and implemented in the file mfcglView.cpp.

The earliest requirement of any window that will be used for OpenGL is that the window styles WS_CLIPCHILDREN and WS_CLIPSIBLINGS be set. We can do this easily in the virtual member function PreCreateWindow of our derived CView class, which is already provided in the file mfcglView.cpp. This function lets us modify the CREATESTRUCT information before the window is created. One of the members of this structure contains the windows styles used on creation. We can simply add these style bits by performing a logical OR, like this:

BOOL CMfcglView::PreCreateWindow(CREATESTRUCT& cs)
        {
        // Add Window styles required for OpenGL before window is created
        cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CS_OWNDC);

        return CView::PreCreateWindow(cs);
        }

Notice that we also set the style for CS_OWNDC, so the window can have its own private device context. Although this is not strictly necessary, it saves time and works better with MFC. Some device context pointers returned by MFC functions are temporary and cannot be stored for later use. It’s better to get it once and keep it.

Space in the CMfcglView class is allocated to store the device context and the rendering context, with the following code from MfcglView.h:

public:
        HGLRC m_hRC;     // Rendering Context
        HDC m_hDC;       // Device Context

Pixel Format and Rendering Context

Now that we have a window with the correct styles necessary for OpenGL, we need to set the OpenGL pixel format. Since the device context is required to create a pixel format, we’ll wait to do this until after the window is created. We can use the Class Wizard to add a message map entry that will be called when the window receives the WM_CREATE message. Figure 21-3 shows the relevant Class Wizard dialog, containing an entry for WM_DESTROY, as well.


Figure 21-3  Adding the message maps for WM_CREATE and WM_DESTROY

Setting the pixel format within the WM_CREATE handler is relatively straightforward. Listing 21-1 shows our message handler with the code that selects the pixel format for the device context.

Listing 21-1 WM_CREATE message handler that sets the Pixel Format

int CMfcglView::OnCreate(LPCREATESTRUCT lpCreateStruct)
        {
        if (CView::OnCreate(lpCreateStruct) == -1)
                return -1;

        int nPixelFormat;                        // Pixel format index
        m_hDC = ::GetDC(m_hWnd);                 // Get the device context

        static PIXELFORMATDESCRIPTOR pfd = {
                sizeof(PIXELFORMATDESCRIPTOR),  // Size of this structure
                1,                              // Version of this
                                                   structure
        PFD_DRAW_TO_WINDOW |                    // Draw to Window
                                                   (not bitmap)
                PFD_SUPPORT_OPENGL |            // Support OpenGL in window
                PFD_DOUBLEBUFFER,               // Double-buffered mode
                PFD_TYPE_RGBA,                  // RGBA color mode
                24,                             // Want 24bit color
                0,0,0,0,0,0,                    // Not used to select mode
                0,0,                            // Not used to select mode
                0,0,0,0,0,                      // Not used to select mode
                32,                             // Size of depth buffer
                0,                              // Not used to select mode
                0,                              // Not used to select mode
                PFD_MAIN_PLANE,                 // Draw in main plane
                0,                              // Not used to select mode
                0,0,0 };                        // Not used to select mode

// Choose a pixel format that best matches that described in pfd
nPixelFormat = ChoosePixelFormat(m_hDC, &pfd);

// Set the pixel format for the device context
VERIFY(SetPixelFormat(m_hDC, nPixelFormat, &pfd));

// Create the rendering context
m_hRC = wglCreateContext(m_hDC);

// Make the rendering context current, perform initialization, then
// deselect it
VERIFY(wglMakeCurrent(m_hDC,m_hRC));
GLSetupRC();
wglMakeCurrent(NULL,NULL);

return 0;
}


Previous Table of Contents Next