Figure 1   Pixel Format Functions

ChoosePixelFormat Obtains a DC's pixel format that's the closest match to a pixel-format template you've provided. Windows tries to match your requirements to what's available.

SetPixelFormat Sets a DC's current pixel format to the pixel-format index specified. Assumes that you know the pixel format identified by the index. Always check the return from this function! If it fails, all your OpenGL calls will produce nothing.

GetPixelFormat Returns the pixel format index of a DC's current pixel format.

DescribePixelFormat Given a DC and a pixel format index, fills a PIXELFORMATDESCRIPTOR data structure with that pixel format's properties.

Figure 2   RC-Manipulating wgl Functions

wglCreateContext Creates a new OpenGL RC suitable for drawing on the device referenced by the associated DC. The pixel format of the new RC takes its pixel format from the DC.

wglMakeCurrent Makes an existing RC the current RC for a particular thread. This needs to be done before any OpenGL commands are issued. Note that the DC that is used doesn't have to be the same one that was used to create the RC, but it must be on the same device and must have the same pixel format.

wglDeleteContext Deletes the specified RC, which must be associated with the current thread. Also makes the RC not current. Has no effect upon the DC associated with this RC.

wglCopyContext This function lets you copy the state of one OpenGL RC to another RC. The RCs must be from the same OpenGL implementation. You can always copy a rendering state between two RCs with the same pixel format in the same process. The destination RC must not be the current RC.

wglGetCurrentDC Returns a handle to the current DC associated with the current thread's RC.

wglGetCurrentContext Returns a handle to the current thread's RC.

wglShareLists Enables an RC to share the display-list space of another RC in another thread. Display lists are a way of caching rendering commands. When you create an RC, it has its own display-list space. All RCs sharing a common pixel format can always share display lists. (wglShareLists isn't available on the very first version of OpenGL for Windows NT. Only version 1.01 or later has this functionality.)

Figure 5   View Class Startup Behavior Changes

 BOOL COpenGLView::OnEraseBkgnd(CDC* pDC) 
{
     // TODO: Add your message handler code here and/or call
     // default

     // Comment this line out
     // return CView::OnEraseBkgnd(pDC);

     return TRUE; // OpenGL will erase the background
}

BOOL COpenGLView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    // An OpenGL window must be created with the following
    // flags and must not include CS_PARENTDC for the
    // class style.

    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

    return CView::PreCreateWindow(cs);
}

Figure 6   View Class Startup Initialization

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

     // TODO: Add your specialized creation code here

     InitializeOpenGL();

     return 0;
}


BOOL COpenGLView::InitializeOpenGL()
{
    m_pDC = new CClientDC(this);

    if ( NULL == m_pDC ) // failure to get DC
        {
    ::AfxMessageBox("Couldn't get a valid DC.");
        return FALSE;
        }

    if ( !SetupPixelFormat() )
        {
    ::AfxMessageBox("SetupPixelFormat failed.\n");
        return FALSE;
        }

    if ( 0 == (m_hRC = 
        ::wglCreateContext( m_pDC->GetSafeHdc() ) ) )
        {
    ::AfxMessageBox("wglCreateContext failed.");
        return FALSE;
        }

    if ( FALSE == 
        ::wglMakeCurrent( m_pDC->GetSafeHdc(), m_hRC ) )
        {
    ::AfxMessageBox("wglMakeCurrent failed.");
        return FALSE;
        }

    // specify black as clear color
    ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    // specify the back of the buffer as clear depth
    ::glClearDepth( 1.0f );
    // enable depth testing
    ::glEnable( GL_DEPTH_TEST );

    return TRUE;
}


BOOL COpenGLView::SetupPixelFormat(
    PIXELFORMATDESCRIPTOR* pPFD)
{
    // default pixel format for a single-buffered,
    // OpenGL-supporting, hardware-accelerated, 
    // RGBA-mode format. Pass in a pointer to a different
    // pixel format if you want something else
    PIXELFORMATDESCRIPTOR pfd = 
        {
        sizeof(PIXELFORMATDESCRIPTOR),// size of this pfd
        1,                      // version number
        PFD_DRAW_TO_WINDOW |    // support window
          PFD_SUPPORT_OPENGL,   // support OpenGL
        PFD_TYPE_RGBA,          // RGBA type
        24,                     // 24-bit color depth
        0, 0, 0, 0, 0, 0,       // color bits ignored
        0,                      // no alpha buffer
        0,                      // shift bit ignored
        0,                      // no accumulation buffer
        0, 0, 0, 0,             // accum bits ignored
        16,                     // 16-bit z-buffer
        0,                      // no stencil buffer
        0,                      // no auxiliary buffer
        PFD_MAIN_PLANE,         // main layer
        0,                      // reserved
        0, 0, 0                 // layer masks ignored
        };

    int pixelformat;
    PIXELFORMATDESCRIPTOR* pPFDtoUse;

    // let the user override the default pixel format
    pPFDtoUse = (0 == pPFD)? &pfd : pPFD; 
 
    if ( 0 == (pixelformat = 
        ::ChoosePixelFormat( m_pDC->GetSafeHdc(), pPFDtoUse )) )
        {
    ::AfxMessageBox("ChoosePixelFormat failed.");
    return FALSE;
        }

    if ( FALSE == ::SetPixelFormat( m_pDC->GetSafeHdc(),
        pixelformat, pPFDtoUse ) )
        {
    ::AfxMessageBox("SetPixelFormat failed.");
        return FALSE;
        }

    return TRUE;
}

Figure 7   View Class Cleanup

 void COpenGLView::OnDestroy() 
{
    CView::OnDestroy();
 
    // TODO: Add your message handler code here

    // this call makes the current RC not current
    if ( FALSE ==  ::wglMakeCurrent( 0, 0 ) )
        {
        ::AfxMessageBox("wglMakeCurrent failed.");
        }

    // delete the RC
    if ( m_hRC && (FALSE == ::wglDeleteContext( m_hRC )) )
        {
        ::AfxMessageBox("wglDeleteContext failed.");
        }

    // delete the DC
    if ( m_pDC )
        {
        delete m_pDC;
        }
}

Figure 9   Handling Window Sizing

 void COpenGLView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    
    // TODO: Add your message handler code here
 
    if ( 0 >= cx || 0 >= cy )
        {
        return;
        }

    // save the width and height of the current window
    m_WindowWidth = cx;
    m_WindowHeight = cy;

    // compute the aspect ratio
    // this will keep all dimension scales equal
    m_AspectRatio = (GLdouble)m_WindowWidth/(GLdouble)m_WindowHeight;

    // Now, set up the viewing area-select the full client area
    ::glViewport(0, 0, m_WindowWidth, m_WindowHeight);

    if ( GL_NO_ERROR != ::glGetError() )
    {
    ::AfxMessageBox("Error while trying to set viewport.");
    }

    // select the projection matrix as the recipient of
    // matrix operations (there's three to choose from)
    ::glMatrixMode(GL_PROJECTION);
    // initialize the projection matrix to a pristine state
    ::glLoadIdentity();

    // select the viewing volume. You do it after you
    // get the aspect ratio and set the viewport
    SetupViewingFrustum( );

    // now select the modelview matrix and clear it
    // this is the mode we do most of our calculations in
    // so we leave it as the default mode.
    ::glMatrixMode(GL_MODELVIEW);
    ::glLoadIdentity();
  
    // now perform a default viewing transformations
    SetupViewingTransform();
}


BOOL COpenGLView::SetupViewingFrustum( void )
{
    // select a default perspective viewing volumn
    ::gluPerspective( 40.0f, m_AspectRatio, 0.1f, 20.0f );

    // NOTE: Other commands you could have here are
    // glFrustum, which gives you much more control over
    // the perspective view, or glOrtho which is used for
    // parallel projections. No matter what you use, check
    // the error status when you set the viewing frustum!

    if ( GL_NO_ERROR != ::glGetError() )
    {
    ::AfxMessageBox("Error while trying to set viewing frustum.");
    return FALSE;
    }

    return TRUE;
}


BOOL COpenGLView::SetupViewingTransform()
{
    // select a default viewing transformation
    // of a 20 degree rotation about the X axis
    // then a -5 unit transformation along Z
    ::glTranslatef( 0.0f, 0.0f, -5.0f );
    ::glRotatef( 20.0f, 1.0f, 0.0f, 0.0f );

    return TRUE;
}