CmD3D9RenderWindow.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org/
  6. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. #include "CmD3D9RenderWindow.h"
  25. #include "CmInput.h"
  26. #include "CmCoreThread.h"
  27. #include "CmViewport.h"
  28. #include "CmException.h"
  29. #include "CmD3D9RenderSystem.h"
  30. #include "CmRenderSystem.h"
  31. #include "CmBitwise.h"
  32. #include "CmWindowEventUtilities.h"
  33. #include "CmD3D9DeviceManager.h"
  34. namespace CamelotFramework
  35. {
  36. // HACK: During the move/resize modal loop no mouse messages will be posted, which means we will
  37. // never receive a "mouse up" event, even though user had to release the mouse to stop the loop. But our GUI system
  38. // relies on mouse down being followed by mouse up otherwise things end start to break a bit. So here we simulate
  39. // the mouse release.
  40. // Note: This is possible because SendMessage won't return until user releases the mouse and modal loop is done.
  41. void HACK_SendLMBUpEvent()
  42. {
  43. gInput().simulateButtonUp(BC_MOUSE_LEFT);
  44. }
  45. D3D9RenderWindow::D3D9RenderWindow(const RENDER_WINDOW_DESC& desc, HINSTANCE instance)
  46. : RenderWindow(desc), mInstance(instance), mIsDepthBuffered(true)
  47. {
  48. mDevice = NULL;
  49. mIsFullScreen = false;
  50. mIsExternal = false;
  51. mHWnd = 0;
  52. mActive = false;
  53. mClosed = false;
  54. mSwitchingFullscreen = false;
  55. mDisplayFrequency = 0;
  56. mDeviceValid = false;
  57. }
  58. D3D9RenderWindow::~D3D9RenderWindow()
  59. { }
  60. void D3D9RenderWindow::initialize_internal()
  61. {
  62. HINSTANCE hInst = mInstance;
  63. mFSAAType = D3DMULTISAMPLE_NONE;
  64. mFSAAQuality = 0;
  65. mFSAA = mDesc.FSAA;
  66. mVSync = mDesc.vsync;
  67. mVSyncInterval = mDesc.vsyncInterval;
  68. HWND parentHWnd = 0;
  69. HWND externalHandle = 0;
  70. NameValuePairList::const_iterator opt;
  71. // parentWindowHandle -> parentHWnd
  72. opt = mDesc.platformSpecific.find("parentWindowHandle");
  73. if(opt != mDesc.platformSpecific.end())
  74. parentHWnd = (HWND)parseUnsignedInt(opt->second);
  75. // externalWindowHandle -> externalHandle
  76. opt = mDesc.platformSpecific.find("externalWindowHandle");
  77. if(opt != mDesc.platformSpecific.end())
  78. externalHandle = (HWND)parseUnsignedInt(opt->second);
  79. if (!externalHandle)
  80. {
  81. DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
  82. DWORD dwStyleEx = 0;
  83. HMONITOR hMonitor = NULL;
  84. MONITORINFO monitorInfo;
  85. RECT rc;
  86. // If we specified which adapter we want to use - find it's monitor.
  87. if (mDesc.monitorIndex != -1)
  88. {
  89. IDirect3D9* direct3D9 = D3D9RenderSystem::getDirect3D9();
  90. for (UINT32 i=0; i < direct3D9->GetAdapterCount(); ++i)
  91. {
  92. if (i == mDesc.monitorIndex)
  93. {
  94. hMonitor = direct3D9->GetAdapterMonitor(i);
  95. break;
  96. }
  97. }
  98. }
  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 = mDesc.left;
  105. windowAnchorPoint.y = mDesc.top;
  106. // Get the nearest monitor to this window.
  107. hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTOPRIMARY);
  108. }
  109. // Get the target monitor info
  110. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  111. monitorInfo.cbSize = sizeof(MONITORINFO);
  112. GetMonitorInfo(hMonitor, &monitorInfo);
  113. unsigned int winWidth, winHeight;
  114. winWidth = mDesc.width;
  115. winHeight = mDesc.height;
  116. UINT32 left = mDesc.left;
  117. UINT32 top = mDesc.top;
  118. // No specified top left -> Center the window in the middle of the monitor
  119. if (left == -1 || top == -1)
  120. {
  121. int screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  122. int screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  123. // clamp window dimensions to screen size
  124. int outerw = (int(winWidth) < screenw)? int(winWidth) : screenw;
  125. int outerh = (int(winHeight) < screenh)? int(winHeight) : screenh;
  126. if (left == -1)
  127. left = monitorInfo.rcWork.left + (screenw - outerw) / 2;
  128. else if (mDesc.monitorIndex != -1)
  129. left += monitorInfo.rcWork.left;
  130. if (top == -1)
  131. top = monitorInfo.rcWork.top + (screenh - outerh) / 2;
  132. else if (mDesc.monitorIndex != -1)
  133. top += monitorInfo.rcWork.top;
  134. }
  135. else if (mDesc.monitorIndex != -1)
  136. {
  137. left += monitorInfo.rcWork.left;
  138. top += monitorInfo.rcWork.top;
  139. }
  140. mWidth = mDesiredWidth = mDesc.width;
  141. mHeight = mDesiredHeight = mDesc.height;
  142. mTop = top;
  143. mLeft = left;
  144. if (mDesc.fullscreen)
  145. {
  146. dwStyleEx |= WS_EX_TOPMOST;
  147. dwStyle |= WS_POPUP;
  148. mTop = monitorInfo.rcMonitor.top;
  149. mLeft = monitorInfo.rcMonitor.left;
  150. }
  151. else
  152. {
  153. if (parentHWnd)
  154. {
  155. if(mDesc.toolWindow)
  156. dwStyleEx = WS_EX_TOOLWINDOW;
  157. else
  158. dwStyle |= WS_CHILD;
  159. }
  160. if (!parentHWnd || mDesc.toolWindow)
  161. {
  162. if (mDesc.border == WindowBorder::None)
  163. dwStyle |= WS_POPUP;
  164. else if (mDesc.border == WindowBorder::Fixed)
  165. dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
  166. WS_SYSMENU | WS_MINIMIZEBOX;
  167. else
  168. dwStyle |= WS_OVERLAPPEDWINDOW;
  169. }
  170. _adjustWindow(mDesc.width, mDesc.height, dwStyle, &winWidth, &winHeight);
  171. if (!mDesc.outerDimensions)
  172. {
  173. // Calculate window dimensions required
  174. // to get the requested client area
  175. SetRect(&rc, 0, 0, mWidth, mHeight);
  176. AdjustWindowRect(&rc, dwStyle, false);
  177. mWidth = rc.right - rc.left;
  178. mHeight = rc.bottom - rc.top;
  179. // Clamp window rect to the nearest display monitor.
  180. if (mLeft < monitorInfo.rcWork.left)
  181. mLeft = monitorInfo.rcWork.left;
  182. if (mTop < monitorInfo.rcWork.top)
  183. mTop = monitorInfo.rcWork.top;
  184. if (static_cast<int>(winWidth) > monitorInfo.rcWork.right - mLeft)
  185. winWidth = monitorInfo.rcWork.right - mLeft;
  186. if (static_cast<int>(winHeight) > monitorInfo.rcWork.bottom - mTop)
  187. winHeight = monitorInfo.rcWork.bottom - mTop;
  188. }
  189. }
  190. // Register the window class
  191. // NB allow 4 bytes of window data for D3D9RenderWindow pointer
  192. WNDCLASS wc = { 0, WindowEventUtilities::_WndProc, 0, 0, hInst,
  193. LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
  194. (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "D3D9Wnd" };
  195. RegisterClass(&wc);
  196. // Create our main window
  197. // Pass pointer to self
  198. mIsExternal = false;
  199. mHWnd = CreateWindowEx(dwStyleEx, "D3D9Wnd", mDesc.title.c_str(), dwStyle,
  200. mLeft, mTop, winWidth, winHeight, parentHWnd, 0, hInst, this);
  201. mStyle = dwStyle;
  202. WindowEventUtilities::_addRenderWindow(this);
  203. }
  204. else
  205. {
  206. mHWnd = externalHandle;
  207. mIsExternal = true;
  208. }
  209. RECT rc;
  210. // top and left represent outer window coordinates
  211. GetWindowRect(mHWnd, &rc);
  212. mTop = rc.top;
  213. mLeft = rc.left;
  214. // width and height represent interior drawable area
  215. GetClientRect(mHWnd, &rc);
  216. mWidth = rc.right;
  217. mHeight = rc.bottom;
  218. mName = mDesc.title;
  219. mIsDepthBuffered = mDesc.depthBuffer;
  220. mIsFullScreen = mDesc.fullscreen;
  221. mColorDepth = mDesc.colorDepth;
  222. mActive = true;
  223. mClosed = false;
  224. D3D9RenderSystem* rs = static_cast<D3D9RenderSystem*>(RenderSystem::instancePtr());
  225. rs->registerWindow(*this);
  226. RenderWindow::initialize_internal();
  227. }
  228. void D3D9RenderWindow::destroy_internal()
  229. {
  230. if (mDevice != NULL)
  231. {
  232. mDevice->detachRenderWindow(this);
  233. mDevice = NULL;
  234. }
  235. if (mHWnd && !mIsExternal)
  236. {
  237. WindowEventUtilities::_removeRenderWindow(this);
  238. DestroyWindow(mHWnd);
  239. }
  240. mHWnd = 0;
  241. mActive = false;
  242. mClosed = true;
  243. RenderWindow::destroy_internal();
  244. }
  245. void D3D9RenderWindow::setFullscreen(bool fullScreen, UINT32 width, UINT32 height)
  246. {
  247. THROW_IF_NOT_CORE_THREAD;
  248. if (fullScreen != mIsFullScreen || width != mWidth || height != mHeight)
  249. {
  250. if (fullScreen != mIsFullScreen)
  251. mSwitchingFullscreen = true;
  252. mStyle = WS_VISIBLE | WS_CLIPCHILDREN;
  253. bool oldFullscreen = mIsFullScreen;
  254. mIsFullScreen = fullScreen;
  255. mWidth = mDesiredWidth = width;
  256. mHeight = mDesiredHeight = height;
  257. if (fullScreen)
  258. {
  259. mStyle |= WS_POPUP;
  260. // Get the nearest monitor to this window.
  261. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  262. // Get monitor info
  263. MONITORINFO monitorInfo;
  264. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  265. monitorInfo.cbSize = sizeof(MONITORINFO);
  266. GetMonitorInfo(hMonitor, &monitorInfo);
  267. mTop = monitorInfo.rcMonitor.top;
  268. mLeft = monitorInfo.rcMonitor.left;
  269. // need different ordering here
  270. if (oldFullscreen)
  271. {
  272. // was previously fullscreen, just changing the resolution
  273. SetWindowPos(mHWnd, HWND_TOPMOST, mLeft, mTop, width, height, SWP_NOACTIVATE);
  274. }
  275. else
  276. {
  277. SetWindowPos(mHWnd, HWND_TOPMOST, mLeft, mTop, width, height, SWP_NOACTIVATE);
  278. //MoveWindow(mHWnd, mLeft, mTop, mWidth, mHeight, FALSE);
  279. SetWindowLong(mHWnd, GWL_STYLE, mStyle);
  280. SetWindowPos(mHWnd, 0, 0,0, 0,0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
  281. }
  282. }
  283. else
  284. {
  285. mStyle |= WS_OVERLAPPEDWINDOW;
  286. // Calculate window dimensions required
  287. // to get the requested client area
  288. unsigned int winWidth, winHeight;
  289. _adjustWindow(mWidth, mHeight, mStyle, &winWidth, &winHeight);
  290. SetWindowLong(mHWnd, GWL_STYLE, mStyle);
  291. SetWindowPos(mHWnd, HWND_NOTOPMOST, 0, 0, winWidth, winHeight,
  292. SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE);
  293. // Note that we also set the position in the restoreLostDevice method
  294. // via _finishSwitchingFullScreen
  295. }
  296. // Have to release & trigger device reset
  297. // NB don't use windowMovedOrResized since Win32 doesn't know
  298. // about the size change yet
  299. mDevice->invalidate(this);
  300. // TODO - Notify viewports of resize
  301. }
  302. }
  303. bool D3D9RenderWindow::isActive() const
  304. {
  305. if (isFullScreen())
  306. return isVisible();
  307. return mActive && isVisible();
  308. }
  309. bool D3D9RenderWindow::isVisible() const
  310. {
  311. return (mHWnd && !IsIconic(mHWnd));
  312. }
  313. void D3D9RenderWindow::reposition(INT32 top, INT32 left)
  314. {
  315. THROW_IF_NOT_CORE_THREAD;
  316. if (mHWnd && !mIsFullScreen)
  317. {
  318. mLeft = left;
  319. mTop = top;
  320. SetWindowPos(mHWnd, 0, top, left, 0, 0,
  321. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  322. }
  323. }
  324. void D3D9RenderWindow::resize(UINT32 width, UINT32 height)
  325. {
  326. THROW_IF_NOT_CORE_THREAD;
  327. if (mHWnd && !mIsFullScreen)
  328. {
  329. mWidth = width;
  330. mHeight = height;
  331. unsigned int winWidth, winHeight;
  332. _adjustWindow(width, height, mStyle, &winWidth, &winHeight);
  333. SetWindowPos(mHWnd, 0, 0, 0, winWidth, winHeight,
  334. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  335. }
  336. }
  337. void D3D9RenderWindow::getCustomAttribute( const String& name, void* pData ) const
  338. {
  339. // Valid attributes and their equvalent native functions:
  340. // D3DDEVICE : getD3DDevice
  341. // WINDOW : getWindowHandle
  342. if( name == "D3DDEVICE" )
  343. {
  344. IDirect3DDevice9* *pDev = (IDirect3DDevice9**)pData;
  345. *pDev = _getD3D9Device();
  346. return;
  347. }
  348. else if( name == "WINDOW" )
  349. {
  350. HWND *pHwnd = (HWND*)pData;
  351. *pHwnd = _getWindowHandle();
  352. return;
  353. }
  354. else if( name == "isTexture" )
  355. {
  356. bool *b = reinterpret_cast< bool * >( pData );
  357. *b = false;
  358. return;
  359. }
  360. else if( name == "D3DZBUFFER" )
  361. {
  362. IDirect3DSurface9* *pSurf = (IDirect3DSurface9**)pData;
  363. *pSurf = mDevice->getDepthBuffer(this);
  364. return;
  365. }
  366. else if( name == "DDBACKBUFFER" )
  367. {
  368. IDirect3DSurface9* *pSurf = (IDirect3DSurface9**)pData;
  369. *pSurf = mDevice->getBackBuffer(this);
  370. return;
  371. }
  372. else if( name == "DDFRONTBUFFER" )
  373. {
  374. IDirect3DSurface9* *pSurf = (IDirect3DSurface9**)pData;
  375. *pSurf = mDevice->getBackBuffer(this);
  376. return;
  377. }
  378. }
  379. void D3D9RenderWindow::swapBuffers()
  380. {
  381. THROW_IF_NOT_CORE_THREAD;
  382. if (mDeviceValid)
  383. mDevice->present(this);
  384. }
  385. Int2 D3D9RenderWindow::screenToWindowPos(const Int2& screenPos) const
  386. {
  387. POINT pos;
  388. pos.x = screenPos.x;
  389. pos.y = screenPos.y;
  390. ScreenToClient(mHWnd, &pos);
  391. return Int2(pos.x, pos.y);
  392. }
  393. Int2 D3D9RenderWindow::windowToScreenPos(const Int2& windowPos) const
  394. {
  395. POINT pos;
  396. pos.x = windowPos.x;
  397. pos.y = windowPos.y;
  398. ClientToScreen(mHWnd, &pos);
  399. return Int2(pos.x, pos.y);
  400. }
  401. void D3D9RenderWindow::copyContentsToMemory(const PixelData &dst, FrameBuffer buffer)
  402. {
  403. THROW_IF_NOT_CORE_THREAD;
  404. mDevice->copyContentsToMemory(this, dst, buffer);
  405. }
  406. void D3D9RenderWindow::startResize(WindowResizeDirection direction)
  407. {
  408. WPARAM dir = HTLEFT;
  409. switch(direction)
  410. {
  411. case WindowResizeDirection::Left:
  412. dir = HTLEFT;
  413. break;
  414. case WindowResizeDirection::TopLeft:
  415. dir = HTTOPLEFT;
  416. break;
  417. case WindowResizeDirection::Top:
  418. dir = HTTOP;
  419. break;
  420. case WindowResizeDirection::TopRight:
  421. dir = HTTOPRIGHT;
  422. break;
  423. case WindowResizeDirection::Right:
  424. dir = HTRIGHT;
  425. break;
  426. case WindowResizeDirection::BottomRight:
  427. dir = HTBOTTOMRIGHT;
  428. break;
  429. case WindowResizeDirection::Bottom:
  430. dir = HTBOTTOM;
  431. break;
  432. case WindowResizeDirection::BottomLeft:
  433. dir = HTBOTTOMLEFT;
  434. break;
  435. }
  436. SendMessage(mHWnd, WM_NCLBUTTONDOWN, dir, 0);
  437. HACK_SendLMBUpEvent();
  438. }
  439. void D3D9RenderWindow::endResize()
  440. {
  441. }
  442. void D3D9RenderWindow::startMove()
  443. {
  444. SendMessage(mHWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
  445. HACK_SendLMBUpEvent();
  446. }
  447. void D3D9RenderWindow::endMove()
  448. {
  449. }
  450. void D3D9RenderWindow::_windowMovedOrResized()
  451. {
  452. THROW_IF_NOT_CORE_THREAD;
  453. if (!mHWnd || IsIconic(mHWnd))
  454. return;
  455. updateWindowRect();
  456. RenderWindow::_windowMovedOrResized();
  457. }
  458. /************************************************************************/
  459. /* D3D9 IMPLEMENTATION SPECIFIC */
  460. /************************************************************************/
  461. void D3D9RenderWindow::_adjustWindow(unsigned int clientWidth, unsigned int clientHeight,
  462. DWORD style, unsigned int* winWidth, unsigned int* winHeight)
  463. {
  464. // NB only call this for non full screen
  465. RECT rc;
  466. SetRect(&rc, 0, 0, clientWidth, clientHeight);
  467. AdjustWindowRect(&rc, style, false);
  468. *winWidth = rc.right - rc.left;
  469. *winHeight = rc.bottom - rc.top;
  470. // adjust to monitor
  471. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  472. // Get monitor info
  473. MONITORINFO monitorInfo;
  474. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  475. monitorInfo.cbSize = sizeof(MONITORINFO);
  476. GetMonitorInfo(hMonitor, &monitorInfo);
  477. LONG maxW = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  478. LONG maxH = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  479. if (*winWidth > (unsigned int)maxW)
  480. *winWidth = maxW;
  481. if (*winHeight > (unsigned int)maxH)
  482. *winHeight = maxH;
  483. }
  484. void D3D9RenderWindow::_finishSwitchingFullscreen()
  485. {
  486. if(mIsFullScreen)
  487. {
  488. // Need to reset the region on the window sometimes, when the
  489. // windowed mode was constrained by desktop
  490. HRGN hRgn = CreateRectRgn(0,0,mWidth, mHeight);
  491. SetWindowRgn(mHWnd, hRgn, FALSE);
  492. }
  493. else
  494. {
  495. // When switching back to windowed mode, need to reset window size
  496. // after device has been restored
  497. // We may have had a resize event which polluted our desired sizes
  498. unsigned int winWidth, winHeight;
  499. _adjustWindow(mDesiredWidth, mDesiredHeight, mStyle, &winWidth, &winHeight);
  500. // deal with centreing when switching down to smaller resolution
  501. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  502. MONITORINFO monitorInfo;
  503. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  504. monitorInfo.cbSize = sizeof(MONITORINFO);
  505. GetMonitorInfo(hMonitor, &monitorInfo);
  506. LONG screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  507. LONG screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  508. int left = screenw > int(winWidth) ? ((screenw - int(winWidth)) / 2) : 0;
  509. int top = screenh > int(winHeight) ? ((screenh - int(winHeight)) / 2) : 0;
  510. SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
  511. SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
  512. if (mWidth != mDesiredWidth ||
  513. mHeight != mDesiredHeight)
  514. {
  515. mWidth = mDesiredWidth;
  516. mHeight = mDesiredHeight;
  517. // TODO - Notify viewports of resize
  518. }
  519. }
  520. mSwitchingFullscreen = false;
  521. }
  522. void D3D9RenderWindow::_buildPresentParameters(D3DPRESENT_PARAMETERS* presentParams) const
  523. {
  524. // Set up the presentation parameters
  525. IDirect3D9* pD3D = D3D9RenderSystem::getDirect3D9();
  526. D3DDEVTYPE devType = D3DDEVTYPE_HAL;
  527. if (mDevice != NULL)
  528. devType = mDevice->getDeviceType();
  529. ZeroMemory( presentParams, sizeof(D3DPRESENT_PARAMETERS) );
  530. presentParams->Windowed = !mIsFullScreen;
  531. presentParams->SwapEffect = D3DSWAPEFFECT_DISCARD;
  532. // triple buffer if VSync is on
  533. presentParams->BackBufferCount = mVSync ? 2 : 1;
  534. presentParams->EnableAutoDepthStencil = mIsDepthBuffered;
  535. presentParams->hDeviceWindow = mHWnd;
  536. presentParams->BackBufferWidth = mWidth;
  537. presentParams->BackBufferHeight = mHeight;
  538. presentParams->FullScreen_RefreshRateInHz = mIsFullScreen ? mDisplayFrequency : 0;
  539. if (presentParams->BackBufferWidth == 0)
  540. presentParams->BackBufferWidth = 1;
  541. if (presentParams->BackBufferHeight == 0)
  542. presentParams->BackBufferHeight = 1;
  543. if (mVSync)
  544. {
  545. // D3D9 only seems to support 2-4 presentation intervals in fullscreen
  546. if (mIsFullScreen)
  547. {
  548. switch(mVSyncInterval)
  549. {
  550. case 1:
  551. default:
  552. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  553. break;
  554. case 2:
  555. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_TWO;
  556. break;
  557. case 3:
  558. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_THREE;
  559. break;
  560. case 4:
  561. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_FOUR;
  562. break;
  563. };
  564. // check that the interval was supported, revert to 1 to be safe otherwise
  565. D3DCAPS9 caps;
  566. pD3D->GetDeviceCaps(mDevice->getAdapterNumber(), devType, &caps);
  567. if (!(caps.PresentationIntervals & presentParams->PresentationInterval))
  568. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  569. }
  570. else
  571. {
  572. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  573. }
  574. }
  575. else
  576. {
  577. // NB not using vsync in windowed mode in D3D9 can cause jerking at low
  578. // frame rates no matter what buffering modes are used (odd - perhaps a
  579. // timer issue in D3D9 since GL doesn't suffer from this)
  580. // low is < 200fps in this context
  581. if (!mIsFullScreen)
  582. {
  583. // TODO LOG PORT - Enable this warning later?
  584. //LogManager::getSingleton().logMessage("D3D9 : WARNING - "
  585. // "disabling VSync in windowed mode can cause timing issues at lower "
  586. // "frame rates, turn VSync on if you observe this problem.");
  587. }
  588. presentParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  589. }
  590. presentParams->BackBufferFormat = D3DFMT_R5G6B5;
  591. if( mColorDepth > 16 )
  592. presentParams->BackBufferFormat = D3DFMT_X8R8G8B8;
  593. if (mColorDepth > 16 )
  594. {
  595. // Try to create a 32-bit depth, 8-bit stencil
  596. if( FAILED( pD3D->CheckDeviceFormat(mDevice->getAdapterNumber(),
  597. devType, presentParams->BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
  598. D3DRTYPE_SURFACE, D3DFMT_D24S8 )))
  599. {
  600. // Bugger, no 8-bit hardware stencil, just try 32-bit zbuffer
  601. if( FAILED( pD3D->CheckDeviceFormat(mDevice->getAdapterNumber(),
  602. devType, presentParams->BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
  603. D3DRTYPE_SURFACE, D3DFMT_D32 )))
  604. {
  605. // Jeez, what a naff card. Fall back on 16-bit depth buffering
  606. presentParams->AutoDepthStencilFormat = D3DFMT_D16;
  607. }
  608. else
  609. presentParams->AutoDepthStencilFormat = D3DFMT_D32;
  610. }
  611. else
  612. {
  613. // Woohoo!
  614. if( SUCCEEDED( pD3D->CheckDepthStencilMatch( mDevice->getAdapterNumber(), devType,
  615. presentParams->BackBufferFormat, presentParams->BackBufferFormat, D3DFMT_D24S8 ) ) )
  616. {
  617. presentParams->AutoDepthStencilFormat = D3DFMT_D24S8;
  618. }
  619. else
  620. presentParams->AutoDepthStencilFormat = D3DFMT_D24X8;
  621. }
  622. }
  623. else
  624. // 16-bit depth, software stencil
  625. presentParams->AutoDepthStencilFormat = D3DFMT_D16;
  626. D3D9RenderSystem* rsys = static_cast<D3D9RenderSystem*>(CamelotFramework::RenderSystem::instancePtr());
  627. D3DMULTISAMPLE_TYPE fsaaType;
  628. DWORD fsaaQuality;
  629. rsys->determineFSAASettings(mDevice->getD3D9Device(),
  630. mFSAA, mFSAAHint, presentParams->BackBufferFormat, mIsFullScreen,
  631. &fsaaType, &fsaaQuality);
  632. presentParams->MultiSampleType = fsaaType;
  633. presentParams->MultiSampleQuality = (fsaaQuality == 0) ? 0 : fsaaQuality;
  634. // Check sRGB
  635. if (mHwGamma)
  636. {
  637. /* hmm, this never succeeds even when device does support??
  638. if(FAILED(pD3D->CheckDeviceFormat(mDriver->getAdapterNumber(),
  639. devType, presentParams->BackBufferFormat, D3DUSAGE_QUERY_SRGBWRITE,
  640. D3DRTYPE_SURFACE, presentParams->BackBufferFormat )))
  641. {
  642. // disable - not supported
  643. mHwGamma = false;
  644. }
  645. */
  646. }
  647. }
  648. IDirect3DDevice9* D3D9RenderWindow::_getD3D9Device() const
  649. {
  650. return mDevice->getD3D9Device();
  651. }
  652. IDirect3DSurface9* D3D9RenderWindow::_getRenderSurface() const
  653. {
  654. return mDevice->getBackBuffer(this);
  655. }
  656. bool D3D9RenderWindow::_getSwitchingFullscreen() const
  657. {
  658. return mSwitchingFullscreen;
  659. }
  660. D3D9Device* D3D9RenderWindow::_getDevice() const
  661. {
  662. return mDevice;
  663. }
  664. void D3D9RenderWindow::_setDevice(D3D9Device* device)
  665. {
  666. mDevice = device;
  667. mDeviceValid = false;
  668. }
  669. bool D3D9RenderWindow::_isDepthBuffered() const
  670. {
  671. return mIsDepthBuffered;
  672. }
  673. void D3D9RenderWindow::updateWindowRect()
  674. {
  675. RECT rc;
  676. BOOL result;
  677. // Update top left parameters
  678. result = GetWindowRect(mHWnd, &rc);
  679. if (result == FALSE)
  680. {
  681. mTop = 0;
  682. mLeft = 0;
  683. mWidth = 0;
  684. mHeight = 0;
  685. return;
  686. }
  687. mTop = rc.top;
  688. mLeft = rc.left;
  689. // width and height represent drawable area only
  690. result = GetClientRect(mHWnd, &rc);
  691. if (result == FALSE)
  692. {
  693. mTop = 0;
  694. mLeft = 0;
  695. mWidth = 0;
  696. mHeight = 0;
  697. return;
  698. }
  699. mWidth = rc.right - rc.left;
  700. mHeight = rc.bottom - rc.top;
  701. }
  702. bool D3D9RenderWindow::_validateDevice()
  703. {
  704. mDeviceValid = mDevice->validate(this);
  705. return mDeviceValid;
  706. }
  707. }