nehe教程的第一课主要讲了OpenGL程序的创建。
它引用了最基本的gl.h、glu.h、glaux.h三个头文件。
包含了五个函数,分别是InitGL、ResizeGLScene、DrawGLScene、WinProc、winMain。
winMain函数是程序的入口,它负责创建windows窗口,将openGL程序引到该窗口(通过调用WinProc函数),并通过窗口句柄hWnd处理信息流(while死循环),死循环里最后调用DrawGLScene。
WinProc函数是OpenGL程序的创建过程,它负责设置OpenGL的基本参数,如颜色深度等等,而且用过switch里处理不同的消息。在窗体创建消息中调用InitGL、在窗口被拖动时调用ResizeGLScene。
InitGL函数主要是设置GL场景中,相机的一些参数,如背景颜色、深度缓存、投影模式等等。
ResizeGLScene函数主要是窗体被拖动,重绘场景。
DrawGLScene函数是负责绘制场景的部分,比如想画一些点、线、图形、颜色、光照就在这个函数里调用相关函数就好,相关函数在接下来的章节进行介绍。
下面是我对代码的一些注释,如全屏模式、鼠标样式等等的设置
#include
#include
// OpenGL32库的头文件
#include
// GLu32库的头文件
#include
// GLaux库的头文件
static HGLRC hRC;//渲染上下文
static HDC hDC; //GDI设备上下文.
BOOL keys[256];//布尔数组,记录键盘响应
/*功能
*1、设置一种颜色清屏作为背景
*2、打开深度缓冲区
*3、启用平滑阴影
*4、设置屏幕渲染方式-透视
*该函数在OpenGL窗口创建后被调用
*/
GLvoid InitGL(GLsizei Width,GLsizei Height)
{
//?
glClearColor(0.0f,0.0f,0.0f,0.0f);
glClearDepth(1.0);//清除指定深度缓存区
glDepthFunc(GL_LESS);//设置深度类型
glEnable(GL_DEPTH_TEST);//深度测试可用
glShadeModel(GL_SMOOTH);//启用平滑阴影
glMatrixMode(GL_PROJECTION);//矩阵模式-投射
glLoadIdentity();//reset the projection matrix
//pram:视角大小、纵横比、近处裁面、远程裁面距离
//类比,unity的camera的各项参数
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
//任何新的变换将影响modelview矩阵
glMatrixMode(GL_MODELVIEW);
}
/*
*作用
*用于修正场景大小因OpenGL窗口改变
*无论改不改变,第一次运行时会调用一次
*/
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);
}
/*
*绘画函数都位于此
*/
GLvoid DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f); // Move Into The Screen
glBegin(GL_POLYGON); // Start Drawing A Polygon
glColor3f(1.0f,0.0f,0.0f); // Set Top Point Of Polygon To Red
glVertex3f( 0.0f, 1.0f, 0.0f); // First Point Of The Polygon (Triangle)
glColor3f(0.0f,1.0f,0.0f); // Set Left Point Of Polygon To Green
glVertex3f(-1.0f,-1.0f, 0.0f); // Second Point Of The Polygon
glColor3f(0.0f,0.0f,1.0f); // Set Right Point Of Polygon To Blue
glVertex3f( 1.0f,-1.0f, 0.0f); // Third Point Of The Polygon
glEnd();
}
/*
*作用
*1、建立系统窗口
*2、设置像素模式
*3、监听窗口重置、按键、程序关闭
*/
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
RECT Screen;
GLuint PixelFormat;
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
16, // Select A 16Bit 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 (?)
};
//处理消息,消息有退出程序、按键、移动窗口等
//pram hWnd是窗口句柄
/*常量解释
*WM_CREATE窗口创建
*WM_DESTROY、WM_CLOSE窗口摧毁和关闭
*WM_KEYDOWN有键按下,函数参数wparam会记录键,相应keys变为true
*WM_KEYUP有键抬起,相应keys变为false
*WM_SIZE,新的窗口大小记录在lParam,高位是高,低位是宽
*default,重新加载该函数处理其他消息
*/
switch(message)
{
case WM_CREATE:
hDC = GetDC(hWnd); // Gets A Device Context For The Window
PixelFormat = ChoosePixelFormat(hDC, &pfd); // Finds The Closest Match To The Pixel Format We Set Above
if (!PixelFormat)
{
MessageBox(0,"Can't Find A Suitable PixelFormat.","Error",MB_OK|MB_ICONERROR);
PostQuitMessage(0); // This Sends A 'Message' Telling The Program To Quit
break; // Prevents The Rest Of The Code From Running
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
{
MessageBox(0,"Can't Set The PixelFormat.","Error",MB_OK|MB_ICONERROR);
PostQuitMessage(0);
break;
}
hRC = wglCreateContext(hDC);
if(!hRC)
{
MessageBox(0,"Can't Create A GL Rendering Context.","Error",MB_OK|MB_ICONERROR);
PostQuitMessage(0);
break;
}
if(!wglMakeCurrent(hDC, hRC))
{
MessageBox(0,"Can't activate GLRC.","Error",MB_OK|MB_ICONERROR);
PostQuitMessage(0);
break;
}
GetClientRect(hWnd, &Screen);
InitGL(Screen.right, Screen.bottom);
break;
case WM_DESTROY:
case WM_CLOSE:
//切换为程序开始前的分辨率
ChangeDisplaySettings(NULL, 0);
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd,hDC);
PostQuitMessage(0);
break;
case WM_KEYDOWN:
keys[wParam] = TRUE;
break;
case WM_KEYUP:
keys[wParam] = FALSE;
break;
case WM_SIZE:
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}
/*wc.lpfnWndProc = (WNDPROC) WndProc;
*窗口创建后加载的函数地址
*wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
*CS_HREDRAW and CS_VREDRAW当窗口移动时进行重绘
*wc.hCursor = LoadCursor(NULL, IDC_ARROW);
*设置鼠标样式
*hWnd = CreateWindow(创建窗口的一些参数
*有窗口的名字、窗口大小、开始的位置、是否全屏
*/
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg; // Windows Message Structure
WNDCLASS wc; // Windows Class Structure Used To Set Up The Type Of Window
HWND hWnd; // Storage For Window Handle
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL WinClass";
if(!RegisterClass(&wc))
{
MessageBox(0,"Failed To Register The Window Class.","Error",MB_OK|MB_ICONERROR);
return FALSE;
}
hWnd = CreateWindow(
"OpenGL WinClass",
"Jeff Molofee's GL Code Tutorial ... NeHe '99", // Title Appearing At The Top Of The Window
WS_POPUP |
WS_CLIPCHILDREN |
WS_CLIPSIBLINGS,
0, 0, // The Position Of The Window On The Screen
640, 480, // The Width And Height Of The WIndow
NULL,
NULL,
hInstance,
NULL);
if(!hWnd)
{
MessageBox(0,"Window Creation Error.","Error",MB_OK|MB_ICONERROR);
return FALSE;
}
DEVMODE dmScreenSettings; // Developer Mode
memset(&dmScreenSettings, 0, sizeof(DEVMODE)); //清除房间存储设置 // Clear Room To Store Settings
dmScreenSettings.dmSize = sizeof(DEVMODE); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = 640; //屏幕宽度 // Screen Width
dmScreenSettings.dmPelsHeight = 480; //屏幕高度 // Screen Height
dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; // Pixel Mode
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);//切换到全屏// Switch To Full Screen
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
SetFocus(hWnd);
wglMakeCurrent(hDC,hRC);
while (1)
{
// Process All Messages
while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
return TRUE;
}
}
DrawGLScene();
SwapBuffers(hDC);
if (keys[VK_ESCAPE]) SendMessage(hWnd,WM_CLOSE,0,0);
}
}