文章链接:http://blog.csdn.net/mni2005/article/details/27228111
作者:莫问(mni2005) 邮箱:mni2005@163.com
具有Windows编程经验的人都知道,在Windows下用GDI作图必须通过设备上下文(DeviceContext简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(RenderingContext简写RC)完成三维图形的绘制。
1 创建OpenGL渲染上下文
创建RC的过程,我自己总结了一下,大致需要经过以下几个步骤:
(1)获取窗口的DC,
(2)初始化窗口像素格式的对象结构体
(3)检查素格式是否与窗口的DC匹配
(4)设置窗口DC的象素格式
(5) 创建OpenGL渲染上下文hRC
(6) 将RC与窗口的DC关联起来
在windows上创建OpenGL渲染上下文,不管谁来写代码,这些步骤都是固定的,我们需要做的就是按照步骤,一步步实现就行了。先在源文件中定义一个创建渲染上下文的函数,该函数带有两个参数,窗口句柄HWND和色彩位深RC,返回值类型BOOL,创建RC成功返回TRUE,否则返回FALSE,函数定义如下:
BOOL createGLContext(HWND hWnd, int bits)
{
return TRUE;
}
下面我们按照这六个步骤,一步步来完成OpenGL渲染上下文的创建。
1、获取窗口的DC。
根据窗口句柄获取DC很简单,调用Windows函数GetDC即可,代码如下:
//1. 获取设备的DC
HDC hDC = GetDC(hWnd);
if (!hDC)
{
return FALSE;
}
2、初始化窗口像素格式的对象结构体。
窗口像素格式的结构体为PIXELFORMATDESCRIPTOR ,从MSDN中查询到它的定义如下:
typedef struct tagPIXELFORMATDESCRIPTOR { // pfd
WORD nSize;
WORD nVersion;
DWORD dwFlags;
BYTE iPixelType;
BYTE cColorBits;
BYTE cRedBits;
BYTE cRedShift;
BYTE cGreenBits;
BYTE cGreenShift;
BYTE cBlueBits;
BYTE cBlueShift;
BYTE cAlphaBits;
BYTE cAlphaShift;
BYTE cAccumBits;
BYTE cAccumRedBits;
BYTE cAccumGreenBits;
BYTE cAccumBlueBits;
BYTE cAccumAlphaBits;
BYTE cDepthBits;
BYTE cStencilBits;
BYTE cAuxBuffers;
BYTE iLayerType;
BYTE bReserved;
DWORD dwLayerMask;
DWORD dwVisibleMask;
DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR;
看完之后,大家发现该结构体参数较多,但是目前我们只要需要关注色彩位深(cColorBits)和 颜色类型(iPixelType)两个参数即可,其它参数无需关注,随着OpenGL学习的深入,大家会慢慢理解这些参数的作用。色彩位深通过函数参数传递进来, 颜色类型我们选择RGBA,最终完成结构体如下:
//2. 初始化窗口像素格式的对象结构体
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR), // 上述格式描述符的大小
1, // 版本号
PFD_DRAW_TO_WINDOW | // 格式支持窗口
PFD_SUPPORT_OPENGL | // 格式必须支持OpenGL
PFD_DOUBLEBUFFER, // 必须支持双缓冲
PFD_TYPE_RGBA, // 申请 RGBA 格式
bits, // 选定色彩深度
0, 0, 0, 0, 0, 0, // 忽略的色彩位
0, // 无Alpha缓存
0, // 忽略Shift Bit
0, // 无累加缓存
0, 0, 0, 0, // 忽略聚集位
16, // 16位 Z-缓存 (深度缓存)
0, // 无蒙板缓存
0, // 无辅助缓存
PFD_MAIN_PLANE, // 主绘图层
0, // Reserved
0, 0, 0 // 忽略层遮罩
};
3、检查素格式是否与窗口的DC匹配
完成了窗口像素格式的初始化,接下来需要检查我们定义的像素格式与当前的窗口DC是否匹配,这里用到一个函数ChoosePixelFormat,该函数的参数很简单,传递窗口DC和像素格式结构体,匹配成功能返回非零值,否份返回零。代码如下:
//3. 检查素格式是否与窗口的DC匹配
int pixelFormat = ChoosePixelFormat(hDC, &pfd);
if ( !pixelFormat )
{
return FALSE;
}
4、设置窗口DC的象素格式
我们定义的像素格式与当前的窗口DC匹配成功后,根据检查结果的返回值,调用SetPixelFormat函数,将窗口DC的象素格式设置成我们自己定义的像素格式。代码如下:
//4. 如果匹配成功,设置窗口DC的象素格式
if(!SetPixelFormat(hDC, pixelFormat, &pfd))
{
return FALSE;
}
5、 创建OpenGL渲染上下文RC
窗口DC的像素格式设置完成后,下面就该干我们最主要的事情,便就是根据窗口的DC创建我们所需的OpenGL渲染上下文,代码如下:
//5. 创建OpenGL设备上下文hRC
g_hRC = wglCreateContext(hDC);
if (! g_hRC)
{
return FALSE;
}
(6) 将RC与窗口的DC关联起来
最后激活我们所创建的RC,即将RC与当前窗口的DC关联起来。这样后面所有的OpenGL函数都是在该渲染上下文下进行绘图,从这里我们可以看出,OpenGL只能有一个激活的渲染上下文,而且OpenGL函数仅仅在当前激活的渲染上下文中绘图。代码如下:
//6. 将hRC与窗口的hDC关联起来。
if(!wglMakeCurrent(hDC, g_hRC))
{
return FALSE;
}
到此,我们的OpenGL渲染上下文创建完毕了,完整的函数实现如下:
BOOL createGLContext(HWND hWnd, int bits)
{
//1. 获取设备的DC
HDC hDC = GetDC(hWnd);
if (!hDC)
{
return FALSE;
}
//2. 初始化窗口像素格式的对象结构体
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR), // 上述格式描述符的大小
1, // 版本号
PFD_DRAW_TO_WINDOW | // 格式支持窗口
PFD_SUPPORT_OPENGL | // 格式必须支持OpenGL
PFD_DOUBLEBUFFER, // 必须支持双缓冲
PFD_TYPE_RGBA, // 申请 RGBA 格式
bits, // 选定色彩深度
0, 0, 0, 0, 0, 0, // 忽略的色彩位
0, // 无Alpha缓存
0, // 忽略Shift Bit
0, // 无累加缓存
0, 0, 0, 0, // 忽略聚集位
16, // 16位 Z-缓存 (深度缓存)
0, // 无蒙板缓存
0, // 无辅助缓存
PFD_MAIN_PLANE, // 主绘图层
0, // Reserved
0, 0, 0 // 忽略层遮罩
};
//3. 检查素格式是否与窗口的DC匹配
int pixelFormat = ChoosePixelFormat(hDC, &pfd);
if ( !pixelFormat )
{
return FALSE;
}
//4. 如果匹配成功,设置窗口DC的象素格式
if(!SetPixelFormat(hDC, pixelFormat, &pfd))
{
return FALSE;
}
//5. 创建OpenGL设备上下文hRC
g_hRC = wglCreateContext(hDC);
if (! g_hRC)
{
return FALSE;
}
//6. 将hRC与窗口的hDC关联起来。
if(!wglMakeCurrent(hDC, g_hRC))
{
return FALSE;
}
return TRUE;
}
2 销毁OpenGL设备上下文
bool destroyGLContext()
{
if (g_hRC)
{
//释放OpenGL设备上下文hRC
if (wglMakeCurrent(NULL,NULL))
{
//删除OpenGL设备上下文hRC
if (wglDeleteContext(g_hRC))
{
g_hRC = NULL;
}
}
}
}
3 设置OpenGL大小
4 清空OpenGL窗口背景