source: obsolete/trunk/VUT/work/ogre_changes/RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp @ 193

Revision 193, 30.6 KB checked in by mattausch, 19 years ago (diff)

changed to ogre 103
added readme

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                // access and update device through driver, realse only primary
113                if (!mIsSwapChain)
114                {
115                        LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
116                        SAFE_RELEASE( mpD3DDevice );
117                        mDriver->setD3DDevice( NULL );
118                }
119        }
120
121        bool D3D9RenderWindow::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
122        {
123                LPDIRECT3D9 pD3D = mDriver->getD3D();
124
125                if (SUCCEEDED(pD3D->CheckDeviceMultiSampleType(
126                                adapterNum,
127                                deviceType, format,
128                                fullScreen, type, outQuality)))
129                        return true;
130                else
131                        return false;
132        }
133
134        void D3D9RenderWindow::create(const String& name, unsigned int width, unsigned int height,
135                    bool fullScreen, const NameValuePairList *miscParams)
136        {
137                HINSTANCE hInst = mInstance;
138                D3D9Driver* driver = mDriver;
139               
140                HWND parentHWnd = 0;
141                HWND externalHandle = 0;
142                mFSAAType = D3DMULTISAMPLE_NONE;
143                mFSAAQuality = 0;
144                mVSync = false;
145                unsigned int displayFrequency = 0;
146                String title = name;
147                unsigned int colourDepth = 32;
148                int left = -1; // Defaults to screen center
149                int top = -1; // Defaults to screen center
150                bool depthBuffer = true;
151                String border = "";
152                bool outerSize = false;
153               
154                if(miscParams)
155                {
156                        // Get variable-length params
157                        NameValuePairList::const_iterator opt;
158                        // left (x)
159                        opt = miscParams->find("left");
160                        if(opt != miscParams->end())
161                                left = StringConverter::parseInt(opt->second);
162                        // top (y)
163                        opt = miscParams->find("top");
164                        if(opt != miscParams->end())
165                                top = StringConverter::parseInt(opt->second);
166                        // Window title
167                        opt = miscParams->find("title");
168                        if(opt != miscParams->end())
169                                title = opt->second;
170                        // parentWindowHandle           -> parentHWnd
171                        opt = miscParams->find("parentWindowHandle");
172                        if(opt != miscParams->end())
173                                parentHWnd = (HWND)StringConverter::parseUnsignedInt(opt->second);
174                        // externalWindowHandle         -> externalHandle
175                        opt = miscParams->find("externalWindowHandle");
176                        if(opt != miscParams->end())
177                                externalHandle = (HWND)StringConverter::parseUnsignedInt(opt->second);
178                        // vsync        [parseBool]
179                        opt = miscParams->find("vsync");
180                        if(opt != miscParams->end())
181                                mVSync = StringConverter::parseBool(opt->second);
182                        // displayFrequency
183                        opt = miscParams->find("displayFrequency");
184                        if(opt != miscParams->end())
185                                displayFrequency = StringConverter::parseUnsignedInt(opt->second);
186                        // colourDepth
187                        opt = miscParams->find("colourDepth");
188                        if(opt != miscParams->end())
189                                colourDepth = StringConverter::parseUnsignedInt(opt->second);
190                        // depthBuffer [parseBool]
191                        opt = miscParams->find("depthBuffer");
192                        if(opt != miscParams->end())
193                                depthBuffer = StringConverter::parseBool(opt->second);
194                        // FSAA type
195                        opt = miscParams->find("FSAA");
196                        if(opt != miscParams->end())
197                                mFSAAType = (D3DMULTISAMPLE_TYPE)StringConverter::parseUnsignedInt(opt->second);
198                        // FSAA quality
199                        opt = miscParams->find("FSAAQuality");
200                        if(opt != miscParams->end())
201                                mFSAAQuality = StringConverter::parseUnsignedInt(opt->second);
202                        // window border style
203                        opt = miscParams->find("border");
204                        if(opt != miscParams->end())
205                                border = opt->second;
206                        // set outer dimensions?
207                        opt = miscParams->find("outerDimensions");
208                        if(opt != miscParams->end())
209                                outerSize = StringConverter::parseBool(opt->second);
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                md3dpp.BackBufferCount                  = 1;
339                md3dpp.EnableAutoDepthStencil   = mIsDepthBuffered;
340                md3dpp.hDeviceWindow                    = mHWnd;
341                md3dpp.BackBufferWidth                  = mWidth;
342                md3dpp.BackBufferHeight                 = mHeight;
343
344#ifdef GTP_VISIBILITY_MODIFIED_OGRE
345        //md3dpp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
346#endif
347                if (mVSync)
348                        md3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
349                else
350                        md3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
351
352                md3dpp.BackBufferFormat         = D3DFMT_R5G6B5;
353                if( mColourDepth > 16 )
354                        md3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
355
356                if (mColourDepth > 16 )
357                {
358                        // Try to create a 32-bit depth, 8-bit stencil
359                        if( FAILED( pD3D->CheckDeviceFormat(mDriver->getAdapterNumber(),
360                                devType,  md3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
361                                D3DRTYPE_SURFACE, D3DFMT_D24S8 )))
362                        {
363                                // Bugger, no 8-bit hardware stencil, just try 32-bit zbuffer
364                                if( FAILED( pD3D->CheckDeviceFormat(mDriver->getAdapterNumber(),
365                                        devType,  md3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
366                                        D3DRTYPE_SURFACE, D3DFMT_D32 )))
367                                {
368                                        // Jeez, what a naff card. Fall back on 16-bit depth buffering
369                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D16;
370                                }
371                                else
372                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D32;
373                        }
374                        else
375                        {
376                                // Woohoo!
377                                if( SUCCEEDED( pD3D->CheckDepthStencilMatch( mDriver->getAdapterNumber(), devType,
378                                        md3dpp.BackBufferFormat, md3dpp.BackBufferFormat, D3DFMT_D24S8 ) ) )
379                                {
380                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
381                                }
382                                else
383                                        md3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
384                        }
385                }
386                else
387                        // 16-bit depth, software stencil
388                        md3dpp.AutoDepthStencilFormat   = D3DFMT_D16;
389
390                md3dpp.MultiSampleType = mFSAAType;
391                md3dpp.MultiSampleQuality = (mFSAAQuality == 0) ? 0 : mFSAAQuality;
392
393                if (mIsSwapChain)
394                {
395                        // Create swap chain                   
396                        hr = mpD3DDevice->CreateAdditionalSwapChain(
397                                &md3dpp, &mpSwapChain);
398                        if (FAILED(hr))
399                        {
400                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
401                                        "Unable to create an additional swap chain",
402                                        "D3D9RenderWindow::createD3DResources");
403
404                        }
405                        // Store references to buffers for convenience
406                        mpSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &mpRenderSurface );
407                        // Additional swap chains need their own depth buffer
408                        // to support resizing them
409                        if (mIsDepthBuffered)
410                        {
411                                hr = mpD3DDevice->CreateDepthStencilSurface(
412                                        mWidth, mHeight,
413                                        md3dpp.AutoDepthStencilFormat,
414                                        md3dpp.MultiSampleType,
415                                        md3dpp.MultiSampleQuality,
416                                        (md3dpp.Flags & D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL),
417                                        &mpRenderZBuffer, NULL
418                                        );
419
420                                if (FAILED(hr))
421                                {
422                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
423                                                "Unable to create a depth buffer for the swap chain",
424                                                "D3D9RenderWindow::createD3DResources");
425
426                                }
427                        }
428                        else
429                        {
430                                mpRenderZBuffer = 0;
431                        }
432                        // release immediately so we don't hog them
433                        mpRenderSurface->Release();
434                        // We'll need the depth buffer for rendering the swap chain
435                        //mpRenderZBuffer->Release();
436                }
437                else
438                {
439                        if (!mpD3DDevice)
440                        {
441                                // We haven't created the device yet, this must be the first time
442
443                                // Do we want to preserve the FPU mode? Might be useful for scientific apps
444                                DWORD extraFlags = 0;
445                                ConfigOptionMap& options = Root::getSingleton().getRenderSystem()->getConfigOptions();
446                                ConfigOptionMap::iterator opti = options.find("Floating-point mode");
447                                if (opti != options.end() && opti->second.currentValue == "Consistent")
448                                        extraFlags |= D3DCREATE_FPU_PRESERVE;
449
450                                hr = pD3D->CreateDevice( mDriver->getAdapterNumber(), devType, mHWnd,
451                                        D3DCREATE_HARDWARE_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
452                                if( FAILED( hr ) )
453                                {
454                                        hr = pD3D->CreateDevice( mDriver->getAdapterNumber(), devType, mHWnd,
455                                                D3DCREATE_MIXED_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
456                                        if( FAILED( hr ) )
457                                        {
458                                                hr = pD3D->CreateDevice( mDriver->getAdapterNumber(), devType, mHWnd,
459                                                        D3DCREATE_SOFTWARE_VERTEXPROCESSING | extraFlags, &md3dpp, &mpD3DDevice );
460                                        }
461                                }
462                                // TODO: make this a bit better e.g. go from pure vertex processing to software
463                                if( FAILED( hr ) )
464                                {
465                                        destroy();
466                                        OGRE_EXCEPT( hr, "Failed to create Direct3D9 Device: " +
467                                                Root::getSingleton().getErrorDescription(hr),
468                                                "D3D9RenderWindow::createD3DResources" );
469                                }
470                        }
471                        // update device in driver
472                        mDriver->setD3DDevice( mpD3DDevice );
473                        // Store references to buffers for convenience
474                        mpD3DDevice->GetRenderTarget( 0, &mpRenderSurface );
475                        mpD3DDevice->GetDepthStencilSurface( &mpRenderZBuffer );
476                        // release immediately so we don't hog them
477                        mpRenderSurface->Release();
478                        mpRenderZBuffer->Release();
479                }
480
481        }
482
483        void D3D9RenderWindow::destroyD3DResources()
484        {
485                mpRenderSurface = 0;
486                if (mIsSwapChain)
487                {
488                        SAFE_RELEASE(mpRenderZBuffer);
489                        SAFE_RELEASE(mpSwapChain);
490                }
491                else
492                {
493                        // ignore depth buffer, access device through driver
494                        mpRenderZBuffer = 0;
495                        LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
496                        SAFE_RELEASE(mpD3DDevice);
497                        mDriver->setD3DDevice(NULL);
498                }
499        }
500
501        void D3D9RenderWindow::destroy()
502        {
503                if (mHWnd && !mIsExternal)
504                        DestroyWindow( mHWnd );
505                mHWnd = 0;
506                mActive = false;
507        }
508
509        bool D3D9RenderWindow::isVisible() const
510        {
511                return (mHWnd && !IsIconic(mHWnd));
512        }
513
514        void D3D9RenderWindow::reposition(int top, int left)
515        {
516                if (mHWnd && !mIsFullScreen)
517                {
518                        SetWindowPos(mHWnd, 0, top, left, 0, 0,
519                                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
520                }
521        }
522
523        void D3D9RenderWindow::resize( unsigned int width, unsigned int height )
524        {
525                if (mHWnd && !mIsFullScreen)
526                {
527                        RECT rc = { 0, 0, width, height };
528                        AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
529                        width = rc.right - rc.left;
530                        height = rc.bottom - rc.top;
531                        SetWindowPos(mHWnd, 0, 0, 0, width, height,
532                                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
533                }
534        }
535
536        void D3D9RenderWindow::windowMovedOrResized()
537        {
538                if (!mHWnd || IsIconic(mHWnd))
539                        return;
540
541                RECT rc;
542                // top and left represent outer window position
543                GetWindowRect(mHWnd, &rc);
544                mTop = rc.top;
545                mLeft = rc.left;
546                // width and height represent drawable area only
547                GetClientRect(mHWnd, &rc);
548                unsigned int width = rc.right;
549                unsigned int height = rc.bottom;
550                if (mWidth == width && mHeight == height)
551                        return;
552               
553                if (mIsSwapChain)
554                {
555
556                        D3DPRESENT_PARAMETERS pp = md3dpp;
557
558                        pp.BackBufferWidth = width;
559                        pp.BackBufferHeight = height;
560
561                        SAFE_RELEASE( mpRenderZBuffer );
562                        SAFE_RELEASE( mpSwapChain );
563
564                        HRESULT hr = mDriver->getD3DDevice()->CreateAdditionalSwapChain(
565                                &pp,
566                                &mpSwapChain);
567
568                        if (FAILED(hr))
569                        {
570                                StringUtil::StrStreamType str;
571                                str << "D3D9RenderWindow: failed to reset device to new dimensions << "
572                                        << width << " x " << height << ". Trying to recover.";
573                                LogManager::getSingleton().logMessage(LML_CRITICAL, str.str());
574
575                                // try to recover
576                                hr = mDriver->getD3DDevice()->CreateAdditionalSwapChain(
577                                        &md3dpp,
578                                        &mpSwapChain);
579
580                                if (FAILED(hr))
581                                        OGRE_EXCEPT( hr, "Reset window to last size failed", "D3D9RenderWindow::resize" );
582
583                        }               
584                        else
585                        {
586                                md3dpp = pp;
587
588                                mWidth = width;
589                                mHeight = height;
590
591                                hr = mpSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mpRenderSurface);
592                                hr = mDriver->getD3DDevice()->CreateDepthStencilSurface(
593                                                mWidth, mHeight,
594                                                md3dpp.AutoDepthStencilFormat,
595                                                md3dpp.MultiSampleType,
596                                                md3dpp.MultiSampleQuality,
597                                                (md3dpp.Flags & D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL),
598                                                &mpRenderZBuffer, NULL
599                                                );
600
601                                if (FAILED(hr))
602                                {
603                                        OGRE_EXCEPT( hr, "Failed to create depth stencil surface for Swap Chain", "D3D9RenderWindow::resize" );
604                                }
605
606                                mpRenderSurface->Release();
607                        }
608                }
609                // primary windows must reset the device
610                else
611                {
612                        md3dpp.BackBufferWidth = mWidth = width;
613                        md3dpp.BackBufferHeight = mHeight = height;
614                        static_cast<D3D9RenderSystem*>(
615                                Root::getSingleton().getRenderSystem())->_notifyDeviceLost();
616                }
617
618                // Notify viewports of resize
619                ViewportList::iterator it = mViewportList.begin();
620                while( it != mViewportList.end() )
621                        (*it++).second->_updateDimensions();
622        }
623
624        void D3D9RenderWindow::swapBuffers( bool waitForVSync )
625        {
626                // access device through driver
627                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
628                if( mpD3DDevice )
629                {
630                        HRESULT hr;
631                        if (mIsSwapChain)
632                        {
633                                hr = mpSwapChain->Present(NULL, NULL, NULL, NULL, 0);
634                        }
635                        else
636                        {
637                                hr = mpD3DDevice->Present( NULL, NULL, 0, NULL );
638                        }
639                        if( D3DERR_DEVICELOST == hr )
640                        {
641                                static_cast<D3D9RenderSystem*>(
642                                        Root::getSingleton().getRenderSystem())->_notifyDeviceLost();
643                        }
644                        else if( FAILED(hr) )
645                                OGRE_EXCEPT( hr, "Error Presenting surfaces", "D3D9RenderWindow::swapBuffers" );
646                }
647        }
648
649        void D3D9RenderWindow::getCustomAttribute( const String& name, void* pData )
650        {
651                // Valid attributes and their equvalent native functions:
652                // D3DDEVICE                    : getD3DDevice
653                // HWND                                 : getWindowHandle
654
655                if( name == "D3DDEVICE" )
656                {
657                        LPDIRECT3DDEVICE9 *pDev = (LPDIRECT3DDEVICE9*)pData;
658                        *pDev = getD3DDevice();
659                        return;
660                }
661                else if( name == "HWND" )
662                {
663                        HWND *pHwnd = (HWND*)pData;
664                        *pHwnd = getWindowHandle();
665                        return;
666                }
667                else if( name == "isTexture" )
668                {
669                        bool *b = reinterpret_cast< bool * >( pData );
670                        *b = false;
671
672                        return;
673                }
674                else if( name == "D3DZBUFFER" )
675                {
676                        LPDIRECT3DSURFACE9 *pSurf = (LPDIRECT3DSURFACE9*)pData;
677                        *pSurf = mpRenderZBuffer;
678                        return;
679                }
680                else if( name == "DDBACKBUFFER" )
681                {
682                        LPDIRECT3DSURFACE9 *pSurf = (LPDIRECT3DSURFACE9*)pData;
683                        *pSurf = mpRenderSurface;
684                        return;
685                }
686                else if( name == "DDFRONTBUFFER" )
687                {
688                        LPDIRECT3DSURFACE9 *pSurf = (LPDIRECT3DSURFACE9*)pData;
689                        *pSurf = mpRenderSurface;
690                        return;
691                }
692        }
693
694        void D3D9RenderWindow::writeContentsToFile(const String& filename)
695        {
696                HRESULT hr;
697                LPDIRECT3DSURFACE9 pSurf=NULL, pTempSurf=NULL;
698                D3DSURFACE_DESC desc;
699                D3DDISPLAYMODE dm;
700
701                // access device through driver
702                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
703
704                // get display dimensions
705                // this will be the dimensions of the front buffer
706                if (FAILED(hr = mpD3DDevice->GetDisplayMode(0, &dm)))
707                        OGRE_EXCEPT(hr, "Can't get display mode!", "D3D9RenderWindow::writeContentsToFile");
708
709                desc.Width = dm.Width;
710                desc.Height = dm.Height;
711                desc.Format = D3DFMT_A8R8G8B8;
712                if (FAILED(hr = mpD3DDevice->CreateOffscreenPlainSurface(
713                                                desc.Width,
714                                                desc.Height,
715                                                desc.Format,
716                                                D3DPOOL_SYSTEMMEM,
717                                                &pTempSurf,
718                                                NULL)))
719                {
720                        OGRE_EXCEPT(hr, "Cannot create offscreen buffer 1!", "D3D9RenderWindow::writeContentsToFile");
721                }
722
723                if (FAILED(hr = mpD3DDevice->GetFrontBufferData(0, pTempSurf)))
724                {
725                        SAFE_RELEASE(pTempSurf);
726                        OGRE_EXCEPT(hr, "Can't get front buffer!", "D3D9RenderWindow::writeContentsToFile");
727                }
728
729                if (!mIsFullScreen)
730                {
731                        POINT pt={0, 0};
732                        RECT srcRect;
733                        GetWindowRect(mHWnd, &srcRect);
734
735                        desc.Width = srcRect.right - srcRect.left;
736                        desc.Height = srcRect.bottom - srcRect.top;
737                        desc.Format = D3DFMT_A8R8G8B8;         // this is what we get from the screen, so stick with it
738
739                        // NB we can't lock the back buffer direct because it's no created that way
740                        // and to do so hits performance, so copy to another surface
741                        // Must be the same format as the source surface
742                        if (FAILED(hr = mpD3DDevice->CreateOffscreenPlainSurface(
743                                                        desc.Width,
744                                                        desc.Height,
745                                                        desc.Format,
746                                                        D3DPOOL_DEFAULT,
747                                                        &pSurf,
748                                                        NULL)))
749                        {
750                                SAFE_RELEASE(pSurf);
751                                OGRE_EXCEPT(hr, "Cannot create offscreen buffer 2!", "D3D9RenderWindow::writeContentsToFile");
752                        }
753
754                        // Copy
755                        if (FAILED(hr = mpD3DDevice->UpdateSurface(pTempSurf, &srcRect, pSurf, &pt)))
756                        {
757                                SAFE_RELEASE(pTempSurf);
758                                SAFE_RELEASE(pSurf);
759                                OGRE_EXCEPT(hr, "Cannot update surface!", "D3D9RenderWindow::writeContentsToFile");
760                        }
761
762                        SAFE_RELEASE(pTempSurf);
763                        pTempSurf = pSurf;
764                        pSurf = NULL;
765                }
766
767                D3DLOCKED_RECT lockedRect;
768                if (FAILED(hr = pTempSurf->LockRect(&lockedRect, NULL,
769                        D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)))
770                {
771                        OGRE_EXCEPT(hr, "can't lock rect!", "D3D9RenderWindow::writeContentsToFile");
772                }
773
774        ImageCodec::ImageData *imgData = new ImageCodec::ImageData();
775        imgData->width = desc.Width;
776        imgData->height = desc.Height;
777        imgData->format = PF_BYTE_RGB;
778
779                // Allocate contiguous buffer (surfaces aren't necessarily contiguous)
780                uchar* pBuffer = new uchar[desc.Width * desc.Height * 3];
781
782                uint x, y;
783                uchar *pData, *pDest;
784
785                pData = (uchar*)lockedRect.pBits;
786                pDest = pBuffer;
787                for (y = 0; y < desc.Height; ++y)
788                {
789                        uchar *pRow = pData;
790
791                        for (x = 0; x < desc.Width; ++x)
792                        {
793                                switch(desc.Format)
794                                {
795                                case D3DFMT_R5G6B5:
796                                        WORD val;
797
798                                        val = *((WORD*)pRow);
799                                        pRow += 2;
800
801                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0xF800, (BYTE)0xFF);
802                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0x07E0, (BYTE)0xFF);
803                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0x001F, (BYTE)0xFF);
804                                        break;
805                                case D3DFMT_A8R8G8B8:
806                                case D3DFMT_X8R8G8B8:
807                                        // Actual format is BRGA for some reason
808                                        *pDest++ = pRow[2]; // R
809                                        *pDest++ = pRow[1]; // G
810                                        *pDest++ = pRow[0]; // B
811                                        pRow += 4; // skip alpha / dummy
812                                        break;
813                                case D3DFMT_R8G8B8:
814                                        // Actual format is BRGA for some reason
815                                        *pDest++ = pRow[2]; // R
816                                        *pDest++ = pRow[1]; // G
817                                        *pDest++ = pRow[0]; // B
818                                        pRow += 3;
819                                        break;
820                                }
821
822
823                        }
824                        // increase by one line
825                        pData += lockedRect.Pitch;
826                }
827
828                // Wrap buffer in a chunk
829                MemoryDataStreamPtr stream(new MemoryDataStream(pBuffer, desc.Width * desc.Height * 3, false));
830
831                // Get codec
832                size_t pos = filename.find_last_of(".");
833                String extension;
834                if( pos == String::npos )
835                        OGRE_EXCEPT(
836                        Exception::ERR_INVALIDPARAMS,
837                        "Unable to determine image type for '" + filename + "' - invalid extension.",
838                        "D3D9RenderWindow::writeContentsToFile" );
839
840                while( pos != filename.length() - 1 )
841                        extension += filename[++pos];
842
843                // Get the codec
844                Codec * pCodec = Codec::getCodec(extension);
845
846                // Write out
847                {
848                        Codec::CodecDataPtr ptr(imgData);
849                pCodec->codeToFile(stream, filename, ptr);
850                }
851
852                delete [] pBuffer;
853
854                SAFE_RELEASE(pTempSurf);
855                SAFE_RELEASE(pSurf);
856        }
857        //-----------------------------------------------------------------------------
858        void D3D9RenderWindow::update(void)
859        {
860                D3D9RenderSystem* rs = static_cast<D3D9RenderSystem*>(
861                        Root::getSingleton().getRenderSystem());
862
863                // access device through driver
864                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
865
866                if (rs->isDeviceLost())
867                {
868                        // Test the cooperative mode first
869                        HRESULT hr = mpD3DDevice->TestCooperativeLevel();
870                        if (hr == D3DERR_DEVICELOST)
871                        {
872                                // device lost, and we can't reset
873                                // can't do anything about it here, wait until we get
874                                // D3DERR_DEVICENOTRESET; rendering calls will silently fail until
875                                // then (except Present, but we ignore device lost there too)
876                                mpRenderSurface = 0;
877                                // need to release if swap chain
878                                if (!mIsSwapChain)
879                                        mpRenderZBuffer = 0;
880                                else
881                                        SAFE_RELEASE (mpRenderZBuffer);
882                                Sleep(50);
883                                return;
884                        }
885                        else
886                        {
887                                // device lost, and we can reset
888                                rs->restoreLostDevice();
889
890                                // Still lost?
891                                if (rs->isDeviceLost())
892                                {
893                                        // Wait a while
894                                        Sleep(50);
895                                        return;
896                                }
897                       
898                                // fixed: this only works for not swap chained
899                                if (!mIsSwapChain)
900                                {
901                                        // re-qeuery buffers
902                                        mpD3DDevice->GetRenderTarget( 0, &mpRenderSurface );
903                                        mpD3DDevice->GetDepthStencilSurface( &mpRenderZBuffer );
904                                        // release immediately so we don't hog them
905                                        mpRenderSurface->Release();
906                                        mpRenderZBuffer->Release();
907                                }
908                                else
909                                {
910                                        mpSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &mpRenderSurface );
911                                        if (mIsDepthBuffered) {
912                                                hr = mpD3DDevice->CreateDepthStencilSurface(
913                                                        mWidth, mHeight,
914                                                        md3dpp.AutoDepthStencilFormat,
915                                                        md3dpp.MultiSampleType,
916                                                        md3dpp.MultiSampleQuality,
917                                                        (md3dpp.Flags & D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL),
918                                                        &mpRenderZBuffer, NULL
919                                                        );
920
921                                                if (FAILED(hr)) {
922                                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
923                                                                "Unable to re-create depth buffer for the swap chain",
924                                                                "D3D9RenderWindow::update");
925
926                                                }
927                                        }
928                                        else
929                                        {
930                                                mpRenderZBuffer = 0;
931                                        }
932
933                                        // release immediately so we don't hog them
934                                        mpRenderSurface->Release();
935                                }
936                        }
937
938                }
939                RenderWindow::update();
940        }
941
942#ifdef GTP_VISIBILITY_MODIFIED_OGRE
943        uchar *D3D9RenderWindow::getBufferContents(int &dimx, int &dimy)
944        {
945                HRESULT hr;
946                LPDIRECT3DSURFACE9 pSurf=NULL, pTempSurf=NULL;
947                //IDirect3DSurface9 *pTempSurf=NULL;
948                D3DSURFACE_DESC desc;
949                D3DDISPLAYMODE dm;
950
951                // access device through driver
952                LPDIRECT3DDEVICE9 mpD3DDevice = mDriver->getD3DDevice();
953
954                // get display dimensions
955                // this will be the dimensions of the front buffer
956                if (FAILED(hr = mpD3DDevice->GetDisplayMode(0, &dm)))
957                        OGRE_EXCEPT(hr, "Can't get display mode!", "D3D9RenderWindow::getBufferContents");
958
959                desc.Width = dm.Width;
960                desc.Height = dm.Height;
961                desc.Format = D3DFMT_A8R8G8B8;
962                if (FAILED(hr = mpD3DDevice->CreateOffscreenPlainSurface(
963                                                desc.Width,
964                                                desc.Height,
965                                                desc.Format,
966                                                D3DPOOL_SYSTEMMEM,
967                                                &pTempSurf,
968                                                NULL)))
969                {
970                        OGRE_EXCEPT(hr, "Cannot create offscreen buffer 1!", "D3D9RenderWindow::getBufferContents");
971                }
972
973                if (FAILED(hr = mpD3DDevice->GetFrontBufferData(0, pTempSurf)))
974                //if (FAILED(hr = mpD3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pTempSurf)))
975                {
976                        SAFE_RELEASE(pTempSurf);
977                        OGRE_EXCEPT(hr, "Can't get back buffer!", "D3D9RenderWindow::getBufferContents");
978                }
979
980                if (!mIsFullScreen)
981                {
982                        POINT pt={0, 0};
983                        RECT srcRect;
984                        GetWindowRect(mHWnd, &srcRect);
985
986                        desc.Width = srcRect.right - srcRect.left;
987                        desc.Height = srcRect.bottom - srcRect.top;
988                        desc.Format = D3DFMT_A8R8G8B8;         // this is what we get from the screen, so stick with it
989
990                        // NB we can't lock the back buffer direct because it's not created that way
991                        // and to do so hits performance, so copy to another surface
992                        // Must be the same format as the source surface
993                        if (FAILED(hr = mpD3DDevice->CreateOffscreenPlainSurface(
994                                                        desc.Width,
995                                                        desc.Height,
996                                                        desc.Format,
997                                                        D3DPOOL_DEFAULT,
998                                                        &pSurf,
999                                                        NULL)))
1000                        {
1001                                SAFE_RELEASE(pSurf);
1002                                OGRE_EXCEPT(hr, "Cannot create offscreen buffer 2!", "D3D9RenderWindow::getBufferContents");
1003                        }
1004
1005                        // Copy
1006                        if (FAILED(hr = mpD3DDevice->UpdateSurface(pTempSurf, &srcRect, pSurf, &pt)))
1007                        {
1008                                SAFE_RELEASE(pTempSurf);
1009                                SAFE_RELEASE(pSurf);
1010                                OGRE_EXCEPT(hr, "Cannot update surface!", "D3D9RenderWindow::getBufferContents");
1011                        }
1012
1013                        SAFE_RELEASE(pTempSurf);
1014                        pTempSurf = pSurf;
1015                        pSurf = NULL;
1016                }
1017
1018                D3DLOCKED_RECT lockedRect;
1019                if (FAILED(hr = pTempSurf->LockRect(&lockedRect, NULL,
1020                        D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)))
1021                {
1022                        OGRE_EXCEPT(hr, "can't lock rect!", "D3D9RenderWindow::getBufferContents");
1023                }
1024
1025       
1026        dimx = desc.Width;
1027        dimy = desc.Height;
1028     
1029                // Allocate contiguous buffer (surfaces aren't necessarily contiguous)
1030                uchar* pBuffer = new uchar[desc.Width * desc.Height * 3];
1031
1032                uint x, y;
1033                uchar *pData, *pDest;
1034
1035                pData = (uchar*)lockedRect.pBits;
1036                pDest = pBuffer;
1037                for (y = 0; y < desc.Height; ++y)
1038                {
1039                        uchar *pRow = pData;
1040
1041                        for (x = 0; x < desc.Width; ++x)
1042                        {
1043                                switch(desc.Format)
1044                                {
1045                                case D3DFMT_R5G6B5:
1046                                        WORD val;
1047
1048                                        val = *((WORD*)pRow);
1049                                        pRow += 2;
1050
1051                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0xF800, (BYTE)0xFF);
1052                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0x07E0, (BYTE)0xFF);
1053                                        *pDest++ = Bitwise::convertBitPattern((WORD)val, (WORD)0x001F, (BYTE)0xFF);
1054                                        break;
1055                                case D3DFMT_A8R8G8B8:
1056                                case D3DFMT_X8R8G8B8:
1057                                        // Actual format is BRGA for some reason
1058                                        *pDest++ = pRow[2]; // R
1059                                        *pDest++ = pRow[1]; // G
1060                                        *pDest++ = pRow[0]; // B
1061                                        pRow += 4; // skip alpha / dummy
1062                                        break;
1063                                case D3DFMT_R8G8B8:
1064                                        // Actual format is BRGA for some reason
1065                                        *pDest++ = pRow[2]; // R
1066                                        *pDest++ = pRow[1]; // G
1067                                        *pDest++ = pRow[0]; // B
1068                                        pRow += 3;
1069                                        break;
1070                                }
1071
1072
1073                        }
1074                        // increase by one line
1075                        pData += lockedRect.Pitch;
1076                }
1077
1078//pTempSurf->UnlockRect();
1079                SAFE_RELEASE(pTempSurf);
1080                SAFE_RELEASE(pSurf);
1081
1082                return pBuffer;
1083        }
1084#endif // GTP_VISIBILITY_MODIFIED_OGRE
1085}
Note: See TracBrowser for help on using the repository browser.