BsWin32Window.cpp 22 KB

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