第一个基于MFC的OpenGL应用程序

来源:互联网 发布:棋牌软件出售 编辑:程序博客网 时间:2024/04/30 04:05

第一个基于MFCOpenGL应用程序

开发环境:VC6.0

1, 首先下载需要的GLUT头文件,DLLLib文件,下载链接: glutdlls37beta.zip (149 kilobytes),解压缩后把gltu.h放到"VC98/Include/GL"下,把glut.libglut32.lib放到"VC9/Lib" 下glut32.dllglut.dll放到你创建的应用程序的运行目录下

2, 创建一个MFC SDI应用程序,在项目属性中加入所需要链接的库文件

1, stdafx.h中加入下列语句:2, 打开ClassWizard,选择CCY457OpenGLView类,为下述消息加入消息处理函数:WM_CREATE (for OnCreate), WM_DESTROY (for OnDestroy), WM_SIZE (for OnSize), WM_ERASEBACKGROUND (for OnEraseBkground).

//OpenGL Headers

#include 
<gl/gl.h>

#include 
<gl/glu.h>

#include 
<gl/glut.h>

#include 
<gl/glaux.h>

 

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())
    {
        
return
 FALSE;
    }
    
//Create Rendering Context

    m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
    
//Failure to Create Rendering Context

    if(m_hRC == 0)
    {
        MessageBox(
"Error Creating RC"
);
        
return
 FALSE;
    }
    
//Make the RC Current

    if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
    {
        MessageBox(
"Error making RC Current"
);
        
return
 FALSE;
    }
    
//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
        000000,               // color bits ignored
        0,                              // no alpha buffer
        0,                              // shift bit ignored
        0,                              // no accumulation buffer
        0000,                     // accum bits ignored
        16,                             // 16-bit z-buffer
        0,                              // no stencil buffer
        0,                              // no auxiliary buffer
        PFD_MAIN_PLANE,                 // main layer
        0,                              // reserved
        000                         // 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)
    {
       
return
 FALSE;
    }
    
return
 TRUE;
}

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(00, 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);
    ::glLoadIdentity();
}

7,在绘制场景时,一般包括如下步骤:1)清空缓存。2)绘制场景。3Flush掉渲染流水线。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

    return TRUE;
}

     内存泄露的原因是我们在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;
}

 

原创粉丝点击