source: OGRE/trunk/ogre_changes/RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp @ 657

Revision 657, 29.4 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

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