Phinecos(洞庭散人) 专注于开源技术的研究与应用 Nehe的OpenGL框架(MFC版)
2016-12-11 16:37
507 查看
原文链接:http://www.cnblogs.com/phinecos/archive/2007/07/29/835386.html
SwapBuffers参考内容链接:http://blog.sina.com.cn/s/blog_4e6f376d0100c0o2.html
Nehe的几个OpenGL框架都是Win32 sdk版本的,我现在需要在MFC下学习OpenGL,今天看了他写的第一个OpenGL框架,就在MFC中实现了下。为了简单起见,把全屏那部分就抛弃掉了,毕竟重点不在这上面,而且MFC要实现这个全屏的功能也不像sdk那么容易。。。
// openGLDemoView.h : interface of the COpenGLDemoView class
//
/////////////////////////////////////////////////////////////////////////////
protected:
BOOL SetWindowPixelFormat(HDC hDC);//设置像素格式
BOOL CreateViewGLContext(HDC hDC);//创建绘制环境(RC)并使之成为当前绘制环境
BOOL InitGL(GLvoid);//初始化openGL
int DrawGLScene(GLvoid);//绘图代码区
int m_GLPixelIndex;
HGLRC m_hGLContext;//绘制环境
// openGLDemoView.cpp : implementation of the COpenGLDemoView class
//
COpenGLDemoView::COpenGLDemoView()
{
// TODO: add construction code here
this->m_GLPixelIndex = 0;
this->m_hGLContext = NULL;
}
BOOL COpenGLDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);//openGL必需的
return CView::PreCreateWindow(cs);
}
BOOL COpenGLDemoView::SetWindowPixelFormat(HDC hDC)
{//定义窗口的像素格式
PIXELFORMATDESCRIPTOR pixelDesc=
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|
PFD_DOUBLEBUFFER|PFD_SUPPORT_GDI,
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
};
this->m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);//选择最相近的像素格式
if(this->m_GLPixelIndex==0)
{//选择失败
this->m_GLPixelIndex = 1;//默认的像素格式
if(DescribePixelFormat(hDC,this->m_GLPixelIndex,sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
{//用默认的像素格式进行设置
return FALSE;
}
}
if(SetPixelFormat(hDC,this->m_GLPixelIndex,&pixelDesc)==FALSE)
{
return FALSE;
}
return TRUE;
}
BOOL COpenGLDemoView::InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0,0.0,0.0,0.0);// Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
f766
return TRUE; // Initialization Went OK
}
BOOL COpenGLDemoView::CreateViewGLContext(HDC hDC)
{
this->m_hGLContext = wglCreateContext(hDC);//创建RC
if(this->m_hGLContext==NULL)
{//创建失败
return FALSE;
}
if(wglMakeCurrent(hDC,this->m_hGLContext)==FALSE)
{//选为当前RC失败
return FALSE;
}
return TRUE;
}
int COpenGLDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
HWND hWnd = this->GetSafeHwnd();
HDC hDC = ::GetDC(hWnd);
if(this->SetWindowPixelFormat(hDC)==FALSE)
{//设置像素格式
return 0;
}
if(this->CreateViewGLContext(hDC)==FALSE)
{//创建RC并选为所用
return 0;
}
if(!this->InitGL())
{//初始化openGL
return 0;
}
return 0;
}
void COpenGLDemoView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
if(wglGetCurrentContext()!=NULL)
{
wglMakeCurrent(NULL,NULL);
}
if(this->m_hGLContext!=NULL)
{
wglDeleteContext(this->m_hGLContext);
this->m_hGLContext = NULL;
}
}
void COpenGLDemoView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
GLsizei width,height;
width = cx;
height = cy;
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);//透视投影
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
void COpenGLDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting
this->DrawGLScene();
}
int COpenGLDemoView::DrawGLScene(GLvoid)
{// Here's Where We Do All The Drawing
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(-1.5f,0.0f,-6.0f);//物体左移1.5,向内移6,相当于移动镜头一样,让物体进入镜头中
glBegin(GL_TRIANGLES); // 绘制三角形
glColor3f(255.0f,0.0f,0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f); // 上顶点
glColor3f(0.0f,255.0f,0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f); // 左下
glColor3f(0.0f,0.0f,255.0f);
glVertex3f( 1.0f,-1.0f, 0.0f); // 右下
glEnd(); // 三角形绘制结束
glTranslatef(3.0f,0.0f,0.0f);
glBegin(GL_QUADS); // 绘制正方形
glColor3f(255.0f,0.0f,0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // 左上
glColor3f(0.0f,255.0f,0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f); // 右上
glColor3f(0.0f,0.0f,255.0f);
glVertex3f( 1.0f,-1.0f, 0.0f); // 左下
glColor3f(255.255f,255.0f,255.0f);
glVertex3f(-1.0f,-1.0f, 0.0f); // 右下
glEnd(); // 正方形绘制结束
glFlush();
::SwapBuffers(::wglGetCurrentDC()); //交换前后缓存(因为前面设置了双缓存方式)
return TRUE; // Everything Went OK
}
PS:标红的一行代码在原来的博客里面是没有的,因为运行了原文代码后发现窗口什么都没画出来,于是上网查了一些其它博客。发现必须要调用SwapBuffers函数,原理就是双缓存的方式,每次glClear后的绘图代码是对后台缓冲区的操作,因此最后要调用这个函数来进行前后缓冲区的交换,完成显示。
SwapBuffers是wgl函数,简单说一下什么是wgl。OpenGL只包括绘图指令,本身不提供窗口系统,但是这又是显示所不可缺少的。Windows为了在窗口中支持OpenGL渲染,在win32库中扩展了一些以wgl为前缀的函数(虽然这里的SwapBuffers并没有wgl前缀
),功能包括对像素格式进行初始化、控制渲染以及访问OpenGL扩展功能。特别要注意的是最后一项功能,windows提供的gl和glu函数库只包括OpenGL1.1版本的功能,对于以后的扩展功能只能通过wgl相关函数来获取相应功能的函数指针。对于wgl,红宝书的附录中有比较详细的介绍。
补充:改变窗口大小时闪烁是windows图形图像编程中的一个问题。这里由于我们采用OpenGL而不是GDI绘图,所以有一种简单的方法。事实上我们已经采用的双缓冲绘图方式已经起到了防止窗口闪烁的作用了,它的原理是用快速的复制操作代替耗时的擦除和重绘操作,但是我们仍然需要屏蔽掉WM_ERASEBKGND消息:
BOOL CglWithMFCView::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
return TRUE;
//return CView::OnEraseBkgnd(pDC);
}这个消息返回TRUE则表示窗口不需要擦除,这样由于改变窗口大小而产生的擦除消息就被我们永远屏蔽掉了,相应的擦除操作就没有了。再结合我们前面的双缓冲方式,闪烁问题就解决了。
SwapBuffers参考内容链接:http://blog.sina.com.cn/s/blog_4e6f376d0100c0o2.html
Nehe的几个OpenGL框架都是Win32 sdk版本的,我现在需要在MFC下学习OpenGL,今天看了他写的第一个OpenGL框架,就在MFC中实现了下。为了简单起见,把全屏那部分就抛弃掉了,毕竟重点不在这上面,而且MFC要实现这个全屏的功能也不像sdk那么容易。。。
// openGLDemoView.h : interface of the COpenGLDemoView class
//
/////////////////////////////////////////////////////////////////////////////
protected:
BOOL SetWindowPixelFormat(HDC hDC);//设置像素格式
BOOL CreateViewGLContext(HDC hDC);//创建绘制环境(RC)并使之成为当前绘制环境
BOOL InitGL(GLvoid);//初始化openGL
int DrawGLScene(GLvoid);//绘图代码区
int m_GLPixelIndex;
HGLRC m_hGLContext;//绘制环境
// openGLDemoView.cpp : implementation of the COpenGLDemoView class
//
COpenGLDemoView::COpenGLDemoView()
{
// TODO: add construction code here
this->m_GLPixelIndex = 0;
this->m_hGLContext = NULL;
}
BOOL COpenGLDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);//openGL必需的
return CView::PreCreateWindow(cs);
}
BOOL COpenGLDemoView::SetWindowPixelFormat(HDC hDC)
{//定义窗口的像素格式
PIXELFORMATDESCRIPTOR pixelDesc=
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|
PFD_DOUBLEBUFFER|PFD_SUPPORT_GDI,
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
};
this->m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);//选择最相近的像素格式
if(this->m_GLPixelIndex==0)
{//选择失败
this->m_GLPixelIndex = 1;//默认的像素格式
if(DescribePixelFormat(hDC,this->m_GLPixelIndex,sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
{//用默认的像素格式进行设置
return FALSE;
}
}
if(SetPixelFormat(hDC,this->m_GLPixelIndex,&pixelDesc)==FALSE)
{
return FALSE;
}
return TRUE;
}
BOOL COpenGLDemoView::InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0,0.0,0.0,0.0);// Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
f766
return TRUE; // Initialization Went OK
}
BOOL COpenGLDemoView::CreateViewGLContext(HDC hDC)
{
this->m_hGLContext = wglCreateContext(hDC);//创建RC
if(this->m_hGLContext==NULL)
{//创建失败
return FALSE;
}
if(wglMakeCurrent(hDC,this->m_hGLContext)==FALSE)
{//选为当前RC失败
return FALSE;
}
return TRUE;
}
int COpenGLDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
HWND hWnd = this->GetSafeHwnd();
HDC hDC = ::GetDC(hWnd);
if(this->SetWindowPixelFormat(hDC)==FALSE)
{//设置像素格式
return 0;
}
if(this->CreateViewGLContext(hDC)==FALSE)
{//创建RC并选为所用
return 0;
}
if(!this->InitGL())
{//初始化openGL
return 0;
}
return 0;
}
void COpenGLDemoView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
if(wglGetCurrentContext()!=NULL)
{
wglMakeCurrent(NULL,NULL);
}
if(this->m_hGLContext!=NULL)
{
wglDeleteContext(this->m_hGLContext);
this->m_hGLContext = NULL;
}
}
void COpenGLDemoView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
GLsizei width,height;
width = cx;
height = cy;
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);//透视投影
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
void COpenGLDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting
this->DrawGLScene();
}
int COpenGLDemoView::DrawGLScene(GLvoid)
{// Here's Where We Do All The Drawing
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(-1.5f,0.0f,-6.0f);//物体左移1.5,向内移6,相当于移动镜头一样,让物体进入镜头中
glBegin(GL_TRIANGLES); // 绘制三角形
glColor3f(255.0f,0.0f,0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f); // 上顶点
glColor3f(0.0f,255.0f,0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f); // 左下
glColor3f(0.0f,0.0f,255.0f);
glVertex3f( 1.0f,-1.0f, 0.0f); // 右下
glEnd(); // 三角形绘制结束
glTranslatef(3.0f,0.0f,0.0f);
glBegin(GL_QUADS); // 绘制正方形
glColor3f(255.0f,0.0f,0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // 左上
glColor3f(0.0f,255.0f,0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f); // 右上
glColor3f(0.0f,0.0f,255.0f);
glVertex3f( 1.0f,-1.0f, 0.0f); // 左下
glColor3f(255.255f,255.0f,255.0f);
glVertex3f(-1.0f,-1.0f, 0.0f); // 右下
glEnd(); // 正方形绘制结束
glFlush();
::SwapBuffers(::wglGetCurrentDC()); //交换前后缓存(因为前面设置了双缓存方式)
return TRUE; // Everything Went OK
}
PS:标红的一行代码在原来的博客里面是没有的,因为运行了原文代码后发现窗口什么都没画出来,于是上网查了一些其它博客。发现必须要调用SwapBuffers函数,原理就是双缓存的方式,每次glClear后的绘图代码是对后台缓冲区的操作,因此最后要调用这个函数来进行前后缓冲区的交换,完成显示。
SwapBuffers是wgl函数,简单说一下什么是wgl。OpenGL只包括绘图指令,本身不提供窗口系统,但是这又是显示所不可缺少的。Windows为了在窗口中支持OpenGL渲染,在win32库中扩展了一些以wgl为前缀的函数(虽然这里的SwapBuffers并没有wgl前缀
),功能包括对像素格式进行初始化、控制渲染以及访问OpenGL扩展功能。特别要注意的是最后一项功能,windows提供的gl和glu函数库只包括OpenGL1.1版本的功能,对于以后的扩展功能只能通过wgl相关函数来获取相应功能的函数指针。对于wgl,红宝书的附录中有比较详细的介绍。
补充:改变窗口大小时闪烁是windows图形图像编程中的一个问题。这里由于我们采用OpenGL而不是GDI绘图,所以有一种简单的方法。事实上我们已经采用的双缓冲绘图方式已经起到了防止窗口闪烁的作用了,它的原理是用快速的复制操作代替耗时的擦除和重绘操作,但是我们仍然需要屏蔽掉WM_ERASEBKGND消息:
BOOL CglWithMFCView::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
return TRUE;
//return CView::OnEraseBkgnd(pDC);
}这个消息返回TRUE则表示窗口不需要擦除,这样由于改变窗口大小而产生的擦除消息就被我们永远屏蔽掉了,相应的擦除操作就没有了。再结合我们前面的双缓冲方式,闪烁问题就解决了。
相关文章推荐
- Phinecos(洞庭散人) 专注于开源技术的研究与应用 基于MFC的OpenGL绘图
- Phinecos(洞庭散人) 专注于开源技术的研究与应用 TinyXML:一个优秀的C++ XML解析器
- 专注于开源技术的研究与应用由Tencent://Message协议想到的一个解决方案
- 专注于开源技术的研究与应用 Ubuntu下配置samba实现文件夹共享
- 开发框架:JDO技术分析及企业应用研究
- 软件系统开发中的组件框架技术研究、设计和应用
- 软件系统开发中的组件框架技术研究、设计和应用[转]
- 软件系统开发中的组件框架技术研究、设计和应用【转自lrn资源网】
- 技术宅---我的网上抢火车票攻略 - Phinecos(洞庭散人) - 博客园
- 软件系统开发中的组件框架技术研究、设计和应用
- Nehe的OpenGL框架(MFC版)
- 软件系统开发中的组件框架技术研究、设计和应用【转】
- Nehe的OpenGL框架(MFC版)
- 干货分享:分析Android应用使用的技术框架和开源库
- Nehe的OpenGL框架(MFC版)
- 软件系统开发中的组件框架技术研究、设计和应用
- 基于DNF4.0框架的MSBuild编译技术研究及其应用
- 分析Android应用使用的技术框架和开源库
- Nehe的OpenGL框架(MFC版)
- 软件系统开发中的组件框架技术研究、设计和应用