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