1.1 windows平台OpenGL介绍
OpenGL是一个强大的2D/3D图形库。作为初学者,在查看各类网络文章或书籍时,往往一开始就被里面提到的各种各样的OpenGL开发库搞糊涂了,为什么开发OpenGL程序要这么多库呢?
OpenGL本身是一个图形开发系统,且OpenGL是利用硬件加速的,这就决定了它需要直接操作显示设备,而在各种现代操作系统中,应用程序及应用程序库都不能直接操作硬件设备,而只能通过操作系统提供的接口层实现对硬件的访问。
微软与SGI有过一段非常短暂的合作开发OpenGL的阶段,所以从windows95(winnt 3.5)开始,windows操作系统提供了对OpenGL的内在支持,除windows Mobile版本之外,都可以在其系统目录中找到opengl32.dll这个动态链接库,在安装了VC6或VisualStudio任何一个版本之后,都能找到gl/gl.h和gl/glu.h这两个头文件,在微软的MSDN上也能找到OpenGL相关的文档。不过,在这段合作中,微软只是想学点技术发展自己的DirectX,所以很快合作失败了,但windows对OpenGL的内在支持却延续至今。
想想我们调用C语言的标准库函数printf,其实printf也需要在某个时候操作显示设备,从而显示出字符串,它利用的是操作系统提供的接口。从这个意义上讲,在windows上使用OpenGL函数与使用printf并无任何区别。
下面介绍一下在windows平台上完成最简单的OpenGL程序需要完成的最基础工作:创建环境。
1.2 创建OpenGL环境
正如在windows上使用Socket要首先调用WSAStartup(…)函数创建好Socket环境,使用OpenGL函数之前也需要创建好环境。VC6或VisualStudio安装好后自带的库中,及下载的windows各版本SDK库中,都提供了对OpenGL的支持。我没有去细究所有细节,只查找了几个主要的数据类型和函数:
1.2.1数据类型及结构
1) PIXELFORMATDESCRIPTOR结构
该结构体的定义位于:wingdi.h
2) HGLRC结构
该结构的定义位于:windef.h,以如下形式声明,其中DECLARE_HANDLE是一个宏
DECLARE_HANDLE(HGLRC); // OpenGL
3)DECLARE_HANDLE宏
该宏位于winnt.h中,定义如下:
#defineDECLARE_HANDLE(name)struct name##__{int unused;};typedefstruct name##__ *name
将2)3)结合在一起得到:
struct HGLRC__{int unused;};
typedef struct HGLRC__ * HGLRC
1.2.2 函数
在wingdi.h中有如下一组函数声明:
// OpenGL wglprototypes
WINGDIAPIBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT);
WINGDIAPIHGLRCWINAPI wglCreateContext(HDC);
WINGDIAPIHGLRCWINAPIwglCreateLayerContext(HDC,int);
WINGDIAPIBOOL WINAPI wglDeleteContext(HGLRC);
WINGDIAPIHGLRCWINAPIwglGetCurrentContext(VOID);
WINGDIAPIHDC WINAPI wglGetCurrentDC(VOID);
WINGDIAPIPROC WINAPI wglGetProcAddress(LPCSTR);
WINGDIAPIBOOL WINAPI wglMakeCurrent(HDC,HGLRC);
WINGDIAPIBOOL WINAPI wglShareLists(HGLRC,HGLRC);
WINGDIAPIBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD);
WINGDIAPIBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD);
用于创建OpenGL环境的函数就在其中。
1)HGLRC wglCreateContext(HDC)
用于创建OpenGL的RenderingContext句柄,需要一个有效地HDC参数。
2)BOOL wglMakeCurrent(HDC,HGLRC)
将HGLRC设置与指定HDC绑定。
以上就是所有Windows平台上OpenGL相关的创建类型与函数。使用这些函数可以创建OpenGL运行环境,且不需要使用微软提供的库之外的任何第三方库。
1.2.3 环境创建步骤
这小节介绍具体如何创建最简单的创建OpenGL环境。首先强调一遍,创建OpenGL环境,并不需要使用任何第三方库。当然如果愿意,我们也可以选择使用freeglut库的glutInit\glutCreateWindow函数来完成环境创建工作。
创建环境的核心函数是wglCreateContext(HDC),这里可以看到参数是HDC类型,熟悉Windows窗口程序就明白,HDC需要从一个窗体获得,这表明为了使用wglCreateContext函数,首先需要创建一个窗口,而创建窗口需要一个程序句柄 HINSTANCE。这就是全部,非常简单,下面整理成5点:
1) 获取一个合法的HINSTANCE
2) 创建一个窗口,并获得HWND
3) 通过HWND获取窗口的HDC
4) 利用HDC创建HGLRC
5) 将HGLRC与HDC绑定
6) 利用glGetString函数获取OpenGL相关信息
1.3 测试程序
理论说得再多不如看一个实例,当然实例要越简单越好,太过复杂的示例程序将显著增加学习的难度。
这里我设计了一个示例:
1)一个控制台程序
2)创建OpenGL环境
3)调用glGetString函数获取系统支持的OpenGL版本等信息并输出
4)撤消环境再次调用glGetString返回空值,表明环境确实在发挥作用
程序设置:创建一个空的windows控制台项目,添加如下程序,编译前需要在VisualStudio项目设置的“链接器-->输入”中添加opengl32.lib,其它均不需要变动。
程序代码及注释如下:
#include<iostream>
#include<Windows.h>
#include<gl/gl.h>
LRESULTCALLBACK WndProc(HWNDhWnd,//定义窗口回调函数,没啥解释的
UINTuMsg,
WPARAMwParam,
LPARAMlParam)
{
Return 1; //没有任何作用,只是为了能成功创建窗口
}
int main(intargc,char **argv)
{
HWND hWnd;
HGLRC hRC;
HDC hDC;
HINSTANCE hInstance;
//第 1)步:获取HINSTANCE
hInstance =GetModuleHandle(NULL);
WNDCLASS windClass;
TCHAR szWindowName[50] = TEXT("OpenGL_Window");//随便设
TCHAR szClassName[50] = TEXT("OpenGL_Class"); //随便设
//初始化窗口结构体
windClass.lpszClassName = szClassName;
windClass.lpfnWndProc = (WNDPROC)WndProc;
windClass.hInstance = hInstance;
windClass.hCursor =LoadCursor(NULL,IDC_ARROW);
windClass.hIcon =LoadIcon(NULL,IDI_WINLOGO);
windClass.hbrBackground =NULL;
windClass.lpszMenuName =NULL;
windClass.style =0;//随便设
windClass.cbClsExtra = 0;
windClass.cbWndExtra = 0;
//注册窗口类
if(!RegisterClass( &windClass )) return 1;
//第 2)步:创建窗口
hWnd = CreateWindowEx(0, // Extended style
szClassName, // class name
szWindowName, // window name
0,
0, //window position, x
0, //window position, y
0, //height
0, //width
NULL, // Parent window
NULL, // menu
hInstance, // instance
NULL); // pass this toWM_CREATE
//第 3)步:获取HDC,并随意设置一个空像素格式
hDC = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd;
SetPixelFormat( hDC, 1,&pfd);
//第 4)步:创建OpenGL环境
hRC = wglCreateContext( hDC );
//第 5)步:绑定HDC与HRC
wglMakeCurrent( hDC, hRC );
constGLubyte * pb = glGetString(GL_VERSION);//获取OpenGL版本字符串
if(pb)
std::cout <<"OpenGL versionis "<< pb << std::endl;
pb = glGetString(GL_VENDOR); //获取OpenGL显卡厂家信息字符串
if(pb)
std::cout <<"OpenGL vendoris "<< pb << std::endl;
pb = (glGetString(GL_RENDERER)); //获取OpenGL显卡型号信息字符串
if(pb)
std::cout <<"OpenGLrenderer is "<< pb << std::endl;
pb = glGetString(GL_EXTENSIONS); //获取OpenGL扩展函数名称字符串
if(pb)
std::cout <<"OpenGLextensions is "<< pb << std::endl;
//一旦释放环境,glGetString函数将总是返回空值
wglMakeCurrent(NULL,NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
//释放后再执行,则pb每次均返回空值,表明OpenGL环境已经被释放
pb = glGetString(GL_VERSION);
if(pb)
std::cout <<"OpenGL versionis "<< pb << std::endl;
pb = glGetString(GL_VENDOR);
if(pb)
std::cout <<"OpenGL vendoris "<< pb << std::endl;
pb = (glGetString(GL_RENDERER));
if(pb)
std::cout <<"OpenGLrenderer is "<< pb << std::endl;
pb = glGetString(GL_EXTENSIONS);
if(pb)
std::cout <<"OpenGLextensions is "<< pb << std::endl;
return 0;
}
1.4 运行结果
上面示例的运行结果如下:
图中结果表明,运行本程序的系统支持的OpenGL版本为4.3.0,显卡生产厂家是NVIDIA Corporation,显卡型号是GeForce 605,支持的扩展函数名很多,这里只截图了一段。
1.5参考文献
OpenGL SuperBible 5/e
OpenGLprogramming guide 8/e