5DG_Window.cpp
上传用户:lygtks
上传日期:2022-06-08
资源大小:874k
文件大小:14k
源码类别:

射击游戏

开发平台:

Visual C++

  1. #include "5DG_Window.h"
  2. void TerminateApplication(GL_Window* window) // 结束程序
  3. {
  4. PostMessage(window->hWnd, WM_QUIT, 0, 0); // 发送WM_QUIT消息
  5. g_isProgramLooping = FALSE; // 停止程序
  6. void ResizeWindowGL(int width, int height) // 重新设置窗口大小
  7. {
  8. glViewport(0, 0, (GLsizei)(width), (GLsizei)(height)); // 重置当前视口大小
  9. glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式
  10. glLoadIdentity(); // 重置投影矩阵
  11. glOrtho(-(float)width/2,(float)width/2,-(float)height/2,(float)height/2,-100,100); // 设置透视投影
  12. glMatrixMode(GL_MODELVIEW); // 切换到模型视图矩阵
  13. glLoadIdentity(); // 重置模型视图矩阵
  14. }
  15. BOOL ChangeScreenResolution(int width, int height, int bitsPerPixel) // 修改屏幕分辨率
  16. {
  17. DEVMODE dmScreenSettings; // 设备设置模式 
  18. ZeroMemory(&dmScreenSettings, sizeof(DEVMODE)); // 清空
  19. dmScreenSettings.dmSize = sizeof(DEVMODE); // Devmode结构的大小
  20. dmScreenSettings.dmPelsWidth = width; // 设置为屏幕宽度
  21. dmScreenSettings.dmPelsHeight = height; // 设置为屏幕高度
  22. dmScreenSettings.dmBitsPerPel = bitsPerPixel; // 设为指定位长
  23. dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  24. // 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态栏
  25. if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
  26. {
  27. return FALSE; // 分辨率修改失败,返回 FALSE
  28. }
  29. return TRUE; // 分辨率修改成功,返回 TRUE
  30. }
  31. BOOL CreateWindowGL(GL_Window* window) // 建立OpenGL窗口
  32. {
  33. DWORD windowStyle = WS_OVERLAPPEDWINDOW; // 设置窗口样式
  34. DWORD windowExtendedStyle = WS_EX_APPWINDOW; // 设置窗口扩展样式
  35. PIXELFORMATDESCRIPTOR pfd = // 像素格式描述符(pfd)的设置
  36. {
  37. sizeof(PIXELFORMATDESCRIPTOR), // 像素的尺寸
  38. 1, // 版本号
  39. PFD_DRAW_TO_WINDOW | // pfd必须支持窗口绘制
  40. PFD_SUPPORT_OPENGL | // pfd必须支持OpenGL
  41. PFD_DOUBLEBUFFER, // pfd必须支持双缓存
  42. PFD_TYPE_RGBA, // 像素格式为RGBA
  43. window->init.bitsPerPixel, // 设置颜色深度
  44. 0, 0, 0, 0, 0, 0, // 忽略颜色位数
  45. 0, // 无Alpha缓存
  46. 0, // 忽略偏移位
  47. 0, // 无累积缓存
  48. 0, 0, 0, 0, // 忽略累积缓存位 
  49. 16, // 深度缓存为16位 
  50. 0, // 无模板缓存
  51. 0, // 无辅助缓存
  52. PFD_MAIN_PLANE, // 主要绘制层
  53. 0, // 保留位
  54. 0, 0, 0 // 忽略层遮罩
  55. };
  56. RECT windowRect = {0, 0, window->init.width, window->init.height}; // 定义窗口大小
  57. GLuint PixelFormat; // 保存像素格式
  58. if (window->init.isFullScreen == TRUE) // 切换全屏
  59. {
  60. if (ChangeScreenResolution(window->init.width, window->init.height, window->init.bitsPerPixel) == FALSE)
  61. {
  62. // 全屏切换失败
  63. MessageBox(HWND_DESKTOP, "无法切换到全屏模式,在窗口模式下运行.nMode Switch Failed,Running In Windowed Mode.", "Error", MB_OK | MB_ICONEXCLAMATION);
  64. window->init.isFullScreen = FALSE; // 设置 isFullscreen 为FALSE
  65. }
  66. else // 全屏切换成功
  67. {
  68. ShowCursor (FALSE); // 隐藏鼠标
  69. windowStyle = WS_POPUP; // 设置窗口样式
  70. windowExtendedStyle |= WS_EX_TOPMOST; // 设置窗口扩展样式
  71. }
  72. }
  73. else
  74. {
  75. // 调整窗口大小,包括窗口边界
  76. AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle);
  77. }
  78. // 开始创建 OpenGL 窗口
  79. window->hWnd = CreateWindowEx(windowExtendedStyle, // 窗口扩展样式
  80. window->init.application->className,// 应用程序类名
  81. window->init.title, // 窗口标题
  82. windowStyle, // 窗口样式
  83. 0, 0, // 窗口的 X,Y 坐标位置
  84. windowRect.right - windowRect.left, // 窗口宽度
  85. windowRect.bottom - windowRect.top, // 窗口高度
  86. HWND_DESKTOP, // 父窗口为桌面
  87. 0, // 无菜单
  88. window->init.application->hInstance,// 传入应用程序实例 
  89. window);
  90. if (window->hWnd == 0) // 窗口是否成功创建
  91. {
  92. return FALSE; // 若失败,则返回FALSE
  93. }
  94. window->hDC = GetDC(window->hWnd); // 取得当前窗口的设备描述表
  95. if (window->hDC == 0) // 若未得到设备描述表
  96. {
  97. DestroyWindow(window->hWnd); // 销毁该窗口
  98. window->hWnd = 0; // 窗口句柄清零
  99. return FALSE; // 返回FALSE
  100. }
  101. PixelFormat = ChoosePixelFormat(window->hDC, &pfd); // 选择兼容的像素格式
  102. if (PixelFormat == 0) // 若选择失败
  103. {
  104. ReleaseDC(window->hWnd, window->hDC); // 释放设备描述表
  105. window->hDC = 0; // 将设备描述表清零
  106. DestroyWindow(window->hWnd); // 销毁窗口
  107. window->hWnd = 0; // 窗口句柄清零
  108. return FALSE; // 返回FALSE
  109. }
  110. if (SetPixelFormat(window->hDC, PixelFormat, &pfd) == FALSE) // 设置像素格式并判断是否失败
  111. {
  112. ReleaseDC(window->hWnd, window->hDC); // 释放设备描述表
  113. window->hDC = 0; // 将设备描述表清零
  114. DestroyWindow(window->hWnd); // 销毁窗口
  115. window->hWnd = 0; // 窗口句柄清零
  116. return FALSE; // 返回FALSE
  117. }
  118. window->hRC = wglCreateContext(window->hDC); // 取得绘制描述表
  119. if (window->hRC == 0) // 若未得到绘制描述表
  120. {
  121. ReleaseDC(window->hWnd, window->hDC); // 释放设备描述表 
  122. window->hDC = 0; // 将设备描述表清零
  123. DestroyWindow(window->hWnd); // 销毁窗口
  124. window->hWnd = 0; // 窗口句柄清零
  125. return FALSE; // 返回FALSE
  126. }
  127. if (wglMakeCurrent(window->hDC, window->hRC) == FALSE) // 设置绘制描述表并判断是否失败
  128. {
  129. wglDeleteContext(window->hRC); // 删除绘制描述表
  130. window->hRC = 0; // 将绘制描述表清零
  131. ReleaseDC(window->hWnd, window->hDC); // 释放设备描述表
  132. window->hDC = 0; // 将设备描述表清零
  133. DestroyWindow(window->hWnd); // 销毁窗口
  134. window->hWnd = 0; // 窗口句柄清零
  135. return FALSE; // 返回FALSE
  136. }
  137. ShowWindow(window->hWnd, SW_NORMAL); // 显示窗口
  138. ResizeWindowGL(window->init.width, window->init.height); // 重设窗口
  139. ZeroMemory(window->keys, sizeof(Keys)); // 清空键盘缓冲区
  140. return TRUE; // 窗口创建成功
  141. }
  142. BOOL DestroyWindowGL(GL_Window* window) // 销毁窗口并释放程序所用的资源
  143. {
  144. if (window->hWnd != 0) // 窗口有句柄?
  145. {
  146. if (window->hDC != 0) // 窗口是否有得到绘制描述表?
  147. {
  148. wglMakeCurrent(window->hDC, 0); // 将当前描述表指针置为0
  149. if (window->hRC != 0) // 该窗口是否有绘制描述表
  150. {
  151. wglDeleteContext(window->hRC); // 释放绘制描述表
  152. window->hRC = 0; // 将绘制描述表清零
  153. }
  154. ReleaseDC(window->hWnd, window->hDC); // 释放设备描述表
  155. window->hDC = 0; // 将设备描述表清零
  156. }
  157. DestroyWindow(window->hWnd); // 销毁窗口
  158. window->hWnd = 0; // 将窗口句柄清零
  159. }
  160. if (window->init.isFullScreen) // 若窗口在全屏模式下
  161. {
  162. ChangeDisplaySettings(NULL, 0); // 切换为桌面分辨率
  163. ShowCursor(TRUE); // 显示鼠标
  164. }
  165. return TRUE; // 返回TRUE
  166. }
  167. LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  168. {
  169. GL_Window* window = (GL_Window*)(GetWindowLong(hWnd, GWL_USERDATA));
  170. switch (uMsg) // 取得Window的消息值
  171. {
  172. case WM_SYSCOMMAND: // 截取系统命令
  173. {
  174. switch (wParam) // 监听系统调用
  175. {
  176. case SC_SCREENSAVE: // 要运行屏保(Screensaver)?
  177. case SC_MONITORPOWER: // 显示器进入节电模式(Powersave)?
  178. return 0; // 提前返回0,防止系统调用执行
  179. }
  180. break; // 退出
  181. }
  182. case WM_CREATE: // 创建Window
  183. {
  184. CREATESTRUCT* creation = (CREATESTRUCT*)(lParam); // 保存窗口结构指针
  185. window = (GL_Window*)(creation->lpCreateParams);
  186. SetWindowLong(hWnd, GWL_USERDATA, (LONG)(window)); // 改变窗口属性
  187. return 0; // 返回
  188. }
  189. case WM_CLOSE: // 关闭窗口
  190. {
  191. PostMessage(window->hWnd, WM_QUIT, 0, 0); // 结束程序
  192. g_isProgramLooping = FALSE;
  193. return 0;
  194. }
  195. case WM_SIZE: // WM_SIZE消息处理
  196. switch (wParam) // 判断消息句柄
  197. {
  198. case SIZE_MINIMIZED: // 窗口最小化?
  199. window->isVisible = FALSE; // 设置isVisible 为 FALSE
  200. return 0;
  201. case SIZE_MAXIMIZED: // 窗口最大化?
  202. window->isVisible = TRUE; // 设置isVisible 为 TRUE
  203. ResizeWindowGL (LOWORD (lParam), HIWORD (lParam)); // 修改窗口大小为 Width=LoWord, Height=HiWord
  204. return 0; // 返回
  205. case SIZE_RESTORED: // 窗口还原?
  206. window->isVisible = TRUE; // 设置isVisible 为 TRUE
  207. ResizeWindowGL (LOWORD (lParam), HIWORD (lParam)); // 修改窗口大小为 Width=LoWord, Height=HiWord
  208. return 0; // 返回
  209. }
  210. break; // 退出
  211. case WM_KEYDOWN: // 更新键盘缓冲区
  212. if ((wParam >= 0) && (wParam <= 255)) // 按键是否合法?
  213. {
  214. window->keys->keyDown[wParam] = TRUE; // 设相应键为 TRUE (被按下的键)
  215. return 0; // 返回
  216. }
  217. break; // 退出
  218. case WM_KEYUP: // 松开按键的时候更新键盘缓冲
  219. if ((wParam >= 0) && (wParam <= 255)) // 按键是否合法?
  220. {
  221. window->keys->keyDown[wParam] = FALSE; // 设相应键为 FALSE (被释放的键)
  222. return 0; // 返回
  223. }
  224. break; // 退出
  225. case WM_TOGGLEFULLSCREEN: // 切换全屏/窗口模式
  226. {
  227. g_createFullScreen = !g_createFullScreen;
  228. PostMessage(hWnd, WM_QUIT, 0, 0);
  229. break; // 退出
  230. }
  231. default:
  232. break;
  233. }
  234. return DefWindowProc(hWnd, uMsg, wParam, lParam); // 将本程序不处理的消息传给 DefWindowProc 
  235. }
  236. BOOL RegisterWindowClass(Application* application) // 为本应用程序注册一个类.
  237. {
  238. WNDCLASSEX windowClass; // 窗口类
  239. ZeroMemory(&windowClass, sizeof(WNDCLASSEX)); // 清空内存
  240. windowClass.cbSize = sizeof(WNDCLASSEX); // 窗口类的大小
  241. windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // 在移动,改变大小的时候重绘 
  242. windowClass.lpfnWndProc = (WNDPROC)(WindowProc); // 用WindowProc函数处理消息
  243. windowClass.hInstance = application->hInstance; // 设置实例
  244. windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE); // 类背景的画刷颜色
  245. windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // 载入箭头光标
  246. windowClass.lpszClassName = application->className; // 设置应用程序的类名
  247. if (RegisterClassEx(&windowClass) == 0) // 注册类失败?
  248. {
  249. MessageBox(HWND_DESKTOP, "应用程序类注册失败!nRegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION);
  250. return FALSE; // 返回FALSE (注册失败)
  251. }
  252. return TRUE; // 返回TRUE (注册成功)
  253. }
  254. // 应用程序的入口 (WinMain)
  255. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  256. {
  257. Application application; // 应用程序
  258. GL_Window window; // 窗口
  259. Keys keys; // 键盘按键
  260. MSG msg; // Window消息
  261. BOOL isMessagePumpActive;
  262. // 给应用程序赋值
  263. application.className = CLASSNAME; // 程序类名字
  264. application.hInstance = hInstance; // 程序入口
  265. // 窗口相关信息设置
  266. ZeroMemory(&window, sizeof(GL_Window)); // 清零窗口变量的内存空间
  267. window.keys = &keys; // 设置按键
  268. window.init.application = &application; // 设置窗口程序
  269. window.init.title = TITLE; // 设置标题
  270. window.init.width = WIDTH; // 设置窗口宽度
  271. window.init.height = HEIGHT; // 设置窗口高度
  272. window.init.bitsPerPixel = BPP; // 设置每像素的位数
  273. window.init.isFullScreen = FALSE; // 设置初始窗口是否全屏否(FALSE)
  274. ZeroMemory(&keys, sizeof(Keys)); // 键盘缓冲清零
  275. if (RegisterWindowClass(&application) == FALSE) // 注册类是否失败
  276. {
  277. MessageBox(HWND_DESKTOP, "窗口类注册失败!nError Registering Window Class!", "Error", MB_OK | MB_ICONEXCLAMATION);
  278. return -1; // 结束程序
  279. }
  280. g_isProgramLooping = TRUE; // 将g_isProgramLooping设TRUE
  281. g_createFullScreen = window.init.isFullScreen; // g_createFullScreen 设为默认值
  282. while (g_isProgramLooping) // 循环直到程序停止
  283. {
  284. // 建立窗口
  285. window.init.isFullScreen = g_createFullScreen; // 传递是否全屏信息
  286. if (CreateWindowGL(&window) == TRUE) // 创建GL窗口成功否?
  287. {
  288. if (Initialize(&window, &keys) == FALSE) // 初始化
  289. {
  290. // 失败
  291. PostMessage(window.hWnd, WM_QUIT, 0, 0); // 抛出消息WM_QUIT
  292. g_isProgramLooping = FALSE;
  293. }
  294. else
  295. { // 初始化成功
  296. isMessagePumpActive = TRUE; // 设isMessagePumpActive为TRUE
  297. while (isMessagePumpActive == TRUE) // 当isMessagePumpActive为TRUE时
  298. {
  299. // 成功建立窗口,监测Window消息
  300. if (PeekMessage(&msg, window.hWnd, 0, 0, PM_REMOVE) != 0)
  301. {
  302. // 检测WM_QUIT消息
  303. if (msg.message != WM_QUIT) // WM_QUIT消息?
  304. {
  305. DispatchMessage(&msg); // 如果不是,分派消息
  306. }
  307. else // 否则(消息是WM_QUIT)
  308. {
  309. isMessagePumpActive = FALSE; // 结束 Message Pump
  310. }
  311. }
  312. else // 如果没有消息
  313. {
  314. if (window.isVisible == FALSE) // 如果窗口不可见
  315. {
  316. WaitMessage(); // 等待消息
  317. }
  318. else // 如果窗口可见
  319. {
  320. Update(); // 更新处理消息事件
  321. DrawSceneGL(); // 绘制场景
  322. SwapBuffers(window.hDC); // 交换缓存
  323. }
  324. }
  325. } // 当isMessagePumpActive 为TRUE时循环执行
  326. }
  327. // 程序结束
  328. Deinitialize(); // 做扫尾工作
  329. DestroyWindowGL(&window); // 销毁窗口
  330. }
  331. else // 如果窗口创建失败
  332. {
  333. MessageBox(HWND_DESKTOP, "创建OpenGL窗口失败nError Creating OpenGL Window", "Error", MB_OK | MB_ICONEXCLAMATION);
  334. g_isProgramLooping = FALSE; // 结束循环
  335. }
  336. }
  337. UnregisterClass(application.className, application.hInstance); // 注销窗口类
  338. return 0;
  339. }