zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Win7_Ultimate + VS2010 + openGL_MFC单文档应用开发框架搭建步骤

文档应用框架开发 搭建 步骤 mfc win7
2023-09-27 14:21:09 时间

Win7_Ultimate + VS2010 + openGL单文档应用开发框架搭建步骤

  上一个配置是基于OpenGL的开发工具配置的,下面就是基于Vs2010的MFC单文档应用开发.

  通过网上查找资料,自己成功配置。

1. Windows GDI是通过设备句柄(Device Context(设备描述表)以下简称"DC")来绘图,而OpenGL则需要绘制环境(Rendering Context(着色描述表),以下简称"RC")。每一个GDI命令需要传给它一个DC,但与GDI不同,OpenGL使用当前绘制环境(RC)。但是 RC并不能直接完成绘图,只能与特定的DC联系起来,从而完成具体的绘图工作。一旦在一个线程中指定了一个当前RC,在此线程中其后所有的OpenGL命 令都使用相同的当前RC。虽然在单一窗口中可以使用多个RC,但在单一线程中只有一个当前RC。下面我将首先产生一个OpenGL RC并使之成为当前RC。这将分为三个步骤:

(1)设置窗口像素格式;

(2)产生RC;

(3)设置为当前RC。

  用一个图表示如下所示,图中介绍了需要在各个函数中设置的信息:

 

(4)VC2010与VC6的区别

 

 

  注意:在VS2010IDE中,在OpenGL库总只有三个文件:

  GL.h,  GLU.h,  glut.h, 是没有glaux.h文件的

  目录位置:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\gl

     

  在VC6.0中包含的OpenGL头文件也有三个文件:

    GL.H,   GLU.H   GLAUX.H 是含有glaux.h文件,

  目录:D:\ProgramFiles\Administrator\VisualCPP60_Professional\Include\GL

    

 

2. 在MFC中搭建MFC中的OpenGL基本框架,单文档应用程序设置步骤。

3. 在项目的的属性中添加链接库信息如下:

(1)添加链接库:菜单栏下的项目->属性->配置属性->链接器->输入->附加依赖项里加入OpenGL32.lib GLu32.lib GLaux.lib

      

(2)包含头文件,将OpenGL的头文件包含到项目中

  在stdafx里面添加opengl的头文件(当然也可以在其他文件中添加,比如绘图一般都是在视图中的,可以在xxxView.cpp文件中包含头文件)。如下代码所示:

  #include <GL\glut.h>

  注意:包含glut.h的同时就把gl.h和glu.h都包括了。因为打开glut.h你可以看到如下图所示的,已经包含了gl.h和glu.h。

 (3)设置窗口显示风格

  在***View类的PreCreateWindow()中,添加如下代码,

 1 BOOL CCGProjectWorkView::PreCreateWindow(CREATESTRUCT& cs)
 2 {
 3     // TODO: 在此处通过修改
 4     //  CREATESTRUCT cs 来修改窗口类或样式
 5     cs.style |= (WS_CLIPCHILDREN|WS_CLIPSIBLINGS);
 6     //WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘时裁剪子窗口所覆盖的区域)和WS_CLIPSIBLINGS(创建子窗口使用的Windows风格,用于重绘时剪裁其他子窗口所覆盖的区域),
 7     //从而避免OpenGL绘制到其他窗口中去。
 8 
 9     return CView::PreCreateWindow(cs);
10 }

 

(4)设置窗口像素格式

  在***View类中添加如下函数的声明与实现,添加代码如下

  成员声明:

 1     //Opengl相关的几个成员变量
 2     HGLRC m_hRC;    //Rendering Context着色描述表   
 3     CClientDC* m_pDC;        //Device Context设备描述表
 4 
 5     int m_wide, m_heigth;//视图窗口的设置
 6 
 7     float m_tFovy;//投射y平面,上下活动范围
 8     float m_zNear, m_zFar;
 9 
10     BOOL InitializeOpenGL();    //初始化 OpenGL   
11     BOOL SetupPixelFormat();    //设置像素格式   
12     void RenderScene();         //绘制场景  

  相关变量初始化

 1 CCGProjectWorkView::CCGProjectWorkView()
 2 {
 3     //设置设备描述表变量与OpenGL渲染描述表初值
 4     m_pDC = NULL;
 5     m_hRC = NULL;
 6 
 7     m_heigth = 0;
 8     m_wide = 0;
 9 
10     //投影信息的设置
11     m_tFovy = 50.0f;
12     m_zNear = 5.0f;
13     m_zFar = 20.0f;
14 }

  相关实现:

  1 //以下是OpenGL绘图的三个函数实现
  2 BOOL CCGProjectWorkView::SetupPixelFormat()
  3 {
  4     static PIXELFORMATDESCRIPTOR pfd =   
  5     {  
  6         sizeof(PIXELFORMATDESCRIPTOR),  // pfd结构的大小    
  7         1,                              // 版本号    
  8         PFD_DRAW_TO_WINDOW |            // 支持在窗口中绘图    
  9         PFD_SUPPORT_OPENGL |            // 支持 OpenGL    
 10         PFD_DOUBLEBUFFER,               // 双缓存模式    
 11         PFD_TYPE_RGBA,                  // RGBA 颜色模式    
 12         24,                             // 24 位颜色深度    
 13         0, 0, 0, 0, 0, 0,               // 忽略颜色位    
 14         0,                              // 没有非透明度缓存    
 15         0,                              // 忽略移位位    
 16         0,                              // 无累计缓存    
 17         0, 0, 0, 0,                     // 忽略累计位    
 18         32,                             // 32 位深度缓存        
 19         0,                              // 无模板缓存    
 20         0,                              // 无辅助缓存    
 21         PFD_MAIN_PLANE,                 // 主层    
 22         0,                              // 保留    
 23         0, 0, 0                         // 忽略层,可见性和损毁掩模    
 24 
 25     };  
 26     int pixelFormat;  
 27     // 为设备描述表得到最匹配的像素格式    
 28     if((pixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd)) == 0)  
 29     {  
 30         MessageBox( _T("ChoosePixelFormat failed") );  
 31         return FALSE;  
 32     }  
 33     // 设置最匹配的像素格式为当前的像素格式    
 34     if(SetPixelFormat(m_pDC->GetSafeHdc(), pixelFormat, &pfd) == FALSE)  
 35     {  
 36         MessageBox( _T("SetPixelFormat failed") );  
 37         return FALSE;  
 38     }  
 39     return TRUE;  
 40 
 41 }
 42 //设置OpenGL渲染环境
 43 BOOL CCGProjectWorkView::InitializeOpenGL()
 44 {
 45     PIXELFORMATDESCRIPTOR pfd;  
 46     int n;  
 47     m_pDC=new CClientDC(this);  
 48     ASSERT(m_pDC != NULL);  
 49     // 设置当前的绘图像素格式   
 50     if(!SetupPixelFormat())  
 51     {  
 52         return FALSE;  
 53     }  
 54 
 55     n=::GetPixelFormat(m_pDC->GetSafeHdc());  
 56     ::DescribePixelFormat(m_pDC->GetSafeHdc(), n,sizeof(pfd),&pfd);  
 57     // 创建绘图描述表   
 58     m_hRC=wglCreateContext(m_pDC->GetSafeHdc());  
 59     if(m_hRC == NULL)  
 60     {  
 61         return FALSE;  
 62     }  
 63     // 使绘图描述表为当前调用现程的当前绘图描述表   
 64     if( wglMakeCurrent(m_pDC->GetSafeHdc(),m_hRC) == FALSE)  
 65     {  
 66         return FALSE;  
 67     }  
 68     glClearDepth(1.0f);  
 69     glEnable(GL_DEPTH_TEST);  
 70     return TRUE;  
 71 
 72 }
 73 //绘制场景
 74 void CCGProjectWorkView::RenderScene()
 75 {
 76      //设置清屏颜色为黑色   
 77     glClearColor(0.0f,0.0f,0.0f,0.0f);  
 78     //清除颜色缓冲区和深度缓冲区   
 79     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
 80 /* 
 81     //建立正交变换下的剪切体 
 82     if(w<h) 
 83     { 
 84         glOrtho(-nRange,nRange,-nRange*h/w,nRange*h/w,-nRange,nRange); 
 85     } 
 86     else 
 87     { 
 88         glOrtho(-nRange*w/h,nRange*w/h,-nRange,nRange,-nRange,nRange); 
 89     } 
 90 */  
 91     //透视投影变换   
 92     glMatrixMode(GL_PROJECTION);  
 93     glLoadIdentity();  
 94     gluPerspective(m_tFovy, (double)m_wide/(double)m_heigth,m_zNear,m_zFar);  
 95     //视角变换   
 96     glMatrixMode(GL_MODELVIEW);  
 97     glLoadIdentity();  
 98     gluLookAt(10,10,10,0,0,0,0,1,0);  
 99     //矩阵堆栈函数,和glPopMatrix()相对应   
100     glPushMatrix();  
101   
102     glBegin( GL_LINES );  
103     glColor3d(1.0, 0.0, 0.0);   // X轴 红色   
104     glVertex3d(0.0, 0.0, 0.0);   
105     glVertex3d(2.0, 0.0, 0.0);  
106     glColor3d(0.0, 1.0, 0.0);   // Y轴 绿色   
107     glVertex3d(0.0, 0.0, 0.0);  
108     glVertex3d(0.0, 2.0, 0.0);  
109     glColor3d(0.0, 0.0, 1.0);   // Z轴 蓝色   
110     glVertex3d(0.0, 0.0, 0.0);   
111     glVertex3d(0.0, 0.0, 2.0);  
112     glEnd();  
113   
114     glColor3f(1.0, 1.0, 1.0);  
115     glutWireCube(0.5);  
116   
117     glPopMatrix();  
118     glFinish();  
119     SwapBuffers(wglGetCurrentDC());  
120 
121 }

  说明:

  a) BOOL CCGProjectWorkView::SetupPixelFormat():产生一个RC的第一步是定义窗口的像素格式。像素格式决定窗口着所显示的图形在内存中是如何表示的。由像素格式控制的参数包括:颜色深度、缓冲模式和所支持的绘画接口。在下面将在SetupPixelFormat()函数中对这些参数的设置。

  b)现在像素格式已经设定,我们下一步工作是产生绘制环境(RC)并使之成为当前绘制环境,即编写InitializeOpenGL()函数,设置RC,并设置当前RC。

  c)void CCGProjectWorkView::RenderScene(): openg中场景绘制

(5)再OnCreate()函数中调用 InitializeOpenGL()函数。

  在**View类中添加消息相应函数WM_CREATE,并添加如下内容,Ctrl + Shift +X 直接通过类向导设置调用。

 1 //在窗口创建成功,显示之前调用
 2 int CCGProjectWorkView::OnCreate(LPCREATESTRUCT lpCreateStruct)
 3 {
 4     if (CView::OnCreate(lpCreateStruct) == -1)
 5         return -1;
 6 
 7     // TODO:  在此添加您专用的创建代码
 8     if ( InitializeOpenGL())  
 9     {  
10         return 0;  
11     }  
12     return 0;
13 }

  说明:

  【1】OnCreate() 与 create()

  OnCreate是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的

  在view类中,Create 是虚函数由框架调用,是用来“生成一个窗口的子窗口”。 而OnCreate 函数是用来“表示一个窗口正在生成”。

   一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此消息的。因为在MFC里面用一 种消息映射的机制来响应消息,也就是可以用函数来响应相应的消息。就拿CMainFrame类来说,当窗口创建后会产生WM_CREATE消息,我们可以 在OnCreate函数里实现我们要在窗口里面增加的东西,例如按扭,状态栏,工具栏等。这些子窗口一般是定义成类中的一个成员变量,因为要保证生命周 期。一般以m_开头来表示成员(member)。

  OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置等,Create()负责注册并产生窗口

  Create()不是对应于消息WM_CREATE的,OnCreate()才是。Create()只用于产生窗口,像动态创建控件中的Create()一样。

  【2】OnCreate和OnDraw

  首先你熟悉OnCreate()和OnDraw()函数的作用和用法,才能正确使用下面是他们的用法:

  OnCreate()是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的。在view类中,Create 是虚函数由框架调用,是用来“生成一个窗口的子窗口”。 而OnCreate 函数是用来“表示一个窗口正在生成”。一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此消息的。因为在MFC里面用一种消息映射的机制来响应消息,也就是可以用函数来响应相应的消息。就拿CMainFrame类来说,当窗口创建后会产生WM_CREATE消息,我们可以在OnCreate函数里实现我们要在窗口里面增加的东西,例如按扭,状态栏,工具栏等。这些子窗口一般是定义成类中的一个成员变量,因为要保证生命周期。一般以m_开头来表示成员(member)。OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置等,Create()负责注册并产生窗口

  OnDraw()函数每当窗口发生重绘时就会执行,它其实跟消息处理函数OnPaint()差不多。当在View类里添加了消息处理函数OnPaint()时,OnPaint()就会覆盖掉OnDraw()。

(6)设置视口

  在OnSize()中一般用来设置视口和视锥,因为这些是和窗口大小相关的。通过类向导,对**View添加WM_SIZE消息相应函数,添加如下代码:

 1 // 在OnSize()中一般用来设置视口和投影,因为这些是和窗口大小相关的。代码如下
 2 void CCGProjectWorkView::OnSize(UINT nType, int cx, int cy)
 3 {
 4     CView::OnSize(nType, cx, cy);
 5 
 6     // TODO: 在此处添加消息处理程序代码   
 7     m_wide = cx;    //m_wide为在CVCOpenGL2View类中添加的表示视口宽度的成员变量   
 8     m_heigth = cy;  //m_height为在CVCOpenGL2View类中添加的表示视口高度的成员变量   
 9     //避免除数为0   
10     if(m_heigth==0)  
11     {  
12         m_heigth=1;  
13     }  
14     //设置视口,看考窗口的大小   
15     glViewport(0,0,m_wide,m_heigth);
16 
17 }

(7)绘制场景(用OpenGL绘图相关的代码都在这里),已在前面给出

  本文以一个三维正方体为例。

(8)在OnDraw()函数中调用场景绘制函数

 1 void CCGProjectWorkView::OnDraw(CDC* /*pDC*/)
 2 {
 3     CCGProjectWorkDoc* pDoc = GetDocument();
 4     ASSERT_VALID(pDoc);
 5     if (!pDoc)
 6         return;
 7 
 8     // TODO: 在此处为本机数据添加绘制代码
 9     //OpenGL场景调用
10     RenderScene();
11 }

3. 一些收尾工作

(1)为了使改变窗口大小时严重的闪烁,在OnEraseBkgnd()里做一些操作,避免windows自己的窗口刷新闪烁。OnEraseBkgnd()函数需要重写

  位**View类添加WM_EraseBkgnd消息相应函数,如下:

 

1 BOOL CCGProjectWorkView::OnEraseBkgnd(CDC* pDC)
2 {
3     // TODO: 在此添加消息处理程序代码和/或调用默认值
4     //return CView::OnEraseBkgnd(pDC);
5     return TRUE;
6 }

 

(2)为了避免内存泄露,OnDestroy()函数中加一些代码

  添加WM_Destroy消息相应函数如下:

 1 // 为了避免内存泄露,OnDestroy()函数中加一些代码
 2 void CCGProjectWorkView::OnDestroy()
 3 {
 4     CView::OnDestroy();
 5 
 6     // TODO: 在此处添加消息处理程序代码
 7     m_hRC = ::wglGetCurrentContext();
 8     //设置当前渲染环境列表为置空
 9     if(::wglMakeCurrent (0,0) == FALSE)  
10       {  
11             MessageBox(_T("Could not make RC non-current"));  
12       }
13     //清除创建的渲染环境句柄
14     if(m_hRC)  
15     {  
16         if(::wglDeleteContext(m_hRC)==FALSE)  
17           {  
18               MessageBox(_T("Could not delete RC"));  
19           }  
20      }
21     //清除设备环境句柄
22      if(m_pDC)  
23       {
24           delete m_pDC;  
25       }  
26       m_pDC = NULL; 
27 }

4. binggo! 运行程序如下,单文档应用显示: