BsWin32Window.cpp 20 KB

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