建立多窗口openGL程序,可以用来制作各种GL控制或者多视图GL程序,为以后设计组态openGL引擎试验。
基础知识
1.OpenGL与其他窗体应用程序消息循环上的不同
这个大家都知道,因为其他窗体应用程序不需要实时绘制,但需要实时监听消息响应,所以为了提高性能,openGL和其他窗体程序的消息循环写法有一点点不一样。(就因为如此,所以我们需要使用多线程来建立不同的窗口)
a.一般窗体程序(例如MFC)消息循环机制如下:
1 |
MSG
msg; |
2 |
while (GetMessage(&msg,NULL,0,0)) |
3 |
{ |
4 |
TranslateMessage(&msg); |
5 |
DispatchMessage(&msg); |
6 |
} |
这么的话需要等系统的WM_PAINT消息才去重新绘制,对3D动画程序来说肯定效率低下,但对窗体应用程序来说却很节省资源。
b.OpenGL改进后的循环如下:
01 |
while (!done) |
02 |
|
03 |
{ |
04 |
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) |
05 |
|
06 |
{ |
07 |
|
08 |
if (msg.message==WM_QUIT) |
09 |
done=TRUE; |
10 |
else |
11 |
|
12 |
{ |
13 |
|
14 |
TranslateMessage(&msg); //
翻译消息 |
15 |
DispatchMessage(&msg); //
发送消息 |
16 |
} |
17 |
} |
18 |
|
19 |
else |
20 |
{ |
21 |
|
22 |
DrawGL(); //绘制gl窗口 |
23 |
|
24 |
} |
25 |
|
26 |
} |
PeekMessage和GetMessage区别就是他不会等函数返回就直接往下执行了,效率当然高很多。
2.多线程
由于第一点原因,所以我们使用多线程。多线程win32api函数:
CreateThread();
返回一个句柄。
这样就能建立多个线程独立运行各个窗口函数,建立其他窗口来控制openGL绘制或者建立多个窗口不同视角来显示GL物体等。窗体间能建立父子关系,可以想象下photoshop,就可以知道这种多窗口程序有多诱人了^ ^.当然还可以做窗口停靠。
示例代码:
文件1:
01 |
#include
<windows.h> |
02 |
#include
<gl\glew.h> |
03 |
#include
<gl\glut.h> |
04 |
#include
"ControlPad.h" |
05 |
|
06 |
void display( void ) |
07 |
{ |
08 |
glClear(GL_COLOR_BUFFER_BIT); |
09 |
|
10 |
glutSwapBuffers(); |
11 |
} |
12 |
|
13 |
void init( void ) |
14 |
{ |
15 |
glClearColor(0.0,0.0,0.0,0.0); |
16 |
glMatrixMode(GL_PROJECTION); |
17 |
|
18 |
glLoadIdentity(); |
19 |
glOrtho(0.0,1.0,0.0,1.0,-1.0,1.0); |
20 |
} |
21 |
|
22 |
int WINAPI
WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstace, LPSTR lpCmdLine, int nCmdShow) |
23 |
{ |
24 |
int argc
= 2; |
25 |
char *
argv[] = { "Jerry" , "OpenGL" }; |
26 |
glutInit(&argc,argv); |
27 |
glutInitDisplayMode(GLUT_DOUBLE
| GLUT_RGB); |
28 |
glutInitWindowSize(800,600); |
29 |
glutInitWindowPosition(100,100); |
30 |
glutCreateWindow( "TestMode" ); |
31 |
|
32 |
|
33 |
|
34 |
//重点在这里 |
35 |
|
36 |
HANDLE hThread; |
37 |
hThread
= CreateThread(NULL,0,WinControlMain,NULL,0,NULL); |
38 |
CloseHandle(hThread); |
39 |
|
40 |
|
41 |
|
42 |
init(); |
43 |
glutDisplayFunc(display); |
44 |
glutMainLoop(); |
45 |
return 0; |
46 |
} |
文件2:ControlPad.cpp
01 |
#include
<windows.h> |
02 |
#include
<stdio.h> |
03 |
#include
"ControlPad.h" |
04 |
|
05 |
LRESULT CALLBACK
WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
06 |
{ |
07 |
switch (uMsg) |
08 |
{ |
09 |
case WM_CHAR: |
10 |
char szChar[20]; |
11 |
//sprintf(szChar,"char
code is %d",wParam); |
12 |
MessageBox(hwnd,szChar, "char" ,0); |
13 |
break ; |
14 |
case WM_DESTROY: |
15 |
PostQuitMessage(0); |
16 |
break ; |
17 |
default : |
18 |
return DefWindowProc(hwnd,uMsg,wParam,lParam); |
19 |
} |
20 |
return 0; |
21 |
} |
22 |
|
23 |
DWORD WINAPI
WinControlMain( LPVOID lpParameter) |
24 |
{ |
25 |
WNDCLASS
wndcls; |
26 |
wndcls.cbClsExtra
= 0; |
27 |
wndcls.cbWndExtra
= 0; |
28 |
wndcls.hbrBackground
= ( HBRUSH )COLOR_BACKGROUND; //GetStockObject(BLACK_BRUSH); |
29 |
wndcls.hCursor
= LoadCursor(NULL,IDC_CROSS); |
30 |
wndcls.hIcon
= LoadIcon(NULL,IDI_ERROR); |
31 |
wndcls.hInstance
= 0; //hInstance; |
32 |
wndcls.lpfnWndProc
= WinProc; |
33 |
wndcls.lpszClassName
= "GL
Control" ; |
34 |
wndcls.lpszMenuName
= NULL; |
35 |
wndcls.style
= CS_HREDRAW | CS_VREDRAW; |
36 |
RegisterClass(&wndcls); |
37 |
|
38 |
HWND hwnd; |
39 |
hwnd
= CreateWindow( "GL
Control" , "GL
Control" ,WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,0,NULL); |
40 |
|
41 |
ShowWindow(hwnd,SW_SHOWNORMAL); |
42 |
UpdateWindow(hwnd); |
43 |
|
44 |
MSG
msg; |
45 |
while (GetMessage(&msg,NULL,0,0)) |
46 |
{ |
47 |
TranslateMessage(&msg); |
48 |
DispatchMessage(&msg); |
49 |
} |
50 |
return msg.wParam; |
51 |
} |
当然我这里写的比较简单,做个示范提供个思路而已,等待以后慢慢扩展。我故意避开mfc,考虑到以后效率问题^^,其实在mfc里可以更简单的做这个,但是咱们提倡直接win32api。