BsWin32Window.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #ifndef _WIN32_WINNT
  5. #define _WIN32_WINNT 0x0500
  6. #endif
  7. #include "BsWin32Window.h"
  8. #include "BsInput.h"
  9. #include "BsRenderSystem.h"
  10. #include "BsCoreThread.h"
  11. #include "BsException.h"
  12. #include "BsWin32GLSupport.h"
  13. #include "BsWin32Context.h"
  14. #include "Win32/BsPlatformWndProc.h"
  15. #include "BsWin32VideoModeInfo.h"
  16. #include "BsGLPixelFormat.h"
  17. GLenum GLEWAPIENTRY wglewContextInit(BansheeEngine::GLSupport *glSupport);
  18. namespace BansheeEngine
  19. {
  20. #define _MAX_CLASS_NAME_ 128
  21. Win32Window::Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport &glsupport)
  22. :RenderWindow(desc), mGLSupport(glsupport), mContext(0), mWindowedStyle(0), mWindowedStyleEx(0)
  23. {
  24. mIsFullScreen = false;
  25. mHWnd = 0;
  26. mIsExternal = false;
  27. mIsExternalGLControl = false;
  28. mSizing = false;
  29. mClosed = false;
  30. mDisplayFrequency = 0;
  31. mActive = false;
  32. mDeviceName = NULL;
  33. }
  34. Win32Window::~Win32Window()
  35. {
  36. }
  37. void Win32Window::initialize_internal()
  38. {
  39. #ifdef BS_STATIC_LIB
  40. HINSTANCE hInst = GetModuleHandle(NULL);
  41. #else
  42. HINSTANCE hInst = GetModuleHandle(MODULE_NAME.c_str());
  43. #endif
  44. mHWnd = 0;
  45. mName = mDesc.title;
  46. mIsFullScreen = mDesc.fullscreen;
  47. mClosed = false;
  48. mIsChild = false;
  49. mDisplayFrequency = Math::roundToInt(mDesc.videoMode.getRefreshRate());
  50. mColorDepth = 32;
  51. HWND parent = 0;
  52. NameValuePairList::const_iterator opt;
  53. NameValuePairList::const_iterator end = mDesc.platformSpecific.end();
  54. if ((opt = mDesc.platformSpecific.find("externalWindowHandle")) != end)
  55. {
  56. mHWnd = (HWND)parseUnsignedInt(opt->second);
  57. if (mHWnd)
  58. {
  59. mIsExternal = true;
  60. }
  61. if ((opt = mDesc.platformSpecific.find("externalGLControl")) != end) {
  62. mIsExternalGLControl = parseBool(opt->second);
  63. }
  64. }
  65. HGLRC glrc = 0;
  66. if ((opt = mDesc.platformSpecific.find("externalGLContext")) != end)
  67. {
  68. glrc = (HGLRC)parseUnsignedLong(opt->second);
  69. }
  70. if ((opt = mDesc.platformSpecific.find("parentWindowHandle")) != end)
  71. {
  72. parent = (HWND)parseUnsignedInt(opt->second);
  73. mIsChild = true;
  74. mIsFullScreen = false;
  75. }
  76. HMONITOR hMonitor = NULL;
  77. const Win32VideoModeInfo& videoModeInfo = static_cast<const Win32VideoModeInfo&>(RenderSystem::instance().getVideoModeInfo());
  78. UINT32 numOutputs = videoModeInfo.getNumOutputs();
  79. if (numOutputs > 0)
  80. {
  81. UINT32 actualMonitorIdx = std::min(mDesc.videoMode.getOutputIdx(), numOutputs - 1);
  82. const Win32VideoOutputInfo& outputInfo = static_cast<const Win32VideoOutputInfo&>(videoModeInfo.getOutputInfo(actualMonitorIdx));
  83. hMonitor = outputInfo.getMonitorHandle();
  84. }
  85. if (!mIsFullScreen)
  86. {
  87. // Make sure we don't exceed desktop color depth
  88. if ((int)mColorDepth > GetDeviceCaps(GetDC(0), BITSPIXEL))
  89. mColorDepth = GetDeviceCaps(GetDC(0), BITSPIXEL);
  90. }
  91. mWindowedStyle = WS_VISIBLE | WS_CLIPCHILDREN;
  92. mWindowedStyleEx = 0;
  93. if (!mIsFullScreen)
  94. {
  95. if (parent)
  96. {
  97. if (mDesc.toolWindow)
  98. mWindowedStyleEx = WS_EX_TOOLWINDOW;
  99. else
  100. mWindowedStyle |= WS_CHILD;
  101. }
  102. if (!parent || mDesc.toolWindow)
  103. {
  104. if (mDesc.border == WindowBorder::None)
  105. mWindowedStyle |= WS_POPUP;
  106. else if (mDesc.border == WindowBorder::Fixed)
  107. mWindowedStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
  108. WS_SYSMENU | WS_MINIMIZEBOX;
  109. else
  110. mWindowedStyle |= WS_OVERLAPPEDWINDOW;
  111. }
  112. }
  113. if (!mIsExternal)
  114. {
  115. RECT rc;
  116. // If we didn't specified the adapter index, or if it didn't find it
  117. if (hMonitor == NULL)
  118. {
  119. POINT windowAnchorPoint;
  120. // Fill in anchor point.
  121. windowAnchorPoint.x = mDesc.left;
  122. windowAnchorPoint.y = mDesc.top;
  123. // Get the nearest monitor to this window.
  124. hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTONEAREST);
  125. }
  126. // Get the target monitor info
  127. MONITORINFOEX monitorInfoEx;
  128. memset(&monitorInfoEx, 0, sizeof(MONITORINFOEX));
  129. monitorInfoEx.cbSize = sizeof(MONITORINFOEX);
  130. GetMonitorInfo(hMonitor, &monitorInfoEx);
  131. size_t devNameLen = strlen(monitorInfoEx.szDevice);
  132. mDeviceName = (char*)bs_alloc<ScratchAlloc>((UINT32)(devNameLen + 1));
  133. strcpy_s(mDeviceName, devNameLen + 1, monitorInfoEx.szDevice);
  134. UINT32 left = mDesc.left;
  135. UINT32 top = mDesc.top;
  136. // No specified top left -> Center the window in the middle of the monitor
  137. if (left == -1 || top == -1)
  138. {
  139. int screenw = monitorInfoEx.rcWork.right - monitorInfoEx.rcWork.left;
  140. int screenh = monitorInfoEx.rcWork.bottom - monitorInfoEx.rcWork.top;
  141. unsigned int winWidth, winHeight;
  142. getAdjustedWindowSize(mDesc.videoMode.getWidth(), mDesc.videoMode.getHeight(), &winWidth, &winHeight);
  143. // clamp window dimensions to screen size
  144. int outerw = (int(winWidth) < screenw)? int(winWidth) : screenw;
  145. int outerh = (int(winHeight) < screenh)? int(winHeight) : screenh;
  146. if (left == -1)
  147. left = monitorInfoEx.rcWork.left + (screenw - outerw) / 2;
  148. else if (hMonitor != NULL)
  149. left += monitorInfoEx.rcWork.left;
  150. if (top == -1)
  151. top = monitorInfoEx.rcWork.top + (screenh - outerh) / 2;
  152. else if (hMonitor != NULL)
  153. top += monitorInfoEx.rcWork.top;
  154. }
  155. else if (hMonitor != NULL)
  156. {
  157. left += monitorInfoEx.rcWork.left;
  158. top += monitorInfoEx.rcWork.top;
  159. }
  160. mWidth = mDesc.videoMode.getWidth();
  161. mHeight = mDesc.videoMode.getHeight();
  162. mTop = top;
  163. mLeft = left;
  164. DWORD dwStyle = 0;
  165. DWORD dwStyleEx = 0;
  166. if (mIsFullScreen)
  167. {
  168. dwStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_POPUP;
  169. mTop = monitorInfoEx.rcMonitor.top;
  170. mLeft = monitorInfoEx.rcMonitor.left;
  171. }
  172. else
  173. {
  174. dwStyle = mWindowedStyle;
  175. dwStyleEx = mWindowedStyleEx;
  176. int screenw = GetSystemMetrics(SM_CXSCREEN);
  177. int screenh = GetSystemMetrics(SM_CYSCREEN);
  178. if (!mDesc.outerDimensions)
  179. {
  180. // Calculate window dimensions required
  181. // to get the requested client area
  182. SetRect(&rc, 0, 0, mWidth, mHeight);
  183. AdjustWindowRect(&rc, dwStyle, false);
  184. mWidth = rc.right - rc.left;
  185. mHeight = rc.bottom - rc.top;
  186. // Clamp window rect to the nearest display monitor.
  187. if (mLeft < monitorInfoEx.rcWork.left)
  188. mLeft = monitorInfoEx.rcWork.left;
  189. if (mTop < monitorInfoEx.rcWork.top)
  190. mTop = monitorInfoEx.rcWork.top;
  191. if ((int)mWidth > monitorInfoEx.rcWork.right - mLeft)
  192. mWidth = monitorInfoEx.rcWork.right - mLeft;
  193. if ((int)mHeight > monitorInfoEx.rcWork.bottom - mTop)
  194. mHeight = monitorInfoEx.rcWork.bottom - mTop;
  195. }
  196. }
  197. // register class and create window
  198. WNDCLASS wc = { CS_OWNDC, PlatformWndProc::_win32WndProc, 0, 0, hInst,
  199. LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
  200. (HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "GLWindow" };
  201. RegisterClass(&wc);
  202. if (mIsFullScreen)
  203. {
  204. DEVMODE displayDeviceMode;
  205. memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
  206. displayDeviceMode.dmSize = sizeof(DEVMODE);
  207. displayDeviceMode.dmBitsPerPel = mColorDepth;
  208. displayDeviceMode.dmPelsWidth = mWidth;
  209. displayDeviceMode.dmPelsHeight = mHeight;
  210. displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  211. if (mDisplayFrequency)
  212. {
  213. displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
  214. displayDeviceMode.dmFields |= DM_DISPLAYFREQUENCY;
  215. if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN | CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL)
  216. {
  217. BS_EXCEPT(RenderingAPIException, "ChangeDisplaySettings with user display frequency failed.");
  218. }
  219. }
  220. if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
  221. {
  222. BS_EXCEPT(RenderingAPIException, "ChangeDisplaySettings failed.");
  223. }
  224. }
  225. // Pass pointer to self as WM_CREATE parameter
  226. mHWnd = CreateWindowEx(dwStyleEx, "GLWindow", mDesc.title.c_str(),
  227. dwStyle, mLeft, mTop, mWidth, mHeight, parent, 0, hInst, this);
  228. }
  229. RECT rc;
  230. GetWindowRect(mHWnd, &rc);
  231. mTop = rc.top;
  232. mLeft = rc.left;
  233. GetClientRect(mHWnd, &rc);
  234. mWidth = rc.right;
  235. mHeight = rc.bottom;
  236. mHDC = GetDC(mHWnd);
  237. if (!mIsExternalGLControl)
  238. {
  239. int testMultisample = mMultisampleCount;
  240. bool testHwGamma = mDesc.gamma;
  241. bool formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testMultisample, testHwGamma);
  242. if (!formatOk)
  243. {
  244. if (mMultisampleCount > 0)
  245. {
  246. // Try without multisampling
  247. testMultisample = 0;
  248. formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testMultisample, testHwGamma);
  249. }
  250. if (!formatOk && mDesc.gamma)
  251. {
  252. // Try without sRGB
  253. testHwGamma = false;
  254. testMultisample = mMultisampleCount;
  255. formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testMultisample, testHwGamma);
  256. }
  257. if (!formatOk && mDesc.gamma && (mMultisampleCount > 0))
  258. {
  259. // Try without both
  260. testHwGamma = false;
  261. testMultisample = 0;
  262. formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testMultisample, testHwGamma);
  263. }
  264. if (!formatOk)
  265. BS_EXCEPT(RenderingAPIException, "Failed selecting pixel format.");
  266. }
  267. // Record what gamma option we used in the end
  268. // this will control enabling of sRGB state flags when used
  269. mHwGamma = testHwGamma;
  270. mMultisampleCount = testMultisample;
  271. }
  272. mActive = true;
  273. mContext = mGLSupport.createContext(mHDC, glrc);
  274. RenderWindow::initialize_internal();
  275. }
  276. void Win32Window::destroy_internal()
  277. {
  278. if (!mHWnd)
  279. return;
  280. // Unregister and destroy GLContext
  281. bs_delete(mContext);
  282. if (!mIsExternal)
  283. {
  284. if (mIsFullScreen)
  285. ChangeDisplaySettingsEx(mDeviceName, NULL, NULL, 0, NULL);
  286. DestroyWindow(mHWnd);
  287. }
  288. else
  289. {
  290. // just release the DC
  291. ReleaseDC(mHWnd, mHDC);
  292. }
  293. mActive = false;
  294. mClosed = true;
  295. mHDC = 0; // no release thanks to CS_OWNDC wndclass style
  296. mHWnd = 0;
  297. if (mDeviceName != NULL)
  298. {
  299. bs_free<ScratchAlloc>(mDeviceName);
  300. mDeviceName = NULL;
  301. }
  302. RenderWindow::destroy_internal();
  303. }
  304. void Win32Window::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
  305. {
  306. THROW_IF_NOT_CORE_THREAD;
  307. if (mIsChild)
  308. return;
  309. const Win32VideoModeInfo& videoModeInfo = static_cast<const Win32VideoModeInfo&>(RenderSystem::instance().getVideoModeInfo());
  310. UINT32 numOutputs = videoModeInfo.getNumOutputs();
  311. if (numOutputs == 0)
  312. return;
  313. UINT32 actualMonitorIdx = std::min(monitorIdx, numOutputs - 1);
  314. const Win32VideoOutputInfo& outputInfo = static_cast<const Win32VideoOutputInfo&>(videoModeInfo.getOutputInfo(actualMonitorIdx));
  315. bool oldFullscreen = mIsFullScreen;
  316. mDisplayFrequency = Math::roundToInt(refreshRate);
  317. mIsFullScreen = true;
  318. DEVMODE displayDeviceMode;
  319. memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
  320. displayDeviceMode.dmSize = sizeof(DEVMODE);
  321. displayDeviceMode.dmBitsPerPel = mColorDepth;
  322. displayDeviceMode.dmPelsWidth = width;
  323. displayDeviceMode.dmPelsHeight = height;
  324. displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
  325. displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
  326. HMONITOR hMonitor = outputInfo.getMonitorHandle();
  327. MONITORINFOEX monitorInfo;
  328. memset(&monitorInfo, 0, sizeof(MONITORINFOEX));
  329. monitorInfo.cbSize = sizeof(MONITORINFOEX);
  330. GetMonitorInfo(hMonitor, &monitorInfo);
  331. if (ChangeDisplaySettingsEx(monitorInfo.szDevice, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
  332. {
  333. BS_EXCEPT(RenderingAPIException, "ChangeDisplaySettings failed");
  334. }
  335. mTop = monitorInfo.rcMonitor.top;
  336. mLeft = monitorInfo.rcMonitor.left;
  337. mWidth = width;
  338. mHeight = height;
  339. SetWindowPos(mHWnd, HWND_TOP, mLeft, mTop, width, height, SWP_NOACTIVATE);
  340. }
  341. void Win32Window::setFullscreen(const VideoMode& mode)
  342. {
  343. THROW_IF_NOT_CORE_THREAD;
  344. setFullscreen(mode.getWidth(), mode.getHeight(), mode.getRefreshRate(), mode.getOutputIdx());
  345. }
  346. void Win32Window::setWindowed(UINT32 width, UINT32 height)
  347. {
  348. THROW_IF_NOT_CORE_THREAD;
  349. if (!mIsFullScreen)
  350. return;
  351. mIsFullScreen = false;
  352. mWidth = width;
  353. mHeight = height;
  354. // Drop out of fullscreen
  355. ChangeDisplaySettingsEx(mDeviceName, NULL, NULL, 0, NULL);
  356. // Calculate overall dimensions for requested client area
  357. UINT32 winWidth, winHeight;
  358. getAdjustedWindowSize(mWidth, mHeight, &winWidth, &winHeight);
  359. // Deal with centering when switching down to smaller resolution
  360. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  361. MONITORINFO monitorInfo;
  362. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  363. monitorInfo.cbSize = sizeof(MONITORINFO);
  364. GetMonitorInfo(hMonitor, &monitorInfo);
  365. LONG screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  366. LONG screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  367. INT32 left = screenw > INT32(winWidth) ? ((screenw - INT32(winWidth)) / 2) : 0;
  368. INT32 top = screenh > INT32(winHeight) ? ((screenh - INT32(winHeight)) / 2) : 0;
  369. SetWindowLong(mHWnd, GWL_STYLE, mWindowedStyle);
  370. SetWindowLong(mHWnd, GWL_EXSTYLE, mWindowedStyleEx);
  371. SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
  372. SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
  373. _windowMovedOrResized();
  374. }
  375. bool Win32Window::isActive(void) const
  376. {
  377. if (isFullScreen())
  378. return isVisible();
  379. return mActive && isVisible();
  380. }
  381. bool Win32Window::isVisible() const
  382. {
  383. return (mHWnd && !IsIconic(mHWnd));
  384. }
  385. bool Win32Window::isClosed() const
  386. {
  387. return mClosed;
  388. }
  389. void Win32Window::move(INT32 left, INT32 top)
  390. {
  391. THROW_IF_NOT_CORE_THREAD;
  392. if (mHWnd && !mIsFullScreen)
  393. {
  394. mLeft = left;
  395. mTop = top;
  396. SetWindowPos(mHWnd, 0, left, top, 0, 0,
  397. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  398. }
  399. }
  400. void Win32Window::resize(UINT32 width, UINT32 height)
  401. {
  402. THROW_IF_NOT_CORE_THREAD;
  403. if (mHWnd && !mIsFullScreen)
  404. {
  405. mWidth = width;
  406. mHeight = height;
  407. RECT rc = { 0, 0, width, height };
  408. AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
  409. width = rc.right - rc.left;
  410. height = rc.bottom - rc.top;
  411. SetWindowPos(mHWnd, 0, 0, 0, width, height,
  412. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  413. }
  414. }
  415. void Win32Window::swapBuffers()
  416. {
  417. THROW_IF_NOT_CORE_THREAD;
  418. if (!mIsExternalGLControl) {
  419. SwapBuffers(mHDC);
  420. }
  421. }
  422. void Win32Window::copyToMemory(PixelData &dst, FrameBuffer buffer)
  423. {
  424. THROW_IF_NOT_CORE_THREAD;
  425. if ((dst.getLeft() < 0) || (dst.getRight() > mWidth) ||
  426. (dst.getTop() < 0) || (dst.getBottom() > mHeight) ||
  427. (dst.getFront() != 0) || (dst.getBack() != 1))
  428. {
  429. BS_EXCEPT(InvalidParametersException, "Invalid box.");
  430. }
  431. if (buffer == FB_AUTO)
  432. {
  433. buffer = mIsFullScreen? FB_FRONT : FB_BACK;
  434. }
  435. GLenum format = BansheeEngine::GLPixelUtil::getGLOriginFormat(dst.getFormat());
  436. GLenum type = BansheeEngine::GLPixelUtil::getGLOriginDataType(dst.getFormat());
  437. if ((format == GL_NONE) || (type == 0))
  438. {
  439. BS_EXCEPT(InvalidParametersException, "Unsupported format.");
  440. }
  441. // Must change the packing to ensure no overruns!
  442. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  443. glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK);
  444. glReadPixels((GLint)dst.getLeft(), (GLint)dst.getTop(),
  445. (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(),
  446. format, type, dst.getData());
  447. // restore default alignment
  448. glPixelStorei(GL_PACK_ALIGNMENT, 4);
  449. //vertical flip
  450. {
  451. size_t rowSpan = dst.getWidth() * PixelUtil::getNumElemBytes(dst.getFormat());
  452. size_t height = dst.getHeight();
  453. UINT8 *tmpData = (UINT8*)bs_alloc<ScratchAlloc>((UINT32)(rowSpan * height));
  454. UINT8 *srcRow = (UINT8 *)dst.getData(), *tmpRow = tmpData + (height - 1) * rowSpan;
  455. while (tmpRow >= tmpData)
  456. {
  457. memcpy(tmpRow, srcRow, rowSpan);
  458. srcRow += rowSpan;
  459. tmpRow -= rowSpan;
  460. }
  461. memcpy(dst.getData(), tmpData, rowSpan * height);
  462. bs_free<ScratchAlloc>(tmpData);
  463. }
  464. }
  465. Vector2I Win32Window::screenToWindowPos(const Vector2I& screenPos) const
  466. {
  467. POINT pos;
  468. pos.x = screenPos.x;
  469. pos.y = screenPos.y;
  470. ScreenToClient(mHWnd, &pos);
  471. return Vector2I(pos.x, pos.y);
  472. }
  473. Vector2I Win32Window::windowToScreenPos(const Vector2I& windowPos) const
  474. {
  475. POINT pos;
  476. pos.x = windowPos.x;
  477. pos.y = windowPos.y;
  478. ClientToScreen(mHWnd, &pos);
  479. return Vector2I(pos.x, pos.y);
  480. }
  481. void Win32Window::getCustomAttribute(const String& name, void* pData) const
  482. {
  483. if(name == "GLCONTEXT")
  484. {
  485. *static_cast<GLContext**>(pData) = mContext;
  486. return;
  487. }
  488. else if(name == "WINDOW")
  489. {
  490. HWND *pHwnd = (HWND*)pData;
  491. *pHwnd = mHWnd;
  492. return;
  493. }
  494. }
  495. void Win32Window::setActive(bool state)
  496. {
  497. THROW_IF_NOT_CORE_THREAD;
  498. if (mDeviceName != NULL && state == false)
  499. {
  500. HWND hActiveWindow = GetActiveWindow();
  501. char classNameSrc[_MAX_CLASS_NAME_ + 1];
  502. char classNameDst[_MAX_CLASS_NAME_ + 1];
  503. GetClassName(mHWnd, classNameSrc, _MAX_CLASS_NAME_);
  504. GetClassName(hActiveWindow, classNameDst, _MAX_CLASS_NAME_);
  505. if (strcmp(classNameDst, classNameSrc) == 0)
  506. {
  507. state = true;
  508. }
  509. }
  510. mActive = state;
  511. if( mIsFullScreen )
  512. {
  513. if( state == false )
  514. { //Restore Desktop
  515. ChangeDisplaySettingsEx(mDeviceName, NULL, NULL, 0, NULL);
  516. ShowWindow(mHWnd, SW_SHOWMINNOACTIVE);
  517. }
  518. else
  519. { //Restore App
  520. ShowWindow(mHWnd, SW_SHOWNORMAL);
  521. DEVMODE displayDeviceMode;
  522. memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
  523. displayDeviceMode.dmSize = sizeof(DEVMODE);
  524. displayDeviceMode.dmBitsPerPel = mColorDepth;
  525. displayDeviceMode.dmPelsWidth = mWidth;
  526. displayDeviceMode.dmPelsHeight = mHeight;
  527. displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  528. if (mDisplayFrequency)
  529. {
  530. displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
  531. displayDeviceMode.dmFields |= DM_DISPLAYFREQUENCY;
  532. }
  533. ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL);
  534. }
  535. }
  536. }
  537. void Win32Window::setHidden(bool hidden)
  538. {
  539. THROW_IF_NOT_CORE_THREAD;
  540. mHidden = hidden;
  541. if (!mIsExternal)
  542. {
  543. if (hidden)
  544. ShowWindow(mHWnd, SW_HIDE);
  545. else
  546. ShowWindow(mHWnd, SW_SHOWNORMAL);
  547. }
  548. }
  549. void Win32Window::_windowMovedOrResized()
  550. {
  551. if (!mHWnd || IsIconic(mHWnd))
  552. return;
  553. RECT rc;
  554. GetWindowRect(mHWnd, &rc);
  555. mTop = rc.top;
  556. mLeft = rc.left;
  557. GetClientRect(mHWnd, &rc);
  558. mWidth = rc.right - rc.left;
  559. mHeight = rc.bottom - rc.top;
  560. RenderWindow::_windowMovedOrResized();
  561. }
  562. void Win32Window::getAdjustedWindowSize(UINT32 clientWidth, UINT32 clientHeight, UINT32* winWidth, UINT32* winHeight)
  563. {
  564. RECT rc;
  565. SetRect(&rc, 0, 0, clientWidth, clientHeight);
  566. AdjustWindowRectEx(&rc, mWindowedStyle, false, mWindowedStyleEx);
  567. *winWidth = rc.right - rc.left;
  568. *winHeight = rc.bottom - rc.top;
  569. // Adjust to monitor
  570. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  571. // Get monitor info
  572. MONITORINFO monitorInfo;
  573. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  574. monitorInfo.cbSize = sizeof(MONITORINFO);
  575. GetMonitorInfo(hMonitor, &monitorInfo);
  576. LONG maxW = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  577. LONG maxH = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  578. if (*winWidth > (UINT32)maxW)
  579. *winWidth = maxW;
  580. if (*winHeight > (UINT32)maxH)
  581. *winHeight = maxH;
  582. }
  583. }