首页
登录 | 注册

【菜鸟也能玩转OpenGL】最简单的OpenGL窗口

本系列文章由 莫问 出品,转载请注明出处。

文章链接: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窗口背景



2020 jeepxie.net webmaster#jeepxie.net
10 q. 0.009 s.
京ICP备10005923号