摘于:http://cracker007.programfan.com 对于windows下的编程,似乎无论是win32 app还是dll,或者mfc,最重要的,也是最难的,都是那个框架。OpenGL也是如此。好在我已经饱经mfc的洗礼,明白如何下手分析框架。不过发现网上的很多程序框架都不是完全一样,不知道这里有没有什么标准?有些代码段去掉之后也仍然没有问题的。这似乎印证了csdn上的一句话:OpenGL出了错,什么都不会做; DirectX出了错,什么都做的出来。^-^ 研究了很多例子之后,我自己总结出了一个最简单、易懂的通用框架,并且给出了重要部分的注释: /******************************by CRACKER007*******************************/ BOOL CGdlg::InitialPixelFormat() //此函数被后面的CreateRC调用{ static PIXELFORMATDESCRIPTOR pfd= { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 24, 0,0,0,0,0,0, 0, 0, 0, 0,0,0,0, 32, 0, 0, PFD_MAIN_PLANE, 0, 0,0,0 }; int pixelformat; //下面两个if用来选择与pDC最匹配的硬件像素格式 if((pixelformat=ChoosePixelFormat(pDC->GetSafeHdc(),&pfd))==0) { MessageBox("ChoosePixelFormat failed"); return FALSE; } if(SetPixelFormat(pDC->GetSafeHdc(),pixelformat,&pfd)==FALSE) { MessageBox("SetPixelFormat failed"); return FALSE; } return TRUE;}----------------------------------------------------------------------------void CGdlg::CreateRC() //创建RC的一系列操作{ PIXELFORMATDESCRIPTOR pdf; int n; HGLRC hrc; //rc句柄 pDC=new CClientDC(this); //pDC声明于类定义中: CClientDC *pDC ASSERT(pDC!=NULL); if(!InitialPixelFormat()) //调用前面定义的函数设置像素格式 { return; } n=::GetPixelFormat(pDC->GetSafeHdc()); //这两行用于测试像素格式 ::DescribePixelFormat(pDC->GetSafeHdc(),n,sizeof(pfd),&pfd); hrc=wglCreateContext(pDC->GetSafeHdc());//创建rc wglMakeCurrent(pDC->GetSafeHdc(),hrc); //使rc当前化}---------------------------------------------------------------------------void CGdlg::FirstDraw() //初始化{ glClearDepth(1.0f); //设置深度缓存 glEnable(GL_DEPTH_TEST); //启用深度测试 glDepthFunc(GL_LEQUAL); //深度测试的类型 glMatrixMode(GL_MODELVIEW); glLoadIdentity();}---------------------------------------------------------------------------void CGdlg::ReleaseRC() //释放RC{ HGLRC hrc; hrc=::wglGetCurrentContext(); ::wglMakeCurrent(NULL,NULL); if(hrc) { ::wglDeleteContext(hrc); } if(pDC) { delete pDC; }}----------------------------------------------------------------------------void CGdlg::ReDraw() //用于OnDraw/OnPaint{ static BOOL bBusy=FALSE; if(bBusy) { return; } bBusy=TRUE; glClearColor(0.2f,0.2f,0.5f,1.0f); //设置背景色 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//刷新深度缓存 //以及背景色 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //DrawOG(); //具体绘图(如果用glClearColor设置了背景色, //那么要记得用glClear刷新 glFinish(); SwapBuffers(wglGetCurrentDC()); bBusy=FALSE;}---------------------------------------------------------------------------开始OpenGl操作所对应的消息函数内容应该包含:CreateRC();FirstDraw();Invalidate(); (或者RedrawWindow(),关于两者的区别,请看注)----------------------------------------------------------------------------结束OpenGl操作所对应的消息函数内容应该包含:ReleaseRC();----------------------------------------------------------------------------OnDraw/OnPaint的内容应该包含:ReDraw();----------------------------------------------------------------------------注一:1 使用Invalidate(..)可以触发WM_PAINT,但系统并不立即重绘,这是因为WM_PAINT的2个特性:low priority、Windows combines multiple WM_PAINT messages in the message queue into a single message, 如果想立即重绘,那么就需要调用UpdateWindow();2 RedrawWindow()可以实现立即重绘;3 如果更新的是一个区域RGN的时候它没法调用Invalidate实现,因为Invalidate只对矩形有效,但是RedrawWindow可以。 注二:如果要使用GDI函数,必须在glFinish()和SwapBuffers(wglGetCurrentDC())函数之后调用,否则会产生闪烁。如果一定要在绘制OpenGL结束之前使用GDI函数,那么想要除去闪烁则只能使用SingleBuffer模式。

评论