OpenGL学习笔记
一.目前网上流传的OpenGL学习笔记主要可以分为三种,一种是以红宝书,蓝宝书为主的,使用glut绘制窗口,第二种则是像Nehe使用windows的API,第三种是在windows下使用的以MFC类库为主的教程,我的笔记里主要是使用第二种方式。
二.绘制窗口
全部代码如下:
#include #include #include #include #include HGLRC hRC=NULL;
HDC hDC=NULL;
HWND hWnd=NULL;
HINSTANCE hInstance;
bool keys[256];
bool active=TRUE;
bool fullscreen=TRUE;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) { if (height==0) { height=1;
} glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
} int InitGL(GLvoid) { glShadeModel(GL_SMOOTH);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return TRUE;
} int DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
return TRUE;
} GLvoid KillGLWindow(GLvoid) { if (fullscreen) { ChangeDisplaySettings(NULL,0);
ShowCursor(TRUE);
} if (hRC) { if (!wglMakeCurrent(NULL,NULL)) { MessageBox(NULL,TEXT("释放DC或RC失败。"),TEXT("关闭错误"),MB_OK | MB_ICONINFORMATION);
} if (!wglDeleteContext(hRC)) { MessageBox(NULL,TEXT("释放DC或RC失败。"),TEXT("关闭错误"),MB_OK | MB_ICONINFORMATION);
} hRC=NULL;
} if (hDC && !ReleaseDC(hWnd,hDC)) { MessageBox(NULL,TEXT("释放DC或RC失败。"),TEXT("关闭错误"),MB_OK | MB_ICONINFORMATION);
hDC=NULL;
} if (hWnd && !DestroyWindow(hWnd)) { MessageBox(NULL,TEXT("释放窗口句柄失败。"),TEXT("关闭错误"),MB_OK | MB_ICONINFORMATION);
hWnd=NULL;
} if (!UnregisterClass(TEXT("OpenGL"),hInstance)) { MessageBox(NULL,TEXT("不能注销窗口类。"),TEXT("关闭错误"),MB_OK | MB_ICONINFORMATION);
hInstance=NULL;
} } BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) { GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;
fullscreen=fullscreenflag;
hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("OpenGL");
if (!RegisterClass(&wc)) { MessageBox(NULL,TEXT("注册窗口失败"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} if (fullscreen) { DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth= width;
dmScreenSettings.dmPelsHeight= height;
dmScreenSettings.dmBitsPerPel= bits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { if (MessageBox(NULL,TEXT("全屏模式在当前显卡上设置失败!/n使用窗口模式?"),TEXT("NeHe G"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES) { fullscreen=FALSE;
} else { MessageBox(NULL,TEXT("程序将被关闭"),TEXT("错误"),MB_OK|MB_ICONSTOP);
return FALSE;
} } } if (fullscreen) { dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
ShowCursor(FALSE);
} else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
} AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
if (!(hWnd=CreateWindowEx( dwExStyle, TEXT("OpenGL"), title, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, hInstance, NULL))) { KillGLWindow();
MessageBox(NULL,TEXT("不能创建一个窗口设备描述表"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} static PIXELFORMATDESCRIPTOR pfd= { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, bits, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 };
if (!(hDC=GetDC(hWnd))) { KillGLWindow();
MessageBox(NULL,TEXT("不能创建一种相匹配的像素格式"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) { KillGLWindow();
MessageBox(NULL,TEXT("不能设置像素格式"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} if(!SetPixelFormat(hDC,PixelFormat,&pfd)) { KillGLWindow();
MessageBox(NULL,TEXT("不能设置像素格式"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} if (!(hRC=wglCreateContext(hDC))) { KillGLWindow();
MessageBox(NULL,TEXT("不能创建OpenGL渲染描述表"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} if(!wglMakeCurrent(hDC,hRC)) { KillGLWindow();
MessageBox(NULL,TEXT("不能激活当前的OpenGL渲然描述表"),TEXT("错误"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} ShowWindow(hWnd,SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
ReSizeGLScene(width, height);
if (!InitGL()) { KillGLWindow();
MessageBox(NULL,TEXT("Initialization Failed."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
} return TRUE;
} LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg,WPARAM wParam,LPARAM lParam) { switch (uMsg) { case WM_ACTIVATE: { if (!HIWORD(wParam)) { active=TRUE;
} else { active=FALSE;
// 程序不再激活 } return 0;
// 返回消息循环 } case WM_SYSCOMMAND: // 系统中断命令 { switch (wParam) // 检查系统调用 { case SC_SCREENSAVE: // 屏保要运行? case SC_MONITORPOWER: // 显示器要进入节电模式? return 0;
// 阻止发生 } break;
// 退出 } case WM_CLOSE: // 收到Close消息? { PostQuitMessage(0);
// 发出退出消息 return 0;
// 返回 } case WM_KEYDOWN: // 有键按下么? { keys[wParam] = TRUE;
// 如果是,设为TRUE return 0;
// 返回 } case WM_KEYUP: // 有键放开么? { keys[wParam] = FALSE;
// 如果是,设为FALSE return 0;
// 返回 } case WM_SIZE: // 调整OpenGL窗口大小 { ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
// LoWord=Width,HiWord=Height return 0;
// 返回 } } return DefWindowProc(hWnd,uMsg,wParam,lParam);
} int WINAPI WinMain( HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { MSG msg;
// Windowsx消息结构 BOOL done=FALSE;
// 用来退出循环的Bool 变量 //这段代码完全可选。程序弹出一个消息窗口,询问用户是否希望在全屏模式下运行。如果用户单击NO按钮,fullscreen变量从缺省的TRUE改变为FALSE,程序也改在窗口模式下运行。 // 提示用户选择运行模式 if (MessageBox(NULL,TEXT("你想在全屏模式下运行么?"),TEXT( "设置全屏模式"),MB_YESNO|MB_ICONQUESTION)==IDNO) { fullscreen=FALSE;
// FALSE为窗口模式 } // 创建OpenGL窗口 if (!CreateGLWindow("NeHe's OpenGL程序框架",640,480,16,fullscreen)) { return 0;
// 失败退出 } while(!done) // 保持循环直到 done=TRUE { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // 有消息在等待吗? { if (msg.message==WM_QUIT) // 收到退出消息? { done=TRUE;
// 是,则done=TRUE } else // 不是,处理窗口消息 { TranslateMessage(&msg);
// 翻译消息 DispatchMessage(&msg);
// 发送消息 } } else // 如果没有消息 { if (active) // 程序激活的么? { if (keys[VK_ESCAPE]) // ESC 按下了么? { done=TRUE;
// ESC 发出退出信号 } else // 不是退出的时候,刷新屏幕 { DrawGLScene();
// 绘制场景 SwapBuffers(hDC);
// 交换缓存 (双缓存) } } if (keys[VK_F1]) // F1键按下了么? { keys[VK_F1]=FALSE;
// 若是,使对应的Key数组中的值为 FALSE KillGLWindow();
// 销毁当前的窗口 fullscreen=!fullscreen;
// 切换 全屏 / 窗口 模式 // 重建 OpenGL 窗口 if (!CreateGLWindow("NeHe's OpenGL 程序框架",640,480,16,fullscreen)) { return 0;
// 如果窗口未能创建,程序退出 } } } } KillGLWindow();
// 销毁窗口 return (msg.wParam);
// 退出程序 }
三.全部代码可以总结为
GLvoid ReSizeGLScene(GLsizei width, GLsizei height);
//重构窗口大小,当移动或者缩放窗口时候有效
int InitGL(GLvoid);
//初始化GL的属性
int DrawGLScene(GLvoid);
//具体的绘制函数
GLvoid KillGLWindow(GLvoid);
//关闭各种对象
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag);
//创建窗口的函数
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg,WPARAM wParam,LPARAM lParam);
//GL窗口的WNDPROC
int WINAPI WinMain( HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTRlpCmdLine,intnCmdShow);
//程序的主函数
【OpenGL学习笔记(一)】
四.总结
其实这一种对于窗口构建的模式虽然很经典,但是和win32下的经典的“Hello World”程序还是有一顶的区别的,有兴趣或者有空的时候,完全可以对窗口程序进行重构.
推荐阅读