BsWin32Window.cpp 21 KB

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