Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp @ 5

Last change on this file since 5 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

File size: 28.8 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreD3D9RenderWindow.h"
30#include "OgreLogManager.h"
31#include "OgreViewport.h"
32#include "OgreException.h"
33#include "OgreD3D9RenderSystem.h"
34#include "OgreRenderSystem.h"
35#include "OgreBitwise.h"
36#include "OgreImageCodec.h"
37#include "OgreStringConverter.h"
38
39#include "OgreNoMemoryMacros.h"
40#include <d3d9.h>
41#include "OgreMemoryMacros.h"
42#include "OgreRoot.h"
43#include "OgreWindowEventUtilities.h"
44
45namespace Ogre
46{
47        D3D9RenderWindow::D3D9RenderWindow(HINSTANCE instance, D3D9Driver *driver, LPDIRECT3DDEVICE9 deviceIfSwapChain)
48        : mInstance(instance)
49        , mDriver(driver)
50        , mpRenderSurface(0)
51        {
52                mIsFullScreen = false;
53                mIsSwapChain = (deviceIfSwapChain != NULL);
54                mIsExternal = false;
55                mHWnd = 0;
56                mActive = false;
57                mSizing = false;
58                mClosed = false;
59                mSwitchingFullscreen = false;
60                mDisplayFrequency = 0;
61        }
62
63        D3D9RenderWindow::~D3D9RenderWindow()
64        {
65                destroy();
66        }
67
68        bool D3D9RenderWindow::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
69        {
70                LPDIRECT3D9 pD3D = mDriver->getD3D();
71
72                if (SUCCEEDED(pD3D->CheckDeviceMultiSampleType(
73                        adapterNum, 
74                        deviceType, format, 
75                        fullScreen, type, outQuality)))
76                        return true;
77                else
78                        return false;
79        }
80
81        void D3D9RenderWindow::create(const String& name, unsigned int width, unsigned int height,
82                bool fullScreen, const NameValuePairList *miscParams)
83        {
84                HINSTANCE hInst = mInstance;
85                D3D9Driver* driver = mDriver;
86
87                HWND parentHWnd = 0;
88                HWND externalHandle = 0;
89                mFSAAType = D3DMULTISAMPLE_NONE;
90                mFSAAQuality = 0;
91                mVSync = false;
92                String title = name;
93                unsigned int colourDepth = 32;
94                int left = -1; // Defaults to screen center
95                int top = -1; // Defaults to screen center
96                bool depthBuffer = true;
97                String border = "";
98                bool outerSize = false;
99                mUseNVPerfHUD = false;
100
101                if(miscParams)
102                {
103                        // Get variable-length params
104                        NameValuePairList::const_iterator opt;
105                        // left (x)
106                        opt = miscParams->find("left");
107                        if(opt != miscParams->end())
108                                left = StringConverter::parseInt(opt->second);
109                        // top (y)
110                        opt = miscParams->find("top");
111                        if(opt != miscParams->end())
112                                top = StringConverter::parseInt(opt->second);
113                        // Window title
114                        opt = miscParams->find("title");
115                        if(opt != miscParams->end())
116                                title = opt->second;
117                        // parentWindowHandle           -> parentHWnd
118                        opt = miscParams->find("parentWindowHandle");
119                        if(opt != miscParams->end())
120                                parentHWnd = (HWND)StringConverter::parseUnsignedInt(opt->second);
121                        // externalWindowHandle         -> externalHandle
122                        opt = miscParams->find("externalWindowHandle");
123                        if(opt != miscParams->end())
124                                externalHandle = (HWND)StringConverter::parseUnsignedInt(opt->second);
125                        // vsync        [parseBool]
126                        opt = miscParams->find("vsync");
127                        if(opt != miscParams->end())
128                                mVSync = StringConverter::parseBool(opt->second);
129                        // displayFrequency
130                        opt = miscParams->find("displayFrequency");
131                        if(opt != miscParams->end())
132                                mDisplayFrequency = StringConverter::parseUnsignedInt(opt->second);
133                        // colourDepth
134                        opt = miscParams->find("colourDepth");
135                        if(opt != miscParams->end())
136                                colourDepth = StringConverter::parseUnsignedInt(opt->second);
137                        // depthBuffer [parseBool]
138                        opt = miscParams->find("depthBuffer");
139                        if(opt != miscParams->end())
140                                depthBuffer = StringConverter::parseBool(opt->second);
141                        // FSAA type
142                        opt = miscParams->find("FSAA");
143                        if(opt != miscParams->end())
144                                mFSAAType = (D3DMULTISAMPLE_TYPE)StringConverter::parseUnsignedInt(opt->second);
145                        // FSAA quality
146                        opt = miscParams->find("FSAAQuality");
147                        if(opt != miscParams->end())
148                                mFSAAQuality = StringConverter::parseUnsignedInt(opt->second);
149                        // window border style
150                        opt = miscParams->find("border");
151                        if(opt != miscParams->end())
152                                border = opt->second;
153                        // set outer dimensions?
154                        opt = miscParams->find("outerDimensions");
155                        if(opt != miscParams->end())
156                                outerSize = StringConverter::parseBool(opt->second);
157                        // NV perf HUD?
158                        opt = miscParams->find("useNVPerfHUD");
159                        if(opt != miscParams->end())
160                                mUseNVPerfHUD = StringConverter::parseBool(opt->second);
161                         
162                }
163
164                // Destroy current window if any
165                if( mHWnd )
166                        destroy();
167
168                if (!externalHandle)
169                {
170                        DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
171                        RECT rc;
172
173                        mWidth = width;
174                        mHeight = height;
175                        mTop = top;
176                        mLeft = left;
177
178                        if (!fullScreen)
179                        {
180                                if (parentHWnd)
181                                {
182                                        dwStyle |= WS_CHILD;
183                                }
184                                else
185                                {
186                                        if (border == "none")
187                                                dwStyle |= WS_POPUP;
188                                        else if (border == "fixed")
189                                                dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
190                                                WS_SYSMENU | WS_MINIMIZEBOX;
191                                        else
192                                                dwStyle |= WS_OVERLAPPEDWINDOW;
193                                }
194
195                                if (!outerSize)
196                                {
197                                        // Calculate window dimensions required
198                                        // to get the requested client area
199                                        SetRect(&rc, 0, 0, mWidth, mHeight);
200                                        AdjustWindowRect(&rc, dwStyle, false);
201                                        mWidth = rc.right - rc.left;
202                                        mHeight = rc.bottom - rc.top;
203
204                                        // Clamp width and height to the desktop dimensions
205                                        int screenw = GetSystemMetrics(SM_CXSCREEN);
206                                        int screenh = GetSystemMetrics(SM_CYSCREEN);
207                                        if ((int)mWidth > screenw)
208                                                mWidth = screenw;
209                                        if ((int)mHeight > screenh)
210                                                mHeight = screenh;
211                                        if (mLeft < 0)
212                                                mLeft = (screenw - mWidth) / 2;
213                                        if (mTop < 0)
214                                                mTop = (screenh - mHeight) / 2;
215                                }
216                        }
217                        else
218                        {
219                                dwStyle |= WS_POPUP;
220                                mTop = mLeft = 0;
221                        }
222
223                        // Register the window class
224                        // NB allow 4 bytes of window data for D3D9RenderWindow pointer
225                        WNDCLASS wc = { 0, WindowEventUtilities::_WndProc, 0, 0, hInst,
226                                LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
227                                (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "OgreD3D9Wnd" };
228                        RegisterClass(&wc);
229
230                        // Create our main window
231                        // Pass pointer to self
232                        mIsExternal = false;
233                        mHWnd = CreateWindow("OgreD3D9Wnd", title.c_str(), dwStyle,
234                                mLeft, mTop, mWidth, mHeight, parentHWnd, 0, hInst, this);
235                       
236                        WindowEventUtilities::_addRenderWindow(this);
237                }
238                else
239                {
240                        mHWnd = externalHandle;
241                        mIsExternal = true;
242                }
243
244                RECT rc;
245                // top and left represent outer window coordinates
246                GetWindowRect(mHWnd, &rc);
247                mTop = rc.top;
248                mLeft = rc.left;
249                // width and height represent interior drawable area
250                GetClientRect(mHWnd, &rc);
251                mWidth = rc.right;
252                mHeight = rc.bottom;
253
254                mName = name;
255                mIsDepthBuffered = depthBuffer;
256                mIsFullScreen = fullScreen;
257                mColourDepth = colourDepth;
258
259                StringUtil::StrStreamType str;
260                str << "D3D9 : Created D3D9 Rendering Window '"
261                        << mName << "' : " << mWidth << "x" << mHeight
262                        << ", " << mColourDepth << "bpp";
263                LogManager::getSingleton().logMessage(
264                        LML_NORMAL, str.str());
265
266                createD3DResources();
267
268                mActive = true;
269                mClosed = false;
270        }
271
272        void D3D9RenderWindow::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
273        {
274                if (fullScreen != mIsFullScreen || width != mWidth || height != mHeight)
275                {
276
277                        if (fullScreen != mIsFullScreen)
278                                mSwitchingFullscreen = true;
279
280                        DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
281
282                        bool oldFullscreen = mIsFullScreen;
283                        mIsFullScreen = fullScreen;
284
285                        if (fullScreen)
286                        {
287                                dwStyle |= WS_POPUP;
288                                mTop = mLeft = 0;
289                                mWidth = width;
290                                mHeight = height;
291                                // need different ordering here
292
293                                if (oldFullscreen)
294                                {
295                                        // was previously fullscreen, just changing the resolution
296                                        SetWindowPos(mHWnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOACTIVATE);
297                                }
298                                else
299                                {
300                                        SetWindowPos(mHWnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOACTIVATE);
301                                        //MoveWindow(mHWnd, mLeft, mTop, mWidth, mHeight, FALSE);
302                                        SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
303                                        SetWindowPos(mHWnd, 0, 0,0, 0,0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
304                                }
305                        }
306                        else
307                        {
308                                dwStyle |= WS_OVERLAPPEDWINDOW;
309                                // Calculate window dimensions required
310                                // to get the requested client area
311                                RECT rc;
312                                SetRect(&rc, 0, 0, width, height);
313                                AdjustWindowRect(&rc, dwStyle, false);
314                                unsigned int winWidth = rc.right - rc.left;
315                                unsigned int winHeight = rc.bottom - rc.top;
316
317                                SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
318                                SetWindowPos(mHWnd, HWND_NOTOPMOST, 0, 0, winWidth, winHeight,
319                                        SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE);
320                                // Note that we also set the position in the restoreLostDevice method
321                                // via _finishSwitchingFullScreen
322                        }
323
324                        md3dpp.Windowed = !fullScreen;
325                        md3dpp.FullScreen_RefreshRateInHz = mIsFullScreen ? mDisplayFrequency : 0;
326                        md3dpp.BackBufferHeight = height;
327                        md3dpp.BackBufferWidth = width;
328
329                        if ((oldFullscreen && fullScreen) || mIsExternal)
330                        {
331                                // Have to release & trigger device reset
332                                // NB don't use windowMovedOrResized since Win32 doesn't know
333                                // about the size change yet
334                                SAFE_RELEASE(mpRenderSurface);
335                                static_cast<D3D9RenderSystem*>(Root::getSingleton().getRenderSystem())->_notifyDeviceLost();
336                                // Notify viewports of resize
337                                ViewportList::iterator it = mViewportList.begin();
338                                while(it != mViewportList.end()) (*it++).second->_updateDimensions();
339                        }
340                }
341        } 
342
343        void D3D9RenderWindow::_finishSwitchingFullscreen()
344        {
345                if(mIsFullScreen)
346                {
347                        // Need to reset the region on the window sometimes, when the
348                        // windowed mode was constrained by desktop
349                        HRGN hRgn = CreateRectRgn(0,0,md3dpp.BackBufferWidth, md3dpp.BackBufferHeight);
350                        SetWindowRgn(mHWnd, hRgn, FALSE);
351                }
352                else
353                {
354                        // When switching back to windowed mode, need to reset window size
355                        // after device has been restored
356                        RECT rc;
357                        SetRect(&rc, 0, 0, md3dpp.BackBufferWidth, md3dpp.BackBufferHeight);
358                        AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
359                        unsigned int winWidth = rc.right - rc.left;
360                        unsigned int winHeight = rc.bottom - rc.top;
361                        int screenw = GetSystemMetrics(SM_CXSCREEN);
362                        int screenh = GetSystemMetrics(SM_CYSCREEN);
363                        int left = (screenw - winWidth) / 2;
364                        int top = (screenh - winHeight) / 2;
365                        SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
366                                SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
367
368                }
369                mSwitchingFullscreen = false;
370        }
371
372        void D3D9RenderWindow::createD3DResources(void)
373        {
374                // access device via driver
375                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
376
377                if (mIsSwapChain && !mpD3DDevice)
378                {
379                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
380                                "Secondary window has not been given the device from the primary!",
381                                "D3D9RenderWindow::createD3DResources");
382                }
383
384                SAFE_RELEASE(mpRenderSurface);
385
386                // Set up the presentation parameters
387                HRESULT hr;
388                LPDIRECT3D9 pD3D = mDriver->getD3D();
389                D3DDEVTYPE devType = D3DDEVTYPE_HAL;
390
391                ZeroMemory( &md3dpp, sizeof(D3DPRESENT_PARAMETERS) );
392                md3dpp.Windowed                                 = !mIsFullScreen;
393                md3dpp.SwapEffect                               = D3DSWAPEFFECT_DISCARD;
394                // triple buffer if VSync is on
395                md3dpp.BackBufferCount                  = mVSync ? 2 : 1;
396                md3dpp.EnableAutoDepthStencil   = mIsDepthBuffered;
397                md3dpp.hDeviceWindow                    = mHWnd;
398                md3dpp.BackBufferWidth                  = mWidth;
399                md3dpp.BackBufferHeight                 = mHeight;
400                md3dpp.FullScreen_RefreshRateInHz = mIsFullScreen ? mDisplayFrequency : 0;
401               
402
403                if (mVSync)
404                {
405                        md3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
406                }
407                else
408                {
409                        // NB not using vsync in windowed mode in D3D9 can cause jerking at low
410                        // frame rates no matter what buffering modes are used (odd - perhaps a
411                        // timer issue in D3D9 since GL doesn't suffer from this)
412                        // low is < 200fps in this context
413                        if (!mIsFullScreen)
414                        {
415                                LogManager::getSingleton().logMessage("D3D9 : WARNING - "
416                                        "disabling VSync in windowed mode can cause timing issues at lower "
417                                        "frame rates, turn VSync on if you observe this problem.");
418                        }
419                        md3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
420                }
421
422                md3dpp.BackBufferFormat         = D3DFMT_R5G6B5;
423                if( mColourDepth > 16 )
424                        md3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
425
426                if (mColourDepth > 16 )
427                {
428                        // Try to create a 32-bit depth, 8-bit stencil
429                        if( FAILED( pD3D->CheckDeviceFormat(mDriver->getAdapterNumber(),
430                                devType,  md3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL, 
431                                D3DRTYPE_SURFACE, D3DFMT_D24S8 )))
432                        {
433                                // Bugger, no 8-bit hardware stencil, just try 32-bit zbuffer
434                                if( FAILED( pD3D->CheckDeviceFormat(mDriver->getAdapterNumber(),
435                                        devType,  md3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL, 
436                                        D3DRTYPE_SURFACE, D3DFMT_D32 )))
437                                {
438                                        // Jeez, what a naff card. Fall back on 16-bit depth buffering
439                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D16;
440                                }
441                                else
442                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D32;
443                        }
444                        else
445                        {
446                                // Woohoo!
447                                if( SUCCEEDED( pD3D->CheckDepthStencilMatch( mDriver->getAdapterNumber(), devType,
448                                        md3dpp.BackBufferFormat, md3dpp.BackBufferFormat, D3DFMT_D24S8 ) ) )
449                                {
450                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; 
451                                } 
452                                else 
453                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D24X8; 
454                        }
455                }
456                else
457                        // 16-bit depth, software stencil
458                        md3dpp.AutoDepthStencilFormat   = D3DFMT_D16;
459
460                md3dpp.MultiSampleType = mFSAAType;
461                md3dpp.MultiSampleQuality = (mFSAAQuality == 0) ? 0 : mFSAAQuality;
462
463                if (mIsSwapChain)
464                {
465                        // Create swap chain                   
466                        hr = mpD3DDevice->CreateAdditionalSwapChain(
467                                &md3dpp, &mpSwapChain);
468                        if (FAILED(hr))
469                        {
470                                // Try a second time, may fail the first time due to back buffer count,
471                                // which will be corrected by the runtime
472                                hr = mpD3DDevice->CreateAdditionalSwapChain(
473                                        &md3dpp, &mpSwapChain);
474                        }
475                        if (FAILED(hr))
476                        {
477                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
478                                        "Unable to create an additional swap chain",
479                                        "D3D9RenderWindow::createD3DResources");
480                        }
481                        // Store references to buffers for convenience
482                        mpSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &mpRenderSurface );
483                        // Additional swap chains need their own depth buffer
484                        // to support resizing them
485                        if (mIsDepthBuffered) 
486                        {
487                                hr = mpD3DDevice->CreateDepthStencilSurface(
488                                        mWidth, mHeight,
489                                        md3dpp.AutoDepthStencilFormat,
490                                        md3dpp.MultiSampleType,
491                                        md3dpp.MultiSampleQuality, 
492                                        (md3dpp.Flags & D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL),
493                                        &mpRenderZBuffer, NULL
494                                        );
495
496                                if (FAILED(hr)) 
497                                {
498                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
499                                                "Unable to create a depth buffer for the swap chain",
500                                                "D3D9RenderWindow::createD3DResources");
501
502                                }
503                        } 
504                        else 
505                        {
506                                mpRenderZBuffer = 0;
507                        }
508                }
509                else
510                {
511                        if (!mpD3DDevice)
512                        {
513                                // We haven't created the device yet, this must be the first time
514
515                                // Do we want to preserve the FPU mode? Might be useful for scientific apps
516                                DWORD extraFlags = 0;
517                                ConfigOptionMap& options = Root::getSingleton().getRenderSystem()->getConfigOptions();
518                                ConfigOptionMap::iterator opti = options.find("Floating-point mode");
519                                if (opti != options.end() && opti->second.currentValue == "Consistent")
520                                        extraFlags |= D3DCREATE_FPU_PRESERVE;
521
522#if OGRE_THREAD_SUPPORT
523                                extraFlags |= D3DCREATE_MULTITHREADED;
524#endif
525                                // Set default settings (use the one Ogre discovered as a default)
526                                UINT adapterToUse = mDriver->getAdapterNumber();
527
528                                if (mUseNVPerfHUD)
529                                {
530                                        // Look for 'NVIDIA NVPerfHUD' adapter (<= v4)
531                                        // or 'NVIDIA PerfHUD' (v5)
532                                        // If it is present, override default settings
533                                        for (UINT adapter=0; adapter < mDriver->getD3D()->GetAdapterCount(); ++adapter)
534                                        {
535                                                D3DADAPTER_IDENTIFIER9 identifier;
536                                                HRESULT res;
537                                                res = mDriver->getD3D()->GetAdapterIdentifier(adapter,0,&identifier);
538                                                if (strstr(identifier.Description,"PerfHUD") != 0)
539                                                {
540                                                        adapterToUse = adapter;
541                                                        devType = D3DDEVTYPE_REF;
542                                                        break;
543                                                }
544                                        }
545                                }
546
547                                hr = pD3D->CreateDevice(adapterToUse, devType, mHWnd,
548                                        D3DCREATE_HARDWARE_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
549                                if (FAILED(hr))
550                                {
551                                        // Try a second time, may fail the first time due to back buffer count,
552                                        // which will be corrected down to 1 by the runtime
553                                        hr = pD3D->CreateDevice( adapterToUse, devType, mHWnd,
554                                                D3DCREATE_HARDWARE_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
555                                }
556                                if( FAILED( hr ) )
557                                {
558                                        hr = pD3D->CreateDevice( adapterToUse, devType, mHWnd,
559                                                D3DCREATE_MIXED_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
560                                        if( FAILED( hr ) )
561                                        {
562                                                hr = pD3D->CreateDevice( adapterToUse, devType, mHWnd,
563                                                        D3DCREATE_SOFTWARE_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
564                                        }
565                                }
566                                // TODO: make this a bit better e.g. go from pure vertex processing to software
567                                if( FAILED( hr ) )
568                                {
569                                        destroy();
570                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
571                                                "Failed to create Direct3D9 Device: " + 
572                                                Root::getSingleton().getErrorDescription(hr), 
573                                                "D3D9RenderWindow::createD3DResources" );
574                                }
575                        }
576                        // update device in driver
577                        mDriver->setD3DDevice( mpD3DDevice );
578                        // Store references to buffers for convenience
579                        mpD3DDevice->GetRenderTarget( 0, &mpRenderSurface );
580                        mpD3DDevice->GetDepthStencilSurface( &mpRenderZBuffer );
581                        // release immediately so we don't hog them
582                        mpRenderZBuffer->Release();
583                }
584
585        }
586
587        void D3D9RenderWindow::destroyD3DResources()
588        {
589                if (mIsSwapChain)
590                {
591                        SAFE_RELEASE(mpRenderZBuffer);
592                        SAFE_RELEASE(mpSwapChain);
593                }
594                else
595                {
596                        // ignore depth buffer, access device through driver
597                        mpRenderZBuffer = 0;
598                }
599                SAFE_RELEASE(mpRenderSurface);
600        }
601
602        void D3D9RenderWindow::destroy()
603        {
604                destroyD3DResources();
605
606                if (mHWnd && !mIsExternal)
607                {
608                        WindowEventUtilities::_removeRenderWindow(this);
609                        DestroyWindow(mHWnd);
610                }
611
612                mHWnd = 0;
613                mActive = false;
614                mClosed = true;
615        }
616
617        bool D3D9RenderWindow::isVisible() const
618        {
619                return (mHWnd && !IsIconic(mHWnd));
620        }
621
622        void D3D9RenderWindow::reposition(int top, int left)
623        {
624                if (mHWnd && !mIsFullScreen)
625                {
626                        SetWindowPos(mHWnd, 0, top, left, 0, 0,
627                                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
628                }
629        }
630
631        void D3D9RenderWindow::resize(unsigned int width, unsigned int height)
632        {
633                if (mHWnd && !mIsFullScreen)
634                {
635                        RECT rc = { 0, 0, width, height };
636                        AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
637                        width = rc.right - rc.left;
638                        height = rc.bottom - rc.top;
639                        SetWindowPos(mHWnd, 0, 0, 0, width, height,
640                                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
641                }
642        }
643
644        void D3D9RenderWindow::windowMovedOrResized()
645        {
646                if (!mHWnd || IsIconic(mHWnd))
647                        return;
648
649                RECT rc;
650                // top and left represent outer window position
651                GetWindowRect(mHWnd, &rc);
652                mTop = rc.top;
653                mLeft = rc.left;
654                // width and height represent drawable area only
655                GetClientRect(mHWnd, &rc);
656                unsigned int width = rc.right;
657                unsigned int height = rc.bottom;
658                if (mWidth == width && mHeight == height)
659                        return;
660
661                SAFE_RELEASE( mpRenderSurface );
662
663                if (mIsSwapChain) 
664                {
665
666                        D3DPRESENT_PARAMETERS pp = md3dpp;
667
668                        pp.BackBufferWidth = width;
669                        pp.BackBufferHeight = height;
670
671                        SAFE_RELEASE( mpRenderZBuffer );
672                        SAFE_RELEASE( mpSwapChain );
673
674                        HRESULT hr = mDriver->getD3DDevice()->CreateAdditionalSwapChain(
675                                &pp,
676                                &mpSwapChain);
677
678                        if (FAILED(hr)) 
679                        {
680                                StringUtil::StrStreamType str;
681                                str << "D3D9RenderWindow: failed to reset device to new dimensions << "
682                                        << width << " x " << height << ". Trying to recover.";
683                                LogManager::getSingleton().logMessage(LML_CRITICAL, str.str());
684
685                                // try to recover
686                                hr = mDriver->getD3DDevice()->CreateAdditionalSwapChain(
687                                        &md3dpp,
688                                        &mpSwapChain);
689
690                                if (FAILED(hr))
691                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Reset window to last size failed", "D3D9RenderWindow::resize" );
692
693                        }               
694                        else 
695                        {
696                                md3dpp = pp;
697
698                                mWidth = width;
699                                mHeight = height;
700
701                                hr = mpSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mpRenderSurface);
702                                hr = mDriver->getD3DDevice()->CreateDepthStencilSurface(
703                                        mWidth, mHeight,
704                                        md3dpp.AutoDepthStencilFormat,
705                                        md3dpp.MultiSampleType,
706                                        md3dpp.MultiSampleQuality, 
707                                        (md3dpp.Flags & D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL),
708                                        &mpRenderZBuffer, NULL
709                                        );
710
711                                if (FAILED(hr)) 
712                                {
713                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to create depth stencil surface for Swap Chain", "D3D9RenderWindow::resize" );
714                                }
715
716                        }
717                }
718                // primary windows must reset the device
719                else 
720                {
721                        md3dpp.BackBufferWidth = mWidth = width;
722                        md3dpp.BackBufferHeight = mHeight = height;
723                        static_cast<D3D9RenderSystem*>(
724                                Root::getSingleton().getRenderSystem())->_notifyDeviceLost();
725                }
726
727                // Notify viewports of resize
728                ViewportList::iterator it = mViewportList.begin();
729                while( it != mViewportList.end() )
730                        (*it++).second->_updateDimensions();
731        }
732
733        void D3D9RenderWindow::swapBuffers( bool waitForVSync )
734        {
735                // access device through driver
736                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
737                if( mpD3DDevice )
738                {
739                        HRESULT hr;
740                        if (mIsSwapChain)
741                        {
742                                hr = mpSwapChain->Present(NULL, NULL, NULL, NULL, 0);
743                        }
744                        else
745                        {
746                                hr = mpD3DDevice->Present( NULL, NULL, 0, NULL );
747                        }
748                        if( D3DERR_DEVICELOST == hr )
749                        {
750                                SAFE_RELEASE(mpRenderSurface);
751
752                                static_cast<D3D9RenderSystem*>(
753                                        Root::getSingleton().getRenderSystem())->_notifyDeviceLost();
754                        }
755                        else if( FAILED(hr) )
756                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error Presenting surfaces", "D3D9RenderWindow::swapBuffers" );
757                }
758        }
759
760        void D3D9RenderWindow::getCustomAttribute( const String& name, void* pData )
761        {
762                // Valid attributes and their equvalent native functions:
763                // D3DDEVICE                    : getD3DDevice
764                // WINDOW                               : getWindowHandle
765
766                if( name == "D3DDEVICE" )
767                {
768                        LPDIRECT3DDEVICE9 *pDev = (LPDIRECT3DDEVICE9*)pData;
769                        *pDev = getD3DDevice();
770                        return;
771                }
772                else if( name == "WINDOW" )
773                {
774                        HWND *pHwnd = (HWND*)pData;
775                        *pHwnd = getWindowHandle();
776                        return;
777                }
778                else if( name == "isTexture" )
779                {
780                        bool *b = reinterpret_cast< bool * >( pData );
781                        *b = false;
782
783                        return;
784                }
785                else if( name == "D3DZBUFFER" )
786                {
787                        LPDIRECT3DSURFACE9 *pSurf = (LPDIRECT3DSURFACE9*)pData;
788                        *pSurf = mpRenderZBuffer;
789                        return;
790                }
791                else if( name == "DDBACKBUFFER" )
792                {
793                        LPDIRECT3DSURFACE9 *pSurf = (LPDIRECT3DSURFACE9*)pData;
794                        *pSurf = mpRenderSurface;
795                        return;
796                }
797                else if( name == "DDFRONTBUFFER" )
798                {
799                        LPDIRECT3DSURFACE9 *pSurf = (LPDIRECT3DSURFACE9*)pData;
800                        *pSurf = mpRenderSurface;
801                        return;
802                }
803        }
804
805        void D3D9RenderWindow::writeContentsToFile(const String& filename)
806        {
807                HRESULT hr;
808                LPDIRECT3DSURFACE9 pSurf=NULL, pTempSurf=NULL;
809                D3DSURFACE_DESC desc;
810                D3DDISPLAYMODE dm;
811
812                // access device through driver
813                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
814
815                // get display dimensions
816                // this will be the dimensions of the front buffer
817                if (FAILED(hr = mpD3DDevice->GetDisplayMode(0, &dm)))
818                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Can't get display mode!", "D3D9RenderWindow::writeContentsToFile");
819
820                desc.Width = dm.Width;
821                desc.Height = dm.Height;
822                desc.Format = D3DFMT_A8R8G8B8;
823                if (FAILED(hr = mpD3DDevice->CreateOffscreenPlainSurface(
824                        desc.Width, 
825                        desc.Height, 
826                        desc.Format, 
827                        D3DPOOL_SYSTEMMEM, 
828                        &pTempSurf, 
829                        NULL)))
830                {
831                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot create offscreen buffer 1!", "D3D9RenderWindow::writeContentsToFile");
832                }
833
834                if (FAILED(hr = mpD3DDevice->GetFrontBufferData(0, pTempSurf)))
835                {
836                        SAFE_RELEASE(pTempSurf);
837                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Can't get front buffer!", "D3D9RenderWindow::writeContentsToFile");
838                }
839               
840                D3DLOCKED_RECT lockedRect;
841                if(mIsFullScreen)
842                {
843                        if (FAILED(hr = pTempSurf->LockRect(&lockedRect, NULL, 
844                        D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)))
845                        {
846                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "can't lock rect!", "D3D9RenderWindow::writeContentsToFile");
847                        } 
848                }
849                else
850                {
851                        RECT srcRect;
852                        GetClientRect(mHWnd, &srcRect);
853                        POINT point;
854                        point.x = srcRect.left;
855                        point.y = srcRect.top;
856                        ClientToScreen(mHWnd, &point);
857                        srcRect.top = point.y;
858                        srcRect.left = point.x;
859                        srcRect.bottom += point.y;
860                        srcRect.right += point.x;
861
862                        desc.Width = srcRect.right - srcRect.left;
863                        desc.Height = srcRect.bottom - srcRect.top;
864
865                        if (FAILED(hr = pTempSurf->LockRect(&lockedRect, &srcRect, 
866
867                        D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)))
868                        {
869                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "can't lock rect!", "D3D9RenderWindow::writeContentsToFile");
870                        } 
871                }
872 
873                ImageCodec::ImageData *imgData = new ImageCodec::ImageData();
874                imgData->width = desc.Width;
875                imgData->height = desc.Height;
876                imgData->format = PF_BYTE_RGB;
877
878                // Allocate contiguous buffer (surfaces aren't necessarily contiguous)
879                uchar* pBuffer = new uchar[desc.Width * desc.Height * 3];
880
881                uint x, y;
882                uchar *pData, *pDest;
883
884                pData = (uchar*)lockedRect.pBits;
885                pDest = pBuffer;
886                for (y = 0; y < desc.Height; ++y)
887                {
888                        uchar *pRow = pData;
889
890                        for (x = 0; x < desc.Width; ++x)
891                        {
892                                switch(desc.Format)
893                                {
894                                case D3DFMT_R5G6B5:
895                                        WORD val;
896
897                                        val = *((WORD*)pRow);
898                                        pRow += 2;
899
900                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0xF800, (BYTE)0xFF);
901                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0x07E0, (BYTE)0xFF);
902                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0x001F, (BYTE)0xFF);
903                                        break;
904                                case D3DFMT_A8R8G8B8:
905                                case D3DFMT_X8R8G8B8:
906                                        // Actual format is BRGA for some reason
907                                        *pDest++ = pRow[2]; // R
908                                        *pDest++ = pRow[1]; // G
909                                        *pDest++ = pRow[0]; // B
910                                        pRow += 4; // skip alpha / dummy
911                                        break;
912                                case D3DFMT_R8G8B8:
913                                        // Actual format is BRGA for some reason
914                                        *pDest++ = pRow[2]; // R
915                                        *pDest++ = pRow[1]; // G
916                                        *pDest++ = pRow[0]; // B
917                                        pRow += 3; 
918                                        break;
919                                }
920
921
922                        }
923                        // increase by one line
924                        pData += lockedRect.Pitch;
925                }
926
927                // Wrap buffer in a chunk
928                MemoryDataStreamPtr stream(new MemoryDataStream(pBuffer, desc.Width * desc.Height * 3, false));
929
930                // Get codec
931                size_t pos = filename.find_last_of(".");
932                String extension;
933                if( pos == String::npos )
934                        OGRE_EXCEPT(
935                        Exception::ERR_INVALIDPARAMS, 
936                        "Unable to determine image type for '" + filename + "' - invalid extension.",
937                        "D3D9RenderWindow::writeContentsToFile" );
938
939                while( pos != filename.length() - 1 )
940                        extension += filename[++pos];
941
942                // Get the codec
943                Codec * pCodec = Codec::getCodec(extension);
944
945                // Write out
946                {
947                        Codec::CodecDataPtr ptr(imgData);
948                        pCodec->codeToFile(stream, filename, ptr);
949                }
950
951                delete [] pBuffer;
952
953                SAFE_RELEASE(pTempSurf);
954                SAFE_RELEASE(pSurf);
955        }
956        //-----------------------------------------------------------------------------
957        void D3D9RenderWindow::update(bool swap)
958        {
959
960                D3D9RenderSystem* rs = static_cast<D3D9RenderSystem*>(
961                        Root::getSingleton().getRenderSystem());
962
963                // access device through driver
964                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
965
966                if (rs->isDeviceLost())
967                {
968                        // Test the cooperative mode first
969                        HRESULT hr = mpD3DDevice->TestCooperativeLevel();
970                        if (hr == D3DERR_DEVICELOST)
971                        {
972                                // device lost, and we can't reset
973                                // can't do anything about it here, wait until we get
974                                // D3DERR_DEVICENOTRESET; rendering calls will silently fail until
975                                // then (except Present, but we ignore device lost there too)
976                                SAFE_RELEASE(mpRenderSurface);
977                                // need to release if swap chain
978                                if (!mIsSwapChain)
979                                        mpRenderZBuffer = 0;
980                                else
981                                        SAFE_RELEASE (mpRenderZBuffer);
982                                Sleep(50);
983                                return;
984                        }
985                        else
986                        {
987                                // device lost, and we can reset
988                                rs->restoreLostDevice();
989
990                                // Still lost?
991                                if (rs->isDeviceLost())
992                                {
993                                        // Wait a while
994                                        Sleep(50);
995                                        return;
996                                }
997
998                                if (!mIsSwapChain) 
999                                {
1000                                        // re-qeuery buffers
1001                                        mpD3DDevice->GetRenderTarget( 0, &mpRenderSurface );
1002                                        mpD3DDevice->GetDepthStencilSurface( &mpRenderZBuffer );
1003                                        // release immediately so we don't hog them
1004                                        mpRenderZBuffer->Release();
1005                                }
1006                                else 
1007                                {
1008                                    // Update dimensions incase changed
1009                            ViewportList::iterator it = mViewportList.begin();
1010                            while( it != mViewportList.end() )
1011                                    (*it++).second->_updateDimensions();
1012                                        // Actual restoration of surfaces will happen in
1013                                        // D3D9RenderSystem::restoreLostDevice when it calls
1014                                        // createD3DResources for each secondary window
1015                                }
1016                        }
1017
1018                }
1019                RenderWindow::update(swap);
1020        }
1021}
Note: See TracBrowser for help on using the repository browser.