2
0

BsWin32Window.cpp 21 KB

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