名词介绍
设备上下文
Windows图形设备接口(GDI)能够绘制到屏幕、内存、打印机或任何提供一个接口层,可以处理GDI调用其他设备。GDI通过渲染处理当前选择的设备,这就是所谓的设备上下文,或DC。
绘制上下文
渲染上下文是GDI的OpenGL的等效直流。所有的OpenGL调用渲染到装置通过一个RC。OpenGL渲染环境保持状态变量,如当前背景色,当前颜色等直流保持GDI状态变量如当前笔,当前刷等。
像素格式
像素格式调用OpenGL和渲染操作,Windows执行之间的转换层
举个例子,若像素格式只支持很少一部分颜色值,则OpenGL在用RGB值(128,120,135)绘制一个像素时,就可能使用转换后的值(128,128,128)来绘制.
第一个基于MFC的OpenGL应用程序
环境:VC6.0
- 首先下载需要的GLUT头文件,DLL和Lib文件,
下载链接: glutdlls37beta.zip ,解压缩后把gltu.h放到”VC98/Include/GL”下,把glut.lib和glut32.lib放到”VC9/Lib” 下,glut32.dll和glut.dll放到你创建的应用程序的运行目录下- 创建一个当文档应用程序
在项目的工具–>设置–>连接中配置好库文件
- 在stdafx.h中加入下列语句,这几个是OpenGL函数调用需要使用的,添加在这个头文件中是因为其他的几个头文件中已经引入了这个头文件
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <gl/glaux.h>
- 需要为项目添加消息处理函数
1.右键view类添加消息函数
WM_CREATE (for OnCreate),
WM_DESTROY (for OnDestroy),
WM_SIZE (for OnSize),
WM_ERASEBACKGROUND (for OnEraseBkground)
- 在窗口创建之前我们必须设置窗口风格包含
WS_CLIPCHILDREN和 WS_CLIPSIBLINGS
从而避免OpenGL绘制到其他窗口中去。
BOOL CDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
//设置窗口风格防止绘图的时候绘制到其他窗口中去
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
return CView::PreCreateWindow(cs);
}
- 右键view类,添加以下几个变量,就是前面所指的DC和RC
HGLRC m_hRC; //Rendering Context
CDC* m_pDC; //Device Context
- 之后添加以下几个函数
void RenderScene ();//屏幕刷新的时候回调函数
BOOL SetupPixelFormat();//设置像素格式
BOOL InitializeOpenGL();//初始化函数
- 在OnCreate中我们将通过建立像素格式和绘制上下文来初始化OpenGL. 在InitializeOpenGL()中会创建一个设备上下文(DC),为这个DC选择一个像素格式,创建和这个DC相关的绘制上下文(RC),然后选择这个RC.这个函数会调用SetupPixelFormat()来建立像素格式
int CDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
InitializeOpenGL();//初始化OpenGL
return 0;
}
BOOL CDemoView::InitializeOpenGL()
{
//获取当前的设上下文DC
m_pDC = new CClientDC(this);
//如果DC获取失败执行的处理方式
if(m_pDC == NULL)
{
MessageBox("Error Obtaining DC");
return FALSE;
}
//判断像素设置是否正常
if(!SetupPixelFormat())
{
return FALSE;
}
//创建绘制上下文RC
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//如果创建失败,弹出消息
if(m_hRC == 0)
{
MessageBox("Error Creating RC");
return FALSE;
}
//选择创建的RC
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
MessageBox("Error making RC Current");
return FALSE;
}
//Specify Black as the clear color
::glClearColor(0.0f,0.0f,0.0f,0.0f);
//Specify the back of the buffer as clear depth
::glClearDepth(1.0f);
//Enable Depth Testing
::glEnable(GL_DEPTH_TEST);
return TRUE;
}
//默认就可以了
BOOL CDemoView::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
16, // 16-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
if ( m_nPixelFormat == 0 )
{
return FALSE;
}
if ( ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)
{
return FALSE;
}
return TRUE;
}
- 在OnSize()中一般用来设置视口和视锥,因为这些是和窗口大小相关的。基本操作包括设置视口,选择投影矩阵,设置模型视图矩阵
void CDemoView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
GLdouble aspect_ratio; // width/height ratio
if ( 0 >= cx || 0 >= cy )
{
return;
}
// select the full client area
::glViewport(0, 0, cx, cy);
// compute the aspect ratio
// this will keep all dimension scales equal
aspect_ratio = (GLdouble)cx/(GLdouble)cy;
// select the projection matrix and clear it
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
// select the viewing volume
::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);
// switch back to the modelview matrix and clear it
::glMatrixMode(GL_MODELVIEW);
::glLoadIdentity();
}
- 在绘制场景时,一般包括如下步骤:
- 清空缓存。
- 绘制场景。
- Flush掉渲染流水线。
- 若设置了双缓冲,则交换前后台缓冲区
void CDemoView::OnDraw(CDC* pDC)
{
CDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// 清空颜色和深度缓存
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
RenderScene();
// Tell OpenGL to flush its pipeline
::glFinish();
//交换缓冲区
::SwapBuffers( m_pDC->GetSafeHdc() );
}
//具体绘制什么图形感觉应该放在这里
void CDemoView::RenderScene()
{
}
- 为了防止窗口大小改变时不闪烁,在关闭程序的时候不出现内存泄漏
//在之前已经使用OpenGL清除颜色和深度缓存,所以不需要Windows自己再清理一遍,把它注释掉就不会闪烁
BOOL CDemoView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
//把这句话注释掉,防止窗口闪烁
//return CView::OnEraseBkgnd(pDC);
return TRUE;
}
/*内存泄露的原因是我们在SetupPixelFormat()中使用了new运算符来为CClientDC对象分配内存,因此需要显示delete掉。*/
void CDemoView::OnDestroy()
{
CView::OnDestroy();
//Make the RC non-current
if(::wglMakeCurrent (0,0) == FALSE)
{
MessageBox("Could not make RC non-current");
}
//Delete the rendering context
if(::wglDeleteContext (m_hRC)==FALSE)
{
MessageBox("Could not delete RC");
}
//Delete the DC
if(m_pDC)
{
delete m_pDC;
}
//Set it to NULL
m_pDC = NULL;
}
到此一个基本的框架就算是搭建完毕了