您的位置:首页 > 运维架构

OpenGL学习笔记(一)

2010-03-20 23:07 555 查看
OpenGL学习笔记

一.目前网上流传的OpenGL学习笔记主要可以分为三种,一种是以红宝书,蓝宝书为主的,使用glut绘制窗口,第二种则是像Nehe使用windows的API,第三种是在windows下使用的以MFC类库为主的教程,我的笔记里主要是使用第二种方式。

二.绘制窗口

全部代码如下:

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
#include <gl/glut.h>

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,LPSTR lpCmdLine,int nCmdShow);

//程序的主函数

四.总结

其实这一种对于窗口构建的模式虽然很经典,但是和win32下的经典的“Hello World”程序还是有一顶的区别的,有兴趣或者有空的时候,完全可以对窗口程序进行重构.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: