www.pudn.com > OPENGL TEST 3.1.rar > 5DG_Window.cpp


#include "5DG_Window.h" 
 
void TerminateApplication(GL_Window* window)							// 结束程序 
{ 
	PostMessage(window->hWnd, WM_QUIT, 0, 0);							// 发送WM_QUIT消息 
	g_isProgramLooping = FALSE;											// 停止程序 
}  
 
void ResizeWindowGL(int width, int height)								// 重新设置窗口大小 
{ 
	glViewport(0, 0, (GLsizei)(width), (GLsizei)(height));				// 重置当前视口大小 
	glMatrixMode(GL_PROJECTION);										// 切换到投影矩阵模式 
	glLoadIdentity();													// 重置投影矩阵 
	gluPerspective(45, (float)width/(float)height, 0.1, 100);			// 设置透视投影 
	glMatrixMode(GL_MODELVIEW);											// 切换到模型视图矩阵 
	glLoadIdentity();													// 重置模型视图矩阵 
} 
 
BOOL ChangeScreenResolution(int width, int height, int bitsPerPixel)	// 修改屏幕分辨率 
{ 
	DEVMODE dmScreenSettings;											// 设备设置模式  
	ZeroMemory(&dmScreenSettings, sizeof(DEVMODE));						// 清空 
	dmScreenSettings.dmSize			= sizeof(DEVMODE);					// Devmode结构的大小 
	dmScreenSettings.dmPelsWidth	= width;							// 设置为屏幕宽度 
	dmScreenSettings.dmPelsHeight	= height;							// 设置为屏幕高度 
	dmScreenSettings.dmBitsPerPel	= bitsPerPixel;						// 设为指定位长 
	dmScreenSettings.dmFields		= DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 
	// 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态栏 
	if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) 
	{ 
		return FALSE;													// 分辨率修改失败,返回 FALSE 
	} 
	return TRUE;														// 分辨率修改成功,返回 TRUE 
} 
 
BOOL CreateWindowGL(GL_Window* window)									// 建立OpenGL窗口 
{ 
	DWORD windowStyle = WS_OVERLAPPEDWINDOW;							// 设置窗口样式 
	DWORD windowExtendedStyle = WS_EX_APPWINDOW;						// 设置窗口扩展样式 
 
	PIXELFORMATDESCRIPTOR pfd =											// 像素格式描述符(pfd)的设置 
	{ 
		sizeof(PIXELFORMATDESCRIPTOR),									// 像素的尺寸 
		1,																// 版本号 
		PFD_DRAW_TO_WINDOW |											// pfd必须支持窗口绘制 
		PFD_SUPPORT_OPENGL |											// pfd必须支持OpenGL 
		PFD_DOUBLEBUFFER,												// pfd必须支持双缓存 
		PFD_TYPE_RGBA,													// 像素格式为RGBA 
		window->init.bitsPerPixel,										// 设置颜色深度 
		0, 0, 0, 0, 0, 0,												// 忽略颜色位数 
		0,																// 无Alpha缓存 
		0,																// 忽略偏移位 
		0,																// 无累积缓存 
		0, 0, 0, 0,														// 忽略累积缓存位  
		16,																// 深度缓存为16位  
		0,																// 无模板缓存 
		0,																// 无辅助缓存 
		PFD_MAIN_PLANE,													// 主要绘制层 
		0,																// 保留位 
		0, 0, 0															// 忽略层遮罩 
	}; 
 
	RECT windowRect = {0, 0, window->init.width, window->init.height};	// 定义窗口大小 
 
	GLuint PixelFormat;													// 保存像素格式 
 
	if (window->init.isFullScreen == TRUE)								// 切换全屏 
	{ 
		if (ChangeScreenResolution(window->init.width, window->init.height, window->init.bitsPerPixel) == FALSE) 
		{ 
			// 全屏切换失败 
			MessageBox(HWND_DESKTOP, "无法切换到全屏模式,在窗口模式下运行.\nMode Switch Failed,Running In Windowed Mode.", "Error", MB_OK | MB_ICONEXCLAMATION); 
			window->init.isFullScreen = FALSE;							// 设置 isFullscreen 为FALSE 
		} 
		else															// 全屏切换成功 
		{ 
			ShowCursor (FALSE);											// 隐藏鼠标 
			windowStyle = WS_POPUP;										// 设置窗口样式 
			windowExtendedStyle |= WS_EX_TOPMOST;						// 设置窗口扩展样式 
		} 
	} 
	else 
	{ 
		// 调整窗口大小,包括窗口边界 
		AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle); 
	} 
 
	// 开始创建 OpenGL 窗口 
	window->hWnd = CreateWindowEx(windowExtendedStyle,					// 窗口扩展样式 
									window->init.application->className,// 应用程序类名 
									window->init.title,					// 窗口标题 
									windowStyle,						// 窗口样式 
									0, 0,								// 窗口的 X,Y 坐标位置 
									windowRect.right - windowRect.left,	// 窗口宽度 
									windowRect.bottom - windowRect.top,	// 窗口高度 
									HWND_DESKTOP,						// 父窗口为桌面 
									0,									// 无菜单 
									window->init.application->hInstance,// 传入应用程序实例  
									window); 
 
	if (window->hWnd == 0)												// 窗口是否成功创建 
	{ 
		return FALSE;													// 若失败,则返回FALSE 
	} 
 
	window->hDC = GetDC(window->hWnd);									// 取得当前窗口的设备描述表 
	if (window->hDC == 0)												// 若未得到设备描述表 
	{ 
		DestroyWindow(window->hWnd);									// 销毁该窗口 
		window->hWnd = 0;												// 窗口句柄清零 
		return FALSE;													// 返回FALSE 
	} 
 
	PixelFormat = ChoosePixelFormat(window->hDC, &pfd);					// 选择兼容的像素格式 
	if (PixelFormat == 0)												// 若选择失败 
	{ 
		ReleaseDC(window->hWnd, window->hDC);							// 释放设备描述表 
		window->hDC = 0;												// 将设备描述表清零 
		DestroyWindow(window->hWnd);									// 销毁窗口 
		window->hWnd = 0;												// 窗口句柄清零 
		return FALSE;													// 返回FALSE 
	} 
 
	if (SetPixelFormat(window->hDC, PixelFormat, &pfd) == FALSE)		// 设置像素格式并判断是否失败 
	{ 
		ReleaseDC(window->hWnd, window->hDC);							// 释放设备描述表 
		window->hDC = 0;												// 将设备描述表清零 
		DestroyWindow(window->hWnd);									// 销毁窗口 
		window->hWnd = 0;												// 窗口句柄清零 
		return FALSE;													// 返回FALSE 
	} 
 
	window->hRC = wglCreateContext(window->hDC);						// 取得绘制描述表 
	if (window->hRC == 0)												// 若未得到绘制描述表 
	{ 
		ReleaseDC(window->hWnd, window->hDC);							// 释放设备描述表  
		window->hDC = 0;												// 将设备描述表清零 
		DestroyWindow(window->hWnd);									// 销毁窗口 
		window->hWnd = 0;												// 窗口句柄清零 
		return FALSE;													// 返回FALSE 
	} 
 
	if (wglMakeCurrent(window->hDC, window->hRC) == FALSE)				// 设置绘制描述表并判断是否失败 
	{ 
		wglDeleteContext(window->hRC);									// 删除绘制描述表 
		window->hRC = 0;												// 将绘制描述表清零 
		ReleaseDC(window->hWnd, window->hDC);							// 释放设备描述表 
		window->hDC = 0;												// 将设备描述表清零 
		DestroyWindow(window->hWnd);									// 销毁窗口 
		window->hWnd = 0;												// 窗口句柄清零 
		return FALSE;													// 返回FALSE 
	} 
 
	ShowWindow(window->hWnd, SW_NORMAL);								// 显示窗口 
	ResizeWindowGL(window->init.width, window->init.height);			// 重设窗口 
	ZeroMemory(window->keys, sizeof(Keys));								// 清空键盘缓冲区 
 
	return TRUE;														// 窗口创建成功 
} 
 
BOOL DestroyWindowGL(GL_Window* window)									// 销毁窗口并释放程序所用的资源 
{ 
	if (window->hWnd != 0)												// 窗口有句柄? 
	{	 
		if (window->hDC != 0)											// 窗口是否有得到绘制描述表? 
		{ 
			wglMakeCurrent(window->hDC, 0);								// 将当前描述表指针置为0 
			if (window->hRC != 0)										// 该窗口是否有绘制描述表 
			{ 
				wglDeleteContext(window->hRC);							// 释放绘制描述表 
				window->hRC = 0;										// 将绘制描述表清零 
			} 
			ReleaseDC(window->hWnd, window->hDC);						// 释放设备描述表 
			window->hDC = 0;											// 将设备描述表清零 
		} 
		DestroyWindow(window->hWnd);									// 销毁窗口 
		window->hWnd = 0;												// 将窗口句柄清零 
	} 
 
	if (window->init.isFullScreen)										// 若窗口在全屏模式下 
	{ 
		ChangeDisplaySettings(NULL, 0);									// 切换为桌面分辨率 
		ShowCursor(TRUE);												// 显示鼠标 
	}	 
	return TRUE;														// 返回TRUE 
} 
 
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
 
	GL_Window* window = (GL_Window*)(GetWindowLong(hWnd, GWL_USERDATA)); 
 
	switch (uMsg)														// 取得Window的消息值 
	{ 
	case WM_SYSCOMMAND:													// 截取系统命令 
		{ 
			switch (wParam)												// 监听系统调用 
			{ 
			case SC_SCREENSAVE:											// 要运行屏保(Screensaver)? 
			case SC_MONITORPOWER:										// 显示器进入节电模式(Powersave)? 
				return 0;												// 提前返回0,防止系统调用执行 
			} 
			break;														// 退出 
		} 
 
	case WM_CREATE:														// 创建Window 
		{ 
			CREATESTRUCT* creation = (CREATESTRUCT*)(lParam);			// 保存窗口结构指针 
			window = (GL_Window*)(creation->lpCreateParams); 
			SetWindowLong(hWnd, GWL_USERDATA, (LONG)(window));			// 改变窗口属性 
			return 0;													// 返回 
		} 
	 
	case WM_CLOSE:														// 关闭窗口 
		{ 
			PostMessage(window->hWnd, WM_QUIT, 0, 0);					// 结束程序 
			g_isProgramLooping = FALSE; 
			return 0; 
		} 
 
	case WM_SIZE:														// WM_SIZE消息处理 
		switch (wParam)													// 判断消息句柄 
		{ 
		case SIZE_MINIMIZED:											// 窗口最小化? 
			window->isVisible = FALSE;									// 设置isVisible 为 FALSE 
			return 0; 
 
		case SIZE_MAXIMIZED:											// 窗口最大化? 
			window->isVisible = TRUE;									// 设置isVisible 为 TRUE 
			ResizeWindowGL (LOWORD (lParam), HIWORD (lParam));			// 修改窗口大小为 Width=LoWord, Height=HiWord 
			return 0;													// 返回 
 
		case SIZE_RESTORED:												// 窗口还原? 
			window->isVisible = TRUE;									// 设置isVisible 为 TRUE 
			ResizeWindowGL (LOWORD (lParam), HIWORD (lParam));			// 修改窗口大小为 Width=LoWord, Height=HiWord 
			return 0;													// 返回 
		} 
		break;															// 退出 
 
	case WM_KEYDOWN:													// 更新键盘缓冲区 
		if ((wParam >= 0) && (wParam <= 255))							// 按键是否合法? 
		{ 
			window->keys->keyDown[wParam] = TRUE;						// 设相应键为 TRUE (被按下的键) 
			return 0;													// 返回 
		} 
		break;															// 退出 
 
	case WM_KEYUP:														// 松开按键的时候更新键盘缓冲 
		if ((wParam >= 0) && (wParam <= 255))							// 按键是否合法? 
		{ 
			window->keys->keyDown[wParam] = FALSE;						// 设相应键为 FALSE (被释放的键) 
			return 0;													// 返回 
		} 
		break;															// 退出 
 
	case WM_TOGGLEFULLSCREEN:											// 切换全屏/窗口模式 
		{ 
			g_createFullScreen = !g_createFullScreen; 
			PostMessage(hWnd, WM_QUIT, 0, 0); 
			break;														// 退出 
		} 
 
	default: 
		break; 
	} 
 
	return DefWindowProc(hWnd, uMsg, wParam, lParam);					// 将本程序不处理的消息传给 DefWindowProc  
} 
 
BOOL RegisterWindowClass(Application* application)						// 为本应用程序注册一个类. 
{	 
	WNDCLASSEX windowClass;												// 窗口类 
	ZeroMemory(&windowClass, sizeof(WNDCLASSEX));						// 清空内存 
	windowClass.cbSize		= sizeof(WNDCLASSEX);						// 窗口类的大小 
	windowClass.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;		// 在移动,改变大小的时候重绘  
	windowClass.lpfnWndProc		= (WNDPROC)(WindowProc);				// 用WindowProc函数处理消息 
	windowClass.hInstance		= application->hInstance;				// 设置实例 
	windowClass.hbrBackground	= (HBRUSH)(COLOR_APPWORKSPACE);			// 类背景的画刷颜色 
	windowClass.hCursor			= LoadCursor(NULL, IDC_ARROW);			// 载入箭头光标 
	windowClass.lpszClassName	= application->className;				// 设置应用程序的类名 
	if (RegisterClassEx(&windowClass) == 0)								// 注册类失败? 
	{ 
		MessageBox(HWND_DESKTOP, "应用程序类注册失败!\nRegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION); 
		return FALSE;													// 返回FALSE (注册失败) 
	} 
	return TRUE;														// 返回TRUE	(注册成功) 
} 
 
// 应用程序的入口 (WinMain) 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{ 
	Application			application;									// 应用程序 
	GL_Window			window;											// 窗口 
	Keys				keys;											// 键盘按键 
	MSG					msg;											// Window消息 
	BOOL				isMessagePumpActive; 
 
	// 给应用程序赋值 
	application.className = CLASSNAME;									// 程序类名字 
	application.hInstance = hInstance;									// 程序入口 
 
	// 窗口相关信息设置 
	ZeroMemory(&window, sizeof(GL_Window));								// 清零窗口变量的内存空间 
	window.keys					= &keys;								// 设置按键 
	window.init.application		= &application;							// 设置窗口程序 
	window.init.title			= TITLE;								// 设置标题 
	window.init.width			= WIDTH;								// 设置窗口宽度 
	window.init.height			= HEIGHT;								// 设置窗口高度 
	window.init.bitsPerPixel	= BPP;									// 设置每像素的位数 
	window.init.isFullScreen	= FALSE;								// 设置初始窗口是否全屏否(FALSE) 
	ZeroMemory(&keys, sizeof(Keys));									// 键盘缓冲清零 
 
	if (RegisterWindowClass(&application) == FALSE)						// 注册类是否失败 
	{ 
		MessageBox(HWND_DESKTOP, "窗口类注册失败!\nError Registering Window Class!", "Error", MB_OK | MB_ICONEXCLAMATION); 
		return -1;														// 结束程序 
	} 
 
	g_isProgramLooping = TRUE;											// 将g_isProgramLooping设TRUE 
	g_createFullScreen = window.init.isFullScreen;						// g_createFullScreen 设为默认值 
	while (g_isProgramLooping)											// 循环直到程序停止 
	{ 
		// 建立窗口 
		window.init.isFullScreen = g_createFullScreen;					// 传递是否全屏信息 
		if (CreateWindowGL(&window) == TRUE)							// 创建GL窗口成功否? 
		{ 
			if (Initialize(&window, &keys) == FALSE)					// 初始化 
			{ 
				// 失败 
				PostMessage(window.hWnd, WM_QUIT, 0, 0);				// 抛出消息WM_QUIT 
				g_isProgramLooping = FALSE; 
			} 
			else 
			{	// 初始化成功 
				isMessagePumpActive = TRUE;								// 设isMessagePumpActive为TRUE 
				while (isMessagePumpActive == TRUE)						// 当isMessagePumpActive为TRUE时 
				{ 
					// 成功建立窗口,监测Window消息 
					if (PeekMessage(&msg, window.hWnd, 0, 0, PM_REMOVE) != 0) 
					{ 
						// 检测WM_QUIT消息 
						if (msg.message != WM_QUIT)						// WM_QUIT消息? 
						{ 
							DispatchMessage(&msg);						// 如果不是,分派消息 
						} 
						else											// 否则(消息是WM_QUIT) 
						{ 
							isMessagePumpActive = FALSE;				// 结束 Message Pump 
						} 
					} 
					else												// 如果没有消息 
					{ 
						if (window.isVisible == FALSE)					// 如果窗口不可见 
						{ 
							WaitMessage();								// 等待消息 
						} 
						else											// 如果窗口可见 
						{ 
							Update();									// 更新处理消息事件 
							DrawSceneGL();								// 绘制场景 
							SwapBuffers(window.hDC);					// 交换缓存 
						} 
					} 
				}														// 当isMessagePumpActive 为TRUE时循环执行 
			} 
 
			// 程序结束 
			Deinitialize();												// 做扫尾工作 
			DestroyWindowGL(&window);									// 销毁窗口 
		} 
		else															// 如果窗口创建失败 
		{ 
			MessageBox(HWND_DESKTOP, "创建OpenGL窗口失败\nError Creating OpenGL Window", "Error", MB_OK | MB_ICONEXCLAMATION); 
			g_isProgramLooping = FALSE;									// 结束循环 
		} 
	}																	 
	UnregisterClass(application.className, application.hInstance);		// 注销窗口类 
	return 0; 
}