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); } }