摘于: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可以。
{
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模式。
如果要使用GDI函数,必须在glFinish()和SwapBuffers(wglGetCurrentDC())函数之后调用,否则会产生闪烁。
如果一定要在绘制OpenGL结束之前使用GDI函数,那么想要除去闪烁则只能使用SingleBuffer模式。
评论