Win7_Ultimate + VS2010 + openGL_MFC单文档应用开发框架搭建步骤
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! 运行程序如下,单文档应用显示: