No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

win32platform.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /* The MIT License
  2. *
  3. * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. */
  23. #include "platform.h"
  24. #include "engine.h"
  25. #include <dir.h>
  26. #include <physfs.h>
  27. #include <windows.h>
  28. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  29. struct Win32PlatformPrivate {
  30. HWND window;
  31. HINSTANCE instance;
  32. HDC hdc;
  33. HGLRC hrc;
  34. std::string appName;
  35. int x, y;
  36. int width, height;
  37. int minWidth, minHeight;
  38. bool focused, visible, maximized;
  39. } win32;
  40. void Platform::init(const char *appName)
  41. {
  42. win32.appName = appName;
  43. win32.instance = GetModuleHandle(NULL);
  44. WNDCLASSA wc;
  45. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
  46. wc.lpfnWndProc = (WNDPROC)WndProc; // WndProc Handles Messages
  47. wc.cbClsExtra = 0; // No Extra Window Data
  48. wc.cbWndExtra = 0; // No Extra Window Data
  49. wc.hInstance = win32.instance; // Set The Instance
  50. wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
  51. wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
  52. wc.hbrBackground = NULL; // No Background Required For GL
  53. wc.lpszMenuName = NULL; // We Don't Want A Menu
  54. wc.lpszClassName = win32.appName.c_str(); // Set The Class Name
  55. if(!RegisterClassA(&wc))
  56. fatal("Failed to register the window class.");
  57. }
  58. void Platform::terminate()
  59. {
  60. if(win32.window) {
  61. destroyWindow();
  62. win32.window = NULL;
  63. }
  64. if(win32.instance) {
  65. if(!UnregisterClassA(win32.appName.c_str(), win32.instance))
  66. error("Unregister class failed.");
  67. win32.instance = NULL;
  68. }
  69. }
  70. void Platform::poll()
  71. {
  72. MSG msg;
  73. if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  74. TranslateMessage(&msg);
  75. DispatchMessage(&msg);
  76. }
  77. }
  78. int Platform::getTicks()
  79. {
  80. static unsigned long firstTick = 0;
  81. if(!firstTick)
  82. firstTick = GetTickCount();
  83. return (uint32_t)(GetTickCount() - firstTick);
  84. }
  85. void Platform::sleep(unsigned long miliseconds)
  86. {
  87. Sleep(miliseconds);
  88. }
  89. bool Platform::createWindow(int x, int y, int width, int height, int minWidth, int minHeight, bool maximized)
  90. {
  91. DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  92. DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  93. win32.x = x;
  94. win32.y = y;
  95. win32.width = width;
  96. win32.height = height;
  97. win32.minWidth = minWidth;
  98. win32.minHeight = minHeight;
  99. win32.maximized = maximized;
  100. RECT windowRect = {x, y, x + width, y + height};
  101. AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
  102. win32.window = CreateWindowExA(dwExStyle, // Extended Style For The Window
  103. win32.appName.c_str(), // Class Name
  104. win32.appName.c_str(), // Window Title
  105. dwStyle, // Required Window Style
  106. windowRect.left, // Window X Position
  107. windowRect.top, // Window Y Position
  108. windowRect.right - windowRect.left, // Calculate Window Width
  109. windowRect.bottom - windowRect.top, // Calculate Window Height
  110. NULL, // No Parent Window
  111. NULL, // No Menu
  112. win32.instance, // Instance
  113. NULL);
  114. if(!win32.window) {
  115. terminate();
  116. fatal("Window creation error.");
  117. return false;
  118. }
  119. GLuint pixelFormat;
  120. static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
  121. {
  122. sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
  123. 1, // Version Number
  124. PFD_DRAW_TO_WINDOW | // Format Must Support Window
  125. PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
  126. PFD_DOUBLEBUFFER, // Must Support Double Buffering
  127. PFD_TYPE_RGBA, // Request An RGBA Format
  128. 32, // Select Our Color Depth
  129. 0, 0, 0, 0, 0, 0, // Color Bits Ignored
  130. 0, // No Alpha Buffer
  131. 0, // Shift Bit Ignored
  132. 0, // No Accumulation Buffer
  133. 0, 0, 0, 0, // Accumulation Bits Ignored
  134. 16, // 16Bit Z-Buffer (Depth Buffer)
  135. 0, // No Stencil Buffer
  136. 0, // No Auxiliary Buffer
  137. PFD_MAIN_PLANE, // Main Drawing Layer
  138. 0, // Reserved
  139. 0, 0, 0 // Layer Masks Ignored
  140. };
  141. if(!(win32.hdc = GetDC(win32.window))) {
  142. terminate();
  143. fatal("Can't Create A GL Device Context.");
  144. return false;
  145. }
  146. if(!(pixelFormat = ChoosePixelFormat(win32.hdc, &pfd))) {
  147. terminate();
  148. fatal("Can't Find A Suitable PixelFormat.");
  149. return false;
  150. }
  151. if(!SetPixelFormat(win32.hdc, pixelFormat, &pfd)) {
  152. terminate();
  153. fatal("Can't Set The PixelFormat.");
  154. return false;
  155. }
  156. if(!(win32.hrc = wglCreateContext(win32.hdc))) {
  157. terminate();
  158. fatal("Can't Create A GL Rendering Context.");
  159. return false;
  160. }
  161. if(!wglMakeCurrent(win32.hdc, win32.hrc)) {
  162. terminate();
  163. fatal("Can't Activate The GL Rendering Context.");
  164. return false;
  165. }
  166. return true;
  167. }
  168. void Platform::destroyWindow()
  169. {
  170. if(win32.hrc) {
  171. if(!wglMakeCurrent(NULL, NULL))
  172. error("Release Of DC And RC Failed.");
  173. if(!wglDeleteContext(win32.hrc))
  174. error("Release Rendering Context Failed.");
  175. win32.hrc = NULL;
  176. }
  177. if(win32.hdc) {
  178. if(!ReleaseDC(win32.window, win32.hdc))
  179. error("Release Device Context Failed.");
  180. win32.hdc = NULL;
  181. }
  182. if(win32.window) {
  183. if(!DestroyWindow(win32.window))
  184. error("Destroy window failed.");
  185. win32.window = NULL;
  186. }
  187. }
  188. void Platform::showWindow()
  189. {
  190. if(win32.maximized)
  191. ShowWindow(win32.window, SW_MAXIMIZE);
  192. else
  193. ShowWindow(win32.window, SW_SHOW);
  194. }
  195. void Platform::setWindowTitle(const char *title)
  196. {
  197. SetWindowTextA(win32.window, title);
  198. }
  199. void *Platform::getExtensionProcAddress(const char *ext)
  200. {
  201. return (void*)wglGetProcAddress(ext);
  202. }
  203. bool Platform::isExtensionSupported(const char *ext)
  204. {
  205. typedef const char* _wglGetExtensionsStringARB(HDC hdc);
  206. _wglGetExtensionsStringARB *wglGetExtensionsStringARB = (_wglGetExtensionsStringARB*)getExtensionProcAddress("wglGetExtensionsStringARB");
  207. const char *exts = wglGetExtensionsStringARB(win32.hdc);
  208. if(strstr(exts, ext))
  209. return true;
  210. return false;
  211. }
  212. const char *Platform::getClipboardText()
  213. {
  214. const char *text = "";
  215. if(OpenClipboard(NULL)) {
  216. text = (const char*)GetClipboardData(CF_TEXT);
  217. CloseClipboard();
  218. }
  219. return text;
  220. }
  221. void Platform::setClipboardText(const char *text)
  222. {
  223. int textLenght = strlen(text);
  224. HANDLE hData = new HANDLE[textLenght + 1];
  225. memcpy(hData, text, textLenght + 1);
  226. if(OpenClipboard(NULL)) {
  227. EmptyClipboard();
  228. SetClipboardData(CF_TEXT, hData);
  229. CloseClipboard();
  230. }
  231. }
  232. void Platform::hideMouseCursor()
  233. {
  234. ShowCursor(false);
  235. }
  236. void Platform::showMouseCursor()
  237. {
  238. ShowCursor(true);
  239. }
  240. void Platform::setVsync(bool enable)
  241. {
  242. typedef GLint (*glSwapIntervalProc)(GLint);
  243. glSwapIntervalProc glSwapInterval = NULL;
  244. if(isExtensionSupported("WGL_EXT_swap_control"))
  245. glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("wglSwapIntervalEXT");
  246. if(glSwapInterval)
  247. glSwapInterval(enable ? 1 : 0);
  248. }
  249. void Platform::swapBuffers()
  250. {
  251. SwapBuffers(win32.hdc);
  252. }
  253. bool Platform::isWindowFocused()
  254. {
  255. return win32.focused;
  256. }
  257. bool Platform::isWindowVisible()
  258. {
  259. return win32.visible;
  260. }
  261. int Platform::getWindowX()
  262. {
  263. return win32.x;
  264. }
  265. int Platform::getWindowY()
  266. {
  267. return win32.y;
  268. }
  269. int Platform::getWindowWidth()
  270. {
  271. return win32.width;
  272. }
  273. int Platform::getWindowHeight()
  274. {
  275. return win32.height;
  276. }
  277. int Platform::getDisplayWidth()
  278. {
  279. return GetSystemMetrics(SM_CXSCREEN);
  280. }
  281. int Platform::getDisplayHeight()
  282. {
  283. return GetSystemMetrics(SM_CYSCREEN);
  284. }
  285. bool Platform::isWindowMaximized()
  286. {
  287. return win32.maximized;
  288. }
  289. const char *Platform::getAppUserDir()
  290. {
  291. std::stringstream sdir;
  292. sdir << PHYSFS_getUserDir() << "/." << win32.appName << "/";
  293. if((mkdir(sdir.str().c_str()) != 0) && (errno != EEXIST))
  294. error("Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
  295. return sdir.str().c_str();
  296. }
  297. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  298. {
  299. static int lastX, lastY;
  300. switch(uMsg)
  301. {
  302. case WM_ACTIVATE:
  303. {
  304. win32.focused = !(wParam == WA_INACTIVE);
  305. break;
  306. }
  307. case WM_CLOSE:
  308. {
  309. g_engine.onClose();
  310. break;
  311. }
  312. case WM_GETMINMAXINFO:
  313. {
  314. MINMAXINFO *minMax = (MINMAXINFO*)lParam;
  315. minMax->ptMinTrackSize.x = win32.minWidth;
  316. minMax->ptMinTrackSize.y = win32.minHeight;
  317. break;
  318. }
  319. case WM_MOVE:
  320. {
  321. lastX = win32.x;
  322. lastY = win32.y;
  323. win32.x = LOWORD(lParam);
  324. win32.y = HIWORD(lParam);
  325. break;
  326. }
  327. case WM_SIZE:
  328. {
  329. switch(wParam)
  330. {
  331. case SIZE_MAXIMIZED:
  332. win32.x = lastX;
  333. win32.y = lastY;
  334. win32.maximized = true;
  335. break;
  336. case SIZE_RESTORED:
  337. win32.maximized = false;
  338. break;
  339. }
  340. win32.visible = !(wParam == SIZE_MINIMIZED);
  341. if(!win32.maximized) {
  342. win32.width = LOWORD(lParam);
  343. win32.height = HIWORD(lParam);
  344. }
  345. g_engine.onResize(LOWORD(lParam), HIWORD(lParam));
  346. break;
  347. }
  348. default:
  349. {
  350. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  351. }
  352. }
  353. return 0;
  354. }