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 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreD3D9RenderWindow.h"
29 #include "OgreLogManager.h"
30 #include "OgreViewport.h"
31 #include "OgreException.h"
32 #include "OgreD3D9RenderSystem.h"
33 #include "OgreRenderSystem.h"
34 #include "OgreBitwise.h"
35 #include "OgreImageCodec.h"
36 #include "OgreStringConverter.h"
37 #include "OgreRoot.h"
38 #include "OgreD3D9DeviceManager.h"
39 #include "OgreDepthBuffer.h"
40 
41 #if OGRE_NO_QUAD_BUFFER_STEREO == 0
42 #include "OgreD3D9StereoDriverBridge.h"
43 #endif
44 
45 namespace Ogre
46 {
D3D9RenderWindow(HINSTANCE instance)47     D3D9RenderWindow::D3D9RenderWindow(HINSTANCE instance)
48         : mInstance(instance)
49     {
50         mDevice = NULL;
51         mIsFullScreen = false;
52         mIsExternal = false;
53         mHWnd = 0;
54         mActive = false;
55         mClosed = false;
56         mHidden = false;
57         mSwitchingFullscreen = false;
58         mDisplayFrequency = 0;
59         mDeviceValid = false;
60         mUseNVPerfHUD = false;
61         mWindowedWinStyle = 0;
62         mFullscreenWinStyle = 0;
63 		mDesiredWidth = 0;
64 		mDesiredHeight = 0;
65     }
66 
~D3D9RenderWindow()67     D3D9RenderWindow::~D3D9RenderWindow()
68     {
69         destroy();
70     }
71 
create(const String & name,unsigned int width,unsigned int height,bool fullScreen,const NameValuePairList * miscParams)72     void D3D9RenderWindow::create(const String& name, unsigned int width, unsigned int height,
73         bool fullScreen, const NameValuePairList *miscParams)
74     {
75         HINSTANCE hInst = mInstance;
76 
77         HWND parentHWnd = 0;
78         WNDPROC windowProc = DefWindowProc;
79         HWND externalHandle = 0;
80         mFSAAType = D3DMULTISAMPLE_NONE;
81         mFSAAQuality = 0;
82         mFSAA = 0;
83         mVSync = false;
84         mVSyncInterval = 1;
85         String title = name;
86         unsigned int colourDepth = 32;
87         int left = INT_MAX; // Defaults to screen center
88         int top = INT_MAX;  // Defaults to screen center
89         bool depthBuffer = true;
90         String border = "";
91         bool outerSize = false;
92         mUseNVPerfHUD = false;
93         size_t fsaaSamples = 0;
94         String fsaaHint;
95         bool enableDoubleClick = false;
96         int monitorIndex = -1;  //Default by detecting the adapter from left / top position
97 
98 
99         if(miscParams)
100         {
101             // Get variable-length params
102             NameValuePairList::const_iterator opt;
103             // left (x)
104             opt = miscParams->find("left");
105             if(opt != miscParams->end())
106                 left = StringConverter::parseInt(opt->second);
107             // top (y)
108             opt = miscParams->find("top");
109             if(opt != miscParams->end())
110                 top = StringConverter::parseInt(opt->second);
111             // Window title
112             opt = miscParams->find("title");
113             if(opt != miscParams->end())
114                 title = opt->second;
115             // parentWindowHandle       -> parentHWnd
116             opt = miscParams->find("parentWindowHandle");
117             if(opt != miscParams->end())
118                 parentHWnd = (HWND)StringConverter::parseSizeT(opt->second);
119             opt = miscParams->find("windowProc");
120             if (opt != miscParams->end())
121                 windowProc = reinterpret_cast<WNDPROC>(StringConverter::parseSizeT(opt->second));
122             // externalWindowHandle     -> externalHandle
123             opt = miscParams->find("externalWindowHandle");
124             if(opt != miscParams->end())
125                 externalHandle = (HWND)StringConverter::parseSizeT(opt->second);
126             // vsync    [parseBool]
127             opt = miscParams->find("vsync");
128             if(opt != miscParams->end())
129                 mVSync = StringConverter::parseBool(opt->second);
130             // hidden   [parseBool]
131             opt = miscParams->find("hidden");
132             if(opt != miscParams->end())
133                 mHidden = StringConverter::parseBool(opt->second);
134             // vsyncInterval    [parseUnsignedInt]
135             opt = miscParams->find("vsyncInterval");
136             if(opt != miscParams->end())
137                 mVSyncInterval = StringConverter::parseUnsignedInt(opt->second);
138             // displayFrequency
139             opt = miscParams->find("displayFrequency");
140             if(opt != miscParams->end())
141                 mDisplayFrequency = StringConverter::parseUnsignedInt(opt->second);
142             // colourDepth
143             opt = miscParams->find("colourDepth");
144             if(opt != miscParams->end())
145                 colourDepth = StringConverter::parseUnsignedInt(opt->second);
146             // depthBuffer [parseBool]
147             opt = miscParams->find("depthBuffer");
148             if(opt != miscParams->end())
149                 depthBuffer = StringConverter::parseBool(opt->second);
150             // FSAA settings
151             opt = miscParams->find("FSAA");
152             if(opt != miscParams->end())
153             {
154                 mFSAA = StringConverter::parseUnsignedInt(opt->second);
155             }
156             opt = miscParams->find("FSAAHint");
157             if(opt != miscParams->end())
158             {
159                 mFSAAHint = opt->second;
160             }
161 
162             // window border style
163             opt = miscParams->find("border");
164             if(opt != miscParams->end())
165                 border = opt->second;
166             // set outer dimensions?
167             opt = miscParams->find("outerDimensions");
168             if(opt != miscParams->end())
169                 outerSize = StringConverter::parseBool(opt->second);
170             // NV perf HUD?
171             opt = miscParams->find("useNVPerfHUD");
172             if(opt != miscParams->end())
173                 mUseNVPerfHUD = StringConverter::parseBool(opt->second);
174             // sRGB?
175             opt = miscParams->find("gamma");
176             if(opt != miscParams->end())
177                 mHwGamma = StringConverter::parseBool(opt->second);
178             // monitor index
179             opt = miscParams->find("monitorIndex");
180             if(opt != miscParams->end())
181                 monitorIndex = StringConverter::parseInt(opt->second);
182             opt = miscParams->find("show");
183             if(opt != miscParams->end())
184                 mHidden = !StringConverter::parseBool(opt->second);
185             // enable double click messages
186             opt = miscParams->find("enableDoubleClick");
187             if(opt != miscParams->end())
188                 enableDoubleClick = StringConverter::parseBool(opt->second);
189 
190         }
191         mIsFullScreen = fullScreen;
192 
193         // Destroy current window if any
194         if( mHWnd )
195             destroy();
196 
197         if (!externalHandle)
198         {
199             DWORD       dwStyleEx = 0;
200             HMONITOR    hMonitor = NULL;
201             MONITORINFO monitorInfo;
202             RECT        rc;
203 
204             // If we specified which adapter we want to use - find it's monitor.
205             if (monitorIndex != -1)
206             {
207                 IDirect3D9* direct3D9 = D3D9RenderSystem::getDirect3D9();
208 
209                 for (uint i=0; i < direct3D9->GetAdapterCount(); ++i)
210                 {
211                     if (i == monitorIndex)
212                     {
213                         hMonitor = direct3D9->GetAdapterMonitor(i);
214                         break;
215                     }
216                 }
217             }
218 
219             // If we didn't specified the adapter index, or if it didn't find it
220             if (hMonitor == NULL)
221             {
222                 POINT windowAnchorPoint;
223 
224                 // Fill in anchor point.
225                 windowAnchorPoint.x = left;
226                 windowAnchorPoint.y = top;
227 
228 
229                 // Get the nearest monitor to this window.
230                 hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTONEAREST);
231             }
232 
233             // Get the target monitor info
234             memset(&monitorInfo, 0, sizeof(MONITORINFO));
235             monitorInfo.cbSize = sizeof(MONITORINFO);
236             GetMonitorInfo(hMonitor, &monitorInfo);
237 
238             // Update window style flags.
239             mFullscreenWinStyle = WS_CLIPCHILDREN | WS_POPUP;
240             mWindowedWinStyle   = WS_CLIPCHILDREN;
241 
242             if (!mHidden)
243             {
244                 mFullscreenWinStyle |= WS_VISIBLE;
245                 mWindowedWinStyle |= WS_VISIBLE;
246             }
247 
248             if (parentHWnd)
249             {
250                 mWindowedWinStyle |= WS_CHILD;
251             }
252             else
253             {
254                 if (border == "none")
255                     mWindowedWinStyle |= WS_POPUP;
256                 else if (border == "fixed")
257                     mWindowedWinStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
258                     WS_SYSMENU | WS_MINIMIZEBOX;
259                 else
260                     mWindowedWinStyle |= WS_OVERLAPPEDWINDOW;
261             }
262 
263             unsigned int winWidth, winHeight;
264             winWidth = width;
265             winHeight = height;
266 
267 
268             // No specified top left -> Center the window in the middle of the monitor
269             if (left == INT_MAX || top == INT_MAX)
270             {
271                 uint32 screenw = monitorInfo.rcWork.right  - monitorInfo.rcWork.left;
272                 uint32 screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
273 
274                 // clamp window dimensions to screen size
275                 uint32 outerw = (winWidth < screenw)? winWidth : screenw;
276                 uint32 outerh = (winHeight < screenh)? winHeight : screenh;
277 
278                 if (left == INT_MAX)
279                     left = monitorInfo.rcWork.left + (screenw - outerw) / 2;
280                 else if (monitorIndex != -1)
281                     left += monitorInfo.rcWork.left;
282 
283                 if (top == INT_MAX)
284                     top = monitorInfo.rcWork.top + (screenh - outerh) / 2;
285                 else if (monitorIndex != -1)
286                     top += monitorInfo.rcWork.top;
287             }
288             else if (monitorIndex != -1)
289             {
290                 left += monitorInfo.rcWork.left;
291                 top += monitorInfo.rcWork.top;
292             }
293 
294             mWidth = mDesiredWidth = width;
295             mHeight = mDesiredHeight = height;
296             mTop = top;
297             mLeft = left;
298 
299             if (fullScreen)
300             {
301                 dwStyleEx |= WS_EX_TOPMOST;
302                 mTop = monitorInfo.rcMonitor.top;
303                 mLeft = monitorInfo.rcMonitor.left;
304             }
305             else
306             {
307                 adjustWindow(width, height, &winWidth, &winHeight);
308 
309                 if (!outerSize)
310                 {
311                     // Calculate window dimensions required
312                     // to get the requested client area
313                     SetRect(&rc, 0, 0, mWidth, mHeight);
314                     AdjustWindowRect(&rc, getWindowStyle(fullScreen), false);
315                     mWidth = rc.right - rc.left;
316                     mHeight = rc.bottom - rc.top;
317 
318                     // Clamp window rect to the nearest display monitor.
319                     if (mLeft < monitorInfo.rcWork.left)
320                         mLeft = monitorInfo.rcWork.left;
321 
322                     if (mTop < monitorInfo.rcWork.top)
323                         mTop = monitorInfo.rcWork.top;
324 
325                     if (static_cast<int>(winWidth) > monitorInfo.rcWork.right - mLeft)
326                         winWidth = monitorInfo.rcWork.right - mLeft;
327 
328                     if (static_cast<int>(winHeight) > monitorInfo.rcWork.bottom - mTop)
329                         winHeight = monitorInfo.rcWork.bottom - mTop;
330                 }
331             }
332 
333             UINT classStyle = 0;
334             if (enableDoubleClick)
335                 classStyle |= CS_DBLCLKS;
336 
337 
338             // Register the window class
339             // NB allow 4 bytes of window data for D3D9RenderWindow pointer
340             WNDCLASS wc = { classStyle, windowProc, 0, 0, hInst,
341                 LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
342                 (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "OgreD3D9Wnd" };
343             RegisterClass(&wc);
344 
345             // Create our main window
346             // Pass pointer to self
347             mIsExternal = false;
348             mHWnd = CreateWindowEx(dwStyleEx, "OgreD3D9Wnd", title.c_str(), getWindowStyle(fullScreen),
349                 mLeft, mTop, winWidth, winHeight, parentHWnd, 0, hInst, this);
350         }
351         else
352         {
353             mHWnd = externalHandle;
354             mIsExternal = true;
355         }
356 
357         RECT rc;
358         // top and left represent outer window coordinates
359         GetWindowRect(mHWnd, &rc);
360         mTop = rc.top;
361         mLeft = rc.left;
362         // width and height represent interior drawable area
363         GetClientRect(mHWnd, &rc);
364         mWidth = rc.right;
365         mHeight = rc.bottom;
366 
367         mName = name;
368         mDepthBufferPoolId = depthBuffer ? DepthBuffer::POOL_DEFAULT : DepthBuffer::POOL_NO_DEPTH;
369         mDepthBuffer = 0;
370         mColourDepth = colourDepth;
371 
372         LogManager::getSingleton().stream()
373             << "D3D9 : Created D3D9 Rendering Window '"
374             << mName << "' : " << mWidth << "x" << mHeight
375             << ", " << mColourDepth << "bpp";
376 
377         mActive = true;
378         mClosed = false;
379         setHidden(mHidden);
380     }
381 
setFullscreen(bool fullScreen,unsigned int width,unsigned int height)382     void D3D9RenderWindow::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
383     {
384         if (fullScreen != mIsFullScreen || width != mWidth || height != mHeight)
385         {
386             if (fullScreen != mIsFullScreen)
387                 mSwitchingFullscreen = true;
388 
389             bool oldFullscreen = mIsFullScreen;
390             mIsFullScreen = fullScreen;
391             mWidth = mDesiredWidth = width;
392             mHeight = mDesiredHeight = height;
393 
394             if (fullScreen)
395             {
396                 // Get the nearest monitor to this window.
397                 HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
398 
399                 // Get monitor info
400                 MONITORINFO monitorInfo;
401 
402                 memset(&monitorInfo, 0, sizeof(MONITORINFO));
403                 monitorInfo.cbSize = sizeof(MONITORINFO);
404                 GetMonitorInfo(hMonitor, &monitorInfo);
405 
406                 mTop = monitorInfo.rcMonitor.top;
407                 mLeft = monitorInfo.rcMonitor.left;
408 
409                 // need different ordering here
410 
411                 if (oldFullscreen)
412                 {
413                     // was previously fullscreen, just changing the resolution
414                     SetWindowPos(mHWnd, HWND_TOPMOST, mLeft, mTop, width, height, SWP_NOACTIVATE);
415                 }
416                 else
417                 {
418                     SetWindowPos(mHWnd, HWND_TOPMOST, mLeft, mTop, width, height, SWP_NOACTIVATE);
419                     SetWindowLong(mHWnd, GWL_STYLE, getWindowStyle(mIsFullScreen));
420                     SetWindowPos(mHWnd, 0, 0,0, 0,0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
421                 }
422             }
423             else
424             {
425                 // Calculate window dimensions required
426                 // to get the requested client area
427                 unsigned int winWidth, winHeight;
428                 winWidth = mWidth;
429                 winHeight = mHeight;
430 
431                 adjustWindow(mWidth, mHeight, &winWidth, &winHeight);
432 
433                 SetWindowLong(mHWnd, GWL_STYLE, getWindowStyle(mIsFullScreen));
434                 SetWindowPos(mHWnd, HWND_NOTOPMOST, 0, 0, winWidth, winHeight,
435                     SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE);
436                 // Note that we also set the position in the restoreLostDevice method
437                 // via _finishSwitchingFullScreen
438 
439                 // Update the current rect.
440                 updateWindowRect();
441             }
442 
443             // Have to release & trigger device reset
444             // NB don't use windowMovedOrResized since Win32 doesn't know
445             // about the size change yet
446             mDevice->invalidate(this);
447             // Notify viewports of resize
448             ViewportList::iterator it = mViewportList.begin();
449             while( it != mViewportList.end() )
450                 (*it++).second->_updateDimensions();
451         }
452     }
453 
adjustWindow(unsigned int clientWidth,unsigned int clientHeight,unsigned int * winWidth,unsigned int * winHeight)454     void D3D9RenderWindow::adjustWindow(unsigned int clientWidth, unsigned int clientHeight,
455         unsigned int* winWidth, unsigned int* winHeight)
456     {
457         // NB only call this for non full screen
458         RECT rc;
459         SetRect(&rc, 0, 0, clientWidth, clientHeight);
460         AdjustWindowRect(&rc, getWindowStyle(mIsFullScreen), false);
461         *winWidth = rc.right - rc.left;
462         *winHeight = rc.bottom - rc.top;
463     }
464 
_finishSwitchingFullscreen()465     void D3D9RenderWindow::_finishSwitchingFullscreen()
466     {
467         if(mIsFullScreen)
468         {
469             // Need to reset the region on the window sometimes, when the
470             // windowed mode was constrained by desktop
471             HRGN hRgn = CreateRectRgn(0,0,mWidth, mHeight);
472             SetWindowRgn(mHWnd, hRgn, FALSE);
473         }
474         else
475         {
476             // When switching back to windowed mode, need to reset window size
477             // after device has been restored
478             // We may have had a resize event which polluted our desired sizes
479             if (mWidth != mDesiredWidth ||
480                 mHeight != mDesiredHeight)
481             {
482                 mWidth = mDesiredWidth;
483                 mHeight = mDesiredHeight;
484             }
485             unsigned int winWidth, winHeight;
486             adjustWindow(mWidth, mHeight, &winWidth, &winHeight);
487 
488             // deal with centering when switching down to smaller resolution
489             HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
490             MONITORINFO monitorInfo;
491             memset(&monitorInfo, 0, sizeof(MONITORINFO));
492             monitorInfo.cbSize = sizeof(MONITORINFO);
493             GetMonitorInfo(hMonitor, &monitorInfo);
494 
495             ULONG screenw = monitorInfo.rcWork.right  - monitorInfo.rcWork.left;
496             ULONG screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
497 
498             int left = screenw > winWidth ? ((screenw - winWidth) / 2) : 0;
499             int top = screenh > winHeight ? ((screenh - winHeight) / 2) : 0;
500             SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
501                 SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
502 
503             updateWindowRect();
504         }
505         mSwitchingFullscreen = false;
506     }
507 
buildPresentParameters(D3DPRESENT_PARAMETERS * presentParams)508     void D3D9RenderWindow::buildPresentParameters(D3DPRESENT_PARAMETERS* presentParams)
509     {
510         // Set up the presentation parameters
511         IDirect3D9* pD3D = D3D9RenderSystem::getDirect3D9();
512         D3DDEVTYPE devType = D3DDEVTYPE_HAL;
513 
514         if (mDevice != NULL)
515             devType = mDevice->getDeviceType();
516 
517 
518         ZeroMemory( presentParams, sizeof(D3DPRESENT_PARAMETERS) );
519         presentParams->Windowed                 = !mIsFullScreen;
520 
521         DWORD version = GetVersion();
522         DWORD major = (DWORD) (LOBYTE(LOWORD(version)));
523         DWORD minor = (DWORD) (HIBYTE(LOWORD(version)));
524         bool isWindows7 = (major > 6) || ((major == 6) && (minor >= 1));
525 
526         // http://msdn.microsoft.com/en-us/library/windows/desktop/bb172574%28v=vs.85%29.aspx
527         // Multisampling is valid only on a swap chain that is being created or reset with the D3DSWAPEFFECT_DISCARD swap effect.
528         bool useFlipSwap =  D3D9RenderSystem::isDirectX9Ex() && isWindows7 && (isAA() == false);
529 
530         presentParams->SwapEffect               = useFlipSwap ? D3DSWAPEFFECT_FLIPEX : D3DSWAPEFFECT_DISCARD;
531         // triple buffer if VSync is on or if flip swap is used. Otherwise we may get a performance penalty.
532         presentParams->BackBufferCount          = mVSync || useFlipSwap ? 2 : 1;
533         presentParams->EnableAutoDepthStencil   = (mDepthBufferPoolId != DepthBuffer::POOL_NO_DEPTH);
534         presentParams->hDeviceWindow            = mHWnd;
535         presentParams->BackBufferWidth          = mWidth;
536         presentParams->BackBufferHeight         = mHeight;
537         presentParams->FullScreen_RefreshRateInHz = mIsFullScreen ? mDisplayFrequency : 0;
538 
539         if (presentParams->BackBufferWidth == 0)
540             presentParams->BackBufferWidth = 1;
541 
542         if (presentParams->BackBufferHeight == 0)
543             presentParams->BackBufferHeight = 1;
544 
545 
546         if (mVSync)
547         {
548             // D3D9 only seems to support 2-4 presentation intervals in fullscreen
549             if (mIsFullScreen)
550             {
551                 switch(mVSyncInterval)
552                 {
553                 case 1:
554                 default:
555                     presentParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
556                     break;
557                 case 2:
558                     presentParams->PresentationInterval = D3DPRESENT_INTERVAL_TWO;
559                     break;
560                 case 3:
561                     presentParams->PresentationInterval = D3DPRESENT_INTERVAL_THREE;
562                     break;
563                 case 4:
564                     presentParams->PresentationInterval = D3DPRESENT_INTERVAL_FOUR;
565                     break;
566                 };
567                 // check that the interval was supported, revert to 1 to be safe otherwise
568                 D3DCAPS9 caps;
569                 pD3D->GetDeviceCaps(mDevice->getAdapterNumber(), devType, &caps);
570                 if (!(caps.PresentationIntervals & presentParams->PresentationInterval))
571                     presentParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
572 
573             }
574             else
575             {
576                 presentParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
577             }
578 
579         }
580         else
581         {
582             // NB not using vsync in windowed mode in D3D9 can cause jerking at low
583             // frame rates no matter what buffering modes are used (odd - perhaps a
584             // timer issue in D3D9 since GL doesn't suffer from this)
585             // low is < 200fps in this context
586             if (!mIsFullScreen)
587             {
588                 LogManager::getSingleton().logWarning(
589                     "D3D9: disabling VSync in windowed mode can cause timing issues at lower "
590                     "frame rates, turn VSync on if you observe this problem.");
591             }
592             presentParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
593         }
594 
595         presentParams->BackBufferFormat     = D3DFMT_R5G6B5;
596         if( mColourDepth > 16 )
597             presentParams->BackBufferFormat = D3DFMT_X8R8G8B8;
598 
599         if (mColourDepth > 16 )
600         {
601             // Try to create a 32-bit depth, 8-bit stencil
602             if( FAILED( pD3D->CheckDeviceFormat(mDevice->getAdapterNumber(),
603                 devType,  presentParams->BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
604                 D3DRTYPE_SURFACE, D3DFMT_D24S8 )))
605             {
606                 // Bugger, no 8-bit hardware stencil, just try 32-bit zbuffer
607                 if( FAILED( pD3D->CheckDeviceFormat(mDevice->getAdapterNumber(),
608                     devType,  presentParams->BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
609                     D3DRTYPE_SURFACE, D3DFMT_D32 )))
610                 {
611                     // Jeez, what a naff card. Fall back on 16-bit depth buffering
612                     presentParams->AutoDepthStencilFormat = D3DFMT_D16;
613                 }
614                 else
615                     presentParams->AutoDepthStencilFormat = D3DFMT_D32;
616             }
617             else
618             {
619                 // Woohoo!
620                 if( SUCCEEDED( pD3D->CheckDepthStencilMatch( mDevice->getAdapterNumber(), devType,
621                     presentParams->BackBufferFormat, presentParams->BackBufferFormat, D3DFMT_D24S8 ) ) )
622                 {
623                     presentParams->AutoDepthStencilFormat = D3DFMT_D24S8;
624                 }
625                 else
626                     presentParams->AutoDepthStencilFormat = D3DFMT_D24X8;
627             }
628         }
629         else
630             // 16-bit depth, software stencil
631             presentParams->AutoDepthStencilFormat   = D3DFMT_D16;
632 
633 
634         D3D9RenderSystem* rsys = static_cast<D3D9RenderSystem*>(Root::getSingleton().getRenderSystem());
635 
636         rsys->determineFSAASettings(mDevice->getD3D9Device(),
637             mFSAA, mFSAAHint, presentParams->BackBufferFormat, mIsFullScreen,
638             &mFSAAType, &mFSAAQuality);
639 
640         presentParams->MultiSampleType = mFSAAType;
641         presentParams->MultiSampleQuality = (mFSAAQuality == 0) ? 0 : mFSAAQuality;
642 
643         // Check sRGB
644         if (mHwGamma)
645         {
646             /* hmm, this never succeeds even when device does support??
647             if(FAILED(pD3D->CheckDeviceFormat(mDriver->getAdapterNumber(),
648                 devType, presentParams->BackBufferFormat, D3DUSAGE_QUERY_SRGBWRITE,
649                 D3DRTYPE_SURFACE, presentParams->BackBufferFormat )))
650             {
651                 // disable - not supported
652                 mHwGamma = false;
653             }
654             */
655 
656         }
657     }
658 
destroy()659     void D3D9RenderWindow::destroy()
660     {
661         if (mDevice != NULL)
662         {
663             mDevice->detachRenderWindow(this);
664             mDevice = NULL;
665         }
666 
667         if (mHWnd && !mIsExternal)
668         {
669             DestroyWindow(mHWnd);
670         }
671 
672         mHWnd = 0;
673         mActive = false;
674         mClosed = true;
675     }
676 
isActive() const677     bool D3D9RenderWindow::isActive() const
678     {
679         if (isFullScreen())
680             return isVisible();
681 
682         return mActive && isVisible();
683     }
684 
isVisible() const685     bool D3D9RenderWindow::isVisible() const
686     {
687         HWND currentWindowHandle = mHWnd;
688         bool visible;
689         while ((visible = (IsIconic(currentWindowHandle) == false)) &&
690             (GetWindowLong(currentWindowHandle, GWL_STYLE) & WS_CHILD) != 0)
691         {
692             currentWindowHandle = GetParent(currentWindowHandle);
693         }
694         return visible;
695     }
696 
setHidden(bool hidden)697     void D3D9RenderWindow::setHidden(bool hidden)
698     {
699         mHidden = hidden;
700         if (!mIsExternal)
701         {
702             if (hidden)
703                 ShowWindow(mHWnd, SW_HIDE);
704             else
705                 ShowWindow(mHWnd, SW_SHOWNORMAL);
706         }
707     }
708 
setVSyncEnabled(bool vsync)709     void D3D9RenderWindow::setVSyncEnabled(bool vsync)
710     {
711         mVSync = vsync;
712         if (!mIsExternal)
713         {
714             // we need to reset the device with new vsync params
715             // invalidate the window to trigger this
716             mDevice->invalidate(this);
717         }
718     }
719 
isVSyncEnabled() const720     bool D3D9RenderWindow::isVSyncEnabled() const
721     {
722         return mVSync;
723     }
724 
setVSyncInterval(unsigned int interval)725     void D3D9RenderWindow::setVSyncInterval(unsigned int interval)
726     {
727         mVSyncInterval = interval;
728         if (mVSync)
729             setVSyncEnabled(true);
730     }
731 
getVSyncInterval() const732     unsigned int D3D9RenderWindow::getVSyncInterval() const
733     {
734         return mVSyncInterval;
735     }
736 
reposition(int top,int left)737     void D3D9RenderWindow::reposition(int top, int left)
738     {
739         if (mHWnd && !mIsFullScreen)
740         {
741             SetWindowPos(mHWnd, 0, top, left, 0, 0,
742                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
743         }
744     }
745 
resize(unsigned int width,unsigned int height)746     void D3D9RenderWindow::resize(unsigned int width, unsigned int height)
747     {
748         if (!mIsExternal)
749         {
750             if (mHWnd && !mIsFullScreen)
751             {
752                 unsigned int winWidth, winHeight;
753                 adjustWindow(width, height, &winWidth, &winHeight);
754                 SetWindowPos(mHWnd, 0, 0, 0, winWidth, winHeight,
755                     SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
756             }
757         }
758         else
759             updateWindowRect();
760     }
761 
windowMovedOrResized()762     void D3D9RenderWindow::windowMovedOrResized()
763     {
764         if (!mHWnd || IsIconic(mHWnd))
765             return;
766 
767         updateWindowRect();
768     }
769 
swapBuffers()770     void D3D9RenderWindow::swapBuffers( )
771     {
772         if (mDeviceValid)
773             mDevice->present(this);
774     }
775 
getCustomAttribute(const String & name,void * pData)776     void D3D9RenderWindow::getCustomAttribute( const String& name, void* pData )
777     {
778         // Valid attributes and their equvalent native functions:
779         // D3DDEVICE            : getD3DDevice
780         // WINDOW               : getWindowHandle
781 
782         if( name == "D3DDEVICE" )
783         {
784             *(IDirect3DDevice9**)pData = getD3D9Device();
785         }
786         else if( name == "WINDOW" )
787         {
788             *(HWND*)pData = getWindowHandle();
789         }
790         else if( name == "isTexture" )
791         {
792             *(bool*)pData = false;
793         }
794         else if( name == "D3DZBUFFER" )
795         {
796             *(IDirect3DSurface9**)pData = mDevice->getDepthBuffer(this);
797         }
798         else if( name == "DDBACKBUFFER" )
799         {
800             *(IDirect3DSurface9**)pData = mDevice->getBackBuffer(this);
801         }
802         else if( name == "DDFRONTBUFFER" )
803         {
804             *(IDirect3DSurface9**)pData = mDevice->getBackBuffer(this);
805         }
806     }
807 
copyContentsToMemory(const Box & src,const PixelBox & dst,FrameBuffer buffer)808     void D3D9RenderWindow::copyContentsToMemory(const Box& src, const PixelBox &dst, FrameBuffer buffer)
809     {
810         mDevice->copyContentsToMemory(this, src, dst, buffer);
811     }
812     //-----------------------------------------------------------------------------
_beginUpdate()813     void D3D9RenderWindow::_beginUpdate()
814     {
815         // External windows should update per frame
816         // since it dosen't get the window resize/move messages.
817         if (mIsExternal)
818         {
819             updateWindowRect();
820         }
821 
822         if (mWidth == 0 || mHeight == 0)
823         {
824             mDeviceValid = false;
825             return;
826         }
827 
828         D3D9RenderSystem::getDeviceManager()->setActiveRenderTargetDevice(mDevice);
829 
830         // Check that device can be used for rendering operations.
831         mDeviceValid = mDevice->validate(this);
832         if (mDeviceValid)
833         {
834             // Finish window / fullscreen mode switch.
835             if (_getSwitchingFullscreen())
836             {
837                 _finishSwitchingFullscreen();
838                 // have to re-validate since this may have altered dimensions
839                 mDeviceValid = mDevice->validate(this);
840             }
841         }
842 
843         RenderWindow::_beginUpdate();
844     }
845     //---------------------------------------------------------------------
_updateViewport(Viewport * viewport,bool updateStatistics)846     void D3D9RenderWindow::_updateViewport(Viewport* viewport, bool updateStatistics)
847     {
848         if (mDeviceValid)
849         {
850             RenderWindow::_updateViewport(viewport, updateStatistics);
851         }
852     }
853     //---------------------------------------------------------------------
_endUpdate()854     void D3D9RenderWindow::_endUpdate()
855     {
856         RenderWindow::_endUpdate();
857 
858         D3D9RenderSystem::getDeviceManager()->setActiveRenderTargetDevice(NULL);
859 
860     }
861     //-----------------------------------------------------------------------------
getD3D9Device()862     IDirect3DDevice9* D3D9RenderWindow::getD3D9Device()
863     {
864         return mDevice->getD3D9Device();
865     }
866 
867     //-----------------------------------------------------------------------------
getRenderSurface()868     IDirect3DSurface9* D3D9RenderWindow::getRenderSurface()
869     {
870         return mDevice->getBackBuffer(this);
871     }
872 
873     //-----------------------------------------------------------------------------
_getSwitchingFullscreen() const874     bool D3D9RenderWindow::_getSwitchingFullscreen() const
875     {
876         return mSwitchingFullscreen;
877     }
878 
879     //-----------------------------------------------------------------------------
getDevice()880     D3D9Device* D3D9RenderWindow::getDevice()
881     {
882         return mDevice;
883     }
884 
885     //-----------------------------------------------------------------------------
setDevice(D3D9Device * device)886     void D3D9RenderWindow::setDevice(D3D9Device* device)
887     {
888         mDevice = device;
889         mDeviceValid = false;
890     }
891 
892     //-----------------------------------------------------------------------------
isDepthBuffered() const893     bool D3D9RenderWindow::isDepthBuffered() const
894     {
895         return (mDepthBufferPoolId != DepthBuffer::POOL_NO_DEPTH);
896     }
897 
898     //-----------------------------------------------------------------------------
updateWindowRect()899     void D3D9RenderWindow::updateWindowRect()
900     {
901         RECT rc;
902         BOOL result;
903 
904         // Update top left parameters
905         result = GetWindowRect(mHWnd, &rc);
906         if (result == FALSE)
907         {
908             mTop = 0;
909             mLeft = 0;
910             mWidth = 0;
911             mHeight = 0;
912             return;
913         }
914 
915         mTop = rc.top;
916         mLeft = rc.left;
917 
918         // width and height represent drawable area only
919         result = GetClientRect(mHWnd, &rc);
920         if (result == FALSE)
921         {
922             mTop = 0;
923             mLeft = 0;
924             mWidth = 0;
925             mHeight = 0;
926             return;
927         }
928         unsigned int width = rc.right - rc.left;
929         unsigned int height = rc.bottom - rc.top;
930 
931         // Case window resized.
932         if (width != mWidth || height != mHeight)
933         {
934             mWidth  = rc.right - rc.left;
935             mHeight = rc.bottom - rc.top;
936 
937             // Notify viewports of resize
938             ViewportList::iterator it = mViewportList.begin();
939             while( it != mViewportList.end() )
940                 (*it++).second->_updateDimensions();
941         }
942 
943     }
944     //-----------------------------------------------------------------------------
updateStats(void)945     void D3D9RenderWindow::updateStats( void )
946     {
947         RenderTarget::updateStats();
948         mStats.vBlankMissCount = mDevice->getVBlankMissCount(this);
949     }
950     //-----------------------------------------------------------------------------
isNvPerfHUDEnable() const951     bool D3D9RenderWindow::isNvPerfHUDEnable() const
952     {
953         return mUseNVPerfHUD;
954     }
955     //---------------------------------------------------------------------
_validateDevice()956     bool D3D9RenderWindow::_validateDevice()
957     {
958         mDeviceValid = mDevice->validate(this);
959         return mDeviceValid;
960     }
961 	//---------------------------------------------------------------------
962 #if OGRE_NO_QUAD_BUFFER_STEREO == 0
_validateStereo()963 	void D3D9RenderWindow::_validateStereo()
964 	{
965 		mStereoEnabled = D3D9StereoDriverBridge::getSingleton().isStereoEnabled(this->getName());
966 	}
967 #endif
968 	//---------------------------------------------------------------------
969 }
970