天天看點

《基于MFC的OpenGL程式設計》Part 2 Setting up OpenGL on Windows

源代碼下載下傳:OpenGL_ch2.rar 

WGL – Windows的 OpenGL擴充層

The WGL extension consists of a set of functions (wglCreateContext, wglDeleteContext etc.) and structures (such as PIXELFORMATDESCRIPTOR, GLYPHMETRICSFLOAT) etc. Thus every OpenGL implementation has a platform-specific portion which has to be set up and used according to the particular platform.

裝置上下文

The Windows Graphical Device Interface (GDI) is capable of drawing to screen, to memory, to printers or to any other device that provides a GDI interface layer and that can process GDI calls. GDI accomplishes this by a rendering handle to the currently selected device, which is called the device context, or DC.

繪制上下文

A rendering context is the OpenGL equivalent of the GDI DC. All OpenGL calls are rendered to the device through a RC. The rendering context maintains OpenGL state variables such as current background color, current color etc. just as the DC maintains GDI state variables such as current pen, current brush etc.

像素格式

Pixel formats are the translation layer between OpenGL calls and the rendering operation that Windows performs.

舉個例子,若像素格式隻支援很少一部分顔色值,則OpenGL在用RGB值(128,120,135)繪制一個像素時,就可能使用轉換後的值(128,128,128)來繪制.

The pixel format selected essentially describes such things as how colors are displayed, depth of field resolution and what additional capabilities are supported by the rendering context created.

第一個基于MFC的OpenGL應用程

開發環境:VC6.0

1, 首先下載下傳需要的GLUT頭檔案,DLL和Lib檔案,下載下傳連結: glutdlls37beta.zip (149 kilobytes),解壓縮後把gltu.h放到"VC98/Include/GL"下,把glut.lib和glut32.lib放到"VC9/Lib" 下,glut32.dll和glut.dll放到你建立的應用程式的運作目錄下

2, 建立一個MFC SDI應用程式,在項目屬性中加入所需要連結的庫檔案

1, 在stdafx.h中加入下列語句:

複制代碼

//OpenGL Headers

#include <gl/gl.h>

#include <gl/glu.h>

#include <gl/glut.h>

#include <gl/glaux.h>

2, 打開ClassWizard,選擇CCY457OpenGLView類,為下述消息加入消息處理函數:WM_CREATE (for OnCreate), WM_DESTROY (for OnDestroy), WM_SIZE (for OnSize), WM_ERASEBACKGROUND (for OnEraseBkground).

3,在視窗建立之前我們必須設定視窗風格包含WS_CLIPCHILDREN和 WS_CLIPSIBLINGS,進而避免OpenGL繪制到其他視窗中去。這些應該放在PreCreateWindow()中。

 複制代碼

BOOL CCY457OpenGLView::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

    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

    return CView::PreCreateWindow(cs);

}

4, 在CCY457OpenGLView.h中加入如下語句:

    HGLRC m_hRC;    //Rendering Context

    CDC* m_pDC;        //Device Context

    BOOL InitializeOpenGL();    //Initialize OpenGL

    BOOL SetupPixelFormat();    //Set up the Pixel Format

    void RenderScene();            //Render the Scene

5, 在OnCreate中我們将通過建立像素格式和繪制上下文來初始化OpenGL. 在InitializeOpenGL()中會建立一個裝置上下文(DC),為這個DC選擇一個像素格式,建立和這個DC相關的繪制上下文(RC),然後選擇這個RC.這個函數會調用SetupPixelFormat()來建立像素格式。

int CCY457OpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) 

    if (CView::OnCreate(lpCreateStruct) == -1)

        return -1;

    //Initialize OpenGL Here

    InitializeOpenGL();

    return 0;

BOOL CCY457OpenGLView::InitializeOpenGL()

    //Get a DC for the Client Area

    m_pDC = new CClientDC(this);

    //Failure to Get DC

    if(m_pDC == NULL)

    {

        MessageBox("Error Obtaining DC");

        return FALSE;

    }

    //Failure to set the pixel format

    if(!SetupPixelFormat())

    //Create Rendering Context

    m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());

    //Failure to Create Rendering Context

    if(m_hRC == 0)

        MessageBox("Error Creating RC");

    //Make the RC Current

    if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)

        MessageBox("Error making RC Current");

    //Specify Black as the 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;

//Setup Pixel Format

/////////////////////////////////////////////////////////////////////////////

BOOL CCY457OpenGLView::SetupPixelFormat()

  static PIXELFORMATDESCRIPTOR pfd = 

        sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd

        1,                              // version number

        PFD_DRAW_TO_WINDOW |            // support window

        PFD_SUPPORT_OPENGL |            // support OpenGL

        PFD_DOUBLEBUFFER,                // double buffered

        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 m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);

    if ( m_nPixelFormat == 0 )

       return FALSE;

    if ( ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)

6, 在OnSize()中一般用來設定視口和視錐,因為這些是和視窗大小相關的。基本操作包括設定視口,選擇投影矩陣,設定模型視圖矩陣。

void CCY457OpenGLView::OnSize(UINT nType, int cx, int cy) 

    CView::OnSize(nType, cx, cy);

    GLdouble aspect_ratio; // width/height ratio

    if ( 0 >= cx || 0 >= cy )

        return;

    // select the full client area

    ::glViewport(0, 0, cx, cy);

    // compute the aspect ratio

    // this will keep all dimension scales equal

    aspect_ratio = (GLdouble)cx/(GLdouble)cy;

    // select the projection matrix and clear it

    ::glMatrixMode(GL_PROJECTION);

    ::glLoadIdentity();

    // select the viewing volume

    ::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);

    // switch back to the modelview matrix and clear it

    ::glMatrixMode(GL_MODELVIEW);

7,在繪制場景時,一般包括如下步驟:1)清空緩存。2)繪制場景。3)Flush掉渲染流水線。4)若設定了雙緩沖,則交換前背景緩沖區。

void CCY457OpenGLView::OnDraw(CDC* pDC)

    CCY457OpenGLDoc* pDoc = GetDocument();

    ASSERT_VALID(pDoc);

    // Clear out the color & depth buffers

    ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    RenderScene();

    // Tell OpenGL to flush its pipeline

    ::glFinish();

    // Now Swap the buffers

    ::SwapBuffers( m_pDC->GetSafeHdc() );

void CCY457OpenGLView::RenderScene ()

{//第一個玩具嘛,先空着,後面慢慢填

8,試試改變視窗的大小,你會看到很嚴重的閃爍,并且關閉程式後會報告記憶體洩露,是以我們這就來解決這兩個問題吧。

發生閃爍的原因是Windows先繪制背景,然後再是OpenGL繪制,因為我們已經讓OpenGL負責清空背景色,是以我們不需要Windows去清空背景了

BOOL CCY457OpenGLView::OnEraseBkgnd(CDC* pDC) 

    //Tell Windows not to erase the background

     記憶體洩露的原因是我們在SetupPixelFormat()中使用了new運算符來為CClientDC對象配置設定記憶體,是以需要顯示delete掉。

void CCY457OpenGLView::OnDestroy() 

    CView::OnDestroy();

    //Make the RC non-current

    if(::wglMakeCurrent (0,0) == FALSE)

        MessageBox("Could not make RC non-current");

    //Delete the rendering context

    if(::wglDeleteContext (m_hRC)==FALSE)

        MessageBox("Could not delete RC");

    //Delete the DC

    if(m_pDC)

        delete m_pDC;

    //Set it to NULL

    m_pDC = NULL;

本文轉自Phinecos(洞庭散人)部落格園部落格,原文連結:http://www.cnblogs.com/phinecos/archive/2008/11/04/1326687.html,如需轉載請自行聯系原作者

繼續閱讀