一、 设置像素格式
像素格式用于指定OpenGL绘画的一些属性,在windows中,使用PIXELFORMATDESCRIPTOR结构体来描述。一个设备可以支持许多像素格式,但只能拥有一种当前像素格式,需要从这一系列的像素格式中选择出一种合适的像素格式来,并设置它。主要属性有:
- 像素缓冲是单缓冲还是双缓冲;
- 像素数据时RGBA还是颜色索引;
- 颜色数据的位数;
- 深度缓冲的位数;
- 模板缓冲的位数;
- 层的数量;
- 各种可视化掩膜;
代码片段如下:
1.1 填写PIXELFORMATDESCRIPTOR结构体
static PIXELFORMATDESCRIPTOR pfd= {
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
bits, // Select Our 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, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
1.2 选择合适的像素格式
// get the best available match of pixel format for the device context
int iPixelFormat = ChoosePixelFormat(hdc, &pfd);
if(0 == iPixelFormat)
{
cerr << "Choose pixel format failed." << endl;
...
}
1.3 设置像素格式
// make that the pixel format of the device context
if(!SetPixelFormat(hdc, iPixelFormat, &pfd))
{
cerr << "Set pixel format failed." << endl;
...
}
注意:必须在创建渲染上下文前设置像素格式。
参考:http://msdn.microsoft.com/en-us/library/dd368832%28v=vs.85%29
二、 创建OpenGL渲染上下文(rendering context)
每一个调用了OpenGL API的线程都必须要有一个OpenGL渲染上下文,这个渲染上下文用来将OpenGL链接到Windwos的窗口系统。
一个线程只能有一个当前渲染上下文,一个渲染上下文只能最为一个线程的当前上下文。如果调用OpenGL API的线程缺少当前渲染上下文,则不会有任何结果产生。
2.1 创建OpenGL上下文
HGLRC hglrc = wglCreateContext(hdc);
if(!hglrc)
{
cerr << "Create render contex failed." << endl;
…
}
2.2 将OpenGL上下文设置为当前线程的当前上下文
if(!wglMakeCurrent(hdc, hglrc))
{
cerr << "Make current rendering context failed." << endl;
…
}
如果要清除当前上下文,可以将wglMakeCurrent中的参数设置为NULL即可。
注意:参数hdc必须和设置像素格式时使用的是同一个hdc。
参考:http://msdn.microsoft.com/en-us/library/dd369038%28v=vs.85%29
三、 显示OpenGL渲染内容
当前面两个步骤完成后,就可以使用OpenGL API进行渲染了。这时不再关注具体的渲染上下文,只需调用OpenGL的相应API即可。待渲染完毕,下一步要做的时就是要把它显示在窗口环境中。因为Windows下的设备环境使用了双缓冲的机制,所以这里就需要交换这两个缓冲,即可将渲染的内容显示在窗口中了。具体代码如下:
SwapBuffers(hdc); // hdc需和前面两个步骤中的hdc相同
四、 销毁OpenGL上下文
当我们不再进行OpenGL渲染的时候,就可以将OpenGL上下文销毁了。具体代码如下:
if (hglrc) // Do We Have A Rendering Context?
{
// Are We Able To Release The DC And RC Contexts?
if (!wglMakeCurrent(NULL,NULL))
{
cerr << “Release HGLRC failed.” << endl;
}
if (!wglDeleteContext(hglrc)) // Are We Able To Delete The HGLRC?
{
cerr << "Release Rendering Context Failed.” << endl;
}
hglrc =NULL; // Set RC To NULL
}
附录
I. 创建窗口
前面说到那么多,但都没有说到如何创建显示OpenGL渲染内容的窗口,下面接着说一下如何创建一个Windows窗口吧。具体代码如下:
1)注册WNDCLASS类(结构体)
WNDCLASS wc; // Windows Class Structure
hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
// Redraw On Size, And Own DC For Window.
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc Handles Messages
wc.cbClsExtra = 0; // No Extra Window Data
wc.cbWndExtra = 0; // No Extra Window Data
wc.hInstance = hInstance; // Set The Instance
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
wc.hbrBackground = NULL; // No Background Required For GL
wc.lpszMenuName = NULL; // We Don't Want A Menu
wc.lpszClassName = "OpenGL"; // Set The Class Name
if (!RegisterClass(&wc)) // Attempt To Register The Window Class
{
cerr << “Failed to register the window.” << endl;
…
}
2)创建窗口
HWND hWnd = CreateWindow("OpenGL", "Hello World.",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
if(!hWnd)
{
cerr << “Create window failed.” << endl;
…
}
ShowWindow(hWnd, SW_SHOW);
Ⅱ. 销毁窗口
当不再需要该窗口时,需要对其进行销毁,步骤如下:
if (hdc && !ReleaseDC(hWnd,hdc)) // Are We Able To Release The DC
{
cerr << "Release Device Context Failed." << endl;
hdc = NULL; // Set DC To NULL
}
if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window?
{
cerr << "Could Not Release hWnd." << endl;
hWnd=NULL; // Set hWnd To NULL
}
if (!UnregisterClass("OpenGL",hInstance)) // Are We Able To Unregister Class
{
cerr << "Could Not Unregister Class." << endl;
hInstance=NULL; // Set hInstance To NULL
}