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