CmWin32Window.cpp 20 KB

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