source: OGRE/trunk/ogrenew/RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp @ 692

Revision 692, 27.2 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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