【OpenGL】nehe教程第一课学习笔记

时间:2022-09-30 20:09:17
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);
	}
}